Skip to content

Commit 8149774

Browse files
committed
Demangler plugin API
Closes #467
1 parent 5353484 commit 8149774

File tree

19 files changed

+5547
-96
lines changed

19 files changed

+5547
-96
lines changed

binaryninjaapi.h

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,11 +1564,29 @@ namespace BinaryNinja {
15641564
*/
15651565
Ref<BinaryView> Load(Ref<BinaryView> rawData, bool updateAnalysis, std::function<bool(size_t, size_t)> progress, Ref<Metadata> options = new Metadata(MetadataType::KeyValueDataType), bool isDatabase = false);
15661566

1567+
/*! Attempt to demangle a mangled name, trying all relevant demanglers and using whichever one accepts it
1568+
1569+
\see Demangler::Demangle for a discussion on which demangler will be used.
1570+
1571+
\param[in] arch Architecture for the symbol. Required for pointer and integer sizes.
1572+
\param[in] mangledName a mangled Microsoft Visual Studio C++ name
1573+
\param[out] outType Pointer to Type to output
1574+
\param[out] outVarName QualifiedName reference to write the output name to.
1575+
\param[in] view (Optional) view of the binary containing the mangled name
1576+
\param[in] simplify (Optional) Whether to simplify demangled names.
1577+
\return True if the name was demangled and written to the out* parameters
1578+
1579+
\ingroup demangle
1580+
*/
1581+
bool DemangleGeneric(Ref<Architecture> arch, const std::string& mangledName, Ref<Type>& outType, QualifiedName& outVarName,
1582+
Ref<BinaryView> view = nullptr, const bool simplify = false);
1583+
15671584
/*! Demangles using LLVM's demangler
15681585

15691586
\param[in] mangledName a mangled (msvc/itanium/rust/dlang) name
15701587
\param[out] outVarName QualifiedName reference to write the output name to.
15711588
\param[in] simplify Whether to simplify demangled names.
1589+
\return True if the name was demangled and written to the out* parameters
15721590

15731591
\ingroup demangle
15741592
*/
@@ -1579,6 +1597,7 @@ namespace BinaryNinja {
15791597
\param[in] mangledName a mangled (msvc/itanium/rust/dlang) name
15801598
\param[out] outVarName QualifiedName reference to write the output name to.
15811599
\param[in] view View to check the analysis.types.templateSimplifier for
1600+
\return True if the name was demangled and written to the out* parameters
15821601

15831602
\ingroup demangle
15841603
*/
@@ -1591,6 +1610,7 @@ namespace BinaryNinja {
15911610
\param[out] outType Reference to Type to output
15921611
\param[out] outVarName QualifiedName reference to write the output name to.
15931612
\param[in] simplify Whether to simplify demangled names.
1613+
\return True if the name was demangled and written to the out* parameters
15941614

15951615
\ingroup demangle
15961616
*/
@@ -1607,6 +1627,7 @@ namespace BinaryNinja {
16071627
\param[out] outType Reference to Type to output
16081628
\param[out] outVarName QualifiedName reference to write the output name to.
16091629
\param[in] view View to check the analysis.types.templateSimplifier for
1630+
\return True if the name was demangled and written to the out* parameters
16101631

16111632
\ingroup demangle
16121633
*/
@@ -1620,6 +1641,7 @@ namespace BinaryNinja {
16201641
\param[out] outType Reference to Type to output
16211642
\param[out] outVarName QualifiedName reference to write the output name to.
16221643
\param[in] simplify Whether to simplify demangled names.
1644+
\return True if the name was demangled and written to the out* parameters
16231645

16241646
\ingroup demangle
16251647
*/
@@ -1636,6 +1658,7 @@ namespace BinaryNinja {
16361658
\param[out] outType Reference to Type to output
16371659
\param[out] outVarName QualifiedName reference to write the output name to.
16381660
\param[in] view View to check the analysis.types.templateSimplifier for
1661+
\return True if the name was demangled and written to the out* parameters
16391662

16401663
\ingroup demangle
16411664
*/
@@ -17968,6 +17991,98 @@ namespace BinaryNinja {
1796817991
bool IsAborted();
1796917992
};
1797017993

17994+
/*!
17995+
\ingroup demangler
17996+
*/
17997+
class Demangler: public StaticCoreRefCountObject<BNDemangler>
17998+
{
17999+
std::string m_nameForRegister;
18000+
18001+
protected:
18002+
explicit Demangler(const std::string& name);
18003+
Demangler(BNDemangler* demangler);
18004+
virtual ~Demangler() = default;
18005+
18006+
static bool IsMangledStringCallback(void* ctxt, const char* name);
18007+
static bool DemangleCallback(void* ctxt, BNArchitecture* arch, const char* name, BNType** outType,
18008+
BNQualifiedName* outVarName, BNBinaryView* view);
18009+
static void FreeVarNameCallback(void* ctxt, BNQualifiedName* name);
18010+
18011+
public:
18012+
/*! Register a custom Demangler. Newly registered demanglers will get priority over
18013+
previously registered demanglers and built-in demanglers.
18014+
*/
18015+
static void Register(Demangler* demangler);
18016+
18017+
/*! Get the list of currently registered demanglers, sorted by lowest to highest priority.
18018+
18019+
\return List of demanglers
18020+
*/
18021+
static std::vector<Ref<Demangler>> GetList();
18022+
static Ref<Demangler> GetByName(const std::string& name);
18023+
18024+
/*! Promote a demangler to the highest-priority position.
18025+
18026+
\param demangler Demangler to promote
18027+
*/
18028+
static void Promote(Ref<Demangler> demangler);
18029+
18030+
std::string GetName() const;
18031+
18032+
/*! Determine if a given name is mangled and this demangler can process it
18033+
18034+
The most recently registered demangler that claims a name is a mangled string
18035+
(returns true from this function), and then returns a value from Demangle will
18036+
determine the result of a call to DemangleGeneric. Returning True from this
18037+
does not require the demangler to succeed the call to Demangle, but simply
18038+
implies that it may succeed.
18039+
18040+
\param name Raw mangled name string
18041+
\return True if the demangler thinks it can handle the name
18042+
*/
18043+
virtual bool IsMangledString(const std::string& name) = 0;
18044+
18045+
/*! Demangle a raw name into a Type and QualifiedName.
18046+
18047+
Any unresolved named types referenced by the resulting Type will be created as
18048+
empty structures or void typedefs in the view, if the result is used on
18049+
a data structure in the view. Given this, the call to Demangle should NOT
18050+
cause any side-effects creating types in the view trying to resolve this
18051+
and instead just return a type with unresolved named type references.
18052+
18053+
The most recently registered demangler that claims a name is a mangled string
18054+
(returns true from IsMangledString), and then returns a value from
18055+
this function will determine the result of a call to DemangleGeneric.
18056+
If this call returns None, the next most recently used demangler(s) will be tried instead.
18057+
18058+
If the mangled name has no type information, but a name is still possible to extract,
18059+
this function may return a successful result with outType=nullptr, which will be accepted.
18060+
18061+
\param arch Architecture for context in which the name exists, eg for pointer sizes
18062+
\param name Raw mangled name
18063+
\param outType Resulting type, if one can be deduced, will be written here. Otherwise nullptr will be written
18064+
\param outVarName Resulting variable name
18065+
\param view (Optional) BinaryView context in which the name exists, eg for type lookup
18066+
\return True if demangling was successful and results were stored into out-parameters
18067+
*/
18068+
virtual bool Demangle(Ref<Architecture> arch, const std::string& name, Ref<Type>& outType,
18069+
QualifiedName& outVarName, Ref<BinaryView> view = nullptr) = 0;
18070+
};
18071+
18072+
/*!
18073+
\ingroup demangler
18074+
*/
18075+
class CoreDemangler: public Demangler
18076+
{
18077+
public:
18078+
CoreDemangler(BNDemangler* demangler);
18079+
virtual ~CoreDemangler() = default;
18080+
18081+
virtual bool IsMangledString(const std::string& name);
18082+
virtual bool Demangle(Ref<Architecture> arch, const std::string& name, Ref<Type>& outType,
18083+
QualifiedName& outVarName, Ref<BinaryView> view);
18084+
};
18085+
1797118086
namespace Unicode
1797218087
{
1797318088
std::string UTF16ToUTF8(const uint8_t* utf16, const size_t len);

binaryninjacore.h

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ extern "C"
297297
typedef struct BNCollaborationLazyT BNCollaborationLazyT;
298298
typedef struct BNUndoAction BNUndoAction;
299299
typedef struct BNUndoEntry BNUndoEntry;
300+
typedef struct BNDemangler BNDemangler;
300301

301302
//! Console log levels
302303
typedef enum BNLogLevel
@@ -3323,6 +3324,15 @@ extern "C"
33233324
void (*freeConflictList)(void* context, BNAnalysisMergeConflict** conflictList, size_t count);
33243325
} BNAnalysisMergeConflictSplitterCallbacks;
33253326

3327+
typedef struct BNDemanglerCallbacks
3328+
{
3329+
void* context;
3330+
bool (*isMangledString)(void* ctxt, const char* name);
3331+
bool (*demangle)(void* ctxt, BNArchitecture* arch, const char* name, BNType** outType,
3332+
BNQualifiedName* outVarName, BNBinaryView* view);
3333+
void (*freeVarName)(void* ctxt, BNQualifiedName* name);
3334+
} BNDemanglerCallbacks;
3335+
33263336
typedef bool(*BNProgressFunction)(void*, size_t, size_t);
33273337
typedef bool(*BNCollaborationAnalysisConflictHandler)(void*, const char** keys, BNAnalysisMergeConflict** conflicts, size_t conflictCount);
33283338
typedef bool(*BNCollaborationNameChangesetFunction)(void*, BNCollaborationChangeset*);
@@ -6546,14 +6556,6 @@ extern "C"
65466556
BINARYNINJACOREAPI BNTypeLibrary** BNGetPlatformTypeLibrariesByName(
65476557
BNPlatform* platform, const char* depName, size_t* count);
65486558

6549-
// Demangler
6550-
BINARYNINJACOREAPI bool BNDemangleMS(BNArchitecture* arch, const char* mangledName, BNType** outType,
6551-
char*** outVarName, size_t* outVarNameElements, const bool simplify);
6552-
BINARYNINJACOREAPI bool BNDemangleMSWithOptions(BNArchitecture* arch, const char* mangledName, BNType** outType,
6553-
char*** outVarName, size_t* outVarNameElements, const BNBinaryView* const view);
6554-
BINARYNINJACOREAPI bool BNDemangleMSPlatform(BNPlatform* platform, const char* mangledName, BNType** outType,
6555-
char*** outVarName, size_t* outVarNameElements, const bool simplify);
6556-
65576559
// Download providers
65586560
BINARYNINJACOREAPI BNDownloadProvider* BNRegisterDownloadProvider(
65596561
const char* name, BNDownloadProviderCallbacks* callbacks);
@@ -6748,6 +6750,14 @@ extern "C"
67486750
BNReportCollection* reports, BNBinaryView* view, const char* title, BNFlowGraph* graph);
67496751
BINARYNINJACOREAPI void BNUpdateReportFlowGraph(BNReportCollection* reports, size_t i, BNFlowGraph* graph);
67506752

6753+
// Demangler
6754+
BINARYNINJACOREAPI bool BNDemangleMS(BNArchitecture* arch, const char* mangledName, BNType** outType,
6755+
char*** outVarName, size_t* outVarNameElements, const bool simplify);
6756+
BINARYNINJACOREAPI bool BNDemangleMSWithOptions(BNArchitecture* arch, const char* mangledName, BNType** outType,
6757+
char*** outVarName, size_t* outVarNameElements, const BNBinaryView* const view);
6758+
BINARYNINJACOREAPI bool BNDemangleMSPlatform(BNPlatform* platform, const char* mangledName, BNType** outType,
6759+
char*** outVarName, size_t* outVarNameElements, const bool simplify);
6760+
67516761
BINARYNINJACOREAPI bool BNIsGNU3MangledString(const char* mangledName);
67526762
BINARYNINJACOREAPI bool BNDemangleGNU3(BNArchitecture* arch, const char* mangledName, BNType** outType,
67536763
char*** outVarName, size_t* outVarNameElements, const bool simplify);
@@ -6756,11 +6766,24 @@ extern "C"
67566766
BINARYNINJACOREAPI void BNFreeDemangledName(char*** name, size_t nameElements);
67576767

67586768
BINARYNINJACOREAPI bool BNDemangleLLVM(const char* mangledName,
6759-
char*** outVarName, size_t* outVarNameElements, const bool simplify);
6769+
char*** outVarName, size_t* outVarNameElements, const bool simplify);
67606770
BINARYNINJACOREAPI bool BNDemangleLLVMWithOptions(const char* mangledName,
6761-
char*** outVarName, size_t* outVarNameElements, const BNBinaryView* const view);
6771+
char*** outVarName, size_t* outVarNameElements, const BNBinaryView* const view);
6772+
6773+
BINARYNINJACOREAPI BNDemangler* BNRegisterDemangler(const char* name, BNDemanglerCallbacks* callbacks);
6774+
BINARYNINJACOREAPI BNDemangler** BNGetDemanglerList(size_t* count);
6775+
BINARYNINJACOREAPI void BNFreeDemanglerList(BNDemangler** demanglers);
6776+
BINARYNINJACOREAPI BNDemangler* BNGetDemanglerByName(const char* name);
6777+
BINARYNINJACOREAPI char* BNGetDemanglerName(BNDemangler* demangler);
6778+
BINARYNINJACOREAPI void BNPromoteDemangler(BNDemangler* demangler);
6779+
6780+
BINARYNINJACOREAPI bool BNIsDemanglerMangledName(BNDemangler* demangler, const char* name);
6781+
BINARYNINJACOREAPI bool BNDemanglerDemangle(BNDemangler* demangler, BNArchitecture* arch, const char* name,
6782+
BNType** outType, BNQualifiedName* outVarName, BNBinaryView* view);
6783+
BINARYNINJACOREAPI bool BNDemangleGeneric(BNArchitecture* arch, const char* name,
6784+
BNType** outType, BNQualifiedName* outVarName, BNBinaryView* view, bool simplify);
67626785

6763-
// Plugin repository APIs
6786+
// Plugin repository APIs
67646787
BINARYNINJACOREAPI char** BNPluginGetApis(BNRepoPlugin* p, size_t* count);
67656788
BINARYNINJACOREAPI const char* BNPluginGetAuthor(BNRepoPlugin* p);
67666789
BINARYNINJACOREAPI const char* BNPluginGetDescription(BNRepoPlugin* p);

demangle.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
11
#include "binaryninjaapi.h"
22
#include <string>
33
using namespace std;
4+
using namespace BinaryNinja;
45

56
namespace BinaryNinja {
7+
bool DemangleGeneric(Ref<Architecture> arch, const std::string& name, Ref<Type>& outType,
8+
QualifiedName& outVarName, Ref<BinaryView> view, bool simplify)
9+
{
10+
BNType* apiType;
11+
BNQualifiedName apiVarName;
12+
bool success = BNDemangleGeneric(
13+
arch->m_object, name.c_str(), &apiType, &apiVarName, view ? view->m_object : nullptr, simplify);
14+
15+
if (!success)
16+
return false;
17+
18+
if (apiType)
19+
outType = new Type(apiType);
20+
outVarName = QualifiedName::FromAPIObject(&apiVarName);
21+
BNFreeQualifiedName(&apiVarName);
22+
return true;
23+
}
24+
625
bool DemangleLLVM(const std::string& mangledName, QualifiedName& outVarName,
726
BinaryView* view)
827
{
@@ -109,4 +128,120 @@ namespace BinaryNinja {
109128
BNFreeQualifiedName(&name);
110129
return result;
111130
}
131+
132+
Demangler::Demangler(const std::string& name): m_nameForRegister(name)
133+
{
134+
}
135+
136+
Demangler::Demangler(BNDemangler* demangler)
137+
{
138+
m_object = demangler;
139+
}
140+
141+
bool Demangler::IsMangledStringCallback(void* ctxt, const char* name)
142+
{
143+
Demangler* demangler = (Demangler*)ctxt;
144+
return demangler->IsMangledString(name);
145+
}
146+
147+
bool Demangler::DemangleCallback(void* ctxt, BNArchitecture* arch, const char* name, BNType** outType,
148+
BNQualifiedName* outVarName, BNBinaryView* view)
149+
{
150+
Demangler* demangler = (Demangler*)ctxt;
151+
152+
Ref<Architecture> apiArch = new CoreArchitecture(arch);
153+
Ref<BinaryView> apiView = view ? new BinaryView(BNNewViewReference(view)) : nullptr;
154+
155+
Ref<Type> apiType;
156+
QualifiedName apiVarName;
157+
bool success = demangler->Demangle(apiArch, name, apiType, apiVarName, apiView);
158+
if (!success)
159+
return false;
160+
161+
if (apiType)
162+
{
163+
*outType = BNNewTypeReference(apiType->m_object);
164+
}
165+
else
166+
{
167+
*outType = nullptr;
168+
}
169+
*outVarName = apiVarName.GetAPIObject();
170+
171+
return true;
172+
}
173+
174+
void Demangler::FreeVarNameCallback(void* ctxt, BNQualifiedName* name)
175+
{
176+
QualifiedName::FreeAPIObject(name);
177+
}
178+
179+
void Demangler::Register(Demangler* demangler)
180+
{
181+
BNDemanglerCallbacks cb;
182+
cb.context = (void*)demangler;
183+
cb.isMangledString = IsMangledStringCallback;
184+
cb.demangle = DemangleCallback;
185+
cb.freeVarName = FreeVarNameCallback;
186+
demangler->m_object = BNRegisterDemangler(demangler->m_nameForRegister.c_str(), &cb);
187+
}
188+
189+
std::vector<Ref<Demangler>> Demangler::GetList()
190+
{
191+
size_t count;
192+
BNDemangler** list = BNGetDemanglerList(&count);
193+
vector<Ref<Demangler>> result;
194+
for (size_t i = 0; i < count; i++)
195+
result.push_back(new CoreDemangler(list[i]));
196+
BNFreeDemanglerList(list);
197+
return result;
198+
}
199+
200+
Ref<Demangler> Demangler::GetByName(const std::string& name)
201+
{
202+
BNDemangler* result = BNGetDemanglerByName(name.c_str());
203+
if (!result)
204+
return nullptr;
205+
return new CoreDemangler(result);
206+
}
207+
208+
void Demangler::Promote(Ref<Demangler> demangler)
209+
{
210+
BNPromoteDemangler(demangler->m_object);
211+
}
212+
213+
std::string Demangler::GetName() const
214+
{
215+
char* name = BNGetDemanglerName(m_object);
216+
std::string value = name;
217+
BNFreeString(name);
218+
return value;
219+
}
220+
221+
CoreDemangler::CoreDemangler(BNDemangler* demangler): Demangler(demangler)
222+
{
223+
}
224+
225+
bool CoreDemangler::IsMangledString(const std::string& name)
226+
{
227+
return BNIsDemanglerMangledName(m_object, name.c_str());
228+
}
229+
230+
bool CoreDemangler::Demangle(Ref<Architecture> arch, const std::string& name, Ref<Type>& outType,
231+
QualifiedName& outVarName, Ref<BinaryView> view)
232+
{
233+
BNType* apiType;
234+
BNQualifiedName apiVarName;
235+
bool success = BNDemanglerDemangle(
236+
m_object, arch->m_object, name.c_str(), &apiType, &apiVarName, view ? view->m_object : nullptr);
237+
238+
if (!success)
239+
return false;
240+
241+
if (apiType)
242+
outType = new Type(apiType);
243+
outVarName = QualifiedName::FromAPIObject(&apiVarName);
244+
BNFreeQualifiedName(&apiVarName);
245+
return true;
246+
}
112247
} // namespace BinaryNinja

0 commit comments

Comments
 (0)