xref: /optee_os/scripts/mem_usage.py (revision 479c49dd9247118109448e5be0883f08e80c5f46)
1#!/usr/bin/env python3
2#
3# Copyright (c) 2014-2017, Linaro Limited
4#
5# SPDX-License-Identifier: BSD-3-Clause
6
7import argparse
8import os
9import subprocess
10import sys
11
12
13def get_args():
14    parser = argparse.ArgumentParser(description='Shows the memory usage '
15                                     'of an OP-TEE based on ELF sections')
16    parser.add_argument('tee_elf', help='the OP-TEE ELF file (tee.elf)')
17    parser.add_argument('-a', '--all', action='store_true',
18                        help=' same as -i -p -u -U')
19    parser.add_argument('-n', '--no-map', action='store_true',
20                        help=' do not show the detailed section mappings and '
21                        'RAM usage')
22    parser.add_argument('-i', '--init', action='store_true',
23                        help='report the total size of the .*_init sections')
24    parser.add_argument('-p', '--paged', action='store_true',
25                        help='report the total size of the .*_pageable '
26                        'sections')
27    parser.add_argument('-u', '--unpaged', action='store_true',
28                        help='report the total size of the unpaged sections, '
29                        'that is, all sections but the ones in --init or '
30                        '--paged')
31    parser.add_argument('-U', '--unpaged-no-heap', action='store_true',
32                        help='report the size of all unpaged sections '
33                        'excluding heap space. Reflects the size of unpaged '
34                        'code and data (.text, .rodata, .data, .bss, .nozi '
35                        'and possibly unwind tables)')
36    parser.add_argument('-r', '--raw', action='store_true',
37                        help='when processing -i, -p, -u, or -U, show only '
38                        'the size (in decimal) and no other text')
39    return parser.parse_args()
40
41
42def printf(format, *args):
43    sys.stdout.write(format % args)
44
45
46def print_sect(name, addr, size, round_up=False, print_num_pages=False):
47    if args.no_map:
48        return
49    if size == 0:
50        size_kib = 0
51        num_pages = 0
52    else:
53        if round_up:
54            size_kib = (size - 1) / 1024 + 1
55        else:
56            size_kib = size / 1024
57        num_pages = (size - 1) / 4096 + 1
58
59    printf('%-16s %.8X - %.8X size %.8X %3d KiB', name, addr, addr + size,
60           size, size_kib)
61    if print_num_pages:
62        printf(' %d pages', num_pages)
63    printf('\n')
64
65
66def print_pager_stat(name, size):
67    size_kib = size / 1024
68    if args.raw:
69        printf('%d ', size)
70    else:
71        printf('%-36s size %.8X %3d KiB\n', name, size, size_kib)
72
73
74def readelf_cmd():
75    return os.getenv('CROSS_COMPILE', '') + 'readelf'
76
77
78def main():
79    global args
80
81    in_shdr = False
82    sects = []
83    init_size = 0
84    paged_size = 0
85    unpaged_size = 0
86    unpaged_no_heap_size = 0
87
88    args = get_args()
89    env = os.environ.copy()
90    env['LC_ALL'] = 'C'
91    readelf = subprocess.Popen(str.split(readelf_cmd()) + ['-s',
92                                                           args.tee_elf],
93                               stdout=subprocess.PIPE, env=env,
94                               universal_newlines=True)
95    for line in iter(readelf.stdout.readline, ''):
96        words = line.split()
97        if len(words) == 8 and words[7] == '_end_of_ram':
98            end_of_ram = int(words[1], 16)
99            break
100    readelf.terminate()
101    readelf = subprocess.Popen(str.split(readelf_cmd()) + ['-S', '-W',
102                                                           args.tee_elf],
103                               stdout=subprocess.PIPE, env=env,
104                               universal_newlines=True)
105    for line in iter(readelf.stdout.readline, ''):
106        if 'Section Headers:' in line:
107            in_shdr = True
108            continue
109        if 'Key to Flags:' in line:
110            in_shdr = False
111            continue
112        if in_shdr:
113            words = line.split()
114            if words[0] == '[':
115                words.pop(0)
116            try:
117                (_, name, _, addr, offs, size, _,
118                 flags) = words[:8]
119            except BaseException:
120                continue
121            if (flags == 'AX' or flags == 'WA' or flags == 'A' or
122                    flags == 'AL'):
123                sects.append({'name': name, 'addr': addr,
124                              'offs': offs, 'size': size})
125    first_addr = None
126    for sect in sects:
127        if sect['addr'] != 0:
128            addr = sect['addr']
129            if not first_addr:
130                first_addr = addr
131            if int(addr, 16) >= end_of_ram:
132                break
133            last_addr = addr
134            last_size = sect['size']
135
136    ram_usage = int(last_addr, 16) + int(last_size, 16) - int(first_addr, 16)
137    print_sect('RAM Usage', int(first_addr, 16), ram_usage, True, True)
138
139    last_addr = 0
140    last_size = 0
141    for sect in sects:
142        name = sect['name']
143        addr = int(sect['addr'], 16)
144        size = int(sect['size'], 16)
145
146        if addr >= end_of_ram:
147            break
148        if last_addr != 0 and addr != last_addr + last_size:
149            print_sect('*hole*', last_addr + last_size,
150                       addr - (last_addr + last_size))
151        print_sect(name, addr, size)
152        if name.endswith('_init'):
153            init_size += size
154        elif name.endswith('_pageable'):
155            paged_size += size
156        else:
157            if not name.startswith('.heap'):
158                unpaged_no_heap_size += size
159            unpaged_size += size
160        last_addr = addr
161        last_size = size
162
163    if args.all or args.init:
164        print_pager_stat('Init sections (.*_init)', init_size)
165    if args.all or args.paged:
166        print_pager_stat('Paged sections (.*_pageable)', paged_size)
167    if args.all or args.unpaged:
168        print_pager_stat('Unpaged sections ', unpaged_size)
169    if args.all or args.unpaged_no_heap:
170        print_pager_stat('Unpaged sections (heap excluded)',
171                         unpaged_no_heap_size)
172    if (args.raw and (args.all or args.init or args.paged or
173                      args.unpaged or args.unpaged_no_heap)):
174        printf('\n')
175
176
177if __name__ == "__main__":
178    main()
179