Battery of NetBSD support improvements

Summary:
Include initial support for:
 - single step mode (PT_STEP)
 - single step trap handling (TRAP_TRACE)
 - exec() trap (TRAP_EXEC)
 - add placeholder interfaces for FPR
 - initial code for NetBSD core(5) files
 - minor tweaks

While there improve style of altered elf-core/ files.

This code raises the number of passing tests on NetBSD to around 50% (600+/1200+).

The introduced code is subject to improve afterwards for additional features and bug fixes.

Sponsored by <The NetBSD Foundation>

Reviewers: labath, joerg, emaste, kettenis

Reviewed By: labath

Subscribers: srhines, #lldb

Tags: #lldb

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

llvm-svn: 299109
This commit is contained in:
Kamil Rytarowski 2017-03-30 20:25:29 +00:00
parent 89653dfd2a
commit 3eef2b5e96
12 changed files with 189 additions and 55 deletions

View File

@ -679,7 +679,7 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path,
sigemptyset(&no_signals);
sigfillset(&all_signals);
::posix_spawnattr_setsigmask(&attr, &no_signals);
#if defined(__linux__) || defined(__FreeBSD__)
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
::posix_spawnattr_setsigdefault(&attr, &no_signals);
#else
::posix_spawnattr_setsigdefault(&attr, &all_signals);

View File

@ -379,12 +379,13 @@ bool DYLDRendezvous::RemoveSOEntries() {
}
bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
// On Linux the executable is indicated by an empty path in the entry. On
// FreeBSD and on Android it is the full path to the executable.
// On some systes the executable is indicated by an empty path in the entry.
// On others it is the full path to the executable.
auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
switch (triple.getOS()) {
case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
return entry.file_spec == m_exe_file_spec;
case llvm::Triple::Linux:
if (triple.isAndroid())

View File

@ -235,6 +235,24 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
}
SetState(StateType::eStateStopped, true);
break;
case TRAP_TRACE:
for (const auto &thread_sp : m_threads) {
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByTrace();
}
SetState(StateType::eStateStopped, true);
break;
case TRAP_EXEC: {
Error error = ReinitializeThreads();
if (error.Fail()) {
SetState(StateType::eStateInvalid);
return;
}
// Let our delegate know we have just exec'd.
NotifyDidExec();
SetState(StateType::eStateStopped, true);
} break;
}
}
}
@ -389,11 +407,13 @@ Error NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
return Error();
}
Error 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);
error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(), (void *)1,
action->signal);
if (!error.Success())
return error;
for (const auto &thread_sp : m_threads) {
@ -403,7 +423,15 @@ Error NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
break;
}
case eStateStepping:
return Error("Not implemented");
// Run the thread, possibly feeding it the signal.
error = NativeProcessNetBSD::PtraceWrapper(PT_STEP, GetID(), (void *)1,
action->signal);
if (!error.Success())
return error;
for (const auto &thread_sp : m_threads) {
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStepping();
}
SetState(eStateStepping, true);
break;
case eStateSuspended:
@ -732,22 +760,11 @@ Error NativeProcessNetBSD::LaunchInferior(MainLoop &mainloop,
ResolveProcessArchitecture(m_pid, m_arch);
/* Initialize threads */
struct ptrace_lwpinfo info = {};
error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
error = ReinitializeThreads();
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);
@ -850,9 +867,6 @@ NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
::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.");
@ -874,21 +888,11 @@ NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
m_pid = pid;
/* Initialize threads */
struct ptrace_lwpinfo info = {};
error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
error = ReinitializeThreads();
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);
@ -989,3 +993,26 @@ NativeProcessNetBSD::GetAuxvData() const {
return buf;
}
Error NativeProcessNetBSD::ReinitializeThreads() {
// Clear old threads
m_threads.clear();
// Initialize new thread
struct ptrace_lwpinfo info = {};
Error error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info));
if (error.Fail()) {
return error;
}
// Reinitialize from scratch threads and register them in process
while (info.pl_lwpid != 0) {
NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
thread_sp->SetStoppedByExec();
error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info));
if (error.Fail()) {
return error;
}
}
return error;
}

View File

@ -131,6 +131,8 @@ private:
void SigchldHandler();
::pid_t Attach(lldb::pid_t pid, Error &error);
Error ReinitializeThreads();
};
} // namespace process_netbsd

View File

@ -41,6 +41,22 @@ Error NativeRegisterContextNetBSD::WriteGPR() {
return DoWriteGPR(buf);
}
Error NativeRegisterContextNetBSD::ReadFPR() {
void *buf = GetFPRBuffer();
if (!buf)
return Error("FPR buffer is NULL");
return DoReadFPR(buf);
}
Error NativeRegisterContextNetBSD::WriteFPR() {
void *buf = GetFPRBuffer();
if (!buf)
return Error("FPR buffer is NULL");
return DoWriteFPR(buf);
}
Error NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
m_thread.GetID());
@ -51,6 +67,16 @@ Error NativeRegisterContextNetBSD::DoWriteGPR(void *buf) {
m_thread.GetID());
}
Error NativeRegisterContextNetBSD::DoReadFPR(void *buf) {
return NativeProcessNetBSD::PtraceWrapper(PT_GETFPREGS, GetProcessPid(), buf,
m_thread.GetID());
}
Error NativeRegisterContextNetBSD::DoWriteFPR(void *buf) {
return NativeProcessNetBSD::PtraceWrapper(PT_SETFPREGS, GetProcessPid(), buf,
m_thread.GetID());
}
NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
auto process_sp =
std::static_pointer_cast<NativeProcessNetBSD>(m_thread.GetProcess());

View File

@ -37,13 +37,24 @@ public:
protected:
virtual Error ReadGPR();
virtual Error WriteGPR();
virtual Error ReadFPR();
virtual Error WriteFPR();
virtual void *GetGPRBuffer() { return nullptr; }
virtual size_t GetGPRSize() {
return GetRegisterInfoInterface().GetGPRSize();
}
virtual void *GetFPRBuffer() { return nullptr; }
virtual size_t GetFPRSize() { return 0; }
virtual Error DoReadGPR(void *buf);
virtual Error DoWriteGPR(void *buf);
virtual Error DoReadFPR(void *buf);
virtual Error DoWriteFPR(void *buf);
virtual NativeProcessNetBSD &GetProcess();
virtual ::pid_t GetProcessPid();
};

View File

@ -154,6 +154,9 @@ int NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
case GPRegSet:
ReadGPR();
return 0;
case FPRegSet:
ReadFPR();
return 0;
default:
break;
}
@ -164,6 +167,9 @@ int NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
case GPRegSet:
WriteGPR();
return 0;
case FPRegSet:
WriteFPR();
return 0;
default:
break;
}

View File

@ -48,13 +48,15 @@ public:
protected:
void *GetGPRBuffer() override { return &m_gpr_x86_64; }
void *GetFPRBuffer() override { return &m_fpr_x86_64; }
private:
// Private member types.
enum { GPRegSet };
enum { GPRegSet, FPRegSet };
// Private member variables.
struct reg m_gpr_x86_64;
struct fpreg m_fpr_x86_64;
int GetSetForNativeRegNum(int reg_num) const;

View File

@ -56,6 +56,18 @@ void NativeThreadNetBSD::SetStoppedByBreakpoint() {
m_stop_info.details.signal.signo = SIGTRAP;
}
void NativeThreadNetBSD::SetStoppedByTrace() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonTrace;
m_stop_info.details.signal.signo = SIGTRAP;
}
void NativeThreadNetBSD::SetStoppedByExec() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonExec;
m_stop_info.details.signal.signo = SIGTRAP;
}
void NativeThreadNetBSD::SetStopped() {
const StateType new_state = StateType::eStateStopped;
m_state = new_state;
@ -67,6 +79,11 @@ void NativeThreadNetBSD::SetRunning() {
m_stop_info.reason = StopReason::eStopReasonNone;
}
void NativeThreadNetBSD::SetStepping() {
m_state = StateType::eStateStepping;
m_stop_info.reason = StopReason::eStopReasonNone;
}
std::string NativeThreadNetBSD::GetName() { return std::string(""); }
lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }

View File

@ -51,8 +51,11 @@ private:
void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
void SetStoppedByBreakpoint();
void SetStoppedByTrace();
void SetStoppedByExec();
void SetStopped();
void SetRunning();
void SetStepping();
// ---------------------------------------------------------------------
// Member Variables

View File

@ -62,8 +62,8 @@ lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp,
// to ignore possible presence of the header extension.
const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr);
auto data_sp =
DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), header_size, 0);
auto data_sp = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(),
header_size, 0);
if (data_sp && data_sp->GetByteSize() == header_size &&
elf::ELFHeader::MagicBytesMatch(data_sp->GetBytes())) {
elf::ELFHeader elf_header;
@ -223,7 +223,7 @@ Error ProcessElfCore::DoLoadCore() {
bool siginfo_signal_found = false;
bool prstatus_signal_found = false;
// Check we found a signal in a SIGINFO note.
for (const auto &thread_data: m_thread_data) {
for (const auto &thread_data : m_thread_data) {
if (thread_data.signo != 0)
siginfo_signal_found = true;
if (thread_data.prstatus_sig != 0)
@ -233,7 +233,7 @@ Error ProcessElfCore::DoLoadCore() {
// If we don't have signal from SIGINFO use the signal from each threads
// PRSTATUS note.
if (prstatus_signal_found) {
for (auto &thread_data: m_thread_data)
for (auto &thread_data : m_thread_data)
thread_data.signo = thread_data.prstatus_sig;
} else if (m_thread_data.size() > 0) {
// If all else fails force the first thread to be SIGSTOP
@ -449,6 +449,11 @@ enum {
};
}
namespace NETBSD {
enum { NT_PROCINFO = 1, NT_AUXV, NT_AMD64_REGS = 33, NT_AMD64_FPREGS = 35 };
}
// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
static void ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
ArchSpec &arch) {
@ -485,13 +490,23 @@ static void ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) {
thread_data.name = data.GetCStr(&offset, 20);
}
static void ParseOpenBSDProcInfo(ThreadData &thread_data, DataExtractor &data)
{
static void ParseNetBSDProcInfo(ThreadData &thread_data, DataExtractor &data) {
lldb::offset_t offset = 0;
int version = data.GetU32(&offset);
if (version != 1)
return;
return;
offset += 4;
thread_data.signo = data.GetU32(&offset);
}
static void ParseOpenBSDProcInfo(ThreadData &thread_data, DataExtractor &data) {
lldb::offset_t offset = 0;
int version = data.GetU32(&offset);
if (version != 1)
return;
offset += 4;
thread_data.signo = data.GetU32(&offset);
@ -585,23 +600,38 @@ Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
default:
break;
}
} else if (note.n_name.substr(0, 11) == "NetBSD-CORE") {
// NetBSD per-thread information is stored in notes named
// "NetBSD-CORE@nnn" so match on the initial part of the string.
m_os = llvm::Triple::NetBSD;
if (note.n_type == NETBSD::NT_PROCINFO) {
ParseNetBSDProcInfo(*thread_data, note_data);
} else if (note.n_type == NETBSD::NT_AUXV) {
m_auxv = DataExtractor(note_data);
} else if (arch.GetMachine() == llvm::Triple::x86_64 &&
note.n_type == NETBSD::NT_AMD64_REGS) {
thread_data->gpregset = note_data;
} else if (arch.GetMachine() == llvm::Triple::x86_64 &&
note.n_type == NETBSD::NT_AMD64_FPREGS) {
thread_data->fpregset = note_data;
}
} else if (note.n_name.substr(0, 7) == "OpenBSD") {
// OpenBSD per-thread information is stored in notes named
// "OpenBSD@nnn" so match on the initial part of the string.
m_os = llvm::Triple::OpenBSD;
switch (note.n_type) {
case NT_OPENBSD_PROCINFO:
ParseOpenBSDProcInfo(*thread_data, note_data);
break;
ParseOpenBSDProcInfo(*thread_data, note_data);
break;
case NT_OPENBSD_AUXV:
m_auxv = DataExtractor(note_data);
break;
m_auxv = DataExtractor(note_data);
break;
case NT_OPENBSD_REGS:
thread_data->gpregset = note_data;
break;
thread_data->gpregset = note_data;
break;
case NT_OPENBSD_FPREGS:
thread_data->fpregset = note_data;
break;
thread_data->fpregset = note_data;
break;
}
} else if (note.n_name == "CORE") {
switch (note.n_type) {

View File

@ -21,6 +21,7 @@
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
#include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
@ -112,6 +113,17 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
break;
}
case llvm::Triple::NetBSD: {
switch (arch.GetMachine()) {
case llvm::Triple::x86_64:
reg_interface = new RegisterContextNetBSD_x86_64(arch);
break;
default:
break;
}
break;
}
case llvm::Triple::Linux: {
switch (arch.GetMachine()) {
case llvm::Triple::arm:
@ -144,8 +156,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
reg_interface = new RegisterInfoPOSIX_arm(arch);
break;
case llvm::Triple::x86:
reg_interface = new RegisterContextOpenBSD_i386(arch);
break;
reg_interface = new RegisterContextOpenBSD_i386(arch);
break;
case llvm::Triple::x86_64:
reg_interface = new RegisterContextOpenBSD_x86_64(arch);
break;
@ -260,7 +272,6 @@ Error ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch) {
pr_cstime.tv_sec = data.GetPointer(&offset);
pr_cstime.tv_usec = data.GetPointer(&offset);
return error;
}
@ -317,9 +328,7 @@ Error ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) {
//----------------------------------------------------------------
// Parse SIGINFO from NOTE entry
//----------------------------------------------------------------
ELFLinuxSigInfo::ELFLinuxSigInfo() {
memset(this, 0, sizeof(ELFLinuxSigInfo));
}
ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(this, 0, sizeof(ELFLinuxSigInfo)); }
Error ELFLinuxSigInfo::Parse(DataExtractor &data, const ArchSpec &arch) {
Error error;