Clone of official tools

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