demangle 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- demangle/__init__.py +103 -0
- demangle/_signature.py +623 -0
- demangle/api.py +749 -0
- demangle/cli.py +521 -0
- demangle/core/__init__.py +20 -0
- demangle/core/ast.py +899 -0
- demangle/core/builder.py +160 -0
- demangle/core/cache.py +70 -0
- demangle/core/decorations.py +73 -0
- demangle/core/errors.py +75 -0
- demangle/core/limits.py +50 -0
- demangle/core/plugin.py +98 -0
- demangle/core/reader.py +247 -0
- demangle/core/registry.py +221 -0
- demangle/core/spelling.py +470 -0
- demangle/core/style.py +192 -0
- demangle/filter.py +226 -0
- demangle/py.typed +0 -0
- demangle/schemes/__init__.py +7 -0
- demangle/schemes/ada/__init__.py +175 -0
- demangle/schemes/ada/_parser.py +313 -0
- demangle/schemes/ada/nodes.py +89 -0
- demangle/schemes/codewarrior/__init__.py +215 -0
- demangle/schemes/codewarrior/_parser.py +583 -0
- demangle/schemes/codewarrior/nodes.py +131 -0
- demangle/schemes/codewarrior/options.py +33 -0
- demangle/schemes/d/__init__.py +118 -0
- demangle/schemes/d/_parser.py +1616 -0
- demangle/schemes/d/nodes.py +93 -0
- demangle/schemes/delphi/__init__.py +79 -0
- demangle/schemes/delphi/_parser.py +897 -0
- demangle/schemes/delphi/nodes.py +128 -0
- demangle/schemes/gnuv2/__init__.py +325 -0
- demangle/schemes/gnuv2/_parser.py +2487 -0
- demangle/schemes/gnuv2/nodes.py +145 -0
- demangle/schemes/gnuv2/options.py +54 -0
- demangle/schemes/go/__init__.py +127 -0
- demangle/schemes/go/_parser.py +278 -0
- demangle/schemes/go/nodes.py +138 -0
- demangle/schemes/itanium/__init__.py +61 -0
- demangle/schemes/itanium/options.py +332 -0
- demangle/schemes/itanium/parser.py +5456 -0
- demangle/schemes/itanium/substitutions.py +362 -0
- demangle/schemes/itanium/tables.py +376 -0
- demangle/schemes/jni/__init__.py +96 -0
- demangle/schemes/jni/_parser.py +226 -0
- demangle/schemes/jni/nodes.py +91 -0
- demangle/schemes/msvc/__init__.py +291 -0
- demangle/schemes/msvc/_parser.py +2024 -0
- demangle/schemes/msvc/nodes.py +450 -0
- demangle/schemes/msvc/options.py +140 -0
- demangle/schemes/nim/__init__.py +81 -0
- demangle/schemes/nim/_parser.py +470 -0
- demangle/schemes/nim/nodes.py +81 -0
- demangle/schemes/objc/__init__.py +119 -0
- demangle/schemes/objc/_parser.py +823 -0
- demangle/schemes/objc/nodes.py +122 -0
- demangle/schemes/pascal/__init__.py +85 -0
- demangle/schemes/pascal/_parser.py +428 -0
- demangle/schemes/pascal/nodes.py +131 -0
- demangle/schemes/rust/__init__.py +244 -0
- demangle/schemes/rust/_dispatch.py +85 -0
- demangle/schemes/rust/_legacy.py +266 -0
- demangle/schemes/rust/_v0.py +1867 -0
- demangle/schemes/rust/nodes.py +194 -0
- demangle/schemes/rust/options.py +36 -0
- demangle/schemes/swift/__init__.py +247 -0
- demangle/schemes/swift/_demangler.py +3224 -0
- demangle/schemes/swift/_node.py +644 -0
- demangle/schemes/swift/_old_demangler.py +1525 -0
- demangle/schemes/swift/_printer.py +2737 -0
- demangle/schemes/swift/_punycode.py +116 -0
- demangle/schemes/swift/nodes.py +143 -0
- demangle/schemes/swift/options.py +155 -0
- demangle/schemes/swift/resolve.py +577 -0
- demangle/schemes/swift/symbolic.py +201 -0
- demangle-0.3.0.dist-info/METADATA +382 -0
- demangle-0.3.0.dist-info/RECORD +82 -0
- demangle-0.3.0.dist-info/WHEEL +4 -0
- demangle-0.3.0.dist-info/entry_points.txt +2 -0
- demangle-0.3.0.dist-info/licenses/LICENSE +21 -0
- demangle-0.3.0.dist-info/licenses/NOTICE +178 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""Symbolic references: the part of the Swift mangling that points into the binary.
|
|
2
|
+
|
|
3
|
+
A mangled name in a Swift binary's *metadata* is not always self-contained. Where a name
|
|
4
|
+
would have to spell a type the image already describes, the compiler writes a symbolic
|
|
5
|
+
reference instead: one byte saying what kind of thing is referred to and how, then a
|
|
6
|
+
four-byte signed offset relative to itself. The bytes are transcribed from
|
|
7
|
+
`Demangler.cpp::demangleSymbolicReference` in the Swift 5.10 sources.
|
|
8
|
+
|
|
9
|
+
01 a context descriptor, directly
|
|
10
|
+
02 a context descriptor, through a pointer
|
|
11
|
+
09 an accessor function that yields the entity when run
|
|
12
|
+
0A a unique extended existential type shape
|
|
13
|
+
0B a non-unique extended existential type shape
|
|
14
|
+
03-08, 0C reserved, and refused: the reference itself refuses them
|
|
15
|
+
FF alignment padding in front of a reference, and skipped
|
|
16
|
+
|
|
17
|
+
Two consequences fall out of the encoding and both matter to a reader:
|
|
18
|
+
|
|
19
|
+
* **A metadata blob cannot be split on NUL.** The four-byte offset is arbitrary bytes
|
|
20
|
+
and very often contains a zero, so finding where a mangled name ends means parsing
|
|
21
|
+
it. `end_of_name` does exactly that and nothing else.
|
|
22
|
+
* **A name holding one is not text.** It is bytes, so the entry points here take
|
|
23
|
+
`bytes` where the rest of the package takes `str`.
|
|
24
|
+
|
|
25
|
+
Resolving a reference needs the image the name came out of, which is why this is a
|
|
26
|
+
separate entry point rather than something `demangle()` could do: see `resolve.py` for a
|
|
27
|
+
resolver that reads one, and `demangle_symbolic` for the parse that uses it.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
import struct
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
"ACCESSOR_FUNCTION",
|
|
34
|
+
"CONTEXT",
|
|
35
|
+
"DIRECT",
|
|
36
|
+
"INDIRECT",
|
|
37
|
+
"KINDS",
|
|
38
|
+
"NON_UNIQUE_EXTENDED_EXISTENTIAL_TYPE_SHAPE",
|
|
39
|
+
"PADDING",
|
|
40
|
+
"RESERVED",
|
|
41
|
+
"UNIQUE_EXTENDED_EXISTENTIAL_TYPE_SHAPE",
|
|
42
|
+
"SymbolicReference",
|
|
43
|
+
"end_of_name",
|
|
44
|
+
"read",
|
|
45
|
+
"scan",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
#: What a reference points at.
|
|
49
|
+
CONTEXT = "context"
|
|
50
|
+
ACCESSOR_FUNCTION = "accessor function"
|
|
51
|
+
UNIQUE_EXTENDED_EXISTENTIAL_TYPE_SHAPE = "unique extended existential type shape"
|
|
52
|
+
NON_UNIQUE_EXTENDED_EXISTENTIAL_TYPE_SHAPE = "non-unique extended existential type shape"
|
|
53
|
+
|
|
54
|
+
#: Whether the offset reaches the entity or a pointer to it.
|
|
55
|
+
DIRECT = "direct"
|
|
56
|
+
INDIRECT = "indirect"
|
|
57
|
+
|
|
58
|
+
#: Introducer byte -> `(kind, directness)`. Exactly the reference's switch, including
|
|
59
|
+
#: which values it leaves out: 3 through 8 are reserved for protocol- and
|
|
60
|
+
#: associated-conformance descriptors and are *not* emitted, and 0x0C reaches the
|
|
61
|
+
#: switch only to fall through its default.
|
|
62
|
+
KINDS = {
|
|
63
|
+
0x01: (CONTEXT, DIRECT),
|
|
64
|
+
0x02: (CONTEXT, INDIRECT),
|
|
65
|
+
0x09: (ACCESSOR_FUNCTION, DIRECT),
|
|
66
|
+
0x0A: (UNIQUE_EXTENDED_EXISTENTIAL_TYPE_SHAPE, DIRECT),
|
|
67
|
+
0x0B: (NON_UNIQUE_EXTENDED_EXISTENTIAL_TYPE_SHAPE, DIRECT),
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#: Introducer bytes the grammar accepts and the reference then refuses.
|
|
71
|
+
RESERVED = frozenset({0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0C})
|
|
72
|
+
|
|
73
|
+
#: Every byte that begins a symbolic reference, refused or not.
|
|
74
|
+
INTRODUCERS = frozenset(KINDS) | RESERVED
|
|
75
|
+
|
|
76
|
+
#: Written in front of a reference where the platform's relocations need the offset
|
|
77
|
+
#: aligned. It carries nothing and is skipped.
|
|
78
|
+
PADDING = 0xFF
|
|
79
|
+
|
|
80
|
+
#: The offset is a 32-bit signed little-endian integer, and it is relative to its own
|
|
81
|
+
#: first byte -- not to the introducer, and not to the end of the field.
|
|
82
|
+
_OFFSET = struct.Struct("<i")
|
|
83
|
+
OFFSET_WIDTH = _OFFSET.size
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class SymbolicReference:
|
|
87
|
+
"""One symbolic reference, as the bytes described it.
|
|
88
|
+
|
|
89
|
+
`at` is where the *offset field* begins, because that is what the offset is relative
|
|
90
|
+
to: the address a resolver wants is `address_of(at) + offset`. Keeping the position
|
|
91
|
+
rather than the resolved address is what lets this module know nothing about images.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
__slots__ = ("at", "directness", "kind", "offset", "raw_kind")
|
|
95
|
+
|
|
96
|
+
def __init__(self, raw_kind, kind, directness, offset, at):
|
|
97
|
+
self.raw_kind = raw_kind
|
|
98
|
+
self.kind = kind
|
|
99
|
+
self.directness = directness
|
|
100
|
+
self.offset = offset
|
|
101
|
+
self.at = at
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def reserved(self):
|
|
105
|
+
"""Whether this is one of the introducers the reference declines to read."""
|
|
106
|
+
return self.kind is None
|
|
107
|
+
|
|
108
|
+
def __repr__(self): # pragma: no cover - debugging aid
|
|
109
|
+
kind = self.kind or f"reserved 0x{self.raw_kind:02x}"
|
|
110
|
+
return f"SymbolicReference({kind}, {self.directness}, {self.offset:+d}, at={self.at})"
|
|
111
|
+
|
|
112
|
+
def __eq__(self, other):
|
|
113
|
+
if not isinstance(other, SymbolicReference):
|
|
114
|
+
return NotImplemented
|
|
115
|
+
return (self.raw_kind, self.offset, self.at) == (other.raw_kind, other.offset, other.at)
|
|
116
|
+
|
|
117
|
+
def __hash__(self):
|
|
118
|
+
return hash((self.raw_kind, self.offset, self.at))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def read(data, pos):
|
|
122
|
+
"""Read the reference whose introducer is at `data[pos]`.
|
|
123
|
+
|
|
124
|
+
Returns `(reference, position after it)`. Raises `ValueError` if `pos` does not hold
|
|
125
|
+
an introducer, or if the four offset bytes are not all there -- which the reference
|
|
126
|
+
also treats as failure rather than reading a short integer.
|
|
127
|
+
"""
|
|
128
|
+
if pos < 0 or pos >= len(data):
|
|
129
|
+
raise ValueError(f"no byte at {pos}")
|
|
130
|
+
raw = data[pos]
|
|
131
|
+
if raw not in INTRODUCERS:
|
|
132
|
+
raise ValueError(f"0x{raw:02x} does not introduce a symbolic reference")
|
|
133
|
+
start = pos + 1
|
|
134
|
+
if start + OFFSET_WIDTH > len(data):
|
|
135
|
+
raise ValueError("truncated symbolic reference")
|
|
136
|
+
(offset,) = _OFFSET.unpack_from(data, start)
|
|
137
|
+
kind, directness = KINDS.get(raw, (None, None))
|
|
138
|
+
return SymbolicReference(raw, kind, directness, offset, start), start + OFFSET_WIDTH
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def scan(data):
|
|
142
|
+
"""Every symbolic reference in `data`, in order.
|
|
143
|
+
|
|
144
|
+
Reading rather than searching: a byte inside an offset can look like an introducer,
|
|
145
|
+
and a name that has been walked properly is the only way to know it is not one.
|
|
146
|
+
"""
|
|
147
|
+
found = []
|
|
148
|
+
pos = 0
|
|
149
|
+
length = len(data)
|
|
150
|
+
while pos < length:
|
|
151
|
+
byte = data[pos]
|
|
152
|
+
if byte in INTRODUCERS:
|
|
153
|
+
reference, pos = read(data, pos)
|
|
154
|
+
found.append(reference)
|
|
155
|
+
else:
|
|
156
|
+
pos += 1
|
|
157
|
+
return tuple(found)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def end_of_name(data, start=0):
|
|
161
|
+
"""Where the NUL-terminated mangled name beginning at `start` ends.
|
|
162
|
+
|
|
163
|
+
The index returned is of the terminating NUL, or of the end of `data` if the name
|
|
164
|
+
runs to it. This exists because the obvious thing does not work: a reference's
|
|
165
|
+
four-byte offset is arbitrary bytes and very often holds a zero, so `data.index(0)`
|
|
166
|
+
cuts a name in half. Swift's own reflection reader walks the name for the same
|
|
167
|
+
reason.
|
|
168
|
+
"""
|
|
169
|
+
if start < 0 or start > len(data):
|
|
170
|
+
raise ValueError(f"no byte at {start}")
|
|
171
|
+
pos = start
|
|
172
|
+
length = len(data)
|
|
173
|
+
while pos < length:
|
|
174
|
+
byte = data[pos]
|
|
175
|
+
if byte == 0:
|
|
176
|
+
return pos
|
|
177
|
+
if byte in INTRODUCERS:
|
|
178
|
+
if pos + 1 + OFFSET_WIDTH > length:
|
|
179
|
+
# Truncated. The name cannot be read, and neither can the one after it,
|
|
180
|
+
# so the whole remainder is this name.
|
|
181
|
+
return length
|
|
182
|
+
pos += 1 + OFFSET_WIDTH
|
|
183
|
+
else:
|
|
184
|
+
pos += 1
|
|
185
|
+
return length
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def names(data):
|
|
189
|
+
"""Split a metadata blob of NUL-terminated mangled names into those names.
|
|
190
|
+
|
|
191
|
+
Empty entries are dropped: a section is padded with them.
|
|
192
|
+
"""
|
|
193
|
+
found = []
|
|
194
|
+
pos = 0
|
|
195
|
+
length = len(data)
|
|
196
|
+
while pos < length:
|
|
197
|
+
stop = end_of_name(data, pos)
|
|
198
|
+
if stop > pos:
|
|
199
|
+
found.append(data[pos:stop])
|
|
200
|
+
pos = stop + 1
|
|
201
|
+
return tuple(found)
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: demangle
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Read mangled symbol names -- Itanium C++, MSVC, pre-Itanium C++, Ada/GNAT, Rust, Swift, Objective-C, Go, D, Nim, Free Pascal, Delphi and JNI -- in pure Python, with no dependencies.
|
|
5
|
+
Project-URL: Homepage, https://github.com/r0ny123/demangle
|
|
6
|
+
Project-URL: Issues, https://github.com/r0ny123/demangle/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/r0ny123/demangle/blob/main/CHANGELOG.md
|
|
8
|
+
Author: demangle contributors
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: NOTICE
|
|
12
|
+
Keywords: abi,binary-analysis,c++,demangle,demangler,disassembler,itanium,mangling,msvc,reverse-engineering,rust,symbol
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
|
+
Classifier: Topic :: Security
|
|
21
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
22
|
+
Classifier: Topic :: Software Development :: Disassemblers
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.13
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# demangle
|
|
28
|
+
|
|
29
|
+
[](https://github.com/r0ny123/demangle/actions/workflows/ci.yml)
|
|
30
|
+
[](https://www.python.org/downloads/)
|
|
31
|
+
[](https://github.com/r0ny123/demangle/blob/main/LICENSE)
|
|
32
|
+
|
|
33
|
+
**Read mangled symbol names in pure Python** — Itanium C++ (GCC/Clang), MSVC, Rust,
|
|
34
|
+
Swift, Objective-C, Go, D, Nim, Free Pascal, Delphi, Ada/GNAT, JNI, and the pre-Itanium
|
|
35
|
+
C++ families (g++ 2.x, cfront/ARM, Lucid, HP aCC, CodeWarrior). No dependencies, no
|
|
36
|
+
native code, no compiler required.
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
>>> import demangle
|
|
40
|
+
>>> demangle.demangle("_ZNSt6vectorIiSaIiEE9push_backERKi")
|
|
41
|
+
'std::vector<int, std::allocator<int>>::push_back(int const&)'
|
|
42
|
+
>>> demangle.demangle("?f@@YAXH@Z")
|
|
43
|
+
'void __cdecl f(int)'
|
|
44
|
+
>>> demangle.demangle("_ZN4core3fmt9Formatter3pad17h9b2b3a0e5b4d1b31E")
|
|
45
|
+
'core::fmt::Formatter::pad'
|
|
46
|
+
>>> demangle.demangle("$s10Foundation4DataV5countSivg")
|
|
47
|
+
'Foundation.Data.count.getter : Swift.Int'
|
|
48
|
+
>>> demangle.demangle("example.com/m/v2%2e5.(*T).Method", language="go")
|
|
49
|
+
'example.com/m/v2.5.(*T).Method'
|
|
50
|
+
>>> demangle.demangle("eqdestroy___systemZassertions_23")
|
|
51
|
+
'system/assertions.=destroy'
|
|
52
|
+
>>> demangle.demangle("MYUNIT$_$TWIDGET_$__$$_AREA$$LONGINT")
|
|
53
|
+
'MYUNIT.TWIDGET.AREA: LONGINT'
|
|
54
|
+
>>> demangle.demangle("@Unit@Class@Method$qqrv")
|
|
55
|
+
'__fastcall Unit::Class::Method()'
|
|
56
|
+
>>> demangle.demangle("AddAlignment__9ivTSolverUiP12ivInteractorP7ivTGlue")
|
|
57
|
+
'ivTSolver::AddAlignment(unsigned int, ivInteractor *, ivTGlue *)'
|
|
58
|
+
>>> demangle.demangle("__dt__6CActorFv")
|
|
59
|
+
'CActor::~CActor()'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **No toolchain.** Every other option in Python binds to a native demangler —
|
|
63
|
+
`cxxfilt` and `pycxxfilt` wrap LLVM or libstdc++, `undname` wraps Wine through CFFI —
|
|
64
|
+
which means a C compiler at install time, a platform-specific wheel, and for MSVC
|
|
65
|
+
nothing maintained at all. This is Python and nothing else.
|
|
66
|
+
- **A tree, not just a string.** `parse()` answers with nodes to walk, so the namespace,
|
|
67
|
+
the template arguments and the parameter types are fields rather than a regular
|
|
68
|
+
expression against C++ declaration syntax, which nests and so cannot be parsed that
|
|
69
|
+
way.
|
|
70
|
+
- **Measured, not asserted.** Every scheme is scored against the reference demangler for
|
|
71
|
+
its mangling, over about 2,400,000 symbols out of shipped libraries, and every name
|
|
72
|
+
that differs is accounted for by name. [CONFORMANCE.md](https://github.com/r0ny123/demangle/blob/main/CONFORMANCE.md) has the
|
|
73
|
+
numbers and what each is measured against.
|
|
74
|
+
- **Safe on untrusted input.** `demangle()` never raises, for any input; recursion depth,
|
|
75
|
+
output size, substitution count and input length are all bounded, and every bound is
|
|
76
|
+
configurable per call.
|
|
77
|
+
|
|
78
|
+
## Install
|
|
79
|
+
|
|
80
|
+
```console
|
|
81
|
+
pip install demangle
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Python 3.13 or newer. That is the whole dependency list.
|
|
85
|
+
|
|
86
|
+
## Use
|
|
87
|
+
|
|
88
|
+
### The string you probably want
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
demangle.demangle(name) # never raises; returns `name` unchanged if unreadable
|
|
92
|
+
demangle.demangle_strict(name) # raises DemanglingError instead
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`demangle()` is built for the case where you are labelling every symbol in a binary and
|
|
96
|
+
most of them are not mangled at all. A name it cannot read comes back exactly as it went
|
|
97
|
+
in, because a wrong expansion is worse than a mangled one — it matches neither the
|
|
98
|
+
symbol nor the declaration.
|
|
99
|
+
|
|
100
|
+
### The structure, when you need it
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
>>> tree = demangle.parse("_ZNK3Foo3barIiEEvPKc")
|
|
104
|
+
>>> tree.spell()
|
|
105
|
+
'void Foo::bar<int>(char const*) const'
|
|
106
|
+
>>> [node.text for node in tree.find("name")]
|
|
107
|
+
['Foo', 'bar']
|
|
108
|
+
>>> function = next(tree.find("function"))
|
|
109
|
+
>>> len(function.parameters)
|
|
110
|
+
1
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Every node supports `.walk()`, `.find(kind)`, `.children()` and `.spell()`.
|
|
114
|
+
|
|
115
|
+
All schemes return full trees. A Rust symbol comes back as a `symbol` holding a
|
|
116
|
+
`path` of `name` components, with `impl`, `template`, `type` and `literal` nodes for what
|
|
117
|
+
the path carries:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
>>> tree = demangle.parse("_ZN4core3fmt9Formatter3pad17h9b2b3a0e5b4d1b31E")
|
|
121
|
+
>>> [node.text for node in tree.find("name")]
|
|
122
|
+
['core', 'fmt', 'Formatter', 'pad']
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### The parts, when the spelling is not what you want
|
|
126
|
+
|
|
127
|
+
`signature()` gives the pieces rather than the string — the base name without its
|
|
128
|
+
scope, the scope without the base name, the parameter types on their own:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
>>> parts = demangle.signature("_ZNSt6vectorIiSaIiEE9push_backERKi")
|
|
132
|
+
>>> parts.namespace, parts.base_name
|
|
133
|
+
('std::vector<int, std::allocator<int>>', 'push_back')
|
|
134
|
+
>>> parts.parameters
|
|
135
|
+
('int const&',)
|
|
136
|
+
>>> demangle.signature("$s4main3FooV3baryS2i_SStF").return_type
|
|
137
|
+
'Swift.Int'
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`namespace`, the scheme's separator and `base_name` spell `qualified_name` exactly, so
|
|
141
|
+
the three recombine. Splitting the *string* would not give that: `::` and `.` and `,`
|
|
142
|
+
occur inside template arguments and inside operator names as well as between components.
|
|
143
|
+
|
|
144
|
+
What each scheme records differs, and the fields say so rather than guessing. A C++ or
|
|
145
|
+
Swift name carries a signature; a Rust or Go path does not, and its `parameters` is
|
|
146
|
+
`None` — which is not `()`. `is_function` is `False` where the name does not say.
|
|
147
|
+
|
|
148
|
+
### A type on its own, not a whole symbol
|
|
149
|
+
|
|
150
|
+
A `typeinfo` name, an RTTI type descriptor and a Swift metadata typeref all carry a
|
|
151
|
+
*type* rather than a symbol. `demangle_type()` reads one, and `parse_type()` gives its
|
|
152
|
+
tree:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
>>> demangle.demangle_type("PKFvRiE", language="itanium")
|
|
156
|
+
'void (*)(int&) const'
|
|
157
|
+
>>> demangle.demangle_type(".PEAX", language="msvc") # a type descriptor's own symbol
|
|
158
|
+
'void *'
|
|
159
|
+
>>> demangle.demangle_type("SaySiG", language="swift")
|
|
160
|
+
'[Swift.Int]'
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`language` is required, and that is not an oversight: a whole symbol announces its
|
|
164
|
+
scheme — `_Z`, `?`, `$s` — and a type encoding announces nothing at all, so `Si` is
|
|
165
|
+
`std::istream` to the Itanium reader and `Swift.Int` to the Swift one. Every reference
|
|
166
|
+
tool puts this behind a flag for the same reason. On the command line it is
|
|
167
|
+
`demangle --types -l itanium`, one encoding per argument rather than a filter over mixed
|
|
168
|
+
text — `Pi` is an ordinary word, and `I like Pi` should stay as it is.
|
|
169
|
+
|
|
170
|
+
### A file, not a name
|
|
171
|
+
|
|
172
|
+
`nm` writes an address and a type letter before a name; a crash log writes a frame
|
|
173
|
+
number. So the useful operation over a file is "substitute every symbol-shaped word and
|
|
174
|
+
copy the rest through", which is what the command does with no arguments — and now what
|
|
175
|
+
the library does too:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
>>> demangle.demangle_text("0000000000001139 T _ZN3foo3barEv")
|
|
179
|
+
'0000000000001139 T foo::bar()'
|
|
180
|
+
>>> demangle.demangle_stream(sys.stdin, sys.stdout) # a line at a time, for pipes
|
|
181
|
+
>>> [f.mangled for f in demangle.find_symbols("a _ZN3foo3barEv b")]
|
|
182
|
+
['_ZN3foo3barEv']
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`find_symbols` gives the span as well as the spelling, for a caller that needs to know
|
|
186
|
+
*where* in a line a symbol was.
|
|
187
|
+
|
|
188
|
+
### Detection and batches
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
>>> demangle.detect("?f@@YAXH@Z")
|
|
192
|
+
'msvc'
|
|
193
|
+
>>> list(demangle.demangle_all(symbol_table)) # generator, shares the cache
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Bytes, when the names came from a symbol table
|
|
197
|
+
|
|
198
|
+
An ELF or Mach-O string table holds bytes, and they are not reliably UTF-8 — a truncated
|
|
199
|
+
table cuts a name mid-character. Every entry point has a bytes form, so reading one does
|
|
200
|
+
not mean guessing an encoding first:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
>>> demangle.demangleb(b"_ZN3foo3barEv")
|
|
204
|
+
b'foo::bar()'
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`demangleb_strict`, `detectb`, `parseb`, `signatureb`, `demangleb_type` and
|
|
208
|
+
`parseb_type` go with it. Undecodable bytes
|
|
209
|
+
survive the round trip: `demangleb` hands back exactly what it was given, byte for byte,
|
|
210
|
+
rather than raising.
|
|
211
|
+
|
|
212
|
+
### The tree as data
|
|
213
|
+
|
|
214
|
+
`parse()` returns a walkable tree; `to_dict()` turns it into plain data, `--json` prints
|
|
215
|
+
it, and `node_kinds()` is the vocabulary to switch on rather than something to read out
|
|
216
|
+
of our source:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
>>> demangle.parse("_Z1fPi").to_dict()
|
|
220
|
+
{'kind': 'function', 'name': {'kind': 'name', 'text': 'f'}, 'parameters': [{'kind': 'pointer', 'inner': {'kind': 'builtin', 'spelling': 'int'}}], 'returns': None, 'suffix': ''}
|
|
221
|
+
>>> demangle.node_kinds("d")
|
|
222
|
+
('name', 'path', 'symbol')
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The nodes carry `__match_args__`, so structural pattern matching works:
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
>>> from demangle.core.ast import Builtin, Pointer
|
|
229
|
+
>>> match demangle.parse("_Z1fPi").parameters[0]:
|
|
230
|
+
... case Pointer(Builtin(name)): print("pointer to", name)
|
|
231
|
+
pointer to int
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
A node reached more than once — an Itanium substitution, a Rust node named both by
|
|
235
|
+
position and by role — is written once with an `id` and afterwards as `{"$ref": id}`. The
|
|
236
|
+
structure is a graph, and expanding it in full does not always terminate in useful time.
|
|
237
|
+
|
|
238
|
+
### Styles
|
|
239
|
+
|
|
240
|
+
The two reference demanglers legitimately disagree on some spellings. Both are
|
|
241
|
+
available, and neither is wrong:
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
>>> demangle.demangle("_ZNSt6vectorIiSaIiEE9push_backERKi", style="llvm") # default
|
|
245
|
+
'std::vector<int, std::allocator<int>>::push_back(int const&)'
|
|
246
|
+
>>> demangle.demangle("_ZNSt6vectorIiSaIiEE9push_backERKi", style="gnu")
|
|
247
|
+
'std::vector<int, std::allocator<int> >::push_back(int const&)'
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Printing less of a name
|
|
251
|
+
|
|
252
|
+
A decorated name expands to a great deal more than the name. `style()` composes what to
|
|
253
|
+
leave out, at the call site rather than by registering anything globally:
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
>>> demangle.demangle("?g@C@@UEAAXXZ")
|
|
257
|
+
'public: virtual void __cdecl C::g(void)'
|
|
258
|
+
>>> narrow = demangle.style("llvm", msvc={"calling_convention": False, "access_specifier": False})
|
|
259
|
+
>>> demangle.demangle("?g@C@@UEAAXXZ", style=narrow)
|
|
260
|
+
'virtual void C::g(void)'
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The MSVC scheme has nine such options: the five flags `llvm-undname` has —
|
|
264
|
+
`calling_convention`, `access_specifier`, `member_type`, `return_type`, `variable_type`
|
|
265
|
+
— and four `UnDecorateSymbolName` mask bits it has no flag for, `ms_keywords`,
|
|
266
|
+
`leading_underscores`, `this_type` and `tag_kind`. The two kinds reach differently, which
|
|
267
|
+
is the references' doing rather than a convenience:
|
|
268
|
+
[`MsvcOptions`](https://github.com/r0ny123/demangle/blob/main/src/demangle/schemes/msvc/options.py) says which is which, field by
|
|
269
|
+
field, and each kind is scored against its own reference in
|
|
270
|
+
[CONFORMANCE.md](https://github.com/r0ny123/demangle/blob/main/CONFORMANCE.md). Every one of them has a command-line flag.
|
|
271
|
+
|
|
272
|
+
Swift has the bundle Xcode and LLDB show instead of the full spelling — `Either` for
|
|
273
|
+
`Monads.Either`, `(_:)` for `(Swift.Int) -> Swift.UInt`, `specialized f()` for a page of
|
|
274
|
+
specialisation arguments. It is `--simplified` on the command line, and exact against
|
|
275
|
+
Swift's own 217 vectors:
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
>>> from demangle.schemes.swift import SIMPLIFIED_OPTIONS
|
|
279
|
+
>>> demangle.demangle("_TtFSiSu", style=demangle.style("llvm", swift=SIMPLIFIED_OPTIONS))
|
|
280
|
+
'(_:)'
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Command line
|
|
284
|
+
|
|
285
|
+
```console
|
|
286
|
+
$ nm -a libfoo.so | demangle
|
|
287
|
+
$ demangle _ZNSt6vectorIiSaIiEE9push_backERKi
|
|
288
|
+
$ demangle --tree _Z1fPKc
|
|
289
|
+
$ demangle --detect _RNvC6_123foo3bar
|
|
290
|
+
$ demangle -p _ZNSt6vectorIiSaIiEE9push_backERKi # the name, without the signature
|
|
291
|
+
$ demangle --base-name _ZSt4sortIPiEvT_S1_ # `sort<int*>`
|
|
292
|
+
$ demangle --no-return-type _ZSt4sortIPiEvT_S1_ # the declaration, minus `void `
|
|
293
|
+
$ demangle --ret-postfix _Z1fIiET_S0_ # `f<int>(int)int`, as `DMGL_RET_POSTFIX`
|
|
294
|
+
$ demangle --strip-underscore '_?f@@YAXH@Z' # ignore one leading underscore
|
|
295
|
+
$ demangle --keep-hash _ZN4core3fmt5write17h05af221e174051e9E # keep Rust's hash
|
|
296
|
+
$ demangle --types -l itanium PKFvRiE # a bare type, as `c++filt -t`
|
|
297
|
+
$ demangle --no-calling-convention '?f@@YAXH@Z' # `void f(int)`
|
|
298
|
+
$ demangle --no-tag-kind '?g3@@YAXVV@@@Z' # `void __cdecl g3(V)`
|
|
299
|
+
$ demangle --simplified _TtFSiSu # Swift, the way Xcode shows it
|
|
300
|
+
$ demangle --json _Z1fPi # the parse tree as JSON
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Correctness
|
|
304
|
+
|
|
305
|
+
Correctness here is a measurement rather than a claim. Every scheme is scored against the
|
|
306
|
+
reference implementation for its mangling — `llvm-cxxfilt`, GNU `c++filt`,
|
|
307
|
+
`llvm-undname`, `rustfilt`, `swift-demangle`, `cwdemangle`, Embarcadero's own unmangler —
|
|
308
|
+
and, where no reference exists, against a property the mangling itself has to satisfy:
|
|
309
|
+
re-mangling what was read must reproduce the symbol the compiler wrote.
|
|
310
|
+
|
|
311
|
+
The checked-in corpora are replayed by the test suite with no compiler and no reference
|
|
312
|
+
demangler present. Beyond them, whole symbol tables are run live against the references:
|
|
313
|
+
about 2,400,000 real symbols from shipped libraries, and every name that differs is
|
|
314
|
+
accounted for one by one.
|
|
315
|
+
|
|
316
|
+
**[CONFORMANCE.md](https://github.com/r0ny123/demangle/blob/main/CONFORMANCE.md) is the whole picture** — what each corpus is measured
|
|
317
|
+
against, the notes behind every number, the live runs, and the places where following a
|
|
318
|
+
reference would itself be the defect.
|
|
319
|
+
|
|
320
|
+
## Safety
|
|
321
|
+
|
|
322
|
+
A mangled name is untrusted input in any tool that opens files it did not produce, so
|
|
323
|
+
the bounds on depth, output size, substitution count and input length are the design
|
|
324
|
+
rather than a hardening pass. Results are deterministic, and the property-based suite
|
|
325
|
+
runs every parser against arbitrary text, mangling-alphabet text, arbitrary bytes, every
|
|
326
|
+
truncation of a known-good name, and inputs built to blow up a naive parser.
|
|
327
|
+
[SECURITY.md](https://github.com/r0ny123/demangle/blob/main/SECURITY.md) has the threat model, what is in scope, and how to report
|
|
328
|
+
privately.
|
|
329
|
+
|
|
330
|
+
## Performance
|
|
331
|
+
|
|
332
|
+
Pure Python, measured on the conformance corpora (`benchmarks/bench.py`):
|
|
333
|
+
|
|
334
|
+
| Workload | Throughput |
|
|
335
|
+
|---|---|
|
|
336
|
+
| Cold — every name distinct | ~24,000 names/sec |
|
|
337
|
+
| Warm — names repeat, as in a real symbol table | ~2,200,000 names/sec |
|
|
338
|
+
| Non-mangled names rejected | ~510,000 names/sec |
|
|
339
|
+
| Full AST construction | ~16,500 names/sec |
|
|
340
|
+
|
|
341
|
+
Treat these as ratios rather than absolutes. The gap between cold and warm is the point:
|
|
342
|
+
symbol tables repeat themselves relentlessly, and results are cached.
|
|
343
|
+
|
|
344
|
+
`bench.py --check` gates CI against the committed baseline. It compares figures normalised
|
|
345
|
+
against a calibration workload measured in the same run, so the gate reports a slower
|
|
346
|
+
*demangler* rather than a slower *machine*.
|
|
347
|
+
|
|
348
|
+
## Architecture
|
|
349
|
+
|
|
350
|
+
The short version: **parsers never build their own output**. Each one is written against
|
|
351
|
+
a `Builder` protocol and reports the grammar productions it recognises; a fast text
|
|
352
|
+
builder or a tree builder decides what those become. That is what lets one parser serve
|
|
353
|
+
both `demangle()` and `parse()` with no second implementation to drift.
|
|
354
|
+
|
|
355
|
+
Schemes are plugins. `core` never imports one, they never import each other, and a
|
|
356
|
+
separate distribution can add a language through the `demangle.languages`
|
|
357
|
+
entry-point group without patching this package. Both rules are enforced by tests.
|
|
358
|
+
|
|
359
|
+
[Working with the tree](https://github.com/r0ny123/demangle/blob/main/docs/analysing-a-binary.md) works
|
|
360
|
+
one real task through `parse()` end to end — finding every function in libstdc++ that
|
|
361
|
+
takes a string by const reference, and measuring what the regular-expression version of
|
|
362
|
+
the same question gets wrong.
|
|
363
|
+
|
|
364
|
+
See [ARCHITECTURE.md](https://github.com/r0ny123/demangle/blob/main/ARCHITECTURE.md) for the full picture and
|
|
365
|
+
[Adding a scheme](https://github.com/r0ny123/demangle/blob/main/docs/adding-a-scheme.md) to add a language
|
|
366
|
+
of your own. The API reference is published at <https://r0ny123.github.io/demangle/>.
|
|
367
|
+
|
|
368
|
+
## Contributing
|
|
369
|
+
|
|
370
|
+
New schemes, corpus contributions, and conformance bug reports are all welcome — see
|
|
371
|
+
[CONTRIBUTING.md](https://github.com/r0ny123/demangle/blob/main/CONTRIBUTING.md). A good bug report is a mangled name, what the
|
|
372
|
+
reference prints, and what this library prints.
|
|
373
|
+
|
|
374
|
+
Fixing a spelling or adding a language should not require understanding the whole
|
|
375
|
+
codebase. Where it does, that is a bug.
|
|
376
|
+
|
|
377
|
+
## Licence
|
|
378
|
+
|
|
379
|
+
MIT. The Rust demangler derives from Team bi0s' `rust_demangler` (MIT) and the MSVC
|
|
380
|
+
demangler from [SMDA](https://github.com/danielplohmann/smda) (BSD 2-Clause); both are
|
|
381
|
+
substantially modified, and both upstream licences are reproduced in
|
|
382
|
+
[NOTICE](https://github.com/r0ny123/demangle/blob/main/NOTICE).
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
demangle/__init__.py,sha256=ZXJT87l6tidPkQoe6QDhxtSfBDhbziOldBdCdkQTBlg,2516
|
|
2
|
+
demangle/_signature.py,sha256=LKJWggi2rtMeYPua64LX1Sc_9jIA6joWIP9APrsTLzY,25959
|
|
3
|
+
demangle/api.py,sha256=M8o7EGokKfTsx5N8PpQ8RlwJiatMK-osyQCsBleGKlo,32512
|
|
4
|
+
demangle/cli.py,sha256=O6PV8fEEzyf5J2gdkEju6_LNZmpYYX6Tkam3AmWuk58,23715
|
|
5
|
+
demangle/filter.py,sha256=8RPEru5Cl32_dyMT55pxxn-bRsabgwmvscGMbKWKjmc,10090
|
|
6
|
+
demangle/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
demangle/core/__init__.py,sha256=AGi-0r12rDEdUf-MFVqOMVEGQipu_-buqoA-x4chqz4,1073
|
|
8
|
+
demangle/core/ast.py,sha256=CiZe43i_kqSnrUUdkUg3K5YR9Ff6mJgJkRjuAR0Uhcg,33325
|
|
9
|
+
demangle/core/builder.py,sha256=AZA7-RH90iMKQ6uW9HxGQdHPD6hr3SgkfQqJAKa6IJk,7352
|
|
10
|
+
demangle/core/cache.py,sha256=411yLDifXOOHTYoUE6uVynqEJbh_bXYNySaJsuBLfuM,2081
|
|
11
|
+
demangle/core/decorations.py,sha256=oWphv2iwfG8RZCt-hBGTE79lWknC44yORxT-eWglrro,3544
|
|
12
|
+
demangle/core/errors.py,sha256=PxKzucafAgKZf4dHdeyh_QG0v8Dvdl2LixBX22RSd6k,3004
|
|
13
|
+
demangle/core/limits.py,sha256=D1c1pEamvcG7H5xCFaWNbwA0WnBXc4S0cMC55odgcwQ,2174
|
|
14
|
+
demangle/core/plugin.py,sha256=gHC31fx7isWyIBpvMmX3h0y4tk5_vZon4QNaEruHsLI,4261
|
|
15
|
+
demangle/core/reader.py,sha256=RMfaH1plMC429T8wvBBXqVxKUQJRaCw7VuQEUBcKfy0,10635
|
|
16
|
+
demangle/core/registry.py,sha256=mf7LpG5o5jnQXXKe_K7YuPww4eBRydfHxmnbk8UB8XA,8302
|
|
17
|
+
demangle/core/spelling.py,sha256=65MxXgUHbZzHz3lXYXyvwtprvUtXMwpwuy5To2uAlOY,24062
|
|
18
|
+
demangle/core/style.py,sha256=hddj1NJvaEsLLB74hLT1Mi0hIVdZAnYawObSZ7iuXj0,7883
|
|
19
|
+
demangle/schemes/__init__.py,sha256=6AjYmDZPnvO4ED9lDqrxolaXzu0NlbYOlQ9pzg90CLo,319
|
|
20
|
+
demangle/schemes/ada/__init__.py,sha256=VRHK5kTjyMF-TwuYHeEwOmJUwmAvPp5mgI5_qJ3jCSI,8998
|
|
21
|
+
demangle/schemes/ada/_parser.py,sha256=VworSHrS85FoIm1hFqISO74JrS60qPbknLzdPLMZpUo,12235
|
|
22
|
+
demangle/schemes/ada/nodes.py,sha256=qyf6mhIbkgHCkMPvANEKlzgrMzRmupEKD4HvuqvtoIU,2805
|
|
23
|
+
demangle/schemes/codewarrior/__init__.py,sha256=1MQO5iYdrZv1T_y5lGC55RQ3QNiRNWrPLq8j8hq5myk,8895
|
|
24
|
+
demangle/schemes/codewarrior/_parser.py,sha256=4N3DmfLdT9HejBlaxs7J47LXjtnb826zUBhl07GaJ_k,20653
|
|
25
|
+
demangle/schemes/codewarrior/nodes.py,sha256=Fwu4vNKePMCd92OMWaYAI2VzAmz99YRuQF0ImDAmDEs,3996
|
|
26
|
+
demangle/schemes/codewarrior/options.py,sha256=q0o5afuIyKSVXmGwvAf4-M2bGR6JIsDCofSxw0muFJI,1235
|
|
27
|
+
demangle/schemes/d/__init__.py,sha256=unROT-mBlhdcktLtnPppSpOu6Ie19nU_48b3Cy7ImGk,4687
|
|
28
|
+
demangle/schemes/d/_parser.py,sha256=jJ6a2JegjDPeCqqfwtckoErh_dVEE3829cHRlbyrCCA,81885
|
|
29
|
+
demangle/schemes/d/nodes.py,sha256=y5HLVrYsAZ-JwODZgkc1Kn8r3FLyT8l5EOT54eX1pT4,2569
|
|
30
|
+
demangle/schemes/delphi/__init__.py,sha256=LYdQluOHjJYs9mdxujpUCC6w7e5KuXpBD6ewMoZ-O4o,3210
|
|
31
|
+
demangle/schemes/delphi/_parser.py,sha256=GdDbgvUPatUXRkA_YqOWDtuqPw_uWGOM8RTUoX8XmTY,34035
|
|
32
|
+
demangle/schemes/delphi/nodes.py,sha256=EbQwhtPOwlMYWT_SVCzWGOfl0X_M31wjb5sJqT_8sZE,3521
|
|
33
|
+
demangle/schemes/gnuv2/__init__.py,sha256=5GZ3Gsmt3qj5Ky3TlA5HLvMbSqb_qzIpR8-UGIdtZ0w,15853
|
|
34
|
+
demangle/schemes/gnuv2/_parser.py,sha256=5ZS7_oOiIrSxcx0nX3ELbdG8rBAHggFgnivmT908vCI,86138
|
|
35
|
+
demangle/schemes/gnuv2/nodes.py,sha256=J2jJqRP7vb6c7KjdbMpabcyGqCQhJKWzjBH8Lq04aj0,4745
|
|
36
|
+
demangle/schemes/gnuv2/options.py,sha256=Sft-bJAI_qfzJYxnxKqf30RVGwLFtEIR1-EuFKo17sc,2184
|
|
37
|
+
demangle/schemes/go/__init__.py,sha256=EKQ8Mj6RaVMju9fRq7tE_1lUnnA5F0h5pLTneeIvCD8,5144
|
|
38
|
+
demangle/schemes/go/_parser.py,sha256=xiFjM5_11UwVbLAhDfPTvFyqSJ0AKMR4apEOR2B3-Wc,12083
|
|
39
|
+
demangle/schemes/go/nodes.py,sha256=toeMLnKMFL_aD1htXdfRwN6xC2Qz-5umZ14XoLlBTj8,4083
|
|
40
|
+
demangle/schemes/itanium/__init__.py,sha256=3k0t5OYGOi8jYY8dgsfvZezNiP982JZJoMWH5ANXkPY,1607
|
|
41
|
+
demangle/schemes/itanium/options.py,sha256=G6__n1TD6jI-S1OUQfpdHDrXV1oYpQ0n0pwSLaPF4MI,17849
|
|
42
|
+
demangle/schemes/itanium/parser.py,sha256=IPlIEqJK5Jqw6Cm3jIXSKx_bjGvC7TuhQR8kZ1KFfyQ,290679
|
|
43
|
+
demangle/schemes/itanium/substitutions.py,sha256=szXj6aPrxTdqyn_aU8kC7DN1X3nAf7Ma-olAFNCsV-g,16471
|
|
44
|
+
demangle/schemes/itanium/tables.py,sha256=Ek4s952qceOmMPb1mDw_rf6vv0GPxSPg_rX9xZynQHs,12799
|
|
45
|
+
demangle/schemes/jni/__init__.py,sha256=E8Vb0Kr9FXye6QzRYK4mdCZ3bvrMxWO6CmCI2TRzT7I,3999
|
|
46
|
+
demangle/schemes/jni/_parser.py,sha256=cIskDqwluojm0w2bw-f5F-DIzmkQSb0kiUi7SfKE0k0,9879
|
|
47
|
+
demangle/schemes/jni/nodes.py,sha256=A7YCBHrNulVSZaUmDUUGtF7oMgt0OzdZMGL6gF7vYuQ,2634
|
|
48
|
+
demangle/schemes/msvc/__init__.py,sha256=prgQAkOYVlb1CuDq0hqGteUYRp3n3Gd6OdTAwHgOdng,14735
|
|
49
|
+
demangle/schemes/msvc/_parser.py,sha256=ZLG3JQNxpPom2ZYJp9wyUQxTWvMAkggX5_ml5M9Vrwo,97310
|
|
50
|
+
demangle/schemes/msvc/nodes.py,sha256=5RBw7McmN4FLMK3_p9xb3SbmhcQoSy3hqhCVcojhUaM,22428
|
|
51
|
+
demangle/schemes/msvc/options.py,sha256=SarkabnhN66O9UCMGcHEjFwCRdMxGKth6XlD4dEF1HI,6395
|
|
52
|
+
demangle/schemes/nim/__init__.py,sha256=ADbv1ePyr5Z6YJp9FrmBGHOypzOe8io_xuxTSUle1Hw,3138
|
|
53
|
+
demangle/schemes/nim/_parser.py,sha256=4QRh6uUIitr-4VbwNexNFoCZF-Ndngan0kudm0gx9HE,19032
|
|
54
|
+
demangle/schemes/nim/nodes.py,sha256=DmNjGboIhIjTt5Qinx6TBPqNOGFm1g_KVUUpizJBd_w,2377
|
|
55
|
+
demangle/schemes/objc/__init__.py,sha256=dxWSdbyZECxwn-fZeqiNUek8bsBlhznXYrHCM1j4X4Y,4970
|
|
56
|
+
demangle/schemes/objc/_parser.py,sha256=zx35Ev_jDism1-6Jkm5m9-B8z9SMLrwHUV2Z1VLUYHs,38712
|
|
57
|
+
demangle/schemes/objc/nodes.py,sha256=DnJJHjgsSV4dOfXGcumclUVzvN7qH6oYF12DUkhUHCg,3768
|
|
58
|
+
demangle/schemes/pascal/__init__.py,sha256=23YaRZm255WL32rHrrEVSzZ-T2c-SvNqW7DhRh91wRc,3550
|
|
59
|
+
demangle/schemes/pascal/_parser.py,sha256=apC5Ri8o6wS1upKWv5WvccqRQ-8OlqHQoCs4sIU3eNs,15397
|
|
60
|
+
demangle/schemes/pascal/nodes.py,sha256=ij2qlpiqJWyySksN6kG66JJ42tgwDA5foXr1Z8JuINQ,4547
|
|
61
|
+
demangle/schemes/rust/__init__.py,sha256=LwXnI5ZgOCORfI_h-HfqY8ojXyuXAiZN-_VT1FBICTY,11471
|
|
62
|
+
demangle/schemes/rust/_dispatch.py,sha256=z_Xbup6nZlUJnjJqoI-IlanvhNb1KkHZkeMGFEfwnTw,3261
|
|
63
|
+
demangle/schemes/rust/_legacy.py,sha256=XJY9t6xlbp6N4cfSKMdfpakdkWcsGS9kMklPx576Za8,11384
|
|
64
|
+
demangle/schemes/rust/_v0.py,sha256=PKzfXj2ZJOwXAkBZY5A1xmTJLd4htRqeGQ1SJiJhwl0,73466
|
|
65
|
+
demangle/schemes/rust/nodes.py,sha256=urcmSyZx0pnIz7uzzYkPRL2Fs8IUWdXowl3PiVAKeQs,6489
|
|
66
|
+
demangle/schemes/rust/options.py,sha256=vVZYmEfiHNgtR9Amjjoy16qVoJZOPiVS3MxjI8ARib8,1489
|
|
67
|
+
demangle/schemes/swift/__init__.py,sha256=WB5ju0yKWUE1bZTWr1RmBif4QvZmolGsD7enNCnnR1Y,10288
|
|
68
|
+
demangle/schemes/swift/_demangler.py,sha256=M422fUZO4VcV-rbCO_x_mJnuMryhmpOLV5jTwWorvzE,132940
|
|
69
|
+
demangle/schemes/swift/_node.py,sha256=LI8txslNyQA9nfVzzSzrd-iM99nsrP2W3IL7e7IXNLI,21212
|
|
70
|
+
demangle/schemes/swift/_old_demangler.py,sha256=p2rgpR_BCLKVXjvFmOHNblowlOejDtvN8wjv6CDKNF4,57355
|
|
71
|
+
demangle/schemes/swift/_printer.py,sha256=xm5_lbsGjI55zzrFA14EBIY9arKLV3tfm_JEpXklwtc,101774
|
|
72
|
+
demangle/schemes/swift/_punycode.py,sha256=9j9yaydBVnjDvzho1A5TOXMgBZqDVoa0mvBmQCKARH8,4341
|
|
73
|
+
demangle/schemes/swift/nodes.py,sha256=Vb_OtVjpGwl7yWV-NBWbLtq7mJ-Oo91pTRaa0DPowyY,5068
|
|
74
|
+
demangle/schemes/swift/options.py,sha256=UTXZUIJTLrfIhHsceVtNw5BTsK-9ZVqDLyxtlk9Mu9Q,6340
|
|
75
|
+
demangle/schemes/swift/resolve.py,sha256=OPC1Vr-aYwVrq_0M4oEQ_Lcrr4pqHfO7lyExgBF02Rs,26227
|
|
76
|
+
demangle/schemes/swift/symbolic.py,sha256=Cz4hapUn1maZ92AjcrqE5XeAcsS7WCB30C75S1Fcty8,7493
|
|
77
|
+
demangle-0.3.0.dist-info/METADATA,sha256=YpfBP3iUSHFjhabFq1EOcdWMDojMAojsrFY_4EkOHD0,17189
|
|
78
|
+
demangle-0.3.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
79
|
+
demangle-0.3.0.dist-info/entry_points.txt,sha256=SEc09SLy0tnFqkFudxqACUKuPu2bCnfw2dpk_0Mspi0,47
|
|
80
|
+
demangle-0.3.0.dist-info/licenses/LICENSE,sha256=BiVCDUXWJRpSX7YsgqxkhsUT_tcfVTFmNHHUfiujrh8,1078
|
|
81
|
+
demangle-0.3.0.dist-info/licenses/NOTICE,sha256=cYig6w7q6AXFFJU8s2ClgR3SqYUpN_mmuz3DrAwXfnk,10123
|
|
82
|
+
demangle-0.3.0.dist-info/RECORD,,
|