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; + } } } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits