Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/ut/utils/msobjdump/msobjdump/msobjdump_main.py: 79%
560 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-27 14:38 +0800
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-27 14:38 +0800
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3# ----------------------------------------------------------------------------------------------------------
4# Copyright (c) 2025 Huawei Technologies Co., Ltd.
5# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6# CANN Open Software License Agreement Version 2.0 (the "License").
7# Please refer to the License for details. You may not use this file except in compliance with the License.
8# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10# See LICENSE in the root of the software repository for the full text of the License.
11# ----------------------------------------------------------------------------------------------------------
13import os
14import re
15import sys
16import time
17import mmap
18import json
19import struct
20import shutil
21import argparse
22from enum import Enum
23from typing import List
24from dataclasses import dataclass, field
26from msobjdump import utils
29KEY_ASCEND_META = '.ascend.meta.'
30KEY_ASCEND_META_OP = '.ascend.meta'
31KEY_ASCEND_KERNEL = '.ascend.kernel.'
32KEY_AICORE_BINARY = '.aicore_binary'
33KEY_O_JSON = '_binary_'
34KEY_A_FILE = '.a'
35KEY_O_FILE = '.cpp.o'
36HEX_NUM = 16
37############### _o_json define ####################
38TYPE_START = 'start'
39TYPE_END = 'end'
40TYPE_SIZE = 'size'
41ACLNN_BINARY = ''
43############### ascend kernel define ####################
44KERNEL_TYPE_MAP = {'0': 'mix', '1': 'aiv', '2': 'aic'}
46############### Function Meta Type ####################
47F_TYPE_KTYPE = 1
48F_TYPE_CROSS_CORE_SYNC = 2
49F_TYPE_MIX_TASK_RATION = 3
50F_TYPE_ENABLE_EARLY_START = 11
51F_TYPE_DETERMINISTIC_INFO = 13
52F_TYPE_FUNCTION_ENTRY = 14
53F_TYPE_BLOCK_NUM = 15
55F_TYPE_MAP = {
56 F_TYPE_KTYPE: "KERNEL_TYPE",
57 F_TYPE_CROSS_CORE_SYNC: "CROSS_CORE_SYNC",
58 F_TYPE_MIX_TASK_RATION: "MIX_TASK_RATION",
59 F_TYPE_ENABLE_EARLY_START: "ENABLE_EARLY_START",
60 F_TYPE_DETERMINISTIC_INFO: "DETERMINISTIC_INFO",
61 F_TYPE_FUNCTION_ENTRY: "FUNCTION_ENTRY",
62 F_TYPE_BLOCK_NUM: "BLOCK_NUM"
63}
65############### Binary Meta Type ####################
66B_TYPE_VERSION = 0
67B_TYPE_DEBUG = 1
68B_TYPE_DYNAMIC_PARAM = 2
69B_TYPE_OPTIONAL_PARAM = 3
70B_TYPE_RUNTIME_IMPLICIT_INFO = 4
72B_TYPE_MAP = {
73 B_TYPE_VERSION: "VERSION",
74 B_TYPE_DEBUG: "DEBUG",
75 B_TYPE_DYNAMIC_PARAM: "DYNAMIC_PARAM",
76 B_TYPE_OPTIONAL_PARAM: "OPTIONAL_PARAM",
77 B_TYPE_RUNTIME_IMPLICIT_INFO: "RUNTIME_IMPLICIT_INFO"
78}
80K_TYPE_MAP = {
81 "1": "AICORE",
82 "2": "AIC",
83 "3": "AIV",
84 "4": "MIX_AIC_MAIN",
85 "5": "MIX_AIV_MAIN",
86 "6": "AIC_ROLLBACK",
87 "7": "AIV_ROLLBACK"
88}
89C_TYPE_MAP = {"0":"NO_USE_SYNC", "1": "USE_SYNC"}
90RUNTIME_IMPLICIT_INFO_MAP = {
91 1: "SIMD Printf Flag",
92 2: "Hardware Sync Flag",
93 3: "L2Cache Hint Flag",
94 4: "SIMT Printf Flag",
95 5: "SIMD Assert Flag"
96}
99class ObjType(Enum):
100 TYPE_ASCEND_KERNEL = 0
101 TYPE_BINARY_O_JSON = 1
102 TYPE_ASCEND_META = 2
103 TYPE_AICORE_BINARY = 3
106class ParseObjMode(Enum):
107 MODE_DUMP_ELF = 0
108 MODE_EXTRA_ELF = 1
109 MODE_LIST_ELF = 2
110 MODE_VERBOSE = 3
113@dataclass
114class AscendKernel:
115 kernel_type: str
116 kernel_len: int
117 kernel_file: str
120@dataclass
121class AscendKernelInfos:
122 version: str
123 type_cnt: int
124 kernels: List[AscendKernel] = field(default_factory=list)
127class ObjDump:
128 '''
129 objdump tool manager
130 ====================
131 支持简易工程打包交付件、aclnn打包交付件、单算子编译交付件的解压解析
132 ====================
133 '''
134 def __init__(self, args):
135 self.obj = None # 待解析解压文件
136 self.src_obj = None # 用户原始输入文件
137 self.parse_obj_mode = None # ParseObjMode 解析解压类型
138 self.obj_type = None # ObjType obj文件场景分类
139 self.tmp_dir = None # 存放临时文件 结束后目录会删除
140 self.out_dir = args.out_dir # 落盘文件目录,用户未设置时当前路径
141 self._aicore_binary_meta_printed = set()
142 self._set_out_dir()
143 # preprocess args
144 self._set_parse_obj_and_mode(args)
146 @staticmethod
147 def _show_ascend_meta_tlv(content: bytes, t: int, l: int, index: int):
148 if t == F_TYPE_MIX_TASK_RATION:
149 v1, v2 = struct.unpack("2H", content[index:index + 4])
150 print(f"{F_TYPE_MAP.get(t)}: [{v1}:{v2}]")
151 elif t == F_TYPE_CROSS_CORE_SYNC:
152 v, = struct.unpack("I", content[index:index + 4])
153 print(f"{F_TYPE_MAP.get(t)}: {C_TYPE_MAP.get(str(v))}")
154 elif t == F_TYPE_KTYPE:
155 v, = struct.unpack("I", content[index:index + 4])
156 print(f"{F_TYPE_MAP.get(t)}: {K_TYPE_MAP.get(str(v))}")
157 elif t == F_TYPE_DETERMINISTIC_INFO:
158 v, = struct.unpack("I", content[index:index + 4])
159 print(f"{F_TYPE_MAP.get(t)}: {v}")
160 elif t == F_TYPE_ENABLE_EARLY_START:
161 v, = struct.unpack("I", content[index:index + 4])
162 print(f"{F_TYPE_MAP.get(t)}: {v}")
163 elif t == F_TYPE_FUNCTION_ENTRY:
164 v, = struct.unpack("<Q", content[index + 4:index + 12])
165 print(f"{F_TYPE_MAP.get(t)}: {v}")
166 elif t == F_TYPE_BLOCK_NUM:
167 v = "0xFFFFFFFF"
168 print(f"{F_TYPE_MAP.get(t)}: {v}")
170 @staticmethod
171 def _unpack_buff_content_by_type(content: bytes, start_idx: int, read_len: int, type_str: str) -> int:
172 error_message = "[ERROR]: Parse ascend kernel content failed with out of bound."
173 end_idx = start_idx + read_len
174 if start_idx < 0 or read_len < 0 or end_idx > len(content):
175 raise RuntimeError(error_message)
176 try:
177 return struct.unpack(type_str, content[start_idx : end_idx])[0]
178 except struct.error as error:
179 raise RuntimeError(error_message) from error
181 def run(self):
182 self._parse_process()
183 self._clean()
184 return
186 def _show_ascend_meta_op_tlv(self, content: bytes, t: int, l: int, index: int):
187 if t == B_TYPE_VERSION:
188 v, = struct.unpack("I", content[index:index + 4])
189 output = f"{B_TYPE_MAP.get(t)}: {v}"
190 self._print_ascend_meta_op_tlv(output)
191 if t == B_TYPE_DEBUG:
192 debugBufSize, debugOptions = struct.unpack("II", content[index:index + 8])
193 output = f"{B_TYPE_MAP.get(t)}: debugBufSize={debugBufSize}, debugOptions={debugOptions}"
194 self._print_ascend_meta_op_tlv(output)
195 elif t == B_TYPE_DYNAMIC_PARAM:
196 dynamicParamMode, = struct.unpack("H", content[index + 2:index + 4])
197 output = f"{B_TYPE_MAP.get(t)}: dynamicParamMode={dynamicParamMode}"
198 self._print_ascend_meta_op_tlv(output)
199 elif t == B_TYPE_OPTIONAL_PARAM:
200 optionalInputMode, optionalOutputMode = struct.unpack("HH", content[index:index + 4])
201 output = (
202 f"{B_TYPE_MAP.get(t)}: optionalInputMode={optionalInputMode}, "
203 f"optionalOutputMode={optionalOutputMode}"
204 )
205 self._print_ascend_meta_op_tlv(output)
206 elif t == B_TYPE_RUNTIME_IMPLICIT_INFO:
207 v, = struct.unpack("I", content[index:index + 4])
208 output = f"{B_TYPE_MAP.get(t)}: {RUNTIME_IMPLICIT_INFO_MAP.get(v, v)}"
209 self._print_ascend_meta_op_tlv(output)
211 def _print_ascend_meta_op_tlv(self, output: str):
212 if self.obj_type == ObjType.TYPE_AICORE_BINARY:
213 if output in self._aicore_binary_meta_printed:
214 return
215 self._aicore_binary_meta_printed.add(output)
216 print(output)
218 def _set_out_dir(self):
219 if not self.out_dir:
220 self.out_dir = os.getcwd()
221 self.out_dir = os.path.realpath(self.out_dir)
222 if not os.path.isdir(self.out_dir):
223 raise RuntimeError(f'[ERROR]: output dir {(self.out_dir)} is invalid path!')
224 self.tmp_dir = os.path.join(self.out_dir, 'objdump_' + time.strftime("%Y%m%d_%H%M%S") + "_" + str(os.getpid()))
225 try:
226 os.mkdir(self.tmp_dir)
227 except PermissionError as e:
228 raise PermissionError(
229 f"[ERROR]: Cannot create {self.tmp_dir} for saving tmp file, please check user permission.") from e
231 def _set_parse_obj_and_mode(self, args):
232 #args check
233 try:
234 if (args.dump_elf or args.extr_elf or args.list_elf) is None:
235 raise RuntimeError(f'[ERROR]: File does not exist or permission denied!!!')
236 except RuntimeError as e:
237 print(f'[ERROR]: command check error, please check !!!')
238 return
240 if args.dump_elf:
241 if args.verbose:
242 self.parse_obj_mode = ParseObjMode.MODE_VERBOSE
243 self.obj = args.dump_elf
244 else:
245 self.obj = args.dump_elf
246 self.parse_obj_mode = ParseObjMode.MODE_DUMP_ELF
247 elif args.extr_elf:
248 self.obj = args.extr_elf
249 self.parse_obj_mode = ParseObjMode.MODE_EXTRA_ELF
250 elif args.list_elf:
251 self.obj = args.list_elf
252 self.parse_obj_mode = ParseObjMode.MODE_LIST_ELF
254 self.src_obj = self.obj
255 self._detect_obj_type()
256 if self.obj_type is not None and self.obj_type != ObjType.TYPE_AICORE_BINARY:
257 return
259 if self.obj_type == ObjType.TYPE_AICORE_BINARY:
260 self.obj = self._extract_aicore_binary()
262 def _detect_obj_type(self):
263 self.obj_type = None
264 output = utils.get_symbols_in_file(self.obj)
266 if "_o_start" in output or "_json_start" in output:
267 self.obj_type = ObjType.TYPE_BINARY_O_JSON
268 output = utils.get_section_headers_in_file(self.obj)
270 if KEY_ASCEND_META in output:
271 self.obj_type = ObjType.TYPE_ASCEND_META
272 if KEY_ASCEND_KERNEL in output:
273 self.obj_type = ObjType.TYPE_ASCEND_KERNEL
274 if KEY_AICORE_BINARY in output:
275 self.obj_type = ObjType.TYPE_AICORE_BINARY
277 def _extract_aicore_binary(self) -> str:
278 src_obj = getattr(self, 'src_obj', None)
279 src_name = os.path.basename(src_obj) if src_obj else 'fusion_aicore_binary'
280 tmp_file = os.path.join(self.tmp_dir, f'{src_name}.aicore.o')
281 if os.path.exists(tmp_file):
282 os.remove(tmp_file)
283 try:
284 result = utils.extract_aicore_binary_from_elf(self.obj, tmp_file)
285 except FileNotFoundError as e:
286 raise RuntimeError('[ERROR]: llvm-objcopy is not available, cannot extract .aicore_binary.') from e
288 if result.returncode != 0:
289 err_msg = result.stderr.strip() if result.stderr else 'unknown error'
290 raise RuntimeError(f'[ERROR]: Extract .aicore_binary failed: {err_msg}')
292 if not os.path.exists(tmp_file) or os.path.getsize(tmp_file) == 0:
293 raise RuntimeError('[ERROR]: Extracted .aicore_binary file is empty or missing.')
294 return tmp_file
296 def _parse_process(self):
297 if self.parse_obj_mode == ParseObjMode.MODE_DUMP_ELF or self.parse_obj_mode == ParseObjMode.MODE_VERBOSE:
298 self._dump_elf_process()
299 elif self.parse_obj_mode == ParseObjMode.MODE_EXTRA_ELF:
300 self._extra_elf()
301 elif self.parse_obj_mode == ParseObjMode.MODE_LIST_ELF:
302 self._list_elf()
304 def _clean(self):
305 if os.path.exists(self.tmp_dir):
306 shutil.rmtree(self.tmp_dir)
308 def _dump_elf_process(self):
309 if self.obj_type == ObjType.TYPE_BINARY_O_JSON:
310 point_content_list = self._parse_binary_o_json_obj()
311 save_files = self._save_dump_elf_o_json(point_content_list)
312 for file_name in save_files:
313 if file_name.endswith('.o'):
314 self.obj = save_files[file_name]
315 self._show_elf_ascend_meta_obj()
316 if self.parse_obj_mode == ParseObjMode.MODE_VERBOSE:
317 self._show_binary_o_json_obj(save_files)
318 elif self.obj_type == ObjType.TYPE_ASCEND_KERNEL:
319 ascend_kernel_dict = self._parse_ascend_kernel_infos()
320 kernel_obj_infos = self._parse_elf_ascend_kernel_by_type(ascend_kernel_dict, 'dump')
321 self._show_elf_ascend_kernel_obj(kernel_obj_infos)
322 elif self.obj_type == ObjType.TYPE_ASCEND_META:
323 self._show_elf_ascend_meta_obj()
324 elif self.obj_type == ObjType.TYPE_AICORE_BINARY:
325 self._show_elf_ascend_meta_obj()
326 if self.parse_obj_mode == ParseObjMode.MODE_VERBOSE:
327 print(f'====== [elf header infos] ======')
328 print(utils.get_all_section_symbols_in_file(self.obj))
329 else:
330 print(f'The kernel meta information cannot be found.')
332 def _extra_elf(self):
333 if self.obj_type == ObjType.TYPE_BINARY_O_JSON:
334 point_content_list = self._parse_binary_o_json_obj()
335 save_files = self._save_dump_elf_o_json(point_content_list)
336 self._move_file_to_outdir_o_json(save_files)
337 elif self.obj_type == ObjType.TYPE_ASCEND_KERNEL:
338 ascend_kernel_dict = self._parse_ascend_kernel_infos()
339 kernel_obj_infos = self._parse_elf_ascend_kernel_by_type(ascend_kernel_dict, 'dump')
340 self._move_file_to_outdir_ascend_kernel(kernel_obj_infos)
341 elif self.obj_type == ObjType.TYPE_ASCEND_META:
342 print('[WARNING]: nothing to extra in single op elf file')
343 elif self.obj_type == ObjType.TYPE_AICORE_BINARY:
344 self._move_extracted_aicore_binary_to_outdir()
346 def _list_elf(self):
347 if self.obj_type == ObjType.TYPE_BINARY_O_JSON:
348 point_content_list = self._parse_binary_o_json_obj()
349 self._list_elf_info_aclnn_pkg_obj(point_content_list)
350 elif self.obj_type == ObjType.TYPE_ASCEND_KERNEL:
351 ascend_kernel_dict = self._parse_ascend_kernel_infos()
352 self._parse_elf_ascend_kernel_by_type(ascend_kernel_dict, 'list')
353 elif self.obj_type == ObjType.TYPE_ASCEND_META:
354 print('[WARNING]: nothing to list in single op elf file')
355 elif self.obj_type == ObjType.TYPE_AICORE_BINARY:
356 self._list_extracted_aicore_binary()
358 def _list_extracted_aicore_binary(self):
359 print(f'ELF file 0: {os.path.basename(self.obj)}')
361 def _move_extracted_aicore_binary_to_outdir(self):
362 utils.copy_file_src_exist(self.obj, os.path.join(self.out_dir, os.path.basename(self.obj)))
364 def _copy_file_o_json_to_out_dir(self, src_file: str, json_file: str, copy_files: list):
365 utils.copy_file_src_exist(src_file, os.path.join(self.out_dir, json_file))
366 copy_files.append(src_file)
367 tmp_o_file = src_file.replace('.json', '.o')
368 o_file = json_file.replace('.json', '.o')
369 if os.path.exists(tmp_o_file):
370 utils.copy_file_src_exist(tmp_o_file, os.path.join(self.out_dir, o_file))
371 copy_files.append(tmp_o_file)
373 def _copy_file_with_file_name_manual(self, base_name: str, tmp_file: str, copy_files: list):
374 new_file_name = self._get_file_name_with_path(base_name)
375 if new_file_name != base_name:
376 self._copy_file_o_json_to_out_dir(tmp_file, new_file_name, copy_files)
378 def _move_file_to_outdir_o_json(self, tmp_files: dict):
379 copy_files = []
380 for base_name, tmp_file in tmp_files.items():
381 if not base_name.endswith('.json'):
382 continue
383 with open(tmp_file, 'r') as f:
384 op_json = json.load(f)
386 if op_json.get('filePath', None):
387 file_json = op_json['filePath']
388 self._copy_file_o_json_to_out_dir(tmp_file, file_json, copy_files)
389 else:
390 self._copy_file_with_file_name_manual(base_name, tmp_file, copy_files)
392 for base_name, tmp_file in tmp_files.items():
393 if tmp_file not in copy_files:
394 utils.copy_file_src_exist(tmp_file, os.path.join(self.out_dir, base_name))
396 def _move_file_to_outdir_ascend_kernel(self, kernel_obj_info_list: List[AscendKernelInfos]):
397 for kernel_obj_infos in kernel_obj_info_list:
398 for kernel_info in kernel_obj_infos.kernels:
399 tmp_file = kernel_info.kernel_file
400 utils.copy_file_src_exist(tmp_file, os.path.join(self.out_dir, os.path.basename(tmp_file)))
402 def _get_file_name_with_path(self, base_name: str):
403 name_list = base_name.split('_')
404 dir_names = [item for item in name_list if utils.is_prefix_substring(item, ['config', 'ascend'])]
405 if not dir_names:
406 return base_name
407 dir_path = os.path.join(*dir_names)
408 file_idx = name_list.index(dir_names[-1]) + 1
409 if file_idx >= len(name_list):
410 return base_name
411 file_name = '_'.join(name_list[file_idx:])
412 return os.path.join(dir_path, file_name)
414 def _parse_binary_o_json_obj(self) -> dict:
415 '''
416 解析各个_o _json的 地址偏移信息, 并把各个obj内容落盘到临时文件中
417 '''
418 point_content_list = {}
419 output = utils.get_symbols_in_file(self.obj)
421 for line in output.split('\n'):
422 if KEY_O_JSON not in line:
423 continue
424 if line.endswith('_' + TYPE_START):
425 line_list = utils.split_str_with_space(line)
426 line_name = utils.get_str_between(line, KEY_O_JSON, "_" + TYPE_START)
427 if line_name not in point_content_list:
428 point_content_list[line_name] = {}
429 point_content_list[line_name][TYPE_START] = hex(int(line_list[1], HEX_NUM))
430 elif line.endswith('_' + TYPE_END):
431 line_list = utils.split_str_with_space(line)
432 line_name = utils.get_str_between(line, KEY_O_JSON, "_" + TYPE_END)
433 if line_name not in point_content_list:
434 point_content_list[line_name] = {}
435 point_content_list[line_name][TYPE_END] = hex(int(line_list[1], HEX_NUM))
436 elif line.endswith('_' + TYPE_SIZE):
437 line_list = utils.split_str_with_space(line)
438 line_name = utils.get_str_between(line, KEY_O_JSON, "_" + TYPE_SIZE)
439 if line_name not in point_content_list:
440 point_content_list[line_name] = {}
441 point_content_list[line_name][TYPE_SIZE] = hex(int(line_list[1], HEX_NUM))
442 return point_content_list
444 def _show_binary_o_json_obj(self, device_files: dict):
445 for file_name, file_path in device_files.items():
446 if file_name.endswith('.json'):
447 continue
448 output = utils.get_all_section_symbols_in_file(file_path)
449 print(f'===== [elf header infos] in {file_name} =====:')
450 for line in output.split('\n'):
451 print(line)
453 def _list_elf_info_aclnn_pkg_obj(self, point_content_dict: dict):
454 file_idx = 0
455 for obj_name, _ in point_content_dict.items():
456 file_name = self._get_file_name_o_json(obj_name)
457 print(f'ELF file {str(file_idx)}: {file_name}')
458 file_idx += 1
460 def _parse_ascend_kernel_infos(self) -> dict:
461 '''
462 解析的.ascend.kernel. 地址偏移信息
463 '''
464 ascend_kernel_infos = {}
465 output = utils.get_section_headers_in_file(self.obj)
466 for line in output.split('\n'):
467 if KEY_ASCEND_KERNEL not in line:
468 continue
469 line = line.split(KEY_ASCEND_KERNEL)[1]
470 line_list = utils.split_str_with_space(line)
472 ascend_kernel_name_id = 0
473 addr_offsize = 2
474 offset_offsize = 3
475 size_offsize = 4
476 ascend_kernel_name = line_list[ascend_kernel_name_id].replace('.', '_')
477 ascend_kernel_addr = hex(int(line_list[ascend_kernel_name_id + addr_offsize], HEX_NUM))
478 ascend_kernel_offset = hex(int(line_list[ascend_kernel_name_id + offset_offsize], HEX_NUM))
479 ascend_kernel_size = hex(int(line_list[ascend_kernel_name_id + size_offsize], HEX_NUM))
480 ascend_kernel_infos[ascend_kernel_name] = [ascend_kernel_addr, ascend_kernel_offset, ascend_kernel_size]
481 return ascend_kernel_infos
484 def _show_elf_ascend_kernel_obj(self, kernel_obj_info_list: List[AscendKernelInfos]):
485 '''
486 打屏显示elf文件信息、section段、symbols
487 '''
488 for kernel_obj_infos in kernel_obj_info_list:
489 print(f'===========================')
490 print(f'[VERSION]: {kernel_obj_infos.version}')
491 print(f'[TYPE COUNT]: {kernel_obj_infos.type_cnt}')
492 print(f'===========================')
493 for idx, kernel_info in enumerate(kernel_obj_infos.kernels):
494 file_name = os.path.basename(kernel_info.kernel_file)
495 print(f'[ELF FILE {idx}]: {file_name}')
496 print(f'[KERNEL TYPE]: {kernel_info.kernel_type}')
497 print(f'[KERNEL LEN]: {kernel_info.kernel_len}')
498 print(f'[ASCEND META]: {self._show_elf_ascend_meta_obj()}')
499 if self.parse_obj_mode == ParseObjMode.MODE_VERBOSE:
500 print(f'====== [elf header infos] ======')
501 print(utils.get_all_section_symbols_in_file(kernel_info.kernel_file))
504 def _get_elf_ascend_meta_tlv(self, meta_infos: dict):
505 '''
506 接收.ascend.meta. 字典数据, offset偏移获取TLV起始地址, size 获取TLV数据长度
507 循环遍历获取TLV数据并打印映射信息
508 '''
509 meta_item_num = 0
510 for meta_name, meta_lists in meta_infos.items():
511 if meta_name == "meta":
512 continue
513 content = self._get_segment_content(int(meta_lists[1], HEX_NUM), int(meta_lists[2], HEX_NUM))
514 index = 0
515 print(f'{KEY_ASCEND_META} [{meta_item_num}]: {meta_name}')
516 while index < len(content):
517 if index + 4 > len(content):
518 break
520 t, l = struct.unpack("2H", content[index:index + 4])
521 index += 4
522 if (index + l) <= len(content):
523 self._show_ascend_meta_tlv(content, t, l, index)
524 index += l
526 def _get_elf_ascend_meta_op_tlv(self, meta_infos: dict):
527 meta_name = 'meta'
528 if meta_name in meta_infos.keys():
529 self._aicore_binary_meta_printed.clear()
530 meta_lists = meta_infos[meta_name]
531 content = self._get_segment_content(int(meta_lists[1], HEX_NUM), int(meta_lists[2], HEX_NUM))
532 idx = 0
533 index = 0
534 print(f'{KEY_ASCEND_META_OP} META INFO')
535 while index < len(content) and (idx < 4 or self.obj_type == ObjType.TYPE_AICORE_BINARY):
536 if index + 4 > len(content):
537 break
538 t, l = struct.unpack("2H", content[index:index+4])
539 index += 4
540 if index + l > len(content):
541 break
542 self._show_ascend_meta_op_tlv(content, t, l, index)
543 index += l
544 idx += 1
546 def _show_elf_ascend_meta_obj(self):
547 '''
548 展示.ascend.meta段信息
549 '''
550 meta_infos = {}
551 output = utils.get_section_headers_in_file(self.obj)
552 for line in output.split('\n'):
553 if KEY_ASCEND_META in line or KEY_ASCEND_META_OP in line:
554 if KEY_ASCEND_META in line:
555 line = line.split(KEY_ASCEND_META)[1]
556 else:
557 line = line.split(".ascend.")[1]
558 line_list = utils.split_str_with_space(line)
559 meta_name_id = 0
560 meta_name = line_list[meta_name_id]
561 meta_addr = hex(int(line_list[meta_name_id + 2], HEX_NUM))
562 meta_offset = hex(int(line_list[meta_name_id + 3], HEX_NUM))
563 meta_size = hex(int(line_list[meta_name_id + 4], HEX_NUM))
564 meta_infos[meta_name] = [meta_addr, meta_offset, meta_size]
565 self._get_elf_ascend_meta_op_tlv(meta_infos)
566 self._get_elf_ascend_meta_tlv(meta_infos)
568 def _get_file_name_o_json(self, obj_name: str) -> list:
569 file_name = obj_name[: obj_name.rfind('_')] + '.' + obj_name[obj_name.rfind('_') + 1 :]
570 return file_name
572 def _save_dump_elf_o_json(self, point_content_dict: dict) -> dict:
573 '''
574 保存data段各个elf的内容到临时文件下
575 文件名示例: ascend910b_add_custom_AddCustom_c43818e8e69f92d25146c434c100f58a.json:
576 若是xxxx_o: 保存为.o
577 若是xxxx_json: 保存为.json
578 '''
579 save_files = {}
580 data_addr, data_offset, data_size = get_data_segment_range(self.obj)
581 if data_size == 0:
582 print(f'[WARNING]: there is no .data section in {self.obj}, please check input elf file.')
583 return {}
584 for obj_name, point_content in point_content_dict.items():
585 obj_start_offset = int(point_content[TYPE_START], HEX_NUM) + data_offset - data_addr
586 obj_size = int(point_content[TYPE_SIZE], HEX_NUM)
587 file_name = self._get_file_name_o_json(obj_name)
588 tmp_file = os.path.join(self.tmp_dir, file_name)
590 content = self._get_segment_content(obj_start_offset, obj_size)
591 if file_name.endswith('.json'):
592 content = json.loads(content.decode('utf-8'))
593 with open(tmp_file, 'a') as f:
594 json.dump(content, f, indent=4)
595 else:
596 with open(tmp_file, 'ab') as f:
597 f.write(content)
598 save_files[file_name] = tmp_file
599 return save_files
601 def _parse_elf_ascend_kernel_by_type(self, point_content_dict: dict, parse_type: str) -> list:
602 '''
603 保存.ascend.kernel段各个elf的内容到临时文件下
604 文件名示例: ascend910b_add_custom_AddCustom_c43818e8e69f92d25146c434c100f58a.json:
605 若是xxxx_o: 保存为.o
606 若是xxxx_json: 保存为.json
607 '''
608 kernel_infos = []
609 for obj_name, point_content in point_content_dict.items():
610 start_offset = int(point_content[1], HEX_NUM)
611 content_size = int(point_content[2], HEX_NUM)
612 content = self._get_segment_content(start_offset, content_size)
613 kernel_info = self._parse_ascend_kernel_content(content, obj_name, parse_type)
614 kernel_infos.append(kernel_info)
615 return kernel_infos
617 def _parse_ascend_kernel_content(self, content: bytes, obj_name: str, parse_type: str) -> AscendKernelInfos:
618 '''
619 解析.ascend.kernel section的内容
620 内容落盘, 返回生成的AscendKernelInfos信息
621 '''
622 total_len = len(content)
623 read_len = 0
624 kernel_infos = AscendKernelInfos(0, 0)
625 read_head_len = 8
626 if read_len + read_head_len < total_len:
627 version = struct.unpack('I', content[read_len : read_len + 4])[0]
628 read_len += 4
629 type_cnt = struct.unpack('I', content[read_len : read_len + 4])[0]
630 read_len += 4
632 kernel_infos = AscendKernelInfos(version, type_cnt)
633 for kernel_id in range(type_cnt):
634 # parse info
635 kernel_type = self._unpack_buff_content_by_type(content, read_len, 4, 'I')
636 kernel_type = KERNEL_TYPE_MAP.get(str(kernel_type), 'unknow')
637 read_len += 4
638 kernel_len = self._unpack_buff_content_by_type(content, read_len, 4, 'I')
639 read_len += 4
640 kernel_len_real = self._unpack_buff_content_by_type(content, read_len, 4, 'I')
641 read_len += 4
642 # parse buff
643 file_name = '_'.join([obj_name, str(kernel_id), kernel_type]) + '.o'
644 if parse_type == 'list':
645 print('ELF file ' + str(kernel_id) + ": " + file_name)
646 else:
647 file_name = os.path.join(self.tmp_dir, file_name)
648 with open(file_name, 'ab') as f:
649 f.write(content[read_len: read_len + kernel_len_real])
650 read_len += kernel_len
651 # record info in kernel_infos
652 ascend_kernel = AscendKernel(kernel_type, kernel_len_real, file_name)
653 kernel_infos.kernels.append(ascend_kernel)
655 return kernel_infos
657 def _get_segment_content(self, offset: int, size: int):
658 '''
659 获取data段上指定偏移量和大小的内容
660 '''
661 file_size = int(os.path.getsize(self.obj))
662 with open(self.obj, 'r+b') as f:
663 mm = mmap.mmap(f.fileno(), file_size)
664 return mm[offset : (offset + size)]
667def get_data_segment_range(filename: str):
668 '''
669 获取data段的起始地址和大小
670 '''
671 output = utils.get_section_headers_in_file(filename)
672 for line in output.split('\n'):
673 if ' .data ' in line:
674 parts = line.strip().split()
675 return int(parts[3], HEX_NUM), int(parts[4], HEX_NUM), int(parts[5], HEX_NUM)
676 return 0, 0, 0
679def run_obj_dump(args):
680 '''
681 Total entry for objdump tool
682 支持多用户同时调用
683 '''
684 objdump = ObjDump(args)
685 objdump.run()
688def extract_values_from_parentheses(string):
689 pattern = r'\((.*?)\)'
690 match = re.search(pattern, string)
691 if match:
692 return match.group(1)
693 else:
694 return None
697def get_o_file_name(file_path):
698 output = utils.get_all_section_symbols_in_file(file_path)
699 for line in output.split('\n'):
700 if KEY_O_FILE in line:
701 file_name = extract_values_from_parentheses(line)
702 if KEY_ASCEND_KERNEL in line:
703 utils.get_o_file_from_a_file(file_path, file_name)
704 return file_name
705 return None
708def get_o_file(values):
709 try:
710 file_name = get_o_file_name(values)
711 return os.path.realpath(file_name)
712 except FileNotFoundError:
713 print("[ERROR]: The specified file or directory does not exist!!!")
714 except PermissionError:
715 print("[ERROR]: Permission denied!!!")
716 except Exception as e:
717 print("[ERROR]: The input file or directory does not exist!!!")
718 return values
721class FileAction(argparse.Action):
722 """
724 """
725 def __call__(self, parser, namespace, values, option_string=None):
726 """
727 文件有效性检查
728 """
729 try:
730 if values.endswith(KEY_A_FILE):
731 get_o_file(values)
732 values = get_o_file(values)
733 if not values or not os.path.exists(values):
734 raise RuntimeError(f'[ERROR]: File({values}) does not exist or permission denied!!!')
735 else:
736 setattr(namespace, self.dest, os.path.realpath(values))
737 except RuntimeError as e:
738 print('[ERROR]: File does not exist or permission denied!!!')
740def parse_args():
741 parser = argparse.ArgumentParser(prog="msobjdump", description='objdump tool for Ascend C elf file')
742 elf_operator_group = parser.add_argument_group()
743 elf_operator_group.add_argument('--dump-elf', '-d', dest='dump_elf', required=False, metavar="", action=FileAction,
744 help='Dump ELF Object brief informations.')
745 elf_operator_group.add_argument('--verbose', '-V', dest='verbose', required=False, action='store_true',
746 default=False, help='Dump ELF Object all section informations.')
747 elf_operator_group.add_argument('--extract-elf', '-e', dest='extr_elf', required=False, metavar="",
748 action=FileAction,
749 help='Extract ELF file(s) name containing <partial file name> and save as file(s).')
750 elf_operator_group.add_argument('--list-elf', '-l', dest='list_elf', required=False, metavar="", action=FileAction,
751 help='List all the ELF files available in the fatbin.')
752 parser.add_argument('--out-dir', '-o', dest='out_dir', required=False,
753 help='Set user output dir path.')
755 parser.set_defaults(entry_function=run_obj_dump)
756 if len(sys.argv) == 1:
757 parser.print_help()
758 parser.exit(0)
760 args = parser.parse_args()
762 return args
765def main():
766 args = parse_args()
767 args.entry_function(args)
770if __name__ == '__main__':
771 sys.exit(main())