diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/architecture.py | 93 | ||||
| -rw-r--r-- | python/binaryview.py | 22 | ||||
| -rw-r--r-- | python/function.py | 15 | ||||
| -rw-r--r-- | python/generator.cpp | 63 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 5 | ||||
| -rw-r--r-- | python/platform.py | 109 | ||||
| -rw-r--r-- | python/types.py | 90 |
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: |
