Skip to content

Commit 6b58d2e

Browse files
committed
Ensure demangling recovers calling convention correctly
1 parent 6ece569 commit 6b58d2e

10 files changed

Lines changed: 157 additions & 38 deletions

File tree

demangle.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,19 @@ namespace BinaryNinja {
4747
bool DemangleMS(Architecture* arch, const std::string& mangledName, Ref<Type>& outType, QualifiedName& outVarName,
4848
BinaryView* view)
4949
{
50-
const bool simplify = Settings::Instance()->Get<bool>("analysis.types.templateSimplifier", view);
51-
return DemangleMS(arch, mangledName, outType, outVarName, simplify);
50+
BNType* localType = nullptr;
51+
char** localVarName = nullptr;
52+
size_t localSize = 0;
53+
if (!BNDemangleMSWithOptions(arch->GetObject(), mangledName.c_str(), &localType, &localVarName, &localSize,
54+
view ? view->GetObject() : nullptr))
55+
return false;
56+
outType = localType ? new Type(localType) : nullptr;
57+
for (size_t i = 0; i < localSize; i++)
58+
{
59+
outVarName.push_back(localVarName[i]);
60+
}
61+
BNFreeDemangledName(&localVarName, localSize);
62+
return true;
5263
}
5364

5465
bool DemangleMS(Architecture* arch, const std::string& mangledName, Ref<Type>& outType, QualifiedName& outVarName,

demangler/gnu3/demangled_type_node.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ DemangledTypeNode::DemangledTypeNode()
8484
: m_typeClass(VoidTypeClass), m_ntrClass(UnknownNamedTypeClass),
8585
m_pointerReference(PointerReferenceType), m_nameType(NoNameType),
8686
m_callingConventionName(NoCallingConvention), m_pointerSuffixBits(0),
87-
m_returnTypeConfidence(BN_DEFAULT_CONFIDENCE),
87+
m_returnTypeConfidence(BN_FULL_CONFIDENCE),
8888
m_const(false), m_volatile(false), m_signed(false), m_hasVariableArgs(false),
8989
m_hasTemplateArgs(false), m_width(0),
9090
m_isMemberPointer(false),
@@ -703,8 +703,11 @@ Ref<Type> DemangledTypeNode::Finalize() const
703703
Ref<Type> pType = p.type ? p.type->Finalize() : Ref<Type>(Type::VoidType());
704704
finalParams.push_back({p.name, pType, true, Variable()});
705705
}
706+
Confidence<Ref<CallingConvention>> callingConvention;
707+
if (m_callingConvention)
708+
callingConvention = Confidence<Ref<CallingConvention>>(m_callingConvention, BN_FULL_CONFIDENCE);
706709
TypeBuilder tb = TypeBuilder::FunctionType(
707-
retType->WithConfidence(static_cast<uint8_t>(m_returnTypeConfidence)), nullptr, finalParams,
710+
retType->WithConfidence(static_cast<uint8_t>(m_returnTypeConfidence)), callingConvention, finalParams,
708711
Confidence<bool>(m_hasVariableArgs, m_hasVariableArgs ? BN_DEFAULT_CONFIDENCE : 0));
709712
tb.SetConst(m_const);
710713
tb.SetVolatile(m_volatile);

demangler/gnu3/demangled_type_node.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class DemangledTypeNode
111111
void AddPointerSuffix(BNPointerSuffix ps) { m_pointerSuffixBits |= PointerSuffixBit(ps); }
112112
void SetReturnTypeConfidence(int8_t c) { m_returnTypeConfidence = c; }
113113
void SetCallingConventionName(BNCallingConventionName cc) { m_callingConventionName = cc; }
114+
void SetCallingConvention(BN::Ref<BN::CallingConvention> cc) { m_callingConvention = std::move(cc); }
114115
void SetNTRType(BNNamedTypeReferenceClass cls) { m_ntrClass = cls; }
115116
void SetImplicitThisParameter(DemangledTypeNode type);
116117

@@ -129,6 +130,7 @@ class DemangledTypeNode
129130
BNReferenceType m_pointerReference;
130131
BNNameType m_nameType;
131132
BNCallingConventionName m_callingConventionName;
133+
BN::Ref<BN::CallingConvention> m_callingConvention;
132134
uint8_t m_pointerSuffixBits;
133135
uint8_t m_returnTypeConfidence;
134136
bool m_const;

demangler/msvc/demangle_msvc.cpp

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,6 +1914,38 @@ BNCallingConventionName Demangle::DemangleCallingConvention()
19141914
}
19151915

19161916

1917+
Ref<CallingConvention> Demangle::ResolveCallingConvention(BNCallingConventionName cc) const
1918+
{
1919+
switch (cc)
1920+
{
1921+
case CdeclCallingConvention:
1922+
if (m_platform && m_platform->GetCdeclCallingConvention())
1923+
return m_platform->GetCdeclCallingConvention();
1924+
if (m_arch && m_arch->GetCdeclCallingConvention())
1925+
return m_arch->GetCdeclCallingConvention();
1926+
return m_arch ? m_arch->GetCallingConventionByName("cdecl") : nullptr;
1927+
case STDCallCallingConvention:
1928+
if (m_platform && m_platform->GetStdcallCallingConvention())
1929+
return m_platform->GetStdcallCallingConvention();
1930+
if (m_arch && m_arch->GetStdcallCallingConvention())
1931+
return m_arch->GetStdcallCallingConvention();
1932+
return m_arch ? m_arch->GetCallingConventionByName("stdcall") : nullptr;
1933+
case FastcallCallingConvention:
1934+
if (m_platform && m_platform->GetFastcallCallingConvention())
1935+
return m_platform->GetFastcallCallingConvention();
1936+
if (m_arch && m_arch->GetFastcallCallingConvention())
1937+
return m_arch->GetFastcallCallingConvention();
1938+
return m_arch ? m_arch->GetCallingConventionByName("fastcall") : nullptr;
1939+
case ThisCallCallingConvention:
1940+
if (m_arch)
1941+
return m_arch->GetCallingConventionByName("thiscall");
1942+
return nullptr;
1943+
default:
1944+
return nullptr;
1945+
}
1946+
}
1947+
1948+
19171949
void Demangle::ConsumeExtendedModifierPrefix()
19181950
{
19191951
while (reader.PeekMatch("$A", 2))
@@ -2112,25 +2144,10 @@ DemangledTypeNode Demangle::DemangleFunction(BNNameType classFunctionType, bool
21122144

21132145
MSVC_TRACE("\tDemangle Function Parameters %s", reader.GetRaw());
21142146
vector<DemangledTypeNode::Param> params;
2115-
bool needsThisPtr = false;
2116-
if (includeImplicitThis && cc == ThisCallCallingConvention)
2117-
{
2118-
needsThisPtr = true;
2119-
}
2120-
if (includeImplicitThis && funcClass != NoneFunctionClass)
2121-
{
2122-
if ((funcClass & VirtualFunctionClass) == VirtualFunctionClass
2123-
|| (funcClass & StaticThunkFunctionClass) == StaticThunkFunctionClass
2124-
|| (funcClass & VirtualThunkFunctionClass) == VirtualThunkFunctionClass)
2125-
{
2126-
needsThisPtr = true;
2127-
}
2128-
else if ((funcClass & StaticFunctionClass) != StaticFunctionClass
2129-
&& (funcClass & GlobalFunctionClass) != GlobalFunctionClass)
2130-
{
2131-
needsThisPtr = true;
2132-
}
2133-
}
2147+
bool needsThisPtr = includeImplicitThis
2148+
&& funcClass != NoneFunctionClass
2149+
&& (funcClass & StaticFunctionClass) != StaticFunctionClass
2150+
&& (funcClass & GlobalFunctionClass) != GlobalFunctionClass;
21342151

21352152
DemangleVariableList(params, nameBackrefList);
21362153

@@ -2145,12 +2162,14 @@ DemangledTypeNode Demangle::DemangleFunction(BNNameType classFunctionType, bool
21452162
newType.SetPointerSuffixBits(suffix);
21462163
newType.SetNameType(classFunctionType);
21472164
newType.SetCallingConventionName(cc);
2165+
if (auto callingConvention = ResolveCallingConvention(cc))
2166+
newType.SetCallingConvention(callingConvention);
21482167
if (needsThisPtr)
21492168
{
21502169
NameList thisName = m_varName;
21512170
if (classFunctionType != OperatorReturnTypeNameType && !thisName.empty())
21522171
thisName.pop_back();
2153-
auto thisNamedType = DemangledTypeNode::NamedType(UnknownNamedTypeClass, std::move(thisName));
2172+
auto thisNamedType = DemangledTypeNode::NamedType(TypedefNamedTypeClass, std::move(thisName));
21542173
newType.SetImplicitThisParameter(DemangledTypeNode::PointerType(
21552174
m_arch, std::move(thisNamedType), false, false, PointerReferenceType));
21562175
}
@@ -2516,6 +2535,8 @@ bool Demangle::DemangleMS(Architecture* arch, const string& mangledName, Ref<Typ
25162535
outType = nullptr;
25172536
if (mangledName.empty() || (mangledName[0] != '?' && mangledName[0] != '.'))
25182537
return false;
2538+
if (view)
2539+
return DemangleMS(mangledName, outType, outVarName, view);
25192540
return DemangleMS(arch, mangledName, outType, outVarName);
25202541
}
25212542

@@ -2525,9 +2546,32 @@ bool Demangle::DemangleMS(Architecture* arch, const string& mangledName, Ref<Typ
25252546
outType = nullptr;
25262547
if (mangledName.empty() || (mangledName[0] != '?' && mangledName[0] != '.'))
25272548
return false;
2549+
if (view)
2550+
return DemangleMS(mangledName, outType, outVarName, Ref<BinaryView>(view));
25282551
return DemangleMS(arch, mangledName, outType, outVarName);
25292552
}
25302553

2554+
bool Demangle::DemangleMS(Platform* platform, const string& mangledName, Ref<Type>& outType,
2555+
QualifiedName& outVarName)
2556+
{
2557+
outType = nullptr;
2558+
if (!platform || mangledName.empty() || (mangledName[0] != '?' && mangledName[0] != '.'))
2559+
return false;
2560+
try
2561+
{
2562+
Demangle demangle(Ref<Platform>(platform), mangledName);
2563+
auto result = demangle.Finalize();
2564+
outType = std::move(result.first);
2565+
outVarName = std::move(result.second);
2566+
}
2567+
catch (DemangleException &e)
2568+
{
2569+
LogDebugForException(e, "Demangling Failed '%s' '%s;", mangledName.c_str(), e.what());
2570+
return false;
2571+
}
2572+
return true;
2573+
}
2574+
25312575
bool Demangle::DemangleMS(Architecture* arch, const string& mangledName, Ref<Type>& outType,
25322576
QualifiedName& outVarName)
25332577
{
@@ -2573,6 +2617,15 @@ bool Demangle::DemangleMS(const string& mangledName, Ref<Type>& outType,
25732617
return true;
25742618
}
25752619

2620+
bool Demangle::DemangleMS(const string& mangledName, Ref<Type>& outType,
2621+
QualifiedName& outVarName, BinaryView* view)
2622+
{
2623+
outType = nullptr;
2624+
if (!view)
2625+
return false;
2626+
return DemangleMS(mangledName, outType, outVarName, Ref<BinaryView>(view));
2627+
}
2628+
25762629

25772630
class MSDemangler: public Demangler
25782631
{

demangler/msvc/demangle_msvc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ class Demangle
234234
BackrefList& nameBackrefList,
235235
bool typeNameContext = false);
236236
BNCallingConventionName DemangleCallingConvention();
237+
BN::Ref<BN::CallingConvention> ResolveCallingConvention(BNCallingConventionName cc) const;
237238
void ConsumeExtendedModifierPrefix();
238239
DemangledTypeNode DemangleFunction(BNNameType classFunctionType, bool pointerSuffix, BackrefList& varList,
239240
int funcClass = NoneFunctionClass, bool includeImplicitThis = true);
@@ -266,6 +267,8 @@ class Demangle
266267
BN::QualifiedName& outVarName, const BN::Ref<BN::BinaryView>& view);
267268
static bool DemangleMS(BN::Architecture* arch, const _STD_STRING& mangledName, BN::Ref<BN::Type>& outType,
268269
BN::QualifiedName& outVarName, BN::BinaryView* view);
270+
static bool DemangleMS(BN::Platform* platform, const _STD_STRING& mangledName, BN::Ref<BN::Type>& outType,
271+
BN::QualifiedName& outVarName);
269272
static bool DemangleMS(BN::Architecture* arch, const _STD_STRING& mangledName, BN::Ref<BN::Type>& outType,
270273
BN::QualifiedName& outVarName);
271274

plugins/pdb-ng/src/symbol_parser.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use crate::PDBParserInstance;
3939
use binaryninja::architecture::{Architecture, ArchitectureExt, Register, RegisterId};
4040
use binaryninja::binary_view::BinaryViewBase;
4141
use binaryninja::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
42-
use binaryninja::demangle::demangle_ms;
42+
use binaryninja::demangle::demangle_ms_with_view;
4343
use binaryninja::rc::Ref;
4444
use binaryninja::types::{FunctionParameter, QualifiedName, StructureBuilder, Type, TypeClass};
4545
use binaryninja::variable::{Variable, VariableSourceType};
@@ -1820,7 +1820,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
18201820
raw_name: &String,
18211821
rva: Rva,
18221822
) -> Result<(Option<Conf<Ref<Type>>>, Option<QualifiedName>)> {
1823-
let (mut t, mut name) = match demangle_ms(&self.arch, raw_name, true) {
1823+
let (mut t, mut name) = match demangle_ms_with_view(&self.arch, raw_name, Some(self.bv)) {
18241824
Some((name, Some(t))) => (Some(Conf::new(t, DEMANGLE_CONFIDENCE)), name),
18251825
Some((name, _)) => (None, name),
18261826
_ => (None, QualifiedName::new(vec![raw_name.clone()])),

plugins/rtti/rtti.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33
using namespace BinaryNinja;
44
using namespace BinaryNinja::RTTI;
55

6+
namespace
7+
{
8+
std::string NormalizeRTTIClassName(std::string name)
9+
{
10+
size_t beginFind = name.find_first_of(' ');
11+
if (beginFind != std::string::npos)
12+
name.erase(0, beginFind + 1);
13+
size_t endFind = name.find(" `RTTI Type Descriptor Name'");
14+
if (endFind != std::string::npos)
15+
name.erase(endFind, name.length());
16+
return name;
17+
}
18+
}
19+
620

721
Ref<Symbol> RTTI::GetRealSymbol(BinaryView *view, uint64_t relocAddr, uint64_t symAddr)
822
{
@@ -24,9 +38,9 @@ std::optional<std::string> RTTI::DemangleNameMS(BinaryView* view, bool allowMang
2438
{
2539
QualifiedName demangledName = {};
2640
Ref<Type> outType = {};
27-
if (!DemangleMS(view->GetDefaultArchitecture(), mangledName, outType, demangledName, true))
41+
if (!DemangleMS(view->GetDefaultArchitecture(), mangledName, outType, demangledName, view))
2842
return DemangleNameLLVM(allowMangled, mangledName);
29-
return demangledName.GetString();
43+
return NormalizeRTTIClassName(demangledName.GetString());
3044
}
3145

3246

@@ -90,14 +104,7 @@ std::optional<std::string> RTTI::DemangleNameLLVM(bool allowMangled, const std::
90104
Ref<Type> outType = {};
91105
if (!DemangleLLVM(mangledName, demangledName, true))
92106
return allowMangled ? std::optional(mangledName) : std::nullopt;
93-
auto demangledNameStr = demangledName.GetString();
94-
size_t beginFind = demangledNameStr.find_first_of(' ');
95-
if (beginFind != std::string::npos)
96-
demangledNameStr.erase(0, beginFind + 1);
97-
size_t endFind = demangledNameStr.find(" `RTTI Type Descriptor Name'");
98-
if (endFind != std::string::npos)
99-
demangledNameStr.erase(endFind, demangledNameStr.length());
100-
return demangledNameStr;
107+
return NormalizeRTTIClassName(demangledName.GetString());
101108
}
102109

103110

rust/src/demangle.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,46 @@ pub fn demangle_ms(
165165
}
166166
}
167167

168+
pub fn demangle_ms_with_view(
169+
arch: &CoreArchitecture,
170+
mangled_name: &str,
171+
view: Option<&BinaryView>,
172+
) -> Option<(QualifiedName, Option<Ref<Type>>)> {
173+
let mangled_name = mangled_name.to_cstr();
174+
let mut out_type: *mut BNType = std::ptr::null_mut();
175+
let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut();
176+
let mut out_size: usize = 0;
177+
let res = unsafe {
178+
BNDemangleMSWithOptions(
179+
arch.handle,
180+
mangled_name.as_ptr(),
181+
&mut out_type,
182+
&mut out_name,
183+
&mut out_size,
184+
view.map(|v| v.handle).unwrap_or(std::ptr::null_mut()),
185+
)
186+
};
187+
188+
match res {
189+
true => {
190+
assert!(!out_name.is_null());
191+
let names: Vec<_> = unsafe { ArrayGuard::<BnString>::new(out_name, out_size, ()) }
192+
.iter()
193+
.map(str::to_string)
194+
.collect();
195+
unsafe { BNFreeDemangledName(&mut out_name, out_size) };
196+
197+
let out_type = match out_type.is_null() {
198+
true => None,
199+
false => Some(unsafe { Type::ref_from_raw(out_type) }),
200+
};
201+
202+
Some((names.into(), out_type))
203+
}
204+
false => None,
205+
}
206+
}
207+
168208
#[derive(PartialEq, Eq, Hash)]
169209
pub struct Demangler {
170210
pub(crate) handle: *mut BNDemangler,

view/pe/coffview.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ void COFFView::AddCOFFSymbol(BNSymbolType type, const string& dll, const string&
15311531
{
15321532
QualifiedName demangledName;
15331533
Ref<Type> demangledType;
1534-
if (DemangleGeneric(m_arch, rawName, demangledType, demangledName, nullptr, m_simplifyTemplates))
1534+
if (DemangleGeneric(m_arch, rawName, demangledType, demangledName, this, m_simplifyTemplates))
15351535
{
15361536
shortName = demangledName.GetString();
15371537
fullName = shortName;

view/pe/peview.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3562,7 +3562,7 @@ void PEView::AddPESymbol(BNSymbolType type, const string& dll, const string& nam
35623562
{
35633563
QualifiedName demangledName;
35643564
Ref<Type> demangledType;
3565-
if (DemangleGeneric(m_arch, rawName, demangledType, demangledName, nullptr, m_simplifyTemplates))
3565+
if (DemangleGeneric(m_arch, rawName, demangledType, demangledName, this, m_simplifyTemplates))
35663566
{
35673567
shortName = demangledName.GetString();
35683568
fullName = shortName;

0 commit comments

Comments
 (0)