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

Commit a2a30ae

Browse files
committed
use DbI to reencode mangled string with identifier back references
1 parent 6e4f9f1 commit a2a30ae

File tree

1 file changed

+191
-6
lines changed

1 file changed

+191
-6
lines changed

src/core/demangle.d

+191-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ 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+
// supported hooks
30+
// static bool parseLName(ref Demangle);
31+
// static char[] parseType(ref Demangle, char[])
32+
}
33+
34+
private struct Demangle(Hooks = NoHooks)
2835
{
2936
// NOTE: This implementation currently only works with mangled function
3037
// names as they exist in an object file. Type names mangled via
@@ -71,6 +78,7 @@ pure:
7178
size_t brp = 0; // current back reference pos
7279
AddType addType = AddType.yes;
7380
bool mute = false;
81+
Hooks hooks;
7482

7583
static class ParseException : Exception
7684
{
@@ -538,6 +546,10 @@ pure:
538546
debug(trace) printf( "parseLName+\n" );
539547
debug(trace) scope(success) printf( "parseLName-\n" );
540548

549+
static if(__traits(hasMember, Hooks, "parseLName"))
550+
if (hooks.parseLName(this))
551+
return;
552+
541553
if( front == 'Q' )
542554
{
543555
// back reference to LName
@@ -771,6 +783,10 @@ pure:
771783
"dchar", // w
772784
];
773785

786+
static if (__traits(hasMember, Hooks, "parseType"))
787+
if (auto n = hooks.parseType(this, name))
788+
return n;
789+
774790
debug(trace) printf( "parseType+\n" );
775791
debug(trace) scope(success) printf( "parseType-\n" );
776792
auto beg = len;
@@ -1962,7 +1978,7 @@ pure:
19621978
char[] demangle( const(char)[] buf, char[] dst = null )
19631979
{
19641980
//return Demangle(buf, dst)();
1965-
auto d = Demangle(buf, dst);
1981+
auto d = Demangle!()(buf, dst);
19661982
return d.demangleName();
19671983
}
19681984

@@ -1980,10 +1996,168 @@ char[] demangle( const(char)[] buf, char[] dst = null )
19801996
*/
19811997
char[] demangleType( const(char)[] buf, char[] dst = null )
19821998
{
1983-
auto d = Demangle(buf, dst);
1999+
auto d = Demangle!()(buf, dst);
19842000
return d.demangleType();
19852001
}
19862002

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

19882162
/**
19892163
* Mangles a D symbol.
@@ -2045,7 +2219,11 @@ char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow
20452219
}
20462220
dst[i .. i + T.mangleof.length] = T.mangleof[];
20472221
i += T.mangleof.length;
2048-
return dst[0 .. i];
2222+
2223+
static if(hasTypeBackRef)
2224+
return reencodeMangled(dst[0 .. i]);
2225+
else
2226+
return dst[0 .. i];
20492227
}
20502228

20512229

@@ -2105,12 +2283,19 @@ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure no
21052283
}
21062284
}
21072285

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

21092288
///
21102289
unittest
21112290
{
21122291
assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi");
2113-
assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFC6ObjectZi");
2292+
static if(hasTypeBackRef)
2293+
{
2294+
assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQ1IZi");
2295+
assert(mangleFunc!(int function(Object, Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQ1IQeZi");
2296+
}
2297+
else
2298+
assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFC6ObjectZi");
21142299
}
21152300

21162301
unittest
@@ -2343,7 +2528,7 @@ string decodeDmdString( const(char)[] ln, ref size_t p )
23432528
break;
23442529
s ~= s[$ - zpos .. $ - zpos + zlen];
23452530
}
2346-
else if( Demangle.isAlpha(cast(char)ch) || Demangle.isDigit(cast(char)ch) || ch == '_' )
2531+
else if( Demangle!().isAlpha(cast(char)ch) || Demangle!().isDigit(cast(char)ch) || ch == '_' )
23472532
s ~= cast(char) ch;
23482533
else
23492534
{

0 commit comments

Comments
 (0)