summaryrefslogtreecommitdiffstats
path: root/lldb/test/functionalities
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2015-08-20 09:06:12 +0000
committerPavel Labath <labath@google.com>2015-08-20 09:06:12 +0000
commit0e1d729b7541cb90c7e5d6107e96347abd120c39 (patch)
tree834b2ee3104745d04828a2c653b6ab1264a5d3f9 /lldb/test/functionalities
parentcfc1df553e22f44b8b14a43da02f700297e7c52d (diff)
downloadbcm5719-llvm-0e1d729b7541cb90c7e5d6107e96347abd120c39.tar.gz
bcm5719-llvm-0e1d729b7541cb90c7e5d6107e96347abd120c39.zip
[NativeProcessLinux] Fix a bug in instruction-stepping over thread creation
Summary: There was a bug in NativeProcessLinux, where doing an instruction-level single-step over the thread-creation syscall resulted in loss of control over the inferior. This happened because after the inferior entered the thread-creation maintenance stop, we unconditionally performed a PTRACE_CONT, even though the original intention was to do a PTRACE_SINGLESTEP. This is fixed by storing the original state of the thread before the stop (stepping or running) and then performing the appropriate action when resuming. I also get rid of the callback in the ThreadContext structure, which stored the lambda used to resume the thread, but which was not used consistently. A test verifying the correctness of the new behavior is included. Reviewers: ovyalov, tberghammer Subscribers: lldb-commits Differential Revision: http://reviews.llvm.org/D12104 llvm-svn: 245545
Diffstat (limited to 'lldb/test/functionalities')
-rw-r--r--lldb/test/functionalities/thread/create_during_instruction_step/Makefile5
-rw-r--r--lldb/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py88
-rw-r--r--lldb/test/functionalities/thread/create_during_instruction_step/main.cpp36
3 files changed, 129 insertions, 0 deletions
diff --git a/lldb/test/functionalities/thread/create_during_instruction_step/Makefile b/lldb/test/functionalities/thread/create_during_instruction_step/Makefile
new file mode 100644
index 00000000000..67aa16625bf
--- /dev/null
+++ b/lldb/test/functionalities/thread/create_during_instruction_step/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py b/lldb/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py
new file mode 100644
index 00000000000..116cd334ff0
--- /dev/null
+++ b/lldb/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py
@@ -0,0 +1,88 @@
+"""
+This tests that we do not lose control of the inferior, while doing an instruction-level step
+over a thread creation instruction.
+"""
+
+import os
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class CreateDuringInstructionStepTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line numbers to break and continue.
+ self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
+
+ @dsym_test
+ def test_step_inst_with_dsym(self):
+ self.buildDsym(dictionary=self.getBuildFlags())
+ self.create_during_step_inst_test()
+
+ @dwarf_test
+ def test_step_inst_with_dwarf(self):
+ self.buildDwarf(dictionary=self.getBuildFlags())
+ self.create_during_step_inst_test()
+
+ def create_during_step_inst_test(self):
+ exe = os.path.join(os.getcwd(), "a.out")
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target and target.IsValid(), "Target is valid")
+
+ # This should create a breakpoint in the stepping thread.
+ self.bp_num = lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=-1)
+
+ # Run the program.
+ process = target.LaunchSimple(None, None, self.get_process_working_directory())
+ self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
+
+ # The stop reason of the thread should be breakpoint.
+ self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+ self.assertEqual(lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint).IsValid(), 1,
+ STOPPED_DUE_TO_BREAKPOINT)
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ # Make sure we see only one threads
+ self.assertEqual(num_threads, 1, 'Number of expected threads and actual threads do not match.')
+
+ thread = process.GetThreadAtIndex(0)
+ self.assertTrue(thread and thread.IsValid(), "Thread is valid")
+
+ # Keep stepping until we see the thread creation
+ while process.GetNumThreads() < 2:
+ # This skips some functions we have trouble stepping into. Testing stepping
+ # through these is not the purpose of this test. We just want to find the
+ # instruction, which creates the thread.
+ if thread.GetFrameAtIndex(0).GetFunctionName() in [
+ '__sync_fetch_and_add_4', # Android arm: unable to set a breakpoint for software single-step
+ 'pthread_mutex_lock' # Android arm: function contains atomic instruction sequences
+ ]:
+ thread.StepOut()
+ else:
+ thread.StepInstruction(False)
+ self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+ self.assertEqual(thread.GetStopReason(), lldb.eStopReasonPlanComplete, "Step operation succeeded")
+ if self.TraceOn():
+ self.runCmd("disassemble --pc")
+
+ if self.TraceOn():
+ self.runCmd("thread list")
+
+ # We have successfully caught thread creation. Now just run to completion
+ process.Continue()
+
+ # At this point, the inferior process should have exited.
+ self.assertEqual(process.GetState(), lldb.eStateExited, PROCESS_EXITED)
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/lldb/test/functionalities/thread/create_during_instruction_step/main.cpp b/lldb/test/functionalities/thread/create_during_instruction_step/main.cpp
new file mode 100644
index 00000000000..c50ce479079
--- /dev/null
+++ b/lldb/test/functionalities/thread/create_during_instruction_step/main.cpp
@@ -0,0 +1,36 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <atomic>
+#include <thread>
+
+std::atomic<bool> flag(false);
+
+void do_nothing()
+{
+ while (flag)
+ ;
+}
+
+int main ()
+{
+ // Instruction-level stepping over a creation of the first thread takes a very long time, so
+ // we give the threading machinery a chance to initialize all its data structures.
+ // This way, stepping over the second thread will be much faster.
+ std::thread dummy(do_nothing);
+ dummy.join();
+
+ // Make sure the new thread does not exit before we get a chance to notice the main thread stopped
+ flag = true;
+
+ std::thread thread(do_nothing); // Set breakpoint here
+ flag = false; // Release the new thread.
+ thread.join();
+ return 0;
+}
OpenPOWER on IntegriCloud