[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
This commit is contained in:
Will Hawkins 2022-05-20 13:50:42 -07:00 committed by Jonas Devlieghere
parent bd62b70b51
commit a3c3482ceb
No known key found for this signature in database
GPG Key ID: 49CC0BD90FDEED4D
5 changed files with 68 additions and 10 deletions

View File

@ -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();
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);
ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec);
if (module_sp) {
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;
}
}

View File

@ -134,7 +134,9 @@ let Command = "breakpoint set" in {
"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 "

View File

@ -0,0 +1,3 @@
C_SOURCES := inferior.c
include Makefile.rules

View File

@ -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())

View File

@ -0,0 +1,6 @@
int function(int a) { return a; }
int main() {
int f = function(10);
return f;
}