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