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

Commit f7378d4

Browse files
committed
core.demangle: add demangling of back references
1 parent 5c01e52 commit f7378d4

File tree

2 files changed

+146
-53
lines changed

2 files changed

+146
-53
lines changed

src/core/demangle.d

Lines changed: 144 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ private struct Demangle
6969
size_t pos = 0;
7070
size_t len = 0;
7171
AddType addType = AddType.yes;
72-
72+
bool mute = false;
7373

7474
static class ParseException : Exception
7575
{
@@ -173,7 +173,7 @@ private struct Demangle
173173
dst[b] = t;
174174
}
175175

176-
if( val.length )
176+
if( val.length && !mute )
177177
{
178178
assert( contains( dst[0 .. len], val ) );
179179
debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr );
@@ -193,7 +193,7 @@ private struct Demangle
193193

194194
char[] append( const(char)[] val )
195195
{
196-
if( val.length )
196+
if( val.length && !mute )
197197
{
198198
if( !dst.length )
199199
dst.length = minBufSize;
@@ -296,6 +296,13 @@ private struct Demangle
296296
return char.init;
297297
}
298298

299+
char peek( size_t n )
300+
{
301+
if( pos + n < buf.length )
302+
return buf[pos + n];
303+
return char.init;
304+
}
305+
299306

300307
void test( char val )
301308
{
@@ -334,18 +341,34 @@ private struct Demangle
334341
popFront();
335342
}
336343

344+
bool isSymbolNameFront()
345+
{
346+
char val = front;
347+
if( isDigit( val ) || val == '_' )
348+
return true;
349+
if( val != 'Q' )
350+
return false;
351+
352+
// check the back reference encoding after 'Q'
353+
val = peek( 1 );
354+
for( int n = 2; isDigit( val ); n++ )
355+
val = peek( n );
356+
return ( val >= 'A' && val <= 'J' ) || ( val >= 'K' && val <= 'T' ); // length or symbol ref
357+
}
337358

338359
//////////////////////////////////////////////////////////////////////////
339360
// Parsing Implementation
340361
//////////////////////////////////////////////////////////////////////////
341362

342363

343364
/*
365+
if term != 0, LastDigit == term + digit-value
366+
344367
Number:
345-
Digit
368+
LastDigit
346369
Digit Number
347370
*/
348-
const(char)[] sliceNumber()
371+
const(char)[] sliceNumber(char term = 0)()
349372
{
350373
debug(trace) printf( "sliceNumber+\n" );
351374
debug(trace) scope(success) printf( "sliceNumber-\n" );
@@ -358,33 +381,45 @@ private struct Demangle
358381
if (t >= '0' && t <= '9')
359382
popFront();
360383
else
384+
{
385+
static if( term )
386+
{
387+
if (t >= term && t <= term + 9)
388+
popFront();
389+
else
390+
error();
391+
}
361392
return buf[beg .. pos];
393+
}
362394
}
363395
}
364396

365397

366-
size_t decodeNumber()
398+
size_t decodeNumber(char term = 0)()
367399
{
368400
debug(trace) printf( "decodeNumber+\n" );
369401
debug(trace) scope(success) printf( "decodeNumber-\n" );
370402

371-
return decodeNumber( sliceNumber() );
403+
return decodeNumber!term( sliceNumber!term() );
372404
}
373405

374406

375-
size_t decodeNumber( const(char)[] num )
407+
size_t decodeNumber(char term = 0)( const(char)[] num )
376408
{
377409
debug(trace) printf( "decodeNumber+\n" );
378410
debug(trace) scope(success) printf( "decodeNumber-\n" );
379411

380412
size_t val = 0;
381413

382-
foreach( c; num )
414+
foreach( char c; num )
383415
{
384416
import core.checkedint : mulu, addu;
385417

386418
bool overflow = false;
387419
val = mulu(val, 10, overflow);
420+
static if( term )
421+
if ( c >= term )
422+
c += '0' - term;
388423
val = addu(val, c - '0', overflow);
389424
if (overflow)
390425
error();
@@ -492,20 +527,53 @@ private struct Demangle
492527
debug(trace) printf( "parseLName+\n" );
493528
debug(trace) scope(success) printf( "parseLName-\n" );
494529

495-
auto n = decodeNumber();
496-
497-
if( !n || n > buf.length || n > buf.length - pos )
498-
error( "LName must be at least 1 character" );
499-
if( '_' != front && !isAlpha( front ) )
500-
error( "Invalid character in LName" );
501-
foreach(char e; buf[pos + 1 .. pos + n] )
530+
if( front == 'Q' )
531+
{
532+
// back reference to LName
533+
auto refPos = pos;
534+
popFront();
535+
char c = front;
536+
for( int n = 1; isDigit( c ); n++ )
537+
c = peek( n );
538+
bool hasDepth = ( c >= 'K' && c <= 'T' );
539+
size_t depth = 0;
540+
if( hasDepth )
541+
depth = decodeNumber!'K'();
542+
else if ( c < 'A' || c > 'J' )
543+
error( "invalid LName back reference" );
544+
545+
size_t n = decodeNumber!'A'();
546+
if ( !mute )
547+
{
548+
auto savePos = pos;
549+
scope(exit) pos = savePos;
550+
pos = refPos - n;
551+
for( size_t d = 0; d < depth; d++ )
552+
{
553+
parseSymbolName();
554+
parseFunctionType( true );
555+
put( '.' );
556+
}
557+
parseSymbolName();
558+
if (hasDepth)
559+
parseFunctionType( true );
560+
}
561+
}
562+
else
502563
{
503-
if( '_' != e && !isAlpha( e ) && !isDigit( e ) )
564+
auto n = decodeNumber();
565+
if( !n || n > buf.length || n > buf.length - pos )
566+
error( "LName must be at least 1 character" );
567+
if( '_' != front && !isAlpha( front ) )
504568
error( "Invalid character in LName" );
569+
foreach(char e; buf[pos + 1 .. pos + n] )
570+
{
571+
if( '_' != e && !isAlpha( e ) && !isDigit( e ) )
572+
error( "Invalid character in LName" );
573+
}
574+
put( buf[pos .. pos + n] );
575+
pos += n;
505576
}
506-
507-
put( buf[pos .. pos + n] );
508-
pos += n;
509577
}
510578

511579

@@ -715,6 +783,17 @@ private struct Demangle
715783

716784
switch( t )
717785
{
786+
case 'Q': // Type back reference
787+
auto refPos = pos;
788+
popFront();
789+
auto n = decodeNumber!'a'();
790+
if ( mute )
791+
return null;
792+
auto savePos = pos;
793+
scope(exit) pos = savePos;
794+
pos = refPos - n;
795+
auto ret = parseType();
796+
return ret;
718797
case 'O': // Shared (O Type)
719798
popFront();
720799
put( "shared(" );
@@ -1554,13 +1633,56 @@ private struct Demangle
15541633
len = t;
15551634
}
15561635
}
1636+
goto case;
1637+
case 'Q':
15571638
parseLName();
15581639
return;
15591640
default:
15601641
error();
15611642
}
15621643
}
15631644

1645+
void parseFunctionType( bool muteReturnType )
1646+
{
1647+
if( 'M' == front )
1648+
{
1649+
// do not emit "needs this"
1650+
popFront();
1651+
}
1652+
if( isCallConvention( front ) )
1653+
{
1654+
// try to demangle a function, in case we are pointing to some function local
1655+
auto prevpos = pos;
1656+
auto prevlen = len;
1657+
1658+
// we don't want calling convention and attributes in the qualified name
1659+
parseCallConvention();
1660+
parseFuncAttr();
1661+
len = prevlen;
1662+
1663+
put( '(' );
1664+
parseFuncArguments();
1665+
put( ')' );
1666+
if( !isSymbolNameFront() ) // voldemort types don't have a return type on the function
1667+
{
1668+
auto funclen = len;
1669+
1670+
bool prevMute = mute;
1671+
scope(exit) mute = prevMute;
1672+
mute = muteReturnType;
1673+
parseType();
1674+
1675+
if( !muteReturnType && !isSymbolNameFront() )
1676+
{
1677+
// not part of a qualified name, so back up
1678+
pos = prevpos;
1679+
len = prevlen;
1680+
}
1681+
else
1682+
len = funclen; // remove return type from qualified name
1683+
}
1684+
}
1685+
}
15641686

15651687
/*
15661688
QualifiedName:
@@ -1579,37 +1701,8 @@ private struct Demangle
15791701
if( n++ )
15801702
put( '.' );
15811703
parseSymbolName();
1582-
1583-
if( isCallConvention( front ) )
1584-
{
1585-
// try to demangle a function, in case we are pointing to some function local
1586-
auto prevpos = pos;
1587-
auto prevlen = len;
1588-
1589-
// we don't want calling convention and attributes in the qualified name
1590-
parseCallConvention();
1591-
parseFuncAttr();
1592-
len = prevlen;
1593-
1594-
put( '(' );
1595-
parseFuncArguments();
1596-
put( ')' );
1597-
if( !isDigit( front ) && front != '_' ) // voldemort types don't have a return type on the function
1598-
{
1599-
auto funclen = len;
1600-
parseType();
1601-
1602-
if( !isDigit( front ) && front != '_' )
1603-
{
1604-
// not part of a qualified name, so back up
1605-
pos = prevpos;
1606-
len = prevlen;
1607-
}
1608-
else
1609-
len = funclen; // remove return type from qualified name
1610-
}
1611-
}
1612-
} while( isDigit( front ) || front == '_' );
1704+
parseFunctionType( false );
1705+
} while( isSymbolNameFront() );
16131706
return dst[beg .. len];
16141707
}
16151708

test/profile/both.def.exp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

22
FUNCTIONS
33
_Dmain
4-
_D4both3fooFkZPS4both3Num
5-
_D4both3Num6__ctorMFNckZS4both3Num
4+
both.Num* both.foo(uint)
5+
ref both.Num both.Num.__ctor(uint)

0 commit comments

Comments
 (0)