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

Commit e7e567c

Browse files
committed
use DbI to reencode mangled string with identifier back references
1 parent 431d7f7 commit e7e567c

File tree

1 file changed

+182
-6
lines changed

1 file changed

+182
-6
lines changed

src/core/demangle.d

+182-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ else version (WatchOS)
2424
debug(trace) import core.stdc.stdio : printf;
2525
debug(info) import core.stdc.stdio : printf;
2626

27-
private struct Demangle
27+
private struct NoHooks {}
28+
29+
private struct Demangle(Hooks = NoHooks)
2830
{
2931
// NOTE: This implementation currently only works with mangled function
3032
// names as they exist in an object file. Type names mangled via
@@ -71,6 +73,7 @@ pure:
7173
size_t brp = 0; // current back reference pos
7274
AddType addType = AddType.yes;
7375
bool mute = false;
76+
Hooks hooks;
7477

7578
static class ParseException : Exception
7679
{
@@ -540,6 +543,10 @@ pure:
540543
debug(trace) printf( "parseLName+\n" );
541544
debug(trace) scope(success) printf( "parseLName-\n" );
542545

546+
static if(__traits(hasMember, Hooks, "parseLName"))
547+
if (size_t num = hooks.parseLName(this))
548+
return num;
549+
543550
if( front == 'Q' )
544551
{
545552
// back reference to LName
@@ -797,6 +804,10 @@ pure:
797804
"dchar", // w
798805
];
799806

807+
static if (__traits(hasMember, Hooks, "parseType"))
808+
if (auto n = hooks.parseType(this, name))
809+
return n;
810+
800811
debug(trace) printf( "parseType+\n" );
801812
debug(trace) scope(success) printf( "parseType-\n" );
802813
auto beg = len;
@@ -1988,7 +1999,7 @@ pure:
19881999
char[] demangle( const(char)[] buf, char[] dst = null )
19892000
{
19902001
//return Demangle(buf, dst)();
1991-
auto d = Demangle(buf, dst);
2002+
auto d = Demangle!()(buf, dst);
19922003
return d.demangleName();
19932004
}
19942005

@@ -2006,10 +2017,168 @@ char[] demangle( const(char)[] buf, char[] dst = null )
20062017
*/
20072018
char[] demangleType( const(char)[] buf, char[] dst = null )
20082019
{
2009-
auto d = Demangle(buf, dst);
2020+
auto d = Demangle!()(buf, dst);
20102021
return d.demangleType();
20112022
}
20122023

2024+
/**
2025+
* reencode a mangled symbol name that might include duplicate occurrences
2026+
* of the same identifier by replacing all but the first occurence with
2027+
* a back reference.
2028+
*
2029+
* Params:
2030+
* mangled = The mangled string representing the type
2031+
*
2032+
* Returns:
2033+
* The mangled name with deduplicated identifiers
2034+
*/
2035+
char[] reencodeMangled(const(char)[] mangled) nothrow pure @safe
2036+
{
2037+
static struct PrependHooks
2038+
{
2039+
size_t lastpos;
2040+
char[] result;
2041+
size_t[const(char)[]] idpos; // identifier positions
2042+
2043+
static struct Replacement
2044+
{
2045+
size_t pos; // postion in original mangled string
2046+
size_t respos; // postion in result string
2047+
}
2048+
Replacement [] replacements;
2049+
2050+
pure:
2051+
size_t positionInResult(size_t pos)
2052+
{
2053+
foreach_reverse (r; replacements)
2054+
if (pos >= r.pos)
2055+
return r.respos + pos - r.pos;
2056+
return pos;
2057+
}
2058+
2059+
alias Remangle = Demangle!(PrependHooks);
2060+
2061+
size_t parseLName(ref Remangle d)
2062+
{
2063+
if (lastpos < d.pos)
2064+
result ~= d.buf[lastpos .. d.pos];
2065+
else if (lastpos > d.pos)
2066+
{
2067+
// todo: roll back to earlier position
2068+
}
2069+
2070+
auto reslen = result.length;
2071+
auto refpos = d.pos;
2072+
if (d.front == 'Q')
2073+
{
2074+
size_t npos;
2075+
{
2076+
scope(exit) result.length = reslen; // remove all intermediate additions
2077+
// only support identifier back references
2078+
d.popFront();
2079+
size_t n = d.decodeNumber!'A'();
2080+
if (!n || n > refpos)
2081+
d.error("invalid back reference");
2082+
2083+
auto savepos = d.pos;
2084+
scope(exit) d.pos = savepos;
2085+
size_t srcpos = refpos - n;
2086+
2087+
auto idlen = d.decodeNumber();
2088+
if (d.pos + idlen > d.buf.length)
2089+
d.error("invalid back reference");
2090+
auto id = d.buf[d.pos .. d.pos + idlen];
2091+
auto pid = id in idpos;
2092+
if (!pid)
2093+
d.error("invalid back reference");
2094+
npos = positionInResult(*pid);
2095+
}
2096+
encodeBackref(reslen - npos, 'A');
2097+
replacements ~= Replacement(d.pos, result.length);
2098+
}
2099+
else
2100+
{
2101+
auto n = d.decodeNumber();
2102+
if(!n || n > d.buf.length || n > d.buf.length - d.pos)
2103+
d.error("LName too shot or too long");
2104+
auto id = d.buf[d.pos .. d.pos + n];
2105+
d.pos += n;
2106+
if (auto pid = id in idpos)
2107+
{
2108+
size_t npos = positionInResult(*pid);
2109+
result.length = reslen;
2110+
encodeBackref(reslen - npos, 'A');
2111+
replacements ~= Replacement(d.pos, result.length);
2112+
}
2113+
else
2114+
{
2115+
idpos[id] = refpos;
2116+
result ~= d.buf[refpos .. d.pos];
2117+
}
2118+
}
2119+
lastpos = d.pos;
2120+
return 1;
2121+
}
2122+
2123+
char[] parseType( ref Remangle d, char[] name = null )
2124+
{
2125+
if (d.front != 'Q')
2126+
return null;
2127+
2128+
if (lastpos < d.pos)
2129+
result ~= d.buf[lastpos .. d.pos];
2130+
else if (lastpos > d.pos)
2131+
{
2132+
// todo: roll back to earlier position
2133+
}
2134+
2135+
auto refPos = d.pos;
2136+
d.popFront();
2137+
auto n = d.decodeNumber!'a'();
2138+
if (n == 0 || n > refPos)
2139+
d.error("invalid back reference");
2140+
2141+
size_t npos = positionInResult(refPos - n);
2142+
size_t reslen = result.length;
2143+
encodeBackref(reslen - npos, 'a');
2144+
2145+
lastpos = d.pos;
2146+
return result[reslen .. $]; // anything but null
2147+
}
2148+
2149+
void encodeBackref(size_t relpos, char lastDigitBase)
2150+
{
2151+
result ~= 'Q';
2152+
size_t div = 1;
2153+
while (relpos >= div * 10)
2154+
div *= 10;
2155+
while (div >= 10)
2156+
{
2157+
auto dig = (relpos / div);
2158+
result ~= cast(char)('0' + dig);
2159+
relpos -= dig * div;
2160+
div /= 10;
2161+
}
2162+
result ~= cast(char)(lastDigitBase + relpos);
2163+
}
2164+
}
2165+
2166+
auto d = Demangle!(PrependHooks)(mangled, null);
2167+
d.hooks = PrependHooks();
2168+
d.mute = true; // no demangled output
2169+
try
2170+
{
2171+
() @trusted { d.parseMangledName(); }();
2172+
if (d.hooks.lastpos < d.pos)
2173+
d.hooks.result ~= d.buf[d.hooks.lastpos .. d.pos];
2174+
return d.hooks.result;
2175+
}
2176+
catch(Exception)
2177+
{
2178+
// overflow exception cannot occur
2179+
return mangled.dup;
2180+
}
2181+
}
20132182

20142183
/**
20152184
* Mangles a D symbol.
@@ -2071,7 +2240,11 @@ char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow
20712240
}
20722241
dst[i .. i + T.mangleof.length] = T.mangleof[];
20732242
i += T.mangleof.length;
2074-
return dst[0 .. i];
2243+
2244+
static if(hasTypeBackRef)
2245+
return reencodeMangled(dst[0 .. i]);
2246+
else
2247+
return dst[0 .. i];
20752248
}
20762249

20772250

@@ -2131,12 +2304,15 @@ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure no
21312304
}
21322305
}
21332306

2307+
private enum hasTypeBackRef = (int function(void**,void**)).mangleof[$-4 .. $] == "QdZi";
21342308

21352309
///
21362310
unittest
21372311
{
21382312
assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi");
2139-
assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFC6ObjectZi");
2313+
assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQ1IZi");
2314+
version(hasTypeBackRef)
2315+
assert(mangleFunc!(int function(Object, Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQ1IQeZi");
21402316
}
21412317

21422318
unittest
@@ -2376,7 +2552,7 @@ string decodeDmdString( const(char)[] ln, ref size_t p )
23762552
break;
23772553
s ~= s[$ - zpos .. $ - zpos + zlen];
23782554
}
2379-
else if( Demangle.isAlpha(cast(char)ch) || Demangle.isDigit(cast(char)ch) || ch == '_' )
2555+
else if( Demangle!().isAlpha(cast(char)ch) || Demangle!().isDigit(cast(char)ch) || ch == '_' )
23802556
s ~= cast(char) ch;
23812557
else
23822558
{

0 commit comments

Comments
 (0)