[Lldb-commits] [lldb] r257186 - Treat an embedded int3/__debugbreak() as a breakpoint on Windows, includes a cross-platform test.

Adrian McCarthy via lldb-commits lldb-commits at lists.llvm.org
Fri Jan 8 10:28:04 PST 2016


Author: amccarth
Date: Fri Jan  8 12:28:03 2016
New Revision: 257186

URL: http://llvm.org/viewvc/llvm-project?rev=257186&view=rev
Log:
Treat an embedded int3/__debugbreak() as a breakpoint on Windows, includes a cross-platform test.

Added:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c
Modified:
    lldb/trunk/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile?rev=257186&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile Fri Jan  8 12:28:03 2016
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py?rev=257186&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py Fri Jan  8 12:28:03 2016
@@ -0,0 +1,51 @@
+"""
+Test embedded breakpoints, like `asm int 3;` in x86 or or `__debugbreak` on Windows.
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class DebugBreakTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipIf(archs=not_in(["i386", "i686"]))
+    @no_debug_info_test
+    def test_asm_int_3(self):
+        """Test that intrinsics like `__debugbreak();` and `asm {"int3"}` are treated like breakpoints."""
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+
+        # Run the program.
+        target = self.dbg.CreateTarget(exe)
+        process = target.LaunchSimple(None, None, self.get_process_working_directory())
+
+        # We've hit the first stop, so grab the frame.
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+        thread = process.GetThreadAtIndex(0)
+        frame = thread.GetFrameAtIndex(0)
+
+        # We should be in funciton 'bar'.
+        self.assertTrue(frame.IsValid())
+        function_name = frame.GetFunctionName()
+        self.assertTrue('bar' in function_name)
+
+        # We should be able to evaluate the parameter foo.
+        value = frame.EvaluateExpression('*foo')
+        self.assertEqual(value.GetValueAsSigned(), 42)
+
+        # The counter should be 1 at the first stop and increase by 2 for each
+        # subsequent stop.
+        counter = 1
+        while counter < 20:
+          value = frame.EvaluateExpression('count')
+          self.assertEqual(value.GetValueAsSigned(), counter)
+          counter += 2
+          process.Continue()
+
+        # The inferior should exit after the last iteration.
+        self.assertEqual(process.GetState(), lldb.eStateExited)

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c?rev=257186&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c Fri Jan  8 12:28:03 2016
@@ -0,0 +1,29 @@
+#ifdef _MSC_VER
+#include <intrin.h>
+#define BREAKPOINT_INTRINSIC()    __debugbreak()
+#else
+#define BREAKPOINT_INTRINSIC()    __asm__ __volatile__ ("int3")
+#endif
+
+int
+bar(int const *foo)
+{
+    int count = 0;
+    for (int i = 0; i < 10; ++i)
+    {
+        count += 1;
+        BREAKPOINT_INTRINSIC();
+        count += 1;
+    }
+    return *foo;
+}
+
+int
+main(int argc, char **argv)
+{
+    int foo = 42;
+    bar(&foo);
+    return 0;
+}
+
+

Modified: lldb/trunk/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp?rev=257186&r1=257185&r2=257186&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp Fri Jan  8 12:28:03 2016
@@ -550,56 +550,74 @@ ProcessWindowsLive::RefreshStateAfterSto
     if (!stop_thread)
         return;
 
-    RegisterContextSP register_context = stop_thread->GetRegisterContext();
-
-    // The current EIP is AFTER the BP opcode, which is one byte.
-    uint64_t pc = register_context->GetPC() - 1;
-    if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT)
+    switch (active_exception->GetExceptionCode())
     {
-        BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
+        case EXCEPTION_SINGLE_STEP:
+        {
+            stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
+            stop_thread->SetStopInfo(stop_info);
+            WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u",
+                         stop_thread->GetID());
+            stop_thread->SetStopInfo(stop_info);
+            return;
+        }
 
-        if (site)
+        case EXCEPTION_BREAKPOINT:
         {
-            WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
-                         "RefreshStateAfterStop detected breakpoint in process %I64u at "
-                         "address 0x%I64x with breakpoint site %d",
-                         m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID());
+            RegisterContextSP register_context = stop_thread->GetRegisterContext();
 
-            if (site->ValidForThisThread(stop_thread.get()))
-            {
-                WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
-                             "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.",
-                             site->GetID(), stop_thread->GetID());
+            // The current EIP is AFTER the BP opcode, which is one byte.
+            uint64_t pc = register_context->GetPC() - 1;
 
-                stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
-                    *stop_thread, site->GetID());
-                register_context->SetPC(pc);
+            BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
+            if (site)
+            {
+                WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
+                             "RefreshStateAfterStop detected breakpoint in process %I64u at "
+                             "address 0x%I64x with breakpoint site %d",
+                             m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID());
+
+                if (site->ValidForThisThread(stop_thread.get()))
+                {
+                    WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
+                                 "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.",
+                                 site->GetID(), stop_thread->GetID());
+
+                    stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
+                        *stop_thread, site->GetID());
+                    register_context->SetPC(pc);
+                }
+                else
+                {
+                    WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
+                                 "Breakpoint site %d is not valid for this thread, creating empty stop info.",
+                                 site->GetID());
+                }
+                stop_thread->SetStopInfo(stop_info);
+                return;
             }
             else
             {
+                // The thread hit a hard-coded breakpoint like an `int 3` or `__debugbreak()`.
                 WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
-                             "Breakpoint site %d is not valid for this thread, creating empty stop info.",
-                             site->GetID());
+                                "No breakpoint site matches for this thread. __debugbreak()?  "
+                                "Creating stop info with the exception.");
+                // FALLTHROUGH:  We'll treat this as a generic exception record in the default case.
             }
         }
-        stop_thread->SetStopInfo(stop_info);
-    }
-    else if (active_exception->GetExceptionCode() == EXCEPTION_SINGLE_STEP)
-    {
-        stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
-        stop_thread->SetStopInfo(stop_info);
-        WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u",
-                     stop_thread->GetID());
-    }
-    else
-    {
-        std::string desc;
-        llvm::raw_string_ostream desc_stream(desc);
-        desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8)
-                    << " encountered at address " << llvm::format_hex(pc, 8);
-        stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str());
-        stop_thread->SetStopInfo(stop_info);
-        WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str());
+
+        default:
+        {
+            std::string desc;
+            llvm::raw_string_ostream desc_stream(desc);
+            desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8)
+                        << " encountered at address "
+                        << llvm::format_hex(active_exception->GetExceptionAddress(), 8);
+            stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str());
+            stop_thread->SetStopInfo(stop_info);
+            WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str());
+            return;
+        }
     }
 }
 




More information about the lldb-commits mailing list