Author: jingham Date: Mon Nov 16 21:39:13 2015 New Revision: 253308 URL: http://llvm.org/viewvc/llvm-project?rev=253308&view=rev Log: Add the ability (through the SB API & command line) to specify an address breakpoint as "file address" so that the address breakpoint will track that module even if it gets loaded in a different place. Also fixed the Address breakpoint resolver so that it handles this tracking correctly.
Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/Makefile lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestAddressBreakpoints.py lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/main.c Modified: lldb/trunk/include/lldb/API/SBTarget.h lldb/trunk/include/lldb/Breakpoint/BreakpointResolverAddress.h lldb/trunk/include/lldb/Target/Target.h lldb/trunk/scripts/interface/SBTarget.i lldb/trunk/source/API/SBTarget.cpp lldb/trunk/source/Breakpoint/BreakpointResolverAddress.cpp lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp lldb/trunk/source/Target/Target.cpp Modified: lldb/trunk/include/lldb/API/SBTarget.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBTarget.h?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/include/lldb/API/SBTarget.h (original) +++ lldb/trunk/include/lldb/API/SBTarget.h Mon Nov 16 21:39:13 2015 @@ -689,6 +689,9 @@ public: lldb::SBBreakpoint BreakpointCreateByAddress (addr_t address); + lldb::SBBreakpoint + BreakpointCreateBySBAddress (SBAddress &address); + uint32_t GetNumBreakpoints () const; Modified: lldb/trunk/include/lldb/Breakpoint/BreakpointResolverAddress.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Breakpoint/BreakpointResolverAddress.h?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/include/lldb/Breakpoint/BreakpointResolverAddress.h (original) +++ lldb/trunk/include/lldb/Breakpoint/BreakpointResolverAddress.h Mon Nov 16 21:39:13 2015 @@ -15,6 +15,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/BreakpointResolver.h" +#include "lldb/Core/ModuleSpec.h" namespace lldb_private { @@ -31,6 +32,10 @@ public: BreakpointResolverAddress (Breakpoint *bkpt, const Address &addr); + BreakpointResolverAddress (Breakpoint *bkpt, + const Address &addr, + const FileSpec &module_spec); + ~BreakpointResolverAddress() override; void @@ -65,8 +70,11 @@ public: CopyForBreakpoint (Breakpoint &breakpoint) override; protected: - Address m_addr; - + Address m_addr; // The address - may be Section Offset or may be just an offset + lldb::addr_t m_resolved_addr; // The current value of the resolved load address for this breakpoint, + FileSpec m_module_filespec; // If this filespec is Valid, and m_addr is an offset, then it will be converted + // to a Section+Offset address in this module, whenever that module gets around to + // being loaded. private: DISALLOW_COPY_AND_ASSIGN(BreakpointResolverAddress); }; Modified: lldb/trunk/include/lldb/Target/Target.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/Target.h (original) +++ lldb/trunk/include/lldb/Target/Target.h Mon Nov 16 21:39:13 2015 @@ -778,9 +778,16 @@ public: bool internal, bool request_hardware); + // Use this to create a breakpoint from a load address and a module file spec + lldb::BreakpointSP + CreateAddressInModuleBreakpoint (lldb::addr_t file_addr, + bool internal, + const FileSpec *file_spec, + bool request_hardware); + // Use this to create Address breakpoints: lldb::BreakpointSP - CreateBreakpoint (Address &addr, + CreateBreakpoint (const Address &addr, bool internal, bool request_hardware); Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/Makefile URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/Makefile?rev=253308&view=auto ============================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/Makefile (added) +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/Makefile Mon Nov 16 21:39:13 2015 @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +C_SOURCES := main.c +CFLAGS_EXTRAS += -std=c99 + +include $(LEVEL)/Makefile.rules Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestAddressBreakpoints.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestAddressBreakpoints.py?rev=253308&view=auto ============================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestAddressBreakpoints.py (added) +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestAddressBreakpoints.py Mon Nov 16 21:39:13 2015 @@ -0,0 +1,91 @@ +""" +Test address breakpoints set with shared library of SBAddress work correctly. +""" + +from __future__ import print_function + + + +import os, time +import re +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + +class AddressBreakpointTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test_address_breakpoints (self): + """Test address breakpoints set with shared library of SBAddress work correctly.""" + self.build() + self.address_breakpoints() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + def address_breakpoints(self): + """Test address breakpoints set with shared library of SBAddress work correctly.""" + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # Now create a breakpoint on main.c by name 'c'. + breakpoint = target.BreakpointCreateBySourceRegex("Set a breakpoint here", lldb.SBFileSpec("main.c")) + self.assertTrue(breakpoint and + breakpoint.GetNumLocations() == 1, + VALID_BREAKPOINT) + + # Get the breakpoint location from breakpoint after we verified that, + # indeed, it has one location. + location = breakpoint.GetLocationAtIndex(0) + self.assertTrue(location and + location.IsEnabled(), + VALID_BREAKPOINT_LOCATION) + + # Next get the address from the location, and create an address breakpoint using + # that address: + + address = location.GetAddress() + target.BreakpointDelete(breakpoint.GetID()) + + breakpoint = target.BreakpointCreateBySBAddress(address) + + # Disable ASLR. This will allow us to actually test (on platforms that support this flag) + # that the breakpoint was able to track the module. + + launch_info = lldb.SBLaunchInfo(None) + flags = launch_info.GetLaunchFlags() + flags &= ~lldb.eLaunchFlagDisableASLR + launch_info.SetLaunchFlags(flags) + + error = lldb.SBError() + + process = target.Launch (launch_info, error) + self.assertTrue(process, PROCESS_IS_VALID) + + # Did we hit our breakpoint? + from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint + threads = get_threads_stopped_at_breakpoint (process, breakpoint) + self.assertTrue(len(threads) == 1, "There should be a thread stopped at our breakpoint") + + # The hit count for the breakpoint should be 1. + self.assertTrue(breakpoint.GetHitCount() == 1) + + process.Kill() + + # Now re-launch and see that we hit the breakpoint again: + launch_info.Clear() + launch_info.SetLaunchFlags(flags) + + process = target.Launch(launch_info, error) + self.assertTrue (process, PROCESS_IS_VALID) + + thread = get_threads_stopped_at_breakpoint (process, breakpoint) + self.assertTrue(len(threads) == 1, "There should be a thread stopped at our breakpoint") + + # The hit count for the breakpoint should now be 2. + self.assertTrue(breakpoint.GetHitCount() == 2) Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/main.c URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/main.c?rev=253308&view=auto ============================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/main.c (added) +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/main.c Mon Nov 16 21:39:13 2015 @@ -0,0 +1,8 @@ +#include <stdio.h> + +int +main() +{ + printf ("Set a breakpoint here.\n"); + return 0; +} Modified: lldb/trunk/scripts/interface/SBTarget.i URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBTarget.i?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/scripts/interface/SBTarget.i (original) +++ lldb/trunk/scripts/interface/SBTarget.i Mon Nov 16 21:39:13 2015 @@ -639,6 +639,9 @@ public: lldb::SBBreakpoint BreakpointCreateByAddress (addr_t address); + lldb::SBBreakpoint + BreakpointCreateBySBAddress (SBAddress &sb_address); + uint32_t GetNumBreakpoints () const; Modified: lldb/trunk/source/API/SBTarget.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBTarget.cpp?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/source/API/SBTarget.cpp (original) +++ lldb/trunk/source/API/SBTarget.cpp Mon Nov 16 21:39:13 2015 @@ -1053,6 +1053,41 @@ SBTarget::BreakpointCreateByAddress (add return sb_bp; } +SBBreakpoint +SBTarget::BreakpointCreateBySBAddress (SBAddress &sb_address) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + SBBreakpoint sb_bp; + TargetSP target_sp(GetSP()); + if (!sb_address.IsValid()) + { + if (log) + log->Printf ("SBTarget(%p)::BreakpointCreateBySBAddress called with invalid address", + static_cast<void*>(target_sp.get())); + return sb_bp; + } + + if (target_sp) + { + Mutex::Locker api_locker (target_sp->GetAPIMutex()); + const bool hardware = false; + *sb_bp = target_sp->CreateBreakpoint (sb_address.ref(), false, hardware); + } + + if (log) + { + SBStream s; + sb_address.GetDescription(s); + log->Printf ("SBTarget(%p)::BreakpointCreateBySBAddress (address=%s) => SBBreakpoint(%p)", + static_cast<void*>(target_sp.get()), + s.GetData(), + static_cast<void*>(sb_bp.get())); + } + + return sb_bp; +} + lldb::SBBreakpoint SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, const lldb::SBFileSpec &source_file, Modified: lldb/trunk/source/Breakpoint/BreakpointResolverAddress.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/BreakpointResolverAddress.cpp?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/source/Breakpoint/BreakpointResolverAddress.cpp (original) +++ lldb/trunk/source/Breakpoint/BreakpointResolverAddress.cpp Mon Nov 16 21:39:13 2015 @@ -16,6 +16,7 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -29,10 +30,25 @@ using namespace lldb_private; BreakpointResolverAddress::BreakpointResolverAddress ( Breakpoint *bkpt, + const Address &addr, + const FileSpec &module_spec +) : + BreakpointResolver (bkpt, BreakpointResolver::AddressResolver), + m_addr (addr), + m_resolved_addr(LLDB_INVALID_ADDRESS), + m_module_filespec(module_spec) +{ +} + +BreakpointResolverAddress::BreakpointResolverAddress +( + Breakpoint *bkpt, const Address &addr ) : BreakpointResolver (bkpt, BreakpointResolver::AddressResolver), - m_addr (addr) + m_addr (addr), + m_resolved_addr(LLDB_INVALID_ADDRESS), + m_module_filespec() { } @@ -44,10 +60,16 @@ BreakpointResolverAddress::~BreakpointRe void BreakpointResolverAddress::ResolveBreakpoint (SearchFilter &filter) { - // The address breakpoint only takes once, so if we've already set it we're done. - if (m_breakpoint->GetNumLocations() > 0) - return; - else + // If the address is not section relative, then we should not try to re-resolve it, it is just some + // random address and we wouldn't know what to do on reload. But if it is section relative, we need to + // re-resolve it since the section it's in may have shifted on re-run. + bool re_resolve = false; + if (m_addr.GetSection() || m_module_filespec) + re_resolve = true; + else if (m_breakpoint->GetNumLocations() == 0) + re_resolve = true; + + if (re_resolve) BreakpointResolver::ResolveBreakpoint(filter); } @@ -58,10 +80,14 @@ BreakpointResolverAddress::ResolveBreakp ModuleList &modules ) { - // The address breakpoint only takes once, so if we've already set it we're done. - if (m_breakpoint->GetNumLocations() > 0) - return; - else + // See comment in ResolveBreakpoint. + bool re_resolve = false; + if (m_addr.GetSection()) + re_resolve = true; + else if (m_breakpoint->GetNumLocations() == 0) + re_resolve = true; + + if (re_resolve) BreakpointResolver::ResolveBreakpointInModules (filter, modules); } @@ -78,14 +104,44 @@ BreakpointResolverAddress::SearchCallbac if (filter.AddressPasses (m_addr)) { - BreakpointLocationSP bp_loc_sp(m_breakpoint->AddLocation(m_addr)); - if (bp_loc_sp && !m_breakpoint->IsInternal()) + if (m_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) + { + Target &target = m_breakpoint->GetTarget(); + ModuleSpec module_spec(m_module_filespec); + ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec); + if (module_sp) + { + Address tmp_address; + if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address)) + m_addr = tmp_address; + } + } + + BreakpointLocationSP bp_loc_sp(m_breakpoint->AddLocation(m_addr)); + m_resolved_addr = m_addr.GetLoadAddress(&m_breakpoint->GetTarget()); + if (bp_loc_sp && !m_breakpoint->IsInternal()) + { + StreamString s; + bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("Added location: %s\n", s.GetData()); + } + } + else { - StreamString s; - bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("Added location: %s\n", s.GetData()); + BreakpointLocationSP loc_sp = m_breakpoint->GetLocationAtIndex(0); + lldb::addr_t cur_load_location = m_addr.GetLoadAddress(&m_breakpoint->GetTarget()); + if (cur_load_location != m_resolved_addr) + { + m_resolved_addr = cur_load_location; + loc_sp->ClearBreakpointSite(); + loc_sp->ResolveBreakpointSite(); + } } } return Searcher::eCallbackReturnStop; @@ -101,7 +157,7 @@ void BreakpointResolverAddress::GetDescription (Stream *s) { s->PutCString ("address = "); - m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(), Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); + m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(), Address::DumpStyleModuleWithFileAddress, Address::DumpStyleLoadAddress); } void Modified: lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp Mon Nov 16 21:39:13 2015 @@ -507,11 +507,32 @@ protected: break; case eSetTypeAddress: // Breakpoint by address - bp = target->CreateBreakpoint (m_options.m_load_addr, - internal, - m_options.m_hardware).get(); + { + // If a shared library has been specified, make an lldb_private::Address with the library, and + // use that. That way the address breakpoint will track the load location of the library. + size_t num_modules_specified = m_options.m_modules.GetSize(); + if (num_modules_specified == 1) + { + const FileSpec *file_spec = m_options.m_modules.GetFileSpecPointerAtIndex(0); + bp = target->CreateAddressInModuleBreakpoint (m_options.m_load_addr, + internal, + file_spec, + m_options.m_hardware).get(); + } + else if (num_modules_specified == 0) + { + bp = target->CreateBreakpoint (m_options.m_load_addr, + internal, + m_options.m_hardware).get(); + } + else + { + result.AppendError("Only one shared library can be specified for address breakpoints."); + result.SetStatus(eReturnStatusFailed); + return false; + } break; - + } case eSetTypeFunctionName: // Breakpoint by function name { uint32_t name_type_mask = m_options.m_func_name_type_mask; @@ -766,7 +787,14 @@ CommandObjectBreakpointSet::CommandOptio // "Set the breakpoint by source location at this particular column."}, { LLDB_OPT_SET_2, true, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression, - "Set the breakpoint by address, at the specified address."}, + "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 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."}, { LLDB_OPT_SET_3, true, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, "Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names" }, Modified: lldb/trunk/source/Target/Target.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=253308&r1=253307&r2=253308&view=diff ============================================================================== --- lldb/trunk/source/Target/Target.cpp (original) +++ lldb/trunk/source/Target/Target.cpp Mon Nov 16 21:39:13 2015 @@ -417,13 +417,24 @@ Target::CreateBreakpoint (lldb::addr_t a } BreakpointSP -Target::CreateBreakpoint (Address &addr, bool internal, bool hardware) +Target::CreateBreakpoint (const Address &addr, bool internal, bool hardware) { SearchFilterSP filter_sp(new SearchFilterForUnconstrainedSearches (shared_from_this())); BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr)); return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, false); } +lldb::BreakpointSP +Target::CreateAddressInModuleBreakpoint (lldb::addr_t file_addr, + bool internal, + const FileSpec *file_spec, + bool request_hardware) +{ + SearchFilterSP filter_sp(new SearchFilterForUnconstrainedSearches (shared_from_this())); + BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, file_addr, file_spec)); + return CreateBreakpoint (filter_sp, resolver_sp, internal, request_hardware, false); +} + BreakpointSP Target::CreateBreakpoint (const FileSpecList *containingModules, const FileSpecList *containingSourceFiles, _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits