diff options
| author | KyleMiles <krm504@nyu.edu> | 2022-09-28 18:21:13 -0400 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2022-10-04 15:36:26 -0400 |
| commit | 3104042adab833e73a71738f57070ab881ade615 (patch) | |
| tree | 4e5280c162a3f681dab5be6c15dba749d5c30115 | |
| parent | ed820d2ab81470b3e5ac543d75211e87ff3bc738 (diff) | |
Rename and move `Analysis/Database Merge Tool` to `File/Merge Databases`; Add API bindings for `BinaryView::GetDebugInfo()`, `BinaryView::ApplyDebugInfo()`, and `BinaryView::SetDebugInfo()`; Remove `analysis.experimental.parseDebugInfo`
(in favor of `loader.debugInfoInternal` and `loader.debugInfoExternal`)
| -rw-r--r-- | binaryninjaapi.h | 5 | ||||
| -rw-r--r-- | binaryview.cpp | 21 | ||||
| -rw-r--r-- | docs/getting-started.md | 1 | ||||
| -rw-r--r-- | python/debuginfo.py | 2 | ||||
| -rwxr-xr-x | python/examples/debug_info.py | 2 | ||||
| -rw-r--r-- | python/examples/mappedview.py | 6 | ||||
| -rw-r--r-- | rust/src/debuginfo.rs | 2 | ||||
| -rw-r--r-- | suite/api_test.py | 242 | ||||
| -rw-r--r-- | ui/settingsview.h | 1 |
9 files changed, 155 insertions, 127 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 91395a90..b58db5cb 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2480,6 +2480,7 @@ namespace BinaryNinja { class NamedTypeReference; struct TypeParserResult; class Component; + class DebugInfo; class QueryMetadataException : public std::exception { @@ -3631,6 +3632,10 @@ namespace BinaryNinja { */ void DefineImportedFunction(Ref<Symbol> importAddressSym, Ref<Function> func, Ref<Type> type = nullptr); + Ref<DebugInfo> GetDebugInfo(); + void ApplyDebugInfo(Ref<DebugInfo> newDebugInfo); + void SetDebugInfo(Ref<DebugInfo> newDebugInfo); + void BeginBulkModifySymbols(); void EndBulkModifySymbols(); diff --git a/binaryview.cpp b/binaryview.cpp index dba92d7c..b8dd7c1a 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -2560,6 +2560,27 @@ void BinaryView::DefineImportedFunction(Ref<Symbol> importAddressSym, Ref<Functi } +Ref<DebugInfo> BinaryView::GetDebugInfo() +{ + BNDebugInfo* result = BNGetDebugInfo(m_object); + if (!result) + return nullptr; + return new DebugInfo(result); +} + + +void BinaryView::ApplyDebugInfo(Ref<DebugInfo> newDebugInfo) +{ + BNApplyDebugInfo(m_object, newDebugInfo->GetObject()); +} + + +void BinaryView::SetDebugInfo(Ref<DebugInfo> newDebugInfo) +{ + BNSetDebugInfo(m_object, newDebugInfo->GetObject()); +} + + void BinaryView::BeginBulkModifySymbols() { BNBeginBulkModifySymbols(m_object); diff --git a/docs/getting-started.md b/docs/getting-started.md index f99dbd2d..a343e995 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -687,7 +687,6 @@ Here's a list of all built-in settings currently available from the UI: |analysis|Gratuitous Function Update|Force the function update cycle to always end with an IncrementalAutoFunctionUpdate type.|`boolean`|`False`|[`SettingsProjectScope`, `SettingsResourceScope`, `SettingsUserScope`]|<a id='analysis.experimental.gratuitousFunctionUpdate'>analysis.experimental.gratuitousFunctionUpdate</a>| |analysis|Heuristic Value Range Clamping|Use DataVariable state inferencing to help determine the possible size of a lookup table.|`boolean`|`True`|[`SettingsProjectScope`, `SettingsResourceScope`, `SettingsUserScope`]|<a id='analysis.experimental.heuristicRangeClamp'>analysis.experimental.heuristicRangeClamp</a>| |analysis|Keep Dead Code Branches|Keep unreachable code branches and associated basic blocks in HLIL.|`boolean`|`False`|[`SettingsProjectScope`, `SettingsResourceScope`, `SettingsUserScope`]|<a id='analysis.experimental.keepDeadCodeBranches'>analysis.experimental.keepDeadCodeBranches</a>| -|analysis|Parse and Apply Debug Info|Attempt to parse debug info with supplied debug info plugins for utilization during analysis.|`boolean`|`False`|[`SettingsProjectScope`, `SettingsResourceScope`, `SettingsUserScope`]|<a id='analysis.experimental.parseDebugInfo'>analysis.experimental.parseDebugInfo</a>| |analysis|Always Analyze Indirect Branches|When using faster analysis modes, perform full analysis of functions containing indirect branches.|`boolean`|`True`|[`SettingsProjectScope`, `SettingsResourceScope`, `SettingsUserScope`]|<a id='analysis.forceIndirectBranches'>analysis.forceIndirectBranches</a>| |analysis|Aggressive Condition Complexity Removal Threshold|High Level IL tuning parameter.|`number`|`64`|[`SettingsProjectScope`, `SettingsResourceScope`, `SettingsUserScope`]|<a id='analysis.hlil.aggressiveConditionComplexityRemovalThreshold'>analysis.hlil.aggressiveConditionComplexityRemovalThreshold</a>| |analysis|Max Condition Complexity|High Level IL tuning parameter.|`number`|`1024`|[`SettingsProjectScope`, `SettingsResourceScope`, `SettingsUserScope`]|<a id='analysis.hlil.maxConditionComplexity'>analysis.hlil.maxConditionComplexity</a>| diff --git a/python/debuginfo.py b/python/debuginfo.py index fc434bfd..153e450d 100644 --- a/python/debuginfo.py +++ b/python/debuginfo.py @@ -177,7 +177,7 @@ class DebugInfoParser(object, metaclass=_DebugInfoParserMetaClass): bn.debuginfo.DebugInfoParser.register("debug info parser", is_valid, parse_info) - :py:class:`DebugInfo` can then be automatically applied to valid binary views (via the "Parse and Apply Debug Info" setting), or manually fetched/applied as bellow:: + :py:class:`DebugInfo` will then be automatically applied to binary views that contain debug information (via the load setting `loader.debugInfoInternal`), binary views that provide valid external debug info files (`loader.debugInfoExternal`), or manually fetched/applied as below:: valid_parsers = bn.debuginfo.DebugInfoParser.get_parsers_for_view(bv) parser = valid_parsers[0] diff --git a/python/examples/debug_info.py b/python/examples/debug_info.py index 28175ba1..0dd25786 100755 --- a/python/examples/debug_info.py +++ b/python/examples/debug_info.py @@ -222,7 +222,7 @@ for p in bn.debuginfo.DebugInfoParser: print(f" {bn.debuginfo.DebugInfoParser[p.name].name}") # Test calling our `is_valid` callback -bv = bn.open_view(filename, options={"analysis.experimental.parseDebugInfo": False}) +bv = bn.open_view(filename, options={"loader.debugInfoInternal": False}) if parser.is_valid_for_view(bv): print("Parser is valid") else: diff --git a/python/examples/mappedview.py b/python/examples/mappedview.py index 645096f5..cfefa87a 100644 --- a/python/examples/mappedview.py +++ b/python/examples/mappedview.py @@ -53,7 +53,7 @@ class MappedView(BinaryView): def get_load_settings_for_data(cls, data): # This method is optional. If provided this is where the Load Settings for a BinaryViewType are specified. Binary Ninja provides # some default read-only load settings which are: - # ["loader.architecture", "loader.platform", "loader.entryPointOffset", "loader.imageBase", "loader.segments", "loader.sections"] + # ["loader.architecture", "loader.platform", "loader.entryPointOffset", "loader.imageBase", "loader.segments", "loader.sections", "loader.debugInfoInternal", "loader.debugInfoExternal"] # The default load settings are provided for consistency and convenience. # The default load settings are always generated with a read-only indication which is respected by the UI. # The read-only indication is a property that consists of a JSON name/value pair ("readOnly" : true). @@ -76,8 +76,8 @@ class MappedView(BinaryView): # Specify default load settings that can be overridden (from the UI). overrides = [ - "loader.architecture", "loader.platform", "loader.entryPointOffset", "loader.imageBase", "loader.segments", - "loader.sections" + "loader.architecture", "loader.platform", "loader.entryPointOffset", "loader.imageBase", + "loader.segments", "loader.sections", "loader.debugInfoInternal", "loader.debugInfoExternal" ] for override in overrides: if load_settings.contains(override): diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 57e40f71..1f0089fe 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -52,7 +52,7 @@ //! } //! ``` //! -//! `DebugInfo` can then be automatically applied to valid binary views (via the "Parse and Apply Debug Info" setting), or manually fetched/applied as bellow: +//! `DebugInfo` will then be automatically applied to binary views that contain debug information (via the load setting `loader.debugInfoInternal`), binary views that provide valid external debug info files (`loader.debugInfoExternal`), or manually fetched/applied as below: //! ``` //! let valid_parsers = DebugInfoParser::parsers_for_view(bv); //! let parser = valid_parsers[0]; diff --git a/suite/api_test.py b/suite/api_test.py index 7ff5ec00..2a544f7c 100644 --- a/suite/api_test.py +++ b/suite/api_test.py @@ -15,9 +15,9 @@ from binaryninja.enums import ( ) from binaryninja.types import ( - QualifiedName, Type, TypeBuilder, EnumerationMember, FunctionParameter, OffsetWithConfidence, BoolWithConfidence, - EnumerationBuilder, NamedTypeReferenceBuilder, StructureBuilder, StructureMember, IntegerType, StructureType, - Symbol, NameSpace, MutableTypeBuilder, NamedTypeReferenceType, QualifiedNameType, TypeDefinitionLine + QualifiedName, Type, TypeBuilder, EnumerationMember, FunctionParameter, OffsetWithConfidence, BoolWithConfidence, + EnumerationBuilder, NamedTypeReferenceBuilder, StructureBuilder, StructureMember, IntegerType, StructureType, + Symbol, NameSpace, MutableTypeBuilder, NamedTypeReferenceType, QualifiedNameType, TypeDefinitionLine ) from binaryninja.architecture import * from binaryninja.function import * @@ -318,6 +318,8 @@ class SettingsAPI(unittest.TestCase): assert load_settings.contains("loader.platform"), "test_load_settings failed" assert load_settings.contains("loader.imageBase"), "test_load_settings failed" assert load_settings.contains("loader.entryPointOffset"), "test_load_settings failed" + assert load_settings.contains("loader.debugInfoInternal"), "test_load_settings failed" + assert load_settings.contains("loader.debugInfoExternal"), "test_load_settings failed" load_settings.set_string("loader.architecture", 'x86_64') load_settings.set_integer("loader.imageBase", 0x500000) load_settings.set_integer("loader.entryPointOffset", 0) @@ -523,9 +525,9 @@ class TypeParserTest(unittest.TestCase): if types is None: raise SyntaxError('\n'.join(str(e) for e in errors)) return BasicTypeParserResult( - types=dict(zip([t.name for t in types.types], [t.type for t in types.types])), - variables=dict(zip([t.name for t in types.variables], [t.type for t in types.variables])), - functions=dict(zip([t.name for t in types.functions], [t.type for t in types.functions])), + types=dict(zip([t.name for t in types.types], [t.type for t in types.types])), + variables=dict(zip([t.name for t in types.variables], [t.type for t in types.variables])), + functions=dict(zip([t.name for t in types.functions], [t.type for t in types.functions])), ) def test_integers(self): @@ -688,7 +690,7 @@ class TypeParserTest(unittest.TestCase): # Clang says (TIL): # "Class 'foo' was previously declared as a struct; this is valid, but may result in linker errors under the Microsoft C++ ABI" valid = [ - r''' + r''' class foo { int a; @@ -715,27 +717,27 @@ class TypeParserTest(unittest.TestCase): def test_parse_empty(self): valid = [ - # Forward declarations - 'struct foo;', - 'class foo;', - 'union foo;', - # Definition with no members - 'struct foo {};', - 'class foo {};', - 'union foo {};', - 'enum foo {};', - # Inner structure is empty - 'struct foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };', - 'class foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };', - 'union foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };', + # Forward declarations + 'struct foo;', + 'class foo;', + 'union foo;', + # Definition with no members + 'struct foo {};', + 'class foo {};', + 'union foo {};', + 'enum foo {};', + # Inner structure is empty + 'struct foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };', + 'class foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };', + 'union foo { struct {} bar; class {} baz; union {} alpha; enum {} bravo; };', ] for source in valid: with self.subTest(): types = self.parse_types_from_source(source) invalid = [ - # Forward declaration of enum is not allowed - 'enum foo;' + # Forward declaration of enum is not allowed + 'enum foo;' ] for source in invalid: with self.subTest(): @@ -813,52 +815,52 @@ class TypeParserTest(unittest.TestCase): name = "MyTypeParser" def preprocess_source( - self, source: str, file_name: str, platform: binaryninja.Platform, - existing_types: Optional[List[QualifiedNameTypeAndId]], - options: Optional[List[str]], include_dirs: Optional[List[str]] + self, source: str, file_name: str, platform: binaryninja.Platform, + existing_types: Optional[List[QualifiedNameTypeAndId]], + options: Optional[List[str]], include_dirs: Optional[List[str]] ) -> Tuple[Optional[str], List[TypeParserError]]: return ( - source, - [ - TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1) - ] + source, + [ + TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1) + ] ) def parse_types_from_source( - self, - source: str, - file_name: str, - platform: binaryninja.Platform, - existing_types: Optional[List[QualifiedNameTypeAndId]], - options: Optional[List[str]], - include_dirs: Optional[List[str]], - auto_type_source: str = "" + self, + source: str, + file_name: str, + platform: binaryninja.Platform, + existing_types: Optional[List[QualifiedNameTypeAndId]], + options: Optional[List[str]], + include_dirs: Optional[List[str]], + auto_type_source: str = "" ) -> Tuple[Optional[TypeParserResult], List[TypeParserError]]: return ( - TypeParserResult( - [ - ParsedType("my_type", Type.int(4, False), True) - ], [ - ParsedType("my_variable", Type.int(4, False), True) - ], [ - ParsedType("my_function", Type.function(Type.void(), []), True) - ] - ), - [ - TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1) - ] + TypeParserResult( + [ + ParsedType("my_type", Type.int(4, False), True) + ], [ + ParsedType("my_variable", Type.int(4, False), True) + ], [ + ParsedType("my_function", Type.function(Type.void(), []), True) + ] + ), + [ + TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1) + ] ) def parse_type_string( - self, source: str, platform: binaryninja.Platform, - existing_types: Optional[List[QualifiedNameTypeAndId]] + self, source: str, platform: binaryninja.Platform, + existing_types: Optional[List[QualifiedNameTypeAndId]] ) -> Tuple[Optional[Tuple[QualifiedNameType, binaryninja.Type]], - List[TypeParserError]]: + List[TypeParserError]]: return ( - ("my_type", Type.int(4, False)), - [ - TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1) - ] + ("my_type", Type.int(4, False)), + [ + TypeParserError(TypeParserErrorSeverity.WarningSeverity, "Test Warning", "sources.hpp", 1, 1) + ] ) MyTypeParser().register() @@ -927,49 +929,49 @@ class TestTypePrinter(unittest.TestCase): bv.platform = platform types = [ - (Type.int(4), 'basic_int', 'typedef int32_t basic_int;\n'), - (Type.array(Type.int(4), 4), 'basic_array', 'typedef int32_t basic_array[0x4];\n'), - (Type.pointer(platform.arch, Type.array( - Type.int(4), 4 - )), 'pointer_array', 'typedef int32_t (* pointer_array)[0x4];\n'), - (Type.array( - Type.pointer(platform.arch, Type.int(4)), 4 - ), 'array_pointer', 'typedef int32_t* array_pointer[0x4];\n'), - (Type.function( - Type.int(4), [] - ), 'basic_func', 'typedef int32_t basic_func();\n'), - (Type.function( - Type.int(4), [], platform.fastcall_calling_convention - ), 'convention_func', 'typedef int32_t __fastcall convention_func();\n'), - (Type.pointer(platform.arch, Type.function( - Type.int(4), [] - ), True), 'const_func_pointer', 'typedef int32_t (* const const_func_pointer)();\n'), - (Type.pointer(platform.arch, Type.function( - Type.int(4), [] - )), 'basic_func_pointer', 'typedef int32_t (* basic_func_pointer)();\n'), - (Type.function( - Type.pointer(platform.arch, Type.int(4)), [] - ), 'func_returning_ptr', 'typedef int32_t* func_returning_ptr();\n'), - (Type.structure([ - (Type.int(4), 'foo') - ]), 'basic_struct', 'struct basic_struct\n{\n int32_t foo;\n};\n'), - (Type.pointer(platform.arch, Type.structure([ - (Type.int(4), 'foo') - ])), 'pointer_struct', 'typedef struct { int32_t foo; }* pointer_struct;\n'), - (Type.pointer(platform.arch, Type.structure([ - (Type.pointer(platform.arch, Type.int(4)), 'foo') - ])), 'pointer_in_pointer_struct', 'typedef struct { int32_t* foo; }* pointer_in_pointer_struct;\n'), - (Type.pointer(platform.arch, Type.structure([ - (Type.pointer(platform.arch, Type.structure([ - (Type.pointer(platform.arch, Type.int(4)), 'foo') - ])), 'foo') - ])), 'nested_pointer_struct', 'typedef struct { struct { int32_t* foo; }* foo; }* nested_pointer_struct;\n'), - (Type.pointer(platform.arch, Type.structure([ - (Type.pointer(platform.arch, Type.function(Type.int(4), [('param', Type.int(4))])), 'foo') - ])), 'pointer_function_struct', 'typedef struct { int32_t (* foo)(int32_t param); }* pointer_function_struct;\n'), - (Type.pointer(platform.arch, Type.enumeration(platform.arch, [ - ('one', 1) - ])), 'pointer_enumeration', 'typedef enum {}* pointer_enumeration;\n'), + (Type.int(4), 'basic_int', 'typedef int32_t basic_int;\n'), + (Type.array(Type.int(4), 4), 'basic_array', 'typedef int32_t basic_array[0x4];\n'), + (Type.pointer(platform.arch, Type.array( + Type.int(4), 4 + )), 'pointer_array', 'typedef int32_t (* pointer_array)[0x4];\n'), + (Type.array( + Type.pointer(platform.arch, Type.int(4)), 4 + ), 'array_pointer', 'typedef int32_t* array_pointer[0x4];\n'), + (Type.function( + Type.int(4), [] + ), 'basic_func', 'typedef int32_t basic_func();\n'), + (Type.function( + Type.int(4), [], platform.fastcall_calling_convention + ), 'convention_func', 'typedef int32_t __fastcall convention_func();\n'), + (Type.pointer(platform.arch, Type.function( + Type.int(4), [] + ), True), 'const_func_pointer', 'typedef int32_t (* const const_func_pointer)();\n'), + (Type.pointer(platform.arch, Type.function( + Type.int(4), [] + )), 'basic_func_pointer', 'typedef int32_t (* basic_func_pointer)();\n'), + (Type.function( + Type.pointer(platform.arch, Type.int(4)), [] + ), 'func_returning_ptr', 'typedef int32_t* func_returning_ptr();\n'), + (Type.structure([ + (Type.int(4), 'foo') + ]), 'basic_struct', 'struct basic_struct\n{\n int32_t foo;\n};\n'), + (Type.pointer(platform.arch, Type.structure([ + (Type.int(4), 'foo') + ])), 'pointer_struct', 'typedef struct { int32_t foo; }* pointer_struct;\n'), + (Type.pointer(platform.arch, Type.structure([ + (Type.pointer(platform.arch, Type.int(4)), 'foo') + ])), 'pointer_in_pointer_struct', 'typedef struct { int32_t* foo; }* pointer_in_pointer_struct;\n'), + (Type.pointer(platform.arch, Type.structure([ + (Type.pointer(platform.arch, Type.structure([ + (Type.pointer(platform.arch, Type.int(4)), 'foo') + ])), 'foo') + ])), 'nested_pointer_struct', 'typedef struct { struct { int32_t* foo; }* foo; }* nested_pointer_struct;\n'), + (Type.pointer(platform.arch, Type.structure([ + (Type.pointer(platform.arch, Type.function(Type.int(4), [('param', Type.int(4))])), 'foo') + ])), 'pointer_function_struct', 'typedef struct { int32_t (* foo)(int32_t param); }* pointer_function_struct;\n'), + (Type.pointer(platform.arch, Type.enumeration(platform.arch, [ + ('one', 1) + ])), 'pointer_enumeration', 'typedef enum {}* pointer_enumeration;\n'), ] for t in types: @@ -988,46 +990,46 @@ class TestTypePrinter(unittest.TestCase): name = "MyTypePrinter" def get_type_tokens(self, type: types.Type, platform: Optional[Platform], name: types.QualifiedName, - base_confidence: int, escaping: TokenEscapingType) -> List[InstructionTextToken]: + base_confidence: int, escaping: TokenEscapingType) -> List[InstructionTextToken]: return [ - InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0), - InstructionTextToken(InstructionTextTokenType.TypeNameToken, str(name), 0), - InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0) + InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0), + InstructionTextToken(InstructionTextTokenType.TypeNameToken, str(name), 0), + InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0) ] def get_type_tokens_before_name(self, type: types.Type, platform: Optional[Platform], base_confidence: int, - parent_type: Optional[types.Type], escaping: TokenEscapingType) -> List[ - InstructionTextToken]: + parent_type: Optional[types.Type], escaping: TokenEscapingType) -> List[ + InstructionTextToken]: return [ - InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0), + InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0), ] def get_type_tokens_after_name(self, type: types.Type, platform: Optional[Platform], base_confidence: int, - parent_type: Optional[types.Type], escaping: TokenEscapingType) -> List[InstructionTextToken]: + parent_type: Optional[types.Type], escaping: TokenEscapingType) -> List[InstructionTextToken]: return [ - InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0), + InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0), ] def get_type_string(self, type: types.Type, platform: Optional[Platform], name: types.QualifiedName, - escaping: TokenEscapingType) -> str: + escaping: TokenEscapingType) -> str: return f"the type is: {name} bottom text" def get_type_string_before_name(self, type: types.Type, platform: Optional[Platform], - escaping: TokenEscapingType) -> str: + escaping: TokenEscapingType) -> str: return f"the type is: " def get_type_string_after_name(self, type: types.Type, platform: Optional[Platform], - escaping: TokenEscapingType) -> str: + escaping: TokenEscapingType) -> str: return f" bottom text" def get_type_lines(self, type: types.Type, data: binaryview.BinaryView, name: types.QualifiedName, line_width, - collapsed, escaping: TokenEscapingType) -> List[types.TypeDefinitionLine]: + collapsed, escaping: TokenEscapingType) -> List[types.TypeDefinitionLine]: return [ - TypeDefinitionLine(TypeDefinitionLineType.TypedefLineType, [ - InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0), - InstructionTextToken(InstructionTextTokenType.TypeNameToken, str(name), 0), - InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0) - ], type, type, '', 0, 1) + TypeDefinitionLine(TypeDefinitionLineType.TypedefLineType, [ + InstructionTextToken(InstructionTextTokenType.TextToken, "the type is: ", 0), + InstructionTextToken(InstructionTextTokenType.TypeNameToken, str(name), 0), + InstructionTextToken(InstructionTextTokenType.TextToken, " bottom text", 0) + ], type, type, '', 0, 1) ] MyTypePrinter().register() @@ -2782,7 +2784,7 @@ class TestBinaryView(TestWithBinaryView): def test_bv_comments(self): self.bv.set_comment_at(self.bv.start, "This is a comment") assert self.bv.get_comment_at(self.bv.start) == "This is a comment" - assert self.bv.address_comments == {self.bv.start :"This is a comment"} + assert self.bv.address_comments == {self.bv.start : "This is a comment"} def test_bv_sections(self): assert self.bv.get_unique_section_names(['foo', 'foo']) == ["foo", "foo#1"] @@ -3314,8 +3316,8 @@ class LowLevelILTests(TestWithBinaryView): func.finalize() self.assertEqual(func.basic_blocks[0].disassembly_text[target_expr_index].il_instruction.__class__, llil_instruction_type, - f"LowLevelILFunction.{target_function.__name__} didn't append expected " - f"{llil_instruction_type.__name__} instruction") + f"LowLevelILFunction.{target_function.__name__} didn't append expected " + f"{llil_instruction_type.__name__} instruction") return func.basic_blocks[0].disassembly_text[target_expr_index].il_instruction diff --git a/ui/settingsview.h b/ui/settingsview.h index 5a785784..5507f182 100644 --- a/ui/settingsview.h +++ b/ui/settingsview.h @@ -186,6 +186,7 @@ class BINARYNINJAUIAPI SettingsEditor : public QWidget void selectUiFont(); void selectInterpreter(); void selectVirtualEnv(); + void selectExternalDebugInfo(); public Q_SLOTS: void updateScope(BinaryViewRef, BNSettingsScope); |
