GeezerVison is showing raw.githubusercontent.com — raw.githubusercontent.com
// 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
#include
#include
#include
#include
#include "binaryninjaapi.h"
using namespace BinaryNinja;
using namespace std;
map g_pythonKeywordReplacements = {
{"False", "False_"},
{"True", "True_"},
{"None", "None_"},
{"and", "and_"},
{"as", "as_"},
{"assert", "assert_"},
{"async", "async_"},
{"await", "await_"},
{"break", "break_"},
{"class", "class_"},
{"continue", "continue_"},
{"def", "def_"},
{"del", "del_"},
{"elif", "elif_"},
{"else", "else_"},
{"except", "except_"},
{"finally", "finally_"},
{"for", "for_"},
{"from", "from_"},
{"global", "global_"},
{"if", "if_"},
{"import", "import_"},
{"in", "in_"},
{"is", "is_"},
{"lambda", "lambda_"},
{"nonlocal", "nonlocal_"},
{"not", "not_"},
{"or", "or_"},
{"pass", "pass_"},
{"raise", "raise_"},
{"return", "return_"},
{"try", "try_"},
{"while", "while_"},
{"with", "with_"},
{"yield", "yield_"},
};
string PythonEnumName(string name)
{
if (name.size() > 2 && name.substr(0, 2) == "BN")
return name.substr(2);
return name;
}
void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallback = false, bool isTypeHint = false)
{
switch (type->GetClass())
{
case BoolTypeClass:
fprintf(out, "ctypes.c_bool");
break;
case IntegerTypeClass:
switch (type->GetWidth())
{
case 1:
if (type->IsSigned())
fprintf(out, "ctypes.c_byte");
else
fprintf(out, "ctypes.c_ubyte");
break;
case 2:
if (type->IsSigned())
fprintf(out, "ctypes.c_short");
else
fprintf(out, "ctypes.c_ushort");
break;
case 4:
if (type->IsSigned())
fprintf(out, "ctypes.c_int");
else
fprintf(out, "ctypes.c_uint");
break;
default:
if (type->IsSigned())
fprintf(out, "ctypes.c_longlong");
else
fprintf(out, "ctypes.c_ulonglong");
break;
}
break;
case FloatTypeClass:
if (type->GetWidth() == 4)
fprintf(out, "ctypes.c_float");
else
fprintf(out, "ctypes.c_double");
break;
case NamedTypeReferenceClass:
if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass)
{
string name = PythonEnumName(type->GetNamedTypeReference()->GetName().GetString());
fprintf(out, "%sEnum", name.c_str());
}
else
{
fprintf(out, "%s", type->GetNamedTypeReference()->GetName().GetString().c_str());
}
break;
case PointerTypeClass:
if (isCallback || (type->GetChildType()->GetClass() == VoidTypeClass))
{
fprintf(out, "ctypes.c_void_p");
break;
}
else if ((type->GetChildType()->GetClass() == IntegerTypeClass) && (type->GetChildType()->GetWidth() == 1)
&& (type->GetChildType()->IsSigned()))
{
if (isTypeHint)
fprintf(out, "ctypes._Pointer[ctypes.c_byte]");
else if (isReturnType)
fprintf(out, "ctypes.POINTER(ctypes.c_byte)");
else
fprintf(out, "ctypes.c_char_p");
break;
}
else if (type->GetChildType()->GetClass() == FunctionTypeClass)
{
if (isTypeHint)
fprintf(out, "ctypes.CFUNCTYPE[");
else
fprintf(out, "ctypes.CFUNCTYPE(");
OutputType(out, type->GetChildType()->GetChildType().GetValue(), true, true, isTypeHint);
for (auto& i : type->GetChildType()->GetParameters())
{
fprintf(out, ", ");
OutputType(out, i.type.GetValue(), false, false, isTypeHint);
}
if (isTypeHint)
fprintf(out, "]");
else
fprintf(out, ")");
break;
}
if (isTypeHint)
fprintf(out, "ctypes._Pointer[");
else
fprintf(out, "ctypes.POINTER(");
OutputType(out, type->GetChildType().GetValue(), false, false, isTypeHint);
if (isTypeHint)
fprintf(out, "]");
else
fprintf(out, ")");
break;
case ArrayTypeClass:
OutputType(out, type->GetChildType().GetValue(), false, false, isTypeHint);
fprintf(out, " * %" PRId64, type->GetElementCount());
break;
default:
fprintf(out, "None");
break;
}
}
void OutputSwizzledType(FILE* out, Type* type, bool isTypeHint = false)
{
switch (type->GetClass())
{
case BoolTypeClass:
fprintf(out, "bool");
break;
case IntegerTypeClass:
fprintf(out, "int");
break;
case FloatTypeClass:
fprintf(out, "float");
break;
case NamedTypeReferenceClass:
if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass)
{
string name = PythonEnumName(type->GetNamedTypeReference()->GetName().GetString());
fprintf(out, "%s", name.c_str());
}
else
{
fprintf(out, "%s", type->GetNamedTypeReference()->GetName().GetString().c_str());
}
break;
case PointerTypeClass:
if (type->GetChildType()->GetClass() == VoidTypeClass)
{
fprintf(out, "Optional[ctypes.c_void_p]");
break;
}
else if ((type->GetChildType()->GetClass() == IntegerTypeClass) && (type->GetChildType()->GetWidth() == 1)
&& (type->GetChildType()->IsSigned()))
{
fprintf(out, "Optional[str]");
break;
}
else if (type->GetChildType()->GetClass() == FunctionTypeClass)
{
if (isTypeHint)
fprintf(out, "ctypes.CFUNCTYPE[");
else
fprintf(out, "ctypes.CFUNCTYPE(");
OutputType(out, type->GetChildType()->GetChildType().GetValue(), true, true, isTypeHint);
for (auto& i : type->GetChildType()->GetParameters())
{
fprintf(out, ", ");
OutputType(out, i.type.GetValue(), false, false, isTypeHint);
}
if (isTypeHint)
fprintf(out, "]");
else
fprintf(out, ")");
break;
}
if (isTypeHint)
fprintf(out, "ctypes._Pointer[");
else
fprintf(out, "ctypes.POINTER(");
OutputType(out, type->GetChildType().GetValue(), false, false, isTypeHint);
if (isTypeHint)
fprintf(out, "]");
else
fprintf(out, ")");
break;
case ArrayTypeClass:
OutputType(out, type->GetChildType().GetValue(), false, false, isTypeHint);
fprintf(out, " * %" PRId64, type->GetElementCount());
break;
default:
fprintf(out, "None");
break;
}
}
void CollectNamedTypeReferences(Type* type, set& names)
{
switch (type->GetClass())
{
case NamedTypeReferenceClass:
names.insert(type->GetNamedTypeReference()->GetName());
break;
case PointerTypeClass:
case ArrayTypeClass:
CollectNamedTypeReferences(type->GetChildType().GetValue(), names);
break;
case FunctionTypeClass:
CollectNamedTypeReferences(type->GetChildType().GetValue(), names);
for (auto& param : type->GetParameters())
CollectNamedTypeReferences(param.type.GetValue(), names);
break;
case StructureTypeClass:
for (auto& member : type->GetStructure()->GetMembers())
CollectNamedTypeReferences(member.type.GetValue(), names);
break;
default:
break;
}
}
// Returns the names the core bindings define for the core type `name`.
vector CoreBindingNames(const string& name, Type* type)
{
switch (type->GetClass())
{
case StructureTypeClass:
case NamedTypeReferenceClass:
return {name, name + "Handle"};
case EnumerationTypeClass:
return {PythonEnumName(name) + "Enum"};
case BoolTypeClass:
case IntegerTypeClass:
case FloatTypeClass:
case ArrayTypeClass:
return {name};
case PointerTypeClass:
if (type->GetChildType()->GetClass() == FunctionTypeClass)
return {name};
return {};
default:
return {};
}
}
static const string g_templateBindingsMarker = "# @@GENERATED_BINDINGS@@";
bool ReadTemplate(const char* path, string& prologue, string& epilogue)
{
ifstream file(path, ios::binary);
if (!file)
return false;
string contents((istreambuf_iterator(file)), istreambuf_iterator());
size_t marker = contents.find(g_templateBindingsMarker);
if (marker == string::npos)
{
prologue = std::move(contents);
epilogue.clear();
return true;
}
size_t lineEnd = contents.find('\n', marker);
prologue = contents.substr(0, marker);
epilogue = lineEnd == string::npos ? string() : contents.substr(lineEnd + 1);
return true;
}
int main(int argc, char* argv[])
{
const char* usage = "Usage: generator