mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #5178 from ARMmbed/release-candidate
Release candidate for mbed-os-5.6.0-rc3pull/5394/head mbed-os-5.6.0
commit
5499db1e81
358
tools/memap.py
358
tools/memap.py
|
@ -20,6 +20,18 @@ RE_IAR = re.compile(
|
||||||
r'^\s+(.+)\s+(zero|const|ro code|inited|uninit)\s'
|
r'^\s+(.+)\s+(zero|const|ro code|inited|uninit)\s'
|
||||||
r'+0x(\w{8})\s+0x(\w+)\s+(.+)\s.+$')
|
r'+0x(\w{8})\s+0x(\w+)\s+(.+)\s.+$')
|
||||||
|
|
||||||
|
RE_CMDLINE_FILE_IAR = re.compile(r'^#\s+(.+\.o)')
|
||||||
|
RE_LIBRARY_IAR = re.compile(r'^(.+\.a)\:.+$')
|
||||||
|
RE_OBJECT_LIBRARY_IAR = re.compile(r'^\s+(.+\.o)\s.*')
|
||||||
|
|
||||||
|
RE_OBJECT_FILE_GCC = re.compile(r'^(.+\/.+\.o)$')
|
||||||
|
RE_LIBRARY_OBJECT_GCC = re.compile(r'^.+\/lib(.+\.a)\((.+\.o)\)$')
|
||||||
|
RE_STD_SECTION_GCC = re.compile(r'^\s+.*0x(\w{8,16})\s+0x(\w+)\s(.+)$')
|
||||||
|
RE_FILL_SECTION_GCC = re.compile(r'^\s*\*fill\*\s+0x(\w{8,16})\s+0x(\w+).*$')
|
||||||
|
|
||||||
|
RE_OBJECT_ARMCC = re.compile(r'(.+\.(l|ar))\((.+\.o)\)')
|
||||||
|
|
||||||
|
|
||||||
class MemapParser(object):
|
class MemapParser(object):
|
||||||
"""An object that represents parsed results, parses the memory map files,
|
"""An object that represents parsed results, parses the memory map files,
|
||||||
and writes out different file types of memory results
|
and writes out different file types of memory results
|
||||||
|
@ -59,31 +71,10 @@ class MemapParser(object):
|
||||||
|
|
||||||
self.misc_flash_mem = 0
|
self.misc_flash_mem = 0
|
||||||
|
|
||||||
|
# Modules passed to the linker on the command line
|
||||||
|
# this is a dict because modules are looked up by their basename
|
||||||
|
self.cmd_modules = {}
|
||||||
|
|
||||||
def remove_unused_modules(self):
|
|
||||||
""" Removes modules/objects that were compiled but are not used
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Using keys to be able to remove entry
|
|
||||||
for i in self.modules.keys():
|
|
||||||
size = 0
|
|
||||||
for k in self.print_sections:
|
|
||||||
size += self.modules[i][k]
|
|
||||||
if size == 0:
|
|
||||||
del self.modules[i]
|
|
||||||
|
|
||||||
def module_init(self, object_name):
|
|
||||||
""" Initialize a module. Just adds the name of the module
|
|
||||||
|
|
||||||
Positional arguments:
|
|
||||||
object_name - name of the entry to add
|
|
||||||
"""
|
|
||||||
|
|
||||||
if object_name not in self.modules:
|
|
||||||
temp_dic = dict()
|
|
||||||
for section_idx in self.all_sections:
|
|
||||||
temp_dic[section_idx] = 0
|
|
||||||
self.modules[object_name] = temp_dic
|
|
||||||
|
|
||||||
def module_add(self, object_name, size, section):
|
def module_add(self, object_name, size, section):
|
||||||
""" Adds a module / section to the list
|
""" Adds a module / section to the list
|
||||||
|
@ -94,28 +85,27 @@ class MemapParser(object):
|
||||||
section - the section the module contributes to
|
section - the section the module contributes to
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Check if object is a sub-string of key
|
if not object_name or not size or not section:
|
||||||
for module_path in self.modules:
|
|
||||||
|
|
||||||
# this is required to differenciate: main.o vs xxxmain.o
|
|
||||||
module_split = os.path.basename(module_path)
|
|
||||||
obj_split = os.path.basename(object_name)
|
|
||||||
|
|
||||||
if module_split == obj_split:
|
|
||||||
self.modules[module_path][section] += size
|
|
||||||
return
|
return
|
||||||
|
|
||||||
new_module = dict()
|
if object_name in self.modules:
|
||||||
for section_idx in self.all_sections:
|
self.modules[object_name].setdefault(section, 0)
|
||||||
new_module[section_idx] = 0
|
self.modules[object_name][section] += size
|
||||||
new_module[section] = size
|
return
|
||||||
|
|
||||||
|
obj_split = os.sep + os.path.basename(object_name)
|
||||||
|
for module_path, contents in self.modules.items():
|
||||||
|
if module_path.endswith(obj_split) or module_path == object_name:
|
||||||
|
contents.setdefault(section, 0)
|
||||||
|
contents[section] += size
|
||||||
|
return
|
||||||
|
|
||||||
|
new_module = {section: size}
|
||||||
self.modules[object_name] = new_module
|
self.modules[object_name] = new_module
|
||||||
|
|
||||||
def module_replace(self, old_object, new_object):
|
def module_replace(self, old_object, new_object):
|
||||||
""" Replaces an object name with a new one
|
""" Replaces an object name with a new one
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Check if object is a sub-string of key
|
|
||||||
if old_object in self.modules:
|
if old_object in self.modules:
|
||||||
self.modules[new_object] = self.modules[old_object]
|
self.modules[new_object] = self.modules[old_object]
|
||||||
del self.modules[old_object]
|
del self.modules[old_object]
|
||||||
|
@ -147,8 +137,7 @@ class MemapParser(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
line = line.replace('\\', '/')
|
line = line.replace('\\', '/')
|
||||||
RE_OBJECT_FILE = r'^.+\/(.+\.o)$'
|
test_re_mbed_os_name = re.match(RE_OBJECT_FILE_GCC, line)
|
||||||
test_re_mbed_os_name = re.match(RE_OBJECT_FILE, line)
|
|
||||||
|
|
||||||
if test_re_mbed_os_name:
|
if test_re_mbed_os_name:
|
||||||
|
|
||||||
|
@ -156,14 +145,12 @@ class MemapParser(object):
|
||||||
|
|
||||||
# corner case: certain objects are provided by the GCC toolchain
|
# corner case: certain objects are provided by the GCC toolchain
|
||||||
if 'arm-none-eabi' in line:
|
if 'arm-none-eabi' in line:
|
||||||
object_name = '[lib]/misc/' + object_name
|
return '[lib]/misc/' + object_name
|
||||||
|
|
||||||
return object_name
|
return object_name
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
RE_LIBRARY_OBJECT_FILE = r'^.+\/(lib.+\.a)\((.+\.o)\)$'
|
test_re_obj_name = re.match(RE_LIBRARY_OBJECT_GCC, line)
|
||||||
test_re_obj_name = re.match(RE_LIBRARY_OBJECT_FILE, line)
|
|
||||||
|
|
||||||
if test_re_obj_name:
|
if test_re_obj_name:
|
||||||
object_name = test_re_obj_name.group(1) + '/' + \
|
object_name = test_re_obj_name.group(1) + '/' + \
|
||||||
|
@ -172,7 +159,7 @@ class MemapParser(object):
|
||||||
return '[lib]/' + object_name
|
return '[lib]/' + object_name
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print "Malformed input found when parsing GCC map: %s" % line
|
print "Unknown object name found in GCC map file: %s" % line
|
||||||
return '[misc]'
|
return '[misc]'
|
||||||
|
|
||||||
def parse_section_gcc(self, line):
|
def parse_section_gcc(self, line):
|
||||||
|
@ -186,40 +173,20 @@ class MemapParser(object):
|
||||||
line - the line to parse a section from
|
line - the line to parse a section from
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RE_STD_SECTION_GCC = re.compile(
|
is_fill = re.match(RE_FILL_SECTION_GCC, line)
|
||||||
r'^\s+.*0x(\w{8,16})\s+0x(\w+)\s(.+)$')
|
if is_fill:
|
||||||
|
|
||||||
test_address_len_name = re.match(RE_STD_SECTION_GCC, line)
|
|
||||||
|
|
||||||
if test_address_len_name:
|
|
||||||
|
|
||||||
if int(test_address_len_name.group(2), 16) == 0: # size == 0
|
|
||||||
return ["", 0] # no valid entry
|
|
||||||
else:
|
|
||||||
o_name = self.parse_object_name_gcc(\
|
|
||||||
test_address_len_name.group(3))
|
|
||||||
o_size = int(test_address_len_name.group(2), 16)
|
|
||||||
|
|
||||||
return [o_name, o_size]
|
|
||||||
|
|
||||||
else: # special corner case for *fill* sections
|
|
||||||
# example
|
|
||||||
# *fill* 0x0000abe4 0x4
|
|
||||||
|
|
||||||
RE_FILL_SECTION_GCC = r'^\s+\*fill\*\s+0x(\w{8,16})\s+0x(\w+).*$'
|
|
||||||
|
|
||||||
test_address_len = re.match(RE_FILL_SECTION_GCC, line)
|
|
||||||
|
|
||||||
if test_address_len:
|
|
||||||
if int(test_address_len.group(2), 16) == 0: # size == 0
|
|
||||||
return ["", 0] # no valid entry
|
|
||||||
else:
|
|
||||||
o_name = '[fill]'
|
o_name = '[fill]'
|
||||||
o_size = int(test_address_len.group(2), 16)
|
o_size = int(is_fill.group(2), 16)
|
||||||
return [o_name, o_size]
|
return [o_name, o_size]
|
||||||
else:
|
|
||||||
return ["", 0] # no valid entry
|
|
||||||
|
|
||||||
|
is_section = re.match(RE_STD_SECTION_GCC, line)
|
||||||
|
if is_section:
|
||||||
|
o_size = int(is_section.group(2), 16)
|
||||||
|
if o_size:
|
||||||
|
o_name = self.parse_object_name_gcc(is_section.group(3))
|
||||||
|
return [o_name, o_size]
|
||||||
|
|
||||||
|
return ["", 0]
|
||||||
|
|
||||||
def parse_map_file_gcc(self, file_desc):
|
def parse_map_file_gcc(self, file_desc):
|
||||||
""" Main logic to decode gcc map files
|
""" Main logic to decode gcc map files
|
||||||
|
@ -231,30 +198,34 @@ class MemapParser(object):
|
||||||
current_section = 'unknown'
|
current_section = 'unknown'
|
||||||
|
|
||||||
with file_desc as infile:
|
with file_desc as infile:
|
||||||
|
|
||||||
# Search area to parse
|
|
||||||
for line in infile:
|
for line in infile:
|
||||||
if line.startswith('Linker script and memory map'):
|
if line.startswith('Linker script and memory map'):
|
||||||
current_section = "unknown"
|
current_section = "unknown"
|
||||||
break
|
break
|
||||||
|
|
||||||
# Start decoding the map file
|
|
||||||
for line in infile:
|
for line in infile:
|
||||||
|
next_section = self.check_new_section_gcc(line)
|
||||||
|
|
||||||
change_section = self.check_new_section_gcc(line)
|
if next_section == "OUTPUT":
|
||||||
|
|
||||||
if change_section == "OUTPUT": # finish parsing file: exit
|
|
||||||
break
|
break
|
||||||
elif change_section != False:
|
elif next_section:
|
||||||
current_section = change_section
|
current_section = next_section
|
||||||
|
|
||||||
[object_name, object_size] = self.parse_section_gcc(line)
|
object_name, object_size = self.parse_section_gcc(line)
|
||||||
|
|
||||||
if object_size == 0 or object_name == "":
|
self.module_add(object_name, object_size, current_section)
|
||||||
pass
|
|
||||||
|
common_prefix = os.path.dirname(os.path.commonprefix([
|
||||||
|
o for o in self.modules.keys() if (o.endswith(".o") and not o.startswith("[lib]"))]))
|
||||||
|
new_modules = {}
|
||||||
|
for name, stats in self.modules.items():
|
||||||
|
if name.startswith("[lib]"):
|
||||||
|
new_modules[name] = stats
|
||||||
|
elif name.endswith(".o"):
|
||||||
|
new_modules[os.path.relpath(name, common_prefix)] = stats
|
||||||
else:
|
else:
|
||||||
self.module_add(object_name, object_size,\
|
new_modules[name] = stats
|
||||||
current_section)
|
self.modules = new_modules
|
||||||
|
|
||||||
def parse_object_name_armcc(self, line):
|
def parse_object_name_armcc(self, line):
|
||||||
""" Parse object file
|
""" Parse object file
|
||||||
|
@ -268,14 +239,9 @@ class MemapParser(object):
|
||||||
return line
|
return line
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
is_obj = re.match(RE_OBJECT_ARMCC, line)
|
||||||
RE_OBJECT_ARMCC = r'(.+\.(l|ar))\((.+\.o)\)'
|
if is_obj:
|
||||||
test_re_obj_name = re.match(RE_OBJECT_ARMCC, line)
|
object_name = os.path.basename(is_obj.group(1)) + '/' + is_obj.group(3)
|
||||||
|
|
||||||
if test_re_obj_name:
|
|
||||||
object_name = test_re_obj_name.group(1) + '/' + \
|
|
||||||
test_re_obj_name.group(2)
|
|
||||||
|
|
||||||
return '[lib]/' + object_name
|
return '[lib]/' + object_name
|
||||||
else:
|
else:
|
||||||
print "Malformed input found when parsing ARMCC map: %s" % line
|
print "Malformed input found when parsing ARMCC map: %s" % line
|
||||||
|
@ -321,7 +287,7 @@ class MemapParser(object):
|
||||||
else:
|
else:
|
||||||
return ["", 0, ""]
|
return ["", 0, ""]
|
||||||
|
|
||||||
def parse_object_name_iar(self, line):
|
def parse_object_name_iar(self, object_name):
|
||||||
""" Parse object file
|
""" Parse object file
|
||||||
|
|
||||||
Positional arguments:
|
Positional arguments:
|
||||||
|
@ -329,10 +295,11 @@ class MemapParser(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# simple object (not library)
|
# simple object (not library)
|
||||||
if line[-2] == '.' and line[-1] == 'o':
|
if object_name.endswith(".o"):
|
||||||
object_name = line
|
try:
|
||||||
|
return self.cmd_modules[object_name]
|
||||||
|
except KeyError:
|
||||||
return object_name
|
return object_name
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return '[misc]'
|
return '[misc]'
|
||||||
|
|
||||||
|
@ -361,11 +328,11 @@ class MemapParser(object):
|
||||||
|
|
||||||
size = int(test_re_iar.group(4), 16)
|
size = int(test_re_iar.group(4), 16)
|
||||||
|
|
||||||
if test_re_iar.group(2) == 'const' or \
|
if (test_re_iar.group(2) == 'const' or
|
||||||
test_re_iar.group(2) == 'ro code':
|
test_re_iar.group(2) == 'ro code'):
|
||||||
section = '.text'
|
section = '.text'
|
||||||
elif test_re_iar.group(2) == 'zero' or \
|
elif (test_re_iar.group(2) == 'zero' or
|
||||||
test_re_iar.group(2) == 'uninit':
|
test_re_iar.group(2) == 'uninit'):
|
||||||
if test_re_iar.group(1)[0:4] == 'HEAP':
|
if test_re_iar.group(1)[0:4] == 'HEAP':
|
||||||
section = '.heap'
|
section = '.heap'
|
||||||
elif test_re_iar.group(1)[0:6] == 'CSTACK':
|
elif test_re_iar.group(1)[0:6] == 'CSTACK':
|
||||||
|
@ -379,8 +346,7 @@ class MemapParser(object):
|
||||||
print "Malformed input found when parsing IAR map: %s" % line
|
print "Malformed input found when parsing IAR map: %s" % line
|
||||||
|
|
||||||
# lookup object in dictionary and return module name
|
# lookup object in dictionary and return module name
|
||||||
temp = test_re_iar.group(5)
|
object_name = self.parse_object_name_iar(test_re_iar.group(5))
|
||||||
object_name = self.parse_object_name_iar(temp)
|
|
||||||
|
|
||||||
return [object_name, size, section]
|
return [object_name, size, section]
|
||||||
|
|
||||||
|
@ -403,14 +369,20 @@ class MemapParser(object):
|
||||||
|
|
||||||
# Start decoding the map file
|
# Start decoding the map file
|
||||||
for line in infile:
|
for line in infile:
|
||||||
|
self.module_add(*self.parse_section_armcc(line))
|
||||||
|
|
||||||
[object_name, object_size, section] = \
|
common_prefix = os.path.dirname(os.path.commonprefix([
|
||||||
self.parse_section_armcc(line)
|
o for o in self.modules.keys() if (o.endswith(".o") and o != "anon$$obj.o" and not o.startswith("[lib]"))]))
|
||||||
|
new_modules = {}
|
||||||
if object_size == 0 or object_name == "" or section == "":
|
for name, stats in self.modules.items():
|
||||||
pass
|
if name == "anon$$obj.o" or name.startswith("[lib]"):
|
||||||
|
new_modules[name] = stats
|
||||||
|
elif name.endswith(".o"):
|
||||||
|
new_modules[os.path.relpath(name, common_prefix)] = stats
|
||||||
else:
|
else:
|
||||||
self.module_add(object_name, object_size, section)
|
new_modules[name] = stats
|
||||||
|
self.modules = new_modules
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def check_new_library_iar(self, line):
|
def check_new_library_iar(self, line):
|
||||||
|
@ -420,7 +392,6 @@ class MemapParser(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RE_LIBRARY_IAR = re.compile(r'^(.+\.a)\:.+$')
|
|
||||||
|
|
||||||
test_address_line = re.match(RE_LIBRARY_IAR, line)
|
test_address_line = re.match(RE_LIBRARY_IAR, line)
|
||||||
|
|
||||||
|
@ -441,8 +412,6 @@ class MemapParser(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RE_OBJECT_LIBRARY_IAR = re.compile(r'^\s+(.+\.o)\s.*')
|
|
||||||
|
|
||||||
test_address_line = re.match(RE_OBJECT_LIBRARY_IAR, line)
|
test_address_line = re.match(RE_OBJECT_LIBRARY_IAR, line)
|
||||||
|
|
||||||
if test_address_line:
|
if test_address_line:
|
||||||
|
@ -450,6 +419,25 @@ class MemapParser(object):
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def parse_iar_command_line(self, lines):
|
||||||
|
"""Parse the files passed on the command line to the iar linker
|
||||||
|
|
||||||
|
Positional arguments:
|
||||||
|
lines -- an iterator over the lines within a file
|
||||||
|
"""
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith("*"):
|
||||||
|
break
|
||||||
|
is_cmdline_file = RE_CMDLINE_FILE_IAR.match(line)
|
||||||
|
if is_cmdline_file:
|
||||||
|
full_path = is_cmdline_file.group(1)
|
||||||
|
self.cmd_modules[os.path.basename(full_path)] = full_path
|
||||||
|
|
||||||
|
common_prefix = os.path.dirname(os.path.commonprefix(self.cmd_modules.values()))
|
||||||
|
self.cmd_modules = {s: os.path.relpath(f, common_prefix)
|
||||||
|
for s, f in self.cmd_modules.items()}
|
||||||
|
|
||||||
|
|
||||||
def parse_map_file_iar(self, file_desc):
|
def parse_map_file_iar(self, file_desc):
|
||||||
""" Main logic to decode IAR map files
|
""" Main logic to decode IAR map files
|
||||||
|
|
||||||
|
@ -457,106 +445,38 @@ class MemapParser(object):
|
||||||
file_desc - a file like object to parse as an IAR map file
|
file_desc - a file like object to parse as an IAR map file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# first round, search for objects
|
|
||||||
with file_desc as infile:
|
with file_desc as infile:
|
||||||
# Search area to parse
|
self.parse_iar_command_line(infile)
|
||||||
|
|
||||||
for line in infile:
|
for line in infile:
|
||||||
if line.startswith(' Section '):
|
if line.startswith(' Section '):
|
||||||
break
|
break
|
||||||
|
|
||||||
# Start decoding the map file
|
|
||||||
for line in infile:
|
for line in infile:
|
||||||
|
self.module_add(*self.parse_section_iar(line))
|
||||||
[name, size, section] = self.parse_section_iar(line)
|
|
||||||
|
|
||||||
if size == 0 or name == "" or section == "":
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.module_add(name, size, section)
|
|
||||||
|
|
||||||
if line.startswith('*** MODULE SUMMARY'): # finish section
|
if line.startswith('*** MODULE SUMMARY'): # finish section
|
||||||
break
|
break
|
||||||
|
|
||||||
# Start decoding the map file
|
|
||||||
current_library = ""
|
current_library = ""
|
||||||
for line in infile:
|
for line in infile:
|
||||||
|
|
||||||
library = self.check_new_library_iar(line)
|
library = self.check_new_library_iar(line)
|
||||||
|
|
||||||
if library != "":
|
if library:
|
||||||
current_library = library
|
current_library = library
|
||||||
|
|
||||||
object_name = self.check_new_object_lib_iar(line)
|
object_name = self.check_new_object_lib_iar(line)
|
||||||
|
|
||||||
if object_name != "" and current_library != "":
|
if object_name and current_library:
|
||||||
|
print("Replacing module", object_name, current_library)
|
||||||
temp = '[lib]' + '/'+ current_library + '/'+ object_name
|
temp = '[lib]' + '/'+ current_library + '/'+ object_name
|
||||||
self.module_replace(object_name, temp)
|
self.module_replace(object_name, temp)
|
||||||
|
|
||||||
|
|
||||||
export_formats = ["json", "csv-ci", "table"]
|
|
||||||
|
|
||||||
def list_dir_obj(self, path):
|
|
||||||
""" Searches all objects in BUILD directory and creates list
|
|
||||||
|
|
||||||
Positional arguments:
|
|
||||||
path - the path to a map file
|
|
||||||
"""
|
|
||||||
|
|
||||||
path = path.replace('\\', '/')
|
|
||||||
|
|
||||||
# check location of map file
|
|
||||||
RE_PATH_MAP_FILE = r'^(.+)\/.+\.map$'
|
|
||||||
test_re = re.match(RE_PATH_MAP_FILE, path)
|
|
||||||
|
|
||||||
if test_re:
|
|
||||||
search_path = test_re.group(1)
|
|
||||||
else:
|
|
||||||
print "Warning: this doesn't look like an mbed project"
|
|
||||||
return
|
|
||||||
|
|
||||||
# create empty disctionary
|
|
||||||
self.modules = dict()
|
|
||||||
|
|
||||||
# search for object files
|
|
||||||
for root, _, obj_files in os.walk(search_path):
|
|
||||||
for obj_file in obj_files:
|
|
||||||
if obj_file.endswith(".o"):
|
|
||||||
|
|
||||||
txt = os.path.join(root, obj_file)
|
|
||||||
|
|
||||||
txt = txt.replace('\\', '/')
|
|
||||||
|
|
||||||
# add relative path + object to list
|
|
||||||
self.module_init(txt[len(search_path)+1:])
|
|
||||||
|
|
||||||
# The code below is a special case for TESTS.
|
|
||||||
# mbed-os lives in a separate location and we need to explicitly search
|
|
||||||
# their object files skiping the TESTS folder (already scanned above)
|
|
||||||
|
|
||||||
# check location of mbed-os
|
|
||||||
RE_PATH_MAP_FILE = r'^(.+)\/mbed-os\/.*TESTS\/.+\.map$'
|
|
||||||
test_re = re.match(RE_PATH_MAP_FILE, path)
|
|
||||||
|
|
||||||
if test_re == None:
|
|
||||||
return
|
|
||||||
|
|
||||||
search_path = test_re.group(1)
|
|
||||||
|
|
||||||
# search for object files
|
|
||||||
for root, _, obj_files in os.walk(search_path):
|
|
||||||
for obj_file in obj_files:
|
|
||||||
if 'TESTS' not in root and obj_file.endswith(".o"):
|
|
||||||
|
|
||||||
txt = os.path.join(root, obj_file)
|
|
||||||
txt = txt.replace('\\', '/')
|
|
||||||
|
|
||||||
# add relative path + object to list
|
|
||||||
self.module_init(txt[len(search_path)+1:])
|
|
||||||
|
|
||||||
|
|
||||||
def reduce_depth(self, depth):
|
def reduce_depth(self, depth):
|
||||||
"""
|
"""
|
||||||
prints list of directories and objects. Examples:
|
populates the short_modules attribute with a truncated module list
|
||||||
|
|
||||||
(1) depth = 1:
|
(1) depth = 1:
|
||||||
main.o
|
main.o
|
||||||
|
@ -568,43 +488,19 @@ class MemapParser(object):
|
||||||
mbed-os/drivers
|
mbed-os/drivers
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# depth 0 or None shows all entries
|
|
||||||
if depth == 0 or depth == None:
|
if depth == 0 or depth == None:
|
||||||
self.short_modules = deepcopy(self.modules)
|
self.short_modules = deepcopy(self.modules)
|
||||||
return
|
else:
|
||||||
|
|
||||||
self.short_modules = dict()
|
self.short_modules = dict()
|
||||||
|
for module_name, v in self.modules.items():
|
||||||
# create reduced list
|
split_name = module_name.split('/')
|
||||||
for line in self.modules:
|
if split_name[0] == '':
|
||||||
|
split_name = split_name[1:]
|
||||||
data = line.split('/')
|
new_name = "/".join(split_name[:depth])
|
||||||
ndir = len(data)
|
self.short_modules.setdefault(new_name, {})
|
||||||
|
for section_idx, value in v.items():
|
||||||
temp = ''
|
self.short_modules[new_name].setdefault(section_idx, 0)
|
||||||
count = 0
|
self.short_modules[new_name][section_idx] += self.modules[module_name][section_idx]
|
||||||
|
|
||||||
# iterate until the max depth level
|
|
||||||
max_level = min(depth, ndir)
|
|
||||||
|
|
||||||
# rebuild the path based on depth level
|
|
||||||
while count < max_level:
|
|
||||||
if count > 0: # ignore '/' from first entry
|
|
||||||
temp = temp + '/'
|
|
||||||
|
|
||||||
temp = temp + data[count]
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
if temp not in self.short_modules:
|
|
||||||
temp_dic = dict()
|
|
||||||
for section_idx in self.all_sections:
|
|
||||||
temp_dic[section_idx] = 0
|
|
||||||
self.short_modules[temp] = temp_dic
|
|
||||||
|
|
||||||
for section_idx in self.all_sections:
|
|
||||||
self.short_modules[temp][section_idx] += \
|
|
||||||
self.modules[line][section_idx]
|
|
||||||
|
|
||||||
|
|
||||||
export_formats = ["json", "csv-ci", "table"]
|
export_formats = ["json", "csv-ci", "table"]
|
||||||
|
@ -728,12 +624,12 @@ class MemapParser(object):
|
||||||
def compute_report(self):
|
def compute_report(self):
|
||||||
""" Generates summary of memory usage for main areas
|
""" Generates summary of memory usage for main areas
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for k in self.sections:
|
for k in self.sections:
|
||||||
self.subtotal[k] = 0
|
self.subtotal[k] = 0
|
||||||
|
|
||||||
for i in sorted(self.short_modules):
|
for i in self.short_modules:
|
||||||
for k in self.sections:
|
for k in self.sections:
|
||||||
|
self.short_modules[i].setdefault(k, 0)
|
||||||
self.subtotal[k] += self.short_modules[i][k]
|
self.subtotal[k] += self.short_modules[i][k]
|
||||||
|
|
||||||
self.mem_summary = {
|
self.mem_summary = {
|
||||||
|
@ -765,10 +661,6 @@ class MemapParser(object):
|
||||||
result = True
|
result = True
|
||||||
try:
|
try:
|
||||||
with open(mapfile, 'r') as file_input:
|
with open(mapfile, 'r') as file_input:
|
||||||
|
|
||||||
# Common to all toolchains: first search for objects in BUILD
|
|
||||||
self.list_dir_obj(os.path.abspath(mapfile))
|
|
||||||
|
|
||||||
if toolchain in ("ARM", "ARM_STD", "ARM_MICRO", "ARMC6"):
|
if toolchain in ("ARM", "ARM_STD", "ARM_MICRO", "ARMC6"):
|
||||||
self.parse_map_file_armcc(file_input)
|
self.parse_map_file_armcc(file_input)
|
||||||
elif toolchain == "GCC_ARM" or toolchain == "GCC_CR":
|
elif toolchain == "GCC_ARM" or toolchain == "GCC_CR":
|
||||||
|
@ -778,8 +670,6 @@ class MemapParser(object):
|
||||||
else:
|
else:
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
self.remove_unused_modules()
|
|
||||||
|
|
||||||
except IOError as error:
|
except IOError as error:
|
||||||
print "I/O error({0}): {1}".format(error.errno, error.strerror)
|
print "I/O error({0}): {1}".format(error.errno, error.strerror)
|
||||||
result = False
|
result = False
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
"asm": [],
|
"asm": [],
|
||||||
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
|
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
|
||||||
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
|
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
|
||||||
"ld": []
|
"ld": ["--show_full_path"]
|
||||||
},
|
},
|
||||||
"uARM": {
|
"uARM": {
|
||||||
"common": ["-c", "--gnu", "-Otime", "--split_sections",
|
"common": ["-c", "--gnu", "-Otime", "--split_sections",
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"asm": [],
|
"asm": [],
|
||||||
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
|
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
|
||||||
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
|
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
|
||||||
"ld": []
|
"ld": ["--show_full_path"]
|
||||||
},
|
},
|
||||||
"uARM": {
|
"uARM": {
|
||||||
"common": ["-c", "--gnu", "-Otime", "--split_sections",
|
"common": ["-c", "--gnu", "-Otime", "--split_sections",
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"asm": [],
|
"asm": [],
|
||||||
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
|
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
|
||||||
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
|
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
|
||||||
"ld": []
|
"ld": ["--show_full_path"]
|
||||||
},
|
},
|
||||||
"uARM": {
|
"uARM": {
|
||||||
"common": ["-c", "--gnu", "-Ospace", "--split_sections",
|
"common": ["-c", "--gnu", "-Ospace", "--split_sections",
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
Component: ARM Compiler 5.06 update 5 (build 528) Tool: armlink [4d35e2]
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Memory Map of the image
|
||||||
|
|
||||||
|
Image Entry point : 0x0001b0c1
|
||||||
|
|
||||||
|
Load Region LR_IROM1 (Base: 0x0001b000, Size: 0x0000ed04, Max: 0x00025000, ABSOLUTE, COMPRESSED[0x0000e23c])
|
||||||
|
|
||||||
|
Execution Region ER_IROM1 (Base: 0x0001b000, Size: 0x0000e1c4, Max: 0x00025000, ABSOLUTE)
|
||||||
|
|
||||||
|
Base Addr Size Type Attr Idx E Section Name Object
|
||||||
|
|
||||||
|
0x0001b000 0x000000c0 Data RO 7002 RESET /common/path/startup/startup.o
|
||||||
|
0x0001b0c0 0x00000008 Code RO 8820 * !!!main /installed/libs/../lib/armlib/c_p.l(__main.o)
|
||||||
|
0x0001b26c 0x00000098 Code RO 6076 .text /common/path/irqs/irqs.o
|
||||||
|
0x000206a0 0x00000036 Code RO 27 i._Z9time_funcPN4mbed5TimerEi /common/path/main.o
|
||||||
|
0x200039b4 0x00000018 Data RW 8092 .data /common/path/data/data.o
|
||||||
|
0x20003af8 0x00000198 Zero RW 57 .bss /common/path/data/data.o
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Image component sizes
|
||||||
|
|
||||||
|
|
||||||
|
Code (inc. data) RO Data RW Data ZI Data Debug
|
||||||
|
|
||||||
|
344 368 0 24 408 36188 Object Totals
|
||||||
|
8 0 0 0 0 7596 Library Totals
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
Code (inc. data) RO Data RW Data ZI Data Debug
|
||||||
|
|
||||||
|
352 376 0 24 408 17208 Grand Totals
|
||||||
|
352 376 0 24 408 17208 ELF Image Totals (compressed)
|
||||||
|
352 376 0 24 0 0 ROM Totals
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Total RO Size (Code + RO Data) 352 ( 0.35kB)
|
||||||
|
Total RW Size (RW Data + ZI Data) 432 ( 0.43kB)
|
||||||
|
Total ROM Size (Code + RO Data + RW Data) 376 ( 0.37kB)
|
||||||
|
|
||||||
|
==============================================================================
|
|
@ -0,0 +1,25 @@
|
||||||
|
Archive member included to satisfy reference by file (symbol)
|
||||||
|
|
||||||
|
Linker script and memory map
|
||||||
|
.text 0x000000000001b000 0x11a30
|
||||||
|
.Vectors 0x000000000001b000 0x98 /common/path/irqs/irqs.o
|
||||||
|
0x000000000001b168 0x36 /common/path/main.o
|
||||||
|
0x000000000001b168 count5(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int)
|
||||||
|
0x000000000001b200 0xc0 /common/path/startup/startup.o
|
||||||
|
0x000000000001b200 startup()
|
||||||
|
0x0000000000024020 0x8 /usr/lib/gcc/arm-none-eabi/7.1.0/../../../../arm-none-eabi/lib/armv6-m/libd16M_tlf.a(__main.o)
|
||||||
|
|
||||||
|
.data 0x0000000020002ef8 0xac8 load address 0x000000000002ca38
|
||||||
|
0x0000000020002ef8 __data_start__ = .
|
||||||
|
*(vtable)
|
||||||
|
*(.data*)
|
||||||
|
0x0000000020002ef8 0x18 /common/path/data/data.o
|
||||||
|
0x0000000020002ef8 some_global_var
|
||||||
|
|
||||||
|
.bss 0x0000000020003a80 0x2050 load address 0x000000000002d5c0
|
||||||
|
0x0000000020003a80 . = ALIGN (0x4)
|
||||||
|
0x0000000020003a80 __bss_start__ = .
|
||||||
|
*(.bss*)
|
||||||
|
.bss.completed.8574
|
||||||
|
.bss.counter 0x0000000020003c08 0x198 /common/path/data.o
|
||||||
|
0x0000000020003c08 some_zero_init_var
|
|
@ -0,0 +1,86 @@
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# IAR ELF Linker V7.80.1.28/LNX for ARM 18/Sep/2017 14:26:09
|
||||||
|
# Copyright 2007-2016 IAR Systems AB.
|
||||||
|
#
|
||||||
|
# Output file =
|
||||||
|
# /common/path/project.elf
|
||||||
|
# Map file =
|
||||||
|
# /common/path/project.map
|
||||||
|
# Command line =
|
||||||
|
# -f
|
||||||
|
# /common/path/.link_files.txt
|
||||||
|
# (-o
|
||||||
|
# --map=/common/path/project.map
|
||||||
|
# /common/path/project.elf
|
||||||
|
# /common/path/main.o
|
||||||
|
# /common/path/startup/startup.o
|
||||||
|
# /common/path/irqs/irqs.o
|
||||||
|
# /common/path/data/data.o
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
*******************************************************************************
|
||||||
|
*** RUNTIME MODEL ATTRIBUTES
|
||||||
|
***
|
||||||
|
|
||||||
|
CppFlavor = *
|
||||||
|
__CPP_Exceptions = Disabled
|
||||||
|
__CPP_Language = C++
|
||||||
|
__Heap_Handler = DLMalloc
|
||||||
|
__SystemLibrary = DLib
|
||||||
|
__dlib_dynamic_initialization = postponed
|
||||||
|
__dlib_has_iterator_debugging = 0
|
||||||
|
__dlib_jmp_buf_num_elements = 8
|
||||||
|
|
||||||
|
|
||||||
|
*******************************************************************************
|
||||||
|
*** PLACEMENT SUMMARY
|
||||||
|
***
|
||||||
|
|
||||||
|
"A0": place at 0x0001b000 { ro section .intvec };
|
||||||
|
"P1": place in [from 0x0001b0c0 to 0x0003ffff] { ro };
|
||||||
|
"P2": place in [from 0x20002ef8 to 0x20007fff] { rw, block HEAP, block CSTACK };
|
||||||
|
do not initialize { section .noinit };
|
||||||
|
initialize by copy { rw };
|
||||||
|
{ section .intvec };
|
||||||
|
|
||||||
|
Section Kind Address Size Object
|
||||||
|
------- ---- ------- ---- ------
|
||||||
|
"A0": 0xc0
|
||||||
|
.intvec ro code 0x0001b000 0xc0 startup.o [4]
|
||||||
|
- 0x0001b0c0 0xc0
|
||||||
|
|
||||||
|
"P1": 0x
|
||||||
|
.text ro code 0x0001c753 0x36 main.o [3]
|
||||||
|
.text ro code 0x0001cfff 0x98 irqs.o [5]
|
||||||
|
.text ro code 0x0001c778 0x8 __main.o [67]
|
||||||
|
|
||||||
|
"P2", part 1 of 2: 0x18
|
||||||
|
P2-1 0x20002ef8 0x18 <Init block>
|
||||||
|
.data inited 0x20002fa8 0x18 data.o [6]
|
||||||
|
|
||||||
|
"P2", part 2 of 2: 0x198
|
||||||
|
P2-2 0x20005388 0x198 <Init block>
|
||||||
|
.bss zero 0x20002fa8 0x198 data.o [6]
|
||||||
|
|
||||||
|
*******************************************************************************
|
||||||
|
*** INIT TABLE
|
||||||
|
***
|
||||||
|
|
||||||
|
*******************************************************************************
|
||||||
|
*** MODULE SUMMARY
|
||||||
|
***
|
||||||
|
|
||||||
|
d16M_tlf.a: [67]
|
||||||
|
__main.o 8
|
||||||
|
------------------------------------------------
|
||||||
|
Total: 8
|
||||||
|
|
||||||
|
Linker created
|
||||||
|
---------------------------------------------------
|
||||||
|
Grand Total:
|
||||||
|
|
||||||
|
*******************************************************************************
|
||||||
|
*** ENTRY LIST
|
||||||
|
***
|
|
@ -0,0 +1,61 @@
|
||||||
|
import sys
|
||||||
|
from io import open
|
||||||
|
from os.path import isfile, join, dirname
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from tools.memap import MemapParser
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
|
PARSED_ARM_DATA = {
|
||||||
|
"startup/startup.o": {".text": 0xc0},
|
||||||
|
"[lib]/c_p.l/__main.o": {".text": 8},
|
||||||
|
"irqs/irqs.o": {".text": 0x98},
|
||||||
|
"data/data.o": {".data": 0x18, ".bss": 0x198},
|
||||||
|
"main.o": {".text": 0x36},
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_parse_armcc():
|
||||||
|
memap = MemapParser()
|
||||||
|
memap.parse_map_file_armcc(open(join(dirname(__file__), "arm.map")))
|
||||||
|
assert memap.modules == PARSED_ARM_DATA
|
||||||
|
|
||||||
|
PARSED_IAR_GCC_DATA = {
|
||||||
|
"startup/startup.o": {".text": 0xc0},
|
||||||
|
"[lib]/d16M_tlf.a/__main.o": {".text": 8},
|
||||||
|
"irqs/irqs.o": {".text": 0x98},
|
||||||
|
"data/data.o": {".data": 0x18, ".bss": 0x198},
|
||||||
|
"main.o": {".text": 0x36},
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_parse_iar():
|
||||||
|
memap = MemapParser()
|
||||||
|
memap.parse_map_file_iar(open(join(dirname(__file__), "iar.map")))
|
||||||
|
assert memap.modules == PARSED_IAR_GCC_DATA
|
||||||
|
|
||||||
|
def test_parse_gcc():
|
||||||
|
memap = MemapParser()
|
||||||
|
memap.parse_map_file_gcc(open(join(dirname(__file__), "gcc.map")))
|
||||||
|
assert memap.modules == PARSED_IAR_GCC_DATA
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_empty_module():
|
||||||
|
memap = MemapParser()
|
||||||
|
old_modules = deepcopy(memap.modules)
|
||||||
|
memap.module_add("", 8, ".data")
|
||||||
|
assert(old_modules == memap.modules)
|
||||||
|
memap.module_add("main.o", 0, ".text")
|
||||||
|
assert(old_modules == memap.modules)
|
||||||
|
memap.module_add("main.o", 8, "")
|
||||||
|
assert(old_modules == memap.modules)
|
||||||
|
|
||||||
|
def test_add_full_module():
|
||||||
|
memap = MemapParser()
|
||||||
|
old_modules = deepcopy(memap.modules)
|
||||||
|
memap.module_add("main.o", 8, ".data")
|
||||||
|
assert(old_modules != memap.modules)
|
||||||
|
assert("main.o" in memap.modules)
|
||||||
|
assert(".data" in memap.modules["main.o"])
|
||||||
|
assert(memap.modules["main.o"][".data"] == 8)
|
|
@ -74,7 +74,7 @@ class ARM(mbedToolchain):
|
||||||
self.cc = [main_cc] + self.flags['common'] + self.flags['c']
|
self.cc = [main_cc] + self.flags['common'] + self.flags['c']
|
||||||
self.cppc = [main_cc] + self.flags['common'] + self.flags['c'] + self.flags['cxx']
|
self.cppc = [main_cc] + self.flags['common'] + self.flags['c'] + self.flags['cxx']
|
||||||
|
|
||||||
self.ld = [join(ARM_BIN, "armlink")]
|
self.ld = [join(ARM_BIN, "armlink")] + self.flags['ld']
|
||||||
|
|
||||||
self.ar = join(ARM_BIN, "armar")
|
self.ar = join(ARM_BIN, "armar")
|
||||||
self.elf2bin = join(ARM_BIN, "fromelf")
|
self.elf2bin = join(ARM_BIN, "fromelf")
|
||||||
|
|
Loading…
Reference in New Issue