NativeProcessNetBSD.cpp revision 360784
114331Speter//===-- NativeProcessNetBSD.cpp ------------------------------- -*- C++ -*-===// 214456Ssos// 314331Speter// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 414331Speter// See https://llvm.org/LICENSE.txt for license information. 514331Speter// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 614331Speter// 714331Speter//===----------------------------------------------------------------------===// 814331Speter 9111798Sdes#include "NativeProcessNetBSD.h" 1014331Speter 1114331Speter#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" 1214331Speter#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 1314331Speter#include "lldb/Host/HostProcess.h" 1414331Speter#include "lldb/Host/common/NativeRegisterContext.h" 1597748Sschweikh#include "lldb/Host/posix/ProcessLauncherPosixFork.h" 1614331Speter#include "lldb/Target/Process.h" 1714331Speter#include "lldb/Utility/State.h" 1814331Speter#include "llvm/Support/Errno.h" 1914331Speter 2014331Speter// System includes - They have to be included after framework includes because 2114331Speter// they define some macros which collide with variable names in other modules 2214331Speter// clang-format off 2314331Speter#include <sys/types.h> 2414331Speter#include <sys/ptrace.h> 2514331Speter#include <sys/sysctl.h> 2614331Speter#include <sys/wait.h> 2714331Speter#include <uvm/uvm_prot.h> 2814331Speter#include <elf.h> 29115705Sobrien#include <util.h> 30115705Sobrien// clang-format on 31115705Sobrien 3214331Speterusing namespace lldb; 3348303Speterusing namespace lldb_private; 34123956Sbdeusing namespace lldb_private::process_netbsd; 35177785Skibusing namespace llvm; 3614331Speter 3739154Sjdp// Simple helper function to ensure flags are enabled on the given file 3814456Ssos// descriptor. 39123956Sbdestatic Status EnsureFDFlags(int fd, int flags) { 4084811Sjhb Status error; 4176166Smarkm 42123956Sbde int status = fcntl(fd, F_GETFL); 4376827Salfred if (status == -1) { 4476166Smarkm error.SetErrorToErrno(); 4514331Speter return error; 46102814Siedowse } 4776166Smarkm 4876166Smarkm if (fcntl(fd, F_SETFL, status | flags) == -1) { 49103050Speter error.SetErrorToErrno(); 50161310Snetchild return error; 5176166Smarkm } 5214331Speter 53123956Sbde return error; 54123956Sbde} 55123956Sbde 56123956Sbde// Public Static Methods 57123956Sbde 5814331Speterllvm::Expected<std::unique_ptr<NativeProcessProtocol>> 59123956SbdeNativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, 6014331Speter NativeDelegate &native_delegate, 61189362Sdchagin MainLoop &mainloop) const { 62103050Speter Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 63138126Sdas 6414331Speter Status status; 6514331Speter ::pid_t pid = ProcessLauncherPosixFork() 6668583Smarcel .LaunchProcess(launch_info, status) 67218658Sdchagin .GetProcessId(); 68191741Sdchagin LLDB_LOG(log, "pid = {0:x}", pid); 69112716Sjhb if (status.Fail()) { 70189362Sdchagin LLDB_LOG(log, "failed to launch process: {0}", status); 7168806Sgallatin return status.ToError(); 7264929Smarcel } 7314331Speter 7460058Speter // Wait for the child process to trap on its call to execve. 7560058Speter int wstatus; 7654122Smarcel ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); 7754122Smarcel assert(wpid == pid); 7859663Sdillon (void)wpid; 7959663Sdillon if (!WIFSTOPPED(wstatus)) { 8059663Sdillon LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", 8159663Sdillon WaitStatus::Decode(wstatus)); 8259663Sdillon return llvm::make_error<StringError>("Could not sync with inferior process", 8359663Sdillon llvm::inconvertibleErrorCode()); 8483278Smarcel } 8583278Smarcel LLDB_LOG(log, "inferior started, now in stopped state"); 8683278Smarcel 8783278Smarcel ProcessInstanceInfo Info; 8883278Smarcel if (!Host::GetProcessInfo(pid, Info)) { 8983278Smarcel return llvm::make_error<StringError>("Cannot get process architecture", 9083278Smarcel llvm::inconvertibleErrorCode()); 9183278Smarcel } 9283278Smarcel 93219609Sdchagin // Set the architecture to the exe architecture. 94219609Sdchagin LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, 9554122Smarcel Info.GetArchitecture().GetArchitectureName()); 9654122Smarcel 9754122Smarcel std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD( 9854122Smarcel pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, 9954122Smarcel Info.GetArchitecture(), mainloop)); 10078161Speter 101158311Sambrisko // Enable event reporting 10254122Smarcel ptrace_event_t events; 10392765Salfred status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events)); 10493074Sbde if (status.Fail()) 10592765Salfred return status.ToError(); 10693074Sbde // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN? 107151316Sdavidxu events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT; 108205642Snwhitehorn status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events)); 109205642Snwhitehorn if (status.Fail()) 110189362Sdchagin return status.ToError(); 111196512Sbz 11214456Ssos status = process_up->ReinitializeThreads(); 113189362Sdchagin if (status.Fail()) 114189362Sdchagin return status.ToError(); 115189362Sdchagin 116161310Snetchild for (const auto &thread : process_up->m_threads) 117161310Snetchild static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP); 118161310Snetchild process_up->SetState(StateType::eStateStopped, false); 11914331Speter 12014331Speter return std::move(process_up); 121161204Snetchild} 122161204Snetchild 123161204Snetchildllvm::Expected<std::unique_ptr<NativeProcessProtocol>> 124161204SnetchildNativeProcessNetBSD::Factory::Attach( 12514331Speter lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, 12641796Sdt MainLoop &mainloop) const { 127111798Sdes Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 128111798Sdes LLDB_LOG(log, "pid = {0:x}", pid); 129111798Sdes 130111798Sdes // Retrieve the architecture for the running process. 131111798Sdes ProcessInstanceInfo Info; 13214456Ssos if (!Host::GetProcessInfo(pid, Info)) { 13314456Ssos return llvm::make_error<StringError>("Cannot get process architecture", 13414456Ssos llvm::inconvertibleErrorCode()); 135161204Snetchild } 136161204Snetchild 13714331Speter std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD( 13814331Speter pid, -1, native_delegate, Info.GetArchitecture(), mainloop)); 13951793Smarcel 14051793Smarcel Status status = process_up->Attach(); 14151793Smarcel if (!status.Success()) 142111429Skan return status.ToError(); 14351793Smarcel 14451793Smarcel return std::move(process_up); 14551793Smarcel} 14651793Smarcel 14751793Smarcel// Public Instance Methods 14814331Speter 14914331SpeterNativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd, 15051793Smarcel NativeDelegate &delegate, 15151793Smarcel const ArchSpec &arch, 15251793Smarcel MainLoop &mainloop) 15351793Smarcel : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) { 15451793Smarcel if (m_terminal_fd != -1) { 15551793Smarcel Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); 15651793Smarcel assert(status.Success()); 15751793Smarcel } 158111429Skan 15914331Speter Status status; 16014331Speter m_sigchld_handle = mainloop.RegisterSignal( 16186647Spb SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); 16286647Spb assert(m_sigchld_handle && status.Success()); 16386647Spb} 16486647Spb 16586647Spb// Handles all waitpid events from the inferior process. 16686647Spbvoid NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) { 16786647Spb switch (signal) { 16886647Spb case SIGTRAP: 16986647Spb return MonitorSIGTRAP(pid); 17086647Spb case SIGSTOP: 17186647Spb return MonitorSIGSTOP(pid); 17286647Spb default: 17386647Spb return MonitorSignal(pid, signal); 17486647Spb } 17586647Spb} 17686647Spb 17786647Spbvoid NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) { 17886647Spb Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 17986647Spb 18086647Spb LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid); 18186647Spb 18286647Spb /* Stop Tracking All Threads attached to Process */ 18386647Spb m_threads.clear(); 18486647Spb 18586647Spb SetExitStatus(status, true); 18686647Spb 18786647Spb // Notify delegate that our process has exited. 18886647Spb SetState(StateType::eStateExited, true); 18986647Spb} 19086647Spb 19186647Spbvoid NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) { 19286647Spb ptrace_siginfo_t info; 19386647Spb 19486647Spb const auto siginfo_err = 19586647Spb PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info)); 19686647Spb 19786647Spb // Get details on the signal raised. 19886647Spb if (siginfo_err.Success()) { 19986647Spb // Handle SIGSTOP from LLGS (LLDB GDB Server) 20035496Seivind if (info.psi_siginfo.si_code == SI_USER && 20135496Seivind info.psi_siginfo.si_pid == ::getpid()) { 20235496Seivind /* Stop Tracking all Threads attached to Process */ 20382585Sdillon for (const auto &thread : m_threads) { 20482585Sdillon static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal( 20535496Seivind SIGSTOP, &info.psi_siginfo); 20633181Seivind } 20735496Seivind } 20835496Seivind SetState(StateType::eStateStopped, true); 20935820Seivind } 21035820Seivind} 21135820Seivind 21235820Seivindvoid NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { 21335820Seivind Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 21435820Seivind ptrace_siginfo_t info; 21535820Seivind 21635820Seivind const auto siginfo_err = 21735496Seivind PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info)); 21835496Seivind 21935496Seivind // Get details on the signal raised. 22035496Seivind if (siginfo_err.Fail()) { 22135496Seivind return; 22235496Seivind } 22355141Sbde 22414331Speter NativeThreadNetBSD* thread = nullptr; 22555141Sbde if (info.psi_lwpid > 0) { 22614331Speter for (const auto &t : m_threads) { 22714456Ssos if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) { 228140992Ssobomax thread = static_cast<NativeThreadNetBSD *>(t.get()); 22914456Ssos break; 230232451Skib } 23114456Ssos static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason(); 232232451Skib } 23314456Ssos if (!thread) 234232451Skib LLDB_LOG(log, 235189362Sdchagin "thread not found in m_threads, pid = {0}, LWP = {1}", pid, 23614331Speter info.psi_lwpid); 23714331Speter } 23833181Seivind 23955141Sbde switch (info.psi_siginfo.si_code) { 24014456Ssos case TRAP_BRKPT: 241189362Sdchagin if (thread) { 242112470Sjhb thread->SetStoppedByBreakpoint(); 243189362Sdchagin FixupBreakpointPCAsNeeded(*thread); 244189362Sdchagin } 24555141Sbde SetState(StateType::eStateStopped, true); 246294905Sdelphij break; 247111798Sdes case TRAP_TRACE: 248177091Sjeff if (thread) 249112470Sjhb thread->SetStoppedByTrace(); 250189362Sdchagin SetState(StateType::eStateStopped, true); 251189362Sdchagin break; 252294905Sdelphij case TRAP_EXEC: { 253189362Sdchagin Status error = ReinitializeThreads(); 254220026Sdchagin if (error.Fail()) { 255112470Sjhb SetState(StateType::eStateInvalid); 256140992Ssobomax return; 257111798Sdes } 258189362Sdchagin 259191973Sdchagin // Let our delegate know we have just exec'd. 260191973Sdchagin NotifyDidExec(); 261191973Sdchagin 262191973Sdchagin for (const auto &thread : m_threads) 263191973Sdchagin static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec(); 264191973Sdchagin SetState(StateType::eStateStopped, true); 265191973Sdchagin } break; 266191973Sdchagin case TRAP_LWP: { 267191973Sdchagin ptrace_state_t pst; 268191973Sdchagin Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst)); 269191973Sdchagin if (error.Fail()) { 27014456Ssos SetState(StateType::eStateInvalid); 27114456Ssos return; 27214456Ssos } 27314456Ssos 27414456Ssos switch (pst.pe_report_event) { 27514456Ssos case PTRACE_LWP_CREATE: { 27614456Ssos LLDB_LOG(log, 277294905Sdelphij "monitoring new thread, pid = {0}, LWP = {1}", pid, 27877183Srwatson pst.pe_lwp); 27977183Srwatson NativeThreadNetBSD& t = AddThread(pst.pe_lwp); 28077183Srwatson error = t.CopyWatchpointsFrom( 28177183Srwatson static_cast<NativeThreadNetBSD &>(*GetCurrentThread())); 282189362Sdchagin if (error.Fail()) { 283189362Sdchagin LLDB_LOG(log, 284189362Sdchagin "failed to copy watchpoints to new thread {0}: {1}", 28514456Ssos pst.pe_lwp, error); 286111798Sdes SetState(StateType::eStateInvalid); 287111798Sdes return; 28814456Ssos } 28914331Speter } break; 29014456Ssos case PTRACE_LWP_EXIT: 291232451Skib LLDB_LOG(log, 292189362Sdchagin "removing exited thread, pid = {0}, LWP = {1}", pid, 29314456Ssos pst.pe_lwp); 29414331Speter RemoveThread(pst.pe_lwp); 295189362Sdchagin break; 296189362Sdchagin } 297189362Sdchagin 298189362Sdchagin error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void*>(1), 0); 299189362Sdchagin if (error.Fail()) { 300189362Sdchagin SetState(StateType::eStateInvalid); 301189362Sdchagin return; 302189362Sdchagin } 303189362Sdchagin } break; 304189362Sdchagin case TRAP_DBREG: { 305189362Sdchagin if (!thread) 306189362Sdchagin break; 307189362Sdchagin 308189362Sdchagin auto ®ctx = static_cast<NativeRegisterContextNetBSD &>( 309189362Sdchagin thread->GetRegisterContext()); 310189362Sdchagin uint32_t wp_index = LLDB_INVALID_INDEX32; 311189362Sdchagin Status error = regctx.GetWatchpointHitIndex(wp_index, 312189362Sdchagin (uintptr_t)info.psi_siginfo.si_addr); 313189362Sdchagin if (error.Fail()) 314219609Sdchagin LLDB_LOG(log, 315219609Sdchagin "received error while checking for watchpoint hits, pid = " 316189362Sdchagin "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error); 317189362Sdchagin if (wp_index != LLDB_INVALID_INDEX32) { 318189362Sdchagin thread->SetStoppedByWatchpoint(wp_index); 319189362Sdchagin regctx.ClearWatchpointHit(wp_index); 320219609Sdchagin SetState(StateType::eStateStopped, true); 321219609Sdchagin break; 322189362Sdchagin } 323189362Sdchagin 324189362Sdchagin thread->SetStoppedByTrace(); 325189362Sdchagin SetState(StateType::eStateStopped, true); 326189362Sdchagin } break; 327189362Sdchagin } 328189362Sdchagin} 329189362Sdchagin 330189362Sdchaginvoid NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { 331189362Sdchagin ptrace_siginfo_t info; 332189362Sdchagin const auto siginfo_err = 333189362Sdchagin PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info)); 334189362Sdchagin 335189362Sdchagin for (const auto &abs_thread : m_threads) { 336189362Sdchagin NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread); 337189362Sdchagin assert(info.psi_lwpid >= 0); 338189362Sdchagin if (info.psi_lwpid == 0 || 339189362Sdchagin static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID()) 340189362Sdchagin thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo); 341189362Sdchagin else 342189362Sdchagin thread.SetStoppedWithNoReason(); 343189362Sdchagin } 344189362Sdchagin SetState(StateType::eStateStopped, true); 345189362Sdchagin} 346189362Sdchagin 347189362SdchaginStatus NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, 348189362Sdchagin int data, int *result) { 349189362Sdchagin Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); 350189362Sdchagin Status error; 351189362Sdchagin int ret; 352189362Sdchagin 353189362Sdchagin errno = 0; 354189362Sdchagin ret = ptrace(req, static_cast<::pid_t>(pid), addr, data); 355189362Sdchagin 356189362Sdchagin if (ret == -1) 357189362Sdchagin error.SetErrorToErrno(); 358189362Sdchagin 359189362Sdchagin if (result) 360189362Sdchagin *result = ret; 361189362Sdchagin 362189362Sdchagin LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret); 363189362Sdchagin 364189362Sdchagin if (error.Fail()) 365189362Sdchagin LLDB_LOG(log, "ptrace() failed: {0}", error); 366189362Sdchagin 367189362Sdchagin return error; 368189362Sdchagin} 369189362Sdchagin 370189362Sdchaginstatic llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo( 371189362Sdchagin const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads, 372189362Sdchagin const ResumeActionList &resume_actions) { 373189362Sdchagin // We need to account for three possible scenarios: 374189362Sdchagin // 1. no signal being sent. 375189362Sdchagin // 2. a signal being sent to one thread. 376189362Sdchagin // 3. a signal being sent to the whole process. 377189362Sdchagin 378189362Sdchagin // Count signaled threads. While at it, determine which signal is being sent 379189362Sdchagin // and ensure there's only one. 380189362Sdchagin size_t signaled_threads = 0; 381189362Sdchagin int signal = LLDB_INVALID_SIGNAL_NUMBER; 382189362Sdchagin lldb::tid_t signaled_lwp; 383189362Sdchagin for (const auto &thread : threads) { 384189362Sdchagin assert(thread && "thread list should not contain NULL threads"); 385189362Sdchagin const ResumeAction *action = 386189362Sdchagin resume_actions.GetActionForThread(thread->GetID(), true); 387189362Sdchagin if (action) { 388189362Sdchagin if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) { 389189362Sdchagin signaled_threads++; 390189362Sdchagin if (action->signal != signal) { 391189362Sdchagin if (signal != LLDB_INVALID_SIGNAL_NUMBER) 392189362Sdchagin return Status("NetBSD does not support passing multiple signals " 393189362Sdchagin "simultaneously") 394189362Sdchagin .ToError(); 395189362Sdchagin signal = action->signal; 396189362Sdchagin signaled_lwp = thread->GetID(); 397189362Sdchagin } 398189362Sdchagin } 399189362Sdchagin } 400189362Sdchagin } 401189362Sdchagin 402189362Sdchagin if (signaled_threads == 0) { 403189362Sdchagin ptrace_siginfo_t siginfo; 40414331Speter siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER; 40573011Sjake return siginfo; 40614331Speter } 40767234Sgallatin 408151316Sdavidxu if (signaled_threads > 1 && signaled_threads < threads.size()) 40967234Sgallatin return Status("NetBSD does not support passing signal to 1<i<all threads") 410111798Sdes .ToError(); 411111798Sdes 412114983Sjhb ptrace_siginfo_t siginfo; 413111798Sdes siginfo.psi_siginfo.si_signo = signal; 41483221Smarcel siginfo.psi_siginfo.si_code = SI_USER; 415151316Sdavidxu siginfo.psi_siginfo.si_pid = getpid(); 41667234Sgallatin siginfo.psi_siginfo.si_uid = getuid(); 41767234Sgallatin if (signaled_threads == 1) 418151316Sdavidxu siginfo.psi_lwpid = signaled_lwp; 419151316Sdavidxu else // signal for the whole process 42083163Sjhb siginfo.psi_lwpid = 0; 421114983Sjhb return siginfo; 422114983Sjhb} 42383366Sjulian 42469379SmarcelStatus NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { 42567234Sgallatin Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 42667234Sgallatin LLDB_LOG(log, "pid {0}", GetID()); 42783221Smarcel 428151343Sjhb Status ret; 42972543Sjlemon 43067234Sgallatin Expected<ptrace_siginfo_t> siginfo = 43167234Sgallatin ComputeSignalInfo(m_threads, resume_actions); 43267234Sgallatin if (!siginfo) 43367234Sgallatin return Status(siginfo.takeError()); 434124092Sdavidxu 435114983Sjhb for (const auto &abs_thread : m_threads) { 436124092Sdavidxu assert(abs_thread && "thread list should not contain NULL threads"); 437124092Sdavidxu NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread); 43869379Smarcel 43983221Smarcel const ResumeAction *action = 440114983Sjhb resume_actions.GetActionForThread(thread.GetID(), true); 44167234Sgallatin // we need to explicit issue suspend requests, so it is simpler to map it 44267234Sgallatin // into proper action 44367234Sgallatin ResumeAction suspend_action{thread.GetID(), eStateSuspended, 44467234Sgallatin LLDB_INVALID_SIGNAL_NUMBER}; 44567234Sgallatin 44667234Sgallatin if (action == nullptr) { 44767234Sgallatin LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), 44867234Sgallatin thread.GetID()); 449106332Smarcel action = &suspend_action; 450106332Smarcel } 45167234Sgallatin 45267234Sgallatin LLDB_LOG( 45367234Sgallatin log, 45467234Sgallatin "processing resume action state {0} signal {1} for pid {2} tid {3}", 45569081Smarcel action->state, action->signal, GetID(), thread.GetID()); 456103077Sjmallett 457184058Skib switch (action->state) { 45869081Smarcel case eStateRunning: 45967234Sgallatin ret = thread.Resume(); 46067234Sgallatin break; 46167234Sgallatin case eStateStepping: 46269081Smarcel ret = thread.SingleStep(); 46369081Smarcel break; 46469081Smarcel case eStateSuspended: 465124092Sdavidxu case eStateStopped: 466124092Sdavidxu if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) 467124092Sdavidxu return Status("Passing signal to suspended thread unsupported"); 46869379Smarcel 46971497Sjhb ret = thread.Suspend(); 47069081Smarcel break; 47169081Smarcel 47269081Smarcel default: 47369081Smarcel return Status("NativeProcessNetBSD::%s (): unexpected state %s specified " 47467234Sgallatin "for pid %" PRIu64 ", tid %" PRIu64, 47567234Sgallatin __FUNCTION__, StateAsCString(action->state), GetID(), 47667234Sgallatin thread.GetID()); 47767234Sgallatin } 47867234Sgallatin 47967234Sgallatin if (!ret.Success()) 48067234Sgallatin return ret; 48167234Sgallatin } 48267234Sgallatin 48367234Sgallatin int signal = 0; 48467234Sgallatin if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) { 48567234Sgallatin ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(), 48667234Sgallatin sizeof(*siginfo)); 48767234Sgallatin if (!ret.Success()) 48867234Sgallatin return ret; 48967234Sgallatin signal = siginfo->psi_siginfo.si_signo; 49067234Sgallatin } 491172255Skib 49286647Spb ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 49367234Sgallatin signal); 49467234Sgallatin if (ret.Success()) 49583221Smarcel SetState(eStateRunning, true); 49672543Sjlemon return ret; 497124113Sdavidxu} 498124113Sdavidxu 49967234SgallatinStatus NativeProcessNetBSD::Halt() { 50067234Sgallatin return PtraceWrapper(PT_STOP, GetID()); 50167234Sgallatin} 50267234Sgallatin 50367234SgallatinStatus NativeProcessNetBSD::Detach() { 50467234Sgallatin Status error; 50567234Sgallatin 50692642Salc // Stop monitoring the inferior. 50792642Salc m_sigchld_handle.reset(); 50892642Salc 50992642Salc // Tell ptrace to detach from the process. 51092642Salc if (GetID() == LLDB_INVALID_PROCESS_ID) 51173929Sjhb return error; 51283366Sjulian 51367234Sgallatin return PtraceWrapper(PT_DETACH, GetID()); 51467234Sgallatin} 51567234Sgallatin 51667234SgallatinStatus NativeProcessNetBSD::Signal(int signo) { 51767234Sgallatin Status error; 51867234Sgallatin 519219609Sdchagin if (kill(GetID(), signo)) 520177145Skib error.SetErrorToErrno(); 52167234Sgallatin 52267234Sgallatin return error; 52367234Sgallatin} 52467234Sgallatin 52567234SgallatinStatus NativeProcessNetBSD::Interrupt() { 52683163Sjhb return PtraceWrapper(PT_STOP, GetID()); 527114983Sjhb} 52867234Sgallatin 52967234SgallatinStatus NativeProcessNetBSD::Kill() { 53067234Sgallatin Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 53114331Speter LLDB_LOG(log, "pid {0}", GetID()); 53214331Speter 53314331Speter Status error; 53414331Speter 53514331Speter switch (m_state) { 53614331Speter case StateType::eStateInvalid: 53714331Speter case StateType::eStateExited: 53814331Speter case StateType::eStateCrashed: 53914331Speter case StateType::eStateDetached: 54014331Speter case StateType::eStateUnloaded: 54133181Seivind // Nothing to do - the process is already dead. 542151316Sdavidxu LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), 54314331Speter StateAsCString(m_state)); 544111798Sdes return error; 545111798Sdes 546114983Sjhb case StateType::eStateConnected: 547111798Sdes case StateType::eStateAttaching: 54883221Smarcel case StateType::eStateLaunching: 54983221Smarcel case StateType::eStateStopped: 550151316Sdavidxu case StateType::eStateRunning: 55168689Sgallatin case StateType::eStateStepping: 55214331Speter case StateType::eStateSuspended: 55383587Sjhb // We can try to kill a process in these states. 554114983Sjhb break; 555151316Sdavidxu } 556151316Sdavidxu 557114983Sjhb if (kill(GetID(), SIGKILL) != 0) { 558114983Sjhb error.SetErrorToErrno(); 55969081Smarcel return error; 560151316Sdavidxu } 56169081Smarcel 56269081Smarcel return error; 56383366Sjulian} 56469379Smarcel 56514331SpeterStatus NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, 56614331Speter MemoryRegionInfo &range_info) { 56783221Smarcel 568151343Sjhb if (m_supports_mem_region == LazyBool::eLazyBoolNo) { 56972543Sjlemon // We're done. 57014331Speter return Status("unsupported"); 57167234Sgallatin } 57214331Speter 57314331Speter Status error = PopulateMemoryRegionCache(); 57414331Speter if (error.Fail()) { 575124092Sdavidxu return error; 576114983Sjhb } 577124092Sdavidxu 578124092Sdavidxu lldb::addr_t prev_base_address = 0; 57969379Smarcel // FIXME start by finding the last region that is <= target address using 58083221Smarcel // binary search. Data is sorted. 581114983Sjhb // There can be a ton of regions on pthreads apps with lots of threads. 58271497Sjhb for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); 58314331Speter ++it) { 58414331Speter MemoryRegionInfo &proc_entry_info = it->first; 58514331Speter // Sanity check assumption that memory map entries are ascending. 58614331Speter assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && 58751793Smarcel "descending memory map entries detected, unexpected"); 58851793Smarcel prev_base_address = proc_entry_info.GetRange().GetRangeBase(); 58951793Smarcel UNUSED_IF_ASSERT_DISABLED(prev_base_address); 59014331Speter // If the target address comes before this entry, indicate distance to next 591106332Smarcel // region. 592106332Smarcel if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { 59314331Speter range_info.GetRange().SetRangeBase(load_addr); 59414331Speter range_info.GetRange().SetByteSize( 59514331Speter proc_entry_info.GetRange().GetRangeBase() - load_addr); 59669081Smarcel range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); 59769081Smarcel range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); 59814331Speter range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); 59914331Speter range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); 60014331Speter return error; 60169081Smarcel } else if (proc_entry_info.GetRange().Contains(load_addr)) { 60246129Sluoqi // The target address is within the memory region we're processing here. 60346129Sluoqi range_info = proc_entry_info; 60425553Speter return error; 60525553Speter } 60625553Speter // The target memory address comes somewhere after the region we just 60725553Speter // parsed. 60825553Speter } 60925553Speter // If we made it here, we didn't find an entry that contained the given 61025553Speter // address. Return the load_addr as start and the amount of bytes betwwen 61125553Speter // load address and the end of the memory as size. 61225553Speter range_info.GetRange().SetRangeBase(load_addr); 61325553Speter range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); 61425553Speter range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); 61525553Speter range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); 61625553Speter range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); 61725553Speter range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); 61825553Speter return error; 619172255Skib} 620151316Sdavidxu 62169081SmarcelStatus NativeProcessNetBSD::PopulateMemoryRegionCache() { 62268689Sgallatin Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 62369081Smarcel // If our cache is empty, pull the latest. There should always be at least 62469081Smarcel // one memory region if memory region handling is supported. 62514331Speter if (!m_mem_region_cache.empty()) { 62614331Speter LLDB_LOG(log, "reusing {0} cached memory region entries", 62714331Speter m_mem_region_cache.size()); 62814331Speter return Status(); 62914331Speter } 63073929Sjhb 63183366Sjulian struct kinfo_vmentry *vm; 63214331Speter size_t count, i; 63314331Speter vm = kinfo_getvmmap(GetID(), &count); 63414331Speter if (vm == NULL) { 63514331Speter m_supports_mem_region = LazyBool::eLazyBoolNo; 63614331Speter Status error; 63725553Speter error.SetErrorString("not supported"); 638219609Sdchagin return error; 639177145Skib } 64025553Speter for (i = 0; i < count; i++) { 64125553Speter MemoryRegionInfo info; 64225553Speter info.Clear(); 64346129Sluoqi info.GetRange().SetRangeBase(vm[i].kve_start); 64425553Speter info.GetRange().SetRangeEnd(vm[i].kve_end); 64583221Smarcel info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); 646114983Sjhb 64714331Speter if (vm[i].kve_protection & VM_PROT_READ) 64814331Speter info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); 64914331Speter else 65014331Speter info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); 65114331Speter 65214331Speter if (vm[i].kve_protection & VM_PROT_WRITE) 65314331Speter info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); 65414331Speter else 65514331Speter info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); 65614331Speter 65714331Speter if (vm[i].kve_protection & VM_PROT_EXECUTE) 65814331Speter info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); 65914331Speter else 660105441Smarkm info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); 66114331Speter 66283221Smarcel if (vm[i].kve_path[0]) 663111798Sdes info.SetName(vm[i].kve_path); 66483221Smarcel 665198507Skib m_mem_region_cache.emplace_back( 66668689Sgallatin info, FileSpec(info.GetName().GetCString())); 667151316Sdavidxu } 66814331Speter free(vm); 66983366Sjulian 67014331Speter if (m_mem_region_cache.empty()) { 67114331Speter // No entries after attempting to read them. This shouldn't happen. Assume 67272543Sjlemon // we don't support map entries. 67372543Sjlemon LLDB_LOG(log, "failed to find any vmmap entries, assuming no support " 67414331Speter "for memory region metadata retrieval"); 67514331Speter m_supports_mem_region = LazyBool::eLazyBoolNo; 67669081Smarcel Status error; 67714331Speter error.SetErrorString("not supported"); 67814331Speter return error; 67914331Speter } 680111797Sdes LLDB_LOG(log, "read {0} memory region entries from process {1}", 68114331Speter m_mem_region_cache.size(), GetID()); 68214331Speter // We support memory retrieval, remember that. 68314331Speter m_supports_mem_region = LazyBool::eLazyBoolYes; 68414331Speter return Status(); 68514331Speter} 68614331Speter 68769081SmarcelStatus NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions, 688258685Semaste lldb::addr_t &addr) { 689111798Sdes return Status("Unimplemented"); 69014331Speter} 69114331Speter 69214331SpeterStatus NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) { 69314331Speter return Status("Unimplemented"); 69414331Speter} 69514331Speter 69628496Scharnierlldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() { 69769081Smarcel // punt on this for now 698151316Sdavidxu return LLDB_INVALID_ADDRESS; 699151316Sdavidxu} 700151316Sdavidxu 701151316Sdavidxusize_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); } 702151316Sdavidxu 703151316SdavidxuStatus NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, 70414331Speter bool hardware) { 70514331Speter if (hardware) 70614331Speter return Status("NativeProcessNetBSD does not support hardware breakpoints"); 70769081Smarcel else 70869081Smarcel return SetSoftwareBreakpoint(addr, size); 70969081Smarcel} 710198507Skib 711198507SkibStatus NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path, 71251793Smarcel FileSpec &file_spec) { 71314331Speter return Status("Unimplemented"); 71414331Speter} 71514331Speter 71646129SluoqiStatus NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name, 71769081Smarcel lldb::addr_t &load_addr) { 71869081Smarcel load_addr = LLDB_INVALID_ADDRESS; 71969081Smarcel return Status(); 72069081Smarcel} 72169081Smarcel 72269081Smarcelvoid NativeProcessNetBSD::SigchldHandler() { 72369081Smarcel Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); 72469081Smarcel // Process all pending waitpid notifications. 72569081Smarcel int status; 72669081Smarcel ::pid_t wait_pid = 72769081Smarcel llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG); 72869081Smarcel 72925553Speter if (wait_pid == 0) 73069081Smarcel return; // We are done. 73169081Smarcel 73214331Speter if (wait_pid == -1) { 73314331Speter Status error(errno, eErrorTypePOSIX); 73414331Speter LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error); 73514331Speter } 73667234Sgallatin 73767234Sgallatin WaitStatus wait_status = WaitStatus::Decode(status); 73867234Sgallatin bool exited = wait_status.type == WaitStatus::Exit || 73967234Sgallatin (wait_status.type == WaitStatus::Signal && 74067234Sgallatin wait_pid == static_cast<::pid_t>(GetID())); 74167234Sgallatin 74267234Sgallatin LLDB_LOG(log, 74367234Sgallatin "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}", 74467234Sgallatin GetID(), wait_pid, status, exited); 74567234Sgallatin 74667234Sgallatin if (exited) 747105441Smarkm MonitorExited(wait_pid, wait_status); 74867234Sgallatin else { 74983221Smarcel assert(wait_status.type == WaitStatus::Stop); 75083221Smarcel MonitorCallback(wait_pid, wait_status.status); 751198507Skib } 75283221Smarcel} 753102814Siedowse 754111798Sdesbool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) { 75567234Sgallatin for (const auto &thread : m_threads) { 756151316Sdavidxu assert(thread && "thread list should not contain NULL threads"); 75767234Sgallatin if (thread->GetID() == thread_id) { 75883366Sjulian // We have this thread. 75967234Sgallatin return true; 76067234Sgallatin } 76172543Sjlemon } 76272543Sjlemon 76367234Sgallatin // We don't have this thread. 76467234Sgallatin return false; 76569081Smarcel} 76667234Sgallatin 76767234SgallatinNativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { 76867234Sgallatin Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 769111797Sdes LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); 77067234Sgallatin 77167234Sgallatin assert(thread_id > 0); 77267234Sgallatin assert(!HasThreadNoLock(thread_id) && 77367234Sgallatin "attempted to add a thread by id that already exists"); 77467234Sgallatin 77567234Sgallatin // If this is the first thread, save it as the current thread 77667234Sgallatin if (m_threads.empty()) 77767234Sgallatin SetCurrentThreadID(thread_id); 77867234Sgallatin 779258685Semaste m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id)); 780111798Sdes return static_cast<NativeThreadNetBSD &>(*m_threads.back()); 78167234Sgallatin} 78267234Sgallatin 78367234Sgallatinvoid NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) { 78467234Sgallatin Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); 78567234Sgallatin LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); 78667234Sgallatin 78767234Sgallatin assert(thread_id > 0); 78867234Sgallatin assert(HasThreadNoLock(thread_id) && 789151316Sdavidxu "attempted to remove a thread that does not exist"); 790151316Sdavidxu 791151316Sdavidxu for (auto it = m_threads.begin(); it != m_threads.end(); ++it) { 792151316Sdavidxu if ((*it)->GetID() == thread_id) { 793151316Sdavidxu m_threads.erase(it); 794151316Sdavidxu break; 79567234Sgallatin } 79667234Sgallatin } 79767234Sgallatin} 798198507Skib 799198507SkibStatus NativeProcessNetBSD::Attach() { 80067234Sgallatin // Attach to the requested process. 80167234Sgallatin // An attach will cause the thread to stop with a SIGSTOP. 80269081Smarcel Status status = PtraceWrapper(PT_ATTACH, m_pid); 80367234Sgallatin if (status.Fail()) 80467234Sgallatin return status; 80567234Sgallatin 80667234Sgallatin int wstatus; 80767234Sgallatin // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this 80867234Sgallatin // point we should have a thread stopped if waitpid succeeds. 80967234Sgallatin if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, 81067234Sgallatin m_pid, nullptr, WALLSIG)) < 0) 81167234Sgallatin return Status(errno, eErrorTypePOSIX); 81267234Sgallatin 81367234Sgallatin /* Initialize threads */ 81467234Sgallatin status = ReinitializeThreads(); 81567234Sgallatin if (status.Fail()) 81667234Sgallatin return status; 81767234Sgallatin 81867234Sgallatin for (const auto &thread : m_threads) 81967234Sgallatin static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP); 82067234Sgallatin 82167234Sgallatin // Let our process instance know the thread has stopped. 82267234Sgallatin SetState(StateType::eStateStopped); 82367234Sgallatin return Status(); 82467234Sgallatin} 825102814Siedowse 826102814SiedowseStatus NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf, 827102814Siedowse size_t size, size_t &bytes_read) { 82867234Sgallatin unsigned char *dst = static_cast<unsigned char *>(buf); 82967234Sgallatin struct ptrace_io_desc io; 83072543Sjlemon 83172543Sjlemon Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); 832102814Siedowse LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); 83367234Sgallatin 834102814Siedowse bytes_read = 0; 83567234Sgallatin io.piod_op = PIOD_READ_D; 83667234Sgallatin io.piod_len = size; 83767234Sgallatin 83867234Sgallatin do { 839208453Skib io.piod_offs = (void *)(addr + bytes_read); 840208453Skib io.piod_addr = dst + bytes_read; 84114331Speter 842208453Skib Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io); 843208453Skib if (error.Fail() || io.piod_len == 0) 844208453Skib return error; 845208453Skib 846208453Skib bytes_read += io.piod_len; 847208453Skib io.piod_len = size - bytes_read; 848208453Skib } while (bytes_read < size); 849208453Skib 850208453Skib return Status(); 851208453Skib} 852208453Skib 853208453SkibStatus NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf, 854208453Skib size_t size, size_t &bytes_written) { 855208453Skib const unsigned char *src = static_cast<const unsigned char *>(buf); 856208453Skib Status error; 857208453Skib struct ptrace_io_desc io; 858208453Skib 859208453Skib Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); 860208453Skib LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); 861208453Skib 862208453Skib bytes_written = 0; 863208453Skib io.piod_op = PIOD_WRITE_D; 864208453Skib io.piod_len = size; 865208453Skib 86614331Speter do { 86714331Speter io.piod_addr = const_cast<void *>(static_cast<const void *>(src + bytes_written)); 86859663Sdillon io.piod_offs = (void *)(addr + bytes_written); 869111798Sdes 87059663Sdillon Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io); 87159663Sdillon if (error.Fail() || io.piod_len == 0) 87259663Sdillon return error; 87359663Sdillon 87492765Salfred bytes_written += io.piod_len; 87559663Sdillon io.piod_len = size - bytes_written; 87659663Sdillon } while (bytes_written < size); 877105441Smarkm 87859663Sdillon return error; 87959663Sdillon} 880141469Sjhb 881210555Salcllvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> 88259663SdillonNativeProcessNetBSD::GetAuxvData() const { 88359663Sdillon /* 88459663Sdillon * ELF_AUX_ENTRIES is currently restricted to kernel 88559663Sdillon * (<sys/exec_elf.h> r. 1.155 specifies 15) 88659663Sdillon * 88759663Sdillon * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this 88859663Sdillon * information isn't needed. 88959663Sdillon */ 89059663Sdillon size_t auxv_size = 100 * sizeof(AuxInfo); 89159663Sdillon 89259663Sdillon ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf = 89359663Sdillon llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size); 89459663Sdillon 895141469Sjhb struct ptrace_io_desc io; 896177997Skib io.piod_op = PIOD_READ_AUXV; 897210555Salc io.piod_offs = 0; 898210555Salc io.piod_addr = static_cast<void *>(buf.get()->getBufferStart()); 899210555Salc io.piod_len = auxv_size; 90059663Sdillon 90159663Sdillon Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io); 902210555Salc 90359663Sdillon if (error.Fail()) 90459663Sdillon return std::error_code(error.GetError(), std::generic_category()); 905114915Smdodd 906114915Smdodd if (io.piod_len < 1) 907114915Smdodd return std::error_code(ECANCELED, std::generic_category()); 908114915Smdodd 909114915Smdodd return std::move(buf); 910114915Smdodd} 911205642Snwhitehorn 912114915SmdoddStatus NativeProcessNetBSD::ReinitializeThreads() { 913114915Smdodd // Clear old threads 914114915Smdodd m_threads.clear(); 915205642Snwhitehorn 916114915Smdodd // Initialize new thread 917114915Smdodd#ifdef PT_LWPSTATUS 918189423Sjhb struct ptrace_lwpstatus info = {}; 919189423Sjhb int op = PT_LWPNEXT; 920141407Sdas#else 921189423Sjhb struct ptrace_lwpinfo info = {}; 922114915Smdodd int op = PT_LWPINFO; 923114915Smdodd#endif 924189362Sdchagin 925189362Sdchagin Status error = PtraceWrapper(op, GetID(), &info, sizeof(info)); 926189362Sdchagin 927189362Sdchagin if (error.Fail()) { 928189362Sdchagin return error; 929189362Sdchagin } 930189362Sdchagin // Reinitialize from scratch threads and register them in process 931189362Sdchagin while (info.pl_lwpid != 0) { 932189362Sdchagin AddThread(info.pl_lwpid); 933189362Sdchagin error = PtraceWrapper(op, GetID(), &info, sizeof(info)); 934189362Sdchagin if (error.Fail()) { 935189362Sdchagin return error; 936189362Sdchagin } 937189362Sdchagin } 938189362Sdchagin 939189362Sdchagin return error; 940189362Sdchagin} 941189362Sdchagin