Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
use DbI to reencode mangled string with identifier back references
Browse files Browse the repository at this point in the history
  • Loading branch information
rainers committed Jun 22, 2017
1 parent 431d7f7 commit 3e13966
Showing 1 changed file with 179 additions and 6 deletions.
185 changes: 179 additions & 6 deletions src/core/demangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ else version (WatchOS)
debug(trace) import core.stdc.stdio : printf;
debug(info) import core.stdc.stdio : printf;

private struct Demangle
private struct NoHooks {}

private struct Demangle(Hooks = NoHooks)
{
// NOTE: This implementation currently only works with mangled function
// names as they exist in an object file. Type names mangled via
Expand Down Expand Up @@ -71,6 +73,7 @@ pure:
size_t brp = 0; // current back reference pos
AddType addType = AddType.yes;
bool mute = false;
Hooks hooks;

static class ParseException : Exception
{
Expand Down Expand Up @@ -540,6 +543,10 @@ pure:
debug(trace) printf( "parseLName+\n" );
debug(trace) scope(success) printf( "parseLName-\n" );

static if(__traits(hasMember, Hooks, "parseLName"))
if (size_t num = hooks.parseLName(this))
return num;

if( front == 'Q' )
{
// back reference to LName
Expand Down Expand Up @@ -797,6 +804,10 @@ pure:
"dchar", // w
];

static if (__traits(hasMember, Hooks, "parseType"))
if (auto n = hooks.parseType(this, name))
return n;

debug(trace) printf( "parseType+\n" );
debug(trace) scope(success) printf( "parseType-\n" );
auto beg = len;
Expand Down Expand Up @@ -1988,7 +1999,7 @@ pure:
char[] demangle( const(char)[] buf, char[] dst = null )
{
//return Demangle(buf, dst)();
auto d = Demangle(buf, dst);
auto d = Demangle!()(buf, dst);
return d.demangleName();
}

Expand All @@ -2006,10 +2017,168 @@ char[] demangle( const(char)[] buf, char[] dst = null )
*/
char[] demangleType( const(char)[] buf, char[] dst = null )
{
auto d = Demangle(buf, dst);
auto d = Demangle!()(buf, dst);
return d.demangleType();
}

/**
* reencode a mangled symbol name that might include duplicate occurrences
* of the same identifier by replacing all but the first occurence with
* a back reference.
*
* Params:
* mangled = The mangled string representing the type
*
* Returns:
* The mangled name with deduplicated identifiers
*/
char[] reencodeMangled(const(char)[] mangled) nothrow pure @safe
{
static struct PrependHooks
{
size_t lastpos;
char[] result;
size_t[const(char)[]] idpos; // identifier positions

static struct Replacement
{
size_t pos; // postion in original mangled string
size_t respos; // postion in result string
}
Replacement [] replacements;

pure:
size_t positionInResult(size_t pos)
{
foreach_reverse (r; replacements)
if (pos >= r.pos)
return r.respos + pos - r.pos;
return pos;
}

alias Remangle = Demangle!(PrependHooks);

size_t parseLName(ref Remangle d)
{
if (lastpos < d.pos)
result ~= d.buf[lastpos .. d.pos];
else if (lastpos > d.pos)
{
// todo: roll back to earlier position
}

auto reslen = result.length;
auto refpos = d.pos;
if (d.front == 'Q')
{
size_t npos;
{
scope(exit) result.length = reslen; // remove all intermediate additions
// only support identifier back references
d.popFront();
size_t n = d.decodeNumber!'A'();
if (!n || n > refpos)
d.error("invalid back reference");

auto savepos = d.pos;
scope(exit) d.pos = savepos;
size_t srcpos = refpos - n;

auto idlen = d.decodeNumber();
if (d.pos + idlen > d.buf.length)
d.error("invalid back reference");
auto id = d.buf[d.pos .. d.pos + idlen];
auto pid = id in idpos;
if (!pid)
d.error("invalid back reference");
npos = positionInResult(*pid);
}
encodeBackref(reslen - npos, 'A');
replacements ~= Replacement(d.pos, result.length);
}
else
{
auto n = d.decodeNumber();
if(!n || n > d.buf.length || n > d.buf.length - d.pos)
d.error("LName too shot or too long");
auto id = d.buf[d.pos .. d.pos + n];
d.pos += n;
if (auto pid = id in idpos)
{
size_t npos = positionInResult(*pid);
result.length = reslen;
encodeBackref(reslen - npos, 'A');
replacements ~= Replacement(d.pos, result.length);
}
else
{
idpos[id] = refpos;
result ~= d.buf[refpos .. d.pos];
}
}
lastpos = d.pos;
return 1;
}

char[] parseType( ref Remangle d, char[] name = null )
{
if (d.front != 'Q')
return null;

if (lastpos < d.pos)
result ~= d.buf[lastpos .. d.pos];
else if (lastpos > d.pos)
{
// todo: roll back to earlier position
}

auto refPos = d.pos;
d.popFront();
auto n = d.decodeNumber!'a'();
if (n == 0 || n > refPos)
d.error("invalid back reference");

size_t npos = positionInResult(refPos - n);
size_t reslen = result.length;
encodeBackref(reslen - npos, 'a');

lastpos = d.pos;
return result[reslen .. $]; // anything but null
}

void encodeBackref(size_t relpos, char lastDigitBase)
{
result ~= 'Q';
size_t div = 1;
while (relpos >= div * 10)
div *= 10;
while (div >= 10)
{
auto dig = (relpos / div);
result ~= cast(char)('0' + dig);
relpos -= dig * div;
div /= 10;
}
result ~= cast(char)(lastDigitBase + relpos);
}
}

auto d = Demangle!(PrependHooks)(mangled, null);
d.hooks = PrependHooks();
d.mute = true; // no demangled output
try
{
() @trusted { d.parseMangledName(); }();
if (d.hooks.lastpos < d.pos)
d.hooks.result ~= d.buf[d.hooks.lastpos .. d.pos];
return d.hooks.result;
}
catch(Exception)
{
// overflow exception cannot occur
return mangled.dup;
}
}

/**
* Mangles a D symbol.
Expand Down Expand Up @@ -2071,7 +2240,9 @@ char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow
}
dst[i .. i + T.mangleof.length] = T.mangleof[];
i += T.mangleof.length;
return dst[0 .. i];

auto reencoded = reencodeMangled(dst[0 .. i]);
return reencoded;
}


Expand Down Expand Up @@ -2136,7 +2307,9 @@ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure no
unittest
{
assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi");
assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFC6ObjectZi");
assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQ1IZi");
// with type back reference in function type:
// assert(mangleFunc!(int function(Object, Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQ1IQeZi");
}

unittest
Expand Down Expand Up @@ -2376,7 +2549,7 @@ string decodeDmdString( const(char)[] ln, ref size_t p )
break;
s ~= s[$ - zpos .. $ - zpos + zlen];
}
else if( Demangle.isAlpha(cast(char)ch) || Demangle.isDigit(cast(char)ch) || ch == '_' )
else if( Demangle!().isAlpha(cast(char)ch) || Demangle!().isDigit(cast(char)ch) || ch == '_' )
s ~= cast(char) ch;
else
{
Expand Down

0 comments on commit 3e13966

Please sign in to comment.