takashi kadono
/
Nucleo446_SSD1331
Color Oled(SSD1331) connect to STMicroelectronics Nucleo-F466
mbed-os/tools/memap.py@3:f3764f852aa8, 2018-10-11 (annotated)
- Committer:
- kadonotakashi
- Date:
- Thu Oct 11 02:27:46 2018 +0000
- Revision:
- 3:f3764f852aa8
- Parent:
- 0:8fdf9a60065b
Nucreo 446 + SSD1331 test version;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kadonotakashi | 0:8fdf9a60065b | 1 | #!/usr/bin/env python |
kadonotakashi | 0:8fdf9a60065b | 2 | |
kadonotakashi | 0:8fdf9a60065b | 3 | """Memory Map File Analyser for ARM mbed""" |
kadonotakashi | 0:8fdf9a60065b | 4 | from __future__ import print_function, division, absolute_import |
kadonotakashi | 0:8fdf9a60065b | 5 | |
kadonotakashi | 0:8fdf9a60065b | 6 | from abc import abstractmethod, ABCMeta |
kadonotakashi | 0:8fdf9a60065b | 7 | from sys import stdout, exit, argv, path |
kadonotakashi | 0:8fdf9a60065b | 8 | from os import sep, rename, remove |
kadonotakashi | 0:8fdf9a60065b | 9 | from os.path import (basename, dirname, join, relpath, abspath, commonprefix, |
kadonotakashi | 0:8fdf9a60065b | 10 | splitext, exists) |
kadonotakashi | 0:8fdf9a60065b | 11 | |
kadonotakashi | 0:8fdf9a60065b | 12 | # Be sure that the tools directory is in the search path |
kadonotakashi | 0:8fdf9a60065b | 13 | ROOT = abspath(join(dirname(__file__), "..")) |
kadonotakashi | 0:8fdf9a60065b | 14 | path.insert(0, ROOT) |
kadonotakashi | 0:8fdf9a60065b | 15 | |
kadonotakashi | 0:8fdf9a60065b | 16 | import re |
kadonotakashi | 0:8fdf9a60065b | 17 | import csv |
kadonotakashi | 0:8fdf9a60065b | 18 | import json |
kadonotakashi | 0:8fdf9a60065b | 19 | from argparse import ArgumentParser |
kadonotakashi | 0:8fdf9a60065b | 20 | from copy import deepcopy |
kadonotakashi | 0:8fdf9a60065b | 21 | from collections import defaultdict |
kadonotakashi | 0:8fdf9a60065b | 22 | from prettytable import PrettyTable, HEADER |
kadonotakashi | 0:8fdf9a60065b | 23 | from jinja2 import FileSystemLoader, StrictUndefined |
kadonotakashi | 0:8fdf9a60065b | 24 | from jinja2.environment import Environment |
kadonotakashi | 0:8fdf9a60065b | 25 | |
kadonotakashi | 0:8fdf9a60065b | 26 | from tools.utils import (argparse_filestring_type, argparse_lowercase_hyphen_type, |
kadonotakashi | 0:8fdf9a60065b | 27 | argparse_uppercase_type) |
kadonotakashi | 0:8fdf9a60065b | 28 | from tools.settings import COMPARE_FIXED |
kadonotakashi | 0:8fdf9a60065b | 29 | |
kadonotakashi | 0:8fdf9a60065b | 30 | |
kadonotakashi | 0:8fdf9a60065b | 31 | class _Parser(object): |
kadonotakashi | 0:8fdf9a60065b | 32 | """Internal interface for parsing""" |
kadonotakashi | 0:8fdf9a60065b | 33 | __metaclass__ = ABCMeta |
kadonotakashi | 0:8fdf9a60065b | 34 | SECTIONS = ('.text', '.data', '.bss', '.heap', '.stack') |
kadonotakashi | 0:8fdf9a60065b | 35 | MISC_FLASH_SECTIONS = ('.interrupts', '.flash_config') |
kadonotakashi | 0:8fdf9a60065b | 36 | OTHER_SECTIONS = ('.interrupts_ram', '.init', '.ARM.extab', |
kadonotakashi | 0:8fdf9a60065b | 37 | '.ARM.exidx', '.ARM.attributes', '.eh_frame', |
kadonotakashi | 0:8fdf9a60065b | 38 | '.init_array', '.fini_array', '.jcr', '.stab', |
kadonotakashi | 0:8fdf9a60065b | 39 | '.stabstr', '.ARM.exidx', '.ARM') |
kadonotakashi | 0:8fdf9a60065b | 40 | |
kadonotakashi | 0:8fdf9a60065b | 41 | def __init__(self): |
kadonotakashi | 0:8fdf9a60065b | 42 | self.modules = dict() |
kadonotakashi | 0:8fdf9a60065b | 43 | |
kadonotakashi | 0:8fdf9a60065b | 44 | def module_add(self, object_name, size, section): |
kadonotakashi | 0:8fdf9a60065b | 45 | """ Adds a module or section to the list |
kadonotakashi | 0:8fdf9a60065b | 46 | |
kadonotakashi | 0:8fdf9a60065b | 47 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 48 | object_name - name of the entry to add |
kadonotakashi | 0:8fdf9a60065b | 49 | size - the size of the module being added |
kadonotakashi | 0:8fdf9a60065b | 50 | section - the section the module contributes to |
kadonotakashi | 0:8fdf9a60065b | 51 | """ |
kadonotakashi | 0:8fdf9a60065b | 52 | if not object_name or not size or not section: |
kadonotakashi | 0:8fdf9a60065b | 53 | return |
kadonotakashi | 0:8fdf9a60065b | 54 | |
kadonotakashi | 0:8fdf9a60065b | 55 | if object_name in self.modules: |
kadonotakashi | 0:8fdf9a60065b | 56 | self.modules[object_name].setdefault(section, 0) |
kadonotakashi | 0:8fdf9a60065b | 57 | self.modules[object_name][section] += size |
kadonotakashi | 0:8fdf9a60065b | 58 | return |
kadonotakashi | 0:8fdf9a60065b | 59 | |
kadonotakashi | 0:8fdf9a60065b | 60 | obj_split = sep + basename(object_name) |
kadonotakashi | 0:8fdf9a60065b | 61 | for module_path, contents in self.modules.items(): |
kadonotakashi | 0:8fdf9a60065b | 62 | if module_path.endswith(obj_split) or module_path == object_name: |
kadonotakashi | 0:8fdf9a60065b | 63 | contents.setdefault(section, 0) |
kadonotakashi | 0:8fdf9a60065b | 64 | contents[section] += size |
kadonotakashi | 0:8fdf9a60065b | 65 | return |
kadonotakashi | 0:8fdf9a60065b | 66 | |
kadonotakashi | 0:8fdf9a60065b | 67 | new_module = defaultdict(int) |
kadonotakashi | 0:8fdf9a60065b | 68 | new_module[section] = size |
kadonotakashi | 0:8fdf9a60065b | 69 | self.modules[object_name] = new_module |
kadonotakashi | 0:8fdf9a60065b | 70 | |
kadonotakashi | 0:8fdf9a60065b | 71 | def module_replace(self, old_object, new_object): |
kadonotakashi | 0:8fdf9a60065b | 72 | """ Replaces an object name with a new one |
kadonotakashi | 0:8fdf9a60065b | 73 | """ |
kadonotakashi | 0:8fdf9a60065b | 74 | if old_object in self.modules: |
kadonotakashi | 0:8fdf9a60065b | 75 | self.modules[new_object] = self.modules[old_object] |
kadonotakashi | 0:8fdf9a60065b | 76 | del self.modules[old_object] |
kadonotakashi | 0:8fdf9a60065b | 77 | |
kadonotakashi | 0:8fdf9a60065b | 78 | @abstractmethod |
kadonotakashi | 0:8fdf9a60065b | 79 | def parse_mapfile(self, mapfile): |
kadonotakashi | 0:8fdf9a60065b | 80 | """Parse a given file object pointing to a map file |
kadonotakashi | 0:8fdf9a60065b | 81 | |
kadonotakashi | 0:8fdf9a60065b | 82 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 83 | mapfile - an open file object that reads a map file |
kadonotakashi | 0:8fdf9a60065b | 84 | |
kadonotakashi | 0:8fdf9a60065b | 85 | return value - a dict mapping from object names to section dicts, |
kadonotakashi | 0:8fdf9a60065b | 86 | where a section dict maps from sections to sizes |
kadonotakashi | 0:8fdf9a60065b | 87 | """ |
kadonotakashi | 0:8fdf9a60065b | 88 | raise NotImplemented |
kadonotakashi | 0:8fdf9a60065b | 89 | |
kadonotakashi | 0:8fdf9a60065b | 90 | |
kadonotakashi | 0:8fdf9a60065b | 91 | class _GccParser(_Parser): |
kadonotakashi | 0:8fdf9a60065b | 92 | RE_OBJECT_FILE = re.compile(r'^(.+\/.+\.o)$') |
kadonotakashi | 0:8fdf9a60065b | 93 | RE_LIBRARY_OBJECT = re.compile(r'^.+' + r''.format(sep) + r'lib((.+\.a)\((.+\.o)\))$') |
kadonotakashi | 0:8fdf9a60065b | 94 | RE_STD_SECTION = re.compile(r'^\s+.*0x(\w{8,16})\s+0x(\w+)\s(.+)$') |
kadonotakashi | 0:8fdf9a60065b | 95 | RE_FILL_SECTION = re.compile(r'^\s*\*fill\*\s+0x(\w{8,16})\s+0x(\w+).*$') |
kadonotakashi | 0:8fdf9a60065b | 96 | |
kadonotakashi | 0:8fdf9a60065b | 97 | ALL_SECTIONS = _Parser.SECTIONS + _Parser.OTHER_SECTIONS + \ |
kadonotakashi | 0:8fdf9a60065b | 98 | _Parser.MISC_FLASH_SECTIONS + ('unknown', 'OUTPUT') |
kadonotakashi | 0:8fdf9a60065b | 99 | |
kadonotakashi | 0:8fdf9a60065b | 100 | def check_new_section(self, line): |
kadonotakashi | 0:8fdf9a60065b | 101 | """ Check whether a new section in a map file has been detected |
kadonotakashi | 0:8fdf9a60065b | 102 | |
kadonotakashi | 0:8fdf9a60065b | 103 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 104 | line - the line to check for a new section |
kadonotakashi | 0:8fdf9a60065b | 105 | |
kadonotakashi | 0:8fdf9a60065b | 106 | return value - A section name, if a new section was found, False |
kadonotakashi | 0:8fdf9a60065b | 107 | otherwise |
kadonotakashi | 0:8fdf9a60065b | 108 | """ |
kadonotakashi | 0:8fdf9a60065b | 109 | for i in self.ALL_SECTIONS: |
kadonotakashi | 0:8fdf9a60065b | 110 | if line.startswith(i): |
kadonotakashi | 0:8fdf9a60065b | 111 | # should name of the section (assuming it's a known one) |
kadonotakashi | 0:8fdf9a60065b | 112 | return i |
kadonotakashi | 0:8fdf9a60065b | 113 | |
kadonotakashi | 0:8fdf9a60065b | 114 | if line.startswith('.'): |
kadonotakashi | 0:8fdf9a60065b | 115 | return 'unknown' # all others are classified are unknown |
kadonotakashi | 0:8fdf9a60065b | 116 | else: |
kadonotakashi | 0:8fdf9a60065b | 117 | return False # everything else, means no change in section |
kadonotakashi | 0:8fdf9a60065b | 118 | |
kadonotakashi | 0:8fdf9a60065b | 119 | |
kadonotakashi | 0:8fdf9a60065b | 120 | def parse_object_name(self, line): |
kadonotakashi | 0:8fdf9a60065b | 121 | """ Parse a path to object file |
kadonotakashi | 0:8fdf9a60065b | 122 | |
kadonotakashi | 0:8fdf9a60065b | 123 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 124 | line - the path to parse the object and module name from |
kadonotakashi | 0:8fdf9a60065b | 125 | |
kadonotakashi | 0:8fdf9a60065b | 126 | return value - an object file name |
kadonotakashi | 0:8fdf9a60065b | 127 | """ |
kadonotakashi | 0:8fdf9a60065b | 128 | test_re_mbed_os_name = re.match(self.RE_OBJECT_FILE, line) |
kadonotakashi | 0:8fdf9a60065b | 129 | |
kadonotakashi | 0:8fdf9a60065b | 130 | if test_re_mbed_os_name: |
kadonotakashi | 0:8fdf9a60065b | 131 | object_name = test_re_mbed_os_name.group(1) |
kadonotakashi | 0:8fdf9a60065b | 132 | |
kadonotakashi | 0:8fdf9a60065b | 133 | # corner case: certain objects are provided by the GCC toolchain |
kadonotakashi | 0:8fdf9a60065b | 134 | if 'arm-none-eabi' in line: |
kadonotakashi | 0:8fdf9a60065b | 135 | return join('[lib]', 'misc', basename(object_name)) |
kadonotakashi | 0:8fdf9a60065b | 136 | return object_name |
kadonotakashi | 0:8fdf9a60065b | 137 | |
kadonotakashi | 0:8fdf9a60065b | 138 | else: |
kadonotakashi | 0:8fdf9a60065b | 139 | test_re_obj_name = re.match(self.RE_LIBRARY_OBJECT, line) |
kadonotakashi | 0:8fdf9a60065b | 140 | |
kadonotakashi | 0:8fdf9a60065b | 141 | if test_re_obj_name: |
kadonotakashi | 0:8fdf9a60065b | 142 | return join('[lib]', test_re_obj_name.group(2), |
kadonotakashi | 0:8fdf9a60065b | 143 | test_re_obj_name.group(3)) |
kadonotakashi | 0:8fdf9a60065b | 144 | else: |
kadonotakashi | 0:8fdf9a60065b | 145 | print("Unknown object name found in GCC map file: %s" % line) |
kadonotakashi | 0:8fdf9a60065b | 146 | return '[misc]' |
kadonotakashi | 0:8fdf9a60065b | 147 | |
kadonotakashi | 0:8fdf9a60065b | 148 | def parse_section(self, line): |
kadonotakashi | 0:8fdf9a60065b | 149 | """ Parse data from a section of gcc map file |
kadonotakashi | 0:8fdf9a60065b | 150 | |
kadonotakashi | 0:8fdf9a60065b | 151 | examples: |
kadonotakashi | 0:8fdf9a60065b | 152 | 0x00004308 0x7c ./BUILD/K64F/GCC_ARM/mbed-os/hal/targets/hal/TARGET_Freescale/TARGET_KPSDK_MCUS/spi_api.o |
kadonotakashi | 0:8fdf9a60065b | 153 | .text 0x00000608 0x198 ./BUILD/K64F/GCC_ARM/mbed-os/core/mbed-rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN/HAL_CM4.o |
kadonotakashi | 0:8fdf9a60065b | 154 | |
kadonotakashi | 0:8fdf9a60065b | 155 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 156 | line - the line to parse a section from |
kadonotakashi | 0:8fdf9a60065b | 157 | """ |
kadonotakashi | 0:8fdf9a60065b | 158 | is_fill = re.match(self.RE_FILL_SECTION, line) |
kadonotakashi | 0:8fdf9a60065b | 159 | if is_fill: |
kadonotakashi | 0:8fdf9a60065b | 160 | o_name = '[fill]' |
kadonotakashi | 0:8fdf9a60065b | 161 | o_size = int(is_fill.group(2), 16) |
kadonotakashi | 0:8fdf9a60065b | 162 | return [o_name, o_size] |
kadonotakashi | 0:8fdf9a60065b | 163 | |
kadonotakashi | 0:8fdf9a60065b | 164 | is_section = re.match(self.RE_STD_SECTION, line) |
kadonotakashi | 0:8fdf9a60065b | 165 | if is_section: |
kadonotakashi | 0:8fdf9a60065b | 166 | o_size = int(is_section.group(2), 16) |
kadonotakashi | 0:8fdf9a60065b | 167 | if o_size: |
kadonotakashi | 0:8fdf9a60065b | 168 | o_name = self.parse_object_name(is_section.group(3)) |
kadonotakashi | 0:8fdf9a60065b | 169 | return [o_name, o_size] |
kadonotakashi | 0:8fdf9a60065b | 170 | |
kadonotakashi | 0:8fdf9a60065b | 171 | return ["", 0] |
kadonotakashi | 0:8fdf9a60065b | 172 | |
kadonotakashi | 0:8fdf9a60065b | 173 | def parse_mapfile(self, file_desc): |
kadonotakashi | 0:8fdf9a60065b | 174 | """ Main logic to decode gcc map files |
kadonotakashi | 0:8fdf9a60065b | 175 | |
kadonotakashi | 0:8fdf9a60065b | 176 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 177 | file_desc - a stream object to parse as a gcc map file |
kadonotakashi | 0:8fdf9a60065b | 178 | """ |
kadonotakashi | 0:8fdf9a60065b | 179 | current_section = 'unknown' |
kadonotakashi | 0:8fdf9a60065b | 180 | |
kadonotakashi | 0:8fdf9a60065b | 181 | with file_desc as infile: |
kadonotakashi | 0:8fdf9a60065b | 182 | for line in infile: |
kadonotakashi | 0:8fdf9a60065b | 183 | if line.startswith('Linker script and memory map'): |
kadonotakashi | 0:8fdf9a60065b | 184 | current_section = "unknown" |
kadonotakashi | 0:8fdf9a60065b | 185 | break |
kadonotakashi | 0:8fdf9a60065b | 186 | |
kadonotakashi | 0:8fdf9a60065b | 187 | for line in infile: |
kadonotakashi | 0:8fdf9a60065b | 188 | next_section = self.check_new_section(line) |
kadonotakashi | 0:8fdf9a60065b | 189 | |
kadonotakashi | 0:8fdf9a60065b | 190 | if next_section == "OUTPUT": |
kadonotakashi | 0:8fdf9a60065b | 191 | break |
kadonotakashi | 0:8fdf9a60065b | 192 | elif next_section: |
kadonotakashi | 0:8fdf9a60065b | 193 | current_section = next_section |
kadonotakashi | 0:8fdf9a60065b | 194 | |
kadonotakashi | 0:8fdf9a60065b | 195 | object_name, object_size = self.parse_section(line) |
kadonotakashi | 0:8fdf9a60065b | 196 | self.module_add(object_name, object_size, current_section) |
kadonotakashi | 0:8fdf9a60065b | 197 | |
kadonotakashi | 0:8fdf9a60065b | 198 | common_prefix = dirname(commonprefix([ |
kadonotakashi | 0:8fdf9a60065b | 199 | o for o in self.modules.keys() if (o.endswith(".o") and not o.startswith("[lib]"))])) |
kadonotakashi | 0:8fdf9a60065b | 200 | new_modules = {} |
kadonotakashi | 0:8fdf9a60065b | 201 | for name, stats in self.modules.items(): |
kadonotakashi | 0:8fdf9a60065b | 202 | if name.startswith("[lib]"): |
kadonotakashi | 0:8fdf9a60065b | 203 | new_modules[name] = stats |
kadonotakashi | 0:8fdf9a60065b | 204 | elif name.endswith(".o"): |
kadonotakashi | 0:8fdf9a60065b | 205 | new_modules[relpath(name, common_prefix)] = stats |
kadonotakashi | 0:8fdf9a60065b | 206 | else: |
kadonotakashi | 0:8fdf9a60065b | 207 | new_modules[name] = stats |
kadonotakashi | 0:8fdf9a60065b | 208 | return new_modules |
kadonotakashi | 0:8fdf9a60065b | 209 | |
kadonotakashi | 0:8fdf9a60065b | 210 | |
kadonotakashi | 0:8fdf9a60065b | 211 | class _ArmccParser(_Parser): |
kadonotakashi | 0:8fdf9a60065b | 212 | RE = re.compile( |
kadonotakashi | 0:8fdf9a60065b | 213 | r'^\s+0x(\w{8})\s+0x(\w{8})\s+(\w+)\s+(\w+)\s+(\d+)\s+[*]?.+\s+(.+)$') |
kadonotakashi | 0:8fdf9a60065b | 214 | RE_OBJECT = re.compile(r'(.+\.(l|ar))\((.+\.o)\)') |
kadonotakashi | 0:8fdf9a60065b | 215 | |
kadonotakashi | 0:8fdf9a60065b | 216 | def parse_object_name(self, line): |
kadonotakashi | 0:8fdf9a60065b | 217 | """ Parse object file |
kadonotakashi | 0:8fdf9a60065b | 218 | |
kadonotakashi | 0:8fdf9a60065b | 219 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 220 | line - the line containing the object or library |
kadonotakashi | 0:8fdf9a60065b | 221 | """ |
kadonotakashi | 0:8fdf9a60065b | 222 | if line.endswith(".o"): |
kadonotakashi | 0:8fdf9a60065b | 223 | return line |
kadonotakashi | 0:8fdf9a60065b | 224 | |
kadonotakashi | 0:8fdf9a60065b | 225 | else: |
kadonotakashi | 0:8fdf9a60065b | 226 | is_obj = re.match(self.RE_OBJECT, line) |
kadonotakashi | 0:8fdf9a60065b | 227 | if is_obj: |
kadonotakashi | 0:8fdf9a60065b | 228 | return join('[lib]', basename(is_obj.group(1)), is_obj.group(3)) |
kadonotakashi | 0:8fdf9a60065b | 229 | else: |
kadonotakashi | 0:8fdf9a60065b | 230 | print("Malformed input found when parsing ARMCC map: %s" % line) |
kadonotakashi | 0:8fdf9a60065b | 231 | return '[misc]' |
kadonotakashi | 0:8fdf9a60065b | 232 | |
kadonotakashi | 0:8fdf9a60065b | 233 | def parse_section(self, line): |
kadonotakashi | 0:8fdf9a60065b | 234 | """ Parse data from an armcc map file |
kadonotakashi | 0:8fdf9a60065b | 235 | |
kadonotakashi | 0:8fdf9a60065b | 236 | Examples of armcc map file: |
kadonotakashi | 0:8fdf9a60065b | 237 | Base_Addr Size Type Attr Idx E Section Name Object |
kadonotakashi | 0:8fdf9a60065b | 238 | 0x00000000 0x00000400 Data RO 11222 self.RESET startup_MK64F12.o |
kadonotakashi | 0:8fdf9a60065b | 239 | 0x00000410 0x00000008 Code RO 49364 * !!!main c_w.l(__main.o) |
kadonotakashi | 0:8fdf9a60065b | 240 | |
kadonotakashi | 0:8fdf9a60065b | 241 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 242 | line - the line to parse the section data from |
kadonotakashi | 0:8fdf9a60065b | 243 | """ |
kadonotakashi | 0:8fdf9a60065b | 244 | test_re = re.match(self.RE, line) |
kadonotakashi | 0:8fdf9a60065b | 245 | |
kadonotakashi | 0:8fdf9a60065b | 246 | if test_re: |
kadonotakashi | 0:8fdf9a60065b | 247 | size = int(test_re.group(2), 16) |
kadonotakashi | 0:8fdf9a60065b | 248 | |
kadonotakashi | 0:8fdf9a60065b | 249 | if test_re.group(4) == 'RO': |
kadonotakashi | 0:8fdf9a60065b | 250 | section = '.text' |
kadonotakashi | 0:8fdf9a60065b | 251 | else: |
kadonotakashi | 0:8fdf9a60065b | 252 | if test_re.group(3) == 'Data': |
kadonotakashi | 0:8fdf9a60065b | 253 | section = '.data' |
kadonotakashi | 0:8fdf9a60065b | 254 | elif test_re.group(3) == 'Zero': |
kadonotakashi | 0:8fdf9a60065b | 255 | section = '.bss' |
kadonotakashi | 0:8fdf9a60065b | 256 | elif test_re.group(3) == 'Code': |
kadonotakashi | 0:8fdf9a60065b | 257 | section = '.text' |
kadonotakashi | 0:8fdf9a60065b | 258 | else: |
kadonotakashi | 0:8fdf9a60065b | 259 | print("Malformed input found when parsing armcc map: %s, %r" |
kadonotakashi | 0:8fdf9a60065b | 260 | % (line, test_re.groups())) |
kadonotakashi | 0:8fdf9a60065b | 261 | |
kadonotakashi | 0:8fdf9a60065b | 262 | return ["", 0, ""] |
kadonotakashi | 0:8fdf9a60065b | 263 | |
kadonotakashi | 0:8fdf9a60065b | 264 | # check name of object or library |
kadonotakashi | 0:8fdf9a60065b | 265 | object_name = self.parse_object_name( |
kadonotakashi | 0:8fdf9a60065b | 266 | test_re.group(6)) |
kadonotakashi | 0:8fdf9a60065b | 267 | |
kadonotakashi | 0:8fdf9a60065b | 268 | return [object_name, size, section] |
kadonotakashi | 0:8fdf9a60065b | 269 | |
kadonotakashi | 0:8fdf9a60065b | 270 | else: |
kadonotakashi | 0:8fdf9a60065b | 271 | return ["", 0, ""] |
kadonotakashi | 0:8fdf9a60065b | 272 | |
kadonotakashi | 0:8fdf9a60065b | 273 | def parse_mapfile(self, file_desc): |
kadonotakashi | 0:8fdf9a60065b | 274 | """ Main logic to decode armc5 map files |
kadonotakashi | 0:8fdf9a60065b | 275 | |
kadonotakashi | 0:8fdf9a60065b | 276 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 277 | file_desc - a file like object to parse as an armc5 map file |
kadonotakashi | 0:8fdf9a60065b | 278 | """ |
kadonotakashi | 0:8fdf9a60065b | 279 | with file_desc as infile: |
kadonotakashi | 0:8fdf9a60065b | 280 | # Search area to parse |
kadonotakashi | 0:8fdf9a60065b | 281 | for line in infile: |
kadonotakashi | 0:8fdf9a60065b | 282 | if line.startswith(' Base Addr Size'): |
kadonotakashi | 0:8fdf9a60065b | 283 | break |
kadonotakashi | 0:8fdf9a60065b | 284 | |
kadonotakashi | 0:8fdf9a60065b | 285 | # Start decoding the map file |
kadonotakashi | 0:8fdf9a60065b | 286 | for line in infile: |
kadonotakashi | 0:8fdf9a60065b | 287 | self.module_add(*self.parse_section(line)) |
kadonotakashi | 0:8fdf9a60065b | 288 | |
kadonotakashi | 0:8fdf9a60065b | 289 | common_prefix = dirname(commonprefix([ |
kadonotakashi | 0:8fdf9a60065b | 290 | o for o in self.modules.keys() if (o.endswith(".o") and o != "anon$$obj.o" and not o.startswith("[lib]"))])) |
kadonotakashi | 0:8fdf9a60065b | 291 | new_modules = {} |
kadonotakashi | 0:8fdf9a60065b | 292 | for name, stats in self.modules.items(): |
kadonotakashi | 0:8fdf9a60065b | 293 | if name == "anon$$obj.o" or name.startswith("[lib]"): |
kadonotakashi | 0:8fdf9a60065b | 294 | new_modules[name] = stats |
kadonotakashi | 0:8fdf9a60065b | 295 | elif name.endswith(".o"): |
kadonotakashi | 0:8fdf9a60065b | 296 | new_modules[relpath(name, common_prefix)] = stats |
kadonotakashi | 0:8fdf9a60065b | 297 | else: |
kadonotakashi | 0:8fdf9a60065b | 298 | new_modules[name] = stats |
kadonotakashi | 0:8fdf9a60065b | 299 | return new_modules |
kadonotakashi | 0:8fdf9a60065b | 300 | |
kadonotakashi | 0:8fdf9a60065b | 301 | |
kadonotakashi | 0:8fdf9a60065b | 302 | class _IarParser(_Parser): |
kadonotakashi | 0:8fdf9a60065b | 303 | RE = re.compile( |
kadonotakashi | 0:8fdf9a60065b | 304 | r'^\s+(.+)\s+(zero|const|ro code|inited|uninit)\s' |
kadonotakashi | 0:8fdf9a60065b | 305 | r'+0x(\w{8})\s+0x(\w+)\s+(.+)\s.+$') |
kadonotakashi | 0:8fdf9a60065b | 306 | |
kadonotakashi | 0:8fdf9a60065b | 307 | RE_CMDLINE_FILE = re.compile(r'^#\s+(.+\.o)') |
kadonotakashi | 0:8fdf9a60065b | 308 | RE_LIBRARY = re.compile(r'^(.+\.a)\:.+$') |
kadonotakashi | 0:8fdf9a60065b | 309 | RE_OBJECT_LIBRARY = re.compile(r'^\s+(.+\.o)\s.*') |
kadonotakashi | 0:8fdf9a60065b | 310 | |
kadonotakashi | 0:8fdf9a60065b | 311 | def __init__(self): |
kadonotakashi | 0:8fdf9a60065b | 312 | _Parser.__init__(self) |
kadonotakashi | 0:8fdf9a60065b | 313 | # Modules passed to the linker on the command line |
kadonotakashi | 0:8fdf9a60065b | 314 | # this is a dict because modules are looked up by their basename |
kadonotakashi | 0:8fdf9a60065b | 315 | self.cmd_modules = {} |
kadonotakashi | 0:8fdf9a60065b | 316 | |
kadonotakashi | 0:8fdf9a60065b | 317 | def parse_object_name(self, object_name): |
kadonotakashi | 0:8fdf9a60065b | 318 | """ Parse object file |
kadonotakashi | 0:8fdf9a60065b | 319 | |
kadonotakashi | 0:8fdf9a60065b | 320 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 321 | line - the line containing the object or library |
kadonotakashi | 0:8fdf9a60065b | 322 | """ |
kadonotakashi | 0:8fdf9a60065b | 323 | if object_name.endswith(".o"): |
kadonotakashi | 0:8fdf9a60065b | 324 | try: |
kadonotakashi | 0:8fdf9a60065b | 325 | return self.cmd_modules[object_name] |
kadonotakashi | 0:8fdf9a60065b | 326 | except KeyError: |
kadonotakashi | 0:8fdf9a60065b | 327 | return object_name |
kadonotakashi | 0:8fdf9a60065b | 328 | else: |
kadonotakashi | 0:8fdf9a60065b | 329 | return '[misc]' |
kadonotakashi | 0:8fdf9a60065b | 330 | |
kadonotakashi | 0:8fdf9a60065b | 331 | def parse_section(self, line): |
kadonotakashi | 0:8fdf9a60065b | 332 | """ Parse data from an IAR map file |
kadonotakashi | 0:8fdf9a60065b | 333 | |
kadonotakashi | 0:8fdf9a60065b | 334 | Examples of IAR map file: |
kadonotakashi | 0:8fdf9a60065b | 335 | Section Kind Address Size Object |
kadonotakashi | 0:8fdf9a60065b | 336 | .intvec ro code 0x00000000 0x198 startup_MK64F12.o [15] |
kadonotakashi | 0:8fdf9a60065b | 337 | .rodata const 0x00000198 0x0 zero_init3.o [133] |
kadonotakashi | 0:8fdf9a60065b | 338 | .iar.init_table const 0x00008384 0x2c - Linker created - |
kadonotakashi | 0:8fdf9a60065b | 339 | Initializer bytes const 0x00000198 0xb2 <for P3 s0> |
kadonotakashi | 0:8fdf9a60065b | 340 | .data inited 0x20000000 0xd4 driverAtmelRFInterface.o [70] |
kadonotakashi | 0:8fdf9a60065b | 341 | .bss zero 0x20000598 0x318 RTX_Conf_CM.o [4] |
kadonotakashi | 0:8fdf9a60065b | 342 | .iar.dynexit uninit 0x20001448 0x204 <Block tail> |
kadonotakashi | 0:8fdf9a60065b | 343 | HEAP uninit 0x20001650 0x10000 <Block tail> |
kadonotakashi | 0:8fdf9a60065b | 344 | |
kadonotakashi | 0:8fdf9a60065b | 345 | Positional_arguments: |
kadonotakashi | 0:8fdf9a60065b | 346 | line - the line to parse section data from |
kadonotakashi | 0:8fdf9a60065b | 347 | """ |
kadonotakashi | 0:8fdf9a60065b | 348 | test_re = re.match(self.RE, line) |
kadonotakashi | 0:8fdf9a60065b | 349 | if test_re: |
kadonotakashi | 0:8fdf9a60065b | 350 | if (test_re.group(2) == 'const' or |
kadonotakashi | 0:8fdf9a60065b | 351 | test_re.group(2) == 'ro code'): |
kadonotakashi | 0:8fdf9a60065b | 352 | section = '.text' |
kadonotakashi | 0:8fdf9a60065b | 353 | elif (test_re.group(2) == 'zero' or |
kadonotakashi | 0:8fdf9a60065b | 354 | test_re.group(2) == 'uninit'): |
kadonotakashi | 0:8fdf9a60065b | 355 | if test_re.group(1)[0:4] == 'HEAP': |
kadonotakashi | 0:8fdf9a60065b | 356 | section = '.heap' |
kadonotakashi | 0:8fdf9a60065b | 357 | elif test_re.group(1)[0:6] == 'CSTACK': |
kadonotakashi | 0:8fdf9a60065b | 358 | section = '.stack' |
kadonotakashi | 0:8fdf9a60065b | 359 | else: |
kadonotakashi | 0:8fdf9a60065b | 360 | section = '.bss' # default section |
kadonotakashi | 0:8fdf9a60065b | 361 | |
kadonotakashi | 0:8fdf9a60065b | 362 | elif test_re.group(2) == 'inited': |
kadonotakashi | 0:8fdf9a60065b | 363 | section = '.data' |
kadonotakashi | 0:8fdf9a60065b | 364 | else: |
kadonotakashi | 0:8fdf9a60065b | 365 | print("Malformed input found when parsing IAR map: %s" % line) |
kadonotakashi | 0:8fdf9a60065b | 366 | return ["", 0, ""] |
kadonotakashi | 0:8fdf9a60065b | 367 | |
kadonotakashi | 0:8fdf9a60065b | 368 | # lookup object in dictionary and return module name |
kadonotakashi | 0:8fdf9a60065b | 369 | object_name = self.parse_object_name(test_re.group(5)) |
kadonotakashi | 0:8fdf9a60065b | 370 | |
kadonotakashi | 0:8fdf9a60065b | 371 | size = int(test_re.group(4), 16) |
kadonotakashi | 0:8fdf9a60065b | 372 | return [object_name, size, section] |
kadonotakashi | 0:8fdf9a60065b | 373 | |
kadonotakashi | 0:8fdf9a60065b | 374 | else: |
kadonotakashi | 0:8fdf9a60065b | 375 | return ["", 0, ""] |
kadonotakashi | 0:8fdf9a60065b | 376 | |
kadonotakashi | 0:8fdf9a60065b | 377 | def check_new_library(self, line): |
kadonotakashi | 0:8fdf9a60065b | 378 | """ |
kadonotakashi | 0:8fdf9a60065b | 379 | Searches for libraries and returns name. Example: |
kadonotakashi | 0:8fdf9a60065b | 380 | m7M_tls.a: [43] |
kadonotakashi | 0:8fdf9a60065b | 381 | |
kadonotakashi | 0:8fdf9a60065b | 382 | """ |
kadonotakashi | 0:8fdf9a60065b | 383 | test_address_line = re.match(self.RE_LIBRARY, line) |
kadonotakashi | 0:8fdf9a60065b | 384 | if test_address_line: |
kadonotakashi | 0:8fdf9a60065b | 385 | return test_address_line.group(1) |
kadonotakashi | 0:8fdf9a60065b | 386 | else: |
kadonotakashi | 0:8fdf9a60065b | 387 | return "" |
kadonotakashi | 0:8fdf9a60065b | 388 | |
kadonotakashi | 0:8fdf9a60065b | 389 | def check_new_object_lib(self, line): |
kadonotakashi | 0:8fdf9a60065b | 390 | """ |
kadonotakashi | 0:8fdf9a60065b | 391 | Searches for objects within a library section and returns name. Example: |
kadonotakashi | 0:8fdf9a60065b | 392 | rt7M_tl.a: [44] |
kadonotakashi | 0:8fdf9a60065b | 393 | ABImemclr4.o 6 |
kadonotakashi | 0:8fdf9a60065b | 394 | ABImemcpy_unaligned.o 118 |
kadonotakashi | 0:8fdf9a60065b | 395 | ABImemset48.o 50 |
kadonotakashi | 0:8fdf9a60065b | 396 | I64DivMod.o 238 |
kadonotakashi | 0:8fdf9a60065b | 397 | I64DivZer.o 2 |
kadonotakashi | 0:8fdf9a60065b | 398 | |
kadonotakashi | 0:8fdf9a60065b | 399 | """ |
kadonotakashi | 0:8fdf9a60065b | 400 | test_address_line = re.match(self.RE_OBJECT_LIBRARY, line) |
kadonotakashi | 0:8fdf9a60065b | 401 | if test_address_line: |
kadonotakashi | 0:8fdf9a60065b | 402 | return test_address_line.group(1) |
kadonotakashi | 0:8fdf9a60065b | 403 | else: |
kadonotakashi | 0:8fdf9a60065b | 404 | return "" |
kadonotakashi | 0:8fdf9a60065b | 405 | |
kadonotakashi | 0:8fdf9a60065b | 406 | def parse_command_line(self, lines): |
kadonotakashi | 0:8fdf9a60065b | 407 | """Parse the files passed on the command line to the iar linker |
kadonotakashi | 0:8fdf9a60065b | 408 | |
kadonotakashi | 0:8fdf9a60065b | 409 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 410 | lines -- an iterator over the lines within a file |
kadonotakashi | 0:8fdf9a60065b | 411 | """ |
kadonotakashi | 0:8fdf9a60065b | 412 | for line in lines: |
kadonotakashi | 0:8fdf9a60065b | 413 | if line.startswith("*"): |
kadonotakashi | 0:8fdf9a60065b | 414 | break |
kadonotakashi | 0:8fdf9a60065b | 415 | for arg in line.split(" "): |
kadonotakashi | 0:8fdf9a60065b | 416 | arg = arg.rstrip(" \n") |
kadonotakashi | 0:8fdf9a60065b | 417 | if (not arg.startswith("-")) and arg.endswith(".o"): |
kadonotakashi | 0:8fdf9a60065b | 418 | self.cmd_modules[basename(arg)] = arg |
kadonotakashi | 0:8fdf9a60065b | 419 | |
kadonotakashi | 0:8fdf9a60065b | 420 | common_prefix = dirname(commonprefix(list(self.cmd_modules.values()))) |
kadonotakashi | 0:8fdf9a60065b | 421 | self.cmd_modules = {s: relpath(f, common_prefix) |
kadonotakashi | 0:8fdf9a60065b | 422 | for s, f in self.cmd_modules.items()} |
kadonotakashi | 0:8fdf9a60065b | 423 | |
kadonotakashi | 0:8fdf9a60065b | 424 | def parse_mapfile(self, file_desc): |
kadonotakashi | 0:8fdf9a60065b | 425 | """ Main logic to decode IAR map files |
kadonotakashi | 0:8fdf9a60065b | 426 | |
kadonotakashi | 0:8fdf9a60065b | 427 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 428 | file_desc - a file like object to parse as an IAR map file |
kadonotakashi | 0:8fdf9a60065b | 429 | """ |
kadonotakashi | 0:8fdf9a60065b | 430 | with file_desc as infile: |
kadonotakashi | 0:8fdf9a60065b | 431 | self.parse_command_line(infile) |
kadonotakashi | 0:8fdf9a60065b | 432 | |
kadonotakashi | 0:8fdf9a60065b | 433 | for line in infile: |
kadonotakashi | 0:8fdf9a60065b | 434 | if line.startswith(' Section '): |
kadonotakashi | 0:8fdf9a60065b | 435 | break |
kadonotakashi | 0:8fdf9a60065b | 436 | |
kadonotakashi | 0:8fdf9a60065b | 437 | for line in infile: |
kadonotakashi | 0:8fdf9a60065b | 438 | self.module_add(*self.parse_section(line)) |
kadonotakashi | 0:8fdf9a60065b | 439 | |
kadonotakashi | 0:8fdf9a60065b | 440 | if line.startswith('*** MODULE SUMMARY'): # finish section |
kadonotakashi | 0:8fdf9a60065b | 441 | break |
kadonotakashi | 0:8fdf9a60065b | 442 | |
kadonotakashi | 0:8fdf9a60065b | 443 | current_library = "" |
kadonotakashi | 0:8fdf9a60065b | 444 | for line in infile: |
kadonotakashi | 0:8fdf9a60065b | 445 | library = self.check_new_library(line) |
kadonotakashi | 0:8fdf9a60065b | 446 | |
kadonotakashi | 0:8fdf9a60065b | 447 | if library: |
kadonotakashi | 0:8fdf9a60065b | 448 | current_library = library |
kadonotakashi | 0:8fdf9a60065b | 449 | |
kadonotakashi | 0:8fdf9a60065b | 450 | object_name = self.check_new_object_lib(line) |
kadonotakashi | 0:8fdf9a60065b | 451 | |
kadonotakashi | 0:8fdf9a60065b | 452 | if object_name and current_library: |
kadonotakashi | 0:8fdf9a60065b | 453 | temp = join('[lib]', current_library, object_name) |
kadonotakashi | 0:8fdf9a60065b | 454 | self.module_replace(object_name, temp) |
kadonotakashi | 0:8fdf9a60065b | 455 | return self.modules |
kadonotakashi | 0:8fdf9a60065b | 456 | |
kadonotakashi | 0:8fdf9a60065b | 457 | |
kadonotakashi | 0:8fdf9a60065b | 458 | class MemapParser(object): |
kadonotakashi | 0:8fdf9a60065b | 459 | """An object that represents parsed results, parses the memory map files, |
kadonotakashi | 0:8fdf9a60065b | 460 | and writes out different file types of memory results |
kadonotakashi | 0:8fdf9a60065b | 461 | """ |
kadonotakashi | 0:8fdf9a60065b | 462 | |
kadonotakashi | 0:8fdf9a60065b | 463 | print_sections = ('.text', '.data', '.bss') |
kadonotakashi | 0:8fdf9a60065b | 464 | delta_sections = ('.text-delta', '.data-delta', '.bss-delta') |
kadonotakashi | 0:8fdf9a60065b | 465 | |
kadonotakashi | 0:8fdf9a60065b | 466 | |
kadonotakashi | 0:8fdf9a60065b | 467 | # sections to print info (generic for all toolchains) |
kadonotakashi | 0:8fdf9a60065b | 468 | sections = _Parser.SECTIONS |
kadonotakashi | 0:8fdf9a60065b | 469 | misc_flash_sections = _Parser.MISC_FLASH_SECTIONS |
kadonotakashi | 0:8fdf9a60065b | 470 | other_sections = _Parser.OTHER_SECTIONS |
kadonotakashi | 0:8fdf9a60065b | 471 | |
kadonotakashi | 0:8fdf9a60065b | 472 | def __init__(self): |
kadonotakashi | 0:8fdf9a60065b | 473 | # list of all modules and their sections |
kadonotakashi | 0:8fdf9a60065b | 474 | # full list - doesn't change with depth |
kadonotakashi | 0:8fdf9a60065b | 475 | self.modules = dict() |
kadonotakashi | 0:8fdf9a60065b | 476 | self.old_modules = None |
kadonotakashi | 0:8fdf9a60065b | 477 | # short version with specific depth |
kadonotakashi | 0:8fdf9a60065b | 478 | self.short_modules = dict() |
kadonotakashi | 0:8fdf9a60065b | 479 | |
kadonotakashi | 0:8fdf9a60065b | 480 | |
kadonotakashi | 0:8fdf9a60065b | 481 | # Memory report (sections + summary) |
kadonotakashi | 0:8fdf9a60065b | 482 | self.mem_report = [] |
kadonotakashi | 0:8fdf9a60065b | 483 | |
kadonotakashi | 0:8fdf9a60065b | 484 | # Memory summary |
kadonotakashi | 0:8fdf9a60065b | 485 | self.mem_summary = dict() |
kadonotakashi | 0:8fdf9a60065b | 486 | |
kadonotakashi | 0:8fdf9a60065b | 487 | # Totals of ".text", ".data" and ".bss" |
kadonotakashi | 0:8fdf9a60065b | 488 | self.subtotal = dict() |
kadonotakashi | 0:8fdf9a60065b | 489 | |
kadonotakashi | 0:8fdf9a60065b | 490 | # Flash no associated with a module |
kadonotakashi | 0:8fdf9a60065b | 491 | self.misc_flash_mem = 0 |
kadonotakashi | 0:8fdf9a60065b | 492 | |
kadonotakashi | 0:8fdf9a60065b | 493 | # Name of the toolchain, for better headings |
kadonotakashi | 0:8fdf9a60065b | 494 | self.tc_name = None |
kadonotakashi | 0:8fdf9a60065b | 495 | |
kadonotakashi | 0:8fdf9a60065b | 496 | def reduce_depth(self, depth): |
kadonotakashi | 0:8fdf9a60065b | 497 | """ |
kadonotakashi | 0:8fdf9a60065b | 498 | populates the short_modules attribute with a truncated module list |
kadonotakashi | 0:8fdf9a60065b | 499 | |
kadonotakashi | 0:8fdf9a60065b | 500 | (1) depth = 1: |
kadonotakashi | 0:8fdf9a60065b | 501 | main.o |
kadonotakashi | 0:8fdf9a60065b | 502 | mbed-os |
kadonotakashi | 0:8fdf9a60065b | 503 | |
kadonotakashi | 0:8fdf9a60065b | 504 | (2) depth = 2: |
kadonotakashi | 0:8fdf9a60065b | 505 | main.o |
kadonotakashi | 0:8fdf9a60065b | 506 | mbed-os/test.o |
kadonotakashi | 0:8fdf9a60065b | 507 | mbed-os/drivers |
kadonotakashi | 0:8fdf9a60065b | 508 | |
kadonotakashi | 0:8fdf9a60065b | 509 | """ |
kadonotakashi | 0:8fdf9a60065b | 510 | if depth == 0 or depth == None: |
kadonotakashi | 0:8fdf9a60065b | 511 | self.short_modules = deepcopy(self.modules) |
kadonotakashi | 0:8fdf9a60065b | 512 | else: |
kadonotakashi | 0:8fdf9a60065b | 513 | self.short_modules = dict() |
kadonotakashi | 0:8fdf9a60065b | 514 | for module_name, v in self.modules.items(): |
kadonotakashi | 0:8fdf9a60065b | 515 | split_name = module_name.split(sep) |
kadonotakashi | 0:8fdf9a60065b | 516 | if split_name[0] == '': |
kadonotakashi | 0:8fdf9a60065b | 517 | split_name = split_name[1:] |
kadonotakashi | 0:8fdf9a60065b | 518 | new_name = join(*split_name[:depth]) |
kadonotakashi | 0:8fdf9a60065b | 519 | self.short_modules.setdefault(new_name, defaultdict(int)) |
kadonotakashi | 0:8fdf9a60065b | 520 | for section_idx, value in v.items(): |
kadonotakashi | 0:8fdf9a60065b | 521 | self.short_modules[new_name][section_idx] += self.modules[module_name][section_idx] |
kadonotakashi | 0:8fdf9a60065b | 522 | self.short_modules[new_name][section_idx + '-delta'] += self.modules[module_name][section_idx] |
kadonotakashi | 0:8fdf9a60065b | 523 | if self.old_modules: |
kadonotakashi | 0:8fdf9a60065b | 524 | for module_name, v in self.old_modules.items(): |
kadonotakashi | 0:8fdf9a60065b | 525 | split_name = module_name.split(sep) |
kadonotakashi | 0:8fdf9a60065b | 526 | if split_name[0] == '': |
kadonotakashi | 0:8fdf9a60065b | 527 | split_name = split_name[1:] |
kadonotakashi | 0:8fdf9a60065b | 528 | new_name = join(*split_name[:depth]) |
kadonotakashi | 0:8fdf9a60065b | 529 | self.short_modules.setdefault(new_name, defaultdict(int)) |
kadonotakashi | 0:8fdf9a60065b | 530 | for section_idx, value in v.items(): |
kadonotakashi | 0:8fdf9a60065b | 531 | self.short_modules[new_name][section_idx + '-delta'] -= self.old_modules[module_name][section_idx] |
kadonotakashi | 0:8fdf9a60065b | 532 | |
kadonotakashi | 0:8fdf9a60065b | 533 | export_formats = ["json", "csv-ci", "html", "table"] |
kadonotakashi | 0:8fdf9a60065b | 534 | |
kadonotakashi | 0:8fdf9a60065b | 535 | def generate_output(self, export_format, depth, file_output=None): |
kadonotakashi | 0:8fdf9a60065b | 536 | """ Generates summary of memory map data |
kadonotakashi | 0:8fdf9a60065b | 537 | |
kadonotakashi | 0:8fdf9a60065b | 538 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 539 | export_format - the format to dump |
kadonotakashi | 0:8fdf9a60065b | 540 | |
kadonotakashi | 0:8fdf9a60065b | 541 | Keyword arguments: |
kadonotakashi | 0:8fdf9a60065b | 542 | file_desc - descriptor (either stdout or file) |
kadonotakashi | 0:8fdf9a60065b | 543 | depth - directory depth on report |
kadonotakashi | 0:8fdf9a60065b | 544 | |
kadonotakashi | 0:8fdf9a60065b | 545 | Returns: generated string for the 'table' format, otherwise None |
kadonotakashi | 0:8fdf9a60065b | 546 | """ |
kadonotakashi | 0:8fdf9a60065b | 547 | if depth is None or depth > 0: |
kadonotakashi | 0:8fdf9a60065b | 548 | self.reduce_depth(depth) |
kadonotakashi | 0:8fdf9a60065b | 549 | self.compute_report() |
kadonotakashi | 0:8fdf9a60065b | 550 | try: |
kadonotakashi | 0:8fdf9a60065b | 551 | if file_output: |
kadonotakashi | 0:8fdf9a60065b | 552 | file_desc = open(file_output, 'w') |
kadonotakashi | 0:8fdf9a60065b | 553 | else: |
kadonotakashi | 0:8fdf9a60065b | 554 | file_desc = stdout |
kadonotakashi | 0:8fdf9a60065b | 555 | except IOError as error: |
kadonotakashi | 0:8fdf9a60065b | 556 | print("I/O error({0}): {1}".format(error.errno, error.strerror)) |
kadonotakashi | 0:8fdf9a60065b | 557 | return False |
kadonotakashi | 0:8fdf9a60065b | 558 | |
kadonotakashi | 0:8fdf9a60065b | 559 | to_call = {'json': self.generate_json, |
kadonotakashi | 0:8fdf9a60065b | 560 | 'html': self.generate_html, |
kadonotakashi | 0:8fdf9a60065b | 561 | 'csv-ci': self.generate_csv, |
kadonotakashi | 0:8fdf9a60065b | 562 | 'table': self.generate_table}[export_format] |
kadonotakashi | 0:8fdf9a60065b | 563 | output = to_call(file_desc) |
kadonotakashi | 0:8fdf9a60065b | 564 | |
kadonotakashi | 0:8fdf9a60065b | 565 | if file_desc is not stdout: |
kadonotakashi | 0:8fdf9a60065b | 566 | file_desc.close() |
kadonotakashi | 0:8fdf9a60065b | 567 | |
kadonotakashi | 0:8fdf9a60065b | 568 | return output |
kadonotakashi | 0:8fdf9a60065b | 569 | |
kadonotakashi | 0:8fdf9a60065b | 570 | @staticmethod |
kadonotakashi | 0:8fdf9a60065b | 571 | def _move_up_tree(tree, next_module): |
kadonotakashi | 0:8fdf9a60065b | 572 | tree.setdefault("children", []) |
kadonotakashi | 0:8fdf9a60065b | 573 | for child in tree["children"]: |
kadonotakashi | 0:8fdf9a60065b | 574 | if child["name"] == next_module: |
kadonotakashi | 0:8fdf9a60065b | 575 | return child |
kadonotakashi | 0:8fdf9a60065b | 576 | else: |
kadonotakashi | 0:8fdf9a60065b | 577 | new_module = {"name": next_module, "value": 0, "delta": 0} |
kadonotakashi | 0:8fdf9a60065b | 578 | tree["children"].append(new_module) |
kadonotakashi | 0:8fdf9a60065b | 579 | return new_module |
kadonotakashi | 0:8fdf9a60065b | 580 | |
kadonotakashi | 0:8fdf9a60065b | 581 | def generate_html(self, file_desc): |
kadonotakashi | 0:8fdf9a60065b | 582 | """Generate a json file from a memory map for D3 |
kadonotakashi | 0:8fdf9a60065b | 583 | |
kadonotakashi | 0:8fdf9a60065b | 584 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 585 | file_desc - the file to write out the final report to |
kadonotakashi | 0:8fdf9a60065b | 586 | """ |
kadonotakashi | 0:8fdf9a60065b | 587 | tree_text = {"name": ".text", "value": 0, "delta": 0} |
kadonotakashi | 0:8fdf9a60065b | 588 | tree_bss = {"name": ".bss", "value": 0, "delta": 0} |
kadonotakashi | 0:8fdf9a60065b | 589 | tree_data = {"name": ".data", "value": 0, "delta": 0} |
kadonotakashi | 0:8fdf9a60065b | 590 | for name, dct in self.modules.items(): |
kadonotakashi | 0:8fdf9a60065b | 591 | cur_text = tree_text |
kadonotakashi | 0:8fdf9a60065b | 592 | cur_bss = tree_bss |
kadonotakashi | 0:8fdf9a60065b | 593 | cur_data = tree_data |
kadonotakashi | 0:8fdf9a60065b | 594 | modules = name.split(sep) |
kadonotakashi | 0:8fdf9a60065b | 595 | while True: |
kadonotakashi | 0:8fdf9a60065b | 596 | try: |
kadonotakashi | 0:8fdf9a60065b | 597 | cur_text["value"] += dct['.text'] |
kadonotakashi | 0:8fdf9a60065b | 598 | cur_text["delta"] += dct['.text'] |
kadonotakashi | 0:8fdf9a60065b | 599 | except KeyError: |
kadonotakashi | 0:8fdf9a60065b | 600 | pass |
kadonotakashi | 0:8fdf9a60065b | 601 | try: |
kadonotakashi | 0:8fdf9a60065b | 602 | cur_bss["value"] += dct['.bss'] |
kadonotakashi | 0:8fdf9a60065b | 603 | cur_bss["delta"] += dct['.bss'] |
kadonotakashi | 0:8fdf9a60065b | 604 | except KeyError: |
kadonotakashi | 0:8fdf9a60065b | 605 | pass |
kadonotakashi | 0:8fdf9a60065b | 606 | try: |
kadonotakashi | 0:8fdf9a60065b | 607 | cur_data["value"] += dct['.data'] |
kadonotakashi | 0:8fdf9a60065b | 608 | cur_data["delta"] += dct['.data'] |
kadonotakashi | 0:8fdf9a60065b | 609 | except KeyError: |
kadonotakashi | 0:8fdf9a60065b | 610 | pass |
kadonotakashi | 0:8fdf9a60065b | 611 | if not modules: |
kadonotakashi | 0:8fdf9a60065b | 612 | break |
kadonotakashi | 0:8fdf9a60065b | 613 | next_module = modules.pop(0) |
kadonotakashi | 0:8fdf9a60065b | 614 | cur_text = self._move_up_tree(cur_text, next_module) |
kadonotakashi | 0:8fdf9a60065b | 615 | cur_data = self._move_up_tree(cur_data, next_module) |
kadonotakashi | 0:8fdf9a60065b | 616 | cur_bss = self._move_up_tree(cur_bss, next_module) |
kadonotakashi | 0:8fdf9a60065b | 617 | if self.old_modules: |
kadonotakashi | 0:8fdf9a60065b | 618 | for name, dct in self.old_modules.items(): |
kadonotakashi | 0:8fdf9a60065b | 619 | cur_text = tree_text |
kadonotakashi | 0:8fdf9a60065b | 620 | cur_bss = tree_bss |
kadonotakashi | 0:8fdf9a60065b | 621 | cur_data = tree_data |
kadonotakashi | 0:8fdf9a60065b | 622 | modules = name.split(sep) |
kadonotakashi | 0:8fdf9a60065b | 623 | while True: |
kadonotakashi | 0:8fdf9a60065b | 624 | try: |
kadonotakashi | 0:8fdf9a60065b | 625 | cur_text["delta"] -= dct['.text'] |
kadonotakashi | 0:8fdf9a60065b | 626 | except KeyError: |
kadonotakashi | 0:8fdf9a60065b | 627 | pass |
kadonotakashi | 0:8fdf9a60065b | 628 | try: |
kadonotakashi | 0:8fdf9a60065b | 629 | cur_bss["delta"] -= dct['.bss'] |
kadonotakashi | 0:8fdf9a60065b | 630 | except KeyError: |
kadonotakashi | 0:8fdf9a60065b | 631 | pass |
kadonotakashi | 0:8fdf9a60065b | 632 | try: |
kadonotakashi | 0:8fdf9a60065b | 633 | cur_data["delta"] -= dct['.data'] |
kadonotakashi | 0:8fdf9a60065b | 634 | except KeyError: |
kadonotakashi | 0:8fdf9a60065b | 635 | pass |
kadonotakashi | 0:8fdf9a60065b | 636 | if not modules: |
kadonotakashi | 0:8fdf9a60065b | 637 | break |
kadonotakashi | 0:8fdf9a60065b | 638 | next_module = modules.pop(0) |
kadonotakashi | 0:8fdf9a60065b | 639 | if not any(cld['name'] == next_module for cld in cur_text['children']): |
kadonotakashi | 0:8fdf9a60065b | 640 | break |
kadonotakashi | 0:8fdf9a60065b | 641 | cur_text = self._move_up_tree(cur_text, next_module) |
kadonotakashi | 0:8fdf9a60065b | 642 | cur_data = self._move_up_tree(cur_data, next_module) |
kadonotakashi | 0:8fdf9a60065b | 643 | cur_bss = self._move_up_tree(cur_bss, next_module) |
kadonotakashi | 0:8fdf9a60065b | 644 | |
kadonotakashi | 0:8fdf9a60065b | 645 | tree_rom = { |
kadonotakashi | 0:8fdf9a60065b | 646 | "name": "ROM", |
kadonotakashi | 0:8fdf9a60065b | 647 | "value": tree_text["value"] + tree_data["value"], |
kadonotakashi | 0:8fdf9a60065b | 648 | "delta": tree_text["delta"] + tree_data["delta"], |
kadonotakashi | 0:8fdf9a60065b | 649 | "children": [tree_text, tree_data] |
kadonotakashi | 0:8fdf9a60065b | 650 | } |
kadonotakashi | 0:8fdf9a60065b | 651 | tree_ram = { |
kadonotakashi | 0:8fdf9a60065b | 652 | "name": "RAM", |
kadonotakashi | 0:8fdf9a60065b | 653 | "value": tree_bss["value"] + tree_data["value"], |
kadonotakashi | 0:8fdf9a60065b | 654 | "delta": tree_bss["delta"] + tree_data["delta"], |
kadonotakashi | 0:8fdf9a60065b | 655 | "children": [tree_bss, tree_data] |
kadonotakashi | 0:8fdf9a60065b | 656 | } |
kadonotakashi | 0:8fdf9a60065b | 657 | |
kadonotakashi | 0:8fdf9a60065b | 658 | jinja_loader = FileSystemLoader(dirname(abspath(__file__))) |
kadonotakashi | 0:8fdf9a60065b | 659 | jinja_environment = Environment(loader=jinja_loader, |
kadonotakashi | 0:8fdf9a60065b | 660 | undefined=StrictUndefined) |
kadonotakashi | 0:8fdf9a60065b | 661 | |
kadonotakashi | 0:8fdf9a60065b | 662 | template = jinja_environment.get_template("memap_flamegraph.html") |
kadonotakashi | 0:8fdf9a60065b | 663 | name, _ = splitext(basename(file_desc.name)) |
kadonotakashi | 0:8fdf9a60065b | 664 | if name.endswith("_map"): |
kadonotakashi | 0:8fdf9a60065b | 665 | name = name[:-4] |
kadonotakashi | 0:8fdf9a60065b | 666 | if self.tc_name: |
kadonotakashi | 0:8fdf9a60065b | 667 | name = "%s %s" % (name, self.tc_name) |
kadonotakashi | 0:8fdf9a60065b | 668 | data = { |
kadonotakashi | 0:8fdf9a60065b | 669 | "name": name, |
kadonotakashi | 0:8fdf9a60065b | 670 | "rom": json.dumps(tree_rom), |
kadonotakashi | 0:8fdf9a60065b | 671 | "ram": json.dumps(tree_ram), |
kadonotakashi | 0:8fdf9a60065b | 672 | } |
kadonotakashi | 0:8fdf9a60065b | 673 | file_desc.write(template.render(data)) |
kadonotakashi | 0:8fdf9a60065b | 674 | return None |
kadonotakashi | 0:8fdf9a60065b | 675 | |
kadonotakashi | 0:8fdf9a60065b | 676 | def generate_json(self, file_desc): |
kadonotakashi | 0:8fdf9a60065b | 677 | """Generate a json file from a memory map |
kadonotakashi | 0:8fdf9a60065b | 678 | |
kadonotakashi | 0:8fdf9a60065b | 679 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 680 | file_desc - the file to write out the final report to |
kadonotakashi | 0:8fdf9a60065b | 681 | """ |
kadonotakashi | 0:8fdf9a60065b | 682 | file_desc.write(json.dumps(self.mem_report, indent=4)) |
kadonotakashi | 0:8fdf9a60065b | 683 | file_desc.write('\n') |
kadonotakashi | 0:8fdf9a60065b | 684 | return None |
kadonotakashi | 0:8fdf9a60065b | 685 | |
kadonotakashi | 0:8fdf9a60065b | 686 | RAM_FORMAT_STR = ( |
kadonotakashi | 0:8fdf9a60065b | 687 | "Total Static RAM memory (data + bss): {}({:+}) bytes\n" |
kadonotakashi | 0:8fdf9a60065b | 688 | ) |
kadonotakashi | 0:8fdf9a60065b | 689 | |
kadonotakashi | 0:8fdf9a60065b | 690 | ROM_FORMAT_STR = ( |
kadonotakashi | 0:8fdf9a60065b | 691 | "Total Flash memory (text + data): {}({:+}) bytes\n" |
kadonotakashi | 0:8fdf9a60065b | 692 | ) |
kadonotakashi | 0:8fdf9a60065b | 693 | |
kadonotakashi | 0:8fdf9a60065b | 694 | def generate_csv(self, file_desc): |
kadonotakashi | 0:8fdf9a60065b | 695 | """Generate a CSV file from a memoy map |
kadonotakashi | 0:8fdf9a60065b | 696 | |
kadonotakashi | 0:8fdf9a60065b | 697 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 698 | file_desc - the file to write out the final report to |
kadonotakashi | 0:8fdf9a60065b | 699 | """ |
kadonotakashi | 0:8fdf9a60065b | 700 | writer = csv.writer(file_desc, delimiter=',', |
kadonotakashi | 0:8fdf9a60065b | 701 | quoting=csv.QUOTE_MINIMAL) |
kadonotakashi | 0:8fdf9a60065b | 702 | |
kadonotakashi | 0:8fdf9a60065b | 703 | module_section = [] |
kadonotakashi | 0:8fdf9a60065b | 704 | sizes = [] |
kadonotakashi | 0:8fdf9a60065b | 705 | for i in sorted(self.short_modules): |
kadonotakashi | 0:8fdf9a60065b | 706 | for k in self.print_sections + self.delta_sections: |
kadonotakashi | 0:8fdf9a60065b | 707 | module_section.append((i + k)) |
kadonotakashi | 0:8fdf9a60065b | 708 | sizes += [self.short_modules[i][k]] |
kadonotakashi | 0:8fdf9a60065b | 709 | |
kadonotakashi | 0:8fdf9a60065b | 710 | module_section.append('static_ram') |
kadonotakashi | 0:8fdf9a60065b | 711 | sizes.append(self.mem_summary['static_ram']) |
kadonotakashi | 0:8fdf9a60065b | 712 | |
kadonotakashi | 0:8fdf9a60065b | 713 | module_section.append('total_flash') |
kadonotakashi | 0:8fdf9a60065b | 714 | sizes.append(self.mem_summary['total_flash']) |
kadonotakashi | 0:8fdf9a60065b | 715 | |
kadonotakashi | 0:8fdf9a60065b | 716 | writer.writerow(module_section) |
kadonotakashi | 0:8fdf9a60065b | 717 | writer.writerow(sizes) |
kadonotakashi | 0:8fdf9a60065b | 718 | return None |
kadonotakashi | 0:8fdf9a60065b | 719 | |
kadonotakashi | 0:8fdf9a60065b | 720 | def generate_table(self, file_desc): |
kadonotakashi | 0:8fdf9a60065b | 721 | """Generate a table from a memoy map |
kadonotakashi | 0:8fdf9a60065b | 722 | |
kadonotakashi | 0:8fdf9a60065b | 723 | Returns: string of the generated table |
kadonotakashi | 0:8fdf9a60065b | 724 | """ |
kadonotakashi | 0:8fdf9a60065b | 725 | # Create table |
kadonotakashi | 0:8fdf9a60065b | 726 | columns = ['Module'] |
kadonotakashi | 0:8fdf9a60065b | 727 | columns.extend(self.print_sections) |
kadonotakashi | 0:8fdf9a60065b | 728 | |
kadonotakashi | 0:8fdf9a60065b | 729 | table = PrettyTable(columns, junction_char="|", hrules=HEADER) |
kadonotakashi | 0:8fdf9a60065b | 730 | table.align["Module"] = "l" |
kadonotakashi | 0:8fdf9a60065b | 731 | for col in self.print_sections: |
kadonotakashi | 0:8fdf9a60065b | 732 | table.align[col] = 'r' |
kadonotakashi | 0:8fdf9a60065b | 733 | |
kadonotakashi | 0:8fdf9a60065b | 734 | for i in list(self.print_sections): |
kadonotakashi | 0:8fdf9a60065b | 735 | table.align[i] = 'r' |
kadonotakashi | 0:8fdf9a60065b | 736 | |
kadonotakashi | 0:8fdf9a60065b | 737 | for i in sorted(self.short_modules): |
kadonotakashi | 0:8fdf9a60065b | 738 | row = [i] |
kadonotakashi | 0:8fdf9a60065b | 739 | |
kadonotakashi | 0:8fdf9a60065b | 740 | for k in self.print_sections: |
kadonotakashi | 0:8fdf9a60065b | 741 | row.append("{}({:+})".format(self.short_modules[i][k], |
kadonotakashi | 0:8fdf9a60065b | 742 | self.short_modules[i][k + "-delta"])) |
kadonotakashi | 0:8fdf9a60065b | 743 | |
kadonotakashi | 0:8fdf9a60065b | 744 | table.add_row(row) |
kadonotakashi | 0:8fdf9a60065b | 745 | |
kadonotakashi | 0:8fdf9a60065b | 746 | subtotal_row = ['Subtotals'] |
kadonotakashi | 0:8fdf9a60065b | 747 | for k in self.print_sections: |
kadonotakashi | 0:8fdf9a60065b | 748 | subtotal_row.append("{}({:+})".format( |
kadonotakashi | 0:8fdf9a60065b | 749 | self.subtotal[k], self.subtotal[k + '-delta'])) |
kadonotakashi | 0:8fdf9a60065b | 750 | |
kadonotakashi | 0:8fdf9a60065b | 751 | table.add_row(subtotal_row) |
kadonotakashi | 0:8fdf9a60065b | 752 | |
kadonotakashi | 0:8fdf9a60065b | 753 | output = table.get_string() |
kadonotakashi | 0:8fdf9a60065b | 754 | output += '\n' |
kadonotakashi | 0:8fdf9a60065b | 755 | |
kadonotakashi | 0:8fdf9a60065b | 756 | output += self.RAM_FORMAT_STR.format( |
kadonotakashi | 0:8fdf9a60065b | 757 | self.mem_summary['static_ram'], |
kadonotakashi | 0:8fdf9a60065b | 758 | self.mem_summary['static_ram_delta'] |
kadonotakashi | 0:8fdf9a60065b | 759 | ) |
kadonotakashi | 0:8fdf9a60065b | 760 | output += self.ROM_FORMAT_STR.format( |
kadonotakashi | 0:8fdf9a60065b | 761 | self.mem_summary['total_flash'], |
kadonotakashi | 0:8fdf9a60065b | 762 | self.mem_summary['total_flash_delta'] |
kadonotakashi | 0:8fdf9a60065b | 763 | ) |
kadonotakashi | 0:8fdf9a60065b | 764 | |
kadonotakashi | 0:8fdf9a60065b | 765 | return output |
kadonotakashi | 0:8fdf9a60065b | 766 | |
kadonotakashi | 0:8fdf9a60065b | 767 | toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "GCC_CR", "IAR"] |
kadonotakashi | 0:8fdf9a60065b | 768 | |
kadonotakashi | 0:8fdf9a60065b | 769 | def compute_report(self): |
kadonotakashi | 0:8fdf9a60065b | 770 | """ Generates summary of memory usage for main areas |
kadonotakashi | 0:8fdf9a60065b | 771 | """ |
kadonotakashi | 0:8fdf9a60065b | 772 | self.subtotal = defaultdict(int) |
kadonotakashi | 0:8fdf9a60065b | 773 | |
kadonotakashi | 0:8fdf9a60065b | 774 | for mod in self.modules.values(): |
kadonotakashi | 0:8fdf9a60065b | 775 | for k in self.sections: |
kadonotakashi | 0:8fdf9a60065b | 776 | self.subtotal[k] += mod[k] |
kadonotakashi | 0:8fdf9a60065b | 777 | self.subtotal[k + '-delta'] += mod[k] |
kadonotakashi | 0:8fdf9a60065b | 778 | if self.old_modules: |
kadonotakashi | 0:8fdf9a60065b | 779 | for mod in self.old_modules.values(): |
kadonotakashi | 0:8fdf9a60065b | 780 | for k in self.sections: |
kadonotakashi | 0:8fdf9a60065b | 781 | self.subtotal[k + '-delta'] -= mod[k] |
kadonotakashi | 0:8fdf9a60065b | 782 | |
kadonotakashi | 0:8fdf9a60065b | 783 | self.mem_summary = { |
kadonotakashi | 0:8fdf9a60065b | 784 | 'static_ram': self.subtotal['.data'] + self.subtotal['.bss'], |
kadonotakashi | 0:8fdf9a60065b | 785 | 'static_ram_delta': |
kadonotakashi | 0:8fdf9a60065b | 786 | self.subtotal['.data-delta'] + self.subtotal['.bss-delta'], |
kadonotakashi | 0:8fdf9a60065b | 787 | 'total_flash': (self.subtotal['.text'] + self.subtotal['.data']), |
kadonotakashi | 0:8fdf9a60065b | 788 | 'total_flash_delta': |
kadonotakashi | 0:8fdf9a60065b | 789 | self.subtotal['.text-delta'] + self.subtotal['.data-delta'], |
kadonotakashi | 0:8fdf9a60065b | 790 | } |
kadonotakashi | 0:8fdf9a60065b | 791 | |
kadonotakashi | 0:8fdf9a60065b | 792 | self.mem_report = [] |
kadonotakashi | 0:8fdf9a60065b | 793 | if self.short_modules: |
kadonotakashi | 0:8fdf9a60065b | 794 | for name, sizes in sorted(self.short_modules.items()): |
kadonotakashi | 0:8fdf9a60065b | 795 | self.mem_report.append({ |
kadonotakashi | 0:8fdf9a60065b | 796 | "module": name, |
kadonotakashi | 0:8fdf9a60065b | 797 | "size":{ |
kadonotakashi | 0:8fdf9a60065b | 798 | k: sizes.get(k, 0) for k in (self.print_sections + |
kadonotakashi | 0:8fdf9a60065b | 799 | self.delta_sections) |
kadonotakashi | 0:8fdf9a60065b | 800 | } |
kadonotakashi | 0:8fdf9a60065b | 801 | }) |
kadonotakashi | 0:8fdf9a60065b | 802 | |
kadonotakashi | 0:8fdf9a60065b | 803 | self.mem_report.append({ |
kadonotakashi | 0:8fdf9a60065b | 804 | 'summary': self.mem_summary |
kadonotakashi | 0:8fdf9a60065b | 805 | }) |
kadonotakashi | 0:8fdf9a60065b | 806 | |
kadonotakashi | 0:8fdf9a60065b | 807 | def parse(self, mapfile, toolchain): |
kadonotakashi | 0:8fdf9a60065b | 808 | """ Parse and decode map file depending on the toolchain |
kadonotakashi | 0:8fdf9a60065b | 809 | |
kadonotakashi | 0:8fdf9a60065b | 810 | Positional arguments: |
kadonotakashi | 0:8fdf9a60065b | 811 | mapfile - the file name of the memory map file |
kadonotakashi | 0:8fdf9a60065b | 812 | toolchain - the toolchain used to create the file |
kadonotakashi | 0:8fdf9a60065b | 813 | """ |
kadonotakashi | 0:8fdf9a60065b | 814 | self.tc_name = toolchain.title() |
kadonotakashi | 0:8fdf9a60065b | 815 | if toolchain in ("ARM", "ARM_STD", "ARM_MICRO", "ARMC6"): |
kadonotakashi | 0:8fdf9a60065b | 816 | parser = _ArmccParser |
kadonotakashi | 0:8fdf9a60065b | 817 | elif toolchain == "GCC_ARM" or toolchain == "GCC_CR": |
kadonotakashi | 0:8fdf9a60065b | 818 | parser = _GccParser |
kadonotakashi | 0:8fdf9a60065b | 819 | elif toolchain == "IAR": |
kadonotakashi | 0:8fdf9a60065b | 820 | parser = _IarParser |
kadonotakashi | 0:8fdf9a60065b | 821 | else: |
kadonotakashi | 0:8fdf9a60065b | 822 | return False |
kadonotakashi | 0:8fdf9a60065b | 823 | try: |
kadonotakashi | 0:8fdf9a60065b | 824 | with open(mapfile, 'r') as file_input: |
kadonotakashi | 0:8fdf9a60065b | 825 | self.modules = parser().parse_mapfile(file_input) |
kadonotakashi | 0:8fdf9a60065b | 826 | try: |
kadonotakashi | 0:8fdf9a60065b | 827 | with open("%s.old" % mapfile, 'r') as old_input: |
kadonotakashi | 0:8fdf9a60065b | 828 | self.old_modules = parser().parse_mapfile(old_input) |
kadonotakashi | 0:8fdf9a60065b | 829 | except IOError: |
kadonotakashi | 0:8fdf9a60065b | 830 | self.old_modules = None |
kadonotakashi | 0:8fdf9a60065b | 831 | if not COMPARE_FIXED: |
kadonotakashi | 0:8fdf9a60065b | 832 | old_mapfile = "%s.old" % mapfile |
kadonotakashi | 0:8fdf9a60065b | 833 | if exists(old_mapfile): |
kadonotakashi | 0:8fdf9a60065b | 834 | remove(old_mapfile) |
kadonotakashi | 0:8fdf9a60065b | 835 | rename(mapfile, old_mapfile) |
kadonotakashi | 0:8fdf9a60065b | 836 | return True |
kadonotakashi | 0:8fdf9a60065b | 837 | |
kadonotakashi | 0:8fdf9a60065b | 838 | except IOError as error: |
kadonotakashi | 0:8fdf9a60065b | 839 | print("I/O error({0}): {1}".format(error.errno, error.strerror)) |
kadonotakashi | 0:8fdf9a60065b | 840 | return False |
kadonotakashi | 0:8fdf9a60065b | 841 | |
kadonotakashi | 0:8fdf9a60065b | 842 | def main(): |
kadonotakashi | 0:8fdf9a60065b | 843 | """Entry Point""" |
kadonotakashi | 0:8fdf9a60065b | 844 | version = '0.4.0' |
kadonotakashi | 0:8fdf9a60065b | 845 | |
kadonotakashi | 0:8fdf9a60065b | 846 | # Parser handling |
kadonotakashi | 0:8fdf9a60065b | 847 | parser = ArgumentParser( |
kadonotakashi | 0:8fdf9a60065b | 848 | description="Memory Map File Analyser for ARM mbed\nversion %s" % |
kadonotakashi | 0:8fdf9a60065b | 849 | version) |
kadonotakashi | 0:8fdf9a60065b | 850 | |
kadonotakashi | 0:8fdf9a60065b | 851 | parser.add_argument( |
kadonotakashi | 0:8fdf9a60065b | 852 | 'file', type=argparse_filestring_type, help='memory map file') |
kadonotakashi | 0:8fdf9a60065b | 853 | |
kadonotakashi | 0:8fdf9a60065b | 854 | parser.add_argument( |
kadonotakashi | 0:8fdf9a60065b | 855 | '-t', '--toolchain', dest='toolchain', |
kadonotakashi | 0:8fdf9a60065b | 856 | help='select a toolchain used to build the memory map file (%s)' % |
kadonotakashi | 0:8fdf9a60065b | 857 | ", ".join(MemapParser.toolchains), |
kadonotakashi | 0:8fdf9a60065b | 858 | required=True, |
kadonotakashi | 0:8fdf9a60065b | 859 | type=argparse_uppercase_type(MemapParser.toolchains, "toolchain")) |
kadonotakashi | 0:8fdf9a60065b | 860 | |
kadonotakashi | 0:8fdf9a60065b | 861 | parser.add_argument( |
kadonotakashi | 0:8fdf9a60065b | 862 | '-d', '--depth', dest='depth', type=int, |
kadonotakashi | 0:8fdf9a60065b | 863 | help='specify directory depth level to display report', required=False) |
kadonotakashi | 0:8fdf9a60065b | 864 | |
kadonotakashi | 0:8fdf9a60065b | 865 | parser.add_argument( |
kadonotakashi | 0:8fdf9a60065b | 866 | '-o', '--output', help='output file name', required=False) |
kadonotakashi | 0:8fdf9a60065b | 867 | |
kadonotakashi | 0:8fdf9a60065b | 868 | parser.add_argument( |
kadonotakashi | 0:8fdf9a60065b | 869 | '-e', '--export', dest='export', required=False, default='table', |
kadonotakashi | 0:8fdf9a60065b | 870 | type=argparse_lowercase_hyphen_type(MemapParser.export_formats, |
kadonotakashi | 0:8fdf9a60065b | 871 | 'export format'), |
kadonotakashi | 0:8fdf9a60065b | 872 | help="export format (examples: %s: default)" % |
kadonotakashi | 0:8fdf9a60065b | 873 | ", ".join(MemapParser.export_formats)) |
kadonotakashi | 0:8fdf9a60065b | 874 | |
kadonotakashi | 0:8fdf9a60065b | 875 | parser.add_argument('-v', '--version', action='version', version=version) |
kadonotakashi | 0:8fdf9a60065b | 876 | |
kadonotakashi | 0:8fdf9a60065b | 877 | # Parse/run command |
kadonotakashi | 0:8fdf9a60065b | 878 | if len(argv) <= 1: |
kadonotakashi | 0:8fdf9a60065b | 879 | parser.print_help() |
kadonotakashi | 0:8fdf9a60065b | 880 | exit(1) |
kadonotakashi | 0:8fdf9a60065b | 881 | |
kadonotakashi | 0:8fdf9a60065b | 882 | args = parser.parse_args() |
kadonotakashi | 0:8fdf9a60065b | 883 | |
kadonotakashi | 0:8fdf9a60065b | 884 | # Create memap object |
kadonotakashi | 0:8fdf9a60065b | 885 | memap = MemapParser() |
kadonotakashi | 0:8fdf9a60065b | 886 | |
kadonotakashi | 0:8fdf9a60065b | 887 | # Parse and decode a map file |
kadonotakashi | 0:8fdf9a60065b | 888 | if args.file and args.toolchain: |
kadonotakashi | 0:8fdf9a60065b | 889 | if memap.parse(args.file, args.toolchain) is False: |
kadonotakashi | 0:8fdf9a60065b | 890 | exit(0) |
kadonotakashi | 0:8fdf9a60065b | 891 | |
kadonotakashi | 0:8fdf9a60065b | 892 | if args.depth is None: |
kadonotakashi | 0:8fdf9a60065b | 893 | depth = 2 # default depth level |
kadonotakashi | 0:8fdf9a60065b | 894 | else: |
kadonotakashi | 0:8fdf9a60065b | 895 | depth = args.depth |
kadonotakashi | 0:8fdf9a60065b | 896 | |
kadonotakashi | 0:8fdf9a60065b | 897 | returned_string = None |
kadonotakashi | 0:8fdf9a60065b | 898 | # Write output in file |
kadonotakashi | 0:8fdf9a60065b | 899 | if args.output != None: |
kadonotakashi | 0:8fdf9a60065b | 900 | returned_string = memap.generate_output(args.export, \ |
kadonotakashi | 0:8fdf9a60065b | 901 | depth, args.output) |
kadonotakashi | 0:8fdf9a60065b | 902 | else: # Write output in screen |
kadonotakashi | 0:8fdf9a60065b | 903 | returned_string = memap.generate_output(args.export, depth) |
kadonotakashi | 0:8fdf9a60065b | 904 | |
kadonotakashi | 0:8fdf9a60065b | 905 | if args.export == 'table' and returned_string: |
kadonotakashi | 0:8fdf9a60065b | 906 | print(returned_string) |
kadonotakashi | 0:8fdf9a60065b | 907 | |
kadonotakashi | 0:8fdf9a60065b | 908 | exit(0) |
kadonotakashi | 0:8fdf9a60065b | 909 | |
kadonotakashi | 0:8fdf9a60065b | 910 | if __name__ == "__main__": |
kadonotakashi | 0:8fdf9a60065b | 911 | main() |