forked from OSchip/llvm-project
Add support for tracing hello-world application on NetBSD
Summary: This patch is a stripped down from features a NetBSD process code (patch is kept under 2k LOC). This code has assumption that there is only one thread within a debugged process. The only debugger trap supported is software breakpoint (TRAP_BRKPT). The generic platform code requires to add dummy function for watchpoints etc. These functions are currently empty. This code is not the final platform support as is and it's treated as a base to extend, refactor and address issues afterwards. Supported features: - handle software breakpoints, - correctly attach to a tracee, - support NetBSD specific ptrace(2), - monitor process termination, - monitor SIGTRAP events, - monitor SIGSTOP events, - monitor other signals events, - resume the whole process, - get memory region info perms, - read memory from tracee, - write memory to tracee, - read ELF AUXV, - x86_64 GPR read and write code For the generic framework include: - halt, - detach, - signal, - kill, - allocatememory, - deallocatememory, - update threads, - getarchitecture, - getfileloadaddress, - and others. This code has preliminary AddThread code. Out of interest in this patch: - exec() traps, - hardware debug register traps, - single step trap, - thread creation/termination trap, - process fork(2), vfork(2) and vfork(2) done traps, - syscall entry and exit trap, - threads, - FPR registers, - retrieving tracee's thread name, - non x86_64 support. This code can be used to start a hello world application and trace it. This code can be used by other BSD systems as a starting point to get similar capabilities. Sponsored by <The NetBSD Foundation> Reviewers: emaste, joerg, kettenis, labath Subscribers: mgorny, #lldb Tags: #lldb Differential Revision: https://reviews.llvm.org/D31374 llvm-svn: 298953
This commit is contained in:
parent
69b191c628
commit
f07a9995e8
|
@ -5,6 +5,7 @@ include_directories(../Utility)
|
||||||
add_lldb_library(lldbPluginProcessNetBSD PLUGIN
|
add_lldb_library(lldbPluginProcessNetBSD PLUGIN
|
||||||
NativeProcessNetBSD.cpp
|
NativeProcessNetBSD.cpp
|
||||||
NativeRegisterContextNetBSD.cpp
|
NativeRegisterContextNetBSD.cpp
|
||||||
|
NativeRegisterContextNetBSD_x86_64.cpp
|
||||||
NativeThreadNetBSD.cpp
|
NativeThreadNetBSD.cpp
|
||||||
|
|
||||||
LINK_LIBS
|
LINK_LIBS
|
||||||
|
|
|
@ -14,18 +14,77 @@
|
||||||
// C++ Includes
|
// C++ Includes
|
||||||
|
|
||||||
// Other libraries and framework includes
|
// Other libraries and framework includes
|
||||||
|
|
||||||
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
|
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
|
||||||
|
#include "lldb/Core/State.h"
|
||||||
|
#include "lldb/Host/HostProcess.h"
|
||||||
|
#include "lldb/Host/common/NativeBreakpoint.h"
|
||||||
|
#include "lldb/Host/common/NativeRegisterContext.h"
|
||||||
|
#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
|
||||||
|
#include "lldb/Target/Process.h"
|
||||||
|
|
||||||
// System includes - They have to be included after framework includes because
|
// System includes - They have to be included after framework includes because
|
||||||
// they define some
|
// they define some
|
||||||
// macros which collide with variable names in other modules
|
// 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 <uvm/uvm_prot.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <util.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
using namespace lldb;
|
using namespace lldb;
|
||||||
using namespace lldb_private;
|
using namespace lldb_private;
|
||||||
using namespace lldb_private::process_netbsd;
|
using namespace lldb_private::process_netbsd;
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
static ExitType convert_pid_status_to_exit_type(int status) {
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
return ExitType::eExitTypeExit;
|
||||||
|
else if (WIFSIGNALED(status))
|
||||||
|
return ExitType::eExitTypeSignal;
|
||||||
|
else if (WIFSTOPPED(status))
|
||||||
|
return ExitType::eExitTypeStop;
|
||||||
|
else {
|
||||||
|
// We don't know what this is.
|
||||||
|
return ExitType::eExitTypeInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int convert_pid_status_to_return_code(int status) {
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
else if (WIFSIGNALED(status))
|
||||||
|
return WTERMSIG(status);
|
||||||
|
else if (WIFSTOPPED(status))
|
||||||
|
return WSTOPSIG(status);
|
||||||
|
else {
|
||||||
|
// We don't know what this is.
|
||||||
|
return ExitType::eExitTypeInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple helper function to ensure flags are enabled on the given file
|
||||||
|
// descriptor.
|
||||||
|
static Error EnsureFDFlags(int fd, int flags) {
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
int status = fcntl(fd, F_GETFL);
|
||||||
|
if (status == -1) {
|
||||||
|
error.SetErrorToErrno();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(fd, F_SETFL, status | flags) == -1) {
|
||||||
|
error.SetErrorToErrno();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Public Static Methods
|
// Public Static Methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -34,13 +93,68 @@ Error NativeProcessProtocol::Launch(
|
||||||
ProcessLaunchInfo &launch_info,
|
ProcessLaunchInfo &launch_info,
|
||||||
NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
|
NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
|
||||||
NativeProcessProtocolSP &native_process_sp) {
|
NativeProcessProtocolSP &native_process_sp) {
|
||||||
return Error();
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
// Verify the working directory is valid if one was specified.
|
||||||
|
FileSpec working_dir{launch_info.GetWorkingDirectory()};
|
||||||
|
if (working_dir && (!working_dir.ResolvePath() ||
|
||||||
|
!llvm::sys::fs::is_directory(working_dir.GetPath()))) {
|
||||||
|
error.SetErrorStringWithFormat("No such file or directory: %s",
|
||||||
|
working_dir.GetCString());
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the NativeProcessNetBSD in launch mode.
|
||||||
|
native_process_sp.reset(new NativeProcessNetBSD());
|
||||||
|
|
||||||
|
if (!native_process_sp->RegisterNativeDelegate(native_delegate)) {
|
||||||
|
native_process_sp.reset();
|
||||||
|
error.SetErrorStringWithFormat("failed to register the native delegate");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = std::static_pointer_cast<NativeProcessNetBSD>(native_process_sp)
|
||||||
|
->LaunchInferior(mainloop, launch_info);
|
||||||
|
|
||||||
|
if (error.Fail()) {
|
||||||
|
native_process_sp.reset();
|
||||||
|
LLDB_LOG(log, "failed to launch process: {0}", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_info.SetProcessID(native_process_sp->GetID());
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error NativeProcessProtocol::Attach(
|
Error NativeProcessProtocol::Attach(
|
||||||
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||||
MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) {
|
MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) {
|
||||||
return Error();
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||||
|
|
||||||
|
// Retrieve the architecture for the running process.
|
||||||
|
ArchSpec process_arch;
|
||||||
|
Error error = ResolveProcessArchitecture(pid, process_arch);
|
||||||
|
if (!error.Success())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
std::shared_ptr<NativeProcessNetBSD> native_process_netbsd_sp(
|
||||||
|
new NativeProcessNetBSD());
|
||||||
|
|
||||||
|
if (!native_process_netbsd_sp->RegisterNativeDelegate(native_delegate)) {
|
||||||
|
error.SetErrorStringWithFormat("failed to register the native delegate");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
native_process_netbsd_sp->AttachToInferior(mainloop, pid, error);
|
||||||
|
if (!error.Success())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
native_process_sp = native_process_netbsd_sp;
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -48,4 +162,830 @@ Error NativeProcessProtocol::Attach(
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
NativeProcessNetBSD::NativeProcessNetBSD()
|
NativeProcessNetBSD::NativeProcessNetBSD()
|
||||||
: NativeProcessProtocol(LLDB_INVALID_PROCESS_ID) {}
|
: NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(),
|
||||||
|
m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache() {}
|
||||||
|
|
||||||
|
// Handles all waitpid events from the inferior process.
|
||||||
|
void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
|
||||||
|
switch (signal) {
|
||||||
|
case SIGTRAP:
|
||||||
|
return MonitorSIGTRAP(pid);
|
||||||
|
case SIGSTOP:
|
||||||
|
return MonitorSIGSTOP(pid);
|
||||||
|
default:
|
||||||
|
return MonitorSignal(pid, signal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, int signal,
|
||||||
|
int status) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
|
||||||
|
LLDB_LOG(log, "got exit signal({0}) , pid = {1}", signal, pid);
|
||||||
|
|
||||||
|
/* Stop Tracking All Threads attached to Process */
|
||||||
|
m_threads.clear();
|
||||||
|
|
||||||
|
SetExitStatus(convert_pid_status_to_exit_type(status),
|
||||||
|
convert_pid_status_to_return_code(status), nullptr, true);
|
||||||
|
|
||||||
|
// Notify delegate that our process has exited.
|
||||||
|
SetState(StateType::eStateExited, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
ptrace_siginfo_t info;
|
||||||
|
|
||||||
|
const auto siginfo_err =
|
||||||
|
PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
|
||||||
|
|
||||||
|
// Get details on the signal raised.
|
||||||
|
if (siginfo_err.Success()) {
|
||||||
|
// Handle SIGSTOP from LLGS (LLDB GDB Server)
|
||||||
|
if (info.psi_siginfo.si_code == SI_USER &&
|
||||||
|
info.psi_siginfo.si_pid == ::getpid()) {
|
||||||
|
/* Stop Tracking All Threads attached to Process */
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
|
||||||
|
SIGSTOP, &info.psi_siginfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
ptrace_siginfo_t info;
|
||||||
|
|
||||||
|
const auto siginfo_err =
|
||||||
|
PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
|
||||||
|
|
||||||
|
// Get details on the signal raised.
|
||||||
|
if (siginfo_err.Success()) {
|
||||||
|
switch (info.psi_siginfo.si_code) {
|
||||||
|
case TRAP_BRKPT:
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)
|
||||||
|
->SetStoppedByBreakpoint();
|
||||||
|
FixupBreakpointPCAsNeeded(
|
||||||
|
*static_pointer_cast<NativeThreadNetBSD>(thread_sp));
|
||||||
|
}
|
||||||
|
SetState(StateType::eStateStopped, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
|
||||||
|
ptrace_siginfo_t info;
|
||||||
|
const auto siginfo_err =
|
||||||
|
PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
|
||||||
|
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
|
||||||
|
info.psi_siginfo.si_signo, &info.psi_siginfo);
|
||||||
|
}
|
||||||
|
SetState(StateType::eStateStopped, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
|
||||||
|
int data, int *result) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
|
||||||
|
Error error;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
error.SetErrorToErrno();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::GetSoftwareBreakpointPCOffset(
|
||||||
|
uint32_t &actual_opcode_size) {
|
||||||
|
// FIXME put this behind a breakpoint protocol class that can be
|
||||||
|
// set per architecture. Need ARM, MIPS support here.
|
||||||
|
static const uint8_t g_i386_opcode[] = {0xCC};
|
||||||
|
switch (m_arch.GetMachine()) {
|
||||||
|
case llvm::Triple::x86_64:
|
||||||
|
actual_opcode_size = static_cast<uint32_t>(sizeof(g_i386_opcode));
|
||||||
|
return Error();
|
||||||
|
default:
|
||||||
|
assert(false && "CPU type not supported!");
|
||||||
|
return Error("CPU type not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::FixupBreakpointPCAsNeeded(
|
||||||
|
NativeThreadNetBSD &thread) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
|
||||||
|
Error error;
|
||||||
|
// Find out the size of a breakpoint (might depend on where we are in the
|
||||||
|
// code).
|
||||||
|
NativeRegisterContextSP context_sp = thread.GetRegisterContext();
|
||||||
|
if (!context_sp) {
|
||||||
|
error.SetErrorString("cannot get a NativeRegisterContext for the thread");
|
||||||
|
LLDB_LOG(log, "failed: {0}", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
uint32_t breakpoint_size = 0;
|
||||||
|
error = GetSoftwareBreakpointPCOffset(breakpoint_size);
|
||||||
|
if (error.Fail()) {
|
||||||
|
LLDB_LOG(log, "GetBreakpointSize() failed: {0}", error);
|
||||||
|
return error;
|
||||||
|
} else
|
||||||
|
LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size);
|
||||||
|
// First try probing for a breakpoint at a software breakpoint location: PC -
|
||||||
|
// breakpoint size.
|
||||||
|
const lldb::addr_t initial_pc_addr =
|
||||||
|
context_sp->GetPCfromBreakpointLocation();
|
||||||
|
lldb::addr_t breakpoint_addr = initial_pc_addr;
|
||||||
|
if (breakpoint_size > 0) {
|
||||||
|
// Do not allow breakpoint probe to wrap around.
|
||||||
|
if (breakpoint_addr >= breakpoint_size)
|
||||||
|
breakpoint_addr -= breakpoint_size;
|
||||||
|
}
|
||||||
|
// Check if we stopped because of a breakpoint.
|
||||||
|
NativeBreakpointSP breakpoint_sp;
|
||||||
|
error = m_breakpoint_list.GetBreakpoint(breakpoint_addr, breakpoint_sp);
|
||||||
|
if (!error.Success() || !breakpoint_sp) {
|
||||||
|
// We didn't find one at a software probe location. Nothing to do.
|
||||||
|
LLDB_LOG(log,
|
||||||
|
"pid {0} no lldb breakpoint found at current pc with "
|
||||||
|
"adjustment: {1}",
|
||||||
|
GetID(), breakpoint_addr);
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
// If the breakpoint is not a software breakpoint, nothing to do.
|
||||||
|
if (!breakpoint_sp->IsSoftwareBreakpoint()) {
|
||||||
|
LLDB_LOG(
|
||||||
|
log,
|
||||||
|
"pid {0} breakpoint found at {1:x}, not software, nothing to adjust",
|
||||||
|
GetID(), breakpoint_addr);
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// We have a software breakpoint and need to adjust the PC.
|
||||||
|
//
|
||||||
|
// Sanity check.
|
||||||
|
if (breakpoint_size == 0) {
|
||||||
|
// Nothing to do! How did we get here?
|
||||||
|
LLDB_LOG(log,
|
||||||
|
"pid {0} breakpoint found at {1:x}, it is software, but the "
|
||||||
|
"size is zero, nothing to do (unexpected)",
|
||||||
|
GetID(), breakpoint_addr);
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// We have a software breakpoint and need to adjust the PC.
|
||||||
|
//
|
||||||
|
// Sanity check.
|
||||||
|
if (breakpoint_size == 0) {
|
||||||
|
// Nothing to do! How did we get here?
|
||||||
|
LLDB_LOG(log,
|
||||||
|
"pid {0} breakpoint found at {1:x}, it is software, but the "
|
||||||
|
"size is zero, nothing to do (unexpected)",
|
||||||
|
GetID(), breakpoint_addr);
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
// Change the program counter.
|
||||||
|
LLDB_LOG(log, "pid {0} tid {1}: changing PC from {2:x} to {3:x}", GetID(),
|
||||||
|
thread.GetID(), initial_pc_addr, breakpoint_addr);
|
||||||
|
error = context_sp->SetPC(breakpoint_addr);
|
||||||
|
if (error.Fail()) {
|
||||||
|
LLDB_LOG(log, "pid {0} tid {1}: failed to set PC: {2}", GetID(),
|
||||||
|
thread.GetID(), error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
LLDB_LOG(log, "pid {0}", GetID());
|
||||||
|
|
||||||
|
const auto &thread_sp = m_threads[0];
|
||||||
|
const ResumeAction *const action =
|
||||||
|
resume_actions.GetActionForThread(thread_sp->GetID(), true);
|
||||||
|
|
||||||
|
if (action == nullptr) {
|
||||||
|
LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
|
||||||
|
thread_sp->GetID());
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action->state) {
|
||||||
|
case eStateRunning: {
|
||||||
|
// Run the thread, possibly feeding it the signal.
|
||||||
|
Error error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(),
|
||||||
|
(void *)1, action->signal);
|
||||||
|
if (!error.Success())
|
||||||
|
return error;
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetRunning();
|
||||||
|
}
|
||||||
|
SetState(eStateRunning, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case eStateStepping:
|
||||||
|
return Error("Not implemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eStateSuspended:
|
||||||
|
case eStateStopped:
|
||||||
|
llvm_unreachable("Unexpected state");
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Error("NativeProcessLinux::%s (): unexpected state %s specified "
|
||||||
|
"for pid %" PRIu64 ", tid %" PRIu64,
|
||||||
|
__FUNCTION__, StateAsCString(action->state), GetID(),
|
||||||
|
thread_sp->GetID());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::Halt() {
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
if (kill(GetID(), SIGSTOP) != 0)
|
||||||
|
error.SetErrorToErrno();
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::Detach() {
|
||||||
|
Error 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::Signal(int signo) {
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
if (kill(GetID(), signo))
|
||||||
|
error.SetErrorToErrno();
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::Kill() {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
LLDB_LOG(log, "pid {0}", GetID());
|
||||||
|
|
||||||
|
Error 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kill(GetID(), SIGKILL) != 0) {
|
||||||
|
error.SetErrorToErrno();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
|
||||||
|
MemoryRegionInfo &range_info) {
|
||||||
|
|
||||||
|
if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
|
||||||
|
// We're done.
|
||||||
|
return Error("unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
Error error = PopulateMemoryRegionCache();
|
||||||
|
if (error.Fail()) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::addr_t prev_base_address = 0;
|
||||||
|
// FIXME start by finding the last region that is <= target address using
|
||||||
|
// binary search. Data is sorted.
|
||||||
|
// There can be a ton of regions on pthreads apps with lots of threads.
|
||||||
|
for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
|
||||||
|
++it) {
|
||||||
|
MemoryRegionInfo &proc_entry_info = it->first;
|
||||||
|
// Sanity check assumption that memory map entries are ascending.
|
||||||
|
assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
|
||||||
|
"descending memory map entries detected, unexpected");
|
||||||
|
prev_base_address = proc_entry_info.GetRange().GetRangeBase();
|
||||||
|
UNUSED_IF_ASSERT_DISABLED(prev_base_address);
|
||||||
|
// If the target address comes before this entry, indicate distance to next
|
||||||
|
// region.
|
||||||
|
if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
|
||||||
|
range_info.GetRange().SetRangeBase(load_addr);
|
||||||
|
range_info.GetRange().SetByteSize(
|
||||||
|
proc_entry_info.GetRange().GetRangeBase() - load_addr);
|
||||||
|
range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
return error;
|
||||||
|
} else if (proc_entry_info.GetRange().Contains(load_addr)) {
|
||||||
|
// The target address is within the memory region we're processing here.
|
||||||
|
range_info = proc_entry_info;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
// The target memory address comes somewhere after the region we just
|
||||||
|
// parsed.
|
||||||
|
}
|
||||||
|
// If we made it here, we didn't find an entry that contained the given
|
||||||
|
// address. Return the
|
||||||
|
// load_addr as start and the amount of bytes betwwen load address and the end
|
||||||
|
// of the memory as
|
||||||
|
// size.
|
||||||
|
range_info.GetRange().SetRangeBase(load_addr);
|
||||||
|
range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
|
||||||
|
range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::PopulateMemoryRegionCache() {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
// If our cache is empty, pull the latest. There should always be at least
|
||||||
|
// one memory region if memory region handling is supported.
|
||||||
|
if (!m_mem_region_cache.empty()) {
|
||||||
|
LLDB_LOG(log, "reusing {0} cached memory region entries",
|
||||||
|
m_mem_region_cache.size());
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct kinfo_vmentry *vm;
|
||||||
|
size_t count, i;
|
||||||
|
vm = kinfo_getvmmap(GetID(), &count);
|
||||||
|
if (vm == NULL) {
|
||||||
|
m_supports_mem_region = LazyBool::eLazyBoolNo;
|
||||||
|
Error error;
|
||||||
|
error.SetErrorString("not supported");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
MemoryRegionInfo info;
|
||||||
|
info.Clear();
|
||||||
|
info.GetRange().SetRangeBase(vm[i].kve_start);
|
||||||
|
info.GetRange().SetRangeEnd(vm[i].kve_end);
|
||||||
|
info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
|
||||||
|
|
||||||
|
if (vm[i].kve_protection & VM_PROT_READ)
|
||||||
|
info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
|
||||||
|
else
|
||||||
|
info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
|
||||||
|
if (vm[i].kve_protection & VM_PROT_WRITE)
|
||||||
|
info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
|
||||||
|
else
|
||||||
|
info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
|
||||||
|
if (vm[i].kve_protection & VM_PROT_EXECUTE)
|
||||||
|
info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
|
||||||
|
else
|
||||||
|
info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
|
||||||
|
if (vm[i].kve_path[0])
|
||||||
|
info.SetName(vm[i].kve_path);
|
||||||
|
|
||||||
|
m_mem_region_cache.emplace_back(
|
||||||
|
info, FileSpec(info.GetName().GetCString(), true));
|
||||||
|
}
|
||||||
|
free(vm);
|
||||||
|
|
||||||
|
if (m_mem_region_cache.empty()) {
|
||||||
|
// No entries after attempting to read them. This shouldn't happen.
|
||||||
|
// Assume we don't support map entries.
|
||||||
|
LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
|
||||||
|
"for memory region metadata retrieval");
|
||||||
|
m_supports_mem_region = LazyBool::eLazyBoolNo;
|
||||||
|
Error error;
|
||||||
|
error.SetErrorString("not supported");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
LLDB_LOG(log, "read {0} memory region entries from process {1}",
|
||||||
|
m_mem_region_cache.size(), GetID());
|
||||||
|
// We support memory retrieval, remember that.
|
||||||
|
m_supports_mem_region = LazyBool::eLazyBoolYes;
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions,
|
||||||
|
lldb::addr_t &addr) {
|
||||||
|
return Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) {
|
||||||
|
return Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
|
||||||
|
// punt on this for now
|
||||||
|
return LLDB_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
|
||||||
|
|
||||||
|
bool NativeProcessNetBSD::GetArchitecture(ArchSpec &arch) const {
|
||||||
|
arch = m_arch;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
|
||||||
|
bool hardware) {
|
||||||
|
if (hardware)
|
||||||
|
return Error("NativeProcessNetBSD does not support hardware breakpoints");
|
||||||
|
else
|
||||||
|
return SetSoftwareBreakpoint(addr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::GetSoftwareBreakpointTrapOpcode(
|
||||||
|
size_t trap_opcode_size_hint, size_t &actual_opcode_size,
|
||||||
|
const uint8_t *&trap_opcode_bytes) {
|
||||||
|
static const uint8_t g_i386_opcode[] = {0xCC};
|
||||||
|
|
||||||
|
switch (m_arch.GetMachine()) {
|
||||||
|
case llvm::Triple::x86:
|
||||||
|
case llvm::Triple::x86_64:
|
||||||
|
trap_opcode_bytes = g_i386_opcode;
|
||||||
|
actual_opcode_size = sizeof(g_i386_opcode);
|
||||||
|
return Error();
|
||||||
|
default:
|
||||||
|
assert(false && "CPU type not supported!");
|
||||||
|
return Error("CPU type not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
|
||||||
|
FileSpec &file_spec) {
|
||||||
|
return Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
|
||||||
|
lldb::addr_t &load_addr) {
|
||||||
|
load_addr = LLDB_INVALID_ADDRESS;
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::LaunchInferior(MainLoop &mainloop,
|
||||||
|
ProcessLaunchInfo &launch_info) {
|
||||||
|
Error error;
|
||||||
|
m_sigchld_handle = mainloop.RegisterSignal(
|
||||||
|
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error);
|
||||||
|
if (!m_sigchld_handle)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
SetState(eStateLaunching);
|
||||||
|
|
||||||
|
::pid_t pid = ProcessLauncherPosixFork()
|
||||||
|
.LaunchProcess(launch_info, error)
|
||||||
|
.GetProcessId();
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
|
||||||
|
// Wait for the child process to trap on its call to execve.
|
||||||
|
::pid_t wpid;
|
||||||
|
int status;
|
||||||
|
if ((wpid = waitpid(pid, &status, 0)) < 0) {
|
||||||
|
error.SetErrorToErrno();
|
||||||
|
LLDB_LOG(log, "waitpid for inferior failed with %s", error);
|
||||||
|
|
||||||
|
// Mark the inferior as invalid.
|
||||||
|
// FIXME this could really use a new state - eStateLaunchFailure. For now,
|
||||||
|
// using eStateInvalid.
|
||||||
|
SetState(StateType::eStateInvalid);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
assert(WIFSTOPPED(status) && (wpid == static_cast<::pid_t>(pid)) &&
|
||||||
|
"Could not sync with inferior process.");
|
||||||
|
|
||||||
|
LLDB_LOG(log, "inferior started, now in stopped state");
|
||||||
|
|
||||||
|
// Release the master terminal descriptor and pass it off to the
|
||||||
|
// NativeProcessNetBSD instance. Similarly stash the inferior pid.
|
||||||
|
m_terminal_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
|
||||||
|
m_pid = pid;
|
||||||
|
launch_info.SetProcessID(pid);
|
||||||
|
|
||||||
|
if (m_terminal_fd != -1) {
|
||||||
|
error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
|
||||||
|
if (error.Fail()) {
|
||||||
|
LLDB_LOG(log,
|
||||||
|
"inferior EnsureFDFlags failed for ensuring terminal "
|
||||||
|
"O_NONBLOCK setting: {0}",
|
||||||
|
error);
|
||||||
|
|
||||||
|
// Mark the inferior as invalid.
|
||||||
|
// FIXME this could really use a new state - eStateLaunchFailure. For
|
||||||
|
// now, using eStateInvalid.
|
||||||
|
SetState(StateType::eStateInvalid);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LLDB_LOG(log, "adding pid = {0}", pid);
|
||||||
|
|
||||||
|
ResolveProcessArchitecture(m_pid, m_arch);
|
||||||
|
|
||||||
|
/* Initialize threads */
|
||||||
|
struct ptrace_lwpinfo info = {};
|
||||||
|
error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
|
||||||
|
if (error.Fail()) {
|
||||||
|
SetState(StateType::eStateInvalid);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
while (info.pl_lwpid != 0) {
|
||||||
|
NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
|
||||||
|
thread_sp->SetStoppedBySignal(SIGSTOP);
|
||||||
|
error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
|
||||||
|
if (error.Fail()) {
|
||||||
|
SetState(StateType::eStateInvalid);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set process stopped */
|
||||||
|
SetState(StateType::eStateStopped);
|
||||||
|
|
||||||
|
if (error.Fail())
|
||||||
|
LLDB_LOG(log, "inferior launching failed {0}", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeProcessNetBSD::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid,
|
||||||
|
Error &error) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||||
|
|
||||||
|
m_sigchld_handle = mainloop.RegisterSignal(
|
||||||
|
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error);
|
||||||
|
if (!m_sigchld_handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error = ResolveProcessArchitecture(pid, m_arch);
|
||||||
|
if (!error.Success())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Set the architecture to the exe architecture.
|
||||||
|
LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
|
||||||
|
m_arch.GetArchitectureName());
|
||||||
|
|
||||||
|
m_pid = pid;
|
||||||
|
SetState(eStateAttaching);
|
||||||
|
|
||||||
|
Attach(pid, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeProcessNetBSD::SigchldHandler() {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||||
|
// Process all pending waitpid notifications.
|
||||||
|
int status;
|
||||||
|
::pid_t wait_pid = waitpid(GetID(), &status, WALLSIG | WNOHANG);
|
||||||
|
|
||||||
|
if (wait_pid == 0)
|
||||||
|
return; // We are done.
|
||||||
|
|
||||||
|
if (wait_pid == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Error error(errno, eErrorTypePOSIX);
|
||||||
|
LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exited = false;
|
||||||
|
int signal = 0;
|
||||||
|
int exit_status = 0;
|
||||||
|
const char *status_cstr = nullptr;
|
||||||
|
if (WIFSTOPPED(status)) {
|
||||||
|
signal = WSTOPSIG(status);
|
||||||
|
status_cstr = "STOPPED";
|
||||||
|
} else if (WIFEXITED(status)) {
|
||||||
|
exit_status = WEXITSTATUS(status);
|
||||||
|
status_cstr = "EXITED";
|
||||||
|
exited = true;
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
signal = WTERMSIG(status);
|
||||||
|
status_cstr = "SIGNALED";
|
||||||
|
if (wait_pid == static_cast<::pid_t>(GetID())) {
|
||||||
|
exited = true;
|
||||||
|
exit_status = -1;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
status_cstr = "(\?\?\?)";
|
||||||
|
|
||||||
|
LLDB_LOG(log,
|
||||||
|
"waitpid ({0}, &status, _) => pid = {1}, status = {2:x} "
|
||||||
|
"({3}), signal = {4}, exit_state = {5}",
|
||||||
|
GetID(), wait_pid, status, status_cstr, signal, exit_status);
|
||||||
|
|
||||||
|
if (exited)
|
||||||
|
MonitorExited(wait_pid, signal, exit_status);
|
||||||
|
else
|
||||||
|
MonitorCallback(wait_pid, signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
|
||||||
|
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_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);
|
||||||
|
|
||||||
|
auto thread_sp = std::make_shared<NativeThreadNetBSD>(this, thread_id);
|
||||||
|
m_threads.push_back(thread_sp);
|
||||||
|
return thread_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
::pid_t NativeProcessNetBSD::Attach(lldb::pid_t pid, Error &error) {
|
||||||
|
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
|
||||||
|
|
||||||
|
// Use a map to keep track of the threads which we have attached/need to
|
||||||
|
// attach.
|
||||||
|
Host::TidMap tids_to_attach;
|
||||||
|
if (pid <= 1) {
|
||||||
|
error.SetErrorToGenericError();
|
||||||
|
error.SetErrorString("Attaching to process 1 is not allowed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach to the requested process.
|
||||||
|
// An attach will cause the thread to stop with a SIGSTOP.
|
||||||
|
error = PtraceWrapper(PT_ATTACH, pid);
|
||||||
|
if (error.Fail())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
// Need to use WALLSIG otherwise we receive an error with errno=ECHLD
|
||||||
|
// At this point we should have a thread stopped if waitpid succeeds.
|
||||||
|
if ((status = waitpid(pid, NULL, WALLSIG)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
m_pid = pid;
|
||||||
|
|
||||||
|
/* Initialize threads */
|
||||||
|
struct ptrace_lwpinfo info = {};
|
||||||
|
error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
|
||||||
|
if (error.Fail()) {
|
||||||
|
SetState(StateType::eStateInvalid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while (info.pl_lwpid != 0) {
|
||||||
|
NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
|
||||||
|
thread_sp->SetStoppedBySignal(SIGSTOP);
|
||||||
|
error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
|
||||||
|
if (error.Fail()) {
|
||||||
|
SetState(StateType::eStateInvalid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let our process instance know the thread has stopped.
|
||||||
|
SetState(StateType::eStateStopped);
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
|
||||||
|
size_t &bytes_read) {
|
||||||
|
unsigned char *dst = static_cast<unsigned char *>(buf);
|
||||||
|
struct ptrace_io_desc io;
|
||||||
|
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_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;
|
||||||
|
|
||||||
|
Error error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
bytes_read = io.piod_len;
|
||||||
|
io.piod_len = size - bytes_read;
|
||||||
|
} while (bytes_read < size);
|
||||||
|
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
|
||||||
|
size_t size,
|
||||||
|
size_t &bytes_read) {
|
||||||
|
Error error = ReadMemory(addr, buf, size, bytes_read);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
|
||||||
|
size_t size, size_t &bytes_written) {
|
||||||
|
const unsigned char *src = static_cast<const unsigned char *>(buf);
|
||||||
|
Error error;
|
||||||
|
struct ptrace_io_desc io;
|
||||||
|
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_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 = (void *)(src + bytes_written);
|
||||||
|
io.piod_offs = (void *)(addr + bytes_written);
|
||||||
|
|
||||||
|
Error error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
bytes_written = io.piod_len;
|
||||||
|
io.piod_len = size - bytes_written;
|
||||||
|
} while (bytes_written < size);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
|
||||||
|
NativeProcessNetBSD::GetAuxvData() const {
|
||||||
|
/*
|
||||||
|
* ELF_AUX_ENTRIES is currently restricted to kernel
|
||||||
|
* (<sys/exec_elf.h> r. 1.155 specifies 15)
|
||||||
|
*
|
||||||
|
* ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
|
||||||
|
* information isn't needed.
|
||||||
|
*/
|
||||||
|
size_t auxv_size = 100 * sizeof(AuxInfo);
|
||||||
|
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> buf =
|
||||||
|
llvm::MemoryBuffer::getNewMemBuffer(auxv_size);
|
||||||
|
|
||||||
|
struct ptrace_io_desc io = {.piod_op = PIOD_READ_AUXV,
|
||||||
|
.piod_offs = 0,
|
||||||
|
.piod_addr = (void *)buf.get()->getBufferStart(),
|
||||||
|
.piod_len = auxv_size};
|
||||||
|
|
||||||
|
Error error = NativeProcessNetBSD::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 buf;
|
||||||
|
}
|
||||||
|
|
|
@ -39,8 +39,98 @@ class NativeProcessNetBSD : public NativeProcessProtocol {
|
||||||
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||||
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
|
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// NativeProcessProtocol Interface
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
Error Resume(const ResumeActionList &resume_actions) override;
|
||||||
|
|
||||||
|
Error Halt() override;
|
||||||
|
|
||||||
|
Error Detach() override;
|
||||||
|
|
||||||
|
Error Signal(int signo) override;
|
||||||
|
|
||||||
|
Error Kill() override;
|
||||||
|
|
||||||
|
Error GetMemoryRegionInfo(lldb::addr_t load_addr,
|
||||||
|
MemoryRegionInfo &range_info) override;
|
||||||
|
|
||||||
|
Error ReadMemory(lldb::addr_t addr, void *buf, size_t size,
|
||||||
|
size_t &bytes_read) override;
|
||||||
|
|
||||||
|
Error ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
|
||||||
|
size_t &bytes_read) override;
|
||||||
|
|
||||||
|
Error WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
|
||||||
|
size_t &bytes_written) override;
|
||||||
|
|
||||||
|
Error AllocateMemory(size_t size, uint32_t permissions,
|
||||||
|
lldb::addr_t &addr) override;
|
||||||
|
|
||||||
|
Error DeallocateMemory(lldb::addr_t addr) override;
|
||||||
|
|
||||||
|
lldb::addr_t GetSharedLibraryInfoAddress() override;
|
||||||
|
|
||||||
|
size_t UpdateThreads() override;
|
||||||
|
|
||||||
|
bool GetArchitecture(ArchSpec &arch) const override;
|
||||||
|
|
||||||
|
Error SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override;
|
||||||
|
|
||||||
|
Error GetLoadedModuleFileSpec(const char *module_path,
|
||||||
|
FileSpec &file_spec) override;
|
||||||
|
|
||||||
|
Error 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 Error PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
|
||||||
|
int data = 0, int *result = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// NativeProcessProtocol protected interface
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Error
|
||||||
|
GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint,
|
||||||
|
size_t &actual_opcode_size,
|
||||||
|
const uint8_t *&trap_opcode_bytes) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
MainLoop::SignalHandleUP m_sigchld_handle;
|
||||||
|
ArchSpec m_arch;
|
||||||
|
LazyBool m_supports_mem_region;
|
||||||
|
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Private Instance Methods
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
NativeProcessNetBSD();
|
NativeProcessNetBSD();
|
||||||
|
|
||||||
|
NativeThreadNetBSDSP AddThread(lldb::tid_t thread_id);
|
||||||
|
|
||||||
|
Error LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info);
|
||||||
|
void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Error &error);
|
||||||
|
|
||||||
|
void MonitorCallback(lldb::pid_t pid, int signal);
|
||||||
|
void MonitorExited(lldb::pid_t pid, int signal, int status);
|
||||||
|
void MonitorSIGSTOP(lldb::pid_t pid);
|
||||||
|
void MonitorSIGTRAP(lldb::pid_t pid);
|
||||||
|
void MonitorSignal(lldb::pid_t pid, int signal);
|
||||||
|
|
||||||
|
Error GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
|
||||||
|
Error FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread);
|
||||||
|
Error PopulateMemoryRegionCache();
|
||||||
|
void SigchldHandler();
|
||||||
|
|
||||||
|
::pid_t Attach(lldb::pid_t pid, Error &error);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace process_netbsd
|
} // namespace process_netbsd
|
||||||
|
|
|
@ -9,11 +9,58 @@
|
||||||
|
|
||||||
#include "NativeRegisterContextNetBSD.h"
|
#include "NativeRegisterContextNetBSD.h"
|
||||||
|
|
||||||
|
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||||
|
|
||||||
using namespace lldb_private;
|
using namespace lldb_private;
|
||||||
using namespace lldb_private::process_netbsd;
|
using namespace lldb_private::process_netbsd;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
NativeRegisterContextNetBSD::NativeRegisterContextNetBSD(
|
NativeRegisterContextNetBSD::NativeRegisterContextNetBSD(
|
||||||
NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx,
|
NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx,
|
||||||
RegisterInfoInterface *reg_info_interface_p)
|
RegisterInfoInterface *reg_info_interface_p)
|
||||||
: NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx,
|
: NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx,
|
||||||
reg_info_interface_p) {}
|
reg_info_interface_p) {}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::ReadGPR() {
|
||||||
|
void *buf = GetGPRBuffer();
|
||||||
|
if (!buf)
|
||||||
|
return Error("GPR buffer is NULL");
|
||||||
|
|
||||||
|
return DoReadGPR(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::WriteGPR() {
|
||||||
|
void *buf = GetGPRBuffer();
|
||||||
|
if (!buf)
|
||||||
|
return Error("GPR buffer is NULL");
|
||||||
|
|
||||||
|
return DoWriteGPR(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
|
||||||
|
return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
|
||||||
|
m_thread.GetID());
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::DoWriteGPR(void *buf) {
|
||||||
|
return NativeProcessNetBSD::PtraceWrapper(PT_SETREGS, GetProcessPid(), buf,
|
||||||
|
m_thread.GetID());
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
|
||||||
|
auto process_sp =
|
||||||
|
std::static_pointer_cast<NativeProcessNetBSD>(m_thread.GetProcess());
|
||||||
|
assert(process_sp);
|
||||||
|
return *process_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
::pid_t NativeRegisterContextNetBSD::GetProcessPid() {
|
||||||
|
NativeProcessNetBSD &process = GetProcess();
|
||||||
|
lldb::pid_t pid = process.GetID();
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,19 @@ public:
|
||||||
CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch,
|
CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch,
|
||||||
NativeThreadProtocol &native_thread,
|
NativeThreadProtocol &native_thread,
|
||||||
uint32_t concrete_frame_idx);
|
uint32_t concrete_frame_idx);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual Error ReadGPR();
|
||||||
|
virtual Error WriteGPR();
|
||||||
|
virtual void *GetGPRBuffer() { return nullptr; }
|
||||||
|
virtual size_t GetGPRSize() {
|
||||||
|
return GetRegisterInfoInterface().GetGPRSize();
|
||||||
|
}
|
||||||
|
virtual Error DoReadGPR(void *buf);
|
||||||
|
virtual Error DoWriteGPR(void *buf);
|
||||||
|
|
||||||
|
virtual NativeProcessNetBSD &GetProcess();
|
||||||
|
virtual ::pid_t GetProcessPid();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace process_netbsd
|
} // namespace process_netbsd
|
||||||
|
|
|
@ -0,0 +1,477 @@
|
||||||
|
//===-- NativeRegisterContextNetBSD_x86_64.cpp ---------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
|
||||||
|
#include "NativeRegisterContextNetBSD_x86_64.h"
|
||||||
|
|
||||||
|
#include "lldb/Core/RegisterValue.h"
|
||||||
|
#include "lldb/Host/HostInfo.h"
|
||||||
|
#include "lldb/Utility/DataBufferHeap.h"
|
||||||
|
#include "lldb/Utility/Error.h"
|
||||||
|
#include "lldb/Utility/Log.h"
|
||||||
|
|
||||||
|
#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
|
using namespace lldb_private;
|
||||||
|
using namespace lldb_private::process_netbsd;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Private namespace.
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// x86 64-bit general purpose registers.
|
||||||
|
static const uint32_t g_gpr_regnums_x86_64[] = {
|
||||||
|
lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64,
|
||||||
|
lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64,
|
||||||
|
lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64,
|
||||||
|
lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64,
|
||||||
|
lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64,
|
||||||
|
lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64,
|
||||||
|
lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64,
|
||||||
|
lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64,
|
||||||
|
lldb_r8d_x86_64, // Low 32 bits or r8
|
||||||
|
lldb_r9d_x86_64, // Low 32 bits or r9
|
||||||
|
lldb_r10d_x86_64, // Low 32 bits or r10
|
||||||
|
lldb_r11d_x86_64, // Low 32 bits or r11
|
||||||
|
lldb_r12d_x86_64, // Low 32 bits or r12
|
||||||
|
lldb_r13d_x86_64, // Low 32 bits or r13
|
||||||
|
lldb_r14d_x86_64, // Low 32 bits or r14
|
||||||
|
lldb_r15d_x86_64, // Low 32 bits or r15
|
||||||
|
lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64,
|
||||||
|
lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64,
|
||||||
|
lldb_r8w_x86_64, // Low 16 bits or r8
|
||||||
|
lldb_r9w_x86_64, // Low 16 bits or r9
|
||||||
|
lldb_r10w_x86_64, // Low 16 bits or r10
|
||||||
|
lldb_r11w_x86_64, // Low 16 bits or r11
|
||||||
|
lldb_r12w_x86_64, // Low 16 bits or r12
|
||||||
|
lldb_r13w_x86_64, // Low 16 bits or r13
|
||||||
|
lldb_r14w_x86_64, // Low 16 bits or r14
|
||||||
|
lldb_r15w_x86_64, // Low 16 bits or r15
|
||||||
|
lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64,
|
||||||
|
lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64,
|
||||||
|
lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64,
|
||||||
|
lldb_r8l_x86_64, // Low 8 bits or r8
|
||||||
|
lldb_r9l_x86_64, // Low 8 bits or r9
|
||||||
|
lldb_r10l_x86_64, // Low 8 bits or r10
|
||||||
|
lldb_r11l_x86_64, // Low 8 bits or r11
|
||||||
|
lldb_r12l_x86_64, // Low 8 bits or r12
|
||||||
|
lldb_r13l_x86_64, // Low 8 bits or r13
|
||||||
|
lldb_r14l_x86_64, // Low 8 bits or r14
|
||||||
|
lldb_r15l_x86_64, // Low 8 bits or r15
|
||||||
|
LLDB_INVALID_REGNUM // register sets need to end with this flag
|
||||||
|
};
|
||||||
|
static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
|
||||||
|
1 ==
|
||||||
|
k_num_gpr_registers_x86_64,
|
||||||
|
"g_gpr_regnums_x86_64 has wrong number of register infos");
|
||||||
|
|
||||||
|
// Number of register sets provided by this context.
|
||||||
|
enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 };
|
||||||
|
|
||||||
|
// Register sets for x86 64-bit.
|
||||||
|
static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
|
||||||
|
{"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
|
||||||
|
g_gpr_regnums_x86_64},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NativeRegisterContextNetBSD *
|
||||||
|
NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
|
||||||
|
const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
|
||||||
|
uint32_t concrete_frame_idx) {
|
||||||
|
return new NativeRegisterContextNetBSD_x86_64(target_arch, native_thread,
|
||||||
|
concrete_frame_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// NativeRegisterContextNetBSD_x86_64 members.
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static RegisterInfoInterface *
|
||||||
|
CreateRegisterInfoInterface(const ArchSpec &target_arch) {
|
||||||
|
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
|
||||||
|
"Register setting path assumes this is a 64-bit host");
|
||||||
|
// X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the
|
||||||
|
// x86_64 register context.
|
||||||
|
return new RegisterContextNetBSD_x86_64(target_arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
|
||||||
|
const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
|
||||||
|
uint32_t concrete_frame_idx)
|
||||||
|
: NativeRegisterContextNetBSD(native_thread, concrete_frame_idx,
|
||||||
|
CreateRegisterInfoInterface(target_arch)),
|
||||||
|
m_gpr_x86_64() {}
|
||||||
|
|
||||||
|
// CONSIDER after local and llgs debugging are merged, register set support can
|
||||||
|
// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
|
||||||
|
uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
|
||||||
|
uint32_t sets = 0;
|
||||||
|
for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
|
||||||
|
if (GetSetForNativeRegNum(set_index) != -1)
|
||||||
|
++sets;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RegisterSet *
|
||||||
|
NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
|
||||||
|
switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
|
||||||
|
case llvm::Triple::x86_64:
|
||||||
|
return &g_reg_sets_x86_64[set_index];
|
||||||
|
default:
|
||||||
|
assert(false && "Unhandled target architecture.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
|
||||||
|
int reg_num) const {
|
||||||
|
if (reg_num < lldb_fctrl_x86_64)
|
||||||
|
return GPRegSet;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
|
||||||
|
switch (set) {
|
||||||
|
case GPRegSet:
|
||||||
|
ReadGPR();
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
|
||||||
|
switch (set) {
|
||||||
|
case GPRegSet:
|
||||||
|
WriteGPR();
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::ReadRegister(
|
||||||
|
const RegisterInfo *reg_info, RegisterValue ®_value) {
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
if (!reg_info) {
|
||||||
|
error.SetErrorString("reg_info NULL");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
|
||||||
|
if (reg == LLDB_INVALID_REGNUM) {
|
||||||
|
// This is likely an internal register for lldb use only and should not be
|
||||||
|
// directly queried.
|
||||||
|
error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
|
||||||
|
"register, cannot read directly",
|
||||||
|
reg_info->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set = GetSetForNativeRegNum(reg);
|
||||||
|
if (set == -1) {
|
||||||
|
// This is likely an internal register for lldb use only and should not be
|
||||||
|
// directly queried.
|
||||||
|
error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
|
||||||
|
reg_info->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReadRegisterSet(set) != 0) {
|
||||||
|
// This is likely an internal register for lldb use only and should not be
|
||||||
|
// directly queried.
|
||||||
|
error.SetErrorStringWithFormat(
|
||||||
|
"reading register set for register \"%s\" failed", reg_info->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case lldb_rax_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX];
|
||||||
|
break;
|
||||||
|
case lldb_rbx_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX];
|
||||||
|
break;
|
||||||
|
case lldb_rcx_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX];
|
||||||
|
break;
|
||||||
|
case lldb_rdx_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX];
|
||||||
|
break;
|
||||||
|
case lldb_rdi_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI];
|
||||||
|
break;
|
||||||
|
case lldb_rsi_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI];
|
||||||
|
break;
|
||||||
|
case lldb_rbp_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP];
|
||||||
|
break;
|
||||||
|
case lldb_rsp_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP];
|
||||||
|
break;
|
||||||
|
case lldb_r8_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8];
|
||||||
|
break;
|
||||||
|
case lldb_r9_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9];
|
||||||
|
break;
|
||||||
|
case lldb_r10_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10];
|
||||||
|
break;
|
||||||
|
case lldb_r11_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11];
|
||||||
|
break;
|
||||||
|
case lldb_r12_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12];
|
||||||
|
break;
|
||||||
|
case lldb_r13_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13];
|
||||||
|
break;
|
||||||
|
case lldb_r14_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14];
|
||||||
|
break;
|
||||||
|
case lldb_r15_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15];
|
||||||
|
break;
|
||||||
|
case lldb_rip_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP];
|
||||||
|
break;
|
||||||
|
case lldb_rflags_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS];
|
||||||
|
break;
|
||||||
|
case lldb_cs_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS];
|
||||||
|
break;
|
||||||
|
case lldb_fs_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS];
|
||||||
|
break;
|
||||||
|
case lldb_gs_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS];
|
||||||
|
break;
|
||||||
|
case lldb_ss_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS];
|
||||||
|
break;
|
||||||
|
case lldb_ds_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS];
|
||||||
|
break;
|
||||||
|
case lldb_es_x86_64:
|
||||||
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::WriteRegister(
|
||||||
|
const RegisterInfo *reg_info, const RegisterValue ®_value) {
|
||||||
|
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
if (!reg_info) {
|
||||||
|
error.SetErrorString("reg_info NULL");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
|
||||||
|
if (reg == LLDB_INVALID_REGNUM) {
|
||||||
|
// This is likely an internal register for lldb use only and should not be
|
||||||
|
// directly queried.
|
||||||
|
error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
|
||||||
|
"register, cannot read directly",
|
||||||
|
reg_info->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set = GetSetForNativeRegNum(reg);
|
||||||
|
if (set == -1) {
|
||||||
|
// This is likely an internal register for lldb use only and should not be
|
||||||
|
// directly queried.
|
||||||
|
error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
|
||||||
|
reg_info->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReadRegisterSet(set) != 0) {
|
||||||
|
// This is likely an internal register for lldb use only and should not be
|
||||||
|
// directly queried.
|
||||||
|
error.SetErrorStringWithFormat(
|
||||||
|
"reading register set for register \"%s\" failed", reg_info->name);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case lldb_rax_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rbx_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rcx_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rdx_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rdi_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rsi_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rbp_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rsp_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r8_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r9_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r10_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r11_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r12_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r13_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r14_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_r15_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rip_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_rflags_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_cs_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_fs_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_gs_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_ss_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_ds_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_es_x86_64:
|
||||||
|
m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WriteRegisterSet(set) != 0)
|
||||||
|
error.SetErrorStringWithFormat("failed to write register set");
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
|
||||||
|
lldb::DataBufferSP &data_sp) {
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
|
||||||
|
if (!data_sp) {
|
||||||
|
error.SetErrorStringWithFormat(
|
||||||
|
"failed to allocate DataBufferHeap instance of size %" PRIu64,
|
||||||
|
REG_CONTEXT_SIZE);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = ReadGPR();
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
uint8_t *dst = data_sp->GetBytes();
|
||||||
|
if (dst == nullptr) {
|
||||||
|
error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
|
||||||
|
" returned a null pointer",
|
||||||
|
REG_CONTEXT_SIZE);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
|
||||||
|
dst += GetRegisterInfoInterface().GetGPRSize();
|
||||||
|
|
||||||
|
RegisterValue value((uint64_t)-1);
|
||||||
|
const RegisterInfo *reg_info =
|
||||||
|
GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
|
||||||
|
if (reg_info == nullptr)
|
||||||
|
reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
|
||||||
|
const lldb::DataBufferSP &data_sp) {
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
if (!data_sp) {
|
||||||
|
error.SetErrorStringWithFormat(
|
||||||
|
"NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided",
|
||||||
|
__FUNCTION__);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
|
||||||
|
error.SetErrorStringWithFormat(
|
||||||
|
"NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched "
|
||||||
|
"data size, expected %" PRIu64 ", actual %" PRIu64,
|
||||||
|
__FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *src = data_sp->GetBytes();
|
||||||
|
if (src == nullptr) {
|
||||||
|
error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s "
|
||||||
|
"DataBuffer::GetBytes() returned a null "
|
||||||
|
"pointer",
|
||||||
|
__FUNCTION__);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize());
|
||||||
|
|
||||||
|
error = WriteGPR();
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
src += GetRegisterInfoInterface().GetGPRSize();
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(__x86_64__)
|
|
@ -0,0 +1,70 @@
|
||||||
|
//===-- NativeRegisterContextNetBSD_x86_64.h --------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
|
||||||
|
#ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
|
||||||
|
#define lldb_NativeRegisterContextNetBSD_x86_64_h
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <machine/reg.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
|
||||||
|
#include "Plugins/Process/Utility/RegisterContext_x86.h"
|
||||||
|
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
|
||||||
|
|
||||||
|
namespace lldb_private {
|
||||||
|
namespace process_netbsd {
|
||||||
|
|
||||||
|
class NativeProcessNetBSD;
|
||||||
|
|
||||||
|
class NativeRegisterContextNetBSD_x86_64 : public NativeRegisterContextNetBSD {
|
||||||
|
public:
|
||||||
|
NativeRegisterContextNetBSD_x86_64(const ArchSpec &target_arch,
|
||||||
|
NativeThreadProtocol &native_thread,
|
||||||
|
uint32_t concrete_frame_idx);
|
||||||
|
uint32_t GetRegisterSetCount() const override;
|
||||||
|
|
||||||
|
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
|
||||||
|
|
||||||
|
Error ReadRegister(const RegisterInfo *reg_info,
|
||||||
|
RegisterValue ®_value) override;
|
||||||
|
|
||||||
|
Error WriteRegister(const RegisterInfo *reg_info,
|
||||||
|
const RegisterValue ®_value) override;
|
||||||
|
|
||||||
|
Error ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
|
||||||
|
|
||||||
|
Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void *GetGPRBuffer() override { return &m_gpr_x86_64; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Private member types.
|
||||||
|
enum { GPRegSet };
|
||||||
|
|
||||||
|
// Private member variables.
|
||||||
|
struct reg m_gpr_x86_64;
|
||||||
|
|
||||||
|
int GetSetForNativeRegNum(int reg_num) const;
|
||||||
|
|
||||||
|
int ReadRegisterSet(uint32_t set);
|
||||||
|
int WriteRegisterSet(uint32_t set);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace process_netbsd
|
||||||
|
} // namespace lldb_private
|
||||||
|
|
||||||
|
#endif // #ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
|
||||||
|
|
||||||
|
#endif // defined(__x86_64__)
|
|
@ -12,10 +12,131 @@
|
||||||
|
|
||||||
#include "NativeProcessNetBSD.h"
|
#include "NativeProcessNetBSD.h"
|
||||||
|
|
||||||
|
#include "Plugins/Process/POSIX/CrashReason.h"
|
||||||
|
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
|
||||||
|
#include "lldb/Core/RegisterValue.h"
|
||||||
|
#include "lldb/Core/State.h"
|
||||||
|
|
||||||
using namespace lldb;
|
using namespace lldb;
|
||||||
using namespace lldb_private;
|
using namespace lldb_private;
|
||||||
using namespace lldb_private::process_netbsd;
|
using namespace lldb_private::process_netbsd;
|
||||||
|
|
||||||
NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD *process,
|
NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD *process,
|
||||||
lldb::tid_t tid)
|
lldb::tid_t tid)
|
||||||
: NativeThreadProtocol(process, tid) {}
|
: NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
|
||||||
|
m_stop_info(), m_reg_context_sp(), m_stop_description() {}
|
||||||
|
|
||||||
|
void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
|
||||||
|
const siginfo_t *info) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
|
||||||
|
LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
|
||||||
|
|
||||||
|
SetStopped();
|
||||||
|
|
||||||
|
m_stop_info.reason = StopReason::eStopReasonSignal;
|
||||||
|
m_stop_info.details.signal.signo = signo;
|
||||||
|
|
||||||
|
m_stop_description.clear();
|
||||||
|
if (info) {
|
||||||
|
switch (signo) {
|
||||||
|
case SIGSEGV:
|
||||||
|
case SIGBUS:
|
||||||
|
case SIGFPE:
|
||||||
|
case SIGILL:
|
||||||
|
const auto reason = GetCrashReason(*info);
|
||||||
|
m_stop_description = GetCrashReasonString(reason, *info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeThreadNetBSD::SetStoppedByBreakpoint() {
|
||||||
|
SetStopped();
|
||||||
|
m_stop_info.reason = StopReason::eStopReasonBreakpoint;
|
||||||
|
m_stop_info.details.signal.signo = SIGTRAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeThreadNetBSD::SetStopped() {
|
||||||
|
const StateType new_state = StateType::eStateStopped;
|
||||||
|
m_state = new_state;
|
||||||
|
m_stop_description.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeThreadNetBSD::SetRunning() {
|
||||||
|
m_state = StateType::eStateRunning;
|
||||||
|
m_stop_info.reason = StopReason::eStopReasonNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NativeThreadNetBSD::GetName() { return std::string(""); }
|
||||||
|
|
||||||
|
lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
|
||||||
|
|
||||||
|
bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
|
||||||
|
std::string &description) {
|
||||||
|
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeRegisterContextSP NativeThreadNetBSD::GetRegisterContext() {
|
||||||
|
// Return the register context if we already created it.
|
||||||
|
if (m_reg_context_sp)
|
||||||
|
return m_reg_context_sp;
|
||||||
|
|
||||||
|
NativeProcessProtocolSP m_process_sp = m_process_wp.lock();
|
||||||
|
if (!m_process_sp)
|
||||||
|
return NativeRegisterContextSP();
|
||||||
|
|
||||||
|
ArchSpec target_arch;
|
||||||
|
if (!m_process_sp->GetArchitecture(target_arch))
|
||||||
|
return NativeRegisterContextSP();
|
||||||
|
|
||||||
|
const uint32_t concrete_frame_idx = 0;
|
||||||
|
m_reg_context_sp.reset(
|
||||||
|
NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
|
||||||
|
target_arch, *this, concrete_frame_idx));
|
||||||
|
|
||||||
|
return m_reg_context_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
|
||||||
|
uint32_t watch_flags, bool hardware) {
|
||||||
|
return Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
|
||||||
|
return Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
|
||||||
|
size_t size) {
|
||||||
|
return Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
|
||||||
|
return Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,45 @@ class NativeThreadNetBSD : public NativeThreadProtocol {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NativeThreadNetBSD(NativeProcessNetBSD *process, lldb::tid_t tid);
|
NativeThreadNetBSD(NativeProcessNetBSD *process, lldb::tid_t tid);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// NativeThreadProtocol Interface
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
std::string GetName() override;
|
||||||
|
|
||||||
|
lldb::StateType GetState() override;
|
||||||
|
|
||||||
|
bool GetStopReason(ThreadStopInfo &stop_info,
|
||||||
|
std::string &description) override;
|
||||||
|
|
||||||
|
NativeRegisterContextSP GetRegisterContext() override;
|
||||||
|
|
||||||
|
Error SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
|
||||||
|
bool hardware) override;
|
||||||
|
|
||||||
|
Error RemoveWatchpoint(lldb::addr_t addr) override;
|
||||||
|
|
||||||
|
Error SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
|
||||||
|
|
||||||
|
Error RemoveHardwareBreakpoint(lldb::addr_t addr) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Interface for friend classes
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
|
||||||
|
void SetStoppedByBreakpoint();
|
||||||
|
void SetStopped();
|
||||||
|
void SetRunning();
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Member Variables
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
lldb::StateType m_state;
|
||||||
|
ThreadStopInfo m_stop_info;
|
||||||
|
NativeRegisterContextSP m_reg_context_sp;
|
||||||
|
std::string m_stop_description;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
|
typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
|
||||||
|
|
Loading…
Reference in New Issue