Skip to content

Commit 74d2100

Browse files
plafosseclaude
andcommitted
GNU3 demangler: GR reference temporaries, u vendor types, $tlv$init, fL fix, decltype
- GR <object name> [<seq-id>] _: implement reference temporary special names - u <source-name> [<template-args>]: add vendor extended type in DemangleType - $tlv$init suffix: strip macOS thread-local init suffix before demangling, append it back to the resulting variable name - fL <level> p <CV> [<param>] _: allow out-of-range listNumber to fall through to the existing "fp" placeholder paths instead of throwing, fixing fL inside decltype return types where m_functionSubstitute is not yet populated - DT/Dt: wrap the demangled expression in decltype(...) instead of emitting raw Reduces failures on a 290k-symbol BN corpus from 119 to 14 (88% improvement). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5de9c9d commit 74d2100

1 file changed

Lines changed: 62 additions & 10 deletions

File tree

demangler/gnu3/demangle_gnu3.cpp

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,23 @@ DemangledTypeNode DemangleGNU3::DemangleType()
721721
substitute = true;
722722
break;
723723
}
724+
case 'u':
725+
{
726+
// Vendor extended type: u <source-name> [<template-args>]
727+
// e.g. u14__remove_cvref, u20__remove_reference_t
728+
string extName = DemangleSourceName();
729+
if (m_reader.Peek() == 'I')
730+
{
731+
m_reader.Consume();
732+
vector<string> targs;
733+
DemangleTemplateArgs(targs);
734+
if (!targs.empty())
735+
extName += GetTemplateString(targs);
736+
}
737+
type = CreateUnknownType(extName);
738+
substitute = true;
739+
break;
740+
}
724741
case 'v': type = DemangledTypeNode::VoidType(); break;
725742
case 'w': type = DemangledTypeNode::IntegerType(4, false, "wchar_t"); break; //TODO: verify
726743
case 'b': type = DemangledTypeNode::BoolType(); break;
@@ -786,7 +803,7 @@ DemangledTypeNode DemangleGNU3::DemangleType()
786803
}
787804
case 't':
788805
case 'T':
789-
type = CreateUnknownType(DemangleExpression());
806+
type = CreateUnknownType("decltype(" + DemangleExpression() + ")");
790807
if (m_reader.Read() != 'E')
791808
throw DemangleException();
792809
break;
@@ -1716,13 +1733,12 @@ string DemangleGNU3::DemangleExpression()
17161733
char elm;
17171734
if (elm2 == 'L')
17181735
{
1719-
// fL case requires a valid function substitute frame
1720-
if (m_functionSubstitute.size() == 0)
1721-
throw DemangleException();
1736+
// fL <L-1 num> p <CV> [<prm-2 num>] _
1737+
// When listNumber is out of range (e.g. fL used inside a decltype return
1738+
// type before function params are known), the fallback paths below produce
1739+
// a placeholder string "fp" / "fpN".
17221740
listNumber = DemangleNumber() + 1;
1723-
if (listNumber < 0 ||
1724-
(uint64_t)listNumber >= (uint64_t)m_functionSubstitute.size() ||
1725-
m_reader.Read() != 'p')
1741+
if (listNumber < 0 || m_reader.Read() != 'p')
17261742
throw DemangleException();
17271743
}
17281744
DemangleCVQualifiers(cnst, vltl, rstrct);
@@ -2334,9 +2350,24 @@ DemangledTypeNode DemangleGNU3::DemangleSymbol(QualifiedName& varName)
23342350
case 'A': //TODO hidden alias
23352351
LogWarn("Unsupported demangle type: hidden alias\n");
23362352
throw DemangleException();
2337-
case 'R': //TODO reference temporaries
2338-
LogWarn("Unsupported demangle type: reference temporary\n");
2339-
throw DemangleException();
2353+
case 'R': // GR <object name> [<seq-id>] _ # reference temporary
2354+
{
2355+
// <object name> is a <name> production (nested, local, or unscoped).
2356+
// For local names (Z prefix), DemangleLocalName consumes the trailing '_'
2357+
// as a zero-discriminator, so we only consume '_' if it's still present.
2358+
DemangledTypeNode nameNode = DemangleName();
2359+
// Consume optional base-36 seq-id (digits + uppercase A-Z) before '_'.
2360+
string seqId;
2361+
while (m_reader.Length() > 0 && m_reader.Peek() != '_')
2362+
seqId += m_reader.Read();
2363+
if (m_reader.Length() > 0)
2364+
m_reader.Consume(); // consume '_'
2365+
string result = "reference_temporary_for_" + nameNode.GetString();
2366+
if (!seqId.empty())
2367+
result += "[" + seqId + "]";
2368+
varName.push_back(result);
2369+
return DemangledTypeNode::NamedType(UnknownNamedTypeClass, varName);
2370+
}
23402371
case 'T': // transaction clone: GTt<encoding> (safe) or GTn<encoding> (non-safe)
23412372
{
23422373
// consume the 't' (transaction-safe) or 'n' (non-transaction-safe) qualifier
@@ -2889,6 +2920,27 @@ bool DemangleGNU3Static::DemangleStringGNU3(Architecture* arch, const string& na
28892920
}
28902921
}
28912922

2923+
// Handle macOS thread-local variable initializer suffix: $tlv$init
2924+
// E.g. __ZL9recursive$tlv$init -> demangle "__ZL9recursive" then annotate.
2925+
static const string tlvInitSuffix = "$tlv$init";
2926+
if (name.size() > tlvInitSuffix.size() &&
2927+
name.compare(name.size() - tlvInitSuffix.size(), tlvInitSuffix.size(), tlvInitSuffix) == 0)
2928+
{
2929+
string base = name.substr(0, name.size() - tlvInitSuffix.size());
2930+
Ref<Type> baseType;
2931+
QualifiedName baseName;
2932+
if (DemangleStringGNU3(arch, base, baseType, baseName))
2933+
{
2934+
outVarName = baseName;
2935+
if (outVarName.size() > 0)
2936+
outVarName[outVarName.size() - 1] += "$tlv$init";
2937+
else
2938+
outVarName.push_back("$tlv$init");
2939+
outType = baseType;
2940+
return true;
2941+
}
2942+
}
2943+
28922944
string encoding = name;
28932945
string header;
28942946
bool foundHeader = DemangleGlobalHeader(encoding, header);

0 commit comments

Comments
 (0)