[Lldb-commits] [lldb] r245838 - Make TestCreateDuringInstructionStep linux-specific

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Mon Aug 24 06:23:48 PDT 2015


Author: labath
Date: Mon Aug 24 08:23:48 2015
New Revision: 245838

URL: http://llvm.org/viewvc/llvm-project?rev=245838&view=rev
Log:
Make TestCreateDuringInstructionStep linux-specific

Summary:
There were a number of issues about the way I have designed this test originally:
- it relied on single-stepping through large parts of code, which was slow and unreliable
- the threading libraries interfered with the exact thing we wanted to test

For this reason, I have rewritted the test using low-level linux api, which allows the test to be
much more focused. The functionality for other platforms will need to be tested separately.

Reviewers: tberghammer

Subscribers: tberghammer, danalbert, srhines, lldb-commits

Differential Revision: http://reviews.llvm.org/D12280

Added:
    lldb/trunk/test/linux/thread/
    lldb/trunk/test/linux/thread/create_during_instruction_step/
    lldb/trunk/test/linux/thread/create_during_instruction_step/Makefile
      - copied, changed from r245831, lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile
    lldb/trunk/test/linux/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py
      - copied, changed from r245831, lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py
    lldb/trunk/test/linux/thread/create_during_instruction_step/main.cpp
Removed:
    lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile
    lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py
    lldb/trunk/test/functionalities/thread/create_during_instruction_step/main.cpp

Removed: lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile?rev=245837&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile (original)
+++ lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile (removed)
@@ -1,5 +0,0 @@
-LEVEL = ../../../make
-
-CXX_SOURCES := main.cpp
-ENABLE_THREADS := YES
-include $(LEVEL)/Makefile.rules

Removed: lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py?rev=245837&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py (original)
+++ lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py (removed)
@@ -1,91 +0,0 @@
-"""
-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
-    @skipIfTargetAndroid(archs=['aarch64'])
-    @expectedFailureAndroid("llvm.org/pr23944", archs=['aarch64']) # We are unable to step through std::thread::_M_start_thread
-    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
-                    'pthread_mutex_unlock'    # 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()

Removed: lldb/trunk/test/functionalities/thread/create_during_instruction_step/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_during_instruction_step/main.cpp?rev=245837&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_during_instruction_step/main.cpp (original)
+++ lldb/trunk/test/functionalities/thread/create_during_instruction_step/main.cpp (removed)
@@ -1,36 +0,0 @@
-//===-- 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;
-}

Copied: lldb/trunk/test/linux/thread/create_during_instruction_step/Makefile (from r245831, lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/linux/thread/create_during_instruction_step/Makefile?p2=lldb/trunk/test/linux/thread/create_during_instruction_step/Makefile&p1=lldb/trunk/test/functionalities/thread/create_during_instruction_step/Makefile&r1=245831&r2=245838&rev=245838&view=diff
==============================================================================
    (empty)

Copied: lldb/trunk/test/linux/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py (from r245831, lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/linux/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py?p2=lldb/trunk/test/linux/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py&p1=lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py&r1=245831&r2=245838&rev=245838&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py (original)
+++ lldb/trunk/test/linux/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py Mon Aug 24 08:23:48 2015
@@ -16,8 +16,6 @@ class CreateDuringInstructionStepTestCas
     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):
@@ -25,8 +23,6 @@ class CreateDuringInstructionStepTestCas
         self.create_during_step_inst_test()
 
     @dwarf_test
-    @skipIfTargetAndroid(archs=['aarch64'])
-    @expectedFailureAndroid("llvm.org/pr23944", archs=['aarch64']) # We are unable to step through std::thread::_M_start_thread
     def test_step_inst_with_dwarf(self):
         self.buildDwarf(dictionary=self.getBuildFlags())
         self.create_during_step_inst_test()
@@ -37,7 +33,8 @@ class CreateDuringInstructionStepTestCas
         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)
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertTrue(breakpoint and breakpoint.IsValid(), "Breakpoint is valid")
 
         # Run the program.
         process = target.LaunchSimple(None, None, self.get_process_working_directory())
@@ -45,31 +42,19 @@ class CreateDuringInstructionStepTestCas
 
         # 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()
+        threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint)
+        self.assertEquals(len(threads), 1, STOPPED_DUE_TO_BREAKPOINT)
 
-        # 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)
+        thread = threads[0]
         self.assertTrue(thread and thread.IsValid(), "Thread is valid")
 
+        # Make sure we see only one threads
+        self.assertEqual(process.GetNumThreads(), 1, 'Number of expected threads and actual threads do not match.')
+
         # 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
-                    'pthread_mutex_unlock'    # Android arm: function contains atomic instruction sequences
-                    ]:
-                thread.StepOut()
-            else:
-                thread.StepInstruction(False)
+            thread.StepInstruction(False)
             self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
             self.assertEqual(thread.GetStopReason(), lldb.eStopReasonPlanComplete, "Step operation succeeded")
             if self.TraceOn():

Added: lldb/trunk/test/linux/thread/create_during_instruction_step/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/linux/thread/create_during_instruction_step/main.cpp?rev=245838&view=auto
==============================================================================
--- lldb/trunk/test/linux/thread/create_during_instruction_step/main.cpp (added)
+++ lldb/trunk/test/linux/thread/create_during_instruction_step/main.cpp Mon Aug 24 08:23:48 2015
@@ -0,0 +1,55 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This file deliberately uses low level linux-specific API for thread creation because:
+// - instruction-stepping over thread creation using higher-level functions was very slow
+// - it was also unreliable due to single-stepping bugs unrelated to this test
+// - some threading libraries do not create or destroy threads when we would expect them to
+
+#include <sched.h>
+
+#include <atomic>
+#include <cstdio>
+
+enum { STACK_SIZE = 0x2000 };
+
+static uint8_t child_stack[STACK_SIZE];
+
+pid_t child_tid;
+
+std::atomic<bool> flag(false);
+
+int thread_main(void *)
+{
+    while (! flag) // Make sure the thread does not exit prematurely
+        ;
+
+    return 0;
+}
+
+int main ()
+{
+    int ret = clone(thread_main,
+            child_stack + STACK_SIZE/2, // Don't care whether the stack grows up or down,
+                                        // just point to the middle
+            CLONE_CHILD_CLEARTID | CLONE_FILES | CLONE_FS | CLONE_PARENT_SETTID | CLONE_SETTLS |
+            CLONE_SIGHAND | CLONE_SYSVSEM | CLONE_THREAD | CLONE_VM,
+            nullptr, // thread_main argument
+            &child_tid);
+
+    if (ret == -1)
+    {
+        perror("clone");
+        return 1;
+    }
+
+    flag = true;
+
+    return 0;
+}




More information about the lldb-commits mailing list