mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

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