-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathDemangle Swift.py
executable file
·136 lines (97 loc) · 3.83 KB
/
Demangle Swift.py
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/python3
import os
import re
import subprocess
from ctypes import cdll, create_string_buffer, sizeof
from datetime import datetime
# ---------------------------------------------------------------------------
SWIFT_DEMANGLE_CLI = None
SWIFT_DEMANGLE_FUN = None
SWIFT_DEMANGLE_LIB = None
SWIFT_DEMANGLE_SYM = 'swift_demangle_getSimplifiedDemangledName'
# ---------------------------------------------------------------------------
def execute(cmd, data=None):
process = subprocess.Popen(
cmd,
encoding='utf-8',
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
output, error = process.communicate(data)
retcode = process.returncode
if retcode != 0:
raise Exception(' '.join(cmd), data, retcode, error.rstrip('\n'))
return output.rstrip('\n')
def find_swift_demangle():
global SWIFT_DEMANGLE_CLI
global SWIFT_DEMANGLE_LIB
SWIFT_DEMANGLE_CLI = execute(['xcrun', '--find', 'swift-demangle'])
SWIFT_DEMANGLE_LIB = os.path.realpath(SWIFT_DEMANGLE_CLI + '/../../lib/libswiftDemangle.dylib')
def load_swift_demangle_lib():
global SWIFT_DEMANGLE_FUN
SWIFT_DEMANGLE_FUN = cdll.LoadLibrary(SWIFT_DEMANGLE_LIB)[SWIFT_DEMANGLE_SYM]
def demangle_swift_lib(name, size=512):
demangled = create_string_buffer(size)
length = SWIFT_DEMANGLE_FUN(name.encode(), demangled, sizeof(demangled))
if length > size:
return demangle_swift_lib(name, length + 1)
if length > 0:
return demangled.value.decode()
return name
def demangle_swift_cli(name):
return execute([SWIFT_DEMANGLE_CLI], name)
def demangle_swift(name):
if SWIFT_DEMANGLE_FUN:
return demangle_swift_lib(name)
return demangle_swift_cli(name)
# ---------------------------------------------------------------------------
def main():
start = datetime.now()
doc = Document.getCurrentDocument()
find_swift_demangle()
try:
load_swift_demangle_lib()
except (OSError, AttributeError) as error:
doc.log(f"Failed to load library with error: {error}")
doc.log('Falling back to CLI mode.')
segs = [doc.getSegment(index) for index in range(doc.getSegmentCount())]
names = sum([seg.getLabelsList() for seg in segs], [])
label_regex = re.compile(r'(.*?)(_(?:T|\$S|\$s)[^\s@]+)(.*)')
block_regex = re.compile(r'(.*?)(_[\da-f]{9})')
prefixes = ['_T', '_$S', '_$s']
success = 0
failure = 0
skipped = 0
for name in names:
address = doc.getAddressForName(name)
if not (address and any([prefix in name for prefix in prefixes])):
# doc.log(f"Skipped symbol with name: {name}")
skipped += 1
continue
label_matches = label_regex.search(name)
if label_matches:
prefix, mangled, suffix = label_matches.groups()
# mangled_10042cafe
block_matches = block_regex.search(mangled)
if block_matches:
mangled, offset = block_matches.groups()
suffix = offset + suffix
demangled = prefix + demangle_swift(mangled) + suffix
if not label_matches or demangled is name:
doc.log(f"Failed to demangle symbol at address: {address:#08x} with name: {name}")
failure += 1
continue
doc.setNameAtAddress(address, demangled)
# doc.log(f"Demangled symbol at address: {address:#08x} with name: {demangled}")
success += 1
doc.log('--------------')
doc.log('Demangle Swift')
doc.log('--------------')
doc.log(f"Success: {success} name(s)")
doc.log(f"Failure: {failure} name(s)")
doc.log(f"Skipped: {skipped} name(s)")
doc.log(f"Elapsed: {datetime.now() - start}")
# ---------------------------------------------------------------------------
if __name__ == '__main__':
main()