Skip to content

Commit

Permalink
Add importDependencies argument to ParseTypeString to control lib…
Browse files Browse the repository at this point in the history
…rary imports
  • Loading branch information
CouleeApps committed Apr 3, 2024
1 parent 6320364 commit 6955825
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 30 deletions.
48 changes: 43 additions & 5 deletions binaryninjaapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -5858,11 +5858,12 @@ namespace BinaryNinja {
\param[in] text Text containing the type definition
\param[out] result Reference into which the resulting type and name will be written
\param[out] errors Reference to a list into which any parse errors will be written
\param typesAllowRedefinition
\param[in] typesAllowRedefinition List of types whose names are allowed to be overwritten (legacy cruft?)
\param[in] importDependencies If Type Library / Type Archive types should be imported during parsing
\return Whether parsing was successful
*/
bool ParseTypeString(const std::string& text, QualifiedNameAndType& result, std::string& errors,
const std::set<QualifiedName>& typesAllowRedefinition = {});
const std::set<QualifiedName>& typesAllowRedefinition = {}, bool importDependencies = true);

/*! Parse an entire block of source into types, variables, and functions

Expand All @@ -5871,14 +5872,25 @@ namespace BinaryNinja {
\param[out] variables Reference to a list of QualifiedNames and Types the parsed variables will be writen to
\param[out] functions Reference to a list of QualifiedNames and Types the parsed functions will be writen to
\param[out] errors Reference to a list into which any parse errors will be written
\param typesAllowRedefinition
\param[in] typesAllowRedefinition List of types whose names are allowed to be overwritten (legacy cruft?)
\param[in] importDependencies If Type Library / Type Archive types should be imported during parsing
\return Whether parsing was successful
*/
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, const std::set<QualifiedName>& typesAllowRedefinition = {});
std::string& errors, const std::set<QualifiedName>& typesAllowRedefinition = {}, bool importDependencies = true);

/*! Parse an entire block of source into a structure containing types, variables, and functions

\param[in] text Source code to parse
\param[out] result Reference to a TypeParserResult structure into which types, variables, and functions will be written
\param[out] errors Reference to a list into which any parse errors will be written
\param[in] typesAllowRedefinition List of types whose names are allowed to be overwritten (legacy cruft?)
\param[in] importDependencies If Type Library / Type Archive types should be imported during parsing
\return Whether parsing was successful
*/
bool ParseTypesFromSource(const std::string& text, const std::vector<std::string>& options, const std::vector<std::string>& includeDirs, TypeParserResult& result,
std::string& errors, const std::set<QualifiedName>& typesAllowRedefinition = {});
std::string& errors, const std::set<QualifiedName>& typesAllowRedefinition = {}, bool importDependencies = true);

/*! Type Container for all types (user and auto) in the BinaryView. Any auto types
modified through the Type Container will be converted into user types.
Expand Down Expand Up @@ -17287,10 +17299,21 @@ namespace BinaryNinja {
with knowledge of the types in the Type Container.

\param source Source code to parse
\param importDependencies If Type Library / Type Archive types should be imported during parsing
\param result Reference into which the resulting type and name will be written
\param errors Reference to a list into which any parse errors will be written
\return True if parsing was successful
*/
bool ParseTypeString(
const std::string& source,
bool importDependencies,
QualifiedNameAndType& result,
std::vector<TypeParserError>& errors
);

/*!
\deprecated Use `ParseTypeString` with the extra `importDependencies` param
*/
bool ParseTypeString(
const std::string& source,
QualifiedNameAndType& result,
Expand All @@ -17305,10 +17328,25 @@ namespace BinaryNinja {
\param options Optional string arguments to pass as options, e.g. command line arguments
\param includeDirs Optional list of directories to include in the header search path
\param autoTypeSource Optional source of types if used for automatically generated types
\param importDependencies If Type Library / Type Archive types should be imported during parsing
\param result Reference to structure into which the results will be written
\param errors Reference to a list into which any parse errors will be written
\return True if successful
*/
bool ParseTypesFromSource(
const std::string& text,
const std::string& fileName,
const std::vector<std::string>& options,
const std::vector<std::string>& includeDirs,
const std::string& autoTypeSource,
bool importDependencies,
TypeParserResult& result,
std::vector<TypeParserError>& errors
);

/*!
\deprecated Use `ParseTypesFromSource` with the extra `importDependencies` param
*/
bool ParseTypesFromSource(
const std::string& text,
const std::string& fileName,
Expand Down
8 changes: 4 additions & 4 deletions binaryninjacore.h
Original file line number Diff line number Diff line change
Expand Up @@ -4662,10 +4662,10 @@ extern "C"
BINARYNINJACOREAPI bool BNGetDataVariableAtAddress(BNBinaryView* view, uint64_t addr, BNDataVariable* var);

BINARYNINJACOREAPI bool BNParseTypeString(BNBinaryView* view, const char* text, BNQualifiedNameAndType* result,
char** errors, BNQualifiedNameList* typesAllowRedefinition);
char** errors, BNQualifiedNameList* typesAllowRedefinition, bool importDepencencies);
BINARYNINJACOREAPI bool BNParseTypesString(BNBinaryView* view, const char* text, const char* const* options, size_t optionCount,
const char* const* includeDirs, size_t includeDirCount, BNTypeParserResult* result, char** errors,
BNQualifiedNameList* typesAllowRedefinition);
BNQualifiedNameList* typesAllowRedefinition, bool importDepencencies);
BINARYNINJACOREAPI void BNFreeQualifiedNameAndType(BNQualifiedNameAndType* obj);
BINARYNINJACOREAPI void BNFreeQualifiedNameAndTypeArray(BNQualifiedNameAndType* obj, size_t count);
BINARYNINJACOREAPI void BNFreeQualifiedNameTypeAndId(BNQualifiedNameTypeAndId* obj);
Expand Down Expand Up @@ -4746,14 +4746,14 @@ extern "C"
BINARYNINJACOREAPI bool BNTypeContainerGetTypeNames(BNTypeContainer* container, BNQualifiedName** typeNames, size_t* count);
BINARYNINJACOREAPI bool BNTypeContainerGetTypeNamesAndIds(BNTypeContainer* container, char*** typeIds, BNQualifiedName** typeNames, size_t* count);
BINARYNINJACOREAPI bool BNTypeContainerParseTypeString(BNTypeContainer* container,
const char* source, BNQualifiedNameAndType* result,
const char* source, bool importDepencencies, BNQualifiedNameAndType* result,
BNTypeParserError** errors, size_t* errorCount
);
BINARYNINJACOREAPI bool BNTypeContainerParseTypesFromSource(BNTypeContainer* container,
const char* source, const char* fileName,
const char* const* options, size_t optionCount,
const char* const* includeDirs, size_t includeDirCount,
const char* autoTypeSource, BNTypeParserResult* result,
const char* autoTypeSource, bool importDepencencies, BNTypeParserResult* result,
BNTypeParserError** errors, size_t* errorCount
);

Expand Down
12 changes: 6 additions & 6 deletions binaryview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3717,7 +3717,7 @@ bool BinaryView::ParsePossibleValueSet(


bool BinaryView::ParseTypeString(const string& text, QualifiedNameAndType& result, string& errors,
const std::set<QualifiedName>& typesAllowRedefinition)
const std::set<QualifiedName>& typesAllowRedefinition, bool importDependencies)
{
BNQualifiedNameAndType nt;
char* errorStr;
Expand All @@ -3732,7 +3732,7 @@ bool BinaryView::ParseTypeString(const string& text, QualifiedNameAndType& resul
i++;
}

if (!BNParseTypeString(m_object, text.c_str(), &nt, &errorStr, &typesList))
if (!BNParseTypeString(m_object, text.c_str(), &nt, &errorStr, &typesList, importDependencies))
{
errors = errorStr;
BNFreeString(errorStr);
Expand All @@ -3751,7 +3751,7 @@ bool BinaryView::ParseTypeString(const string& text, QualifiedNameAndType& resul

bool BinaryView::ParseTypeString(const string& source, map<QualifiedName, Ref<Type>>& types,
map<QualifiedName, Ref<Type>>& variables, map<QualifiedName, Ref<Type>>& functions, string& errors,
const std::set<QualifiedName>& typesAllowRedefinition)
const std::set<QualifiedName>& typesAllowRedefinition, bool importDependencies)
{
BNTypeParserResult result;
char* errorStr = nullptr;
Expand All @@ -3774,7 +3774,7 @@ bool BinaryView::ParseTypeString(const string& source, map<QualifiedName, Ref<Ty
vector<const char*> includeDirs;

bool ok = BNParseTypesString(m_object, source.c_str(), options.data(), options.size(),
includeDirs.data(), includeDirs.size(), &result, &errorStr, &typesList);
includeDirs.data(), includeDirs.size(), &result, &errorStr, &typesList, importDependencies);
if (errorStr)
{
errors = errorStr;
Expand Down Expand Up @@ -3805,7 +3805,7 @@ bool BinaryView::ParseTypeString(const string& source, map<QualifiedName, Ref<Ty


bool BinaryView::ParseTypesFromSource(const string& source, const vector<string>& options, const vector<string>& includeDirs,
TypeParserResult& result, string& errors, const std::set<QualifiedName>& typesAllowRedefinition)
TypeParserResult& result, string& errors, const std::set<QualifiedName>& typesAllowRedefinition, bool importDependencies)
{
BNQualifiedNameList typesList;
typesList.count = typesAllowRedefinition.size();
Expand All @@ -3829,7 +3829,7 @@ bool BinaryView::ParseTypesFromSource(const string& source, const vector<string>
char* errorStr = nullptr;

bool ok = BNParseTypesString(m_object, source.c_str(), coreOptions.data(), coreOptions.size(),
coreIncludeDirs.data(), coreIncludeDirs.size(), &apiResult, &errorStr, &typesList);
coreIncludeDirs.data(), coreIncludeDirs.size(), &apiResult, &errorStr, &typesList, importDependencies);
if (errorStr)
{
errors = errorStr;
Expand Down
12 changes: 7 additions & 5 deletions python/binaryview.py
Original file line number Diff line number Diff line change
Expand Up @@ -7026,14 +7026,15 @@ def __iter__(self):

return iter(LinearDisassemblyIterator(self, settings))

def parse_type_string(self, text: str) -> Tuple['_types.Type', '_types.QualifiedName']:
def parse_type_string(self, text: str, import_dependencies: bool = True) -> Tuple['_types.Type', '_types.QualifiedName']:
"""
``parse_type_string`` parses string containing C into a single type :py:class:`Type`.
In contrast to the :py:func:`~binaryninja.platform.Platform.parse_types_from_source` or :py:func:`~binaryninja.platform.Platform.parse_types_from_source_file`, ``parse_type_string``
can only load a single type, though it can take advantage of existing type information in the binary
view, while those two APIs do not.

:param str text: C source code string of type to create
:param import_dependencies: If Type Library / Type Archive types should be imported during parsing
:return: A tuple of a :py:class:`Type` and type name
:rtype: tuple(Type, QualifiedName)
:Example:
Expand All @@ -7050,7 +7051,7 @@ def parse_type_string(self, text: str) -> Tuple['_types.Type', '_types.Qualified
errors = ctypes.c_char_p()
type_list = core.BNQualifiedNameList()
type_list.count = 0
if not core.BNParseTypeString(self.handle, text, result, errors, type_list):
if not core.BNParseTypeString(self.handle, text, result, errors, type_list, import_dependencies):
assert errors.value is not None, "core.BNParseTypeString returned 'errors' set to None"
error_str = errors.value.decode("utf-8")
core.free_string(errors)
Expand All @@ -7061,7 +7062,7 @@ def parse_type_string(self, text: str) -> Tuple['_types.Type', '_types.Qualified
finally:
core.BNFreeQualifiedNameAndType(result)

def parse_types_from_string(self, text: str, options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None) -> '_types.TypeParserResult':
def parse_types_from_string(self, text: str, options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None, import_dependencies: bool = True) -> '_types.TypeParserResult':
"""
``parse_types_from_string`` parses string containing C into a :py:class:`TypeParserResult` objects. This API
unlike the :py:func:`~binaryninja.platform.Platform.parse_types_from_source` allows the reference of types already defined
Expand All @@ -7070,6 +7071,7 @@ def parse_types_from_string(self, text: str, options: Optional[List[str]] = None
:param str text: C source code string of types, variables, and function types, to create
:param options: Optional list of string options to be passed into the type parser
:param include_dirs: Optional list of header search directories
:param import_dependencies: If Type Library / Type Archive types should be imported during parsing
:return: :py:class:`~binaryninja.typeparser.TypeParserResult` (a SyntaxError is thrown on parse error)
:rtype: TypeParserResult
:Example:
Expand Down Expand Up @@ -7102,7 +7104,7 @@ def parse_types_from_string(self, text: str, options: Optional[List[str]] = None
type_list.count = 0
if not core.BNParseTypesString(
self.handle, text, options_cpp, len(options), include_dirs_cpp,
len(include_dirs), parse, errors, type_list):
len(include_dirs), parse, errors, type_list, import_dependencies):
assert errors.value is not None, "core.BNParseTypesString returned errors set to None"
error_str = errors.value.decode("utf-8")
core.free_string(errors)
Expand Down Expand Up @@ -7170,7 +7172,7 @@ def parse_possiblevalueset(
value = ''
if not core.BNParsePossibleValueSet(self.handle, value, state, result, here, errors):
if errors:
assert errors.value is not None, "core.BNParseTypesString returned errors set to None"
assert errors.value is not None, "core.BNParsePossibleValueSet returned errors set to None"
error_str = errors.value.decode("utf-8")
else:
error_str = "Error parsing specified PossibleValueSet"
Expand Down
42 changes: 40 additions & 2 deletions python/typecontainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,46 @@ def type_names_and_ids(self) -> Optional[Mapping[str, '_types.QualifiedName']]:
core.BNFreeStringList(result_ids, result_count.value)
return result

def parse_type_string(
self, source: str, import_dependencies: bool = True
) -> Tuple[Optional[Tuple['_types.QualifiedNameType', '_types.Type']], List['typeparser.TypeParserError']]:
"""
Parse a single type and name from a string containing their definition, with
knowledge of the types in the Type Container.

:param source: Source code to parse
:param import_dependencies: If Type Library / Type Archive types should be imported during parsing
:return: A tuple of (result, errors) where result is a tuple of (type, name) or
None of there was a fatal error.
"""
result_cpp = core.BNQualifiedNameAndType()
errors_cpp = ctypes.POINTER(core.BNTypeParserError)()
error_count = ctypes.c_size_t()

success = core.BNTypeContainerParseTypeString(
self.handle, source, import_dependencies, result_cpp, errors_cpp, error_count
)

if success:
result = (
_types.QualifiedName._from_core_struct(result_cpp.name),
_types.Type.create(handle=core.BNNewTypeReference(result_cpp.type))
)
core.BNFreeQualifiedNameAndType(result_cpp)
else:
result = None
core.BNFreeTypeParserResult(result_cpp)

errors = []
for i in range(error_count.value):
errors.append(typeparser.TypeParserError._from_core_struct(errors_cpp[i]))
core.BNFreeTypeParserErrors(errors_cpp, error_count.value)

return result, errors

def parse_types_from_source(self, source: str, file_name: str,
options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None,
auto_type_source: str = ""
auto_type_source: str = "", import_dependencies: bool = True
) -> Tuple[Optional['typeparser.TypeParserResult'], List['typeparser.TypeParserError']]:
"""
Parse an entire block of source into types, variables, and functions, with
Expand All @@ -313,6 +350,7 @@ def parse_types_from_source(self, source: str, file_name: str,
:param options: Optional string arguments to pass as options, e.g. command line arguments
:param include_dirs: Optional list of directories to include in the header search path
:param auto_type_source: Optional source of types if used for automatically generated types
:param import_dependencies: If Type Library / Type Archive types should be imported during parsing
:return: A tuple of (result, errors) where the result is None if there was a fatal error
"""
if options is None:
Expand All @@ -335,7 +373,7 @@ def parse_types_from_source(self, source: str, file_name: str,
success = core.BNTypeContainerParseTypesFromSource(
self.handle, source, file_name,
options_cpp, len(options),
include_dirs_cpp, len(include_dirs), auto_type_source,
include_dirs_cpp, len(include_dirs), auto_type_source, import_dependencies,
result_cpp, errors_cpp, error_count
)

Expand Down
51 changes: 43 additions & 8 deletions typecontainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ std::optional<std::unordered_map<std::string, QualifiedName>> TypeContainer::Get

bool TypeContainer::ParseTypeString(
const std::string& source,
bool importDependencies,
BinaryNinja::QualifiedNameAndType& result,
std::vector<TypeParserError>& errors
)
Expand All @@ -339,7 +340,7 @@ bool TypeContainer::ParseTypeString(
BNTypeParserError* apiErrors;
size_t errorCount;

auto success = BNTypeContainerParseTypeString(m_object, source.c_str(), &apiResult,
auto success = BNTypeContainerParseTypeString(m_object, source.c_str(), importDependencies, &apiResult,
&apiErrors, &errorCount);

for (size_t j = 0; j < errorCount; j ++)
Expand Down Expand Up @@ -367,12 +368,23 @@ bool TypeContainer::ParseTypeString(
}


bool TypeContainer::ParseTypeString(
const std::string& source,
BinaryNinja::QualifiedNameAndType& result,
std::vector<TypeParserError>& errors
)
{
return ParseTypeString(source, true, result, errors);
}


bool TypeContainer::ParseTypesFromSource(
const std::string& text,
const std::string& fileName,
const std::vector<std::string>& options,
const std::vector<std::string>& includeDirs,
const std::string& autoTypeSource,
bool importDependencies,
BinaryNinja::TypeParserResult& result,
std::vector<TypeParserError>& errors
)
Expand All @@ -393,8 +405,8 @@ bool TypeContainer::ParseTypesFromSource(
size_t errorCount;

auto success = BNTypeContainerParseTypesFromSource(m_object, text.c_str(), fileName.c_str(),
apiOptions, options.size(), apiIncludeDirs, includeDirs.size(), autoTypeSource.c_str(), &apiResult,
&apiErrors, &errorCount);
apiOptions, options.size(), apiIncludeDirs, includeDirs.size(), autoTypeSource.c_str(), importDependencies,
&apiResult, &apiErrors, &errorCount);

delete [] apiOptions;
delete [] apiIncludeDirs;
Expand All @@ -403,11 +415,11 @@ bool TypeContainer::ParseTypesFromSource(
{
TypeParserError error;
error.severity = apiErrors[j].severity,
error.message = apiErrors[j].message,
error.fileName = apiErrors[j].fileName,
error.line = apiErrors[j].line,
error.column = apiErrors[j].column,
errors.push_back(error);
error.message = apiErrors[j].message,
error.fileName = apiErrors[j].fileName,
error.line = apiErrors[j].line,
error.column = apiErrors[j].column,
errors.push_back(error);
}
BNFreeTypeParserErrors(apiErrors, errorCount);

Expand Down Expand Up @@ -449,3 +461,26 @@ bool TypeContainer::ParseTypesFromSource(
BNFreeTypeParserResult(&apiResult);
return true;
}


bool TypeContainer::ParseTypesFromSource(
const std::string& text,
const std::string& fileName,
const std::vector<std::string>& options,
const std::vector<std::string>& includeDirs,
const std::string& autoTypeSource,
BinaryNinja::TypeParserResult& result,
std::vector<TypeParserError>& errors
)
{
return ParseTypesFromSource(
text,
fileName,
options,
includeDirs,
autoTypeSource,
true,
result,
errors
);
}

0 comments on commit 6955825

Please sign in to comment.