diff --git a/tests/inferior.c b/tests/inferior.c index 90450bb6..0b66c177 100644 --- a/tests/inferior.c +++ b/tests/inferior.c @@ -2,6 +2,8 @@ #include #include +int global = 0xfeedface; + void test_function() { printf("*** test_function()\n"); diff --git a/tests/lldb_api_tests.py b/tests/lldb_api_tests.py index f08bcf35..298e5543 100644 --- a/tests/lldb_api_tests.py +++ b/tests/lldb_api_tests.py @@ -126,6 +126,21 @@ def test_command(): assert 'rax' in output process.Destroy() + def test_resolve_variable(): + process = target.LaunchSimple(None, None, os.getcwd()) + output = adaptor.resolve_variable("global") + assert output.load_addr > 0 + output = adaptor.resolve_variable("nonexistant") + assert output is None + process.Destroy() + + def test_deref_variable(): + process = target.LaunchSimple(None, None, os.getcwd()) + output = adaptor.resolve_variable("global") + value = adaptor.read_pointer(output) + assert value == 0xfeedface + process.Destroy() + def test_dereference_main(): process = target.LaunchSimple(None, None, os.getcwd()) regs = adaptor.registers() @@ -162,4 +177,4 @@ def test_capabilities(): assert adaptor.capabilities() == ['async'] except: - print("No LLDB") \ No newline at end of file + print("No LLDB") diff --git a/voltron/plugins/debugger/dbg_lldb.py b/voltron/plugins/debugger/dbg_lldb.py index c78cf3d3..af4fa216 100644 --- a/voltron/plugins/debugger/dbg_lldb.py +++ b/voltron/plugins/debugger/dbg_lldb.py @@ -265,6 +265,23 @@ def program_counter(self, target_id=0, thread_id=None): return (pc_name, pc) + @validate_busy + @validate_target + @lock_host + def resolve_variable(self, symbol, target_id=0): + """ + Resolve a symbol, returning an SBValue if found, or None if not located. + """ + target = self.host.GetTargetAtIndex(target_id) + # Send some absurd upper bound on matches + candidates = target.FindGlobalVariables(symbol, 256) + if len(candidates) == 0: + return None + elif len(candidates) != 1: + raise RuntimeError("Found more than 1 location for {}".format(symbol)) + else: + return candidates[0] + @validate_busy @validate_target @lock_host @@ -330,6 +347,29 @@ def disassemble(self, target_id=0, address=None, count=None): return output + @validate_busy + @validate_target + @lock_host + def read_pointer(self, pointer, target_id=0): + """Read process memory at *pointer* returning the value pointed to. + + if *pointer* is an SBValue it will automatically be lowered to an + address, otherwise pointer is assumed to be an *int* of pointer + width on the target platform + """ + t = self.host.GetTargetAtIndex(target_id) + error = lldb.SBError() + if isinstance(pointer, lldb.SBValue): + # For convenience, do something reasonable if you hand in an + # SBValue, as retrieved by resolve_function, but default to + # doing the right thing when handed an address + pointer = pointer.load_addr + ptr = t.process.ReadPointerFromMemory(pointer, error) + if not error.Success(): + raise Exception("Failed reading memory: {}".format(error.GetCString())) + return ptr + + @validate_busy @validate_target @lock_host