| #!/usr/bin/env python3 |
| # |
| # Copyright (c) 2014-2017, Linaro Limited |
| # |
| # SPDX-License-Identifier: BSD-3-Clause |
| |
| import argparse |
| import os |
| import subprocess |
| import sys |
| |
| |
| def get_args(): |
| parser = argparse.ArgumentParser(description='Shows the memory usage ' |
| 'of an OP-TEE based on ELF sections') |
| parser.add_argument('tee_elf', help='the OP-TEE ELF file (tee.elf)') |
| parser.add_argument('-a', '--all', action='store_true', |
| help=' same as -i -p -u -U') |
| parser.add_argument('-n', '--no-map', action='store_true', |
| help=' do not show the detailed section mappings and ' |
| 'RAM usage') |
| parser.add_argument('-i', '--init', action='store_true', |
| help='report the total size of the .*_init sections') |
| parser.add_argument('-p', '--paged', action='store_true', |
| help='report the total size of the .*_pageable ' |
| 'sections') |
| parser.add_argument('-u', '--unpaged', action='store_true', |
| help='report the total size of the unpaged sections, ' |
| 'that is, all sections but the ones in --init or ' |
| '--paged') |
| parser.add_argument('-U', '--unpaged-no-heap', action='store_true', |
| help='report the size of all unpaged sections ' |
| 'excluding heap space. Reflects the size of unpaged ' |
| 'code and data (.text, .rodata, .data, .bss, .nozi ' |
| 'and possibly unwind tables)') |
| parser.add_argument('-r', '--raw', action='store_true', |
| help='when processing -i, -p, -u, or -U, show only ' |
| 'the size (in decimal) and no other text') |
| return parser.parse_args() |
| |
| |
| def printf(format, *args): |
| sys.stdout.write(format % args) |
| |
| |
| def print_sect(name, addr, size, round_up=False, print_num_pages=False): |
| if args.no_map: |
| return |
| if size == 0: |
| size_kib = 0 |
| num_pages = 0 |
| else: |
| if round_up: |
| size_kib = (size - 1) / 1024 + 1 |
| else: |
| size_kib = size / 1024 |
| num_pages = (size - 1) / 4096 + 1 |
| |
| printf('%-16s %.8X - %.8X size %.8X %3d KiB', name, addr, addr + size, |
| size, size_kib) |
| if print_num_pages: |
| printf(' %d pages', num_pages) |
| printf('\n') |
| |
| |
| def print_pager_stat(name, size): |
| size_kib = size / 1024 |
| if args.raw: |
| printf('%d ', size) |
| else: |
| printf('%-36s size %.8X %3d KiB\n', name, size, size_kib) |
| |
| |
| def readelf_cmd(): |
| return os.getenv('CROSS_COMPILE', '') + 'readelf' |
| |
| |
| def main(): |
| global args |
| |
| in_shdr = False |
| sects = [] |
| init_size = 0 |
| paged_size = 0 |
| unpaged_size = 0 |
| unpaged_no_heap_size = 0 |
| |
| args = get_args() |
| env = os.environ.copy() |
| env['LC_ALL'] = 'C' |
| readelf = subprocess.Popen(str.split(readelf_cmd()) + ['-s', |
| args.tee_elf], |
| stdout=subprocess.PIPE, env=env, |
| universal_newlines=True) |
| for line in iter(readelf.stdout.readline, ''): |
| words = line.split() |
| if len(words) == 8 and words[7] == '_end_of_ram': |
| end_of_ram = int(words[1], 16) |
| break |
| readelf.terminate() |
| readelf = subprocess.Popen(str.split(readelf_cmd()) + ['-S', '-W', |
| args.tee_elf], |
| stdout=subprocess.PIPE, env=env, |
| universal_newlines=True) |
| for line in iter(readelf.stdout.readline, ''): |
| if 'Section Headers:' in line: |
| in_shdr = True |
| continue |
| if 'Key to Flags:' in line: |
| in_shdr = False |
| continue |
| if in_shdr: |
| words = line.split() |
| if words[0] == '[': |
| words.pop(0) |
| try: |
| (_, name, _, addr, offs, size, _, |
| flags) = words[:8] |
| except BaseException: |
| continue |
| if (flags == 'AX' or flags == 'WA' or flags == 'A' or |
| flags == 'AL'): |
| sects.append({'name': name, 'addr': addr, |
| 'offs': offs, 'size': size}) |
| first_addr = None |
| for sect in sects: |
| if sect['addr'] != 0: |
| addr = sect['addr'] |
| if not first_addr: |
| first_addr = addr |
| if int(addr, 16) >= end_of_ram: |
| break |
| last_addr = addr |
| last_size = sect['size'] |
| |
| ram_usage = int(last_addr, 16) + int(last_size, 16) - int(first_addr, 16) |
| print_sect('RAM Usage', int(first_addr, 16), ram_usage, True, True) |
| |
| last_addr = 0 |
| last_size = 0 |
| for sect in sects: |
| name = sect['name'] |
| addr = int(sect['addr'], 16) |
| size = int(sect['size'], 16) |
| |
| if addr >= end_of_ram: |
| break |
| if last_addr != 0 and addr != last_addr + last_size: |
| print_sect('*hole*', last_addr + last_size, |
| addr - (last_addr + last_size)) |
| print_sect(name, addr, size) |
| if name.endswith('_init'): |
| init_size += size |
| elif name.endswith('_pageable'): |
| paged_size += size |
| else: |
| if not name.startswith('.heap'): |
| unpaged_no_heap_size += size |
| unpaged_size += size |
| last_addr = addr |
| last_size = size |
| |
| if args.all or args.init: |
| print_pager_stat('Init sections (.*_init)', init_size) |
| if args.all or args.paged: |
| print_pager_stat('Paged sections (.*_pageable)', paged_size) |
| if args.all or args.unpaged: |
| print_pager_stat('Unpaged sections ', unpaged_size) |
| if args.all or args.unpaged_no_heap: |
| print_pager_stat('Unpaged sections (heap excluded)', |
| unpaged_no_heap_size) |
| if (args.raw and (args.all or args.init or args.paged or |
| args.unpaged or args.unpaged_no_heap)): |
| printf('\n') |
| |
| |
| if __name__ == "__main__": |
| main() |