[Lldb-commits] [lldb] r183340 - Add test cases for attaching to a process after fork
Daniel Malea
daniel.malea at intel.com
Wed Jun 5 14:07:03 PDT 2013
Author: dmalea
Date: Wed Jun 5 16:07:02 2013
New Revision: 183340
URL: http://llvm.org/viewvc/llvm-project?rev=183340&view=rev
Log:
Add test cases for attaching to a process after fork
- one test case is due to llvm.org/pr16229
- other test case uses a Linux workaround for above by using os.fork() instead of subprocess module
Patch by Andy Kaylor!
Added:
lldb/trunk/test/functionalities/thread/create_after_attach/
lldb/trunk/test/functionalities/thread/create_after_attach/Makefile
lldb/trunk/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py
lldb/trunk/test/functionalities/thread/create_after_attach/main.c
Modified:
lldb/trunk/test/lldbtest.py
Added: lldb/trunk/test/functionalities/thread/create_after_attach/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_after_attach/Makefile?rev=183340&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_after_attach/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/create_after_attach/Makefile Wed Jun 5 16:07:02 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+include $(LEVEL)/Makefile.rules
Added: lldb/trunk/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py?rev=183340&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py (added)
+++ lldb/trunk/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py Wed Jun 5 16:07:02 2013
@@ -0,0 +1,124 @@
+"""
+Test thread creation after process attach.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class CreateAfterAttachTestCase(TestBase):
+
+ mydir = os.path.join("functionalities", "thread", "create_after_attach")
+
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ @dsym_test
+ def test_create_after_attach_with_dsym(self):
+ """Test thread creation after process attach."""
+ self.buildDsym(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.create_after_attach(use_fork=False)
+
+ @skipIfLinux # Hangs, see llvm.org/pr16229
+ @dwarf_test
+ def test_create_after_attach_with_dwarf_and_popen(self):
+ """Test thread creation after process attach."""
+ self.buildDwarf(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.create_after_attach(use_fork=False)
+
+ @dwarf_test
+ def test_create_after_attach_with_dwarf_and_fork(self):
+ """Test thread creation after process attach."""
+ self.buildDwarf(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.create_after_attach(use_fork=True)
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line numbers for our breakpoints.
+ self.break_1 = line_number('main.c', '// Set first breakpoint here')
+ self.break_2 = line_number('main.c', '// Set second breakpoint here')
+ self.break_3 = line_number('main.c', '// Set third breakpoint here')
+
+ def create_after_attach(self, use_fork):
+ """Test thread creation after process attach."""
+
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ # Spawn a new process
+ if use_fork:
+ pid = self.forkSubprocess(exe)
+ else:
+ popen = self.spawnSubprocess(exe)
+ pid = popen.pid
+ self.addTearDownHook(self.cleanupSubprocesses)
+
+ # Attach to the spawned process
+ self.runCmd("process attach -p " + str(pid))
+
+ target = self.dbg.GetSelectedTarget()
+
+ process = target.GetProcess()
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ # This should create a breakpoint in the main thread.
+ lldbutil.run_break_set_by_file_and_line (self, "main.c", self.break_1, num_expected_locations=1)
+
+ # This should create a breakpoint in the second child thread.
+ lldbutil.run_break_set_by_file_and_line (self, "main.c", self.break_2, num_expected_locations=1)
+
+ # This should create a breakpoint in the first child thread.
+ lldbutil.run_break_set_by_file_and_line (self, "main.c", self.break_3, num_expected_locations=1)
+
+ # Run to the first breakpoint
+ self.runCmd("continue")
+
+ # The stop reason of the thread should be breakpoint.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ '* thread #1',
+ 'stop reason = breakpoint',
+ 'thread #2'])
+
+ # Change a variable to escape the loop
+ self.runCmd("expression main_thread_continue = 1")
+
+ # Run to the second breakpoint
+ self.runCmd("continue")
+ self.runCmd("thread select 3")
+
+ # The stop reason of the thread should be breakpoint.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ 'thread #1',
+ 'thread #2',
+ '* thread #3',
+ 'stop reason = breakpoint'])
+
+ # Change a variable to escape the loop
+ self.runCmd("expression child_thread_continue = 1")
+
+ # Run to the third breakpoint
+ self.runCmd("continue")
+ self.runCmd("thread select 2")
+
+ # The stop reason of the thread should be breakpoint.
+ # Thread 3 may or may not have already exited.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ 'thread #1',
+ '* thread #2',
+ 'stop reason = breakpoint'])
+
+ # Run to completion
+ self.runCmd("continue")
+
+ # At this point, the inferior process should have exited.
+ self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
+
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
Added: lldb/trunk/test/functionalities/thread/create_after_attach/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_after_attach/main.c?rev=183340&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_after_attach/main.c (added)
+++ lldb/trunk/test/functionalities/thread/create_after_attach/main.c Wed Jun 5 16:07:02 2013
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+
+volatile int g_thread_2_continuing = 0;
+
+void *
+thread_1_func (void *input)
+{
+ // Waiting to be released by the debugger.
+ while (!g_thread_2_continuing) // The debugger will change this value
+ {
+ usleep(1);
+ }
+
+ // Return
+ return NULL; // Set third breakpoint here
+}
+
+void *
+thread_2_func (void *input)
+{
+ // Waiting to be released by the debugger.
+ int child_thread_continue = 0;
+ while (!child_thread_continue) // The debugger will change this value
+ {
+ usleep(1); // Set second breakpoint here
+ }
+
+ // Release thread 1
+ g_thread_2_continuing = 1;
+
+ // Return
+ return NULL;
+}
+
+int main(int argc, char const *argv[])
+{
+ pthread_t thread_1;
+ pthread_t thread_2;
+
+ // Create a new thread
+ pthread_create (&thread_1, NULL, thread_1_func, NULL);
+
+ // Waiting to be attached by the debugger.
+ int main_thread_continue = 0;
+ while (!main_thread_continue) // The debugger will change this value
+ {
+ usleep(1); // Set first breakpoint here
+ }
+
+ // Create another new thread
+ pthread_create (&thread_2, NULL, thread_2_func, NULL);
+
+ // Wait for the threads to finish.
+ pthread_join(thread_1, NULL);
+ pthread_join(thread_2, NULL);
+
+ printf("Exiting now\n");
+}
Modified: lldb/trunk/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=183340&r1=183339&r2=183340&view=diff
==============================================================================
--- lldb/trunk/test/lldbtest.py (original)
+++ lldb/trunk/test/lldbtest.py Wed Jun 5 16:07:02 2013
@@ -34,6 +34,7 @@ $
import os, sys, traceback
import os.path
import re
+import signal
from subprocess import *
import StringIO
import time
@@ -820,6 +821,9 @@ class Base(unittest2.TestCase):
# List of spawned subproces.Popen objects
self.subprocesses = []
+ # List of forked process PIDs
+ self.forkedProcessPids = []
+
# Create a string buffer to record the session info, to be dumped into a
# test case specific file if test failure is encountered.
self.session = StringIO.StringIO()
@@ -886,6 +890,10 @@ class Base(unittest2.TestCase):
p.terminate()
del p
del self.subprocesses[:]
+ # Ensure any forked processes are cleaned up
+ for pid in self.forkedProcessPids:
+ if os.path.exists("/proc/" + str(pid)):
+ os.kill(pid, signal.SIGTERM)
def spawnSubprocess(self, executable, args=[]):
""" Creates a subprocess.Popen object with the specified executable and arguments,
@@ -904,6 +912,29 @@ class Base(unittest2.TestCase):
self.subprocesses.append(proc)
return proc
+ def forkSubprocess(self, executable, args=[]):
+ """ Fork a subprocess with its own group ID.
+ NOTE: if using this function, ensure you also call:
+
+ self.addTearDownHook(self.cleanupSubprocesses)
+
+ otherwise the test suite will leak processes.
+ """
+ child_pid = os.fork()
+ if child_pid == 0:
+ # If more I/O support is required, this can be beefed up.
+ fd = os.open(os.devnull, os.O_RDWR)
+ os.dup2(fd, 0)
+ os.dup2(fd, 1)
+ os.dup2(fd, 2)
+ # This call causes the child to have its of group ID
+ os.setpgid(0,0)
+ os.execvp(executable, [executable] + args)
+ # Give the child time to get through the execvp() call
+ time.sleep(0.1)
+ self.forkedProcessPids.append(child_pid)
+ return child_pid
+
def HideStdout(self):
"""Hide output to stdout from the user.
More information about the lldb-commits
mailing list