[Lldb-commits] [lldb] 9f34f75 - [lldb] [Windows] Fix continuing from breakpoints and singlestepping on ARM/AArch64

Martin Storsjö via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 22 04:11:52 PDT 2021


Author: Martin Storsjö
Date: 2021-09-22T14:11:41+03:00
New Revision: 9f34f75ff8f49b0efca6e20d916527a2c432d8b4

URL: https://github.com/llvm/llvm-project/commit/9f34f75ff8f49b0efca6e20d916527a2c432d8b4
DIFF: https://github.com/llvm/llvm-project/commit/9f34f75ff8f49b0efca6e20d916527a2c432d8b4.diff

LOG: [lldb] [Windows] Fix continuing from breakpoints and singlestepping on ARM/AArch64

Based on suggestions by Eric Youngdale.

This fixes https://llvm.org/PR51673.

Differential Revision: https://reviews.llvm.org/D109777

Added: 
    

Modified: 
    lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
    lldb/source/Plugins/Platform/Windows/PlatformWindows.h
    lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
    lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
    lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp
    lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
    lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
index fdb6758c8b7a1..69fa94c12d93a 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
@@ -312,3 +312,38 @@ ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
   stream.Printf("%s.dll", basename.GetCString());
   return ConstString(stream.GetString());
 }
+
+size_t
+PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
+                                                 BreakpointSite *bp_site) {
+  ArchSpec arch = target.GetArchitecture();
+  assert(arch.IsValid());
+  const uint8_t *trap_opcode = nullptr;
+  size_t trap_opcode_size = 0;
+
+  switch (arch.GetMachine()) {
+  case llvm::Triple::aarch64: {
+    static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
+    trap_opcode = g_aarch64_opcode;
+    trap_opcode_size = sizeof(g_aarch64_opcode);
+
+    if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+      return trap_opcode_size;
+    return 0;
+  } break;
+
+  case llvm::Triple::arm:
+  case llvm::Triple::thumb: {
+    static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
+    trap_opcode = g_thumb_opcode;
+    trap_opcode_size = sizeof(g_thumb_opcode);
+
+    if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+      return trap_opcode_size;
+    return 0;
+  } break;
+
+  default:
+    return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
+  }
+}

diff  --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
index aff6924e448d5..9bff68f163197 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
@@ -61,6 +61,9 @@ class PlatformWindows : public RemoteAwarePlatform {
   void CalculateTrapHandlerSymbolNames() override {}
 
   ConstString GetFullNameForDylib(ConstString basename) override;
+
+  size_t GetSoftwareBreakpointTrapOpcode(Target &target,
+                                         BreakpointSite *bp_site) override;
 };
 
 } // namespace lldb_private

diff  --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index 69a5cb20b90b8..5ae878024be17 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -289,6 +289,30 @@ NativeProcessWindows::GetAuxvData() const {
   return llvm::errc::not_supported;
 }
 
+llvm::Expected<llvm::ArrayRef<uint8_t>>
+NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
+  static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
+  static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
+
+  switch (GetArchitecture().GetMachine()) {
+  case llvm::Triple::aarch64:
+    return llvm::makeArrayRef(g_aarch64_opcode);
+
+  case llvm::Triple::arm:
+  case llvm::Triple::thumb:
+    return llvm::makeArrayRef(g_thumb_opcode);
+
+  default:
+    return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
+  }
+}
+
+size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() {
+    // Windows always reports an incremented PC after a breakpoint is hit,
+    // even on ARM.
+    return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size();
+}
+
 bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {
   auto it = m_software_breakpoints.find(addr);
   if (it == m_software_breakpoints.end())
@@ -474,8 +498,9 @@ NativeProcessWindows::OnDebugException(bool first_chance,
       if (NativeThreadWindows *stop_thread =
               GetThreadByID(record.GetThreadID())) {
         auto &register_context = stop_thread->GetRegisterContext();
-        // The current EIP is AFTER the BP opcode, which is one byte '0xCC'
-        uint64_t pc = register_context.GetPC() - 1;
+        uint32_t breakpoint_size = GetSoftwareBreakpointPCOffset();
+        // The current PC is AFTER the BP opcode, on all architectures.
+        uint64_t pc = register_context.GetPC() - breakpoint_size;
         register_context.SetPC(pc);
       }
 

diff  --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
index 150f7083e8691..6c83733346227 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
@@ -108,6 +108,11 @@ class NativeProcessWindows : public NativeProcessProtocol,
 protected:
   NativeThreadWindows *GetThreadByID(lldb::tid_t thread_id);
 
+  llvm::Expected<llvm::ArrayRef<uint8_t>>
+  GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
+
+  size_t GetSoftwareBreakpointPCOffset() override;
+
   bool FindSoftwareBreakpoint(lldb::addr_t addr);
 
   void StopThread(lldb::tid_t thread_id, lldb::StopReason reason,

diff  --git a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp
index 16e67bb9f8632..b2b16cdeee718 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp
@@ -48,12 +48,29 @@ Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
     return Status();
 
   if (resume_state == eStateStepping) {
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+
     uint32_t flags_index =
         GetRegisterContext().ConvertRegisterKindToRegisterNumber(
             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
     uint64_t flags_value =
         GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0);
-    flags_value |= 0x100; // Set the trap flag on the CPU
+    NativeProcessProtocol &process = GetProcess();
+    const ArchSpec &arch = process.GetArchitecture();
+    switch (arch.GetMachine()) {
+    case llvm::Triple::x86:
+    case llvm::Triple::x86_64:
+      flags_value |= 0x100; // Set the trap flag on the CPU
+      break;
+    case llvm::Triple::aarch64:
+    case llvm::Triple::arm:
+    case llvm::Triple::thumb:
+      flags_value |= 0x200000; // The SS bit in PState
+      break;
+    default:
+      LLDB_LOG(log, "single stepping unsupported on this architecture");
+      break;
+    }
     GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value);
   }
 

diff  --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 2b692b2ecd4dd..74efa35f962f4 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -436,8 +436,29 @@ void ProcessWindows::RefreshStateAfterStop() {
   case EXCEPTION_BREAKPOINT: {
     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;
+    int breakpoint_size = 1;
+    switch (GetTarget().GetArchitecture().GetMachine()) {
+    case llvm::Triple::aarch64:
+      breakpoint_size = 4;
+      break;
+
+    case llvm::Triple::arm:
+    case llvm::Triple::thumb:
+      breakpoint_size = 2;
+      break;
+
+    case llvm::Triple::x86:
+    case llvm::Triple::x86_64:
+      breakpoint_size = 1;
+      break;
+
+    default:
+      LLDB_LOG(log, "Unknown breakpoint size for architecture");
+      break;
+    }
+
+    // The current PC is AFTER the BP opcode, on all architectures.
+    uint64_t pc = register_context->GetPC() - breakpoint_size;
 
     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
     if (site) {

diff  --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
index 6d608b2b6ce35..9810d21eb224f 100644
--- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
@@ -131,12 +131,29 @@ Status TargetThreadWindows::DoResume() {
     return Status();
 
   if (resume_state == eStateStepping) {
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+
     uint32_t flags_index =
         GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
     uint64_t flags_value =
         GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
-    flags_value |= 0x100; // Set the trap flag on the CPU
+    ProcessSP process = GetProcess();
+    const ArchSpec &arch = process->GetTarget().GetArchitecture();
+    switch (arch.GetMachine()) {
+    case llvm::Triple::x86:
+    case llvm::Triple::x86_64:
+      flags_value |= 0x100; // Set the trap flag on the CPU
+      break;
+    case llvm::Triple::aarch64:
+    case llvm::Triple::arm:
+    case llvm::Triple::thumb:
+      flags_value |= 0x200000; // The SS bit in PState
+      break;
+    default:
+      LLDB_LOG(log, "single stepping unsupported on this architecture");
+      break;
+    }
     GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
   }
 


        


More information about the lldb-commits mailing list