https://github.com/DuncanMcBain updated 
https://github.com/llvm/llvm-project/pull/174348

>From 8c9c66e54f727df87bdafe2d8a6b4e2965d67d1c Mon Sep 17 00:00:00 2001
From: Duncan McBain <[email protected]>
Date: Wed, 3 Dec 2025 17:02:11 +0000
Subject: [PATCH] [lldb] Step over non-lldb breakpoints

Several languages support some sort of "breakpoint" function, which
adds ISA-specific instructions to generate an interrupt at runtime.
However, on some platforms, these instructions don't increment the
program counter. When LLDB sets these instructions it isn't a problem,
as we remove them before continuing, then re-add them after stepping
over the location. However, for breakpoint sequences that are part of
the inferior process, this doesn't happen - and so users might be left
unable to continue past the breakpoint without manually interfering
with the program counter.

This patch adds logic to LLDB to intercept SIGTRAPs, inspect the bytes
of the inferior at the program counter, and if the instruction looks
like a BRK or BKPT or similar, increment the pc by the size of the
instruction we found. This unifies platform behaviour (e.g. on x86_64,
LLDB debug sessions already look like this) and improves UX (in my
opinion, but I think it beats messing with stuff every break).

Some ISAs (like AArch64) require slightly different handling, as while
there are multiple possible instructions, we should be careful only to
find the ones likely to have been emitted by a compiler backend, and
not those inserted from (for example) the UB sanitizer, or any others.

There is an existing builtin-debugtrap test which was under the macos
folder before. I've now moved that to "functionalities", made it pure
C only, and updated it a little bit so that it works regardless of
platform.
---
 lldb/include/lldb/Core/Architecture.h         |  12 ++
 lldb/include/lldb/Target/Platform.h           |  11 ++
 .../AArch64/ArchitectureAArch64.cpp           |  17 +++
 .../AArch64/ArchitectureAArch64.h             |   4 +
 .../Architecture/Arm/ArchitectureArm.cpp      |  30 +++++
 .../Architecture/Arm/ArchitectureArm.h        |   4 +
 .../Architecture/Mips/ArchitectureMips.cpp    |  11 ++
 .../Architecture/Mips/ArchitectureMips.h      |   4 +
 lldb/source/Target/Platform.cpp               | 126 +++++++++---------
 lldb/source/Target/StopInfo.cpp               |  34 +++++
 .../builtin-debugtrap/Makefile                |   2 +-
 .../builtin-debugtrap/TestBuiltinDebugTrap.py |  23 ++--
 .../builtin-debugtrap/main.c}                 |   3 +-
 13 files changed, 206 insertions(+), 75 deletions(-)
 rename lldb/test/API/{macosx => functionalities}/builtin-debugtrap/Makefile 
(50%)
 rename lldb/test/API/{macosx => 
functionalities}/builtin-debugtrap/TestBuiltinDebugTrap.py (74%)
 rename lldb/test/API/{macosx/builtin-debugtrap/main.cpp => 
functionalities/builtin-debugtrap/main.c} (93%)

diff --git a/lldb/include/lldb/Core/Architecture.h 
b/lldb/include/lldb/Core/Architecture.h
index ed64a895717a1..aaff8deb3582a 100644
--- a/lldb/include/lldb/Core/Architecture.h
+++ b/lldb/include/lldb/Core/Architecture.h
@@ -138,6 +138,18 @@ class Architecture : public PluginInterface {
       std::shared_ptr<const UnwindPlan> current_unwindplan) {
     return lldb::UnwindPlanSP();
   }
+
+  /// Returns whether a given byte sequence is a valid breakpoint for the
+  /// architecture. Some architectures have breakpoint instructions that
+  /// have immediates that can take on any value, resulting in a family
+  /// of valid byte sequences. Bases the size comparison on the reference.
+  virtual bool
+  IsValidBreakpointInstruction(llvm::ArrayRef<uint8_t> reference,
+                               llvm::ArrayRef<uint8_t> observed) const {
+    if (reference.size() > observed.size())
+      return false;
+    return !std::memcmp(reference.data(), observed.data(), reference.size());
+  }
 };
 
 } // namespace lldb_private
diff --git a/lldb/include/lldb/Target/Platform.h 
b/lldb/include/lldb/Target/Platform.h
index 1104722f52c70..8b911a8f2eab1 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -330,6 +330,17 @@ class Platform : public PluginInterface {
   virtual std::vector<ArchSpec>
   GetSupportedArchitectures(const ArchSpec &process_host_arch) = 0;
 
+  /// Get the bytes of the platform's software interrupt instruction.
+  ///
+  /// \param[in] arch
+  ///     The architecture of the inferior
+  /// \param size_hint
+  ///     A hint to disambiguate which instruction is used on platforms where
+  ///     there are multiple interrupts with different sizes in the ISA (e.g
+  ///     ARM Thumb, RISC-V)
+  llvm::ArrayRef<uint8_t> SoftwareTrapOpcodeTable(const ArchSpec &arch,
+                                                  size_t size_hint = 0);
+
   virtual size_t GetSoftwareBreakpointTrapOpcode(Target &target,
                                                  BreakpointSite *bp_site);
 
diff --git a/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp 
b/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp
index 6a072354972ac..9dca0d9e3a265 100644
--- a/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp
+++ b/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp
@@ -13,6 +13,8 @@
 #include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/DataExtractor.h"
 
+#include "llvm/Support/Endian.h"
+
 using namespace lldb_private;
 using namespace lldb;
 
@@ -141,3 +143,18 @@ bool 
ArchitectureAArch64::ReconfigureRegisterInfo(DynamicRegisterInfo &reg_info,
 
   return true;
 }
+
+bool ArchitectureAArch64::IsValidBreakpointInstruction(
+    llvm::ArrayRef<uint8_t> reference, llvm::ArrayRef<uint8_t> observed) const 
{
+  if (reference.size() < 4 || observed.size() < 4)
+    return false;
+  auto ref_bytes = llvm::support::endian::read32le(reference.data());
+  auto bytes = llvm::support::endian::read32le(observed.data());
+  // Only the 11 highest bits define the breakpoint, the others include an
+  // immediate which is stored to a CPU register.
+  uint32_t mask = 0xFFE00000;
+  // Check that the masked bytes match the reference, but also check that the
+  // immediate in the instruction is the default output by llvm.debugtrap
+  // The reference has the immediate set as all-zero, so mask and check here
+  return (ref_bytes == (bytes & mask)) && ((bytes & ~mask) >> 5 == 0xF000);
+}
diff --git a/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h 
b/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h
index ba409428c951e..502a55ba23a91 100644
--- a/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h
+++ b/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h
@@ -39,6 +39,10 @@ class ArchitectureAArch64 : public Architecture {
                                DataExtractor &reg_data,
                                RegisterContext &reg_context) const override;
 
+  bool
+  IsValidBreakpointInstruction(llvm::ArrayRef<uint8_t> reference,
+                               llvm::ArrayRef<uint8_t> observed) const 
override;
+
 private:
   static std::unique_ptr<Architecture> Create(const ArchSpec &arch);
   ArchitectureAArch64() = default;
diff --git a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp 
b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp
index 721c4bcfe6342..138d28b50988b 100644
--- a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp
+++ b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp
@@ -22,6 +22,8 @@
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/RegisterValue.h"
 
+#include "llvm/Support/Endian.h"
+
 using namespace lldb_private;
 using namespace lldb;
 
@@ -336,3 +338,31 @@ UnwindPlanSP ArchitectureArm::GetArchitectureUnwindPlan(
   }
   return new_plan;
 }
+
+bool ArchitectureArm::IsValidBreakpointInstruction(
+    llvm::ArrayRef<uint8_t> reference, llvm::ArrayRef<uint8_t> observed) const 
{
+  auto is_bkpt = false;
+  if (observed.size() < reference.size())
+    return false;
+  if (reference.size() == 2) {
+    auto ref_bytes = llvm::support::endian::read16le(reference.data());
+    auto obs_bytes = llvm::support::endian::read16le(observed.data());
+    is_bkpt = ref_bytes == obs_bytes;
+    // LLDB uses an undef instruction encoding for breakpoints
+    // perhaps we have an actual BKPT in the inferior
+    if (!is_bkpt) {
+      uint16_t mask = 0xF0;
+      is_bkpt = (obs_bytes & mask) == 0xBE00;
+    }
+  } else if (reference.size() == 4) {
+    auto ref_bytes = llvm::support::endian::read32le(reference.data());
+    auto obs_bytes = llvm::support::endian::read32le(observed.data());
+    is_bkpt = ref_bytes == obs_bytes;
+    if (!is_bkpt) {
+      uint32_t mask = 0x0FF000F0;
+      uint32_t bkpt_pattern = 0xE1200070;
+      is_bkpt = (obs_bytes & mask) == bkpt_pattern;
+    }
+  }
+  return is_bkpt;
+}
diff --git a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h 
b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h
index 52277dc5dbae0..071f756c96a0a 100644
--- a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h
+++ b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h
@@ -34,6 +34,10 @@ class ArchitectureArm : public Architecture {
       lldb_private::Thread &thread, lldb_private::RegisterContextUnwind 
*regctx,
       std::shared_ptr<const UnwindPlan> current_unwindplan) override;
 
+  bool
+  IsValidBreakpointInstruction(llvm::ArrayRef<uint8_t> reference,
+                               llvm::ArrayRef<uint8_t> observed) const 
override;
+
 private:
   static std::unique_ptr<Architecture> Create(const ArchSpec &arch);
   ArchitectureArm() = default;
diff --git a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp 
b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
index 3748be0533ad7..8d921149bb1b3 100644
--- a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
+++ b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
@@ -19,6 +19,8 @@
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 
+#include "llvm/Support/Endian.h"
+
 using namespace lldb_private;
 using namespace lldb;
 
@@ -229,3 +231,12 @@ Instruction *ArchitectureMips::GetInstructionAtAddress(
 
   return nullptr;
 }
+
+bool ArchitectureMips::IsValidBreakpointInstruction(
+    llvm::ArrayRef<uint8_t> reference, llvm::ArrayRef<uint8_t> observed) const 
{
+  // The middle twenty bits of BREAK can be anything, so zero them
+  uint32_t mask = 0xFC00003F;
+  auto ref_bytes = llvm::support::endian::read32le(reference.data());
+  auto bytes = llvm::support::endian::read32le(observed.data());
+  return (ref_bytes & mask) == (bytes & mask);
+}
diff --git a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h 
b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h
index cedd4127afcb6..8d48eef61019f 100644
--- a/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h
+++ b/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h
@@ -33,6 +33,10 @@ class ArchitectureMips : public Architecture {
   lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr,
                                     AddressClass addr_class) const override;
 
+  bool
+  IsValidBreakpointInstruction(llvm::ArrayRef<uint8_t> reference,
+                               llvm::ArrayRef<uint8_t> observed) const 
override;
+
 private:
   Instruction *GetInstructionAtAddress(Target &target,
                                        const Address &resolved_addr,
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 67a5857c12aa0..92a222ea01947 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -39,6 +39,7 @@
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StructuredData.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
@@ -1946,121 +1947,99 @@ size_t 
Platform::ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
   return 0;
 }
 
-size_t Platform::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;
+llvm::ArrayRef<uint8_t> Platform::SoftwareTrapOpcodeTable(const ArchSpec &arch,
+                                                          size_t size_hint) {
+  llvm::ArrayRef<uint8_t> trap_opcode;
 
   switch (arch.GetMachine()) {
   case llvm::Triple::aarch64_32:
   case llvm::Triple::aarch64: {
     static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4};
-    trap_opcode = g_aarch64_opcode;
-    trap_opcode_size = sizeof(g_aarch64_opcode);
+    trap_opcode =
+        llvm::ArrayRef<uint8_t>(g_aarch64_opcode, sizeof(g_aarch64_opcode));
   } break;
 
   case llvm::Triple::arc: {
-    static const uint8_t g_hex_opcode[] = { 0xff, 0x7f };
-    trap_opcode = g_hex_opcode;
-    trap_opcode_size = sizeof(g_hex_opcode);
+    static const uint8_t g_hex_opcode[] = {0xff, 0x7f};
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_hex_opcode, sizeof(g_hex_opcode));
   } break;
 
-  // TODO: support big-endian arm and thumb trap codes.
   case llvm::Triple::arm: {
-    // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the
-    // linux kernel does otherwise.
+    // ARM CPUs have dedicated BKPT instructions: 0xe7fddefe and 0xdefe.
+    // However, the linux kernel recognizes two different sequences based on
+    // undefined instruction encodings (linux/arch/arm/kernel/ptrace.c)
     static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7};
     static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde};
 
-    lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(0));
-    AddressClass addr_class = AddressClass::eUnknown;
-
-    if (bp_loc_sp) {
-      addr_class = bp_loc_sp->GetAddress().GetAddressClass();
-      if (addr_class == AddressClass::eUnknown &&
-          (bp_loc_sp->GetAddress().GetFileAddress() & 1))
-        addr_class = AddressClass::eCodeAlternateISA;
-    }
-
-    if (addr_class == AddressClass::eCodeAlternateISA) {
-      trap_opcode = g_thumb_breakpoint_opcode;
-      trap_opcode_size = sizeof(g_thumb_breakpoint_opcode);
+    if (size_hint == 2) {
+      trap_opcode = llvm::ArrayRef<uint8_t>(g_thumb_breakpoint_opcode,
+                                            sizeof(g_thumb_breakpoint_opcode));
     } else {
-      trap_opcode = g_arm_breakpoint_opcode;
-      trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+      trap_opcode = llvm::ArrayRef<uint8_t>(g_arm_breakpoint_opcode,
+                                            sizeof(g_arm_breakpoint_opcode));
     }
   } break;
 
   case llvm::Triple::avr: {
     static const uint8_t g_hex_opcode[] = {0x98, 0x95};
-    trap_opcode = g_hex_opcode;
-    trap_opcode_size = sizeof(g_hex_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_hex_opcode, sizeof(g_hex_opcode));
   } break;
 
   case llvm::Triple::mips:
   case llvm::Triple::mips64: {
     static const uint8_t g_hex_opcode[] = {0x00, 0x00, 0x00, 0x0d};
-    trap_opcode = g_hex_opcode;
-    trap_opcode_size = sizeof(g_hex_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_hex_opcode, sizeof(g_hex_opcode));
   } break;
 
   case llvm::Triple::mipsel:
   case llvm::Triple::mips64el: {
     static const uint8_t g_hex_opcode[] = {0x0d, 0x00, 0x00, 0x00};
-    trap_opcode = g_hex_opcode;
-    trap_opcode_size = sizeof(g_hex_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_hex_opcode, sizeof(g_hex_opcode));
   } break;
 
   case llvm::Triple::msp430: {
     static const uint8_t g_msp430_opcode[] = {0x43, 0x43};
-    trap_opcode = g_msp430_opcode;
-    trap_opcode_size = sizeof(g_msp430_opcode);
+    trap_opcode =
+        llvm::ArrayRef<uint8_t>(g_msp430_opcode, sizeof(g_msp430_opcode));
   } break;
 
   case llvm::Triple::systemz: {
     static const uint8_t g_hex_opcode[] = {0x00, 0x01};
-    trap_opcode = g_hex_opcode;
-    trap_opcode_size = sizeof(g_hex_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_hex_opcode, sizeof(g_hex_opcode));
   } break;
 
   case llvm::Triple::hexagon: {
     static const uint8_t g_hex_opcode[] = {0x0c, 0xdb, 0x00, 0x54};
-    trap_opcode = g_hex_opcode;
-    trap_opcode_size = sizeof(g_hex_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_hex_opcode, sizeof(g_hex_opcode));
   } break;
 
   case llvm::Triple::ppc:
   case llvm::Triple::ppc64: {
     static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08};
-    trap_opcode = g_ppc_opcode;
-    trap_opcode_size = sizeof(g_ppc_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_ppc_opcode, sizeof(g_ppc_opcode));
   } break;
 
   case llvm::Triple::ppc64le: {
     static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap
-    trap_opcode = g_ppc64le_opcode;
-    trap_opcode_size = sizeof(g_ppc64le_opcode);
+    trap_opcode =
+        llvm::ArrayRef<uint8_t>(g_ppc64le_opcode, sizeof(g_ppc64le_opcode));
   } break;
 
   case llvm::Triple::x86:
   case llvm::Triple::x86_64: {
     static const uint8_t g_i386_opcode[] = {0xCC};
-    trap_opcode = g_i386_opcode;
-    trap_opcode_size = sizeof(g_i386_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_i386_opcode, 
sizeof(g_i386_opcode));
   } break;
 
   case llvm::Triple::riscv32:
   case llvm::Triple::riscv64: {
     static const uint8_t g_riscv_opcode[] = {0x73, 0x00, 0x10, 0x00}; // ebreak
     static const uint8_t g_riscv_opcode_c[] = {0x02, 0x90}; // c.ebreak
-    if (arch.GetFlags() & ArchSpec::eRISCV_rvc) {
+    if (size_hint == 2) {
       trap_opcode = g_riscv_opcode_c;
-      trap_opcode_size = sizeof(g_riscv_opcode_c);
     } else {
-      trap_opcode = g_riscv_opcode;
-      trap_opcode_size = sizeof(g_riscv_opcode);
+      trap_opcode =
+          llvm::ArrayRef<uint8_t>(g_riscv_opcode, sizeof(g_riscv_opcode));
     }
   } break;
 
@@ -2068,24 +2047,47 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target 
&target,
   case llvm::Triple::loongarch64: {
     static const uint8_t g_loongarch_opcode[] = {0x05, 0x00, 0x2a,
                                                  0x00}; // break 0x5
-    trap_opcode = g_loongarch_opcode;
-    trap_opcode_size = sizeof(g_loongarch_opcode);
+    trap_opcode =
+        llvm::ArrayRef<uint8_t>(g_loongarch_opcode, 
sizeof(g_loongarch_opcode));
   } break;
 
-  case llvm::Triple::wasm32: {
-    // Unreachable (0x00) triggers an unconditional trap.
+  // Unreachable (0x00) triggers an unconditional trap.
+  case llvm::Triple::wasm32:
+  // In the case of an unkown platform, return 0x00 too
+  default: {
     static const uint8_t g_wasm_opcode[] = {0x00};
-    trap_opcode = g_wasm_opcode;
-    trap_opcode_size = sizeof(g_wasm_opcode);
+    trap_opcode = llvm::ArrayRef<uint8_t>(g_wasm_opcode, 
sizeof(g_wasm_opcode));
   } break;
+  }
+  return trap_opcode;
+}
 
-  default:
-    return 0;
+size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
+                                                 BreakpointSite *bp_site) {
+  ArchSpec arch = target.GetArchitecture();
+  assert(arch.IsValid());
+  AddressClass addr_class = AddressClass::eUnknown;
+  if (bp_site) {
+    // TODO: support big-endian arm and thumb trap codes.
+    lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(0));
+    if (bp_loc_sp) {
+      addr_class = bp_loc_sp->GetAddress().GetAddressClass();
+      if (addr_class == AddressClass::eUnknown &&
+          (bp_loc_sp->GetAddress().GetFileAddress() & 1))
+        addr_class = AddressClass::eCodeAlternateISA;
+    }
   }
 
-  assert(bp_site);
-  if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
-    return trap_opcode_size;
+  size_t size_hint = 0;
+  // Check for either ARM or RISC-V short instruction conditions
+  if ((addr_class == AddressClass::eCodeAlternateISA) ||
+      (arch.GetFlags() & ArchSpec::eRISCV_rvc))
+    size_hint = 2;
+  auto trap_opcode = SoftwareTrapOpcodeTable(arch, size_hint);
+
+  if (bp_site &&
+      bp_site->SetTrapOpcode(trap_opcode.begin(), trap_opcode.size()))
+    return trap_opcode.size();
 
   return 0;
 }
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index e9e534a57973e..97d5276634a79 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -1159,6 +1159,40 @@ class StopInfoUnixSignal : public StopInfo {
     return false;
   }
 
+  void PerformAction(Event *event_ptr) override {
+    // A signal of SIGTRAP indicates that a break instruction has been hit
+    if (m_value == SIGTRAP) {
+      Log *log = GetLog(LLDBLog::Process);
+      Status error;
+      std::array<uint8_t, 4> bytes_at_pc = {0, 0, 0, 0};
+      auto reg_ctx_sp = GetThread()->GetRegisterContext();
+      auto process_sp = GetThread()->GetProcess();
+      addr_t pc = reg_ctx_sp->GetPC();
+      if (!process_sp->ReadMemory(pc, bytes_at_pc.data(), bytes_at_pc.size(),
+                                  error)) {
+        // If this fails, we simply don't handle the step-over-break logic and
+        // log the failure
+        LLDB_LOG(log, "failed to read program bytes at pc address {}, error 
{}",
+                 pc, error);
+        return;
+      }
+      auto &target = process_sp->GetTarget();
+      auto platform_sp = target.GetPlatform();
+      auto platform_opcode =
+          platform_sp->SoftwareTrapOpcodeTable(target.GetArchitecture());
+
+      if (auto *arch_plugin = target.GetArchitecturePlugin();
+          arch_plugin &&
+          arch_plugin->IsValidBreakpointInstruction(
+              platform_opcode, llvm::ArrayRef<uint8_t>(bytes_at_pc.data(),
+                                                       bytes_at_pc.size()))) {
+        LLDB_LOG(log, "stepping over breakpoint in debuggee to new pc: {}",
+                 pc + platform_opcode.size());
+        reg_ctx_sp->SetPC(pc + platform_opcode.size());
+      }
+    }
+  }
+
   bool ShouldStop(Event *event_ptr) override { return IsShouldStopSignal(); }
 
   // If should stop returns false, check if we should notify of this event
diff --git a/lldb/test/API/macosx/builtin-debugtrap/Makefile 
b/lldb/test/API/functionalities/builtin-debugtrap/Makefile
similarity index 50%
rename from lldb/test/API/macosx/builtin-debugtrap/Makefile
rename to lldb/test/API/functionalities/builtin-debugtrap/Makefile
index 99998b20bcb05..10495940055b6 100644
--- a/lldb/test/API/macosx/builtin-debugtrap/Makefile
+++ b/lldb/test/API/functionalities/builtin-debugtrap/Makefile
@@ -1,3 +1,3 @@
-CXX_SOURCES := main.cpp
+C_SOURCES := main.c
 
 include Makefile.rules
diff --git a/lldb/test/API/macosx/builtin-debugtrap/TestBuiltinDebugTrap.py 
b/lldb/test/API/functionalities/builtin-debugtrap/TestBuiltinDebugTrap.py
similarity index 74%
rename from lldb/test/API/macosx/builtin-debugtrap/TestBuiltinDebugTrap.py
rename to 
lldb/test/API/functionalities/builtin-debugtrap/TestBuiltinDebugTrap.py
index e66892b7ee87a..9e5a40036de07 100644
--- a/lldb/test/API/macosx/builtin-debugtrap/TestBuiltinDebugTrap.py
+++ b/lldb/test/API/functionalities/builtin-debugtrap/TestBuiltinDebugTrap.py
@@ -11,16 +11,15 @@
 class BuiltinDebugTrapTestCase(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
 
-    # Currently this depends on behavior in debugserver to
-    # advance the pc past __builtin_trap instructions so that
-    # continue works.  Everyone is in agreement that this
-    # should be moved up into lldb instead of depending on the
-    # remote stub rewriting the pc values.
-    @skipUnlessDarwin
     def test(self):
+        platform_stop_reason = lldb.eStopReasonSignal
+        platform = self.getPlatform()
+        if platform == "darwin" or platform == "windows":
+            platform_stop_reason = lldb.eStopReasonException
+
         self.build()
         (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
-            self, "// Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+            self, "// Set a breakpoint here", lldb.SBFileSpec("main.c")
         )
 
         # Continue to __builtin_debugtrap()
@@ -31,7 +30,7 @@ def test(self):
             self.runCmd("ta v global")
 
         self.assertEqual(
-            process.GetSelectedThread().GetStopReason(), 
lldb.eStopReasonException
+            process.GetSelectedThread().GetStopReason(), platform_stop_reason
         )
 
         list = target.FindGlobalVariables("global", 1, lldb.eMatchTypeNormal)
@@ -49,7 +48,7 @@ def test(self):
             self.runCmd("ta v global")
 
         self.assertEqual(
-            process.GetSelectedThread().GetStopReason(), 
lldb.eStopReasonException
+            process.GetSelectedThread().GetStopReason(), platform_stop_reason
         )
 
         # "global" is now 10.
@@ -63,8 +62,12 @@ def test(self):
             self.runCmd("bt")
             self.runCmd("ta v global")
 
+        # Some platforms might exit when seeing the trap instruction
+        if process.GetState() == lldb.eStateExited:
+            return
+
         self.assertEqual(
-            process.GetSelectedThread().GetStopReason(), 
lldb.eStopReasonException
+            process.GetSelectedThread().GetStopReason(), platform_stop_reason
         )
 
         # "global" is still 10.
diff --git a/lldb/test/API/macosx/builtin-debugtrap/main.cpp 
b/lldb/test/API/functionalities/builtin-debugtrap/main.c
similarity index 93%
rename from lldb/test/API/macosx/builtin-debugtrap/main.cpp
rename to lldb/test/API/functionalities/builtin-debugtrap/main.c
index 84332d800148f..8010be4a0235e 100644
--- a/lldb/test/API/macosx/builtin-debugtrap/main.cpp
+++ b/lldb/test/API/functionalities/builtin-debugtrap/main.c
@@ -1,7 +1,6 @@
 #include <stdio.h>
 int global = 0;
-int main()
-{
+int main() {
   global = 5; // Set a breakpoint here
   puts("");
   __builtin_debugtrap();

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to