• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4#
5# Copyright (c) 2020-2022 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import re
20import sys
21import argparse
22import os
23import datetime
24
25g_version = 2.5
26g_excel_support = False
27g_row_num = 0
28
29try:
30    from openpyxl import Workbook
31except:
32    print("excel output is not support, need install openpyxl")
33else:
34    g_excel_support = True
35
36def is_number(num):
37    try:
38        int(num, 16)
39        return True
40    except ValueError:
41        pass
42    return False
43
44static_map = {}
45def storage_static_data(offset, section, sizeHex, symbol, lib, obj):
46    global g_row_num
47    if (0 == g_row_num):
48        static_map[g_row_num] = {'offsets' : "offsets", 'section' : "section",\
49            'sizeH' : "size(Hex)", 'sizeD' : "size(Dec)",\
50            'symbol' : "symbol", 'lib' : "lib", 'obj' : "object"}
51        g_row_num = g_row_num + 1
52
53    size = int(sizeHex, 16)
54    static_map[g_row_num] = {'offsets': offset, 'section' : section,\
55            'sizeH' : sizeHex, 'sizeD' : size,\
56            'symbol' : symbol, 'lib' : lib, 'obj' : obj}
57    g_row_num = g_row_num + 1
58
59def store_static_excel():
60    wb = Workbook()
61    ws = wb.active
62    for base_address, values in static_map.items():
63        c = ws.cell(row=base_address + 1, column=1)
64        c.value = values.get('offsets')
65        c = ws.cell(row=base_address + 1, column=2)
66        c.value = values.get('section')
67        c = ws.cell(row=base_address + 1, column=3)
68        c.value = values.get('sizeH')
69        c = ws.cell(row=base_address + 1, column=4)
70        c.value = values.get('sizeD')
71        c = ws.cell(row=base_address + 1, column=5)
72        c.value = values.get('symbol')
73        c = ws.cell(row=base_address + 1, column=6)
74        c.value = values.get('lib')
75        c = ws.cell(row=base_address + 1, column=7)
76        c.value = values.get('obj')
77    wb.save('static_symbol-%s.xlsx' % datetime.datetime.now().strftime('%Y-%m-%d %H_%M_%S'))
78    return
79
80def format_store_static():
81    global g_excel_support
82    target_list = []
83
84    for base_address, values in static_map.items():
85        target_list.append('{:<10s}'.format(values.get('offsets')))
86        target_list.append('{:<30s}'.format(values.get('section')))
87        target_list.append('{:<10}'.format(values.get('sizeH')))
88        target_list.append('{:<10}'.format(values.get('sizeD')))
89        target_list.append('{:<55s}{:<55s}{:<55s}'.format(values.get('symbol'), values.get('lib'), values.get('obj')))
90        target_list.append("\r")
91
92    with open("./static_symbol_out.txt", "w+") as out_fd:
93        out_fd.write("".join(target_list))
94    if g_excel_support == True:
95        store_static_excel()
96    return
97
98dync_map = {}
99#dync map multiple LR, first dync_map node will record LR size
100def storage_dync_head(size):
101    global g_row_num
102    dync_map[0] = {'addr' : "Memnode", 'symbol' : "size", 'lib' : size}
103    g_row_num = 1
104
105#when the analysis of one line LR is finished, need record "\r\n" and the new line info
106def storage_dync_node(node_addr, size):
107    global g_row_num
108    dync_map[g_row_num] = {'addr' : "\r\n", 'symbol' : node_addr, 'lib' : size}
109    g_row_num = g_row_num + 1
110
111def storage_dync_data(addr, symbol, lib):
112    global g_row_num
113    dync_map[g_row_num] = {'addr' : addr, 'symbol' : symbol, 'lib' : lib}
114    g_row_num = g_row_num + 1
115
116def store_dync_excel():
117    wb = Workbook()
118    ws = wb.active
119    row = 1
120    column = 0
121    for base_address, values in dync_map.items():
122        if (0 == base_address):
123            c = ws.cell(row, 1)
124            c.value = values.get('addr')
125            c = ws.cell(row, 2)
126            c.value = values.get('symbol')
127            for i in range(values.get('lib')):
128                column = i * 3 + 2
129                addr_name = "LR%s_addr" % (str(i))
130                c = ws.cell(row, column + 1)
131                c.value = addr_name
132                symbol_name = "LR%s_symbol" % (str(i))
133                c = ws.cell(row, column + 2)
134                c.value = symbol_name
135                object_name = "LR%s_object" % (str(i))
136                c = ws.cell(row, column + 3)
137                c.value = object_name
138        else:
139            if("\r\n" == values.get('addr')):
140                row = row + 1
141                column = 1
142                c = ws.cell(row, column)
143                c.value = values.get('symbol')
144                column = column + 1
145                c = ws.cell(row, column)
146                c.value = values.get('lib')
147            else:
148                c = ws.cell(row, column + 1)
149                c.value = values.get('addr')
150                c = ws.cell(row, column + 2)
151                c.value = values.get('symbol')
152                c = ws.cell(row, column + 3)
153                c.value = values.get('lib')
154                column = column + 3
155    wb.save('dync_mem-%s.xlsx' % datetime.datetime.now().strftime('%Y-%m-%d %H_%M_%S'))
156    return
157
158def format_store_dync():
159    global g_excel_support
160    target_list = []
161
162    for base_address, values in dync_map.items():
163        if (0 == base_address):
164            target_list.append('{:<15s}{:<15s}'.format("node", "size"))
165            for i in range(values.get('lib')):
166                addr_name = "LR%s_addr" % (str(i))
167                symbol_name = "LR%s_symbol" % (str(i))
168                object_name = "LR%s_object" % (str(i))
169                target_list.append('{:<15s}{:<55s}{:<55s}'.format(addr_name, symbol_name, object_name))
170
171        else:
172            if ("\r\n" == values.get('addr')):
173                target_list.append("\r")
174                target_list.append('{:<15s}{:<15}'.format(values.get('symbol'), values.get('lib')))
175            else:
176                target_list.append('{:<15s}'.format(values.get('addr')))
177                target_list.append('{:<55s}'.format(values.get('symbol')))
178                target_list.append('{:<55s}'.format(values.get('lib')))
179
180    with open("./dynamic_memory_out.txt", "w+") as out_fd:
181        out_fd.write("".join(target_list))
182    if g_excel_support == True:
183        store_dync_excel()
184    return
185
186address_map = {}
187def get_func_by_name(function_name):
188    for base_address, values in address_map.items():
189        if values.get('func_name') == function_name:
190            return values.get('lib_name'), values.get('obj_name')
191    return "none", "none"
192
193def get_func_by_address(address):
194    if 0 == address:
195        return "none", "none"
196
197    for base_address, values in address_map.items():
198        if (base_address <= address) and (base_address  + values.get('size') > address):
199            return values.get('func_name'), values.get('obj_name')
200    return "none", "none"
201
202def line_start_check(line):
203    if line.startswith(' .text.'):
204        function_name = line.split(".text.")[1]
205    elif line.startswith(' .rodata.'):
206        function_name = line.split(".rodata.")[1]
207    elif line.startswith(' .bss.'):
208        function_name = line.split(".bss.")[1]
209    elif line.startswith(' .sram.text.'):
210        function_name = line.split(".sram.text.")[1]
211    elif line.startswith(' .data.'):
212        function_name = line.split(".data.")[1]
213    else:
214        return None
215    return function_name
216
217def parse_map(file_path):
218    parse_begin = False
219    function_name = ""
220    address = None
221    size = None
222    obj_name = ""
223    lib_name = ""
224    pl = re.compile(r'[(](.*?)[)]', re.S)
225    with open(file_path, "r") as f:
226        for line in f.readlines():
227            if not parse_begin:
228                function_name = line_start_check(line)
229                if function_name != None:
230                    if len(function_name.split()) > 1:
231                        strs = function_name.split()
232                        function_name = strs[0]
233                        function_name = function_name.strip()
234                        address = int(strs[1], 16)
235                        size = int(strs[2], 16)
236                        obj_name = re.findall(pl, strs[3])
237                        if len(obj_name) > 0:
238                            obj_name = obj_name[0]
239                        else:
240                            obj_name = strs[3]
241                        char_temp = strs[3].split('(')
242                        if len(char_temp) > 1:
243                            lib_name = char_temp[0].split('/')[-1]
244                        else:
245                            lib_name = "none"
246                        address_map[address] = {'size' : size, 'lib_name' : lib_name, \
247                            'obj_name' : obj_name, 'func_name' : function_name}
248                    else:
249                        parse_begin = True
250                else:
251                    continue
252            else:
253                parse_begin = False
254                if len(line.strip().split()) != 3:
255                    continue
256                strs = line.strip().split()
257                address = int(strs[0], 16)
258                size = int(strs[1], 16)
259                obj_name = re.findall(pl, strs[2])
260                if len(obj_name) > 0:
261                    obj_name = obj_name[0]
262                else:
263                    obj_name = strs[2]
264                function_name = function_name.strip()
265                char_temp = strs[2].split('(')
266                if len(char_temp) > 1:
267                    lib_name = char_temp[0].split('/')[-1]
268                else:
269                    lib_name = "none"
270                address_map[address] = {'size' : size, 'lib_name' : lib_name, \
271                    'obj_name' : obj_name, 'func_name' : function_name}
272
273def parse_dump(dump_path):
274    with open(dump_path, "r") as symbol_fd:
275        symline = symbol_fd.readlines()
276
277    for index, line in enumerate(symline):
278        offset = line[:8]
279
280        #According to the regular expression of objdump , section start at 17 char
281        symbol_list = line[17:].split()
282        if len(symbol_list) < 3:
283            continue
284
285        sec = symbol_list[0]
286        size = symbol_list[1]
287        if (False == is_number(size)) or 0 == int(size, 16):
288            continue
289
290        lib, obj = get_func_by_name(symbol_list[-1])
291        storage_static_data(offset, sec, size, symbol_list[-1], lib, obj)
292
293def parse_log(log_path):
294    with open(log_path, "r") as log_fd:
295        logline = log_fd.readlines()
296    get_valid_log = False
297    for index, line in enumerate(logline):
298        char_list = line.split()
299        if len(char_list) < 3:
300            continue
301        if ("node" == char_list[0]) & ("LR[0]" == char_list[2]):
302            storage_dync_head(len(char_list) - 2)
303            get_valid_log = True
304            continue
305
306        if True == get_valid_log:
307            mem_addr = char_list[0].split(':')
308            if True == is_number(mem_addr[0]):
309                for i in range(len(char_list)):
310                    if i == 0:
311                        size = int(char_list[1], 16)
312                        storage_dync_node(mem_addr[0], size)
313                    if i > 1:
314                        symbol, lib = get_func_by_address(int(char_list[i], 16))
315                        storage_dync_data(char_list[i], symbol, lib)
316            else:
317                get_valid_log = False
318                continue
319
320def main():
321    print("memory parses tool ver.%2f\r\n" % g_version)
322    parser = argparse.ArgumentParser()
323    parser.add_argument('--m', help='map path.')
324    parser.add_argument('--l', help='dynamic mem log path.')
325    parser.add_argument('--d', help='objdump path.')
326    args = parser.parse_args()
327
328    print("map path: %s\r\n" % args.m)
329    if args.m == None :
330        print("arg error, input -h get the help list\r\n")
331        return
332
333    parse_map(args.m)
334
335    print("dump path: %s" % args.d)
336    if args.d != None :
337        parse_dump(args.d)
338        format_store_static()
339    else:
340        print("dump path unspecified, will not be static parser")
341        print("you can enter the objdump -t command under the linux shell to obtain dump information\r\n")
342
343    print("log path: %s" % args.l)
344    if args.l != None :
345        parse_log(args.l)
346        format_store_dync()
347    else:
348        print("log path unspecified, will not be dynamic parser\r\n")
349
350    return
351
352if __name__ == '__main__':
353    sys.exit(main())