• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# coding=utf-8
3#   Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
4#    Licensed under the Apache License, Version 2.0 (the "License");
5#    you may not use this file except in compliance with the License.
6#    You may obtain a copy of the License at
7#
8#        http://www.apache.org/licenses/LICENSE-2.0
9#
10#    Unless required by applicable law or agreed to in writing, software
11#    distributed under the License is distributed on an "AS IS" BASIS,
12#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13#    See the License for the specific language governing permissions and
14#    limitations under the License.
15
16import json
17import os
18import sys
19from os.path import join, isdir, abspath, exists, isabs, sep, normpath
20import re
21
22from common_utils import CommonUtils
23
24work_dir = os.path.split(os.path.realpath(__file__))[0]
25root_dir = os.path.join(work_dir, '..', '..', '..')
26sys.path.append(os.path.join(root_dir, 'build'))
27sys.path.append(os.path.join(root_dir, 'build', 'script'))
28sys.path.append(os.path.join(root_dir, 'build', 'config'))
29from enviroment import TargetEnvironment
30from utils.build_utils import output_root
31
32map_start_rule = r'Memory Configuration'
33map_end_rule = r'Linker script and memory map'
34# map文件中Cross Reference Table项不涉及镜像大小,结束map文件解析
35map_file_size_end = r"Cross Reference Table"
36elf_setion_rule = r'^\s[0-9]'
37elf_symbol_rule = r'^[0-9]+'
38file_size_content_rule = r'^(\s*\.[a-zA-Z]+)'
39
40
41class BuildDataAnalyzer:
42    _elf_path = ''
43    _map_path = ''
44    _build_config_path = ''
45    _module_config = {}
46    _compiler_path = ''
47    _prefix = 'arm-none-eabi'
48    _section_keys = []
49    _environment = ''
50
51    section_data = {}
52    region_data = []
53    size_data = {}
54    elf_size_data = {}
55    module_data = {}
56    folder_data = {}
57    rom_addr = {
58        'start': 0,
59        'end': 0
60    }
61    rom_parts = {}
62    is_rom = True
63    last_symbol = []
64    last_line = ''
65    is_unknown = False
66    cur_section = ''
67    cur_section_size = ''
68
69    def __init__(self, paths):
70        print('++++++++++start buildAnalyzer++++++++++')
71        data = CommonUtils.get_prefix(paths['compiler_path'])
72        self._prefix = data['prefix']
73        self._environment = data['environment']
74        for key, value in paths.items():
75            print(f"{key}:{value}")
76        self._elf_path = paths['elf_path']
77        self._map_path = paths['map_path']
78        self._compiler_path = paths['compiler_path']
79        self._build_config_path = paths['build_config_path']
80        self._remove_sections_config_path = paths['remove_sections_config_path']
81        self._result_save_path = paths['result_save_path']
82
83        try:
84            save_dir = os.path.dirname(self._result_save_path)
85            if not os.path.isdir(save_dir):
86                os.makedirs(save_dir)
87        except Exception as e:
88            raise Exception(f"Failed to Create Save Directory,{e}")
89        self._root_dir = os.getcwd()
90        self._json_path = join(self._root_dir, 'memoryDetails.json')
91        self._image_remove_section = []
92
93    def do_build_analysis(self, paths):
94        try:
95            with open(self._remove_sections_config_path, 'r') as rv_f:
96                for line in rv_f.readlines():
97                    l_s = line.strip()
98                    self._image_remove_section.append(l_s)
99
100            self._module_config = self._get_build_json(paths.get('build_config_path', ""))
101            json_obj = self._parse_map_file()
102            self.result_filter(json_obj)
103            # with open(self._result_save_path, 'w') as result_f:
104            #     json.dump(json_obj, result_f, indent=4)
105            print('++++++++++end buildAnalyzer++++++++++')
106        except Exception as e:
107            raise Exception('buildAnalyzer error') from e
108
109    def result_filter(self, json_cont):
110        """
111        结果过滤
112        """
113        new_json = json_cont.get("moduleData", "")
114        if not new_json:
115            raise Exception("ImageAnalysis Failed")
116        with open(self._result_save_path, 'w') as res_f:
117            res_f.write('<h1>Image Analysis</h1>')
118            res_f.write('<table border="1" width = "40%" cellspacing="0" cellpadding="0" align="left">')
119            line = 0
120            for key, value in new_json.items():
121                if line == 0:
122                    head_line = '<tr>'
123                    for v in value:
124                        if v == 'parent':
125                            continue
126                        head_line = head_line + '<th>' +  v + '</th>'
127                    head_line = head_line + '<tr>\n'
128                    res_f.write(head_line)
129                    line = line + 1
130                new_line = '<tr>'
131                if value["parent"]:
132                    continue
133                for v in value:
134                    if value[v] != '':
135                        new_line = new_line + '<td>' + str(value[v]) + '</td>'
136                new_line = new_line + '</tr>\n'
137                res_f.write(new_line)
138
139    @staticmethod
140    def _get_build_json(file_path):
141        try:
142            with open(file_path, 'r', encoding='utf-8') as f:
143                res = f.read()
144                json_data = json.loads(s=res)
145                return json_data
146        except FileExistsError as e:
147            print('file exists error')
148            raise FileExistsError() from e
149
150    def _parse_map_file(self):
151        try:
152            suffix = self._prefix + '-size.exe'
153            if self._environment == 'linux':
154                suffix = self._prefix + '-size'
155            file_size_path = join(self._compiler_path, suffix)
156            if not exists(file_size_path):
157                print(f'size path not find: {file_size_path}')
158                raise FileExistsError()
159            size_arr = self.get_file_size(file_size_path, '-A', self._elf_path)
160            size_arr.pop()
161            size_arr.pop(0)
162            self._set_elf_size_data(size_arr)
163            json_obj = self._read_file()
164            return json_obj
165        except SystemError as e:
166            print('map parse error')
167            raise SystemError() from e
168
169    def _set_elf_size_data(self, size_arr):
170        order_section_keys = [".text", ".data", ".bss", ".reboot_retention"]
171        order_elf_size_data = dict()
172        for key in order_section_keys:
173            order_elf_size_data[key] = {'addr': None, 'size': None}
174
175        for item in size_arr:
176            elf_key, elf_size, elf_addr = re.sub(r'\s+', ' ', item).split(' ')[:3]
177            if elf_key.startswith('.') and (elf_size != '0' or elf_addr != '0'):
178                order_elf_size_data[elf_key] = {'addr': int(elf_addr), 'size': int(elf_size)}
179                if elf_key not in order_section_keys:
180                    order_section_keys.append(elf_key)
181        self._section_keys = list()
182        for k, v in order_elf_size_data.items():
183            if v.get("size", None) is None:
184                continue
185            if k in self._image_remove_section:
186                continue
187            self.elf_size_data[k] = v
188            self._section_keys.append(k)
189
190    def _read_file(self):
191        try:
192            self._read_file_to_arr()
193            json_obj = self._parse_elf_file(self._elf_path)
194            return json_obj
195        except Exception as e:
196            print('elf parse error')
197            raise Exception() from e
198
199    def _parse_elf_file(self, elf_path):
200        suffix = self._prefix + '-objdump.exe'
201        if self._environment == 'linux':
202            suffix = self._prefix + '-objdump'
203        obj_dump_path = join(self._compiler_path, suffix)
204        if not obj_dump_path or not exists(obj_dump_path):
205            print('Please configure the correct compiler type and compiler path')
206            raise FileExistsError()
207        try:
208            data = CommonUtils.get_obj_dump_info(obj_dump_path, '-h', elf_path)
209            self._set_section(data)
210            json_obj = self._get_symbol_data(obj_dump_path, elf_path)
211            return json_obj
212        except SystemError as e:
213            print('elf parse error')
214            raise SystemError() from e
215
216    def _set_section(self, data):
217        for key, value in enumerate(data):
218            line = re.sub(r'\s+', ' ', value)
219            if re.search(elf_setion_rule, line):
220                data_arr = line.split(' ')
221                if len(data_arr) > 2 and data_arr[2] in self._image_remove_section:
222                    continue
223                next_line = ''
224                if self._prefix != 'llvm' and key < len(data) - 1:
225                    next_line = data[key + 1]
226                self._set_section_data(data_arr, next_line)
227
228    def _set_section_data(self, data_arr, next_line):
229        size = int('0x' + data_arr[3], 16)
230        vma = int('0x' + data_arr[4], 16)
231        if vma > 0 or size != 0:
232            lma = 0
233            if next_line:
234                lma = 0 if next_line.find('LOAD') < 0 else int('0x' + data_arr[5], 16)
235            elif data_arr[5]:
236                lma = int('0x' + data_arr[5], 16)
237            region_name = []
238            for region_item in self.region_data:
239                start_addr = int(region_item['startAddr'], 16)
240                end_addr = int(region_item['endAddr'], 16)
241                if (start_addr <= vma < end_addr) or (lma != 0 and start_addr <= lma < end_addr):
242                    region_name.append(region_item['name'])
243                    region_item['used'] += size
244            section = {
245                'regionName': region_name,
246                'runAddr': '0x' + data_arr[4],
247                'loadAddr': '0x' + data_arr[5] if lma else '',
248                'size': self._addr_to_size('0x' + data_arr[3]),
249                'sizeOri': '0x' + data_arr[3],
250                'children': []
251            }
252            self.section_data[data_arr[2]] = section
253
254    def _get_symbol_data(self, obj_dump_path, elf_path):
255        try:
256            data = CommonUtils.get_obj_dump_info(obj_dump_path, '-t', elf_path)
257            for item in data:
258                line = re.sub(r'\s+', ' ', item)
259                if re.search(elf_symbol_rule, line):
260                    self._set_section_symbol_data(line)
261        except SystemError as e:
262            print('data parse error')
263            raise SystemError() from e
264
265        for region in self.region_data:
266            used = self._addr_to_size(hex(region['used']))
267            try:
268                usage = region['used'] / region['size']
269                region['usage'] = '%.2f' % (usage * 100) + '%'
270            except ZeroDivisionError:
271                region['usage'] = '0.00%'
272            region['free'] = self._addr_to_size(hex(region['size'] - region['used']))
273            region['used'] = used
274            region['size'] = self._addr_to_size(hex(region['size']))
275        json_obj = {
276            'region': self.region_data,
277            'details': self.section_data,
278            'sizeData': self.size_data,
279            'moduleData': self.module_data,
280            'folderData': self.folder_data
281        }
282        return json_obj
283
284    def _set_section_symbol_data(self, line):
285        data_arr = line.split(' ')
286        section_name = data_arr[3]
287        symbol_name = data_arr[-2]
288        type_name = data_arr[2]
289        if len(data_arr[-1]) != 0:
290            symbol_name = data_arr[-1]
291        if section_name != symbol_name and section_name in self.section_data:
292            section = self.section_data[section_name]
293            vma = int('0x' + data_arr[0], 16)
294            lma = 0
295            if section['loadAddr']:
296                lma = int(section['loadAddr'], 16) - int(section['runAddr'], 16) + vma
297            symbol = {
298                'name': symbol_name,
299                'runAddr': '0x' + data_arr[0],
300                'loadAddr': hex(lma) if lma else '',
301                'size': self._addr_to_size('0x' + data_arr[4]),
302                'sizeOri': '0x' + data_arr[4],
303                'location': '',
304                'type': type_name
305            }
306            self.section_data[section_name]['children'].append(symbol)
307
308    @staticmethod
309    def _addr_to_size(addr):
310        size = int(addr, 16)
311        if size < 1024:
312            return f'{size} B'
313        else:
314            return '%.2f' % (size / 1024) + 'KB'
315
316    @staticmethod
317    def get_file_size(file_size_path, arg, elf_file_path):
318        cmd = [file_size_path, arg, elf_file_path]
319        data = CommonUtils.exec_cmd(cmd)
320        return data.strip().split('\n')
321
322    def _read_file_to_arr(self):
323        is_start = False
324        is_end = False
325        with open(self._map_path, 'r') as f:
326            line = f.readline()
327            while line:
328                line = line.strip()
329                if line == map_file_size_end:
330                    break
331                if re.match(map_start_rule, line):
332                    is_start = True
333                elif re.match(map_end_rule, line):
334                    is_end = True
335                elif is_start and not is_end:
336                    self._set_region_data(line)
337                elif is_end:
338                    self._parse_size_data(line)
339                line = f.readline()
340
341    def _set_region_data(self, line):
342        if len(line) > 0 and not line.startswith('Name') and not line.startswith('*default*'):
343            line_arr = re.sub(r'\s+', ' ', line).split(' ')
344            end_addr = '0x%08x' % (int(line_arr[1], 16) + int(line_arr[2], 16))
345            if len(line_arr) >= 3:
346                region = {
347                    'name': line_arr[0],
348                    'startAddr': line_arr[1],
349                    'endAddr': end_addr,
350                    'size': int(line_arr[2], 16),
351                    'sizeOri': line_arr[2],
352                    'used': 0,
353                    'usage': 0
354                }
355                self.region_data.append(region)
356                name_sp = line_arr[0].split("_")
357                if 'FLASH' in name_sp or "ROM" in name_sp:
358                    self.rom_parts[line_arr[0]] = {'start': int(region['startAddr'], 16),
359                                                   'end': int(region['endAddr'], 16)}
360
361    def _parse_size_data(self, line):
362        is_need_parse = False
363        file_size_content_end_rule = re.compile(r'0x[0-9a-fA-F]{8,16}\s+0x[0-9a-fA-F]{1,16}\s+')
364        file_size_symbol_rule = re.compile(r'^(\s*0x[0-9a-fA-F]{8,16})\s*\w+')
365        file_rule = re.compile(r'^(\s+\*fill\*)\s+0x[0-9a-fA-F]{8,16}\s+0x[0-9a-fA-F]{1,16}')
366        is_content_rule = len(line) > 0 and re.search(file_size_content_rule, line) is not None
367        is_end_rule = line.find('.o') > 0 and re.search(file_size_content_end_rule, line) is not None
368        if is_content_rule and is_end_rule:
369            is_need_parse = True
370        elif is_content_rule:
371            self.last_line = line
372            is_need_parse = False
373        elif len(line) > 0 and is_end_rule:
374            line = self.last_line + ' ' + line
375            self.last_line = ''
376            is_need_parse = True
377        elif re.search(file_rule, line) is not None:
378            self.last_line = ''
379            is_need_parse = True
380        else:
381            self.last_line = ''
382        if is_need_parse:
383            if self.is_unknown and len(self.last_symbol) > 1 and self.last_symbol[0]['addr'] in self.size_data:
384                self._reset_symbol_size_data()
385            self.is_unknown = False
386            line = line.strip()
387            line_arr = re.sub(r'\s+', ' ', line).split(' ')
388            for rv_s in self._image_remove_section:
389                if line_arr[0].startswith(rv_s):
390                    return
391            addr = line_arr[1]
392            self._get_cur_section(addr)
393            if self.cur_section:
394                self._calculate_size_data(line_arr, addr)
395        elif self.is_unknown and re.search(file_size_symbol_rule, line):
396            line_arr = re.sub(r'\s+', ' ', line).split(' ')
397            addr = line_arr[0]
398            name = line_arr[1]
399            if len(self.last_symbol) == 1 and self.last_symbol[0]['addr'] != addr:
400                self.is_unknown = False
401                self.last_symbol = []
402            else:
403                self.last_symbol.append({
404                    'addr': addr,
405                    'name': name
406                })
407
408    def _calculate_size_data(self, line_arr, addr):
409        cur_size = int(line_arr[2], 16)
410        # .o或者.obj文件路径相对路径,包含括号里,可能没有.a文件一定有.o/.obj文件
411        # 如 ../../../../interim_binary/brandy/libs/media/evb_standard/libaudio_player.a(liteplayer.cpp.obj)
412        nor_path = normpath(line_arr[3])
413        a_file_index = nor_path.find('.a(')
414        if nor_path and a_file_index > 0:
415            a_file_path = nor_path[0: a_file_index + 2]
416            a_file_dir = os.path.dirname(a_file_path)
417            a_file_name = os.path.basename(a_file_path)
418            o_file_name = nor_path[a_file_index + 3: len(nor_path) - 1]
419            o_file_dir = a_file_path
420            # 统计.a文件大小
421            param_size = dict(name=a_file_name,
422                              parent='',
423                              path=a_file_dir,
424                              obj_name=o_file_name,
425                              lib_name=a_file_name,
426                              cur_size=cur_size)
427            self._set_size_data(param_size)
428            # 统计.o/.obj文件大小
429            param_size = dict(name=o_file_name,
430                              parent=a_file_name,
431                              path=o_file_dir,
432                              obj_name=o_file_name,
433                              lib_name=a_file_name,
434                              cur_size=cur_size)
435            self._set_size_data(param_size)
436
437        else:
438            o_file_name = os.path.basename(nor_path)
439            o_file_dir = os.path.dirname(nor_path)
440            param_size = dict(name=o_file_name, parent='', path=o_file_dir,
441                              obj_name=o_file_name, lib_name='', cur_size=cur_size)
442            self._set_size_data(param_size)
443
444        # 函数
445        child = line_arr[0] + ':' + addr
446        self._set_addr_data(addr)
447        if cur_size != 0:
448            param_size.update({'name': child, 'parent': o_file_name, 'path': ''})
449            self._set_size_data(param_size, True)
450
451    def _set_addr_data(self, addr):
452        if addr in self.size_data:
453            old_size = self.size_data[addr][self.cur_section_size]
454            old_lib = self.size_data[addr]['lib']
455            old_parent = self.size_data[addr]['parent']
456            old_module_name = self.size_data[addr]['moduleName']
457            old_component_name = self.size_data[addr]['componentName']
458            if old_lib in self.size_data:
459                self.size_data[old_lib][self.cur_section_size] = self.size_data[
460                                                                     old_lib][self.cur_section_size] - old_size
461
462            if old_parent in self.size_data:
463                self.size_data[old_parent][self.cur_section_size] = self.size_data[
464                                                                        old_parent][self.cur_section_size] - old_size
465                self._set_old_parent_size(old_parent, old_size)
466
467            if old_module_name in self.module_data:
468                self.module_data[old_module_name][self.cur_section_size] = self.module_data[
469                                                                               old_module_name][
470                                                                               self.cur_section_size] - old_size
471
472            if old_component_name in self.module_data:
473                self.module_data[old_component_name][self.cur_section_size] = self.module_data[
474                                                                                  old_component_name][
475                                                                                  self.cur_section_size] - old_size
476
477    def _set_old_parent_size(self, cur_parent, cur_size):
478        if self.size_data[cur_parent]['parent'] == '' and 'path' in self.size_data[cur_parent]:
479            path_list = self.size_data[cur_parent]['path'].split(sep)
480            temp_folder = self.folder_data
481            for path in path_list:
482                if path in temp_folder and self.cur_section_size in temp_folder[path]:
483                    temp_folder[path][self.cur_section_size] = temp_folder[path][self.cur_section_size] - cur_size
484                temp_folder = temp_folder[path]
485
486    def _set_size_data(self, param_size, is_symbol=False):
487        # .a/.o/.obj文件的索引字符串:全路径
488        name = param_size.get('name')
489        # .o/.obj是否有父节点.a文件
490        parent = param_size.get('parent')
491        # .o/.obj文件名称
492        obj_name = param_size.get('obj_name')
493        # .a文件名称
494        lib_name = param_size.get('lib_name')
495        # .o/.obj文件大小
496        cur_size = param_size.get('cur_size')
497        # .a/.o/.obj文件的目录
498        file_dir = param_size.get('path')
499        if name in self.size_data and not is_symbol:
500            if not self.size_data[name][self.cur_section_size]:
501                self.size_data[name][self.cur_section_size] = cur_size
502            else:
503                self.size_data[name][self.cur_section_size] = self.size_data[name][self.cur_section_size] + cur_size
504        elif name:
505            symbol_name = name.split(':')[0]
506            name = symbol_name
507            self.size_data[name] = {
508                'objName': symbol_name,
509                'parent': parent,
510                'path': file_dir,
511                'romSize': 0,
512                'moduleName': self._get_module_name(obj_name),
513                'componentName': self._get_component_name(lib_name)
514            }
515            if is_symbol:
516                self.size_data[name]['isSymbol'] = True
517                self.size_data[name]['lib'] = lib_name
518                self._set_module_data(self.size_data[name]['moduleName'], self.size_data[name]['componentName'],
519                                      cur_size)
520                self._set_module_data(self.size_data[name]['componentName'], '', cur_size)
521                if self.size_data[name]['moduleName'] == '' and self.size_data[name]['componentName']:
522                    self.size_data[name]['moduleName'] = self.size_data[name]['componentName']
523            for item in self._section_keys:
524                self.size_data[name][item] = 0
525            self.size_data[name][self.cur_section_size] = cur_size
526        if self.is_rom and name:
527            self.size_data[name]['romSize'] = self.size_data[name]['romSize'] + cur_size
528
529        if file_dir and not isabs(file_dir):
530            self._set_folder_data(file_dir, name, cur_size, obj_name)
531
532    def _set_folder_data(self, cur_path, cur_name, cur_size, child_name):
533        """
534        Split paths and assemble them into dict
535        Example: "build/libs/main.o" assemble to {"build":{"child":[], "size":1, "libs"{"child":[main.o], "size":1}}}
536        """
537        path_list = cur_path.split(sep)
538        temp_folder = self.folder_data
539
540        for path in path_list:
541            self._set_child_size(path, temp_folder, cur_size, [])
542            temp_folder = temp_folder[path]
543
544        if cur_name not in temp_folder['child']:
545            if cur_name != child_name:
546                self._set_child_size(cur_name, temp_folder, cur_size, [child_name])
547                if cur_name in temp_folder and child_name not in temp_folder[cur_name]['child']:
548                    temp_folder[cur_name]['child'].append(child_name)
549            else:
550                temp_folder['child'].append(cur_name)
551
552    def _set_child_size(self, cur, folder, size, child_list):
553        if cur not in folder:
554            folder[cur] = {"child": child_list}
555            for item in self._section_keys:
556                folder[cur][item] = 0
557            folder[cur][self.cur_section_size] = size
558        else:
559            if self.cur_section_size in folder[cur]:
560                folder[cur][self.cur_section_size] = folder[cur][self.cur_section_size] + size
561            else:
562                folder[cur][self.cur_section_size] = size
563
564    def _set_module_data(self, name, parent, cur_size):
565        if name == '':
566            return
567        if name in self.module_data:
568            if not self.module_data[name][self.cur_section_size]:
569                self.module_data[name][self.cur_section_size] = cur_size
570            else:
571                self.module_data[name][self.cur_section_size] = self.module_data[name][self.cur_section_size] + cur_size
572        elif name:
573            self.module_data[name] = {
574                'objName': name,
575                'parent': parent,
576                'romSize': 0
577            }
578            for item in self._section_keys:
579                self.module_data[name][item] = 0
580            self.module_data[name][self.cur_section_size] = cur_size
581        if self.is_rom and name:
582            self.module_data[name]['romSize'] = self.module_data[name]['romSize'] + cur_size
583
584    def _get_module_name(self, obj_name):
585        if obj_name in self._module_config and type(self._module_config[obj_name]) == str:
586            return self._module_config[obj_name]
587        else:
588            return obj_name
589
590    def _get_component_name(self, lib_name):
591        if lib_name in self._module_config and type(self._module_config[lib_name]) == str:
592            return self._module_config[lib_name]
593        else:
594            return lib_name
595
596    def _get_cur_section(self, addr):
597        self.cur_section = ''
598        self.cur_section_size = ''
599
600        for section_key in self.elf_size_data:
601            section_size = self.elf_size_data[section_key]['size']
602            section_addr = self.elf_size_data[section_key]['addr']
603            if section_addr <= int(addr, 16) < section_addr + section_size:
604                self.cur_section = section_key
605                self.cur_section_size = self.cur_section
606                break
607
608        self.is_rom = False
609        if self.cur_section in ('.text', '.rodata', '.data', '.l2m_gpu_text', '.plt_ramtext'):
610            self.is_rom = True
611        else:
612            for rom_part, part_size in self.rom_parts.items():
613                if part_size['start'] <= int(addr, 16) < part_size['end']:
614                    self.is_rom = True
615                    break
616
617    def _reset_symbol_size_data(self):
618        length = len(self.last_symbol)
619        tmp_parent = self.last_symbol[0]['addr']
620        all_size = int(self.size_data[tmp_parent][self.cur_section_size])
621
622        for key, val in enumerate(self.last_symbol):
623            if key != 0:
624                tmp = val['addr']
625                size = 0
626                if key == length - 1:
627                    size = all_size
628                else:
629                    size = int(self.last_symbol[key + 1]['addr'], 16) - int(self.last_symbol[key]['addr'], 16)
630                    all_size = all_size - size
631                tmp_size = {
632                    'objName': self.last_symbol[key]['name'],
633                    'parent': self.size_data[tmp_parent]['parent'],
634                    'isSymbol': True,
635                    'lib': self.size_data[tmp_parent]['lib'],
636                    'moduleName': self.size_data[tmp_parent]['moduleName'],
637                    'componentName': self.size_data[tmp_parent]['componentName']
638                }
639                for item in self._section_keys:
640                    tmp_size[item] = 0
641                self.size_data[tmp] = tmp_size
642                self.size_data[tmp][self.cur_section_size] = size
643
644
645if __name__ == '__main__':
646    env = TargetEnvironment(sys.argv[1])
647    chip = env.get('chip')
648    core = env.get('core')
649    bin_name = env.get('bin_name')
650    hso_xlm_chip_name = env.get('hso_xml_chip')
651
652    ELF_PATH = os.path.join(output_root, chip, core, sys.argv[1], bin_name + ".elf")
653    MAP_PATH = os.path.join(output_root, chip, core, sys.argv[1], bin_name + ".map")
654    RESULT_SAVE_PATH = os.path.join(output_root, chip, core, sys.argv[1], "image_analysis_result.html")
655    COMPILER_PATH = sys.argv[2]
656    # for debug
657    # COMPILER_PATH = os.path.join(root_dir, "tools", "bin", "compiler", "linx", "linx_170", "linx-llvm-binary-debug",
658    #                              "linx-llvm-binary-release-musl", "bin", "riscv32")
659
660    if hso_xlm_chip_name != None: # just for melody
661        chip = hso_xlm_chip_name
662    BUILD_CONFIG_PATH = os.path.join(root_dir, 'build', 'config', 'target_config', chip, 'image_analysis_cfg', 'module.json')
663    REMOVE_SECTIONS_CONFIG_PATH = os.path.join(root_dir, 'build', 'config', 'target_config', chip, 'image_analysis_cfg', "remove_sections.txt")
664
665    PAHT_DICT = {"elf_path": ELF_PATH,
666                 "map_path": MAP_PATH,
667                 "compiler_path": COMPILER_PATH,
668                 "build_config_path": BUILD_CONFIG_PATH,
669                 "remove_sections_config_path": REMOVE_SECTIONS_CONFIG_PATH,
670                 "result_save_path": RESULT_SAVE_PATH,
671                 }
672
673    IMAGE_ANALYSE_RUN = BuildDataAnalyzer(PAHT_DICT)
674    IMAGE_ANALYSE_RUN.do_build_analysis(PAHT_DICT)
675
676    print('Image Analyse Done ^_^')