Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
memap.py
00001 #!/usr/bin/env python 00002 00003 """Memory Map File Analyser for ARM mbed""" 00004 from __future__ import print_function, division, absolute_import 00005 00006 from abc import abstractmethod, ABCMeta 00007 from sys import stdout, exit, argv 00008 from os import sep 00009 from os.path import basename, dirname, join, relpath, commonprefix 00010 import re 00011 import csv 00012 import json 00013 from argparse import ArgumentParser 00014 from copy import deepcopy 00015 from prettytable import PrettyTable 00016 00017 from .utils import (argparse_filestring_type, argparse_lowercase_hyphen_type, 00018 argparse_uppercase_type) 00019 00020 00021 class _Parser (object): 00022 """Internal interface for parsing""" 00023 __metaclass__ = ABCMeta 00024 SECTIONS = ('.text', '.data', '.bss', '.heap', '.stack') 00025 MISC_FLASH_SECTIONS = ('.interrupts', '.flash_config') 00026 OTHER_SECTIONS = ('.interrupts_ram', '.init', '.ARM.extab', 00027 '.ARM.exidx', '.ARM.attributes', '.eh_frame', 00028 '.init_array', '.fini_array', '.jcr', '.stab', 00029 '.stabstr', '.ARM.exidx', '.ARM') 00030 00031 def __init__(self): 00032 self.modules = dict() 00033 00034 def module_add (self, object_name, size, section): 00035 """ Adds a module or section to the list 00036 00037 Positional arguments: 00038 object_name - name of the entry to add 00039 size - the size of the module being added 00040 section - the section the module contributes to 00041 """ 00042 if not object_name or not size or not section: 00043 return 00044 00045 if object_name in self.modules : 00046 self.modules [object_name].setdefault(section, 0) 00047 self.modules [object_name][section] += size 00048 return 00049 00050 obj_split = sep + basename(object_name) 00051 for module_path, contents in self.modules .items(): 00052 if module_path.endswith(obj_split) or module_path == object_name: 00053 contents.setdefault(section, 0) 00054 contents[section] += size 00055 return 00056 00057 new_module = {section: size} 00058 self.modules [object_name] = new_module 00059 00060 def module_replace (self, old_object, new_object): 00061 """ Replaces an object name with a new one 00062 """ 00063 if old_object in self.modules : 00064 self.modules [new_object] = self.modules [old_object] 00065 del self.modules [old_object] 00066 00067 @abstractmethod 00068 def parse_mapfile (self, mapfile): 00069 """Parse a given file object pointing to a map file 00070 00071 Positional arguments: 00072 mapfile - an open file object that reads a map file 00073 00074 return value - a dict mapping from object names to section dicts, 00075 where a section dict maps from sections to sizes 00076 """ 00077 raise NotImplemented 00078 00079 00080 class _GccParser(_Parser ): 00081 RE_OBJECT_FILE = re.compile(r'^(.+\/.+\.o)$') 00082 RE_LIBRARY_OBJECT = re.compile(r'^.+' + sep + r'lib((.+\.a)\((.+\.o)\))$') 00083 RE_STD_SECTION = re.compile(r'^\s+.*0x(\w{8,16})\s+0x(\w+)\s(.+)$') 00084 RE_FILL_SECTION = re.compile(r'^\s*\*fill\*\s+0x(\w{8,16})\s+0x(\w+).*$') 00085 00086 ALL_SECTIONS = _Parser.SECTIONS + _Parser.OTHER_SECTIONS + \ 00087 _Parser.MISC_FLASH_SECTIONS + ('unknown', 'OUTPUT') 00088 00089 def check_new_section(self, line): 00090 """ Check whether a new section in a map file has been detected 00091 00092 Positional arguments: 00093 line - the line to check for a new section 00094 00095 return value - A section name, if a new section was found, False 00096 otherwise 00097 """ 00098 for i in self.ALL_SECTIONS: 00099 if line.startswith(i): 00100 # should name of the section (assuming it's a known one) 00101 return i 00102 00103 if line.startswith('.'): 00104 return 'unknown' # all others are classified are unknown 00105 else: 00106 return False # everything else, means no change in section 00107 00108 00109 def parse_object_name(self, line): 00110 """ Parse a path to object file 00111 00112 Positional arguments: 00113 line - the path to parse the object and module name from 00114 00115 return value - an object file name 00116 """ 00117 test_re_mbed_os_name = re.match(self.RE_OBJECT_FILE, line) 00118 00119 if test_re_mbed_os_name: 00120 object_name = test_re_mbed_os_name.group(1) 00121 00122 # corner case: certain objects are provided by the GCC toolchain 00123 if 'arm-none-eabi' in line: 00124 return join('[lib]', 'misc', basename(object_name)) 00125 return object_name 00126 00127 else: 00128 test_re_obj_name = re.match(self.RE_LIBRARY_OBJECT, line) 00129 00130 if test_re_obj_name: 00131 return join('[lib]', test_re_obj_name.group(2), 00132 test_re_obj_name.group(3)) 00133 else: 00134 print("Unknown object name found in GCC map file: %s" % line) 00135 return '[misc]' 00136 00137 def parse_section(self, line): 00138 """ Parse data from a section of gcc map file 00139 00140 examples: 00141 0x00004308 0x7c ./BUILD/K64F/GCC_ARM/mbed-os/hal/targets/hal/TARGET_Freescale/TARGET_KPSDK_MCUS/spi_api.o 00142 .text 0x00000608 0x198 ./BUILD/K64F/GCC_ARM/mbed-os/core/mbed-rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN/HAL_CM4.o 00143 00144 Positional arguments: 00145 line - the line to parse a section from 00146 """ 00147 is_fill = re.match(self.RE_FILL_SECTION, line) 00148 if is_fill: 00149 o_name = '[fill]' 00150 o_size = int(is_fill.group(2), 16) 00151 return [o_name, o_size] 00152 00153 is_section = re.match(self.RE_STD_SECTION, line) 00154 if is_section: 00155 o_size = int(is_section.group(2), 16) 00156 if o_size: 00157 o_name = self.parse_object_name(is_section.group(3)) 00158 return [o_name, o_size] 00159 00160 return ["", 0] 00161 00162 def parse_mapfile (self, file_desc): 00163 """ Main logic to decode gcc map files 00164 00165 Positional arguments: 00166 file_desc - a stream object to parse as a gcc map file 00167 """ 00168 current_section = 'unknown' 00169 00170 with file_desc as infile: 00171 for line in infile: 00172 if line.startswith('Linker script and memory map'): 00173 current_section = "unknown" 00174 break 00175 00176 for line in infile: 00177 next_section = self.check_new_section(line) 00178 00179 if next_section == "OUTPUT": 00180 break 00181 elif next_section: 00182 current_section = next_section 00183 00184 object_name, object_size = self.parse_section(line) 00185 self.module_add (object_name, object_size, current_section) 00186 00187 common_prefix = dirname(commonprefix([ 00188 o for o in self.modules .keys() if (o.endswith(".o") and not o.startswith("[lib]"))])) 00189 new_modules = {} 00190 for name, stats in self.modules .items(): 00191 if name.startswith("[lib]"): 00192 new_modules[name] = stats 00193 elif name.endswith(".o"): 00194 new_modules[relpath(name, common_prefix)] = stats 00195 else: 00196 new_modules[name] = stats 00197 return new_modules 00198 00199 00200 class _ArmccParser(_Parser ): 00201 RE = re.compile( 00202 r'^\s+0x(\w{8})\s+0x(\w{8})\s+(\w+)\s+(\w+)\s+(\d+)\s+[*]?.+\s+(.+)$') 00203 RE_OBJECT = re.compile(r'(.+\.(l|ar))\((.+\.o)\)') 00204 00205 def parse_object_name(self, line): 00206 """ Parse object file 00207 00208 Positional arguments: 00209 line - the line containing the object or library 00210 """ 00211 if line.endswith(".o"): 00212 return line 00213 00214 else: 00215 is_obj = re.match(self.RE_OBJECT, line) 00216 if is_obj: 00217 return join('[lib]', basename(is_obj.group(1)), is_obj.group(3)) 00218 else: 00219 print("Malformed input found when parsing ARMCC map: %s" % line) 00220 return '[misc]' 00221 00222 def parse_section(self, line): 00223 """ Parse data from an armcc map file 00224 00225 Examples of armcc map file: 00226 Base_Addr Size Type Attr Idx E Section Name Object 00227 0x00000000 0x00000400 Data RO 11222 self.RESET startup_MK64F12.o 00228 0x00000410 0x00000008 Code RO 49364 * !!!main c_w.l(__main.o) 00229 00230 Positional arguments: 00231 line - the line to parse the section data from 00232 """ 00233 test_re = re.match(self.RE, line) 00234 00235 if test_re: 00236 size = int(test_re.group(2), 16) 00237 00238 if test_re.group(4) == 'RO': 00239 section = '.text' 00240 else: 00241 if test_re.group(3) == 'Data': 00242 section = '.data' 00243 elif test_re.group(3) == 'Zero': 00244 section = '.bss' 00245 elif test_re.group(3) == 'Code': 00246 section = '.text' 00247 else: 00248 print("Malformed input found when parsing armcc map: %s, %r" 00249 % (line, test_re.groups())) 00250 00251 return ["", 0, ""] 00252 00253 # check name of object or library 00254 object_name = self.parse_object_name( 00255 test_re.group(6)) 00256 00257 return [object_name, size, section] 00258 00259 else: 00260 return ["", 0, ""] 00261 00262 def parse_mapfile (self, file_desc): 00263 """ Main logic to decode armc5 map files 00264 00265 Positional arguments: 00266 file_desc - a file like object to parse as an armc5 map file 00267 """ 00268 with file_desc as infile: 00269 # Search area to parse 00270 for line in infile: 00271 if line.startswith(' Base Addr Size'): 00272 break 00273 00274 # Start decoding the map file 00275 for line in infile: 00276 self.module_add (*self.parse_section(line)) 00277 00278 common_prefix = dirname(commonprefix([ 00279 o for o in self.modules .keys() if (o.endswith(".o") and o != "anon$$obj.o" and not o.startswith("[lib]"))])) 00280 new_modules = {} 00281 for name, stats in self.modules .items(): 00282 if name == "anon$$obj.o" or name.startswith("[lib]"): 00283 new_modules[name] = stats 00284 elif name.endswith(".o"): 00285 new_modules[relpath(name, common_prefix)] = stats 00286 else: 00287 new_modules[name] = stats 00288 return new_modules 00289 00290 00291 class _IarParser(_Parser ): 00292 RE = re.compile( 00293 r'^\s+(.+)\s+(zero|const|ro code|inited|uninit)\s' 00294 r'+0x(\w{8})\s+0x(\w+)\s+(.+)\s.+$') 00295 00296 RE_CMDLINE_FILE = re.compile(r'^#\s+(.+\.o)') 00297 RE_LIBRARY = re.compile(r'^(.+\.a)\:.+$') 00298 RE_OBJECT_LIBRARY = re.compile(r'^\s+(.+\.o)\s.*') 00299 00300 def __init__(self): 00301 _Parser.__init__(self) 00302 # Modules passed to the linker on the command line 00303 # this is a dict because modules are looked up by their basename 00304 self.cmd_modules = {} 00305 00306 def parse_object_name(self, object_name): 00307 """ Parse object file 00308 00309 Positional arguments: 00310 line - the line containing the object or library 00311 """ 00312 if object_name.endswith(".o"): 00313 try: 00314 return self.cmd_modules[object_name] 00315 except KeyError: 00316 return object_name 00317 else: 00318 return '[misc]' 00319 00320 def parse_section(self, line): 00321 """ Parse data from an IAR map file 00322 00323 Examples of IAR map file: 00324 Section Kind Address Size Object 00325 .intvec ro code 0x00000000 0x198 startup_MK64F12.o [15] 00326 .rodata const 0x00000198 0x0 zero_init3.o [133] 00327 .iar.init_table const 0x00008384 0x2c - Linker created - 00328 Initializer bytes const 0x00000198 0xb2 <for P3 s0> 00329 .data inited 0x20000000 0xd4 driverAtmelRFInterface.o [70] 00330 .bss zero 0x20000598 0x318 RTX_Conf_CM.o [4] 00331 .iar.dynexit uninit 0x20001448 0x204 <Block tail> 00332 HEAP uninit 0x20001650 0x10000 <Block tail> 00333 00334 Positional_arguments: 00335 line - the line to parse section data from 00336 """ 00337 test_re = re.match(self.RE, line) 00338 if test_re: 00339 if (test_re.group(2) == 'const' or 00340 test_re.group(2) == 'ro code'): 00341 section = '.text' 00342 elif (test_re.group(2) == 'zero' or 00343 test_re.group(2) == 'uninit'): 00344 if test_re.group(1)[0:4] == 'HEAP': 00345 section = '.heap' 00346 elif test_re.group(1)[0:6] == 'CSTACK': 00347 section = '.stack' 00348 else: 00349 section = '.bss' # default section 00350 00351 elif test_re.group(2) == 'inited': 00352 section = '.data' 00353 else: 00354 print("Malformed input found when parsing IAR map: %s" % line) 00355 return ["", 0, ""] 00356 00357 # lookup object in dictionary and return module name 00358 object_name = self.parse_object_name(test_re.group(5)) 00359 00360 size = int(test_re.group(4), 16) 00361 return [object_name, size, section] 00362 00363 else: 00364 return ["", 0, ""] 00365 00366 def check_new_library(self, line): 00367 """ 00368 Searches for libraries and returns name. Example: 00369 m7M_tls.a: [43] 00370 00371 """ 00372 test_address_line = re.match(self.RE_LIBRARY, line) 00373 if test_address_line: 00374 return test_address_line.group(1) 00375 else: 00376 return "" 00377 00378 def check_new_object_lib(self, line): 00379 """ 00380 Searches for objects within a library section and returns name. Example: 00381 rt7M_tl.a: [44] 00382 ABImemclr4.o 6 00383 ABImemcpy_unaligned.o 118 00384 ABImemset48.o 50 00385 I64DivMod.o 238 00386 I64DivZer.o 2 00387 00388 """ 00389 test_address_line = re.match(self.RE_OBJECT_LIBRARY, line) 00390 if test_address_line: 00391 return test_address_line.group(1) 00392 else: 00393 return "" 00394 00395 def parse_command_line(self, lines): 00396 """Parse the files passed on the command line to the iar linker 00397 00398 Positional arguments: 00399 lines -- an iterator over the lines within a file 00400 """ 00401 for line in lines: 00402 if line.startswith("*"): 00403 break 00404 for arg in line.split(" "): 00405 arg = arg.rstrip(" \n") 00406 if (not arg.startswith("-")) and arg.endswith(".o"): 00407 self.cmd_modules[basename(arg)] = arg 00408 00409 common_prefix = dirname(commonprefix(list(self.cmd_modules.values()))) 00410 self.cmd_modules = {s: relpath(f, common_prefix) 00411 for s, f in self.cmd_modules.items()} 00412 00413 def parse_mapfile (self, file_desc): 00414 """ Main logic to decode IAR map files 00415 00416 Positional arguments: 00417 file_desc - a file like object to parse as an IAR map file 00418 """ 00419 with file_desc as infile: 00420 self.parse_command_line(infile) 00421 00422 for line in infile: 00423 if line.startswith(' Section '): 00424 break 00425 00426 for line in infile: 00427 self.module_add (*self.parse_section(line)) 00428 00429 if line.startswith('*** MODULE SUMMARY'): # finish section 00430 break 00431 00432 current_library = "" 00433 for line in infile: 00434 library = self.check_new_library(line) 00435 00436 if library: 00437 current_library = library 00438 00439 object_name = self.check_new_object_lib(line) 00440 00441 if object_name and current_library: 00442 temp = join('[lib]', current_library, object_name) 00443 self.module_replace (object_name, temp) 00444 return self.modules 00445 00446 00447 class MemapParser (object): 00448 """An object that represents parsed results, parses the memory map files, 00449 and writes out different file types of memory results 00450 """ 00451 00452 print_sections = ('.text', '.data', '.bss') 00453 00454 00455 # sections to print info (generic for all toolchains) 00456 sections = _Parser.SECTIONS 00457 misc_flash_sections = _Parser.MISC_FLASH_SECTIONS 00458 other_sections = _Parser.OTHER_SECTIONS 00459 00460 def __init__(self): 00461 # list of all modules and their sections 00462 # full list - doesn't change with depth 00463 self.modules = dict() 00464 # short version with specific depth 00465 self.short_modules = dict() 00466 00467 00468 # Memory report (sections + summary) 00469 self.mem_report = [] 00470 00471 # Memory summary 00472 self.mem_summary = dict() 00473 00474 # Totals of ".text", ".data" and ".bss" 00475 self.subtotal = dict() 00476 00477 # Flash no associated with a module 00478 self.misc_flash_mem = 0 00479 00480 def reduce_depth (self, depth): 00481 """ 00482 populates the short_modules attribute with a truncated module list 00483 00484 (1) depth = 1: 00485 main.o 00486 mbed-os 00487 00488 (2) depth = 2: 00489 main.o 00490 mbed-os/test.o 00491 mbed-os/drivers 00492 00493 """ 00494 if depth == 0 or depth == None: 00495 self.short_modules = deepcopy(self.modules ) 00496 else: 00497 self.short_modules = dict() 00498 for module_name, v in self.modules .items(): 00499 split_name = module_name.split(sep) 00500 if split_name[0] == '': 00501 split_name = split_name[1:] 00502 new_name = join(*split_name[:depth]) 00503 self.short_modules .setdefault(new_name, {}) 00504 for section_idx, value in v.items(): 00505 self.short_modules [new_name].setdefault(section_idx, 0) 00506 self.short_modules [new_name][section_idx] += self.modules [module_name][section_idx] 00507 00508 export_formats = ["json", "csv-ci", "table"] 00509 00510 def generate_output (self, export_format, depth, file_output=None): 00511 """ Generates summary of memory map data 00512 00513 Positional arguments: 00514 export_format - the format to dump 00515 00516 Keyword arguments: 00517 file_desc - descriptor (either stdout or file) 00518 depth - directory depth on report 00519 00520 Returns: generated string for the 'table' format, otherwise None 00521 """ 00522 self.reduce_depth (depth) 00523 self.compute_report () 00524 try: 00525 if file_output: 00526 file_desc = open(file_output, 'w') 00527 else: 00528 file_desc = stdout 00529 except IOError as error: 00530 print("I/O error({0}): {1}".format(error.errno, error.strerror)) 00531 return False 00532 00533 to_call = {'json': self.generate_json , 00534 'csv-ci': self.generate_csv , 00535 'table': self.generate_table }[export_format] 00536 output = to_call(file_desc) 00537 00538 if file_desc is not stdout: 00539 file_desc.close() 00540 00541 return output 00542 00543 def generate_json (self, file_desc): 00544 """Generate a json file from a memory map 00545 00546 Positional arguments: 00547 file_desc - the file to write out the final report to 00548 """ 00549 file_desc.write(json.dumps(self.mem_report , indent=4)) 00550 file_desc.write('\n') 00551 return None 00552 00553 def generate_csv (self, file_desc): 00554 """Generate a CSV file from a memoy map 00555 00556 Positional arguments: 00557 file_desc - the file to write out the final report to 00558 """ 00559 writer = csv.writer(file_desc, delimiter=',', 00560 quoting=csv.QUOTE_MINIMAL) 00561 00562 module_section = [] 00563 sizes = [] 00564 for i in sorted(self.short_modules ): 00565 for k in self.print_sections : 00566 module_section.append((i + k)) 00567 sizes += [self.short_modules [i][k]] 00568 00569 module_section.append('static_ram') 00570 sizes.append(self.mem_summary ['static_ram']) 00571 00572 module_section.append('total_flash') 00573 sizes.append(self.mem_summary ['total_flash']) 00574 00575 writer.writerow(module_section) 00576 writer.writerow(sizes) 00577 return None 00578 00579 def generate_table (self, file_desc): 00580 """Generate a table from a memoy map 00581 00582 Returns: string of the generated table 00583 """ 00584 # Create table 00585 columns = ['Module'] 00586 columns.extend(self.print_sections ) 00587 00588 table = PrettyTable(columns) 00589 table.align["Module"] = "l" 00590 for col in self.print_sections : 00591 table.align[col] = 'r' 00592 00593 for i in list(self.print_sections ): 00594 table.align[i] = 'r' 00595 00596 for i in sorted(self.short_modules ): 00597 row = [i] 00598 00599 for k in self.print_sections : 00600 row.append(self.short_modules [i][k]) 00601 00602 table.add_row(row) 00603 00604 subtotal_row = ['Subtotals'] 00605 for k in self.print_sections : 00606 subtotal_row.append(self.subtotal [k]) 00607 00608 table.add_row(subtotal_row) 00609 00610 output = table.get_string() 00611 output += '\n' 00612 00613 output += "Total Static RAM memory (data + bss): %s bytes\n" % \ 00614 str(self.mem_summary ['static_ram']) 00615 output += "Total Flash memory (text + data): %s bytes\n" % \ 00616 str(self.mem_summary ['total_flash']) 00617 00618 return output 00619 00620 toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "GCC_CR", "IAR"] 00621 00622 def compute_report (self): 00623 """ Generates summary of memory usage for main areas 00624 """ 00625 for k in self.sections : 00626 self.subtotal [k] = 0 00627 00628 for i in self.short_modules : 00629 for k in self.sections : 00630 self.short_modules [i].setdefault(k, 0) 00631 self.subtotal [k] += self.short_modules [i][k] 00632 00633 self.mem_summary = { 00634 'static_ram': (self.subtotal ['.data'] + self.subtotal ['.bss']), 00635 'total_flash': (self.subtotal ['.text'] + self.subtotal ['.data']), 00636 } 00637 00638 self.mem_report = [] 00639 for i in sorted(self.short_modules ): 00640 self.mem_report .append({ 00641 "module":i, 00642 "size":{ 00643 k: self.short_modules [i][k] for k in self.print_sections 00644 } 00645 }) 00646 00647 self.mem_report .append({ 00648 'summary': self.mem_summary 00649 }) 00650 00651 def parse (self, mapfile, toolchain): 00652 """ Parse and decode map file depending on the toolchain 00653 00654 Positional arguments: 00655 mapfile - the file name of the memory map file 00656 toolchain - the toolchain used to create the file 00657 """ 00658 if toolchain in ("ARM", "ARM_STD", "ARM_MICRO", "ARMC6"): 00659 parser = _ArmccParser() 00660 elif toolchain == "GCC_ARM" or toolchain == "GCC_CR": 00661 parser = _GccParser() 00662 elif toolchain == "IAR": 00663 parser = _IarParser() 00664 else: 00665 return False 00666 try: 00667 with open(mapfile, 'r') as file_input: 00668 self.modules = parser.parse_mapfile(file_input) 00669 return True 00670 00671 except IOError as error: 00672 print("I/O error({0}): {1}".format(error.errno, error.strerror)) 00673 return False 00674 00675 def main(): 00676 """Entry Point""" 00677 version = '0.4.0' 00678 00679 # Parser handling 00680 parser = ArgumentParser( 00681 description="Memory Map File Analyser for ARM mbed\nversion %s" % 00682 version) 00683 00684 parser.add_argument( 00685 'file', type=argparse_filestring_type, help='memory map file') 00686 00687 parser.add_argument( 00688 '-t', '--toolchain', dest='toolchain', 00689 help='select a toolchain used to build the memory map file (%s)' % 00690 ", ".join(MemapParser.toolchains), 00691 required=True, 00692 type=argparse_uppercase_type(MemapParser.toolchains, "toolchain")) 00693 00694 parser.add_argument( 00695 '-d', '--depth', dest='depth', type=int, 00696 help='specify directory depth level to display report', required=False) 00697 00698 parser.add_argument( 00699 '-o', '--output', help='output file name', required=False) 00700 00701 parser.add_argument( 00702 '-e', '--export', dest='export', required=False, default='table', 00703 type=argparse_lowercase_hyphen_type(MemapParser.export_formats, 00704 'export format'), 00705 help="export format (examples: %s: default)" % 00706 ", ".join(MemapParser.export_formats)) 00707 00708 parser.add_argument('-v', '--version', action='version', version=version) 00709 00710 # Parse/run command 00711 if len(argv) <= 1: 00712 parser.print_help() 00713 exit(1) 00714 00715 args = parser.parse_args() 00716 00717 # Create memap object 00718 memap = MemapParser() 00719 00720 # Parse and decode a map file 00721 if args.file and args.toolchain: 00722 if memap.parse(args.file, args.toolchain) is False: 00723 exit(0) 00724 00725 if args.depth is None: 00726 depth = 2 # default depth level 00727 else: 00728 depth = args.depth 00729 00730 returned_string = None 00731 # Write output in file 00732 if args.output != None: 00733 returned_string = memap.generate_output(args.export, \ 00734 depth, args.output) 00735 else: # Write output in screen 00736 returned_string = memap.generate_output(args.export, depth) 00737 00738 if args.export == 'table' and returned_string: 00739 print(returned_string) 00740 00741 exit(0) 00742 00743 if __name__ == "__main__": 00744 main()
Generated on Tue Jul 12 2022 13:30:56 by
