Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cppmangle/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .mangle import mangle, demangle
from .cdecl import cdecl_sym
from .cdecl import cdecl_sym, cdecl_qname
from .ast import *
24 changes: 16 additions & 8 deletions cppmangle/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,32 @@ def __init__(self, cv, basic_type):
class BasicType(_Enum):
pass

t_none = BasicType('none')
t_void = BasicType('void')
t_bool = BasicType('bool')
t_char = BasicType('char')
t_schar = BasicType('signed char')
t_uchar = BasicType('unsigned char')
t_sshort = BasicType('short int')
t_ushort = BasicType('unsigned short int')
t_ushort = BasicType('unsigned short')
t_sint = BasicType('int')
t_uint = BasicType('unsigned int')
t_slong = BasicType('long')
t_ulong = BasicType('unsigned long')
t_slonglong = BasicType('long long')
t_ulonglong = BasicType('unsigned long long')
t_slonglong = BasicType('__int64')
t_ulonglong = BasicType('unsigned __int64')
t_wchar = BasicType('wchar_t')
t_float = BasicType('float')
t_double = BasicType('double')
t_longdouble = BasicType('long double')
t_ellipsis = BasicType('...')

class PtrType(Type):
def __init__(self, cv, target, ref):
def __init__(self, cv, target, ref, addr_space):
super(PtrType, self).__init__(cv)
self.target = target
self.ref = ref
self.addr_space = addr_space

k_union = 0
k_struct = 1
Expand Down Expand Up @@ -80,9 +82,9 @@ def __init__(self, desc):
def __repr__(self):
return 'SpecialName({!r})'.format(self.desc)

n_constructor = SpecialName("<constructor>")
n_def_constr_closure = SpecialName("<default constructor closure>")
n_destructor = SpecialName("<destructor>")
n_constructor = SpecialName("`constructor'")
n_def_constr_closure = SpecialName("`default constructor closure'")
n_destructor = SpecialName("`destructor'")
n_op_subscript = SpecialName("operator[]")
n_op_call = SpecialName("operator()")
n_op_member = SpecialName("operator->")
Expand Down Expand Up @@ -157,9 +159,15 @@ class FunctionKind(_Enum):
fn_virtual = FunctionKind('<virtual member fn>')
fn_class_static = FunctionKind('<static member fn>')

class AddressSpace(_Enum):
pass
as_default = AddressSpace('<default>')
as_msvc_x64_absolute = AddressSpace('absolute')

class Function(object):
def __init__(self, qname, type, kind, access_spec):
def __init__(self, qname, type, kind, access_spec, addr_space):
self.qname = qname
self.type = type
self.kind = kind
self.access_spec = access_spec
self.addr_space = addr_space
40 changes: 29 additions & 11 deletions cppmangle/cdecl.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ast import *
from .ast import *

_cvs = ('', 'const ', 'volatile ', 'const volatile ')
_class_kinds = ('union', 'struct', 'class', 'enum')
Expand All @@ -8,15 +8,24 @@ def _cdecl_templ_arg(arg):
return str(arg)
return cdecl_type(arg)

def _cdecl_name(name):
def _cdecl_name(name, prev):
if name == n_constructor:
return prev, None
if name == n_destructor:
return '~{}'.format(prev), None
if isinstance(name, SpecialName):
return name.desc
return name.desc, None
if isinstance(name, TemplateId):
return '{}<{}>'.format(name.name, ', '.join(_cdecl_templ_arg(arg) for arg in name.args))
return name
return '{}<{}>'.format(name.name, ','.join(_cdecl_templ_arg(arg) for arg in name.args)), name.name
return name, name

def _cdecl_qname(qname):
return '::'.join(_cdecl_name(name) for name in qname)
def cdecl_qname(qname):
names = []
base_name = None
for name in qname:
full_name, base_name = _cdecl_name(name, base_name)
names.append(full_name)
return '::'.join(names)

def cdecl_type(type, obj_name=''):
prefixes = []
Expand All @@ -28,14 +37,18 @@ def cdecl_type(type, obj_name=''):

while True:
if isinstance(type, SimpleType):
if type.basic_type == t_none:
break

prefixes.append(_cvs[type.cv])
prefixes.append(' ')
prefixes.append(type.basic_type.desc)
break

if isinstance(type, ClassType):
prefixes.append(_cvs[type.cv])
prefixes.append(' ')
prefixes.append(_cdecl_qname(type.qname))
prefixes.append(cdecl_qname(type.qname))
prefixes.append(' ')
prefixes.append(_class_kinds[type.kind])
break
Expand All @@ -55,19 +68,24 @@ def cdecl_type(type, obj_name=''):
if type.ref:
prefixes.append('& ')
else:
prefixes.append(_cvs[type.cv])
prefixes.append('* ')
type = type.target
continue

if isinstance(type, FunctionType):
prefixes.append('__{} '.format(type.cconv.desc))
if not prefixes or prefixes[-1][0] != '*':
prefixes.append(' ')
prefixes.append('__{}'.format(type.cconv.desc))
if prio != 0:
prefixes.append('(')
suffixes.append(')')
prio = 0
suffixes.append('(')
suffixes.append(', '.join(cdecl_type(param) for param in type.params))
suffixes.append(','.join(cdecl_type(param) for param in type.params))
suffixes.append(')')
if type.this_cv is not None:
suffixes.append(_cvs[type.this_cv])
type = type.ret_type
continue

Expand All @@ -84,6 +102,6 @@ def cdecl_sym(sym):
r.append('virtual ')
if sym.kind == fn_class_static:
r.append('static ')
r.append(cdecl_type(sym.type, _cdecl_qname(sym.qname)))
r.append(cdecl_type(sym.type, cdecl_qname(sym.qname)))
return ''.join(r)
raise RuntimeError('unk')
33 changes: 20 additions & 13 deletions cppmangle/msvc.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import speg
from ast import *
from .ast import *

def _transpose(m):
return dict((m[k], k) for k in m)

_noncv_member_funcs = frozenset([n_constructor, n_destructor])

_basic_type_map = {
'@': t_none,
'X': t_void,
'_N': t_bool,
'D': t_char,
Expand Down Expand Up @@ -153,7 +152,7 @@ def _p_qname(p):
return tuple(qname[::-1])

def _p_basic_type(p):
c = p(r'[XDCEFGHIJKMNOZ]|_[NJKW]')
c = p(r'[@XDCEFGHIJKMNOZ]|_[NJKW]')
return SimpleType(0, _basic_type_map[c]), len(c) >= 2

_cvs = [0, cv_const, cv_volatile, cv_const | cv_volatile]
Expand All @@ -177,17 +176,18 @@ def _p_type(p):
# pointer to fn
cv = _cvs[ord(p('[PQRS]6')[0]) - ord('P')]
fn_type = p(_p_fn_type)
return PtrType(cv, fn_type, False), True
return PtrType(cv, fn_type, False, as_default), True

with p:
# pointer types
kind = p('[APQRS]E?')[0]
kind = p('[APQRS]')
addr_space = as_msvc_x64_absolute if p('E?') else as_default
target_cv = p('[A-D]')
target, reg = p(_p_type)
target.cv = _cvs[ord(target_cv) - ord('A')]

cv = _cvs[ord(kind) - ord('P')] if kind != 'A' else 0
return PtrType(cv, target, kind == 'A'), True
return PtrType(cv, target, kind == 'A', addr_space), True

return p(_p_basic_type)

Expand Down Expand Up @@ -249,15 +249,21 @@ def _p_root(p):
else:
kind = fn_instance

can_have_cv = kind in (fn_instance, fn_virtual) and qname[-1] not in _noncv_member_funcs
this_cv = ord(p('[A-D]')) - ord('A') if can_have_cv else None

can_have_cv = kind in (fn_instance, fn_virtual)
if can_have_cv:
addr_space = as_msvc_x64_absolute if p('E?') else as_default
this_cv = ord(p('[A-D]')) - ord('A')
else:
addr_space = as_default
this_cv = None

type = p(_p_fn_type)
p(p.eof)

type.this_cv = this_cv

return Function(qname, type, kind, access_class)
return Function(qname, type, kind, access_class, addr_space)

def msvc_demangle(s):
return speg.peg(s, _p_root)
Expand Down Expand Up @@ -317,7 +323,7 @@ def _m_type(type, nl, tl):
if isinstance(type.target, FunctionType):
return '{}6{}'.format(kind, _m_fn_type(type.target, nl, tl))
else:
return '{}{}{}'.format(kind, 'ABCD'[type.target.cv], _m_type(type.target, nl, tl))
return '{}{}{}{}'.format(kind, 'E' if type.addr_space == as_msvc_x64_absolute else '', 'ABCD'[type.target.cv], _m_type(type.target, nl, tl))
if isinstance(type, ArrayType):
return 'Y{}{}{}'.format(_m_int(len(type.dims)), ''.join(_m_int(dim) for dim in type.dims), _m_type(type.target, nl, tl))
if isinstance(type, ClassType):
Expand Down Expand Up @@ -379,9 +385,10 @@ def msvc_mangle(obj):

modif = chr(ord('A') + modif)

can_have_cv = obj.kind in (fn_instance, fn_virtual) and obj.qname[-1] not in _noncv_member_funcs
addr_space = 'E' if obj.addr_space == as_msvc_x64_absolute else ''
can_have_cv = obj.kind in (fn_instance, fn_virtual)
this_cv = 'ABCD'[obj.type.this_cv] if can_have_cv else ''

return '?{}{}{}{}'.format(qname, modif, this_cv, type)
return '?{}{}{}{}{}'.format(qname, modif, addr_space, this_cv, type)

raise RuntimeError('unknown obj')
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@

setup(
name='cppmangle',
version='0.1',
version='0.2',

description='A parser for mangled C++ names',
author='AVG Technologies CZ, s.r.o.',
url='https://github.com/AVGTechnologies/cppmangle',
license='Apache 2.0',

packages=['cppmangle'],
install_requires=['speg>=0.3'],

entry_points={
'console_scripts': [
'cppdemangle=cppmangle.__main__:main'
Expand Down