[Lldb-commits] [lldb] r182428 - Added a test case that verifies that LLDB can debug across a process exec'ing itself into a new program. This currently is only enabled for Darwin since we exec from 64 bit to 32 bit and vice versa for 'x86_64' targets.

Greg Clayton gclayton at apple.com
Tue May 21 14:55:59 PDT 2013


Author: gclayton
Date: Tue May 21 16:55:59 2013
New Revision: 182428

URL: http://llvm.org/viewvc/llvm-project?rev=182428&view=rev
Log:
Added a test case that verifies that LLDB can debug across a process exec'ing itself into a new program. This currently is only enabled for Darwin since we exec from 64 bit to 32 bit and vice versa for 'x86_64' targets.

This can easily be adapted for linux and other platforms, but I didn't want to break any buildbots by assuming it will work.


Added:
    lldb/trunk/test/functionalities/exec/
    lldb/trunk/test/functionalities/exec/Makefile
    lldb/trunk/test/functionalities/exec/TestExec.py
    lldb/trunk/test/functionalities/exec/main.cpp
Modified:
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Target/Thread.cpp
    lldb/trunk/source/Utility/StringExtractor.h

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=182428&r1=182427&r2=182428&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Tue May 21 16:55:59 2013
@@ -1005,15 +1005,6 @@ ProcessGDBRemote::DidAttach ()
     DidLaunchOrAttach ();
 }
 
-void
-ProcessGDBRemote::DoDidExec ()
-{
-    // The process exec'ed itself, figure out the dynamic loader, etc...
-    BuildDynamicRegisterInfo (true);
-    m_gdb_comm.ResetDiscoverableSettings();
-}
-
-
 
 Error
 ProcessGDBRemote::WillResume ()
@@ -1354,15 +1345,8 @@ ProcessGDBRemote::SetThreadStopInfo (Str
             // register info before we lookup and threads and populate the expedited
             // register values so we need to know this right away so we can cleanup
             // and update our registers.
-            const bool did_exec = stop_packet.GetStringRef().find(";reason:exec;") != std::string::npos;
-
-            if (did_exec)
-            {
-                m_thread_list_real.Clear();
-                m_thread_list.Clear();
-            }
-
-            if (GetStopID() == 0 || did_exec)
+            const uint32_t stop_id = GetStopID();
+            if (stop_id == 0)
             {
                 // Our first stop, make sure we have a process ID, and also make
                 // sure we know about our registers
@@ -1519,6 +1503,7 @@ ProcessGDBRemote::SetThreadStopInfo (Str
                 else
                 {
                     bool handled = false;
+                    bool did_exec = false;
                     if (!reason.empty())
                     {
                         if (reason.compare("trace") == 0)
@@ -1566,6 +1551,7 @@ ProcessGDBRemote::SetThreadStopInfo (Str
                         }
                         else if (reason.compare("exec") == 0)
                         {
+                            did_exec = true;
                             thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
                             handled = true;
                         }
@@ -1898,6 +1884,26 @@ ProcessGDBRemote::DoDestroy ()
     return error;
 }
 
+void
+ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
+{
+    lldb_private::Mutex::Locker locker (m_last_stop_packet_mutex);
+    const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos;
+    if (did_exec)
+    {
+        Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+        if (log)
+            log->Printf ("ProcessGDBRemote::SetLastStopPacket () - detected exec");
+
+        m_thread_list_real.Clear();
+        m_thread_list.Clear();
+        BuildDynamicRegisterInfo (true);
+        m_gdb_comm.ResetDiscoverableSettings();
+    }
+    m_last_stop_packet = response;
+}
+
+
 //------------------------------------------------------------------
 // Process Queries
 //------------------------------------------------------------------

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=182428&r1=182427&r2=182428&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Tue May 21 16:55:59 2013
@@ -114,9 +114,6 @@ public:
     virtual void
     DidAttach ();
 
-    virtual void
-    DoDidExec ();
-
     //------------------------------------------------------------------
     // PluginInterface protocol
     //------------------------------------------------------------------
@@ -289,11 +286,7 @@ protected:
     BuildDynamicRegisterInfo (bool force);
 
     void
-    SetLastStopPacket (const StringExtractorGDBRemote &response)
-    {
-        lldb_private::Mutex::Locker locker (m_last_stop_packet_mutex);
-        m_last_stop_packet = response;
-    }
+    SetLastStopPacket (const StringExtractorGDBRemote &response);
 
     //------------------------------------------------------------------
     /// Broadcaster event bits definitions.

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=182428&r1=182427&r2=182428&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Tue May 21 16:55:59 2013
@@ -5588,8 +5588,6 @@ Process::DidExec ()
     m_allocated_memory_cache.Clear();
     m_language_runtimes.clear();
     m_thread_list.DiscardThreadPlans();
-    m_thread_list.Clear();
-    m_thread_list_real.Clear();
     m_memory_cache.Clear(true);
     DoDidExec();
     CompleteAttach ();

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=182428&r1=182427&r2=182428&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Tue May 21 16:55:59 2013
@@ -442,6 +442,9 @@ Thread::SetStopInfo (const lldb::StopInf
         m_stop_info_stop_id = process_sp->GetStopID();
     else
         m_stop_info_stop_id = UINT32_MAX;
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf("%p: tid = 0x%llx: stop info = %s (stop_id = %u)\n", this, GetID(), stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", m_stop_info_stop_id);
 }
 
 void

Modified: lldb/trunk/source/Utility/StringExtractor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractor.h?rev=182428&r1=182427&r2=182428&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractor.h (original)
+++ lldb/trunk/source/Utility/StringExtractor.h Tue May 21 16:55:59 2013
@@ -73,6 +73,12 @@ public:
         return m_packet;
     }
 
+    const std::string &
+    GetStringRef () const
+    {
+        return m_packet;
+    }
+
     bool
     Empty()
     {

Added: lldb/trunk/test/functionalities/exec/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/exec/Makefile?rev=182428&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/exec/Makefile (added)
+++ lldb/trunk/test/functionalities/exec/Makefile Tue May 21 16:55:59 2013
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/exec/TestExec.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/exec/TestExec.py?rev=182428&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/exec/TestExec.py (added)
+++ lldb/trunk/test/functionalities/exec/TestExec.py Tue May 21 16:55:59 2013
@@ -0,0 +1,121 @@
+"""
+Test some lldb command abbreviations.
+"""
+import commands
+import lldb
+import os
+import time
+import unittest2
+from lldbtest import *
+import lldbutil
+
+def execute_command (command):
+    print '%% %s' % (command)
+    (exit_status, output) = commands.getstatusoutput (command)
+    if output:
+        print output
+    print 'status = %u' % (exit_status)
+    return exit_status
+
+class ExecTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "exec")
+
+        
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_with_dsym (self):
+        if self.getArchitecture() == 'x86_64':
+            source = os.path.join (os.getcwd(), "main.cpp")
+            o_file = os.path.join (os.getcwd(), "main.o")
+            execute_command ("'%s' -g -O0 -arch i386 -arch x86_64 '%s' -c -o '%s'" % (os.environ["CC"], source, o_file))
+            execute_command ("'%s' -g -O0 -arch i386 -arch x86_64 '%s'" % (os.environ["CC"], o_file))
+        else:
+            self.buildDsym()
+        self.do_test ()
+
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dwarf_test
+    def test_with_dwarf (self):
+        if self.getArchitecture() == 'x86_64':
+            source = os.path.join (os.getcwd(), "main.cpp")
+            o_file = os.path.join (os.getcwd(), "main.o")
+            dsym_path = os.path.join (os.getcwd(), "a.out.dSYM")
+            execute_command ("'%s' -g -O0 -arch i386 -arch x86_64 '%s' -c -o '%s'" % (os.environ["CC"], source, o_file))
+            execute_command ("'%s' -g -O0 -arch i386 -arch x86_64 '%s'" % (os.environ["CC"], o_file))
+            execute_command ("rm -rf '%s'" % (dsym_path))
+        else:
+            self.buildDwarf()
+        self.do_test ()
+
+    def do_test (self):
+        exe = os.path.join (os.getcwd(), "a.out")
+        
+        # Create the target
+        target = self.dbg.CreateTarget(exe)
+        
+        print target
+        # Create any breakpoints we need
+        breakpoint = target.BreakpointCreateBySourceRegex ('Set breakpoint 1 here', lldb.SBFileSpec ("main.cpp", False))
+        print breakpoint
+        self.assertTrue(breakpoint, VALID_BREAKPOINT)
+
+        # Launch the process
+        process = target.LaunchSimple(None, None, os.getcwd())
+        self.assertTrue(process, PROCESS_IS_VALID)
+        
+        for i in range(6):
+            # The stop reason of the thread should be breakpoint.
+            self.assertTrue(process.GetState() == lldb.eStateStopped,
+                            STOPPED_DUE_TO_BREAKPOINT)
+
+            thread = process.GetThreadAtIndex (0)
+
+            self.assertTrue (thread.IsValid(),
+                             "Process stopped at 'main' should have a valid thread");
+
+            stop_reason = thread.GetStopReason()
+            
+            print 'stop_reason = %u' % (stop_reason)
+
+            print thread
+            for frame in thread:
+                print frame
+
+            self.assertTrue (stop_reason == lldb.eStopReasonBreakpoint,
+                             "Thread in process stopped in 'main' should have a stop reason of eStopReasonBreakpoint");
+
+            # Run and we should stop due to exec
+            process.Continue()
+        
+            print process
+            self.assertTrue(process.GetState() == lldb.eStateStopped,
+                            "Process should be stopped at __dyld_start")
+                        
+            thread = process.GetThreadAtIndex (0)
+        
+            self.assertTrue (thread.IsValid(),
+                             "Process stopped at exec should have a valid thread");
+        
+            print thread
+            for frame in thread:
+                print frame
+
+            stop_reason = thread.GetStopReason()
+        
+            print 'stop_reason = %u' % (stop_reason)
+
+            self.assertTrue (stop_reason == lldb.eStopReasonExec,
+                             "Thread in process stopped on exec should have a stop reason of eStopReasonExec");
+        
+             # Run and we should stop at breakpoint in main after exec
+            process.Continue()
+        
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
+

Added: lldb/trunk/test/functionalities/exec/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/exec/main.cpp?rev=182428&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/exec/main.cpp (added)
+++ lldb/trunk/test/functionalities/exec/main.cpp Tue May 21 16:55:59 2013
@@ -0,0 +1,94 @@
+#include <errno.h>
+#include <mach/mach.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <spawn.h>
+#include <unistd.h>
+
+static void
+exit_with_errno (int err, const char *prefix)
+{
+    if (err)
+    {
+        fprintf (stderr,
+                 "%s%s",
+                 prefix ? prefix : "",
+                 strerror(err));
+        exit (err);
+    }
+}
+
+static pid_t
+spawn_process (const char **argv,
+               const char **envp,
+               cpu_type_t cpu_type,
+               int &err)
+{
+    pid_t pid = 0;
+
+    const posix_spawn_file_actions_t *file_actions = NULL;
+    posix_spawnattr_t attr;
+    err = posix_spawnattr_init (&attr);
+    if (err)
+        return pid;
+
+    short flags = POSIX_SPAWN_SETEXEC | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+    err = posix_spawnattr_setflags (&attr, flags);
+    if (err == 0)
+    {
+        // Use the default signal masks
+        sigset_t no_signals;
+        sigset_t all_signals;
+        sigemptyset (&no_signals);
+        sigfillset (&all_signals);
+        posix_spawnattr_setsigmask(&attr, &no_signals);
+        posix_spawnattr_setsigdefault(&attr, &all_signals);
+
+        if (cpu_type != 0)
+        {
+            size_t ocount = 0;
+            err = posix_spawnattr_setbinpref_np (&attr, 1, &cpu_type, &ocount);
+        }
+
+        if (err == 0)
+        {
+            err = posix_spawn (&pid,
+                               argv[0],
+                               file_actions,
+                               &attr,
+                               (char * const *)argv,
+                               (char * const *)envp);
+        }
+        
+        posix_spawnattr_destroy(&attr);
+    }
+    return pid;
+}
+
+int 
+main (int argc, char const **argv)
+{
+    printf ("pid %i: Pointer size is %zu.\n", getpid(), sizeof(void *));
+    int err = 0;    // Set breakpoint 1 here
+#if defined (__x86_64__)
+    if (sizeof(void *) == 8)
+    {
+        spawn_process (argv, NULL, CPU_TYPE_I386, err);
+        if (err)
+            exit_with_errno (err, "posix_spawn i386 error");
+    }
+    else
+    {
+        spawn_process (argv, NULL, CPU_TYPE_X86_64, err);
+        if (err)
+            exit_with_errno (err, "posix_spawn x86_64 error");
+    }
+#else
+    spawn_process (argv, NULL, 0, err);
+    if (err)
+        exit_with_errno (err, "posix_spawn x86_64 error");
+#endif
+    return 0;
+}





More information about the lldb-commits mailing list