Last active
August 18, 2023 10:28
-
-
Save Itay2805/817f3118431cb9658a166e91f7d17eaf to your computer and use it in GitHub Desktop.
Visual C++ name manglerfor fun and profit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from curses.ascii import isalnum | |
class CppNameMangler: | |
KNOWN_TYPES = { | |
# Basic types | |
'signed char': 'A', | |
'char': 'D', | |
'unsigned char': 'E', | |
'short': 'F', | |
'unsigned short': 'G', | |
'int': 'H', | |
'unsigned int': 'I', | |
'long': 'J', | |
'unsigned long': 'K', | |
'float': 'M', | |
'double': 'N', | |
'long double': 'O', | |
'bool': '_N', | |
'__int8': '_D', | |
'unsigned __int8': '_E', | |
'__int16': '_F', | |
'unsigned __int16': '_G', | |
'__int32': '_H', | |
'unsigned __int32': '_I', | |
'__int64': '_J', | |
'unsigned __int64': '_K', | |
'__int128': '_L', | |
'unsigned __int128': '_M', | |
'char8_t': '_Q', | |
'char16_t': '_S', | |
'char32_t': '_U', | |
# Complex types | |
'union': 'T', | |
'struct': 'U', | |
'class': 'V', | |
'void': 'X', | |
} | |
def __init__(self, name: str) -> None: | |
self._name = name | |
self._index = 0 | |
def _get(self) -> str: | |
c = self._name[self._index] | |
self._index += 1 | |
return c | |
def _consume(self, value): | |
if self._peek() == value: | |
self._index += 1 | |
return True | |
return False | |
def _peek(self) -> str: | |
if self._index == len(self._name): | |
return '' | |
c = self._get() | |
self._unget() | |
return c | |
def _expect(self, c): | |
cc = self._get() | |
assert cc == c, f'wanted {c} got {cc} (left `{self._name[self._index:]}`)' | |
def _unget(self): | |
self._index -= 1 | |
def _get_basic_name(self) -> str: | |
ident = '' | |
while True: | |
c = self._peek() | |
if c == '': | |
break | |
c = self._get() | |
if len(ident) == 0: | |
assert c.isalpha(), c | |
ident += c | |
elif c.isalnum(): | |
ident += c | |
else: | |
self._unget() | |
break | |
return ident | |
def _mangle_type_name(self): | |
mname = '' | |
while True: | |
name = self._get_basic_name() | |
if name in ['unsigned', 'signed', 'long']: | |
if self._consume(' '): | |
name += ' ' + self._get_basic_name() | |
if name in self.KNOWN_TYPES: | |
mname += self.KNOWN_TYPES[name] | |
if name in ['union', 'struct', 'class']: | |
self._expect(' ') | |
mname += self._mangle_name() + '@' | |
break | |
else: | |
# TODO: const/volatile/whatever | |
assert False, name + f' -- left: {self._name[self._index:]}' | |
while True: | |
if self._consume('*'): | |
mname = 'PA' + mname | |
elif self._consume('&'): | |
if self._consume('&'): | |
mname = '$$QA' + mname | |
else: | |
mname = 'AA' + mname | |
else: | |
break | |
return mname | |
def _mangle_qualification(self): | |
basic_name = self._get_basic_name() + '@' | |
assert basic_name != '' | |
if self._consume('<'): | |
basic_name = '?$' + basic_name | |
while True: | |
basic_name += self._mangle_type_name() | |
if not self._consume(','): | |
self._expect('>') | |
break | |
basic_name += '@' | |
return basic_name | |
def _mangle_name(self): | |
final = self._mangle_qualification() | |
while self._peek() == ':': | |
self._expect(':') | |
self._expect(':') | |
final = self._mangle_qualification() + final | |
return final | |
def mangle_function(self): | |
ret_type = self._mangle_type_name() | |
self._expect(' ') | |
# TODO: access | |
access = 'Y' | |
name = self._mangle_name() | |
# None, not exported | |
# TODO: this | |
calling_convention = 'K' | |
# arguments | |
args = '' | |
self._expect('(') | |
while self._peek() != ')': | |
args += self._mangle_type_name() | |
if self._peek() == ')': | |
break | |
self._expect(',') | |
self._expect(')') | |
# terminate it | |
if args == '': | |
args = 'X' | |
else: | |
args += '@' | |
# TODO: throw attribute | |
throw_attribute = 'Z' | |
return '?' + name + '@' + access + calling_convention + ret_type + args + throw_attribute | |
print(CppNameMangler("void abc<class def<int>,void*>::xyz()").mangle_function()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment