summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorRusty Wagner <rusty@vector35.com>2017-08-17 02:04:50 -0400
committerRusty Wagner <rusty@vector35.com>2017-08-17 02:04:50 -0400
commit5e25409d02479285d1f16d6cc55df1b267e9ba06 (patch)
treeca7a800c57bb907e04e916d5c90f72c601544679 /python
parentec2d882e1a165b703e8fedaa81246dcdd91f50f3 (diff)
Support custom calling conventions in the type parser and type objects
Diffstat (limited to 'python')
-rw-r--r--python/architecture.py93
-rw-r--r--python/binaryview.py22
-rw-r--r--python/function.py15
-rw-r--r--python/generator.cpp63
-rw-r--r--python/mediumlevelil.py5
-rw-r--r--python/platform.py109
-rw-r--r--python/types.py90
7 files changed, 249 insertions, 148 deletions
diff --git a/python/architecture.py b/python/architecture.py
index 61559934..72403fec 100644
--- a/python/architecture.py
+++ b/python/architecture.py
@@ -1674,99 +1674,6 @@ class Architecture(object):
"""
core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value)
- def parse_types_from_source(self, source, filename=None, include_dirs=[], auto_type_source=None):
- """
- ``parse_types_from_source`` parses the source string and any needed headers searching for them in
- the optional list of directories provided in ``include_dirs``.
-
- :param str source: source string to be parsed
- :param str filename: optional source filename
- :param list(str) include_dirs: optional list of string filename include directories
- :param str auto_type_source: optional source of types if used for automatically generated types
- :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error)
- :rtype: TypeParserResult
- :Example:
-
- >>> arch.parse_types_from_source('int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n')
- ({types: {'bas': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions:{'bar':
- <type: int32_t(int32_t x)>}}, '')
- >>>
- """
-
- if filename is None:
- filename = "input"
- dir_buf = (ctypes.c_char_p * len(include_dirs))()
- for i in xrange(0, len(include_dirs)):
- dir_buf[i] = str(include_dirs[i])
- parse = core.BNTypeParserResult()
- errors = ctypes.c_char_p()
- result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf,
- len(include_dirs), auto_type_source)
- error_str = errors.value
- core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
- if not result:
- raise SyntaxError(error_str)
- type_dict = {}
- variables = {}
- functions = {}
- for i in xrange(0, parse.typeCount):
- name = types.QualifiedName._from_core_struct(parse.types[i].name)
- type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type))
- for i in xrange(0, parse.variableCount):
- name = types.QualifiedName._from_core_struct(parse.variables[i].name)
- variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type))
- for i in xrange(0, parse.functionCount):
- name = types.QualifiedName._from_core_struct(parse.functions[i].name)
- functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type))
- core.BNFreeTypeParserResult(parse)
- return types.TypeParserResult(type_dict, variables, functions)
-
- def parse_types_from_source_file(self, filename, include_dirs=[], auto_type_source=None):
- """
- ``parse_types_from_source_file`` parses the source file ``filename`` and any needed headers searching for them in
- the optional list of directories provided in ``include_dirs``.
-
- :param str filename: filename of file to be parsed
- :param list(str) include_dirs: optional list of string filename include directories
- :param str auto_type_source: optional source of types if used for automatically generated types
- :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error)
- :rtype: TypeParserResult
- :Example:
-
- >>> file = "/Users/binja/tmp.c"
- >>> open(file).read()
- 'int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n'
- >>> arch.parse_types_from_source_file(file)
- ({types: {'bas': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions:
- {'bar': <type: int32_t(int32_t x)>}}, '')
- >>>
- """
- dir_buf = (ctypes.c_char_p * len(include_dirs))()
- for i in xrange(0, len(include_dirs)):
- dir_buf[i] = str(include_dirs[i])
- parse = core.BNTypeParserResult()
- errors = ctypes.c_char_p()
- result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf,
- len(include_dirs), auto_type_source)
- error_str = errors.value
- core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
- if not result:
- raise SyntaxError(error_str)
- type_dict = {}
- variables = {}
- functions = {}
- for i in xrange(0, parse.typeCount):
- name = types.QualifiedName._from_core_struct(parse.types[i].name)
- type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type))
- for i in xrange(0, parse.variableCount):
- name = types.QualifiedName._from_core_struct(parse.variables[i].name)
- variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type))
- for i in xrange(0, parse.functionCount):
- name = types.QualifiedName._from_core_struct(parse.functions[i].name)
- functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type))
- core.BNFreeTypeParserResult(parse)
- return types.TypeParserResult(type_dict, variables, functions)
-
def register_calling_convention(self, cc):
"""
``register_calling_convention`` registers a new calling convention for the Architecture.
diff --git a/python/binaryview.py b/python/binaryview.py
index a43bd5b5..bdba11af 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -217,7 +217,7 @@ class BinaryDataNotificationCallbacks(object):
def _data_var_added(self, ctxt, view, var):
try:
address = var[0].address
- var_type = types.Type(core.BNNewTypeReference(var[0].type), confidence = var[0].typeConfidence)
+ var_type = types.Type(core.BNNewTypeReference(var[0].type), platform = self.view.platform, confidence = var[0].typeConfidence)
auto_discovered = var[0].autoDiscovered
self.notify.data_var_added(self.view, DataVariable(address, var_type, auto_discovered))
except:
@@ -226,7 +226,7 @@ class BinaryDataNotificationCallbacks(object):
def _data_var_removed(self, ctxt, view, var):
try:
address = var[0].address
- var_type = types.Type(core.BNNewTypeReference(var[0].type), confidence = var[0].typeConfidence)
+ var_type = types.Type(core.BNNewTypeReference(var[0].type), platform = self.view.platform, confidence = var[0].typeConfidence)
auto_discovered = var[0].autoDiscovered
self.notify.data_var_removed(self.view, DataVariable(address, var_type, auto_discovered))
except:
@@ -235,7 +235,7 @@ class BinaryDataNotificationCallbacks(object):
def _data_var_updated(self, ctxt, view, var):
try:
address = var[0].address
- var_type = types.Type(core.BNNewTypeReference(var[0].type), confidence = var[0].typeConfidence)
+ var_type = types.Type(core.BNNewTypeReference(var[0].type), platform = self.view.platform, confidence = var[0].typeConfidence)
auto_discovered = var[0].autoDiscovered
self.notify.data_var_updated(self.view, DataVariable(address, var_type, auto_discovered))
except:
@@ -256,14 +256,14 @@ class BinaryDataNotificationCallbacks(object):
def _type_defined(self, ctxt, view, name, type_obj):
try:
qualified_name = types.QualifiedName._from_core_struct(name[0])
- self.notify.type_defined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj)))
+ self.notify.type_defined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj), platform = self.view.platform))
except:
log.log_error(traceback.format_exc())
def _type_undefined(self, ctxt, view, name, type_obj):
try:
qualified_name = types.QualifiedName._from_core_struct(name[0])
- self.notify.type_undefined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj)))
+ self.notify.type_undefined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj), platform = self.view.platform))
except:
log.log_error(traceback.format_exc())
@@ -860,7 +860,7 @@ class BinaryView(object):
result = {}
for i in xrange(0, count.value):
addr = var_list[i].address
- var_type = types.Type(core.BNNewTypeReference(var_list[i].type), confidence = var_list[i].typeConfidence)
+ var_type = types.Type(core.BNNewTypeReference(var_list[i].type), platform = self.platform, confidence = var_list[i].typeConfidence)
auto_discovered = var_list[i].autoDiscovered
result[addr] = DataVariable(addr, var_type, auto_discovered)
core.BNFreeDataVariables(var_list, count.value)
@@ -874,7 +874,7 @@ class BinaryView(object):
result = {}
for i in xrange(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
- result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self.platform)
core.BNFreeTypeList(type_list, count.value)
return result
@@ -1915,7 +1915,7 @@ class BinaryView(object):
var = core.BNDataVariable()
if not core.BNGetDataVariableAtAddress(self.handle, addr, var):
return None
- return DataVariable(var.address, types.Type(var.type, confidence = var.typeConfidence), var.autoDiscovered)
+ return DataVariable(var.address, types.Type(var.type, platform = self.platform, confidence = var.typeConfidence), var.autoDiscovered)
def get_functions_containing(self, addr):
"""
@@ -2918,7 +2918,7 @@ class BinaryView(object):
error_str = errors.value
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise SyntaxError(error_str)
- type_obj = types.Type(core.BNNewTypeReference(result.type))
+ type_obj = types.Type(core.BNNewTypeReference(result.type), platform = self.platform)
name = types.QualifiedName._from_core_struct(result.name)
core.BNFreeQualifiedNameAndType(result)
return type_obj, name
@@ -2942,7 +2942,7 @@ class BinaryView(object):
obj = core.BNGetAnalysisTypeByName(self.handle, name)
if not obj:
return None
- return types.Type(obj)
+ return types.Type(obj, platform = self.platform)
def get_type_by_id(self, id):
"""
@@ -2963,7 +2963,7 @@ class BinaryView(object):
obj = core.BNGetAnalysisTypeById(self.handle, id)
if not obj:
return None
- return types.Type(obj)
+ return types.Type(obj, platform = self.platform)
def get_type_name_by_id(self, id):
"""
diff --git a/python/function.py b/python/function.py
index cf9bd759..55151e16 100644
--- a/python/function.py
+++ b/python/function.py
@@ -211,7 +211,7 @@ class Variable(object):
if var_type is None:
var_type_conf = core.BNGetVariableType(func.handle, var)
if var_type_conf.type:
- var_type = types.Type(var_type_conf.type, confidence = var_type_conf.confidence)
+ var_type = types.Type(var_type_conf.type, platform = func.platform, confidence = var_type_conf.confidence)
else:
var_type = None
@@ -443,7 +443,7 @@ class Function(object):
@property
def function_type(self):
"""Function type object"""
- return types.Type(core.BNGetFunctionType(self.handle))
+ return types.Type(core.BNGetFunctionType(self.handle), platform = self.platform)
@function_type.setter
def function_type(self, value):
@@ -457,7 +457,7 @@ class Function(object):
result = []
for i in xrange(0, count.value):
result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
- types.Type(handle = core.BNNewTypeReference(v[i].type), confidence = v[i].typeConfidence)))
+ types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence)))
result.sort(key = lambda x: x.identifier)
core.BNFreeVariableList(v, count.value)
return result
@@ -470,7 +470,7 @@ class Function(object):
result = []
for i in xrange(0, count.value):
result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
- types.Type(handle = core.BNNewTypeReference(v[i].type), confidence = v[i].typeConfidence)))
+ types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence)))
result.sort(key = lambda x: x.identifier)
core.BNFreeVariableList(v, count.value)
return result
@@ -518,7 +518,7 @@ class Function(object):
result = core.BNGetFunctionReturnType(self.handle)
if not result.type:
return None
- return types.Type(result.type, confidence = result.confidence)
+ return types.Type(result.type, platform = self.platform, confidence = result.confidence)
@return_type.setter
def return_type(self, value):
@@ -778,7 +778,7 @@ class Function(object):
refs = core.BNGetStackVariablesReferencedByInstruction(self.handle, arch.handle, addr, count)
result = []
for i in xrange(0, count.value):
- var_type = types.Type(core.BNNewTypeReference(refs[i].type), confidence = refs[i].typeConfidence)
+ var_type = types.Type(core.BNNewTypeReference(refs[i].type), platform = self.platform, confidence = refs[i].typeConfidence)
result.append(StackVariableReference(refs[i].sourceOperand, var_type,
refs[i].name, Variable.from_identifier(self, refs[i].varIdentifier, refs[i].name, var_type),
refs[i].referencedOffset, refs[i].size))
@@ -1132,7 +1132,8 @@ class Function(object):
if not core.BNGetStackVariableAtFrameOffset(self.handle, arch.handle, addr, offset, found_var):
return None
result = Variable(self, found_var.var.type, found_var.var.index, found_var.var.storage,
- found_var.name, types.Type(handle = core.BNNewTypeReference(found_var.type), confidence = found_var.typeConfidence))
+ found_var.name, types.Type(handle = core.BNNewTypeReference(found_var.type), platform = self.platform,
+ confidence = found_var.typeConfidence))
core.BNFreeVariableNameAndType(found_var)
return result
diff --git a/python/generator.cpp b/python/generator.cpp
index 554f82cd..f838b36d 100644
--- a/python/generator.cpp
+++ b/python/generator.cpp
@@ -172,7 +172,7 @@ int main(int argc, char* argv[])
return 1;
}
- bool ok = arch->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors);
+ bool ok = arch->GetStandalonePlatform()->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors);
fprintf(stderr, "Errors: %s", errors.c_str());
if (!ok)
return 1;
@@ -237,22 +237,61 @@ int main(int argc, char* argv[])
fprintf(out, "\n# Structure definitions\n");
+ set<QualifiedName> structsToProcess;
+ set<QualifiedName> finishedStructs;
for (auto& i : types)
+ structsToProcess.insert(i.first);
+ while (structsToProcess.size() != 0)
{
- string name;
- if (i.first.size() != 1)
- continue;
- name = i.first[0];
- if ((i.second->GetClass() == StructureTypeClass) && (i.second->GetStructure()->GetMembers().size() != 0))
+ set<QualifiedName> currentStructList = structsToProcess;
+ structsToProcess.clear();
+ bool processedSome = false;
+ for (auto& i : currentStructList)
{
- fprintf(out, "%s._fields_ = [\n", name.c_str());
- for (auto& j : i.second->GetStructure()->GetMembers())
+ string name;
+ if (i.size() != 1)
+ continue;
+ Ref<Type> type = types[i];
+ name = i[0];
+ if ((type->GetClass() == StructureTypeClass) && (type->GetStructure()->GetMembers().size() != 0))
{
- fprintf(out, "\t\t(\"%s\", ", j.name.c_str());
- OutputType(out, j.type);
- fprintf(out, "),\n");
+ bool requiresDependency = false;
+ for (auto& j : type->GetStructure()->GetMembers())
+ {
+ if ((j.type->GetClass() == NamedTypeReferenceClass) &&
+ (types[j.type->GetNamedTypeReference()->GetName()]->GetClass() == StructureTypeClass) &&
+ (finishedStructs.count(j.type->GetNamedTypeReference()->GetName()) == 0))
+ {
+ // This structure needs another structure that isn't fully defined yet, need to wait
+ // for the dependencies to be defined
+ structsToProcess.insert(i);
+ requiresDependency = true;
+ break;
+ }
+ }
+
+ if (requiresDependency)
+ continue;
+
+ fprintf(out, "%s._fields_ = [\n", name.c_str());
+ for (auto& j : type->GetStructure()->GetMembers())
+ {
+ fprintf(out, "\t\t(\"%s\", ", j.name.c_str());
+ OutputType(out, j.type);
+ fprintf(out, "),\n");
+ }
+ fprintf(out, "\t]\n");
+ finishedStructs.insert(i);
+ processedSome = true;
}
- fprintf(out, "\t]\n");
+ }
+
+ if (!processedSome)
+ {
+ fprintf(stderr, "Detected dependency cycle in structures\n");
+ for (auto& i : structsToProcess)
+ fprintf(stderr, "%s\n", i.GetString().c_str());
+ return 1;
}
}
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index c837aa42..3e7a6997 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -417,7 +417,10 @@ class MediumLevelILInstruction(object):
"""Type of expression"""
result = core.BNGetMediumLevelILExprType(self.function.handle, self.expr_index)
if result.type:
- return types.Type(result.type, confidence = result.confidence)
+ platform = None
+ if self.function.source_function:
+ platform = self.function.source_function.platform
+ return types.Type(result.type, platform = platform, confidence = result.confidence)
return None
def get_ssa_var_possible_values(self, ssa_var):
diff --git a/python/platform.py b/python/platform.py
index 1c2fdcd3..5e63d836 100644
--- a/python/platform.py
+++ b/python/platform.py
@@ -234,7 +234,7 @@ class Platform(object):
result = {}
for i in xrange(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
- result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self)
core.BNFreeTypeList(type_list, count.value)
return result
@@ -246,7 +246,7 @@ class Platform(object):
result = {}
for i in xrange(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
- result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self)
core.BNFreeTypeList(type_list, count.value)
return result
@@ -258,7 +258,7 @@ class Platform(object):
result = {}
for i in xrange(0, count.value):
name = types.QualifiedName._from_core_struct(type_list[i].name)
- result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self)
core.BNFreeTypeList(type_list, count.value)
return result
@@ -270,7 +270,7 @@ class Platform(object):
result = {}
for i in xrange(0, count.value):
name = types.QualifiedName._from_core_struct(call_list[i].name)
- t = types.Type(core.BNNewTypeReference(call_list[i].type))
+ t = types.Type(core.BNNewTypeReference(call_list[i].type), platform = self)
result[call_list[i].number] = (name, t)
core.BNFreeSystemCallList(call_list, count.value)
return result
@@ -325,21 +325,21 @@ class Platform(object):
obj = core.BNGetPlatformTypeByName(self.handle, name)
if not obj:
return None
- return types.Type(obj)
+ return types.Type(obj, platform = self)
def get_variable_by_name(self, name):
name = types.QualifiedName(name)._get_core_struct()
obj = core.BNGetPlatformVariableByName(self.handle, name)
if not obj:
return None
- return types.Type(obj)
+ return types.Type(obj, platform = self)
def get_function_by_name(self, name):
name = types.QualifiedName(name)._get_core_struct()
obj = core.BNGetPlatformFunctionByName(self.handle, name)
if not obj:
return None
- return types.Type(obj)
+ return types.Type(obj, platform = self)
def get_system_call_name(self, number):
return core.BNGetPlatformSystemCallName(self.handle, number)
@@ -348,7 +348,7 @@ class Platform(object):
obj = core.BNGetPlatformSystemCallType(self.handle, number)
if not obj:
return None
- return types.Type(obj)
+ return types.Type(obj, platform = self)
def generate_auto_platform_type_id(self, name):
name = types.QualifiedName(name)._get_core_struct()
@@ -360,3 +360,96 @@ class Platform(object):
def get_auto_platform_type_id_source(self):
return core.BNGetAutoPlatformTypeIdSource(self.handle)
+
+ def parse_types_from_source(self, source, filename=None, include_dirs=[], auto_type_source=None):
+ """
+ ``parse_types_from_source`` parses the source string and any needed headers searching for them in
+ the optional list of directories provided in ``include_dirs``.
+
+ :param str source: source string to be parsed
+ :param str filename: optional source filename
+ :param list(str) include_dirs: optional list of string filename include directories
+ :param str auto_type_source: optional source of types if used for automatically generated types
+ :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error)
+ :rtype: TypeParserResult
+ :Example:
+
+ >>> platform.parse_types_from_source('int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n')
+ ({types: {'bas': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions:{'bar':
+ <type: int32_t(int32_t x)>}}, '')
+ >>>
+ """
+
+ if filename is None:
+ filename = "input"
+ dir_buf = (ctypes.c_char_p * len(include_dirs))()
+ for i in xrange(0, len(include_dirs)):
+ dir_buf[i] = str(include_dirs[i])
+ parse = core.BNTypeParserResult()
+ errors = ctypes.c_char_p()
+ result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf,
+ len(include_dirs), auto_type_source)
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ if not result:
+ raise SyntaxError(error_str)
+ type_dict = {}
+ variables = {}
+ functions = {}
+ for i in xrange(0, parse.typeCount):
+ name = types.QualifiedName._from_core_struct(parse.types[i].name)
+ type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self)
+ for i in xrange(0, parse.variableCount):
+ name = types.QualifiedName._from_core_struct(parse.variables[i].name)
+ variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self)
+ for i in xrange(0, parse.functionCount):
+ name = types.QualifiedName._from_core_struct(parse.functions[i].name)
+ functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self)
+ core.BNFreeTypeParserResult(parse)
+ return types.TypeParserResult(type_dict, variables, functions)
+
+ def parse_types_from_source_file(self, filename, include_dirs=[], auto_type_source=None):
+ """
+ ``parse_types_from_source_file`` parses the source file ``filename`` and any needed headers searching for them in
+ the optional list of directories provided in ``include_dirs``.
+
+ :param str filename: filename of file to be parsed
+ :param list(str) include_dirs: optional list of string filename include directories
+ :param str auto_type_source: optional source of types if used for automatically generated types
+ :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error)
+ :rtype: TypeParserResult
+ :Example:
+
+ >>> file = "/Users/binja/tmp.c"
+ >>> open(file).read()
+ 'int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n'
+ >>> platform.parse_types_from_source_file(file)
+ ({types: {'bas': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions:
+ {'bar': <type: int32_t(int32_t x)>}}, '')
+ >>>
+ """
+ dir_buf = (ctypes.c_char_p * len(include_dirs))()
+ for i in xrange(0, len(include_dirs)):
+ dir_buf[i] = str(include_dirs[i])
+ parse = core.BNTypeParserResult()
+ errors = ctypes.c_char_p()
+ result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf,
+ len(include_dirs), auto_type_source)
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ if not result:
+ raise SyntaxError(error_str)
+ type_dict = {}
+ variables = {}
+ functions = {}
+ for i in xrange(0, parse.typeCount):
+ name = types.QualifiedName._from_core_struct(parse.types[i].name)
+ type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self)
+ for i in xrange(0, parse.variableCount):
+ name = types.QualifiedName._from_core_struct(parse.variables[i].name)
+ variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self)
+ for i in xrange(0, parse.functionCount):
+ name = types.QualifiedName._from_core_struct(parse.functions[i].name)
+ functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self)
+ core.BNFreeTypeParserResult(parse)
+ return types.TypeParserResult(type_dict, variables, functions)
diff --git a/python/types.py b/python/types.py
index e297ddd2..fd2ee27e 100644
--- a/python/types.py
+++ b/python/types.py
@@ -24,7 +24,7 @@ import ctypes
# Binary Ninja components
import _binaryninjacore as core
-from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType
+from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType
import callingconvention
import function
@@ -199,10 +199,23 @@ class Symbol(object):
raise AttributeError("attribute '%s' is read only" % name)
+class FunctionParameter(object):
+ def __init__(self, param_type, name = "", location = None):
+ self.type = param_type
+ self.name = name
+ self.location = location
+
+ def __repr__(self):
+ if (self.location is not None) and (self.location.name != self.name):
+ return "%s %s%s @ %s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name(), self.location.name)
+ return "%s %s%s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name())
+
+
class Type(object):
- def __init__(self, handle, confidence = max_confidence):
+ def __init__(self, handle, platform = None, confidence = max_confidence):
self.handle = handle
self.confidence = confidence
+ self.platform = platform
def __del__(self):
core.BNFreeType(self.handle)
@@ -255,7 +268,7 @@ class Type(object):
result = core.BNGetChildType(self.handle)
if not result.type:
return None
- return Type(result.type, confidence = result.confidence)
+ return Type(result.type, platform = self.platform, confidence = result.confidence)
@property
def element_type(self):
@@ -263,7 +276,7 @@ class Type(object):
result = core.BNGetChildType(self.handle)
if not result.type:
return None
- return Type(result.type, confidence = result.confidence)
+ return Type(result.type, platform = self.platform, confidence = result.confidence)
@property
def return_value(self):
@@ -271,7 +284,7 @@ class Type(object):
result = core.BNGetChildType(self.handle)
if not result.type:
return None
- return Type(result.type, confidence = result.confidence)
+ return Type(result.type, platform = self.platform, confidence = result.confidence)
@property
def calling_convention(self):
@@ -288,7 +301,18 @@ class Type(object):
params = core.BNGetTypeParameters(self.handle, count)
result = []
for i in xrange(0, count.value):
- result.append((Type(core.BNNewTypeReference(params[i].type), confidence = params[i].typeConfidence), params[i].name))
+ param_type = Type(core.BNNewTypeReference(params[i].type), platform = self.platform, confidence = params[i].typeConfidence)
+ if params[i].defaultLocation:
+ param_location = None
+ else:
+ name = params[i].name
+ if (params[i].location.type == VariableSourceType.RegisterVariableSourceType) and (self.platform is not None):
+ name = self.platform.arch.get_reg_name(params[i].location.storage)
+ elif params[i].location.type == VariableSourceType.StackVariableSourceType:
+ name = "arg_%x" % params[i].location.storage
+ param_location = function.Variable(None, params[i].location.type, params[i].location.index,
+ params[i].location.storage, name, param_type)
+ result.append(FunctionParameter(param_type, params[i].name, param_location))
core.BNFreeTypeParameterList(params, count.value)
return result
@@ -339,7 +363,10 @@ class Type(object):
return core.BNGetTypeOffset(self.handle)
def __str__(self):
- return core.BNGetTypeString(self.handle)
+ platform = None
+ if self.platform is not None:
+ platform = self.platform.handle
+ return core.BNGetTypeString(self.handle, platform)
def __repr__(self):
if self.confidence < max_confidence:
@@ -347,16 +374,28 @@ class Type(object):
return "<type: %s>" % str(self)
def get_string_before_name(self):
- return core.BNGetTypeStringBeforeName(self.handle)
+ platform = None
+ if self.platform is not None:
+ platform = self.platform.handle
+ return core.BNGetTypeStringBeforeName(self.handle, platform)
def get_string_after_name(self):
- return core.BNGetTypeStringAfterName(self.handle)
+ platform = None
+ if self.platform is not None:
+ platform = self.platform.handle
+ return core.BNGetTypeStringAfterName(self.handle, platform)
@property
def tokens(self):
"""Type string as a list of tokens (read-only)"""
+ return self.get_tokens()
+
+ def get_tokens(self, base_confidence = max_confidence):
count = ctypes.c_ulonglong()
- tokens = core.BNGetTypeTokens(self.handle, count)
+ platform = None
+ if self.platform is not None:
+ platform = self.platform.handle
+ tokens = core.BNGetTypeTokens(self.handle, platform, base_confidence, count)
result = []
for i in xrange(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
@@ -371,9 +410,12 @@ class Type(object):
core.BNFreeTokenList(tokens, count.value)
return result
- def get_tokens_before_name(self):
+ def get_tokens_before_name(self, base_confidence = max_confidence):
count = ctypes.c_ulonglong()
- tokens = core.BNGetTypeTokensBeforeName(self.handle, count)
+ platform = None
+ if self.platform is not None:
+ platform = self.platform.handle
+ tokens = core.BNGetTypeTokensBeforeName(self.handle, platform, base_confidence, count)
result = []
for i in xrange(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
@@ -388,9 +430,12 @@ class Type(object):
core.BNFreeTokenList(tokens, count.value)
return result
- def get_tokens_after_name(self):
+ def get_tokens_after_name(self, base_confidence = max_confidence):
count = ctypes.c_ulonglong()
- tokens = core.BNGetTypeTokensAfterName(self.handle, count)
+ platform = None
+ if self.platform is not None:
+ platform = self.platform.handle
+ tokens = core.BNGetTypeTokensAfterName(self.handle, platform, base_confidence, count)
result = []
for i in xrange(0, count.value):
token_type = InstructionTextTokenType(tokens[i].type)
@@ -515,16 +560,29 @@ class Type(object):
:param CallingConvention calling_convention: optional argument for function calling convention
:param bool variable_arguments: optional argument for functions that have a variable number of arguments
"""
- param_buf = (core.BNNameAndType * len(params))()
+ param_buf = (core.BNFunctionParameter * len(params))()
for i in xrange(0, len(params)):
if isinstance(params[i], Type):
param_buf[i].name = ""
param_buf[i].type = params[i].handle
param_buf[i].typeConfidence = params[i].confidence
+ param_buf[i].defaultLocation = True
+ elif isinstance(params[i], FunctionParameter):
+ param_buf[i].name = params[i].name
+ param_buf[i].type = params[i].type.handle
+ param_buf[i].typeConfidence = params[i].type.confidence
+ if params[i].location is None:
+ param_buf[i].defaultLocation = True
+ else:
+ param_buf[i].defaultLocation = False
+ param_buf[i].location.type = params[i].location.type
+ param_buf[i].location.index = params[i].location.index
+ param_buf[i].location.storage = params[i].location.storage
else:
param_buf[i].name = params[i][1]
param_buf[i].type = params[i][0].handle
param_buf[i].typeConfidence = params[i][0].confidence
+ param_buf[i].defaultLocation = True
ret_conf = core.BNTypeWithConfidence()
ret_conf.type = ret.handle
@@ -565,7 +623,7 @@ class Type(object):
return core.BNGetAutoDemangledTypeIdSource()
def with_confidence(self, confidence):
- return Type(handle = core.BNNewTypeReference(self.handle), confidence = confidence)
+ return Type(handle = core.BNNewTypeReference(self.handle), platform = self.platform, confidence = confidence)
def __setattr__(self, name, value):
try: