Clone of official tools

Committer:
The Other Jimmy
Date:
Thu Jun 22 11:12:28 2017 -0500
Revision:
36:96847d42f010
Parent:
31:8ea194f6145b
Child:
40:7d3fa6b99b2b
Tools release 5.5.1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 1 #!/usr/bin/env python
screamer 8:a8ac6ed29081 2
screamer 29:1210849dba19 3 """Memory Map File Analyser for ARM mbed"""
screamer 8:a8ac6ed29081 4
screamer 8:a8ac6ed29081 5 import sys
screamer 8:a8ac6ed29081 6 import os
screamer 8:a8ac6ed29081 7 import re
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 8 import csv
screamer 8:a8ac6ed29081 9 import json
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 10 import argparse
screamer 8:a8ac6ed29081 11 from prettytable import PrettyTable
screamer 8:a8ac6ed29081 12
The Other Jimmy 31:8ea194f6145b 13 from utils import argparse_filestring_type, \
screamer 29:1210849dba19 14 argparse_lowercase_hyphen_type, argparse_uppercase_type
screamer 29:1210849dba19 15
screamer 29:1210849dba19 16 DEBUG = False
The Other Jimmy 31:8ea194f6145b 17
screamer 29:1210849dba19 18 RE_ARMCC = re.compile(
screamer 29:1210849dba19 19 r'^\s+0x(\w{8})\s+0x(\w{8})\s+(\w+)\s+(\w+)\s+(\d+)\s+[*]?.+\s+(.+)$')
screamer 29:1210849dba19 20 RE_IAR = re.compile(
screamer 29:1210849dba19 21 r'^\s+(.+)\s+(zero|const|ro code|inited|uninit)\s'
screamer 29:1210849dba19 22 r'+0x(\w{8})\s+0x(\w+)\s+(.+)\s.+$')
screamer 8:a8ac6ed29081 23
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 24 class MemapParser(object):
screamer 29:1210849dba19 25 """An object that represents parsed results, parses the memory map files,
screamer 29:1210849dba19 26 and writes out different file types of memory results
screamer 29:1210849dba19 27 """
screamer 29:1210849dba19 28
screamer 29:1210849dba19 29 print_sections = ('.text', '.data', '.bss')
screamer 29:1210849dba19 30
screamer 29:1210849dba19 31 misc_flash_sections = ('.interrupts', '.flash_config')
screamer 29:1210849dba19 32
screamer 29:1210849dba19 33 other_sections = ('.interrupts_ram', '.init', '.ARM.extab',
screamer 29:1210849dba19 34 '.ARM.exidx', '.ARM.attributes', '.eh_frame',
screamer 29:1210849dba19 35 '.init_array', '.fini_array', '.jcr', '.stab',
screamer 29:1210849dba19 36 '.stabstr', '.ARM.exidx', '.ARM')
screamer 29:1210849dba19 37
screamer 29:1210849dba19 38 # sections to print info (generic for all toolchains)
screamer 29:1210849dba19 39 sections = ('.text', '.data', '.bss', '.heap', '.stack')
screamer 8:a8ac6ed29081 40
The Other Jimmy 31:8ea194f6145b 41 def __init__(self, detailed_misc=False):
screamer 29:1210849dba19 42 """ General initialization
screamer 8:a8ac6ed29081 43 """
The Other Jimmy 31:8ea194f6145b 44 #
The Other Jimmy 31:8ea194f6145b 45 self.detailed_misc = detailed_misc
The Other Jimmy 31:8ea194f6145b 46
screamer 8:a8ac6ed29081 47 # list of all modules and their sections
screamer 8:a8ac6ed29081 48 self.modules = dict()
screamer 8:a8ac6ed29081 49
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 50 # sections must be defined in this order to take irrelevant out
screamer 8:a8ac6ed29081 51 self.all_sections = self.sections + self.other_sections + \
screamer 8:a8ac6ed29081 52 self.misc_flash_sections + ('unknown', 'OUTPUT')
screamer 8:a8ac6ed29081 53
screamer 8:a8ac6ed29081 54 # list of all object files and mappting to module names
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 55 self.object_to_module = dict()
screamer 8:a8ac6ed29081 56
The Other Jimmy 31:8ea194f6145b 57 # Memory report (sections + summary)
The Other Jimmy 31:8ea194f6145b 58 self.mem_report = []
The Other Jimmy 31:8ea194f6145b 59
The Other Jimmy 31:8ea194f6145b 60 # Just the memory summary section
screamer 22:9e85236d8716 61 self.mem_summary = dict()
screamer 22:9e85236d8716 62
The Other Jimmy 31:8ea194f6145b 63 self.subtotal = dict()
The Other Jimmy 31:8ea194f6145b 64
screamer 8:a8ac6ed29081 65 def module_add(self, module_name, size, section):
screamer 29:1210849dba19 66 """ Adds a module / section to the list
screamer 29:1210849dba19 67
screamer 29:1210849dba19 68 Positional arguments:
screamer 29:1210849dba19 69 module_name - name of the module to add
screamer 29:1210849dba19 70 size - the size of the module being added
screamer 29:1210849dba19 71 section - the section the module contributes to
screamer 8:a8ac6ed29081 72 """
screamer 8:a8ac6ed29081 73
screamer 8:a8ac6ed29081 74 if module_name in self.modules:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 75 self.modules[module_name][section] += size
screamer 8:a8ac6ed29081 76 else:
screamer 8:a8ac6ed29081 77 temp_dic = dict()
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 78 for section_idx in self.all_sections:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 79 temp_dic[section_idx] = 0
screamer 8:a8ac6ed29081 80 temp_dic[section] = size
screamer 8:a8ac6ed29081 81 self.modules[module_name] = temp_dic
screamer 8:a8ac6ed29081 82
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 83 def check_new_section_gcc(self, line):
screamer 29:1210849dba19 84 """ Check whether a new section in a map file has been detected (only
screamer 29:1210849dba19 85 applies to gcc)
screamer 29:1210849dba19 86
screamer 29:1210849dba19 87 Positional arguments:
screamer 29:1210849dba19 88 line - the line to check for a new section
screamer 8:a8ac6ed29081 89 """
screamer 8:a8ac6ed29081 90
screamer 8:a8ac6ed29081 91 for i in self.all_sections:
screamer 8:a8ac6ed29081 92 if line.startswith(i):
screamer 29:1210849dba19 93 # should name of the section (assuming it's a known one)
screamer 29:1210849dba19 94 return i
screamer 8:a8ac6ed29081 95
screamer 8:a8ac6ed29081 96 if line.startswith('.'):
screamer 22:9e85236d8716 97 return 'unknown' # all others are classified are unknown
screamer 8:a8ac6ed29081 98 else:
screamer 8:a8ac6ed29081 99 return False # everything else, means no change in section
screamer 8:a8ac6ed29081 100
The Other Jimmy 31:8ea194f6145b 101
The Other Jimmy 31:8ea194f6145b 102 def path_object_to_module_name(self, txt):
screamer 29:1210849dba19 103 """ Parse a path to object file to extract it's module and object data
screamer 29:1210849dba19 104
screamer 29:1210849dba19 105 Positional arguments:
screamer 29:1210849dba19 106 txt - the path to parse the object and module name from
screamer 8:a8ac6ed29081 107 """
screamer 8:a8ac6ed29081 108
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 109 txt = txt.replace('\\', '/')
screamer 8:a8ac6ed29081 110 rex_mbed_os_name = r'^.+mbed-os\/(.+)\/(.+\.o)$'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 111 test_rex_mbed_os_name = re.match(rex_mbed_os_name, txt)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 112
screamer 8:a8ac6ed29081 113 if test_rex_mbed_os_name:
screamer 8:a8ac6ed29081 114
screamer 8:a8ac6ed29081 115 object_name = test_rex_mbed_os_name.group(2)
screamer 8:a8ac6ed29081 116 data = test_rex_mbed_os_name.group(1).split('/')
screamer 8:a8ac6ed29081 117 ndata = len(data)
screamer 8:a8ac6ed29081 118
screamer 8:a8ac6ed29081 119 if ndata == 1:
screamer 8:a8ac6ed29081 120 module_name = data[0]
screamer 8:a8ac6ed29081 121 else:
screamer 8:a8ac6ed29081 122 module_name = data[0] + '/' + data[1]
screamer 8:a8ac6ed29081 123
The Other Jimmy 36:96847d42f010 124 if self.detailed_misc:
The Other Jimmy 36:96847d42f010 125 return [module_name + '/' + object_name, object_name]
The Other Jimmy 36:96847d42f010 126 else:
The Other Jimmy 36:96847d42f010 127 return [module_name, object_name]
The Other Jimmy 31:8ea194f6145b 128
The Other Jimmy 31:8ea194f6145b 129 elif self.detailed_misc:
The Other Jimmy 31:8ea194f6145b 130 rex_obj_name = r'^.+\/(.+\.o\)*)$'
The Other Jimmy 31:8ea194f6145b 131 test_rex_obj_name = re.match(rex_obj_name, txt)
The Other Jimmy 31:8ea194f6145b 132 if test_rex_obj_name:
The Other Jimmy 31:8ea194f6145b 133 object_name = test_rex_obj_name.group(1)
The Other Jimmy 31:8ea194f6145b 134 return ['Misc/' + object_name, ""]
The Other Jimmy 31:8ea194f6145b 135
screamer 8:a8ac6ed29081 136 return ['Misc', ""]
The Other Jimmy 31:8ea194f6145b 137 else:
The Other Jimmy 31:8ea194f6145b 138 return ['Misc', ""]
screamer 8:a8ac6ed29081 139
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 140 def parse_section_gcc(self, line):
screamer 29:1210849dba19 141 """ Parse data from a section of gcc map file
screamer 29:1210849dba19 142
screamer 29:1210849dba19 143 examples:
The Other Jimmy 31:8ea194f6145b 144 0x00004308 0x7c ./BUILD/K64F/GCC_ARM/mbed-os/hal/targets/hal/TARGET_Freescale/TARGET_KPSDK_MCUS/spi_api.o
The Other Jimmy 31:8ea194f6145b 145 .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
screamer 29:1210849dba19 146
screamer 29:1210849dba19 147 Positional arguments:
screamer 29:1210849dba19 148 line - the line to parse a section from
screamer 8:a8ac6ed29081 149 """
screamer 29:1210849dba19 150 rex_address_len_name = re.compile(
screamer 29:1210849dba19 151 r'^\s+.*0x(\w{8,16})\s+0x(\w+)\s(.+)$')
screamer 8:a8ac6ed29081 152
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 153 test_address_len_name = re.match(rex_address_len_name, line)
screamer 8:a8ac6ed29081 154
screamer 8:a8ac6ed29081 155 if test_address_len_name:
screamer 8:a8ac6ed29081 156
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 157 if int(test_address_len_name.group(2), 16) == 0: # size == 0
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 158 return ["", 0] # no valid entry
screamer 8:a8ac6ed29081 159 else:
screamer 29:1210849dba19 160 m_name, _ = self.path_object_to_module_name(
screamer 29:1210849dba19 161 test_address_len_name.group(3))
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 162 m_size = int(test_address_len_name.group(2), 16)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 163 return [m_name, m_size]
screamer 8:a8ac6ed29081 164
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 165 else: # special corner case for *fill* sections
screamer 8:a8ac6ed29081 166 # example
screamer 8:a8ac6ed29081 167 # *fill* 0x0000abe4 0x4
screamer 8:a8ac6ed29081 168 rex_address_len = r'^\s+\*fill\*\s+0x(\w{8,16})\s+0x(\w+).*$'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 169 test_address_len = re.match(rex_address_len, line)
screamer 8:a8ac6ed29081 170
screamer 8:a8ac6ed29081 171 if test_address_len:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 172 if int(test_address_len.group(2), 16) == 0: # size == 0
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 173 return ["", 0] # no valid entry
screamer 8:a8ac6ed29081 174 else:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 175 m_name = 'Fill'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 176 m_size = int(test_address_len.group(2), 16)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 177 return [m_name, m_size]
screamer 8:a8ac6ed29081 178 else:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 179 return ["", 0] # no valid entry
screamer 8:a8ac6ed29081 180
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 181 def parse_map_file_gcc(self, file_desc):
screamer 29:1210849dba19 182 """ Main logic to decode gcc map files
screamer 29:1210849dba19 183
screamer 29:1210849dba19 184 Positional arguments:
screamer 29:1210849dba19 185 file_desc - a stream object to parse as a gcc map file
screamer 8:a8ac6ed29081 186 """
screamer 8:a8ac6ed29081 187
screamer 8:a8ac6ed29081 188 current_section = 'unknown'
screamer 8:a8ac6ed29081 189
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 190 with file_desc as infile:
screamer 8:a8ac6ed29081 191
screamer 8:a8ac6ed29081 192 # Search area to parse
screamer 8:a8ac6ed29081 193 for line in infile:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 194 if line.startswith('Linker script and memory map'):
screamer 8:a8ac6ed29081 195 current_section = "unknown"
screamer 8:a8ac6ed29081 196 break
screamer 8:a8ac6ed29081 197
screamer 8:a8ac6ed29081 198 # Start decoding the map file
screamer 8:a8ac6ed29081 199 for line in infile:
screamer 8:a8ac6ed29081 200
screamer 8:a8ac6ed29081 201 change_section = self.check_new_section_gcc(line)
screamer 8:a8ac6ed29081 202
screamer 8:a8ac6ed29081 203 if change_section == "OUTPUT": # finish parsing file: exit
screamer 8:a8ac6ed29081 204 break
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 205 elif change_section != False:
screamer 8:a8ac6ed29081 206 current_section = change_section
screamer 8:a8ac6ed29081 207
screamer 8:a8ac6ed29081 208 [module_name, module_size] = self.parse_section_gcc(line)
screamer 8:a8ac6ed29081 209
screamer 8:a8ac6ed29081 210 if module_size == 0 or module_name == "":
screamer 8:a8ac6ed29081 211 pass
screamer 8:a8ac6ed29081 212 else:
screamer 8:a8ac6ed29081 213 self.module_add(module_name, module_size, current_section)
screamer 8:a8ac6ed29081 214
screamer 29:1210849dba19 215 if DEBUG:
screamer 8:a8ac6ed29081 216 print "Line: %s" % line,
screamer 29:1210849dba19 217 print "Module: %s\tSection: %s\tSize: %s" % \
screamer 29:1210849dba19 218 (module_name, current_section, module_size)
screamer 8:a8ac6ed29081 219 raw_input("----------")
screamer 8:a8ac6ed29081 220
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 221 def parse_section_armcc(self, line):
screamer 29:1210849dba19 222 """ Parse data from an armcc map file
screamer 29:1210849dba19 223
screamer 29:1210849dba19 224 Examples of armcc map file:
screamer 29:1210849dba19 225 Base_Addr Size Type Attr Idx E Section Name Object
screamer 29:1210849dba19 226 0x00000000 0x00000400 Data RO 11222 RESET startup_MK64F12.o
screamer 29:1210849dba19 227 0x00000410 0x00000008 Code RO 49364 * !!!main c_w.l(__main.o)
screamer 29:1210849dba19 228
screamer 29:1210849dba19 229 Positional arguments:
screamer 29:1210849dba19 230 line - the line to parse the section data from
screamer 8:a8ac6ed29081 231 """
screamer 8:a8ac6ed29081 232
screamer 29:1210849dba19 233 test_rex_armcc = re.match(RE_ARMCC, line)
screamer 8:a8ac6ed29081 234
screamer 8:a8ac6ed29081 235 if test_rex_armcc:
screamer 8:a8ac6ed29081 236
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 237 size = int(test_rex_armcc.group(2), 16)
screamer 8:a8ac6ed29081 238
screamer 8:a8ac6ed29081 239 if test_rex_armcc.group(4) == 'RO':
screamer 8:a8ac6ed29081 240 section = '.text'
screamer 8:a8ac6ed29081 241 else:
screamer 8:a8ac6ed29081 242 if test_rex_armcc.group(3) == 'Data':
screamer 8:a8ac6ed29081 243 section = '.data'
screamer 8:a8ac6ed29081 244 elif test_rex_armcc.group(3) == 'Zero':
screamer 8:a8ac6ed29081 245 section = '.bss'
screamer 8:a8ac6ed29081 246 else:
screamer 8:a8ac6ed29081 247 print "BUG armcc map parser"
screamer 8:a8ac6ed29081 248 raw_input()
screamer 8:a8ac6ed29081 249
screamer 8:a8ac6ed29081 250 # lookup object in dictionary and return module name
screamer 8:a8ac6ed29081 251 object_name = test_rex_armcc.group(6)
screamer 8:a8ac6ed29081 252 if object_name in self.object_to_module:
screamer 8:a8ac6ed29081 253 module_name = self.object_to_module[object_name]
screamer 8:a8ac6ed29081 254 else:
screamer 8:a8ac6ed29081 255 module_name = 'Misc'
screamer 8:a8ac6ed29081 256
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 257 return [module_name, size, section]
screamer 8:a8ac6ed29081 258
screamer 8:a8ac6ed29081 259 else:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 260 return ["", 0, ""] # no valid entry
screamer 8:a8ac6ed29081 261
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 262 def parse_section_iar(self, line):
screamer 29:1210849dba19 263 """ Parse data from an IAR map file
screamer 29:1210849dba19 264
screamer 29:1210849dba19 265 Examples of IAR map file:
screamer 29:1210849dba19 266 Section Kind Address Size Object
screamer 29:1210849dba19 267 .intvec ro code 0x00000000 0x198 startup_MK64F12.o [15]
screamer 29:1210849dba19 268 .rodata const 0x00000198 0x0 zero_init3.o [133]
screamer 29:1210849dba19 269 .iar.init_table const 0x00008384 0x2c - Linker created -
screamer 29:1210849dba19 270 Initializer bytes const 0x00000198 0xb2 <for P3 s0>
screamer 29:1210849dba19 271 .data inited 0x20000000 0xd4 driverAtmelRFInterface.o [70]
screamer 29:1210849dba19 272 .bss zero 0x20000598 0x318 RTX_Conf_CM.o [4]
screamer 29:1210849dba19 273 .iar.dynexit uninit 0x20001448 0x204 <Block tail>
screamer 29:1210849dba19 274 HEAP uninit 0x20001650 0x10000 <Block tail>
screamer 29:1210849dba19 275
screamer 29:1210849dba19 276 Positional_arguments:
screamer 29:1210849dba19 277 line - the line to parse section data from
screamer 8:a8ac6ed29081 278 """
screamer 8:a8ac6ed29081 279
screamer 29:1210849dba19 280 test_rex_iar = re.match(RE_IAR, line)
screamer 8:a8ac6ed29081 281
screamer 8:a8ac6ed29081 282 if test_rex_iar:
screamer 8:a8ac6ed29081 283
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 284 size = int(test_rex_iar.group(4), 16)
screamer 8:a8ac6ed29081 285
screamer 29:1210849dba19 286 if test_rex_iar.group(2) == 'const' or \
screamer 29:1210849dba19 287 test_rex_iar.group(2) == 'ro code':
screamer 8:a8ac6ed29081 288 section = '.text'
screamer 29:1210849dba19 289 elif test_rex_iar.group(2) == 'zero' or \
screamer 29:1210849dba19 290 test_rex_iar.group(2) == 'uninit':
screamer 8:a8ac6ed29081 291 if test_rex_iar.group(1)[0:4] == 'HEAP':
screamer 8:a8ac6ed29081 292 section = '.heap'
screamer 8:a8ac6ed29081 293 elif test_rex_iar.group(1)[0:6] == 'CSTACK':
screamer 8:a8ac6ed29081 294 section = '.stack'
screamer 8:a8ac6ed29081 295 else:
screamer 8:a8ac6ed29081 296 section = '.bss' # default section
screamer 8:a8ac6ed29081 297
screamer 8:a8ac6ed29081 298 elif test_rex_iar.group(2) == 'inited':
screamer 8:a8ac6ed29081 299 section = '.data'
screamer 8:a8ac6ed29081 300 else:
screamer 8:a8ac6ed29081 301 print "BUG IAR map parser"
screamer 8:a8ac6ed29081 302 raw_input()
screamer 8:a8ac6ed29081 303
screamer 8:a8ac6ed29081 304 # lookup object in dictionary and return module name
screamer 8:a8ac6ed29081 305 object_name = test_rex_iar.group(5)
screamer 8:a8ac6ed29081 306 if object_name in self.object_to_module:
screamer 8:a8ac6ed29081 307 module_name = self.object_to_module[object_name]
screamer 8:a8ac6ed29081 308 else:
screamer 8:a8ac6ed29081 309 module_name = 'Misc'
screamer 8:a8ac6ed29081 310
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 311 return [module_name, size, section]
screamer 8:a8ac6ed29081 312
screamer 8:a8ac6ed29081 313 else:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 314 return ["", 0, ""] # no valid entry
screamer 8:a8ac6ed29081 315
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 316 def parse_map_file_armcc(self, file_desc):
screamer 29:1210849dba19 317 """ Main logic to decode armc5 map files
screamer 29:1210849dba19 318
screamer 29:1210849dba19 319 Positional arguments:
screamer 29:1210849dba19 320 file_desc - a file like object to parse as an armc5 map file
screamer 8:a8ac6ed29081 321 """
screamer 8:a8ac6ed29081 322
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 323 with file_desc as infile:
screamer 8:a8ac6ed29081 324
screamer 8:a8ac6ed29081 325 # Search area to parse
screamer 8:a8ac6ed29081 326 for line in infile:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 327 if line.startswith(' Base Addr Size'):
screamer 8:a8ac6ed29081 328 break
screamer 8:a8ac6ed29081 329
screamer 8:a8ac6ed29081 330 # Start decoding the map file
screamer 8:a8ac6ed29081 331 for line in infile:
screamer 8:a8ac6ed29081 332
screamer 8:a8ac6ed29081 333 [name, size, section] = self.parse_section_armcc(line)
screamer 8:a8ac6ed29081 334
screamer 8:a8ac6ed29081 335 if size == 0 or name == "" or section == "":
screamer 8:a8ac6ed29081 336 pass
screamer 8:a8ac6ed29081 337 else:
screamer 8:a8ac6ed29081 338 self.module_add(name, size, section)
screamer 8:a8ac6ed29081 339
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 340 def parse_map_file_iar(self, file_desc):
screamer 29:1210849dba19 341 """ Main logic to decode IAR map files
screamer 29:1210849dba19 342
screamer 29:1210849dba19 343 Positional arguments:
screamer 29:1210849dba19 344 file_desc - a file like object to parse as an IAR map file
screamer 8:a8ac6ed29081 345 """
screamer 8:a8ac6ed29081 346
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 347 with file_desc as infile:
screamer 8:a8ac6ed29081 348
screamer 8:a8ac6ed29081 349 # Search area to parse
screamer 8:a8ac6ed29081 350 for line in infile:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 351 if line.startswith(' Section '):
screamer 8:a8ac6ed29081 352 break
screamer 8:a8ac6ed29081 353
screamer 8:a8ac6ed29081 354 # Start decoding the map file
screamer 8:a8ac6ed29081 355 for line in infile:
screamer 8:a8ac6ed29081 356
screamer 8:a8ac6ed29081 357 [name, size, section] = self.parse_section_iar(line)
screamer 8:a8ac6ed29081 358
screamer 8:a8ac6ed29081 359 if size == 0 or name == "" or section == "":
screamer 8:a8ac6ed29081 360 pass
screamer 8:a8ac6ed29081 361 else:
screamer 8:a8ac6ed29081 362 self.module_add(name, size, section)
screamer 8:a8ac6ed29081 363
The Other Jimmy 31:8ea194f6145b 364 def search_objects(self, path):
The Other Jimmy 31:8ea194f6145b 365 """ Searches for object files and creates mapping: object --> module
screamer 29:1210849dba19 366
screamer 29:1210849dba19 367 Positional arguments:
screamer 29:1210849dba19 368 path - the path to an object file
screamer 8:a8ac6ed29081 369 """
screamer 8:a8ac6ed29081 370
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 371 path = path.replace('\\', '/')
screamer 8:a8ac6ed29081 372
screamer 8:a8ac6ed29081 373 # check location of map file
The Other Jimmy 31:8ea194f6145b 374 rex = r'^(.+)' + r'\/(.+\.map)$'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 375 test_rex = re.match(rex, path)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 376
screamer 8:a8ac6ed29081 377 if test_rex:
The Other Jimmy 31:8ea194f6145b 378 search_path = test_rex.group(1) + '/mbed-os/'
screamer 8:a8ac6ed29081 379 else:
The Other Jimmy 31:8ea194f6145b 380 print "Warning: this doesn't look like an mbed project"
screamer 8:a8ac6ed29081 381 return
screamer 8:a8ac6ed29081 382
screamer 29:1210849dba19 383 for root, _, obj_files in os.walk(search_path):
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 384 for obj_file in obj_files:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 385 if obj_file.endswith(".o"):
screamer 29:1210849dba19 386 module_name, object_name = self.path_object_to_module_name(
screamer 29:1210849dba19 387 os.path.join(root, obj_file))
screamer 8:a8ac6ed29081 388
screamer 8:a8ac6ed29081 389 if object_name in self.object_to_module:
screamer 29:1210849dba19 390 if DEBUG:
screamer 29:1210849dba19 391 print "WARNING: multiple usages of object file: %s"\
screamer 29:1210849dba19 392 % object_name
screamer 29:1210849dba19 393 print " Current: %s" % \
screamer 29:1210849dba19 394 self.object_to_module[object_name]
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 395 print " New: %s" % module_name
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 396 print " "
screamer 8:a8ac6ed29081 397 else:
screamer 8:a8ac6ed29081 398 self.object_to_module.update({object_name:module_name})
screamer 8:a8ac6ed29081 399
screamer 22:9e85236d8716 400 export_formats = ["json", "csv-ci", "table"]
screamer 22:9e85236d8716 401
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 402 def generate_output(self, export_format, file_output=None):
screamer 29:1210849dba19 403 """ Generates summary of memory map data
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 404
screamer 29:1210849dba19 405 Positional arguments:
screamer 29:1210849dba19 406 export_format - the format to dump
screamer 29:1210849dba19 407
screamer 29:1210849dba19 408 Keyword arguments:
screamer 29:1210849dba19 409 file_desc - descriptor (either stdout or file)
The Other Jimmy 31:8ea194f6145b 410
The Other Jimmy 31:8ea194f6145b 411 Returns: generated string for the 'table' format, otherwise None
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 412 """
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 413
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 414 try:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 415 if file_output:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 416 file_desc = open(file_output, 'wb')
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 417 else:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 418 file_desc = sys.stdout
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 419 except IOError as error:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 420 print "I/O error({0}): {1}".format(error.errno, error.strerror)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 421 return False
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 422
screamer 29:1210849dba19 423 to_call = {'json': self.generate_json,
screamer 29:1210849dba19 424 'csv-ci': self.generate_csv,
screamer 29:1210849dba19 425 'table': self.generate_table}[export_format]
The Other Jimmy 31:8ea194f6145b 426 output = to_call(file_desc)
screamer 29:1210849dba19 427
screamer 29:1210849dba19 428 if file_desc is not sys.stdout:
screamer 29:1210849dba19 429 file_desc.close()
screamer 29:1210849dba19 430
The Other Jimmy 31:8ea194f6145b 431 return output
The Other Jimmy 31:8ea194f6145b 432
The Other Jimmy 31:8ea194f6145b 433 def generate_json(self, file_desc):
screamer 29:1210849dba19 434 """Generate a json file from a memory map
screamer 29:1210849dba19 435
screamer 29:1210849dba19 436 Positional arguments:
screamer 29:1210849dba19 437 file_desc - the file to write out the final report to
screamer 29:1210849dba19 438 """
The Other Jimmy 31:8ea194f6145b 439 file_desc.write(json.dumps(self.mem_report, indent=4))
screamer 29:1210849dba19 440 file_desc.write('\n')
screamer 29:1210849dba19 441
The Other Jimmy 31:8ea194f6145b 442 return None
The Other Jimmy 31:8ea194f6145b 443
The Other Jimmy 31:8ea194f6145b 444 def generate_csv(self, file_desc):
screamer 29:1210849dba19 445 """Generate a CSV file from a memoy map
screamer 29:1210849dba19 446
screamer 29:1210849dba19 447 Positional arguments:
screamer 29:1210849dba19 448 file_desc - the file to write out the final report to
screamer 29:1210849dba19 449 """
screamer 29:1210849dba19 450 csv_writer = csv.writer(file_desc, delimiter=',',
The Other Jimmy 31:8ea194f6145b 451 quoting=csv.QUOTE_MINIMAL)
screamer 29:1210849dba19 452
screamer 29:1210849dba19 453 csv_module_section = []
screamer 29:1210849dba19 454 csv_sizes = []
screamer 29:1210849dba19 455 for i in sorted(self.modules):
screamer 29:1210849dba19 456 for k in self.print_sections:
screamer 29:1210849dba19 457 csv_module_section += [i+k]
screamer 29:1210849dba19 458 csv_sizes += [self.modules[i][k]]
screamer 29:1210849dba19 459
screamer 29:1210849dba19 460 csv_module_section += ['static_ram']
The Other Jimmy 31:8ea194f6145b 461 csv_sizes += [self.mem_summary['static_ram']]
screamer 29:1210849dba19 462
screamer 29:1210849dba19 463 csv_module_section += ['heap']
The Other Jimmy 31:8ea194f6145b 464 if self.mem_summary['heap'] == 0:
screamer 29:1210849dba19 465 csv_sizes += ['unknown']
screamer 29:1210849dba19 466 else:
The Other Jimmy 31:8ea194f6145b 467 csv_sizes += [self.mem_summary['heap']]
screamer 29:1210849dba19 468
screamer 29:1210849dba19 469 csv_module_section += ['stack']
The Other Jimmy 31:8ea194f6145b 470 if self.mem_summary['stack'] == 0:
screamer 29:1210849dba19 471 csv_sizes += ['unknown']
screamer 29:1210849dba19 472 else:
The Other Jimmy 31:8ea194f6145b 473 csv_sizes += [self.mem_summary['stack']]
screamer 29:1210849dba19 474
screamer 29:1210849dba19 475 csv_module_section += ['total_ram']
The Other Jimmy 31:8ea194f6145b 476 csv_sizes += [self.mem_summary['total_ram']]
screamer 29:1210849dba19 477
screamer 29:1210849dba19 478 csv_module_section += ['total_flash']
The Other Jimmy 31:8ea194f6145b 479 csv_sizes += [self.mem_summary['total_flash']]
screamer 29:1210849dba19 480
screamer 29:1210849dba19 481 csv_writer.writerow(csv_module_section)
screamer 29:1210849dba19 482 csv_writer.writerow(csv_sizes)
screamer 29:1210849dba19 483
The Other Jimmy 31:8ea194f6145b 484 return None
The Other Jimmy 31:8ea194f6145b 485
The Other Jimmy 31:8ea194f6145b 486 def generate_table(self, file_desc):
screamer 29:1210849dba19 487 """Generate a table from a memoy map
screamer 29:1210849dba19 488
screamer 29:1210849dba19 489 Positional arguments:
screamer 29:1210849dba19 490 file_desc - the file to write out the final report to
The Other Jimmy 31:8ea194f6145b 491
The Other Jimmy 31:8ea194f6145b 492 Returns: string of the generated table
screamer 29:1210849dba19 493 """
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 494 # Create table
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 495 columns = ['Module']
screamer 22:9e85236d8716 496 columns.extend(self.print_sections)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 497
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 498 table = PrettyTable(columns)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 499 table.align["Module"] = "l"
screamer 22:9e85236d8716 500 for col in self.print_sections:
screamer 22:9e85236d8716 501 table.align[col] = 'r'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 502
screamer 13:ab47a20b66f0 503 for i in list(self.print_sections):
screamer 13:ab47a20b66f0 504 table.align[i] = 'r'
screamer 13:ab47a20b66f0 505
The Other Jimmy 31:8ea194f6145b 506 for i in sorted(self.modules):
The Other Jimmy 31:8ea194f6145b 507 row = [i]
The Other Jimmy 31:8ea194f6145b 508
The Other Jimmy 31:8ea194f6145b 509 for k in self.print_sections:
The Other Jimmy 31:8ea194f6145b 510 row.append(self.modules[i][k])
The Other Jimmy 31:8ea194f6145b 511
The Other Jimmy 31:8ea194f6145b 512 table.add_row(row)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 513
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 514 subtotal_row = ['Subtotals']
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 515 for k in self.print_sections:
The Other Jimmy 31:8ea194f6145b 516 subtotal_row.append(self.subtotal[k])
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 517
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 518 table.add_row(subtotal_row)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 519
The Other Jimmy 31:8ea194f6145b 520 output = table.get_string()
The Other Jimmy 31:8ea194f6145b 521 output += '\n'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 522
The Other Jimmy 31:8ea194f6145b 523 if self.mem_summary['heap'] == 0:
The Other Jimmy 31:8ea194f6145b 524 output += "Allocated Heap: unknown\n"
screamer 29:1210849dba19 525 else:
The Other Jimmy 31:8ea194f6145b 526 output += "Allocated Heap: %s bytes\n" % \
The Other Jimmy 31:8ea194f6145b 527 str(self.mem_summary['heap'])
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 528
The Other Jimmy 31:8ea194f6145b 529 if self.mem_summary['stack'] == 0:
The Other Jimmy 31:8ea194f6145b 530 output += "Allocated Stack: unknown\n"
screamer 29:1210849dba19 531 else:
The Other Jimmy 31:8ea194f6145b 532 output += "Allocated Stack: %s bytes\n" % \
The Other Jimmy 31:8ea194f6145b 533 str(self.mem_summary['stack'])
screamer 13:ab47a20b66f0 534
The Other Jimmy 31:8ea194f6145b 535 output += "Total Static RAM memory (data + bss): %s bytes\n" % \
The Other Jimmy 31:8ea194f6145b 536 str(self.mem_summary['static_ram'])
The Other Jimmy 31:8ea194f6145b 537 output += "Total RAM memory (data + bss + heap + stack): %s bytes\n" % \
The Other Jimmy 31:8ea194f6145b 538 str(self.mem_summary['total_ram'])
The Other Jimmy 31:8ea194f6145b 539 output += "Total Flash memory (text + data + misc): %s bytes\n" % \
The Other Jimmy 31:8ea194f6145b 540 str(self.mem_summary['total_flash'])
The Other Jimmy 31:8ea194f6145b 541
The Other Jimmy 31:8ea194f6145b 542 return output
screamer 22:9e85236d8716 543
The Other Jimmy 36:96847d42f010 544 toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "GCC_CR", "IAR"]
screamer 22:9e85236d8716 545
The Other Jimmy 31:8ea194f6145b 546 def compute_report(self):
The Other Jimmy 31:8ea194f6145b 547 for k in self.sections:
The Other Jimmy 31:8ea194f6145b 548 self.subtotal[k] = 0
The Other Jimmy 31:8ea194f6145b 549
The Other Jimmy 31:8ea194f6145b 550 for i in sorted(self.modules):
The Other Jimmy 31:8ea194f6145b 551 for k in self.sections:
The Other Jimmy 31:8ea194f6145b 552 self.subtotal[k] += self.modules[i][k]
The Other Jimmy 31:8ea194f6145b 553
The Other Jimmy 31:8ea194f6145b 554 # Calculate misc flash sections
The Other Jimmy 31:8ea194f6145b 555 self.misc_flash_mem = 0
The Other Jimmy 31:8ea194f6145b 556 for i in self.modules:
The Other Jimmy 31:8ea194f6145b 557 for k in self.misc_flash_sections:
The Other Jimmy 31:8ea194f6145b 558 if self.modules[i][k]:
The Other Jimmy 31:8ea194f6145b 559 self.misc_flash_mem += self.modules[i][k]
The Other Jimmy 31:8ea194f6145b 560
The Other Jimmy 31:8ea194f6145b 561 self.mem_summary = {
The Other Jimmy 31:8ea194f6145b 562 'static_ram': (self.subtotal['.data'] + self.subtotal['.bss']),
The Other Jimmy 31:8ea194f6145b 563 'heap': (self.subtotal['.heap']),
The Other Jimmy 31:8ea194f6145b 564 'stack': (self.subtotal['.stack']),
The Other Jimmy 31:8ea194f6145b 565 'total_ram': (self.subtotal['.data'] + self.subtotal['.bss'] +
The Other Jimmy 31:8ea194f6145b 566 self.subtotal['.heap']+self.subtotal['.stack']),
The Other Jimmy 31:8ea194f6145b 567 'total_flash': (self.subtotal['.text'] + self.subtotal['.data'] +
The Other Jimmy 31:8ea194f6145b 568 self.misc_flash_mem),
The Other Jimmy 31:8ea194f6145b 569 }
The Other Jimmy 31:8ea194f6145b 570
The Other Jimmy 31:8ea194f6145b 571 self.mem_report = []
The Other Jimmy 31:8ea194f6145b 572 for i in sorted(self.modules):
The Other Jimmy 31:8ea194f6145b 573 self.mem_report.append({
The Other Jimmy 31:8ea194f6145b 574 "module":i,
The Other Jimmy 31:8ea194f6145b 575 "size":{
The Other Jimmy 31:8ea194f6145b 576 k:self.modules[i][k] for k in self.print_sections
The Other Jimmy 31:8ea194f6145b 577 }
The Other Jimmy 31:8ea194f6145b 578 })
The Other Jimmy 31:8ea194f6145b 579
The Other Jimmy 31:8ea194f6145b 580 self.mem_report.append({
The Other Jimmy 31:8ea194f6145b 581 'summary': self.mem_summary
The Other Jimmy 31:8ea194f6145b 582 })
The Other Jimmy 31:8ea194f6145b 583
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 584 def parse(self, mapfile, toolchain):
screamer 29:1210849dba19 585 """ Parse and decode map file depending on the toolchain
screamer 29:1210849dba19 586
screamer 29:1210849dba19 587 Positional arguments:
screamer 29:1210849dba19 588 mapfile - the file name of the memory map file
screamer 29:1210849dba19 589 toolchain - the toolchain used to create the file
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 590 """
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 591
screamer 22:9e85236d8716 592 result = True
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 593 try:
screamer 29:1210849dba19 594 with open(mapfile, 'r') as file_input:
screamer 29:1210849dba19 595 if toolchain == "ARM" or toolchain == "ARM_STD" or\
screamer 29:1210849dba19 596 toolchain == "ARM_MICRO":
The Other Jimmy 31:8ea194f6145b 597 self.search_objects(os.path.abspath(mapfile))
screamer 22:9e85236d8716 598 self.parse_map_file_armcc(file_input)
The Other Jimmy 36:96847d42f010 599 elif toolchain == "GCC_ARM" or toolchain == "GCC_CR":
screamer 22:9e85236d8716 600 self.parse_map_file_gcc(file_input)
screamer 22:9e85236d8716 601 elif toolchain == "IAR":
The Other Jimmy 31:8ea194f6145b 602 self.search_objects(os.path.abspath(mapfile))
screamer 22:9e85236d8716 603 self.parse_map_file_iar(file_input)
screamer 22:9e85236d8716 604 else:
screamer 22:9e85236d8716 605 result = False
The Other Jimmy 31:8ea194f6145b 606
The Other Jimmy 31:8ea194f6145b 607 self.compute_report()
The Other Jimmy 31:8ea194f6145b 608
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 609 except IOError as error:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 610 print "I/O error({0}): {1}".format(error.errno, error.strerror)
screamer 22:9e85236d8716 611 result = False
screamer 22:9e85236d8716 612 return result
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 613
screamer 8:a8ac6ed29081 614 def main():
screamer 29:1210849dba19 615 """Entry Point"""
screamer 8:a8ac6ed29081 616
The Other Jimmy 31:8ea194f6145b 617 version = '0.3.12'
screamer 8:a8ac6ed29081 618
screamer 8:a8ac6ed29081 619 # Parser handling
screamer 29:1210849dba19 620 parser = argparse.ArgumentParser(
screamer 29:1210849dba19 621 description="Memory Map File Analyser for ARM mbed\nversion %s" %
screamer 29:1210849dba19 622 version)
screamer 8:a8ac6ed29081 623
screamer 29:1210849dba19 624 parser.add_argument(
screamer 29:1210849dba19 625 'file', type=argparse_filestring_type, help='memory map file')
screamer 8:a8ac6ed29081 626
screamer 29:1210849dba19 627 parser.add_argument(
screamer 29:1210849dba19 628 '-t', '--toolchain', dest='toolchain',
screamer 29:1210849dba19 629 help='select a toolchain used to build the memory map file (%s)' %
screamer 29:1210849dba19 630 ", ".join(MemapParser.toolchains),
screamer 29:1210849dba19 631 required=True,
screamer 29:1210849dba19 632 type=argparse_uppercase_type(MemapParser.toolchains, "toolchain"))
screamer 8:a8ac6ed29081 633
screamer 29:1210849dba19 634 parser.add_argument(
screamer 29:1210849dba19 635 '-o', '--output', help='output file name', required=False)
screamer 8:a8ac6ed29081 636
screamer 29:1210849dba19 637 parser.add_argument(
screamer 29:1210849dba19 638 '-e', '--export', dest='export', required=False, default='table',
screamer 29:1210849dba19 639 type=argparse_lowercase_hyphen_type(MemapParser.export_formats,
screamer 29:1210849dba19 640 'export format'),
screamer 29:1210849dba19 641 help="export format (examples: %s: default)" %
screamer 29:1210849dba19 642 ", ".join(MemapParser.export_formats))
screamer 8:a8ac6ed29081 643
screamer 8:a8ac6ed29081 644 parser.add_argument('-v', '--version', action='version', version=version)
The Other Jimmy 31:8ea194f6145b 645
The Other Jimmy 31:8ea194f6145b 646 parser.add_argument('-d', '--detailed', action='store_true', help='Displays the elements in "Misc" in a detailed fashion', required=False)
screamer 8:a8ac6ed29081 647
screamer 8:a8ac6ed29081 648 # Parse/run command
screamer 8:a8ac6ed29081 649 if len(sys.argv) <= 1:
screamer 8:a8ac6ed29081 650 parser.print_help()
screamer 8:a8ac6ed29081 651 sys.exit(1)
screamer 8:a8ac6ed29081 652
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 653
screamer 29:1210849dba19 654 args = parser.parse_args()
screamer 8:a8ac6ed29081 655
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 656 # Create memap object
The Other Jimmy 31:8ea194f6145b 657 memap = MemapParser(detailed_misc=args.detailed)
screamer 8:a8ac6ed29081 658
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 659 # Parse and decode a map file
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 660 if args.file and args.toolchain:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 661 if memap.parse(args.file, args.toolchain) is False:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 662 sys.exit(0)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 663
The Other Jimmy 31:8ea194f6145b 664 returned_string = None
screamer 8:a8ac6ed29081 665 # Write output in file
screamer 8:a8ac6ed29081 666 if args.output != None:
The Other Jimmy 31:8ea194f6145b 667 returned_string = memap.generate_output(args.export, args.output)
screamer 8:a8ac6ed29081 668 else: # Write output in screen
The Other Jimmy 31:8ea194f6145b 669 returned_string = memap.generate_output(args.export)
The Other Jimmy 31:8ea194f6145b 670
The Other Jimmy 31:8ea194f6145b 671 if args.export == 'table' and returned_string:
The Other Jimmy 31:8ea194f6145b 672 print returned_string
screamer 8:a8ac6ed29081 673
screamer 8:a8ac6ed29081 674 sys.exit(0)
screamer 8:a8ac6ed29081 675
screamer 8:a8ac6ed29081 676 if __name__ == "__main__":
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 677 main()