blob: 4d54e0a863ac0a4030b28e2ce2e737304d1500b0 [file] [log] [blame]
xiaohu.huang29fd84c2022-12-19 15:27:00 +08001#!/usr/bin/python3
2#coding:utf-8
3#
4# Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
5#
6# SPDX-License-Identifier: MIT
7#
8
9
10from __future__ import print_function
11
12import sys
13import os
14import argparse
15import operator
16
17parser = argparse.ArgumentParser(description='total size of each object file in an ld linker map.')
18parser.add_argument('map_file', help="A map file generated by passing -M/--print-map to ld during linking.")
19parser.add_argument('--combine', action='store_true',
20 help="All object files in an .a archive or in a directory are combined")
21args = parser.parse_args()
22
23class SectionSize():
24 text = 0
25 data = 0 # Including metadata like import tables
26 bss = 0
27 customize = 0
28 def rom(self):
29 return self.text + self.data
30 def ram(self):
31 return self.data + self.bss
32 def total(self):
33 return self.text + self.data + self.bss
34 def add_clang_llvm_section(self, section, size):
35 if section == ".text":
36 self.text += size
37 elif section == ".bss":
38 self.bss += size
39 elif section == ".data" or section == ".rodata":
40 self.data += size
41 else:
42 if (size > 0):
43 print("customer section:%s, size:%d" % (section, size))
44 self.customize += size
45
46size_by_source = {}
47current_section = None
48last_section = None
49last_source = None
50current_addr = 0x00;
51last_addr = "0"
52size = 0x00;
53last_size = 0x00;
54last_real_size = 0x00;
55heap = 0
56stack = 0
57with open(args.map_file) as f:
58 print("clang+llvm toolchain map analyzer")
59 lines = iter(f)
60 for line in lines:
61 line = line.strip('\n')
62
63 if operator.contains(line, ":(.debug_") or operator.contains(line, ":(.comment"):
64 continue
65 elif operator.contains(line, ":(.shstrtab") or operator.contains(line, ":(.symtab") or operator.contains(line, ":(.strtab"):
66 continue
67 elif (line.endswith(".text")) or (line.endswith(".data")) or (line.endswith(".rodata")) or (line.endswith(".bss")):
68 pieces = line.split(None, 5)
69 current_section = pieces[4]
70 elif operator.contains(line, ":(.") \
71 or operator.contains(line, ".heap") \
72 or operator.contains(line, ".stack") \
73 or operator.contains(line, ":(.text") \
74 or operator.contains(line, ":(.data") \
75 or operator.contains(line, ":(.bss") \
76 or operator.contains(line, ":(.rodata."):
77 pieces = line.split(None, 5) # Don't split paths containing spaces
78 size = int(pieces[2], 16)
79 source = pieces[4]
80 current_addr = pieces[1]
81 if operator.contains(line, '.heap'):
82 heap += size
83 elif operator.contains(line, '.stack'):
84 stack += size
85
86 if args.combine:
87 if '.a(' in source:
88 source = source[:source.index('.a(') + 2]
89 elif '.dir' in source:
90 source = source[:source.find(".dir")]
91 elif '<internal>' in source:
92 source = last_source
93 else:
94 source = os.path.basename(source)
95
96 if source not in size_by_source:
97 size_by_source[source] = SectionSize()
98
99 last_real_size = operator.sub(int(current_addr, 16), int(last_addr, 16))
100 if operator.ne(last_size, 0x00) and operator.gt(last_real_size, last_size):
101 #fixed the last size from address by the size not from last section
102 if (last_section != None) and (current_section != last_section ):
103 #fixed the last size from last source
104 if (last_source != None) and (source != last_source):
105 size_by_source[last_source].add_clang_llvm_section(last_section, (last_real_size - last_size))
106 else:
107 size_by_source[source].add_clang_llvm_section(last_section, (last_real_size - last_size))
108 else:
109 if (last_source != None) and (source != last_source):
110 size_by_source[last_source].add_clang_llvm_section(current_section, (last_real_size - last_size))
111 else:
112 size_by_source[source].add_clang_llvm_section(current_section, (last_real_size - last_size))
113 size_by_source[source].add_clang_llvm_section(current_section, size)
114
115 last_addr = current_addr
116 last_size = size
117 last_section = current_section;
118 last_source = source;
119
120# Print out summary
121sources = list(size_by_source.keys())
122sources.sort(key = lambda x: size_by_source[x].total())
123sumrom = sumram = sumcode = sumdata = sumbss = sumcustomize = 0
124
125print('---------------------------------------------------------------------------------------------------')
126col_format = "%-20s\t%-12s\t%-12s\t%-7s\t%-12s\t%-12s\t%-7s"
127print(col_format % ("module file", "ROM(text+data)", "RAM(data+bss)", ".text", ".data", ".bss", "customize"))
128for source in sources:
129 size = size_by_source[source]
130 sumcode += size.text
131 sumdata += size.data
132 sumbss += size.bss
133 sumrom += size.rom()
134 sumram += size.ram()
135 sumcustomize += size.customize
136 print(col_format % (os.path.basename(source), size.rom(), size.ram(), size.text, size.data, size.bss, size.customize))
137
138print('---------------------------------------------------------------------------------------------------')
139col_format = "%-5s\t%-12s\t%-12s\t%-7s\t%-12s\t%-12s\t%-7s\t%-7s\t%-7s"
140print(col_format % (" ", "ROM(text+data)", "RAM(data+bss)", ".text", ".data", ".bss", "cust", "stack", "heap" ))
141print(col_format % ("total", sumrom, sumram, sumcode, sumdata, sumbss, sumcustomize, stack, heap))
142print('---------------------------------------------------------------------------------------------------')