Marco Mayer / Mbed OS Queue
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers memap.py Source File

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()