// Copyright (c) 2015-2026 Vector 35 Inc
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
#include "binaryninjaapi.h"
using namespace std;
using namespace BinaryNinja;
Platform::Platform(BNPlatform* platform)
{
m_object = platform;
}
CorePlatform::CorePlatform(BNPlatform* platform) : Platform(platform) {}
Platform::Platform(Architecture* arch, const string& name)
{
BNCustomPlatform plat;
plat.context = this;
plat.init = InitCallback;
plat.viewInit = InitViewCallback;
plat.getGlobalRegisters = GetGlobalRegistersCallback;
plat.freeRegisterList = FreeRegisterListCallback;
plat.getAddressSize = GetAddressSizeCallback;
plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback;
plat.adjustTypeParserInput = AdjustTypeParserInputCallback;
plat.freeTypeParserInput = FreeTypeParserInputCallback;
plat.getFallbackEnabled = GetFallbackEnabledCallback;
m_object = BNCreateCustomPlatform(arch->GetObject(), name.c_str(), &plat);
AddRefForRegistration();
}
Platform::Platform(Architecture* arch, const string& name, const string& typeFile, const vector& includeDirs)
{
BNCustomPlatform plat;
plat.context = this;
plat.init = InitCallback;
plat.viewInit = InitViewCallback;
plat.getGlobalRegisters = GetGlobalRegistersCallback;
plat.freeRegisterList = FreeRegisterListCallback;
plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback;
plat.getAddressSize = GetAddressSizeCallback;
plat.adjustTypeParserInput = AdjustTypeParserInputCallback;
plat.freeTypeParserInput = FreeTypeParserInputCallback;
plat.getFallbackEnabled = GetFallbackEnabledCallback;
const char** includeDirList = new const char*[includeDirs.size()];
for (size_t i = 0; i < includeDirs.size(); i++)
includeDirList[i] = includeDirs[i].c_str();
m_object = BNCreateCustomPlatformWithTypes(
arch->GetObject(), name.c_str(), &plat,
typeFile.c_str(), includeDirList, includeDirs.size());
delete[] includeDirList;
AddRefForRegistration();
}
void Platform::InitCallback(void* ctxt, BNPlatform* plat)
{
}
void Platform::InitViewCallback(void* ctxt, BNBinaryView* view)
{
CallbackRef plat(ctxt);
Ref viewObj = new BinaryView(BNNewViewReference(view));
plat->BinaryViewInit(viewObj);
}
uint32_t* Platform::GetGlobalRegistersCallback(void* ctxt, size_t* count)
{
CallbackRef plat(ctxt);
std::vector regs = plat->GetGlobalRegisters();
*count = regs.size();
uint32_t* result = new uint32_t[regs.size()];
for (size_t i = 0; i < regs.size(); i++)
result[i] = regs[i];
return result;
}
void Platform::AdjustTypeParserInputCallback(
void* ctxt,
BNTypeParser* parser,
const char* const* argumentsIn,
size_t argumentsLenIn,
const char* const* sourceFileNamesIn,
const char* const* sourceFileValuesIn,
size_t sourceFilesLenIn,
char*** argumentsOut,
size_t* argumentsLenOut,
char*** sourceFileNamesOut,
char*** sourceFileValuesOut,
size_t* sourceFilesLenOut
)
{
CallbackRef plat(ctxt);
Ref parserCpp = new CoreTypeParser(parser);
vector arguments;
arguments.reserve(argumentsLenIn);
for (size_t i = 0; i < argumentsLenIn; i ++)
{
arguments.push_back(argumentsIn[i]);
}
vector sourceFiles;
sourceFiles.reserve(sourceFilesLenIn);
for (size_t i = 0; i < sourceFilesLenIn; i ++)
{
sourceFiles.push_back(make_pair(sourceFileNamesIn[i], sourceFileValuesIn[i]));
}
plat->AdjustTypeParserInput(
parserCpp,
arguments,
sourceFiles
);
vector argumentsPtrs;
argumentsPtrs.reserve(arguments.size());
for (auto& argument : arguments)
{
argumentsPtrs.push_back(argument.c_str());
}
*argumentsOut = BNAllocStringList(argumentsPtrs.data(), argumentsPtrs.size());
*argumentsLenOut = arguments.size();
vector sourceFileNamesPtrs;
vector sourceFileValuesPtrs;
for (auto& [sourceFileName, sourceFileValue] : sourceFiles)
{
sourceFileNamesPtrs.push_back(sourceFileName.c_str());
sourceFileValuesPtrs.push_back(sourceFileValue.c_str());
}
*sourceFileNamesOut = BNAllocStringList(sourceFileNamesPtrs.data(), sourceFileNamesPtrs.size());
*sourceFileValuesOut = BNAllocStringList(sourceFileValuesPtrs.data(), sourceFileValuesPtrs.size());
*sourceFilesLenOut = sourceFiles.size();
}
void Platform::FreeTypeParserInputCallback(
void* ctxt,
char** arguments,
size_t argumentsLen,
char** sourceFileNames,
char** sourceFileValues,
size_t sourceFilesLen
)
{
(void)ctxt;
BNFreeStringList(arguments, argumentsLen);
BNFreeStringList(sourceFileNames, sourceFilesLen);
BNFreeStringList(sourceFileValues, sourceFilesLen);
}
void Platform::FreeRegisterListCallback(void*, uint32_t* regs, size_t)
{
delete[] regs;
}
BNType* Platform::GetGlobalRegisterTypeCallback(void* ctxt, uint32_t reg)
{
CallbackRef plat(ctxt);
Ref result = plat->GetGlobalRegisterType(reg);
if (!result)
return nullptr;
return BNNewTypeReference(result->GetObject());
}
size_t Platform::GetAddressSizeCallback(void* ctxt)
{
CallbackRef plat(ctxt);
return plat->GetAddressSize();
}
bool Platform::GetFallbackEnabledCallback(void* ctxt)
{
CallbackRef plat(ctxt);
return plat->GetFallbackEnabled();
}
Ref Platform::GetArchitecture() const
{
return new CoreArchitecture(BNGetPlatformArchitecture(m_object));
}
string Platform::GetName() const
{
char* str = BNGetPlatformName(m_object);
string result = str;
BNFreeString(str);
return result;
}
void Platform::Register(const string& os, Platform* platform)
{
BNRegisterPlatform(os.c_str(), platform->GetObject());
}
Ref Platform::GetByName(const string& name)
{
BNPlatform* platform = BNGetPlatformByName(name.c_str());
if (!platform)
return nullptr;
return new CorePlatform(platform);
}
vector Platform::GetList()
{
size_t count;
BNPlatform** list = BNGetPlatformList(&count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(new CorePlatform(BNNewPlatformReference(list[i])));
BNFreePlatformList(list, count);
return result;
}
vector Platform::GetList(Architecture* arch)
{
size_t count;
BNPlatform** list = BNGetPlatformListByArchitecture(arch->GetObject(), &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(new CorePlatform(BNNewPlatformReference(list[i])));
BNFreePlatformList(list, count);
return result;
}
vector Platform::GetList(const string& os)
{
size_t count;
BNPlatform** list = BNGetPlatformListByOS(os.c_str(), &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(new CorePlatform(BNNewPlatformReference(list[i])));
BNFreePlatformList(list, count);
return result;
}
vector Platform::GetList(const string& os, Architecture* arch)
{
size_t count;
BNPlatform** list = BNGetPlatformListByOSAndArchitecture(os.c_str(), arch->GetObject(), &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(new CorePlatform(BNNewPlatformReference(list[i])));
BNFreePlatformList(list, count);
return result;
}
vector Platform::GetOSList()
{
size_t count;
char** list = BNGetPlatformOSList(&count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(list[i]);
BNFreePlatformOSList(list, count);
return result;
}
Ref Platform::GetDefaultCallingConvention() const
{
BNCallingConvention* cc = BNGetPlatformDefaultCallingConvention(m_object);
if (!cc)
return nullptr;
return new CoreCallingConvention(cc);
}
Ref Platform::GetCdeclCallingConvention() const
{
BNCallingConvention* cc = BNGetPlatformCdeclCallingConvention(m_object);
if (!cc)
return nullptr;
return new CoreCallingConvention(cc);
}
Ref Platform::GetStdcallCallingConvention() const
{
BNCallingConvention* cc = BNGetPlatformStdcallCallingConvention(m_object);
if (!cc)
return nullptr;
return new CoreCallingConvention(cc);
}
Ref Platform::GetFastcallCallingConvention() const
{
BNCallingConvention* cc = BNGetPlatformFastcallCallingConvention(m_object);
if (!cc)
return nullptr;
return new CoreCallingConvention(cc);
}
vector Platform::GetCallingConventions() const
{
size_t count;
BNCallingConvention** list = BNGetPlatformCallingConventions(m_object, &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(new CoreCallingConvention(BNNewCallingConventionReference(list[i])));
BNFreeCallingConventionList(list, count);
return result;
}
Ref Platform::GetSystemCallConvention() const
{
BNCallingConvention* cc = BNGetPlatformSystemCallConvention(m_object);
if (!cc)
return nullptr;
return new CoreCallingConvention(cc);
}
void Platform::RegisterCallingConvention(CallingConvention* cc)
{
BNRegisterPlatformCallingConvention(m_object, cc->GetObject());
}
void Platform::RegisterDefaultCallingConvention(CallingConvention* cc)
{
BNRegisterPlatformDefaultCallingConvention(m_object, cc->GetObject());
}
void Platform::RegisterCdeclCallingConvention(CallingConvention* cc)
{
BNRegisterPlatformCdeclCallingConvention(m_object, cc->GetObject());
}
void Platform::RegisterStdcallCallingConvention(CallingConvention* cc)
{
BNRegisterPlatformStdcallCallingConvention(m_object, cc->GetObject());
}
void Platform::RegisterFastcallCallingConvention(CallingConvention* cc)
{
BNRegisterPlatformFastcallCallingConvention(m_object, cc->GetObject());
}
void Platform::SetSystemCallConvention(CallingConvention* cc)
{
BNSetPlatformSystemCallConvention(m_object, cc ? cc->GetObject() : nullptr);
}
void Platform::BinaryViewInit(BinaryView*)
{
}
std::vector Platform::GetGlobalRegisters()
{
return GetArchitecture()->GetGlobalRegisters();
}
Ref Platform::GetGlobalRegisterType(uint32_t reg)
{
return nullptr;
}
bool Platform::GetFallbackEnabled()
{
return true;
}
size_t Platform::GetAddressSize() const
{
return GetArchitecture()->GetAddressSize();
}
std::vector CorePlatform::GetGlobalRegisters()
{
size_t count;
uint32_t* regs = BNGetPlatformGlobalRegisters(m_object, &count);
std::vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(regs[i]);
BNFreeRegisterList(regs);
return result;
}
Ref CorePlatform::GetGlobalRegisterType(uint32_t reg)
{
BNType* res = BNGetPlatformGlobalRegisterType(m_object, reg);
if (!res)
return nullptr;
return new Type(res);
}
size_t CorePlatform::GetAddressSize() const
{
return BNGetPlatformAddressSize(m_object);
}
void Platform::AdjustTypeParserInput(
Ref parser,
vector& arguments,
vector& sourceFiles
)
{
(void)parser;
(void)arguments;
(void)sourceFiles;
}
void CorePlatform::AdjustTypeParserInput(
Ref parser,
vector& arguments,
vector& sourceFiles
)
{
vector argumentsIn;
argumentsIn.reserve(arguments.size());
for (size_t i = 0; i < arguments.size(); i ++)
{
argumentsIn.push_back(arguments[i].c_str());
}
vector sourceFileNamesIn;
vector sourceFileValuesIn;
for (size_t i = 0; i < sourceFiles.size(); i ++)
{
sourceFileNamesIn.push_back(sourceFiles[i].first.c_str());
sourceFileValuesIn.push_back(sourceFiles[i].second.c_str());
}
char** argumentsOut;
size_t argumentsLenOut;
char** sourceFileNamesOut;
char** sourceFileValuesOut;
size_t sourceFilesLenOut;
BNPlatformAdjustTypeParserInput(
m_object,
parser->m_object,
argumentsIn.data(),
argumentsIn.size(),
sourceFileNamesIn.data(),
sourceFileValuesIn.data(),
sourceFileNamesIn.size(),
&argumentsOut,
&argumentsLenOut,
&sourceFileNamesOut,
&sourceFileValuesOut,
&sourceFilesLenOut
);
arguments.clear();
for (size_t i = 0; i < argumentsLenOut; i ++)
{
arguments.push_back(argumentsOut[i]);
}
sourceFiles.clear();
for (size_t i = 0; i < sourceFilesLenOut; i ++)
{
sourceFiles.push_back(make_pair(sourceFileNamesOut[i], sourceFileValuesOut[i]));
}
BNFreeStringList(argumentsOut, argumentsLenOut);
BNFreeStringList(sourceFileNamesOut, sourceFilesLenOut);
BNFreeStringList(sourceFileValuesOut, sourceFilesLenOut);
}
Ref Platform::GetRelatedPlatform(Architecture* arch)
{
BNPlatform* platform = BNGetRelatedPlatform(m_object, arch->GetObject());
if (!platform)
return nullptr;
return new CorePlatform(platform);
}
void Platform::AddRelatedPlatform(Architecture* arch, Platform* platform)
{
BNAddRelatedPlatform(m_object, arch->GetObject(), platform->GetObject());
}
std::vector Platform::GetRelatedPlatforms()
{
size_t count;
BNPlatform** related = BNGetRelatedPlatforms(m_object, &count);
std::vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
result.push_back(new CorePlatform(BNNewPlatformReference(related[i])));
}
BNFreePlatformList(related, count);
return result;
}
Ref Platform::GetAssociatedPlatformByAddress(uint64_t& addr)
{
BNPlatform* platform = BNGetAssociatedPlatformByAddress(m_object, &addr);
if (!platform)
return nullptr;
return new CorePlatform(platform);
}
map Platform::GetTypes()
{
size_t count;
BNQualifiedNameAndType* types = BNGetPlatformTypes(m_object, &count);
map result;
for (size_t i = 0; i < count; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&types[i].name);
result[name] = new Type(BNNewTypeReference(types[i].type));
}
BNFreeTypeAndNameList(types, count);
return result;
}
map Platform::GetVariables()
{
size_t count;
BNQualifiedNameAndType* types = BNGetPlatformVariables(m_object, &count);
map result;
for (size_t i = 0; i < count; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&types[i].name);
result[name] = new Type(BNNewTypeReference(types[i].type));
}
BNFreeTypeAndNameList(types, count);
return result;
}
map Platform::GetFunctions()
{
size_t count;
BNQualifiedNameAndType* types = BNGetPlatformFunctions(m_object, &count);
map result;
for (size_t i = 0; i < count; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&types[i].name);
result[name] = new Type(BNNewTypeReference(types[i].type));
}
BNFreeTypeAndNameList(types, count);
return result;
}
map Platform::GetSystemCalls()
{
size_t count;
BNSystemCallInfo* calls = BNGetPlatformSystemCalls(m_object, &count);
map result;
for (size_t i = 0; i < count; i++)
{
QualifiedNameAndType nt;
nt.name = QualifiedName::FromAPIObject(&calls[i].name);
nt.type = new Type(BNNewTypeReference(calls[i].type));
result[calls[i].number] = nt;
}
BNFreeSystemCallList(calls, count);
return result;
}
vector Platform::GetTypeLibraries()
{
size_t count;
BNTypeLibrary** libs = BNGetPlatformTypeLibraries(m_object, &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; ++i)
{
result.push_back(new TypeLibrary(BNNewTypeLibraryReference(libs[i])));
}
BNFreeTypeLibraryList(libs, count);
return result;
}
vector Platform::GetTypeLibrariesByName(const std::string& name)
{
size_t count;
BNTypeLibrary** libs = BNGetPlatformTypeLibrariesByName(m_object, name.c_str(), &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; ++i)
{
result.push_back(new TypeLibrary(BNNewTypeLibraryReference(libs[i])));
}
BNFreeTypeLibraryList(libs, count);
return result;
}
TypeContainer Platform::GetTypeContainer()
{
return TypeContainer(BNGetPlatformTypeContainer(m_object));
}
Ref Platform::GetTypeByName(const QualifiedName& name)
{
BNQualifiedName nameObj = name.GetAPIObject();
BNType* type = BNGetPlatformTypeByName(m_object, &nameObj);
QualifiedName::FreeAPIObject(&nameObj);
if (!type)
return nullptr;
return new Type(type);
}
Ref Platform::GetVariableByName(const QualifiedName& name)
{
BNQualifiedName nameObj = name.GetAPIObject();
BNType* type = BNGetPlatformVariableByName(m_object, &nameObj);
QualifiedName::FreeAPIObject(&nameObj);
if (!type)
return nullptr;
return new Type(type);
}
Ref Platform::GetFunctionByName(const QualifiedName& name, bool exactMatch)
{
BNQualifiedName nameObj = name.GetAPIObject();
BNType* type = BNGetPlatformFunctionByName(m_object, &nameObj, exactMatch);
QualifiedName::FreeAPIObject(&nameObj);
if (!type)
return nullptr;
return new Type(type);
}
string Platform::GetSystemCallName(uint32_t n)
{
char* str = BNGetPlatformSystemCallName(m_object, n);
string result = str;
BNFreeString(str);
return result;
}
Ref Platform::GetSystemCallType(uint32_t n)
{
BNType* type = BNGetPlatformSystemCallType(m_object, n);
if (!type)
return nullptr;
return new Type(type);
}
string Platform::GenerateAutoPlatformTypeId(const QualifiedName& name)
{
BNQualifiedName nameObj = name.GetAPIObject();
char* str = BNGenerateAutoPlatformTypeId(m_object, &nameObj);
string result = str;
QualifiedName::FreeAPIObject(&nameObj);
BNFreeString(str);
return result;
}
Ref Platform::GenerateAutoPlatformTypeReference(
BNNamedTypeReferenceClass cls, const QualifiedName& name)
{
string id = GenerateAutoPlatformTypeId(name);
return new NamedTypeReference(cls, id, name);
}
string Platform::GetAutoPlatformTypeIdSource()
{
char* str = BNGetAutoPlatformTypeIdSource(m_object);
string result = str;
BNFreeString(str);
return result;
}
bool Platform::ParseTypesFromSource(const string& source, const string& fileName, map& types,
map& variables, map& functions, string& errors,
const vector& includeDirs, const string& autoTypeSource)
{
BNTypeParserResult result;
char* errorStr;
const char** includeDirList = new const char*[includeDirs.size()];
for (size_t i = 0; i < includeDirs.size(); i++)
includeDirList[i] = includeDirs[i].c_str();
types.clear();
variables.clear();
functions.clear();
bool ok = BNParseTypesFromSource(m_object, source.c_str(), fileName.c_str(), &result, &errorStr, includeDirList,
includeDirs.size(), autoTypeSource.c_str());
errors = errorStr;
BNFreeString(errorStr);
delete[] includeDirList;
if (!ok)
return false;
for (size_t i = 0; i < result.typeCount; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&result.types[i].name);
types[name] = new Type(BNNewTypeReference(result.types[i].type));
}
for (size_t i = 0; i < result.variableCount; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&result.variables[i].name);
variables[name] = new Type(BNNewTypeReference(result.variables[i].type));
}
for (size_t i = 0; i < result.functionCount; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&result.functions[i].name);
functions[name] = new Type(BNNewTypeReference(result.functions[i].type));
}
BNFreeTypeParserResult(&result);
return true;
}
bool Platform::ParseTypesFromSourceFile(const string& fileName, map& types,
map& variables, map& functions, string& errors,
const vector& includeDirs, const string& autoTypeSource)
{
BNTypeParserResult result;
char* errorStr;
const char** includeDirList = new const char*[includeDirs.size()];
for (size_t i = 0; i < includeDirs.size(); i++)
includeDirList[i] = includeDirs[i].c_str();
types.clear();
variables.clear();
functions.clear();
bool ok = BNParseTypesFromSourceFile(
m_object, fileName.c_str(), &result, &errorStr, includeDirList, includeDirs.size(), autoTypeSource.c_str());
errors = errorStr;
BNFreeString(errorStr);
delete[] includeDirList;
if (!ok)
return false;
for (size_t i = 0; i < result.typeCount; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&result.types[i].name);
types[name] = new Type(BNNewTypeReference(result.types[i].type));
}
for (size_t i = 0; i < result.variableCount; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&result.variables[i].name);
variables[name] = new Type(BNNewTypeReference(result.variables[i].type));
}
for (size_t i = 0; i < result.functionCount; i++)
{
QualifiedName name = QualifiedName::FromAPIObject(&result.functions[i].name);
functions[name] = new Type(BNNewTypeReference(result.functions[i].type));
}
BNFreeTypeParserResult(&result);
return true;
}