forked from XIVN1987/RTTView
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_elf_parsing.py
More file actions
109 lines (89 loc) · 4.91 KB
/
Copy pathtest_elf_parsing.py
File metadata and controls
109 lines (89 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import collections
import struct
from elftools.elf.elffile import ELFFile
Variable = collections.namedtuple('Variable', 'name addr size')
def parse_elffile(path):
try:
elffile = ELFFile(open(path, 'rb'))
Vars = {}
# 增加对 .symtab 的空检查
symtab = elffile.get_section_by_name('.symtab')
if symtab:
for sym in symtab.iter_symbols():
if sym.entry['st_info']['type'] == 'STT_OBJECT':
Vars[sym.name] = Variable(sym.name, sym.entry['st_value'], sym.entry['st_size'])
if elffile.has_dwarf_info():
dwarfinfo = elffile.get_dwarf_info()
def get_type_die(die):
while 'DW_AT_type' in die.attributes:
die = die.get_DIE_from_attribute('DW_AT_type')
if die.tag not in ('DW_TAG_typedef', 'DW_TAG_const_type', 'DW_TAG_volatile_type', 'DW_TAG_restrict_type'):
return die
return None
def parse_struct(die, addr, name):
for child in die.iter_children():
if child.tag == 'DW_TAG_member':
if 'DW_AT_name' not in child.attributes or 'DW_AT_data_member_location' not in child.attributes:
continue
m_name = child.attributes['DW_AT_name'].value.decode('utf-8')
m_off = child.attributes['DW_AT_data_member_location'].value
# LEB128 偏移处理 (DW_OP_plus_uconst)
if not isinstance(m_off, int):
if isinstance(m_off, list) and len(m_off) > 1 and m_off[0] == 0x23:
val, shift, i = 0, 0, 1
while i < len(m_off):
byte = m_off[i]
val |= (byte & 0x7F) << shift
i += 1
if not (byte & 0x80): break
shift += 7
m_off = val
else:
m_off = 0
t_die = get_type_die(child)
if t_die:
f_name = f"{name}.{m_name}"
# 提取成员大小
size = t_die.attributes['DW_AT_byte_size'].value if 'DW_AT_byte_size' in t_die.attributes else 0
# 仅添加基本类型的成员(或可以被读取的成员)
if size in (1, 2, 4, 8):
Vars[f_name] = Variable(f_name, addr + m_off, size)
# 递归处理嵌套结构体
if t_die.tag == 'DW_TAG_structure_type':
parse_struct(t_die, addr + m_off, f_name)
for CU in dwarfinfo.iter_CUs():
for die in CU.get_top_DIE().iter_children():
if die.tag == 'DW_TAG_variable' and 'DW_AT_name' in die.attributes:
v_name = die.attributes['DW_AT_name'].value.decode('utf-8')
# 尝试从 DWARF 中获取变量地址,如果 .symtab 中没有
v_addr = None
if 'DW_AT_location' in die.attributes:
loc = die.attributes['DW_AT_location'].value
if isinstance(loc, list) and len(loc) == 5 and loc[0] == 0x03: # DW_OP_addr
v_addr = struct.unpack('<I', bytes(loc[1:]))[0]
if v_addr is not None and v_name not in Vars:
# 这里的 size 可能需要从类型 DIE 获取
t_die = get_type_die(die)
v_size = t_die.attributes['DW_AT_byte_size'].value if t_die and 'DW_AT_byte_size' in t_die.attributes else 0
Vars[v_name] = Variable(v_name, v_addr, v_size)
if v_name in Vars:
t_die = get_type_die(die)
if t_die and t_die.tag == 'DW_TAG_structure_type':
parse_struct(t_die, Vars[v_name].addr, v_name)
return {k: v for k, v in Vars.items() if v.size in (1, 2, 4, 8)}
except Exception as e:
print(f'parse elf file fail: {e}')
return {}
if __name__ == "__main__":
import sys
path = "frame.axf"
if len(sys.argv) > 1:
path = sys.argv[1]
print(f"Parsing {path}...")
vars = parse_elffile(path)
# 打印一些结构体成员示例
struct_vars = [name for name in vars.keys() if '.' in name]
print(f"Found {len(vars)} variables total, {len(struct_vars)} of which are struct members.")
for name in sorted(struct_vars)[:20]:
v = vars[name]
print(f" {name:40} @ 0x{v.addr:08X} (size {v.size})")