diff options
| author | Peter LaFosse <peter@vector35.com> | 2020-06-12 16:27:36 -0400 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2020-06-23 09:02:48 -0400 |
| commit | e0fbcc712f8ca31914d2f1e04b7f8b16eff44d66 (patch) | |
| tree | 1c79e6e76f4d0bdf6dfc09c3cd3036dbf96c56f2 | |
| parent | 4ffa5187aa0c9589dffac5bf00f3a7dd423578e8 (diff) | |
Add BinaryView.parse_types_from_string to the python API and update how the underlying BNParseTypesString works
| -rw-r--r-- | binaryninjaapi.h | 3 | ||||
| -rw-r--r-- | binaryninjacore.h | 3 | ||||
| -rw-r--r-- | binaryview.cpp | 38 | ||||
| -rw-r--r-- | platform.cpp | 7 | ||||
| -rw-r--r-- | python/binaryview.py | 52 | ||||
| -rw-r--r-- | python/platform.py | 4 |
6 files changed, 81 insertions, 26 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 60320769..0328b58f 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1649,7 +1649,8 @@ __attribute__ ((format (printf, 1, 2))) uint64_t GetPreviousDataVariableStartBeforeAddress(uint64_t addr); bool ParseTypeString(const std::string& text, QualifiedNameAndType& result, std::string& errors); - bool ParseTypeString(const std::string& text, std::map<QualifiedName, Ref<Type>>& result, std::string& errors); + bool ParseTypeString(const std::string& text, std::map<QualifiedName, Ref<Type>>& types, + std::map<QualifiedName, Ref<Type>>& variables, std::map<QualifiedName, Ref<Type>>& functions, std::string& errors); std::map<QualifiedName, Ref<Type>> GetTypes(); std::vector<QualifiedName> GetTypeNames(const std::string& matching=""); diff --git a/binaryninjacore.h b/binaryninjacore.h index 35dcc31b..b09a917a 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -3232,8 +3232,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI bool BNParseTypeString(BNBinaryView* view, const char* text, BNQualifiedNameAndType* result, char** errors); - BINARYNINJACOREAPI bool BNParseTypesString(BNBinaryView* view, const char* text, - BNQualifiedNameAndType** result, size_t* count, char** errors); + BINARYNINJACOREAPI bool BNParseTypesString(BNBinaryView* view, const char* text, BNTypeParserResult* result, char** errors); BINARYNINJACOREAPI void BNFreeQualifiedNameAndType(BNQualifiedNameAndType* obj); BINARYNINJACOREAPI void BNFreeQualifiedNameAndTypeArray(BNQualifiedNameAndType* obj, size_t count); diff --git a/binaryview.cpp b/binaryview.cpp index 0dfd0a8d..287dc94b 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -2466,26 +2466,38 @@ bool BinaryView::ParseTypeString(const string& text, QualifiedNameAndType& resul } -bool BinaryView::ParseTypeString(const string& text, std::map<QualifiedName, Ref<Type>>& result, string& errors) +bool BinaryView::ParseTypeString(const string& source, map<QualifiedName, Ref<Type>>& types, + map<QualifiedName, Ref<Type>>& variables, map<QualifiedName, Ref<Type>>& functions, string& errors) { - BNQualifiedNameAndType* nt; + BNTypeParserResult result; char* errorStr; - size_t count; - if (!BNParseTypesString(m_object, text.c_str(), &nt, &count, &errorStr)) - { - errors = errorStr; - BNFreeString(errorStr); + types.clear(); + variables.clear(); + functions.clear(); + + bool ok = BNParseTypesString(m_object, source.c_str(), &result, &errorStr); + errors = errorStr; + BNFreeString(errorStr); + if (!ok) return false; - } - for(size_t i = 0; i < count; i++) + for (size_t i = 0; i < result.typeCount; i++) { - result[QualifiedName::FromAPIObject(&nt[i].name)] = new Type(BNNewTypeReference(nt[i].type)); + QualifiedName name = QualifiedName::FromAPIObject(&result.types[i].name); + types[name] = new Type(BNNewTypeReference(result.types[i].type)); } - BNFreeQualifiedNameAndTypeArray(nt, count); - - errors = ""; + 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; } diff --git a/platform.cpp b/platform.cpp index 070c6d94..1a94b34d 100644 --- a/platform.cpp +++ b/platform.cpp @@ -430,6 +430,7 @@ bool Platform::ParseTypesFromSource(const string& source, const string& fileName &errorStr, includeDirList, includeDirs.size(), autoTypeSource.c_str()); errors = errorStr; BNFreeString(errorStr); + delete[] includeDirList; if (!ok) return false; @@ -441,14 +442,13 @@ bool Platform::ParseTypesFromSource(const string& source, const string& fileName for (size_t i = 0; i < result.variableCount; i++) { QualifiedName name = QualifiedName::FromAPIObject(&result.variables[i].name); - types[name] = new Type(BNNewTypeReference(result.variables[i].type)); + 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); - types[name] = new Type(BNNewTypeReference(result.functions[i].type)); + functions[name] = new Type(BNNewTypeReference(result.functions[i].type)); } - delete[] includeDirList; BNFreeTypeParserResult(&result); return true; } @@ -473,6 +473,7 @@ bool Platform::ParseTypesFromSourceFile(const string& fileName, map<QualifiedNam includeDirList, includeDirs.size(), autoTypeSource.c_str()); errors = errorStr; BNFreeString(errorStr); + delete[] includeDirList; if (!ok) return false; diff --git a/python/binaryview.py b/python/binaryview.py index 1cf802a2..3e1478be 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -4579,9 +4579,10 @@ class BinaryView(object): def parse_type_string(self, text): """ - ``parse_type_string`` converts `C-style` string into a :py:Class:`Type`. + ``parse_type_string`` parses string containing C into a single type :py:Class:`Type`. + In contrast to the :py:'platform - :param str text: `C-style` string of type to create + :param str text: C source code string of type to create :return: A tuple of a :py:Class:`Type` and type name :rtype: tuple(Type, QualifiedName) :Example: @@ -4590,12 +4591,12 @@ class BinaryView(object): (<type: int32_t>, 'foo') >>> """ - if not isinstance(text, str): - raise AttributeError("Text must be a string") + if not (isinstance(text, str) or isinstance(text, unicode)): + raise AttributeError("Source must be a string") result = core.BNQualifiedNameAndType() errors = ctypes.c_char_p() if not core.BNParseTypeString(self.handle, text, result, errors): - error_str = errors.value + error_str = errors.value.decode("utf-8") core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) raise SyntaxError(error_str) type_obj = types.Type(core.BNNewTypeReference(result.type), platform = self.platform) @@ -4603,6 +4604,47 @@ class BinaryView(object): core.BNFreeQualifiedNameAndType(result) return type_obj, name + def parse_types_from_string(self, text): + """ + ``parse_types_from_string`` parses string containing C into a :py:Class:`TypeParserResult` objects. This API + unlike the :py:Function:`platform.Platform.parse_types_from_source` allows the reference of types already defined + in the BinaryView. + + :param str text: C source code string of types, variables, and function types, to create + :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error) + :rtype: TypeParserResult + :Example: + + >>> bv.parse_types_from_string('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 not (isinstance(text, str) or isinstance(text, unicode)): + raise AttributeError("Source must be a string") + + parse = core.BNTypeParserResult() + errors = ctypes.c_char_p() + if not core.BNParseTypesString(self.handle, text, parse, errors): + error_str = errors.value.decode("utf-8") + core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) + raise SyntaxError(error_str) + + type_dict = {} + variables = {} + functions = {} + for i in range(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.platform) + for i in range(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.platform) + for i in range(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.platform) + core.BNFreeTypeParserResult(parse) + return types.TypeParserResult(type_dict, variables, functions) + def get_type_by_name(self, name): """ ``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name`` diff --git a/python/platform.py b/python/platform.py index 5031d2d6..8d7d1d99 100644 --- a/python/platform.py +++ b/python/platform.py @@ -411,7 +411,7 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): 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 + error_str = errors.value.decode("utf-8") core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: raise SyntaxError(error_str) @@ -460,7 +460,7 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): 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 + error_str = errors.value.decode("utf-8") core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: raise SyntaxError(error_str) |
