mbed os with nrf51 internal bandgap enabled to read battery level

Dependents:   BLE_file_test BLE_Blink ExternalEncoder

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

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