[Lldb-commits] [lldb] [lldb] Add native process support for OpenBSD (PR #236288)
Brad Smith via lldb-commits
lldb-commits at lists.llvm.org
Sat Oct 31 15:07:09 PDT 2026
https://github.com/brad0 updated https://github.com/llvm/llvm-project/pull/236288
>From f537896533e37fbd867adb2549613a07473d7dff Mon Sep 17 00:00:00 2001
From: Claude <noreply at anthropic.com>
Date: Tue, 27 Oct 2026 20:49:00 -0400
Subject: [PATCH] [lldb] Add native process support for OpenBSD
Add a NativeProcessOpenBSD plugin so that lldb-server can launch,
attach to and debug processes on OpenBSD, and allow process debugging
in PlatformOpenBSD.
This is the architecture-independent core of the plugin. Following
fork() and memory region information follow in a separate change, as
do the register contexts for x86_64, i386 and aarch64; until those
land, launching or attaching reports that the architecture is not
supported.
The plugin provides:
- Launch, attach and detach. Attaching to a process that is not a
child of the debugger requires root or kern.global_ptrace=1.
- Software breakpoints, instruction stepping and step-out.
- Memory reads and writes via PT_IO, and auxv via PIOD_READ_AUXV.
- Multi-threaded processes. OpenBSD does not report thread creation
or exit, so the thread list is refreshed on every stop. The thread
that stopped is taken from PT_GET_PROCESS_STATE, and register
accesses and single-steps are addressed by thread ID.
- The shared library list, provided by deriving from
NativeProcessELF (qXfer:libraries-svr4), which locates r_debug
through DT_DEBUG.
Limitations, due to what OpenBSD's ptrace(2) provides:
- There is no siginfo, so crash stops report only the signal.
- There are no exec, vfork or thread events.
- Individual threads cannot be suspended. lldb can resume either all
threads, or only the thread that reported the last stop.
- There are no hardware breakpoints or watchpoints.
Co-authored-by: Claude Opus 5.5 <noreply at anthropic.com>
---
.../Platform/OpenBSD/PlatformOpenBSD.cpp | 10 +-
lldb/source/Plugins/Process/CMakeLists.txt | 1 +
.../Plugins/Process/OpenBSD/CMakeLists.txt | 16 +
.../Process/OpenBSD/NativeProcessOpenBSD.cpp | 723 ++++++++++++++++++
.../Process/OpenBSD/NativeProcessOpenBSD.h | 116 +++
.../OpenBSD/NativeRegisterContextOpenBSD.cpp | 17 +
.../OpenBSD/NativeRegisterContextOpenBSD.h | 38 +
.../NativeRegisterContextOpenBSD_arch.cpp | 25 +
.../Process/OpenBSD/NativeThreadOpenBSD.cpp | 142 ++++
.../Process/OpenBSD/NativeThreadOpenBSD.h | 71 ++
lldb/tools/lldb-server/CMakeLists.txt | 4 +
lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 +
12 files changed, 1164 insertions(+), 3 deletions(-)
create mode 100644 lldb/source/Plugins/Process/OpenBSD/CMakeLists.txt
create mode 100644 lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.cpp
create mode 100644 lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.h
create mode 100644 lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.cpp
create mode 100644 lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.h
create mode 100644 lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD_arch.cpp
create mode 100644 lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.cpp
create mode 100644 lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.h
diff --git a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
index e5c30adc056158..7f4c38c0a918a5 100644
--- a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
+++ b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
@@ -79,7 +79,7 @@ llvm::StringRef PlatformOpenBSD::GetPluginDescriptionStatic(bool is_host) {
}
void PlatformOpenBSD::Initialize() {
- Platform::Initialize();
+ PlatformPOSIX::Initialize();
if (g_initialize_count++ == 0) {
#if defined(__OpenBSD__)
@@ -145,9 +145,13 @@ void PlatformOpenBSD::GetStatus(Stream &strm) {
#endif
}
-// OpenBSD processes cannot yet be launched by spawning and attaching.
bool PlatformOpenBSD::CanDebugProcess() {
- return false;
+ if (IsHost()) {
+ return true;
+ } else {
+ // If we're connected, we can debug.
+ return IsConnected();
+ }
}
void PlatformOpenBSD::CalculateTrapHandlerSymbolNames() {
diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt
index 84cc65e45157e4..8a8f813b4870d3 100644
--- a/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/CMakeLists.txt
@@ -16,6 +16,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "AIX")
add_subdirectory(AIX)
add_subdirectory(POSIX)
elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+ add_subdirectory(OpenBSD)
add_subdirectory(POSIX)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
add_subdirectory(Windows/Common)
diff --git a/lldb/source/Plugins/Process/OpenBSD/CMakeLists.txt b/lldb/source/Plugins/Process/OpenBSD/CMakeLists.txt
new file mode 100644
index 00000000000000..561c7ad5586e06
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_lldb_library(lldbPluginProcessOpenBSD
+ NativeProcessOpenBSD.cpp
+ NativeRegisterContextOpenBSD.cpp
+ NativeRegisterContextOpenBSD_arch.cpp
+ NativeThreadOpenBSD.cpp
+
+ LINK_COMPONENTS
+ Support
+ LINK_LIBS
+ lldbHost
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ lldbPluginProcessPOSIX
+ lldbPluginProcessUtility
+ )
diff --git a/lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.cpp b/lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.cpp
new file mode 100644
index 00000000000000..76d5816d0d9413
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.cpp
@@ -0,0 +1,723 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessOpenBSD.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#define _DYN_LOADER
+#include <elf.h>
+#include <util.h>
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/State.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Errno.h"
+
+#include <cstring>
+
+// System includes - They have to be included after framework includes because
+// they define some macros which collide with variable names in other modules
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+// clang-format on
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_openbsd;
+using namespace llvm;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Status EnsureFDFlags(int fd, int flags) {
+ int status = fcntl(fd, F_GETFL);
+ if (status == -1)
+ return Status::FromErrno();
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ return Status::FromErrno();
+
+ return Status();
+}
+
+// No architecture has a register context yet.
+static llvm::Error CheckArchitectureSupported() {
+ return llvm::createStringError(
+ "debugging is not supported on this architecture");
+}
+
+// Whether kern.global_ptrace allows attaching to processes that are not
+// children of the debugger.
+static bool IsGlobalPtraceEnabled() {
+ int mib[2] = {CTL_KERN, KERN_GLOBAL_PTRACE};
+ int value = 0;
+ size_t len = sizeof(value);
+ return ::sysctl(mib, 2, &value, &len, nullptr, 0) == 0 && value != 0;
+}
+
+// Public Static Methods
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessOpenBSD::Manager::Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ if (llvm::Error error = CheckArchitectureSupported())
+ return std::move(error);
+
+ Status status;
+ ::pid_t pid = ProcessLauncherPosixFork()
+ .LaunchProcess(launch_info, status)
+ .GetProcessId();
+ LLDB_LOG(log, "pid = {0:x}", pid);
+ if (status.Fail()) {
+ LLDB_LOG(log, "failed to launch process: {0}", status);
+ return status.ToError();
+ }
+
+ // Wait for the child process to trap on its call to execve.
+ int wstatus;
+ ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
+ assert(wpid == pid);
+ UNUSED_IF_ASSERT_DISABLED(wpid);
+ if (!WIFSTOPPED(wstatus)) {
+ LLDB_LOG(log, "Could not sync with inferior process: wstatus={0}",
+ WaitStatus::Decode(wstatus));
+ return llvm::createStringError("could not sync with inferior process");
+ }
+ LLDB_LOG(log, "inferior started, now in stopped state");
+
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::createStringError("cannot get process architecture");
+ }
+
+ // Set the architecture to the exe architecture.
+ LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
+ Info.GetArchitecture().GetArchitectureName());
+
+ std::unique_ptr<NativeProcessOpenBSD> process_up(new NativeProcessOpenBSD(
+ pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
+ Info.GetArchitecture(), m_mainloop));
+
+ status = process_up->RefreshThreads();
+ if (status.Fail())
+ return status.ToError();
+
+ process_up->m_trapped_tid = process_up->GetTrappedThreadID();
+ for (const auto &thread : process_up->m_threads)
+ static_cast<NativeThreadOpenBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+ process_up->SetState(StateType::eStateStopped, false);
+
+ return std::move(process_up);
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessOpenBSD::Manager::Attach(
+ lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
+
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid = {0:x}", pid);
+
+ if (llvm::Error error = CheckArchitectureSupported())
+ return std::move(error);
+
+ // Retrieve the architecture for the running process.
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::createStringError("cannot get process architecture");
+ }
+
+ std::unique_ptr<NativeProcessOpenBSD> process_up(new NativeProcessOpenBSD(
+ pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));
+
+ Status status = process_up->Attach();
+ if (!status.Success())
+ return status.ToError();
+
+ return std::move(process_up);
+}
+
+NativeProcessOpenBSD::Extension
+NativeProcessOpenBSD::Manager::GetSupportedExtensions() const {
+ Extension supported =
+ Extension::pass_signals | Extension::auxv | Extension::libraries_svr4;
+ return supported;
+}
+
+// Public Instance Methods
+
+NativeProcessOpenBSD::NativeProcessOpenBSD(::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate,
+ const ArchSpec &arch,
+ MainLoop &mainloop)
+ : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) {
+ if (m_terminal_fd != -1) {
+ Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ assert(status.Success());
+ }
+
+ Status status;
+ m_sigchld_handle = mainloop.RegisterSignal(
+ SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+ assert(m_sigchld_handle && status.Success());
+}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessOpenBSD::MonitorCallback(lldb::pid_t pid, int signal) {
+ // OpenBSD does not report thread creation or exit, so resynchronize the
+ // thread list every time the process stops.
+ Status error = RefreshThreads();
+ if (error.Fail()) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "failed to refresh threads for pid {0}: {1}", pid, error);
+ }
+
+ switch (signal) {
+ case SIGTRAP:
+ return MonitorSIGTRAP(pid);
+ default:
+ return MonitorSignal(pid, signal);
+ }
+}
+
+void NativeProcessOpenBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
+
+ /* Stop Tracking All Threads attached to Process */
+ m_threads.clear();
+
+ SetExitStatus(status, true);
+
+ // Notify delegate that our process has exited.
+ SetState(StateType::eStateExited, true);
+}
+
+void NativeProcessOpenBSD::MonitorSIGTRAP(lldb::pid_t pid) {
+ // OpenBSD reports a plain SIGTRAP for both a completed PT_STEP and a
+ // software breakpoint, so use what the last resume requested to tell them
+ // apart: it is a step only if the thread that trapped is the one that was
+ // being stepped.
+ m_trapped_tid = GetTrappedThreadID();
+
+ const bool stepped =
+ m_step_tid != LLDB_INVALID_THREAD_ID && m_step_tid == m_trapped_tid;
+ m_step_tid = LLDB_INVALID_THREAD_ID;
+
+ for (const auto &thread : m_threads) {
+ auto &t = static_cast<NativeThreadOpenBSD &>(*thread);
+ if (t.GetID() != m_trapped_tid) {
+ t.SetStoppedWithNoReason();
+ } else if (stepped) {
+ t.SetStoppedByTrace();
+ } else {
+ t.SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(t);
+ }
+ }
+ if (m_trapped_tid != LLDB_INVALID_THREAD_ID)
+ SetCurrentThreadID(m_trapped_tid);
+ SetState(StateType::eStateStopped, true);
+}
+
+void NativeProcessOpenBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+ m_trapped_tid = GetTrappedThreadID();
+ m_step_tid = LLDB_INVALID_THREAD_ID;
+
+ for (const auto &thread : m_threads) {
+ auto &t = static_cast<NativeThreadOpenBSD &>(*thread);
+ if (t.GetID() == m_trapped_tid)
+ t.SetStoppedBySignal(signal);
+ else
+ t.SetStoppedWithNoReason();
+ }
+ if (m_trapped_tid != LLDB_INVALID_THREAD_ID)
+ SetCurrentThreadID(m_trapped_tid);
+ SetState(StateType::eStateStopped, true);
+}
+
+Status NativeProcessOpenBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+ int data, int *result) {
+ Log *log = GetLog(POSIXLog::Ptrace);
+ Status error;
+ int ret;
+
+ errno = 0;
+ ret =
+ ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(addr), data);
+
+ if (ret == -1)
+ error = Status::FromErrno();
+
+ if (result)
+ *result = ret;
+
+ LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
+
+ if (error.Fail())
+ LLDB_LOG(log, "ptrace() failed: {0}", error);
+
+ return error;
+}
+
+Status NativeProcessOpenBSD::Resume(const ResumeActionList &resume_actions) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ // OpenBSD's ptrace(2) can resume either the whole process or, when given a
+ // thread ID, only the thread that reported the last stop (the others stay
+ // suspended). It cannot suspend individual threads, so map lldb's
+ // per-thread actions onto those two modes.
+ NativeThreadOpenBSD *step_thread = nullptr;
+ std::vector<NativeThreadOpenBSD *> run_threads;
+ bool any_suspended = false;
+ int signal = 0;
+
+ for (const auto &abs_thread : m_threads) {
+ auto &thread = static_cast<NativeThreadOpenBSD &>(*abs_thread);
+ const ResumeAction *action =
+ resume_actions.GetActionForThread(thread.GetID(), true);
+ if (action == nullptr) {
+ any_suspended = true;
+ continue;
+ }
+
+ switch (action->state) {
+ case eStateRunning:
+ run_threads.push_back(&thread);
+ break;
+ case eStateStepping:
+ if (step_thread)
+ return Status::FromErrorString(
+ "OpenBSD can only single-step one thread at a time");
+ step_thread = &thread;
+ break;
+ case eStateSuspended:
+ case eStateStopped:
+ any_suspended = true;
+ break;
+ default:
+ return Status::FromErrorStringWithFormat(
+ "NativeProcessOpenBSD::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID());
+ }
+
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ signal = action->signal;
+ }
+
+ lldb::pid_t target = GetID();
+ int req;
+ if (step_thread) {
+#ifdef PT_STEP
+ if (step_thread->GetID() != m_trapped_tid)
+ return Status::FromErrorStringWithFormat(
+ "OpenBSD can only single-step the thread that reported the last "
+ "stop (tid %" PRIu64 ")",
+ m_trapped_tid);
+ req = PT_STEP;
+ // With the thread ID only the stepping thread runs, which is what lldb
+ // wants when the other threads are suspended (e.g. stepping over a
+ // breakpoint). With the process ID the other threads run as well.
+ if (run_threads.empty())
+ target = step_thread->GetID();
+#else
+ return Status::FromErrorString(
+ "NativeProcessOpenBSD stepping not supported on this platform");
+#endif
+ } else if (run_threads.empty()) {
+ LLDB_LOG(log, "no threads to resume for pid {0}", GetID());
+ return Status();
+ } else {
+ req = PT_CONTINUE;
+ if (any_suspended) {
+ if (run_threads.size() == 1 &&
+ run_threads.front()->GetID() == m_trapped_tid)
+ target = m_trapped_tid;
+ else
+ LLDB_LOG(log,
+ "cannot suspend individual threads, resuming all threads "
+ "of pid {0}",
+ GetID());
+ }
+ }
+
+ Status error = PtraceWrapper(req, target, (void *)1, signal);
+ if (error.Fail())
+ return error;
+
+ const bool whole_process = target == GetID();
+ for (const auto &abs_thread : m_threads) {
+ auto &thread = static_cast<NativeThreadOpenBSD &>(*abs_thread);
+ if (&thread == step_thread)
+ thread.SetStepping();
+ else if (whole_process || thread.GetID() == target)
+ thread.SetRunning();
+ }
+ m_step_tid = step_thread ? step_thread->GetID() : LLDB_INVALID_THREAD_ID;
+ SetState(step_thread ? eStateStepping : eStateRunning, true);
+
+ return Status();
+}
+
+Status NativeProcessOpenBSD::Halt() {
+ // Do not try to stop a process that's already stopped, this may cause
+ // the SIGSTOP to get queued and stop the process again once resumed.
+ if (StateIsStoppedState(m_state, false))
+ return Status();
+ if (kill(GetID(), SIGSTOP) != 0)
+ return Status::FromErrno();
+ return Status();
+}
+
+Status NativeProcessOpenBSD::Detach() {
+ Status error;
+
+ // Stop monitoring the inferior.
+ m_sigchld_handle.reset();
+
+ // Tell ptrace to detach from the process.
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ return PtraceWrapper(PT_DETACH, GetID());
+}
+
+Status NativeProcessOpenBSD::Signal(int signo) {
+ if (kill(GetID(), signo) != 0)
+ return Status::FromErrno();
+ return Status();
+}
+
+Status NativeProcessOpenBSD::Kill() {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status error;
+
+ switch (m_state) {
+ case StateType::eStateInvalid:
+ case StateType::eStateExited:
+ case StateType::eStateCrashed:
+ case StateType::eStateDetached:
+ case StateType::eStateUnloaded:
+ // Nothing to do - the process is already dead.
+ LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
+ StateAsCString(m_state));
+ return error;
+
+ case StateType::eStateConnected:
+ case StateType::eStateAttaching:
+ case StateType::eStateLaunching:
+ case StateType::eStateStopped:
+ case StateType::eStateRunning:
+ case StateType::eStateStepping:
+ case StateType::eStateSuspended:
+ // We can try to kill a process in these states.
+ break;
+ }
+
+ // A process stopped by ptrace(2) does not act on SIGKILL until it is
+ // resumed, so use PT_KILL, which resumes it with SIGKILL. PT_KILL fails on
+ // a running process, so signal that one directly.
+ if (StateIsStoppedState(m_state, false))
+ return PtraceWrapper(PT_KILL, GetID());
+
+ if (kill(GetID(), SIGKILL) != 0)
+ return Status::FromErrno();
+
+ return error;
+}
+
+llvm::Expected<lldb::addr_t>
+NativeProcessOpenBSD::AllocateMemory(size_t size, uint32_t permissions) {
+ return llvm::make_error<UnimplementedError>();
+}
+
+llvm::Error NativeProcessOpenBSD::DeallocateMemory(lldb::addr_t addr) {
+ return llvm::make_error<UnimplementedError>();
+}
+
+size_t NativeProcessOpenBSD::UpdateThreads() { return m_threads.size(); }
+
+Status NativeProcessOpenBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ if (hardware)
+ return Status::FromErrorString(
+ "NativeProcessOpenBSD does not support hardware breakpoints");
+ else
+ return SetSoftwareBreakpoint(addr, size);
+}
+
+Status NativeProcessOpenBSD::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ return Status::FromErrorString("Unimplemented");
+}
+
+Status
+NativeProcessOpenBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ return Status::FromErrorString("Unimplemented");
+}
+
+void NativeProcessOpenBSD::SigchldHandler() {
+ Log *log = GetLog(POSIXLog::Process);
+ // Process all pending waitpid notifications.
+ int status;
+ ::pid_t wait_pid =
+ llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG);
+
+ if (wait_pid == 0)
+ return; // We are done.
+
+ if (wait_pid == -1) {
+ Status error(errno, eErrorTypePOSIX);
+ LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+ return;
+ }
+
+ WaitStatus wait_status = WaitStatus::Decode(status);
+ bool exited = wait_status.type == WaitStatus::Exit ||
+ (wait_status.type == WaitStatus::Signal &&
+ wait_pid == static_cast<::pid_t>(GetID()));
+
+ LLDB_LOG(log,
+ "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
+ GetID(), wait_pid, status, exited);
+
+ if (exited)
+ MonitorExited(wait_pid, wait_status);
+ else {
+ assert(wait_status.type == WaitStatus::Stop);
+ MonitorCallback(wait_pid, wait_status.status);
+ }
+}
+
+bool NativeProcessOpenBSD::HasThreadNoLock(lldb::tid_t thread_id) {
+ for (const auto &thread : m_threads) {
+ assert(thread && "thread list should not contain NULL threads");
+ if (thread->GetID() == thread_id) {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+NativeThreadOpenBSD &NativeProcessOpenBSD::AddThread(lldb::tid_t thread_id) {
+
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+
+ assert(!HasThreadNoLock(thread_id) &&
+ "attempted to add a thread by id that already exists");
+
+ // If this is the first thread, save it as the current thread
+ if (m_threads.empty())
+ SetCurrentThreadID(thread_id);
+
+ m_threads.push_back(std::make_unique<NativeThreadOpenBSD>(*this, thread_id));
+ return static_cast<NativeThreadOpenBSD &>(*m_threads.back());
+}
+
+Status NativeProcessOpenBSD::Attach() {
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ Status status = PtraceWrapper(PT_ATTACH, m_pid);
+ if (status.Fail()) {
+ if (status.GetError() == EPERM && ::geteuid() != 0 &&
+ !IsGlobalPtraceEnabled())
+ return Status::FromErrorString(
+ "operation not permitted: attaching to a process that is not a "
+ "child of the debugger requires root or kern.global_ptrace=1");
+ return status;
+ }
+
+ int wstatus;
+ // At this point we should have a thread stopped if waitpid succeeds.
+ if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) <
+ 0)
+ return Status(errno, eErrorTypePOSIX);
+
+ // Initialize threads.
+ status = RefreshThreads();
+ if (status.Fail())
+ return status;
+
+ m_trapped_tid = GetTrappedThreadID();
+
+ for (const auto &thread : m_threads)
+ static_cast<NativeThreadOpenBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+
+ // Let our process instance know the thread has stopped.
+ SetCurrentThreadID(m_threads.front()->GetID());
+ SetState(StateType::eStateStopped, false);
+ return Status();
+}
+
+Status NativeProcessOpenBSD::ReadMemory(const ProcessAddress &process_addr,
+ void *buf, size_t size,
+ size_t &bytes_read) {
+ lldb::addr_t addr = process_addr.GetValue();
+ unsigned char *dst = static_cast<unsigned char *>(buf);
+ struct ptrace_io_desc io;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_read = 0;
+ io.piod_op = PIOD_READ_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_offs = (void *)(addr + bytes_read);
+ io.piod_addr = dst + bytes_read;
+
+ Status error = NativeProcessOpenBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_read += io.piod_len;
+ io.piod_len = size - bytes_read;
+ } while (bytes_read < size);
+
+ return Status();
+}
+
+Status NativeProcessOpenBSD::DoWriteMemory(lldb::addr_t addr, const void *buf,
+ size_t size, size_t &bytes_written) {
+ const unsigned char *src = static_cast<const unsigned char *>(buf);
+ struct ptrace_io_desc io;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_written = 0;
+ io.piod_op = PIOD_WRITE_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_addr =
+ const_cast<void *>(static_cast<const void *>(src + bytes_written));
+ io.piod_offs = (void *)(addr + bytes_written);
+
+ Status error = NativeProcessOpenBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_written += io.piod_len;
+ io.piod_len = size - bytes_written;
+ } while (bytes_written < size);
+
+ return Status();
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+NativeProcessOpenBSD::GetAuxvData() const {
+ size_t auxv_size = 100 * sizeof(AuxInfo);
+
+ std::unique_ptr<WritableMemoryBuffer> buf =
+ llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
+ if (!buf)
+ return std::make_error_code(std::errc::not_enough_memory);
+
+ struct ptrace_io_desc io;
+ io.piod_op = PIOD_READ_AUXV;
+ io.piod_offs = 0;
+ io.piod_addr = buf->getBufferStart();
+ io.piod_len = auxv_size;
+
+ Status error = NativeProcessOpenBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail())
+ return std::error_code(error.GetError(), std::generic_category());
+
+ if (io.piod_len < 1)
+ return std::error_code(ECANCELED, std::generic_category());
+
+ // Return only what the kernel actually filled in.
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::StringRef(buf->getBufferStart(), io.piod_len));
+}
+
+Status NativeProcessOpenBSD::RefreshThreads() {
+ Log *log = GetLog(POSIXLog::Thread);
+
+ // Read the kernel's current list of threads.
+ std::vector<std::pair<lldb::tid_t, std::string>> kernel_threads;
+ struct ptrace_thread_state info = {};
+ Status error =
+ PtraceWrapper(PT_GET_THREAD_FIRST, GetID(), &info, sizeof(info));
+ if (error.Fail())
+ return error;
+ while (info.pts_tid > 0) {
+ kernel_threads.emplace_back(
+ info.pts_tid,
+ std::string(info.pts_name,
+ strnlen(info.pts_name, sizeof(info.pts_name))));
+ error = PtraceWrapper(PT_GET_THREAD_NEXT, GetID(), &info, sizeof(info));
+ if (error.Fail()) {
+ LLDB_LOG(log, "PT_GET_THREAD_NEXT failed for pid {0}: {1}", GetID(),
+ error);
+ break;
+ }
+ }
+
+ // Drop threads that have exited since the last stop.
+ llvm::erase_if(
+ m_threads, [&](const std::unique_ptr<NativeThreadProtocol> &t) {
+ bool alive = llvm::any_of(kernel_threads, [&](const auto &kt) {
+ return kt.first == t->GetID();
+ });
+ if (!alive)
+ LLDB_LOG(log, "pid {0} removing exited thread with tid {1}", GetID(),
+ t->GetID());
+ return !alive;
+ });
+
+ // Add threads created since the last stop, and refresh thread names.
+ for (const auto &[tid, name] : kernel_threads) {
+ auto *thread = static_cast<NativeThreadOpenBSD *>(GetThreadByID(tid));
+ if (!thread)
+ thread = &AddThread(tid);
+ thread->SetName(name);
+ }
+
+ if (!m_threads.empty() && !HasThreadNoLock(GetCurrentThreadID()))
+ SetCurrentThreadID(m_threads.front()->GetID());
+
+ return Status();
+}
+
+lldb::tid_t NativeProcessOpenBSD::GetTrappedThreadID() {
+ Log *log = GetLog(POSIXLog::Thread);
+
+ struct ptrace_state state = {};
+ Status error =
+ PtraceWrapper(PT_GET_PROCESS_STATE, GetID(), &state, sizeof(state));
+ if (error.Success() && state.pe_tid > 0 &&
+ HasThreadNoLock(static_cast<lldb::tid_t>(state.pe_tid)))
+ return state.pe_tid;
+
+ LLDB_LOG(log, "could not determine the stopped thread of pid {0}: {1}",
+ GetID(), error);
+ return m_threads.empty() ? LLDB_INVALID_THREAD_ID
+ : m_threads.front()->GetID();
+}
diff --git a/lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.h b/lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.h
new file mode 100644
index 00000000000000..2401ce73685f27
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/NativeProcessOpenBSD.h
@@ -0,0 +1,116 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVEPROCESSOPENBSD_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVEPROCESSOPENBSD_H
+
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "NativeThreadOpenBSD.h"
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
+
+namespace lldb_private {
+namespace process_openbsd {
+/// @class NativeProcessOpenBSD
+/// Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process
+/// for debugging.
+///
+/// Changes in the inferior process state are broadcasted.
+class NativeProcessOpenBSD : public NativeProcessELF {
+public:
+ class Manager : public NativeProcessProtocol::Manager {
+ public:
+ using NativeProcessProtocol::Manager::Manager;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) override;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override;
+
+ Extension GetSupportedExtensions() const override;
+ };
+
+ // NativeProcessProtocol Interface
+ Status Resume(const ResumeActionList &resume_actions) override;
+
+ Status Halt() override;
+
+ Status Detach() override;
+
+ Status Signal(int signo) override;
+
+ Status Kill() override;
+
+ Status ReadMemory(const ProcessAddress &addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Status DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
+
+ llvm::Expected<lldb::addr_t> AllocateMemory(size_t size,
+ uint32_t permissions) override;
+
+ llvm::Error DeallocateMemory(lldb::addr_t addr) override;
+
+ size_t UpdateThreads() override;
+
+ const ArchSpec &GetArchitecture() const override { return m_arch; }
+
+ Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) override;
+
+ Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
+
+ Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const override;
+
+ // Interface used by NativeRegisterContext-derived classes.
+ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ int data = 0, int *result = nullptr);
+
+private:
+ MainLoop::SignalHandleUP m_sigchld_handle;
+ ArchSpec m_arch;
+ // Thread that was single-stepped by the last Resume(), if any.
+ lldb::tid_t m_step_tid = LLDB_INVALID_THREAD_ID;
+ // Thread that reported the last stop.
+ lldb::tid_t m_trapped_tid = LLDB_INVALID_THREAD_ID;
+
+ // Private Instance Methods
+ NativeProcessOpenBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
+ const ArchSpec &arch, MainLoop &mainloop);
+
+ bool HasThreadNoLock(lldb::tid_t thread_id);
+
+ NativeThreadOpenBSD &AddThread(lldb::tid_t thread_id);
+
+ void MonitorCallback(lldb::pid_t pid, int signal);
+ void MonitorExited(lldb::pid_t pid, WaitStatus status);
+ void MonitorSIGTRAP(lldb::pid_t pid);
+ void MonitorSignal(lldb::pid_t pid, int signal);
+
+ void SigchldHandler();
+
+ Status Attach();
+ Status RefreshThreads();
+ lldb::tid_t GetTrappedThreadID();
+};
+
+} // namespace process_openbsd
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVEPROCESSOPENBSD_H
diff --git a/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.cpp b/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.cpp
new file mode 100644
index 00000000000000..37ffb44050f376
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.cpp
@@ -0,0 +1,17 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextOpenBSD.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_openbsd;
+
+NativeRegisterContextOpenBSD::NativeRegisterContextOpenBSD(
+ NativeThreadProtocol &native_thread,
+ RegisterInfoInterface *reg_info_interface_p)
+ : NativeRegisterContextRegisterInfo(native_thread, reg_info_interface_p) {}
diff --git a/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.h b/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.h
new file mode 100644
index 00000000000000..1e1300a7c1a1ef
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.h
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVEREGISTERCONTEXTOPENBSD_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVEREGISTERCONTEXTOPENBSD_H
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/OpenBSD/NativeProcessOpenBSD.h"
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+namespace process_openbsd {
+
+class NativeRegisterContextOpenBSD : public NativeRegisterContextRegisterInfo {
+public:
+ NativeRegisterContextOpenBSD(NativeThreadProtocol &native_thread,
+ RegisterInfoInterface *reg_info_interface_p);
+
+ // This function is implemented in the NativeRegisterContextOpenBSD_*
+ // subclasses to create a new instance of the host specific
+ // NativeRegisterContextOpenBSD. The implementations can't collide as only one
+ // NativeRegisterContextOpenBSD_* variant should be compiled into the final
+ // executable.
+ static std::unique_ptr<NativeRegisterContextOpenBSD>
+ CreateHostNativeRegisterContextOpenBSD(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread);
+};
+
+} // namespace process_openbsd
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVEREGISTERCONTEXTOPENBSD_H
diff --git a/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD_arch.cpp b/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD_arch.cpp
new file mode 100644
index 00000000000000..1a26483b861c99
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD_arch.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// NativeRegisterContextOpenBSD_* contains the implementations for each
+// supported architecture, and includes the static initalizer
+// CreateHostNativeRegisterContextOpenBSD() implementation which returns a arch
+// specific register context. This implementation contains a stub
+// which just reports an error and exits on architectures which do
+// not have a backend.
+
+#include "Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_openbsd;
+
+std::unique_ptr<NativeRegisterContextOpenBSD>
+NativeRegisterContextOpenBSD::CreateHostNativeRegisterContextOpenBSD(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+ return std::unique_ptr<NativeRegisterContextOpenBSD>{};
+}
diff --git a/lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.cpp b/lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.cpp
new file mode 100644
index 00000000000000..f0a355962f21bd
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.cpp
@@ -0,0 +1,142 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadOpenBSD.h"
+#include "NativeRegisterContextOpenBSD.h"
+
+#include "NativeProcessOpenBSD.h"
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_openbsd;
+
+NativeThreadOpenBSD::NativeThreadOpenBSD(NativeProcessOpenBSD &process,
+ lldb::tid_t tid)
+ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {
+ m_reg_context_up =
+ NativeRegisterContextOpenBSD::CreateHostNativeRegisterContextOpenBSD(
+ process.GetArchitecture(), *this);
+ // NativeProcessOpenBSD::Manager refuses to launch or attach on
+ // architectures without a register context.
+ assert(m_reg_context_up && "no register context for this architecture");
+}
+
+void NativeThreadOpenBSD::SetStoppedBySignal(uint32_t signo) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.signo = signo;
+}
+
+void NativeThreadOpenBSD::SetStoppedByBreakpoint() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadOpenBSD::SetStoppedByTrace() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonTrace;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadOpenBSD::SetStoppedByExec() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonExec;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadOpenBSD::SetStoppedWithNoReason() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_info.signo = 0;
+}
+
+void NativeThreadOpenBSD::SetStopped() {
+ const StateType new_state = StateType::eStateStopped;
+ m_state = new_state;
+ m_stop_description.clear();
+}
+
+void NativeThreadOpenBSD::SetRunning() {
+ m_state = StateType::eStateRunning;
+ ClearStopInfo();
+}
+
+void NativeThreadOpenBSD::SetStepping() {
+ m_state = StateType::eStateStepping;
+ ClearStopInfo();
+}
+
+std::string NativeThreadOpenBSD::GetName() { return m_name; }
+
+lldb::StateType NativeThreadOpenBSD::GetState() { return m_state; }
+
+bool NativeThreadOpenBSD::GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) {
+ Log *log = GetLog(POSIXLog::Thread);
+
+ description.clear();
+
+ switch (m_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ stop_info = m_stop_info;
+ description = m_stop_description;
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
+ StateAsCString(m_state));
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+NativeRegisterContext &NativeThreadOpenBSD::GetRegisterContext() {
+ assert(m_reg_context_up);
+ return *m_reg_context_up;
+}
+
+Status NativeThreadOpenBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ if (hardware)
+ return Status::FromErrorString("Not Available");
+ return Status::FromErrorString("Software watchpoints not implemented");
+}
+
+Status NativeThreadOpenBSD::RemoveWatchpoint(lldb::addr_t addr) {
+ return Status::FromErrorString("Software watchpoints not implemented");
+}
+
+Status NativeThreadOpenBSD::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ return Status::FromErrorString("Not Available");
+}
+
+Status NativeThreadOpenBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ return Status::FromErrorString("Not Available");
+}
diff --git a/lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.h b/lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.h
new file mode 100644
index 00000000000000..f7ace9456a7f72
--- /dev/null
+++ b/lldb/source/Plugins/Process/OpenBSD/NativeThreadOpenBSD.h
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVETHREADOPENBSD_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVETHREADOPENBSD_H
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include <csignal>
+#include <string>
+
+namespace lldb_private {
+namespace process_openbsd {
+
+class NativeProcessOpenBSD;
+
+class NativeThreadOpenBSD : public NativeThreadProtocol {
+ friend class NativeProcessOpenBSD;
+
+public:
+ NativeThreadOpenBSD(NativeProcessOpenBSD &process, lldb::tid_t tid);
+
+ // NativeThreadProtocol Interface
+ std::string GetName() override;
+
+ lldb::StateType GetState() override;
+
+ bool GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) override;
+
+ NativeRegisterContext &GetRegisterContext() override;
+
+ // OpenBSD does not expose hardware debug registers to userland
+ // so these functions will just return a Status error.
+ Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+ Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+ // Similarly, until software watchpoints are implemented in lldb,
+ // these functions will just return a Status error.
+ Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
+ Status RemoveWatchpoint(lldb::addr_t addr) override;
+
+private:
+ // Interface for friend classes
+
+ void SetStoppedBySignal(uint32_t signo);
+ void SetStoppedByBreakpoint();
+ void SetStoppedByTrace();
+ void SetStoppedByExec();
+ void SetStoppedWithNoReason();
+ void SetStopped();
+ void SetRunning();
+ void SetStepping();
+ void SetName(std::string name) { m_name = std::move(name); }
+
+ // Member Variables
+ lldb::StateType m_state;
+ std::unique_ptr<NativeRegisterContext> m_reg_context_up;
+ std::string m_name;
+};
+
+} // namespace process_openbsd
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_OPENBSD_NATIVETHREADOPENBSD_H
diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt
index fd31d81a35c202..e0e50ba1df7ef7 100644
--- a/lldb/tools/lldb-server/CMakeLists.txt
+++ b/lldb/tools/lldb-server/CMakeLists.txt
@@ -24,6 +24,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
list(APPEND LLDB_PLUGINS lldbPluginProcessNetBSD)
endif()
+if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+ list(APPEND LLDB_PLUGINS lldbPluginProcessOpenBSD)
+endif()
+
if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
list(APPEND LLDB_PLUGINS lldbPluginObjectFileMachO)
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp
index 98a79dedf65c02..8bb79e9696daba 100644
--- a/lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -50,6 +50,8 @@
#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
#elif defined(__NetBSD__)
#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
+#elif defined(__OpenBSD__)
+#include "Plugins/Process/OpenBSD/NativeProcessOpenBSD.h"
#elif defined(_WIN32)
#include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
#elif defined(_AIX)
@@ -77,6 +79,8 @@ typedef process_linux::NativeProcessLinux::Manager NativeProcessManager;
typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager;
#elif defined(__NetBSD__)
typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager;
+#elif defined(__OpenBSD__)
+typedef process_openbsd::NativeProcessOpenBSD::Manager NativeProcessManager;
#elif defined(_WIN32)
typedef NativeProcessWindows::Manager NativeProcessManager;
#elif defined(_AIX)
More information about the lldb-commits
mailing list