Clone of official tools

Committer:
screamer
Date:
Tue Jun 07 11:35:02 2016 +0100
Revision:
8:a8ac6ed29081
Child:
9:2d27d77ada5c
Add missing files and profile support

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 8:a8ac6ed29081 1 #! /usr/bin/env python
screamer 8:a8ac6ed29081 2
screamer 8:a8ac6ed29081 3 # Memory Map File Analyser for ARM mbed OS
screamer 8:a8ac6ed29081 4
screamer 8:a8ac6ed29081 5 import argparse
screamer 8:a8ac6ed29081 6 import sys
screamer 8:a8ac6ed29081 7 import string
screamer 8:a8ac6ed29081 8 import os
screamer 8:a8ac6ed29081 9 import re
screamer 8:a8ac6ed29081 10 import json
screamer 8:a8ac6ed29081 11 import time
screamer 8:a8ac6ed29081 12 import string
screamer 8:a8ac6ed29081 13 import StringIO
screamer 8:a8ac6ed29081 14 from prettytable import PrettyTable
screamer 8:a8ac6ed29081 15
screamer 8:a8ac6ed29081 16 debug = False
screamer 8:a8ac6ed29081 17
screamer 8:a8ac6ed29081 18 class MemmapParser(object):
screamer 8:a8ac6ed29081 19
screamer 8:a8ac6ed29081 20 def __init__(self):
screamer 8:a8ac6ed29081 21 """
screamer 8:a8ac6ed29081 22 General initialization
screamer 8:a8ac6ed29081 23 """
screamer 8:a8ac6ed29081 24
screamer 8:a8ac6ed29081 25 # list of all modules and their sections
screamer 8:a8ac6ed29081 26 self.modules = dict()
screamer 8:a8ac6ed29081 27
screamer 8:a8ac6ed29081 28 self.misc_flash_sections = ('.interrupts', '.flash_config')
screamer 8:a8ac6ed29081 29
screamer 8:a8ac6ed29081 30 self.other_sections = ('.interrupts_ram', '.init', '.ARM.extab', '.ARM.exidx', '.ARM.attributes', \
screamer 8:a8ac6ed29081 31 '.eh_frame', '.init_array', '.fini_array', '.jcr', '.stab', '.stabstr', \
screamer 8:a8ac6ed29081 32 '.ARM.exidx','.ARM' )
screamer 8:a8ac6ed29081 33
screamer 8:a8ac6ed29081 34 # sections to print info (generic for all toolchains)
screamer 8:a8ac6ed29081 35 self.sections = ('.text', '.data', '.bss', '.heap', '.stack',)
screamer 8:a8ac6ed29081 36
screamer 8:a8ac6ed29081 37 # need to have sections merged in this order ()
screamer 8:a8ac6ed29081 38 self.all_sections = self.sections + self.other_sections + \
screamer 8:a8ac6ed29081 39 self.misc_flash_sections + ('unknown', 'OUTPUT')
screamer 8:a8ac6ed29081 40
screamer 8:a8ac6ed29081 41 self.print_sections = ('.text', '.data', '.bss')
screamer 8:a8ac6ed29081 42
screamer 8:a8ac6ed29081 43 # list of all object files and mappting to module names
screamer 8:a8ac6ed29081 44 self.object_to_module = dict()
screamer 8:a8ac6ed29081 45
screamer 8:a8ac6ed29081 46
screamer 8:a8ac6ed29081 47 def generate_output(self, file, json_mode):
screamer 8:a8ac6ed29081 48 """
screamer 8:a8ac6ed29081 49 Generates summary of memory map data
screamer 8:a8ac6ed29081 50
screamer 8:a8ac6ed29081 51 Parameters
screamer 8:a8ac6ed29081 52 file: descriptor (either stdout or file)
screamer 8:a8ac6ed29081 53 json_mode: generates output in json formal (True/False)
screamer 8:a8ac6ed29081 54 """
screamer 8:a8ac6ed29081 55
screamer 8:a8ac6ed29081 56 buf = StringIO.StringIO()
screamer 8:a8ac6ed29081 57
screamer 8:a8ac6ed29081 58 # Calculate misc flash sections
screamer 8:a8ac6ed29081 59 misc_flash_mem = 0
screamer 8:a8ac6ed29081 60 for i in self.modules:
screamer 8:a8ac6ed29081 61 for k in self.misc_flash_sections:
screamer 8:a8ac6ed29081 62 if self.modules[i][k]:
screamer 8:a8ac6ed29081 63 misc_flash_mem += self.modules[i][k]
screamer 8:a8ac6ed29081 64
screamer 8:a8ac6ed29081 65 # Create table
screamer 8:a8ac6ed29081 66 colums = ['Module']
screamer 8:a8ac6ed29081 67 for i in list(self.print_sections):
screamer 8:a8ac6ed29081 68 colums.append(i)
screamer 8:a8ac6ed29081 69
screamer 8:a8ac6ed29081 70 table = PrettyTable(colums)
screamer 8:a8ac6ed29081 71 table.align["Module"] = "l"
screamer 8:a8ac6ed29081 72
screamer 8:a8ac6ed29081 73 subtotal = dict()
screamer 8:a8ac6ed29081 74 for k in self.sections:
screamer 8:a8ac6ed29081 75 subtotal[k] = 0
screamer 8:a8ac6ed29081 76
screamer 8:a8ac6ed29081 77 json_obj = []
screamer 8:a8ac6ed29081 78 for i in sorted(self.modules):
screamer 8:a8ac6ed29081 79
screamer 8:a8ac6ed29081 80 row = []
screamer 8:a8ac6ed29081 81 row.append(i)
screamer 8:a8ac6ed29081 82
screamer 8:a8ac6ed29081 83 for k in self.sections:
screamer 8:a8ac6ed29081 84 subtotal[k] += self.modules[i][k]
screamer 8:a8ac6ed29081 85
screamer 8:a8ac6ed29081 86 for k in self.print_sections:
screamer 8:a8ac6ed29081 87 row.append(self.modules[i][k])
screamer 8:a8ac6ed29081 88
screamer 8:a8ac6ed29081 89 json_obj.append({ "module":i, "size":{k:self.modules[i][k] for k in self.print_sections}})
screamer 8:a8ac6ed29081 90 table.add_row(row)
screamer 8:a8ac6ed29081 91
screamer 8:a8ac6ed29081 92 subtotal_row = ['Subtotals']
screamer 8:a8ac6ed29081 93 for k in self.print_sections:
screamer 8:a8ac6ed29081 94 subtotal_row.append(subtotal[k])
screamer 8:a8ac6ed29081 95
screamer 8:a8ac6ed29081 96 table.add_row(subtotal_row)
screamer 8:a8ac6ed29081 97
screamer 8:a8ac6ed29081 98 if json_mode:
screamer 8:a8ac6ed29081 99 json_obj.append({ "summary":{'static_ram':(subtotal['.data']+subtotal['.bss']),
screamer 8:a8ac6ed29081 100 'heap':(subtotal['.heap']),
screamer 8:a8ac6ed29081 101 'stack':(subtotal['.stack']),
screamer 8:a8ac6ed29081 102 'total_ram':(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']),
screamer 8:a8ac6ed29081 103 'total_flash':(subtotal['.text']+subtotal['.data']+misc_flash_mem),}})
screamer 8:a8ac6ed29081 104
screamer 8:a8ac6ed29081 105 file.write(json.dumps(json_obj, indent=4))
screamer 8:a8ac6ed29081 106 file.write('\n')
screamer 8:a8ac6ed29081 107 else:
screamer 8:a8ac6ed29081 108 file.write(table.get_string())
screamer 8:a8ac6ed29081 109 file.write('\n')
screamer 8:a8ac6ed29081 110 file.write("Static RAM memory (data + bss): %s\n" % (str(subtotal['.data']+subtotal['.bss'])))
screamer 8:a8ac6ed29081 111 file.write("Heap: %s\n" % str(subtotal['.heap']))
screamer 8:a8ac6ed29081 112 file.write("Stack: %s\n" % str(subtotal['.stack']))
screamer 8:a8ac6ed29081 113 file.write("Total RAM memory (data + bss + heap + stack): %s\n" % (str(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack'])))
screamer 8:a8ac6ed29081 114 file.write("Total Flash memory (text + data + misc): %s\n" % (str(subtotal['.text']+subtotal['.data']+misc_flash_mem)))
screamer 8:a8ac6ed29081 115 return
screamer 8:a8ac6ed29081 116
screamer 8:a8ac6ed29081 117 def module_add(self, module_name, size, section):
screamer 8:a8ac6ed29081 118 """
screamer 8:a8ac6ed29081 119 Adds a module / section to the list
screamer 8:a8ac6ed29081 120 """
screamer 8:a8ac6ed29081 121
screamer 8:a8ac6ed29081 122 if module_name in self.modules:
screamer 8:a8ac6ed29081 123 self.modules[module_name][section] += size
screamer 8:a8ac6ed29081 124 else:
screamer 8:a8ac6ed29081 125 temp_dic = dict()
screamer 8:a8ac6ed29081 126 for x in self.all_sections:
screamer 8:a8ac6ed29081 127 temp_dic[x] = 0
screamer 8:a8ac6ed29081 128 temp_dic[section] = size
screamer 8:a8ac6ed29081 129 self.modules[module_name] = temp_dic
screamer 8:a8ac6ed29081 130
screamer 8:a8ac6ed29081 131 def find_start_gcc(self,line):
screamer 8:a8ac6ed29081 132 """
screamer 8:a8ac6ed29081 133 Checks location of gcc map file to start parsing map file
screamer 8:a8ac6ed29081 134 """
screamer 8:a8ac6ed29081 135 if line.startswith('Linker script and memory map'):
screamer 8:a8ac6ed29081 136 return True
screamer 8:a8ac6ed29081 137 else:
screamer 8:a8ac6ed29081 138 return False
screamer 8:a8ac6ed29081 139
screamer 8:a8ac6ed29081 140 def find_start_armcc(self,line):
screamer 8:a8ac6ed29081 141 """
screamer 8:a8ac6ed29081 142 Checks location of armcc map file to start parsing map file
screamer 8:a8ac6ed29081 143 """
screamer 8:a8ac6ed29081 144 if line.startswith(' Base Addr Size'):
screamer 8:a8ac6ed29081 145 return True
screamer 8:a8ac6ed29081 146 else:
screamer 8:a8ac6ed29081 147 return False
screamer 8:a8ac6ed29081 148
screamer 8:a8ac6ed29081 149 def find_start_iar(self,line):
screamer 8:a8ac6ed29081 150 """
screamer 8:a8ac6ed29081 151 Checks location of armcc map file to start parsing map file
screamer 8:a8ac6ed29081 152 """
screamer 8:a8ac6ed29081 153 if line.startswith(' Section '):
screamer 8:a8ac6ed29081 154 return True
screamer 8:a8ac6ed29081 155 else:
screamer 8:a8ac6ed29081 156 return False
screamer 8:a8ac6ed29081 157
screamer 8:a8ac6ed29081 158 def check_new_section_gcc(self,line):
screamer 8:a8ac6ed29081 159 """
screamer 8:a8ac6ed29081 160 Check whether a new section in a map file has been detected (only applies to gcc)
screamer 8:a8ac6ed29081 161 """
screamer 8:a8ac6ed29081 162
screamer 8:a8ac6ed29081 163 for i in self.all_sections:
screamer 8:a8ac6ed29081 164 if line.startswith(i):
screamer 8:a8ac6ed29081 165 return i # should name of the section (assuming it's a known one)
screamer 8:a8ac6ed29081 166
screamer 8:a8ac6ed29081 167 if line.startswith('.'):
screamer 8:a8ac6ed29081 168 return 'unknown' # all others are clasified are unknown
screamer 8:a8ac6ed29081 169 else:
screamer 8:a8ac6ed29081 170 return False # everything else, means no change in section
screamer 8:a8ac6ed29081 171
screamer 8:a8ac6ed29081 172 def path_object_to_module_name(self,txt):
screamer 8:a8ac6ed29081 173 """
screamer 8:a8ac6ed29081 174 Parses path to object file and extracts module / object data
screamer 8:a8ac6ed29081 175 """
screamer 8:a8ac6ed29081 176
screamer 8:a8ac6ed29081 177 txt = txt.replace('\\','/')
screamer 8:a8ac6ed29081 178 rex_mbed_os_name = r'^.+mbed-os\/(.+)\/(.+\.o)$'
screamer 8:a8ac6ed29081 179 test_rex_mbed_os_name = re.match(rex_mbed_os_name,txt)
screamer 8:a8ac6ed29081 180
screamer 8:a8ac6ed29081 181 if test_rex_mbed_os_name:
screamer 8:a8ac6ed29081 182
screamer 8:a8ac6ed29081 183 object_name = test_rex_mbed_os_name.group(2)
screamer 8:a8ac6ed29081 184 data = test_rex_mbed_os_name.group(1).split('/')
screamer 8:a8ac6ed29081 185 ndata = len(data)
screamer 8:a8ac6ed29081 186
screamer 8:a8ac6ed29081 187 if ndata == 1:
screamer 8:a8ac6ed29081 188 module_name = data[0]
screamer 8:a8ac6ed29081 189 else:
screamer 8:a8ac6ed29081 190 module_name = data[0] + '/' + data[1]
screamer 8:a8ac6ed29081 191
screamer 8:a8ac6ed29081 192 return [module_name, object_name]
screamer 8:a8ac6ed29081 193 else:
screamer 8:a8ac6ed29081 194 return ['Misc', ""]
screamer 8:a8ac6ed29081 195
screamer 8:a8ac6ed29081 196
screamer 8:a8ac6ed29081 197 def parse_section_gcc(self,line):
screamer 8:a8ac6ed29081 198 """
screamer 8:a8ac6ed29081 199 Parse data from a section of gcc map file
screamer 8:a8ac6ed29081 200 """
screamer 8:a8ac6ed29081 201 # examples
screamer 8:a8ac6ed29081 202 # 0x00004308 0x7c ./.build/K64F/GCC_ARM/mbed-os/hal/targets/hal/TARGET_Freescale/TARGET_KPSDK_MCUS/spi_api.o
screamer 8:a8ac6ed29081 203 # .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 8:a8ac6ed29081 204 rex_address_len_name = r'^\s+.*0x(\w{8,16})\s+0x(\w+)\s(.+)$'
screamer 8:a8ac6ed29081 205
screamer 8:a8ac6ed29081 206 test_address_len_name = re.match(rex_address_len_name,line)
screamer 8:a8ac6ed29081 207
screamer 8:a8ac6ed29081 208 if test_address_len_name:
screamer 8:a8ac6ed29081 209
screamer 8:a8ac6ed29081 210 if int(test_address_len_name.group(2),16) == 0: # size == 0
screamer 8:a8ac6ed29081 211 return ["",0] # no valid entry
screamer 8:a8ac6ed29081 212 else:
screamer 8:a8ac6ed29081 213 m_name, m_object = self.path_object_to_module_name(test_address_len_name.group(3))
screamer 8:a8ac6ed29081 214 m_size = int(test_address_len_name.group(2),16)
screamer 8:a8ac6ed29081 215 return [m_name,m_size]
screamer 8:a8ac6ed29081 216
screamer 8:a8ac6ed29081 217 else: # special cortner case for *fill* sections
screamer 8:a8ac6ed29081 218 # example
screamer 8:a8ac6ed29081 219 # *fill* 0x0000abe4 0x4
screamer 8:a8ac6ed29081 220 rex_address_len = r'^\s+\*fill\*\s+0x(\w{8,16})\s+0x(\w+).*$'
screamer 8:a8ac6ed29081 221 test_address_len = re.match(rex_address_len,line)
screamer 8:a8ac6ed29081 222
screamer 8:a8ac6ed29081 223 if test_address_len:
screamer 8:a8ac6ed29081 224 if int(test_address_len.group(2),16) == 0: # size == 0
screamer 8:a8ac6ed29081 225 return ["",0] # no valid entry
screamer 8:a8ac6ed29081 226 else:
screamer 8:a8ac6ed29081 227 m_name = 'Misc'
screamer 8:a8ac6ed29081 228 m_size = int(test_address_len.group(2),16)
screamer 8:a8ac6ed29081 229 return [m_name,m_size]
screamer 8:a8ac6ed29081 230 else:
screamer 8:a8ac6ed29081 231 return ["",0] # no valid entry
screamer 8:a8ac6ed29081 232
screamer 8:a8ac6ed29081 233 def parse_map_file_gcc(self, file):
screamer 8:a8ac6ed29081 234 """
screamer 8:a8ac6ed29081 235 Main logic to decode gcc map files
screamer 8:a8ac6ed29081 236 """
screamer 8:a8ac6ed29081 237
screamer 8:a8ac6ed29081 238 current_section = 'unknown'
screamer 8:a8ac6ed29081 239
screamer 8:a8ac6ed29081 240 with file as infile:
screamer 8:a8ac6ed29081 241
screamer 8:a8ac6ed29081 242 # Search area to parse
screamer 8:a8ac6ed29081 243 for line in infile:
screamer 8:a8ac6ed29081 244 if self.find_start_gcc(line) == True:
screamer 8:a8ac6ed29081 245 current_section = "unknown"
screamer 8:a8ac6ed29081 246 break
screamer 8:a8ac6ed29081 247
screamer 8:a8ac6ed29081 248 # Start decoding the map file
screamer 8:a8ac6ed29081 249 for line in infile:
screamer 8:a8ac6ed29081 250
screamer 8:a8ac6ed29081 251 change_section = self.check_new_section_gcc(line)
screamer 8:a8ac6ed29081 252
screamer 8:a8ac6ed29081 253 if change_section == "OUTPUT": # finish parsing file: exit
screamer 8:a8ac6ed29081 254 break
screamer 8:a8ac6ed29081 255 elif change_section != False:
screamer 8:a8ac6ed29081 256 current_section = change_section
screamer 8:a8ac6ed29081 257
screamer 8:a8ac6ed29081 258 [module_name, module_size] = self.parse_section_gcc(line)
screamer 8:a8ac6ed29081 259
screamer 8:a8ac6ed29081 260 if module_size == 0 or module_name == "":
screamer 8:a8ac6ed29081 261 pass
screamer 8:a8ac6ed29081 262 else:
screamer 8:a8ac6ed29081 263 self.module_add(module_name, module_size, current_section)
screamer 8:a8ac6ed29081 264
screamer 8:a8ac6ed29081 265 if debug:
screamer 8:a8ac6ed29081 266 print "Line: %s" % line,
screamer 8:a8ac6ed29081 267 print "Module: %s\tSection: %s\tSize: %s" % (module_name,current_section,module_size)
screamer 8:a8ac6ed29081 268 raw_input("----------")
screamer 8:a8ac6ed29081 269
screamer 8:a8ac6ed29081 270 def parse_section_armcc(self,line):
screamer 8:a8ac6ed29081 271 """
screamer 8:a8ac6ed29081 272 Parse data from an armcc map file
screamer 8:a8ac6ed29081 273 """
screamer 8:a8ac6ed29081 274 # Examples of armcc map file:
screamer 8:a8ac6ed29081 275 # Base_Addr Size Type Attr Idx E Section Name Object
screamer 8:a8ac6ed29081 276 # 0x00000000 0x00000400 Data RO 11222 RESET startup_MK64F12.o
screamer 8:a8ac6ed29081 277 # 0x00000410 0x00000008 Code RO 49364 * !!!main c_w.l(__main.o)
screamer 8:a8ac6ed29081 278 rex_armcc = r'^\s+0x(\w{8})\s+0x(\w{8})\s+(\w+)\s+(\w+)\s+(\d+)\s+[*]?.+\s+(.+)$'
screamer 8:a8ac6ed29081 279
screamer 8:a8ac6ed29081 280 test_rex_armcc = re.match(rex_armcc,line)
screamer 8:a8ac6ed29081 281
screamer 8:a8ac6ed29081 282 if test_rex_armcc:
screamer 8:a8ac6ed29081 283
screamer 8:a8ac6ed29081 284 size = int(test_rex_armcc.group(2),16)
screamer 8:a8ac6ed29081 285
screamer 8:a8ac6ed29081 286 if test_rex_armcc.group(4) == 'RO':
screamer 8:a8ac6ed29081 287 section = '.text'
screamer 8:a8ac6ed29081 288 else:
screamer 8:a8ac6ed29081 289 if test_rex_armcc.group(3) == 'Data':
screamer 8:a8ac6ed29081 290 section = '.data'
screamer 8:a8ac6ed29081 291 elif test_rex_armcc.group(3) == 'Zero':
screamer 8:a8ac6ed29081 292 section = '.bss'
screamer 8:a8ac6ed29081 293 else:
screamer 8:a8ac6ed29081 294 print "BUG armcc map parser"
screamer 8:a8ac6ed29081 295 raw_input()
screamer 8:a8ac6ed29081 296
screamer 8:a8ac6ed29081 297 # lookup object in dictionary and return module name
screamer 8:a8ac6ed29081 298 object_name = test_rex_armcc.group(6)
screamer 8:a8ac6ed29081 299 if object_name in self.object_to_module:
screamer 8:a8ac6ed29081 300 module_name = self.object_to_module[object_name]
screamer 8:a8ac6ed29081 301 else:
screamer 8:a8ac6ed29081 302 module_name = 'Misc'
screamer 8:a8ac6ed29081 303
screamer 8:a8ac6ed29081 304 return [module_name,size,section]
screamer 8:a8ac6ed29081 305
screamer 8:a8ac6ed29081 306 else:
screamer 8:a8ac6ed29081 307 return ["",0,""] # no valid entry
screamer 8:a8ac6ed29081 308
screamer 8:a8ac6ed29081 309 def parse_section_iar(self,line):
screamer 8:a8ac6ed29081 310 """
screamer 8:a8ac6ed29081 311 Parse data from an IAR map file
screamer 8:a8ac6ed29081 312 """
screamer 8:a8ac6ed29081 313 # Examples of IAR map file:
screamer 8:a8ac6ed29081 314 # Section Kind Address Size Object
screamer 8:a8ac6ed29081 315 # .intvec ro code 0x00000000 0x198 startup_MK64F12.o [15]
screamer 8:a8ac6ed29081 316 # .rodata const 0x00000198 0x0 zero_init3.o [133]
screamer 8:a8ac6ed29081 317 # .iar.init_table const 0x00008384 0x2c - Linker created -
screamer 8:a8ac6ed29081 318 # Initializer bytes const 0x00000198 0xb2 <for P3 s0>
screamer 8:a8ac6ed29081 319 # .data inited 0x20000000 0xd4 driverAtmelRFInterface.o [70]
screamer 8:a8ac6ed29081 320 # .bss zero 0x20000598 0x318 RTX_Conf_CM.o [4]
screamer 8:a8ac6ed29081 321 # .iar.dynexit uninit 0x20001448 0x204 <Block tail>
screamer 8:a8ac6ed29081 322 # HEAP uninit 0x20001650 0x10000 <Block tail>
screamer 8:a8ac6ed29081 323 rex_iar = r'^\s+(.+)\s+(zero|const|ro code|inited|uninit)\s+0x(\w{8})\s+0x(\w+)\s+(.+)\s.+$'
screamer 8:a8ac6ed29081 324
screamer 8:a8ac6ed29081 325 test_rex_iar = re.match(rex_iar,line)
screamer 8:a8ac6ed29081 326
screamer 8:a8ac6ed29081 327 if test_rex_iar:
screamer 8:a8ac6ed29081 328
screamer 8:a8ac6ed29081 329 size = int(test_rex_iar.group(4),16)
screamer 8:a8ac6ed29081 330
screamer 8:a8ac6ed29081 331 if test_rex_iar.group(2) == 'const' or test_rex_iar.group(2) == 'ro code':
screamer 8:a8ac6ed29081 332 section = '.text'
screamer 8:a8ac6ed29081 333 elif test_rex_iar.group(2) == 'zero' or test_rex_iar.group(2) == 'uninit':
screamer 8:a8ac6ed29081 334
screamer 8:a8ac6ed29081 335 if test_rex_iar.group(1)[0:4] == 'HEAP':
screamer 8:a8ac6ed29081 336 section = '.heap'
screamer 8:a8ac6ed29081 337 elif test_rex_iar.group(1)[0:6] == 'CSTACK':
screamer 8:a8ac6ed29081 338 section = '.stack'
screamer 8:a8ac6ed29081 339 else:
screamer 8:a8ac6ed29081 340 section = '.bss' # default section
screamer 8:a8ac6ed29081 341
screamer 8:a8ac6ed29081 342 elif test_rex_iar.group(2) == 'inited':
screamer 8:a8ac6ed29081 343 section = '.data'
screamer 8:a8ac6ed29081 344 else:
screamer 8:a8ac6ed29081 345 print "BUG IAR map parser"
screamer 8:a8ac6ed29081 346 raw_input()
screamer 8:a8ac6ed29081 347
screamer 8:a8ac6ed29081 348 # lookup object in dictionary and return module name
screamer 8:a8ac6ed29081 349 object_name = test_rex_iar.group(5)
screamer 8:a8ac6ed29081 350 if object_name in self.object_to_module:
screamer 8:a8ac6ed29081 351 module_name = self.object_to_module[object_name]
screamer 8:a8ac6ed29081 352 else:
screamer 8:a8ac6ed29081 353 module_name = 'Misc'
screamer 8:a8ac6ed29081 354
screamer 8:a8ac6ed29081 355 return [module_name,size,section]
screamer 8:a8ac6ed29081 356
screamer 8:a8ac6ed29081 357 else:
screamer 8:a8ac6ed29081 358 return ["",0,""] # no valid entry
screamer 8:a8ac6ed29081 359
screamer 8:a8ac6ed29081 360 def parse_map_file_armcc(self, file):
screamer 8:a8ac6ed29081 361 """
screamer 8:a8ac6ed29081 362 Main logic to decode armcc map files
screamer 8:a8ac6ed29081 363 """
screamer 8:a8ac6ed29081 364
screamer 8:a8ac6ed29081 365 with file as infile:
screamer 8:a8ac6ed29081 366
screamer 8:a8ac6ed29081 367 # Search area to parse
screamer 8:a8ac6ed29081 368 for line in infile:
screamer 8:a8ac6ed29081 369 if self.find_start_armcc(line) == True:
screamer 8:a8ac6ed29081 370 break
screamer 8:a8ac6ed29081 371
screamer 8:a8ac6ed29081 372 # Start decoding the map file
screamer 8:a8ac6ed29081 373 for line in infile:
screamer 8:a8ac6ed29081 374
screamer 8:a8ac6ed29081 375 [name, size, section] = self.parse_section_armcc(line)
screamer 8:a8ac6ed29081 376
screamer 8:a8ac6ed29081 377 if size == 0 or name == "" or section == "":
screamer 8:a8ac6ed29081 378 pass
screamer 8:a8ac6ed29081 379 else:
screamer 8:a8ac6ed29081 380 self.module_add(name, size, section)
screamer 8:a8ac6ed29081 381
screamer 8:a8ac6ed29081 382 def parse_map_file_iar(self, file):
screamer 8:a8ac6ed29081 383 """
screamer 8:a8ac6ed29081 384 Main logic to decode armcc map files
screamer 8:a8ac6ed29081 385 """
screamer 8:a8ac6ed29081 386
screamer 8:a8ac6ed29081 387 with file as infile:
screamer 8:a8ac6ed29081 388
screamer 8:a8ac6ed29081 389 # Search area to parse
screamer 8:a8ac6ed29081 390 for line in infile:
screamer 8:a8ac6ed29081 391 if self.find_start_iar(line) == True:
screamer 8:a8ac6ed29081 392 break
screamer 8:a8ac6ed29081 393
screamer 8:a8ac6ed29081 394 # Start decoding the map file
screamer 8:a8ac6ed29081 395 for line in infile:
screamer 8:a8ac6ed29081 396
screamer 8:a8ac6ed29081 397 [name, size, section] = self.parse_section_iar(line)
screamer 8:a8ac6ed29081 398
screamer 8:a8ac6ed29081 399 if size == 0 or name == "" or section == "":
screamer 8:a8ac6ed29081 400 pass
screamer 8:a8ac6ed29081 401 else:
screamer 8:a8ac6ed29081 402 self.module_add(name, size, section)
screamer 8:a8ac6ed29081 403
screamer 8:a8ac6ed29081 404 def search_objects(self,path,toolchain):
screamer 8:a8ac6ed29081 405 """
screamer 8:a8ac6ed29081 406 Check whether the specified map file matches with the toolchain.
screamer 8:a8ac6ed29081 407 Searches for object files and creates mapping: object --> module
screamer 8:a8ac6ed29081 408 """
screamer 8:a8ac6ed29081 409
screamer 8:a8ac6ed29081 410 path = path.replace('\\','/')
screamer 8:a8ac6ed29081 411
screamer 8:a8ac6ed29081 412 # check location of map file
screamer 8:a8ac6ed29081 413 rex = r'^(.+\/)' + re.escape(toolchain) + r'\/(.+\.map)$'
screamer 8:a8ac6ed29081 414 test_rex = re.match(rex,path)
screamer 8:a8ac6ed29081 415
screamer 8:a8ac6ed29081 416 if test_rex:
screamer 8:a8ac6ed29081 417 search_path = test_rex.group(1) + toolchain + '/mbed-os/'
screamer 8:a8ac6ed29081 418 else:
screamer 8:a8ac6ed29081 419 # It looks this is not an mbed OS project
screamer 8:a8ac6ed29081 420 # object-to-module mapping cannot be generated
screamer 8:a8ac6ed29081 421 print "Warning: specified toolchain doesn't match with path to the memory map file."
screamer 8:a8ac6ed29081 422 return
screamer 8:a8ac6ed29081 423
screamer 8:a8ac6ed29081 424 for root, dirs, files in os.walk(search_path):
screamer 8:a8ac6ed29081 425 for file in files:
screamer 8:a8ac6ed29081 426 if file.endswith(".o"):
screamer 8:a8ac6ed29081 427 module_name, object_name = self.path_object_to_module_name(os.path.join(root, file))
screamer 8:a8ac6ed29081 428
screamer 8:a8ac6ed29081 429 if object_name in self.object_to_module:
screamer 8:a8ac6ed29081 430 print "WARNING: multiple usages of object file: %s" % object_name
screamer 8:a8ac6ed29081 431 print " Current: %s" % self.object_to_module[object_name]
screamer 8:a8ac6ed29081 432 print " New: %s" % module_name
screamer 8:a8ac6ed29081 433 print " "
screamer 8:a8ac6ed29081 434
screamer 8:a8ac6ed29081 435 else:
screamer 8:a8ac6ed29081 436 self.object_to_module.update({object_name:module_name})
screamer 8:a8ac6ed29081 437
screamer 8:a8ac6ed29081 438 def main():
screamer 8:a8ac6ed29081 439
screamer 8:a8ac6ed29081 440 version = '0.3.7'
screamer 8:a8ac6ed29081 441 time_start = time.clock()
screamer 8:a8ac6ed29081 442
screamer 8:a8ac6ed29081 443 # Parser handling
screamer 8:a8ac6ed29081 444 parser = argparse.ArgumentParser(description="Memory Map File Analyser for ARM mbed OS\nversion %s" % version)
screamer 8:a8ac6ed29081 445
screamer 8:a8ac6ed29081 446 parser.add_argument('file', help='memory map file')
screamer 8:a8ac6ed29081 447
screamer 8:a8ac6ed29081 448 parser.add_argument('-t','--toolchain', dest='toolchain', help='select a toolchain that corresponds to the memory map file (ARM, GCC_ARM, IAR)',
screamer 8:a8ac6ed29081 449 required=True)
screamer 8:a8ac6ed29081 450
screamer 8:a8ac6ed29081 451 parser.add_argument('-o','--output',help='output file name', required=False)
screamer 8:a8ac6ed29081 452
screamer 8:a8ac6ed29081 453 parser.add_argument('-j', '--json', dest='json', required=False, action="store_true",
screamer 8:a8ac6ed29081 454 help='output in JSON formatted list')
screamer 8:a8ac6ed29081 455
screamer 8:a8ac6ed29081 456 parser.add_argument('-v', '--version', action='version', version=version)
screamer 8:a8ac6ed29081 457
screamer 8:a8ac6ed29081 458 # Parse/run command
screamer 8:a8ac6ed29081 459 if len(sys.argv) <= 1:
screamer 8:a8ac6ed29081 460 parser.print_help()
screamer 8:a8ac6ed29081 461 sys.exit(1)
screamer 8:a8ac6ed29081 462
screamer 8:a8ac6ed29081 463 args, remainder = parser.parse_known_args()
screamer 8:a8ac6ed29081 464
screamer 8:a8ac6ed29081 465 try:
screamer 8:a8ac6ed29081 466 file_input = open(args.file,'rt')
screamer 8:a8ac6ed29081 467 except IOError as e:
screamer 8:a8ac6ed29081 468 print "I/O error({0}): {1}".format(e.errno, e.strerror)
screamer 8:a8ac6ed29081 469 sys.exit(0)
screamer 8:a8ac6ed29081 470
screamer 8:a8ac6ed29081 471 # Creates parser object
screamer 8:a8ac6ed29081 472 t = MemmapParser()
screamer 8:a8ac6ed29081 473
screamer 8:a8ac6ed29081 474 # Decode map file depending on the toolchain
screamer 8:a8ac6ed29081 475 if args.toolchain == "ARM":
screamer 8:a8ac6ed29081 476 t.search_objects(os.path.abspath(args.file),args.toolchain)
screamer 8:a8ac6ed29081 477 t.parse_map_file_armcc(file_input)
screamer 8:a8ac6ed29081 478 elif args.toolchain == "GCC_ARM":
screamer 8:a8ac6ed29081 479 t.parse_map_file_gcc(file_input)
screamer 8:a8ac6ed29081 480 elif args.toolchain == "IAR":
screamer 8:a8ac6ed29081 481 print "WARNING: IAR Compiler not fully supported (yet)"
screamer 8:a8ac6ed29081 482 print " "
screamer 8:a8ac6ed29081 483 t.search_objects(os.path.abspath(args.file),args.toolchain)
screamer 8:a8ac6ed29081 484 t.parse_map_file_iar(file_input)
screamer 8:a8ac6ed29081 485 else:
screamer 8:a8ac6ed29081 486 print "Invalid toolchain. Options are: ARM, GCC_ARM, IAR"
screamer 8:a8ac6ed29081 487 sys.exit(0)
screamer 8:a8ac6ed29081 488
screamer 8:a8ac6ed29081 489 # Write output in file
screamer 8:a8ac6ed29081 490 if args.output != None:
screamer 8:a8ac6ed29081 491 try:
screamer 8:a8ac6ed29081 492 file_output = open(args.output,'w')
screamer 8:a8ac6ed29081 493 t.generate_output(file_output,args.json)
screamer 8:a8ac6ed29081 494 file_output.close()
screamer 8:a8ac6ed29081 495 except IOError as e:
screamer 8:a8ac6ed29081 496 print "I/O error({0}): {1}".format(e.errno, e.strerror)
screamer 8:a8ac6ed29081 497 sys.exit(0)
screamer 8:a8ac6ed29081 498 else: # Write output in screen
screamer 8:a8ac6ed29081 499 t.generate_output(sys.stdout,args.json)
screamer 8:a8ac6ed29081 500
screamer 8:a8ac6ed29081 501 file_input.close()
screamer 8:a8ac6ed29081 502
screamer 8:a8ac6ed29081 503 print "Elapsed time: %smS" %int(round((time.clock()-time_start)*1000))
screamer 8:a8ac6ed29081 504
screamer 8:a8ac6ed29081 505 sys.exit(0)
screamer 8:a8ac6ed29081 506
screamer 8:a8ac6ed29081 507 if __name__ == "__main__":
screamer 8:a8ac6ed29081 508 main()