[Lldb-commits] [lldb] r253308 - Add the ability (through the SB API & command line) to specify an address

Jim Ingham via lldb-commits lldb-commits at lists.llvm.org
Mon Nov 16 19:39:13 PST 2015


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,




More information about the lldb-commits mailing list