Clone of official tools

Committer:
theotherjimmy
Date:
Wed Oct 25 14:46:50 2017 -0500
Revision:
41:2a77626a4c21
Parent:
40:7d3fa6b99b2b
Child:
43:2a7da56ebd24
Update to track Mbed OS 5.6.3

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 temp = '[lib]' + '/'+ current_library + '/'+ object_name
theotherjimmy 40:7d3fa6b99b2b 473 self.module_replace(object_name, temp)
theotherjimmy 40:7d3fa6b99b2b 474
screamer 8:a8ac6ed29081 475
theotherjimmy 40:7d3fa6b99b2b 476 def reduce_depth(self, depth):
theotherjimmy 40:7d3fa6b99b2b 477 """
theotherjimmy 40:7d3fa6b99b2b 478 populates the short_modules attribute with a truncated module list
screamer 8:a8ac6ed29081 479
theotherjimmy 40:7d3fa6b99b2b 480 (1) depth = 1:
theotherjimmy 40:7d3fa6b99b2b 481 main.o
theotherjimmy 40:7d3fa6b99b2b 482 mbed-os
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 483
theotherjimmy 40:7d3fa6b99b2b 484 (2) depth = 2:
theotherjimmy 40:7d3fa6b99b2b 485 main.o
theotherjimmy 40:7d3fa6b99b2b 486 mbed-os/test.o
theotherjimmy 40:7d3fa6b99b2b 487 mbed-os/drivers
screamer 8:a8ac6ed29081 488
theotherjimmy 40:7d3fa6b99b2b 489 """
theotherjimmy 40:7d3fa6b99b2b 490 if depth == 0 or depth == None:
theotherjimmy 40:7d3fa6b99b2b 491 self.short_modules = deepcopy(self.modules)
theotherjimmy 40:7d3fa6b99b2b 492 else:
theotherjimmy 40:7d3fa6b99b2b 493 self.short_modules = dict()
theotherjimmy 40:7d3fa6b99b2b 494 for module_name, v in self.modules.items():
theotherjimmy 40:7d3fa6b99b2b 495 split_name = module_name.split('/')
theotherjimmy 40:7d3fa6b99b2b 496 if split_name[0] == '':
theotherjimmy 40:7d3fa6b99b2b 497 split_name = split_name[1:]
theotherjimmy 40:7d3fa6b99b2b 498 new_name = "/".join(split_name[:depth])
theotherjimmy 40:7d3fa6b99b2b 499 self.short_modules.setdefault(new_name, {})
theotherjimmy 40:7d3fa6b99b2b 500 for section_idx, value in v.items():
theotherjimmy 40:7d3fa6b99b2b 501 self.short_modules[new_name].setdefault(section_idx, 0)
theotherjimmy 40:7d3fa6b99b2b 502 self.short_modules[new_name][section_idx] += self.modules[module_name][section_idx]
screamer 8:a8ac6ed29081 503
screamer 8:a8ac6ed29081 504
screamer 22:9e85236d8716 505 export_formats = ["json", "csv-ci", "table"]
screamer 22:9e85236d8716 506
theotherjimmy 40:7d3fa6b99b2b 507 def generate_output(self, export_format, depth, file_output=None):
screamer 29:1210849dba19 508 """ Generates summary of memory map data
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 509
screamer 29:1210849dba19 510 Positional arguments:
screamer 29:1210849dba19 511 export_format - the format to dump
screamer 29:1210849dba19 512
screamer 29:1210849dba19 513 Keyword arguments:
screamer 29:1210849dba19 514 file_desc - descriptor (either stdout or file)
theotherjimmy 40:7d3fa6b99b2b 515 depth - directory depth on report
The Other Jimmy 31:8ea194f6145b 516
The Other Jimmy 31:8ea194f6145b 517 Returns: generated string for the 'table' format, otherwise None
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 518 """
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 519
theotherjimmy 40:7d3fa6b99b2b 520 self.reduce_depth(depth)
theotherjimmy 40:7d3fa6b99b2b 521 self.compute_report()
theotherjimmy 40:7d3fa6b99b2b 522
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 523 try:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 524 if file_output:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 525 file_desc = open(file_output, 'wb')
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 526 else:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 527 file_desc = sys.stdout
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 528 except IOError as error:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 529 print "I/O error({0}): {1}".format(error.errno, error.strerror)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 530 return False
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 531
screamer 29:1210849dba19 532 to_call = {'json': self.generate_json,
screamer 29:1210849dba19 533 'csv-ci': self.generate_csv,
screamer 29:1210849dba19 534 'table': self.generate_table}[export_format]
The Other Jimmy 31:8ea194f6145b 535 output = to_call(file_desc)
screamer 29:1210849dba19 536
screamer 29:1210849dba19 537 if file_desc is not sys.stdout:
screamer 29:1210849dba19 538 file_desc.close()
screamer 29:1210849dba19 539
The Other Jimmy 31:8ea194f6145b 540 return output
The Other Jimmy 31:8ea194f6145b 541
The Other Jimmy 31:8ea194f6145b 542 def generate_json(self, file_desc):
screamer 29:1210849dba19 543 """Generate a json file from a memory map
screamer 29:1210849dba19 544
screamer 29:1210849dba19 545 Positional arguments:
screamer 29:1210849dba19 546 file_desc - the file to write out the final report to
screamer 29:1210849dba19 547 """
The Other Jimmy 31:8ea194f6145b 548 file_desc.write(json.dumps(self.mem_report, indent=4))
screamer 29:1210849dba19 549 file_desc.write('\n')
screamer 29:1210849dba19 550
The Other Jimmy 31:8ea194f6145b 551 return None
The Other Jimmy 31:8ea194f6145b 552
The Other Jimmy 31:8ea194f6145b 553 def generate_csv(self, file_desc):
screamer 29:1210849dba19 554 """Generate a CSV file from a memoy map
screamer 29:1210849dba19 555
screamer 29:1210849dba19 556 Positional arguments:
screamer 29:1210849dba19 557 file_desc - the file to write out the final report to
screamer 29:1210849dba19 558 """
screamer 29:1210849dba19 559 csv_writer = csv.writer(file_desc, delimiter=',',
The Other Jimmy 31:8ea194f6145b 560 quoting=csv.QUOTE_MINIMAL)
screamer 29:1210849dba19 561
screamer 29:1210849dba19 562 csv_module_section = []
screamer 29:1210849dba19 563 csv_sizes = []
theotherjimmy 40:7d3fa6b99b2b 564 for i in sorted(self.short_modules):
screamer 29:1210849dba19 565 for k in self.print_sections:
screamer 29:1210849dba19 566 csv_module_section += [i+k]
theotherjimmy 40:7d3fa6b99b2b 567 csv_sizes += [self.short_modules[i][k]]
screamer 29:1210849dba19 568
screamer 29:1210849dba19 569 csv_module_section += ['static_ram']
The Other Jimmy 31:8ea194f6145b 570 csv_sizes += [self.mem_summary['static_ram']]
screamer 29:1210849dba19 571
screamer 29:1210849dba19 572 csv_module_section += ['total_flash']
The Other Jimmy 31:8ea194f6145b 573 csv_sizes += [self.mem_summary['total_flash']]
screamer 29:1210849dba19 574
screamer 29:1210849dba19 575 csv_writer.writerow(csv_module_section)
screamer 29:1210849dba19 576 csv_writer.writerow(csv_sizes)
screamer 29:1210849dba19 577
The Other Jimmy 31:8ea194f6145b 578 return None
The Other Jimmy 31:8ea194f6145b 579
The Other Jimmy 31:8ea194f6145b 580 def generate_table(self, file_desc):
screamer 29:1210849dba19 581 """Generate a table from a memoy map
screamer 29:1210849dba19 582
The Other Jimmy 31:8ea194f6145b 583 Returns: string of the generated table
screamer 29:1210849dba19 584 """
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 585 # Create table
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 586 columns = ['Module']
screamer 22:9e85236d8716 587 columns.extend(self.print_sections)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 588
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 589 table = PrettyTable(columns)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 590 table.align["Module"] = "l"
screamer 22:9e85236d8716 591 for col in self.print_sections:
screamer 22:9e85236d8716 592 table.align[col] = 'r'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 593
screamer 13:ab47a20b66f0 594 for i in list(self.print_sections):
screamer 13:ab47a20b66f0 595 table.align[i] = 'r'
screamer 13:ab47a20b66f0 596
theotherjimmy 40:7d3fa6b99b2b 597 for i in sorted(self.short_modules):
The Other Jimmy 31:8ea194f6145b 598 row = [i]
The Other Jimmy 31:8ea194f6145b 599
The Other Jimmy 31:8ea194f6145b 600 for k in self.print_sections:
theotherjimmy 40:7d3fa6b99b2b 601 row.append(self.short_modules[i][k])
The Other Jimmy 31:8ea194f6145b 602
The Other Jimmy 31:8ea194f6145b 603 table.add_row(row)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 604
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 605 subtotal_row = ['Subtotals']
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 606 for k in self.print_sections:
The Other Jimmy 31:8ea194f6145b 607 subtotal_row.append(self.subtotal[k])
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 608
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 609 table.add_row(subtotal_row)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 610
The Other Jimmy 31:8ea194f6145b 611 output = table.get_string()
The Other Jimmy 31:8ea194f6145b 612 output += '\n'
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 613
The Other Jimmy 31:8ea194f6145b 614 output += "Total Static RAM memory (data + bss): %s bytes\n" % \
The Other Jimmy 31:8ea194f6145b 615 str(self.mem_summary['static_ram'])
theotherjimmy 40:7d3fa6b99b2b 616 output += "Total Flash memory (text + data): %s bytes\n" % \
The Other Jimmy 31:8ea194f6145b 617 str(self.mem_summary['total_flash'])
The Other Jimmy 31:8ea194f6145b 618
The Other Jimmy 31:8ea194f6145b 619 return output
screamer 22:9e85236d8716 620
The Other Jimmy 36:96847d42f010 621 toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "GCC_CR", "IAR"]
screamer 22:9e85236d8716 622
The Other Jimmy 31:8ea194f6145b 623 def compute_report(self):
theotherjimmy 40:7d3fa6b99b2b 624 """ Generates summary of memory usage for main areas
theotherjimmy 40:7d3fa6b99b2b 625 """
The Other Jimmy 31:8ea194f6145b 626 for k in self.sections:
The Other Jimmy 31:8ea194f6145b 627 self.subtotal[k] = 0
The Other Jimmy 31:8ea194f6145b 628
theotherjimmy 40:7d3fa6b99b2b 629 for i in self.short_modules:
The Other Jimmy 31:8ea194f6145b 630 for k in self.sections:
theotherjimmy 40:7d3fa6b99b2b 631 self.short_modules[i].setdefault(k, 0)
theotherjimmy 40:7d3fa6b99b2b 632 self.subtotal[k] += self.short_modules[i][k]
The Other Jimmy 31:8ea194f6145b 633
The Other Jimmy 31:8ea194f6145b 634 self.mem_summary = {
The Other Jimmy 31:8ea194f6145b 635 'static_ram': (self.subtotal['.data'] + self.subtotal['.bss']),
theotherjimmy 40:7d3fa6b99b2b 636 'total_flash': (self.subtotal['.text'] + self.subtotal['.data']),
The Other Jimmy 31:8ea194f6145b 637 }
The Other Jimmy 31:8ea194f6145b 638
The Other Jimmy 31:8ea194f6145b 639 self.mem_report = []
theotherjimmy 40:7d3fa6b99b2b 640 for i in sorted(self.short_modules):
The Other Jimmy 31:8ea194f6145b 641 self.mem_report.append({
The Other Jimmy 31:8ea194f6145b 642 "module":i,
The Other Jimmy 31:8ea194f6145b 643 "size":{
theotherjimmy 40:7d3fa6b99b2b 644 k: self.short_modules[i][k] for k in self.print_sections
The Other Jimmy 31:8ea194f6145b 645 }
The Other Jimmy 31:8ea194f6145b 646 })
The Other Jimmy 31:8ea194f6145b 647
The Other Jimmy 31:8ea194f6145b 648 self.mem_report.append({
The Other Jimmy 31:8ea194f6145b 649 'summary': self.mem_summary
The Other Jimmy 31:8ea194f6145b 650 })
The Other Jimmy 31:8ea194f6145b 651
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 652 def parse(self, mapfile, toolchain):
screamer 29:1210849dba19 653 """ Parse and decode map file depending on the toolchain
screamer 29:1210849dba19 654
screamer 29:1210849dba19 655 Positional arguments:
screamer 29:1210849dba19 656 mapfile - the file name of the memory map file
screamer 29:1210849dba19 657 toolchain - the toolchain used to create the file
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 658 """
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 659
screamer 22:9e85236d8716 660 result = True
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 661 try:
screamer 29:1210849dba19 662 with open(mapfile, 'r') as file_input:
theotherjimmy 40:7d3fa6b99b2b 663 if toolchain in ("ARM", "ARM_STD", "ARM_MICRO", "ARMC6"):
screamer 22:9e85236d8716 664 self.parse_map_file_armcc(file_input)
The Other Jimmy 36:96847d42f010 665 elif toolchain == "GCC_ARM" or toolchain == "GCC_CR":
screamer 22:9e85236d8716 666 self.parse_map_file_gcc(file_input)
screamer 22:9e85236d8716 667 elif toolchain == "IAR":
screamer 22:9e85236d8716 668 self.parse_map_file_iar(file_input)
screamer 22:9e85236d8716 669 else:
screamer 22:9e85236d8716 670 result = False
theotherjimmy 40:7d3fa6b99b2b 671
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 672 except IOError as error:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 673 print "I/O error({0}): {1}".format(error.errno, error.strerror)
screamer 22:9e85236d8716 674 result = False
screamer 22:9e85236d8716 675 return result
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 676
screamer 8:a8ac6ed29081 677 def main():
screamer 29:1210849dba19 678 """Entry Point"""
screamer 8:a8ac6ed29081 679
theotherjimmy 40:7d3fa6b99b2b 680 version = '0.4.0'
screamer 8:a8ac6ed29081 681
screamer 8:a8ac6ed29081 682 # Parser handling
screamer 29:1210849dba19 683 parser = argparse.ArgumentParser(
screamer 29:1210849dba19 684 description="Memory Map File Analyser for ARM mbed\nversion %s" %
screamer 29:1210849dba19 685 version)
screamer 8:a8ac6ed29081 686
screamer 29:1210849dba19 687 parser.add_argument(
screamer 29:1210849dba19 688 'file', type=argparse_filestring_type, help='memory map file')
screamer 8:a8ac6ed29081 689
screamer 29:1210849dba19 690 parser.add_argument(
screamer 29:1210849dba19 691 '-t', '--toolchain', dest='toolchain',
screamer 29:1210849dba19 692 help='select a toolchain used to build the memory map file (%s)' %
screamer 29:1210849dba19 693 ", ".join(MemapParser.toolchains),
screamer 29:1210849dba19 694 required=True,
screamer 29:1210849dba19 695 type=argparse_uppercase_type(MemapParser.toolchains, "toolchain"))
screamer 8:a8ac6ed29081 696
screamer 29:1210849dba19 697 parser.add_argument(
theotherjimmy 40:7d3fa6b99b2b 698 '-d', '--depth', dest='depth', type=int,
theotherjimmy 40:7d3fa6b99b2b 699 help='specify directory depth level to display report', required=False)
theotherjimmy 40:7d3fa6b99b2b 700
theotherjimmy 40:7d3fa6b99b2b 701 parser.add_argument(
screamer 29:1210849dba19 702 '-o', '--output', help='output file name', required=False)
screamer 8:a8ac6ed29081 703
screamer 29:1210849dba19 704 parser.add_argument(
screamer 29:1210849dba19 705 '-e', '--export', dest='export', required=False, default='table',
screamer 29:1210849dba19 706 type=argparse_lowercase_hyphen_type(MemapParser.export_formats,
screamer 29:1210849dba19 707 'export format'),
screamer 29:1210849dba19 708 help="export format (examples: %s: default)" %
screamer 29:1210849dba19 709 ", ".join(MemapParser.export_formats))
screamer 8:a8ac6ed29081 710
screamer 8:a8ac6ed29081 711 parser.add_argument('-v', '--version', action='version', version=version)
screamer 8:a8ac6ed29081 712
screamer 8:a8ac6ed29081 713 # Parse/run command
screamer 8:a8ac6ed29081 714 if len(sys.argv) <= 1:
screamer 8:a8ac6ed29081 715 parser.print_help()
screamer 8:a8ac6ed29081 716 sys.exit(1)
screamer 8:a8ac6ed29081 717
screamer 29:1210849dba19 718 args = parser.parse_args()
screamer 8:a8ac6ed29081 719
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 720 # Create memap object
theotherjimmy 40:7d3fa6b99b2b 721 memap = MemapParser()
screamer 8:a8ac6ed29081 722
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 723 # Parse and decode a map file
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 724 if args.file and args.toolchain:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 725 if memap.parse(args.file, args.toolchain) is False:
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 726 sys.exit(0)
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 727
theotherjimmy 40:7d3fa6b99b2b 728 if args.depth is None:
theotherjimmy 40:7d3fa6b99b2b 729 depth = 2 # default depth level
theotherjimmy 40:7d3fa6b99b2b 730 else:
theotherjimmy 40:7d3fa6b99b2b 731 depth = args.depth
theotherjimmy 40:7d3fa6b99b2b 732
The Other Jimmy 31:8ea194f6145b 733 returned_string = None
screamer 8:a8ac6ed29081 734 # Write output in file
screamer 8:a8ac6ed29081 735 if args.output != None:
theotherjimmy 40:7d3fa6b99b2b 736 returned_string = memap.generate_output(args.export, \
theotherjimmy 40:7d3fa6b99b2b 737 depth, args.output)
screamer 8:a8ac6ed29081 738 else: # Write output in screen
theotherjimmy 40:7d3fa6b99b2b 739 returned_string = memap.generate_output(args.export, depth)
The Other Jimmy 31:8ea194f6145b 740
The Other Jimmy 31:8ea194f6145b 741 if args.export == 'table' and returned_string:
The Other Jimmy 31:8ea194f6145b 742 print returned_string
screamer 8:a8ac6ed29081 743
screamer 8:a8ac6ed29081 744 sys.exit(0)
screamer 8:a8ac6ed29081 745
screamer 8:a8ac6ed29081 746 if __name__ == "__main__":
Screamer@Y5070-M.virtuoso 9:2d27d77ada5c 747 main()