From a3c3482ceb529206b0ae4e7782e5496da5e0879d Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Fri, 20 May 2022 13:50:42 -0700 Subject: [PATCH] [lldb] Consider binary as module of last resort When setting an address breakpoint using a non-section address in lldb before having ever run the program, the binary itself is not considered a module. As a result, the breakpoint is unresolved (and never gets resolved subsequently). This patch changes that behavior: as a last resort, the binary is considered as a module when resolving a non-section address breakpoint. Differential revision: https://reviews.llvm.org/D124731 --- .../Breakpoint/BreakpointResolverAddress.cpp | 27 +++++++++----- lldb/source/Commands/Options.td | 6 ++-- .../breakpoint/set/address-nomodule/Makefile | 3 ++ .../TestBreakpointAddressNoModule.py | 36 +++++++++++++++++++ .../set/address-nomodule/inferior.c | 6 ++++ 5 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 lldb/test/API/commands/breakpoint/set/address-nomodule/Makefile create mode 100644 lldb/test/API/commands/breakpoint/set/address-nomodule/TestBreakpointAddressNoModule.py create mode 100644 lldb/test/API/commands/breakpoint/set/address-nomodule/inferior.c diff --git a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp index c173fc0c2a7a..9b6b6d29cbce 100644 --- a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp @@ -121,16 +121,27 @@ Searcher::CallbackReturn BreakpointResolverAddress::SearchCallback( if (filter.AddressPasses(m_addr)) { if (breakpoint.GetNumLocations() == 0) { - // If the address is just an offset, and we're given a module, see if we - // can find the appropriate module loaded in the binary, and fix up - // m_addr to use that. - if (!m_addr.IsSectionOffset() && m_module_filespec) { + // If the address is just an offset ... + if (!m_addr.IsSectionOffset()) { + ModuleSP containing_module_sp = nullptr; Target &target = breakpoint.GetTarget(); - ModuleSpec module_spec(m_module_filespec); - ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec); - if (module_sp) { + if (m_module_filespec) { + // ... and we're given a module, see if we can find the + // appropriate module loaded in the binary, and fix up + // m_addr to use that. + ModuleSpec module_spec(m_module_filespec); + containing_module_sp = + target.GetImages().FindFirstModule(module_spec); + } else { + // ... and we're not given a module, see if the offset is + // somewhere in the executable module. If it is, then we'll + // fix up m_addr to use that. + containing_module_sp = target.GetExecutableModule(); + } + if (containing_module_sp) { Address tmp_address; - if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address)) + if (containing_module_sp->ResolveFileAddress(m_addr.GetOffset(), + tmp_address)) m_addr = tmp_address; } } diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index c326f8a32074..284437887a0b 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -128,13 +128,15 @@ let Command = "breakpoint set" in { Arg<"AddressOrExpression">, Required, Desc<"Set the breakpoint at the specified address. If the address maps " "uniquely to a particular binary, then the address will be converted to " - "a \"file\"address, so that the breakpoint will track that binary+offset " + "a \"file\" address, so that the breakpoint will track that binary+offset " "no matter where the binary eventually loads. Alternately, if you also " "specify the module - with the -s option - then the address will be " "treated as a file address in that module, and resolved accordingly. " "Again, this will allow lldb to track that offset on subsequent reloads. " "The module need not have been loaded at the time you specify this " - "breakpoint, and will get resolved when the module is loaded.">; + "breakpoint, and will get resolved when the module is loaded. If no " + "module is specified, the binary being debugged is considered as a " + "fallback.">; def breakpoint_set_name : Option<"name", "n">, Group<3>, Arg<"FunctionName">, Completion<"Symbol">, Required, Desc<"Set the breakpoint by function name. Can be repeated multiple times " diff --git a/lldb/test/API/commands/breakpoint/set/address-nomodule/Makefile b/lldb/test/API/commands/breakpoint/set/address-nomodule/Makefile new file mode 100644 index 000000000000..7c82a2dde6c2 --- /dev/null +++ b/lldb/test/API/commands/breakpoint/set/address-nomodule/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := inferior.c + +include Makefile.rules diff --git a/lldb/test/API/commands/breakpoint/set/address-nomodule/TestBreakpointAddressNoModule.py b/lldb/test/API/commands/breakpoint/set/address-nomodule/TestBreakpointAddressNoModule.py new file mode 100644 index 000000000000..3e3550d69470 --- /dev/null +++ b/lldb/test/API/commands/breakpoint/set/address-nomodule/TestBreakpointAddressNoModule.py @@ -0,0 +1,36 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def get_address_from_symbol(self, symbol): + target = lldbutil.run_to_breakpoint_make_target(self, "a.out", True) + bp = target.BreakpointCreateByName(symbol, None) + address = bp.GetLocationAtIndex(0).GetAddress().GetFileAddress() + return address + + def test_set_address_no_module(self): + self.build() + + main_address = self.get_address_from_symbol("main") + + target = lldbutil.run_to_breakpoint_make_target(self) + debugger = target.GetDebugger() + + debugger.HandleCommand(f"break set -a {main_address:#x}") + self.assertEquals(target.GetNumBreakpoints(), 1) + + bp = target.GetBreakpointAtIndex(0) + self.assertIsNotNone(bp) + + _, _, thread, _ = lldbutil.run_to_breakpoint_do_run(self, target, bp) + self.assertGreaterEqual(thread.GetNumFrames(), 1) + + thread_pc = thread.GetFrameAtIndex(0).GetPCAddress() + self.assertNotEqual(thread_pc, None) + + self.assertEquals(main_address, thread_pc.GetFileAddress()) diff --git a/lldb/test/API/commands/breakpoint/set/address-nomodule/inferior.c b/lldb/test/API/commands/breakpoint/set/address-nomodule/inferior.c new file mode 100644 index 000000000000..b3af1438927c --- /dev/null +++ b/lldb/test/API/commands/breakpoint/set/address-nomodule/inferior.c @@ -0,0 +1,6 @@ +int function(int a) { return a; } + +int main() { + int f = function(10); + return f; +}