summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter LaFosse <peter@vector35.com>2020-06-12 16:27:36 -0400
committerPeter LaFosse <peter@vector35.com>2020-06-23 09:02:48 -0400
commite0fbcc712f8ca31914d2f1e04b7f8b16eff44d66 (patch)
tree1c79e6e76f4d0bdf6dfc09c3cd3036dbf96c56f2
parent4ffa5187aa0c9589dffac5bf00f3a7dd423578e8 (diff)
Add BinaryView.parse_types_from_string to the python API and update how the underlying BNParseTypesString works
-rw-r--r--binaryninjaapi.h3
-rw-r--r--binaryninjacore.h3
-rw-r--r--binaryview.cpp38
-rw-r--r--platform.cpp7
-rw-r--r--python/binaryview.py52
-rw-r--r--python/platform.py4
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)