1//===-- NativeProcessNetBSD.cpp ------------------------------- -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "NativeProcessNetBSD.h"
10
11#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
12#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
13#include "lldb/Host/HostProcess.h"
14#include "lldb/Host/common/NativeRegisterContext.h"
15#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
16#include "lldb/Target/Process.h"
17#include "lldb/Utility/State.h"
18#include "llvm/Support/Errno.h"
19
20// System includes - They have to be included after framework includes because
21// they define some macros which collide with variable names in other modules
22// clang-format off
23#include <sys/types.h>
24#include <sys/ptrace.h>
25#include <sys/sysctl.h>
26#include <sys/wait.h>
27#include <uvm/uvm_prot.h>
28#include <elf.h>
29#include <util.h>
30// clang-format on
31
32using namespace lldb;
33using namespace lldb_private;
34using namespace lldb_private::process_netbsd;
35using namespace llvm;
36
37// Simple helper function to ensure flags are enabled on the given file
38// descriptor.
39static Status EnsureFDFlags(int fd, int flags) {
40  Status error;
41
42  int status = fcntl(fd, F_GETFL);
43  if (status == -1) {
44    error.SetErrorToErrno();
45    return error;
46  }
47
48  if (fcntl(fd, F_SETFL, status | flags) == -1) {
49    error.SetErrorToErrno();
50    return error;
51  }
52
53  return error;
54}
55
56// Public Static Methods
57
58llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
59NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
60                                     NativeDelegate &native_delegate,
61                                     MainLoop &mainloop) const {
62  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
63
64  Status status;
65  ::pid_t pid = ProcessLauncherPosixFork()
66                    .LaunchProcess(launch_info, status)
67                    .GetProcessId();
68  LLDB_LOG(log, "pid = {0:x}", pid);
69  if (status.Fail()) {
70    LLDB_LOG(log, "failed to launch process: {0}", status);
71    return status.ToError();
72  }
73
74  // Wait for the child process to trap on its call to execve.
75  int wstatus;
76  ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
77  assert(wpid == pid);
78  (void)wpid;
79  if (!WIFSTOPPED(wstatus)) {
80    LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
81             WaitStatus::Decode(wstatus));
82    return llvm::make_error<StringError>("Could not sync with inferior process",
83                                         llvm::inconvertibleErrorCode());
84  }
85  LLDB_LOG(log, "inferior started, now in stopped state");
86
87  ProcessInstanceInfo Info;
88  if (!Host::GetProcessInfo(pid, Info)) {
89    return llvm::make_error<StringError>("Cannot get process architecture",
90                                         llvm::inconvertibleErrorCode());
91  }
92
93  // Set the architecture to the exe architecture.
94  LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
95           Info.GetArchitecture().GetArchitectureName());
96
97  std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
98      pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate,
99      Info.GetArchitecture(), mainloop));
100
101  // Enable event reporting
102  ptrace_event_t events;
103  status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events));
104  if (status.Fail())
105    return status.ToError();
106  // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN?
107  events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
108  status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events));
109  if (status.Fail())
110    return status.ToError();
111
112  status = process_up->ReinitializeThreads();
113  if (status.Fail())
114    return status.ToError();
115
116  for (const auto &thread : process_up->m_threads)
117    static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
118  process_up->SetState(StateType::eStateStopped, false);
119
120  return std::move(process_up);
121}
122
123llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
124NativeProcessNetBSD::Factory::Attach(
125    lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
126    MainLoop &mainloop) const {
127  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
128  LLDB_LOG(log, "pid = {0:x}", pid);
129
130  // Retrieve the architecture for the running process.
131  ProcessInstanceInfo Info;
132  if (!Host::GetProcessInfo(pid, Info)) {
133    return llvm::make_error<StringError>("Cannot get process architecture",
134                                         llvm::inconvertibleErrorCode());
135  }
136
137  std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
138      pid, -1, native_delegate, Info.GetArchitecture(), mainloop));
139
140  Status status = process_up->Attach();
141  if (!status.Success())
142    return status.ToError();
143
144  return std::move(process_up);
145}
146
147// Public Instance Methods
148
149NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,
150                                         NativeDelegate &delegate,
151                                         const ArchSpec &arch,
152                                         MainLoop &mainloop)
153    : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) {
154  if (m_terminal_fd != -1) {
155    Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
156    assert(status.Success());
157  }
158
159  Status status;
160  m_sigchld_handle = mainloop.RegisterSignal(
161      SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
162  assert(m_sigchld_handle && status.Success());
163}
164
165// Handles all waitpid events from the inferior process.
166void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
167  switch (signal) {
168  case SIGTRAP:
169    return MonitorSIGTRAP(pid);
170  case SIGSTOP:
171    return MonitorSIGSTOP(pid);
172  default:
173    return MonitorSignal(pid, signal);
174  }
175}
176
177void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
178  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
179
180  LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
181
182  /* Stop Tracking All Threads attached to Process */
183  m_threads.clear();
184
185  SetExitStatus(status, true);
186
187  // Notify delegate that our process has exited.
188  SetState(StateType::eStateExited, true);
189}
190
191void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
192  ptrace_siginfo_t info;
193
194  const auto siginfo_err =
195      PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
196
197  // Get details on the signal raised.
198  if (siginfo_err.Success()) {
199    // Handle SIGSTOP from LLGS (LLDB GDB Server)
200    if (info.psi_siginfo.si_code == SI_USER &&
201        info.psi_siginfo.si_pid == ::getpid()) {
202      /* Stop Tracking all Threads attached to Process */
203      for (const auto &thread : m_threads) {
204        static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(
205            SIGSTOP, &info.psi_siginfo);
206      }
207    }
208    SetState(StateType::eStateStopped, true);
209  }
210}
211
212void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
213  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
214  ptrace_siginfo_t info;
215
216  const auto siginfo_err =
217      PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
218
219  // Get details on the signal raised.
220  if (siginfo_err.Fail()) {
221    return;
222  }
223
224  NativeThreadNetBSD* thread = nullptr;
225  if (info.psi_lwpid > 0) {
226    for (const auto &t : m_threads) {
227      if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {
228        thread = static_cast<NativeThreadNetBSD *>(t.get());
229        break;
230      }
231      static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();
232    }
233    if (!thread)
234      LLDB_LOG(log,
235               "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
236               info.psi_lwpid);
237  }
238
239  switch (info.psi_siginfo.si_code) {
240  case TRAP_BRKPT:
241    if (thread) {
242      thread->SetStoppedByBreakpoint();
243      FixupBreakpointPCAsNeeded(*thread);
244    }
245    SetState(StateType::eStateStopped, true);
246    break;
247  case TRAP_TRACE:
248    if (thread)
249      thread->SetStoppedByTrace();
250    SetState(StateType::eStateStopped, true);
251    break;
252  case TRAP_EXEC: {
253    Status error = ReinitializeThreads();
254    if (error.Fail()) {
255      SetState(StateType::eStateInvalid);
256      return;
257    }
258
259    // Let our delegate know we have just exec'd.
260    NotifyDidExec();
261
262    for (const auto &thread : m_threads)
263      static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
264    SetState(StateType::eStateStopped, true);
265  } break;
266  case TRAP_LWP: {
267    ptrace_state_t pst;
268    Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
269    if (error.Fail()) {
270      SetState(StateType::eStateInvalid);
271      return;
272    }
273
274    switch (pst.pe_report_event) {
275      case PTRACE_LWP_CREATE: {
276        LLDB_LOG(log,
277                 "monitoring new thread, pid = {0}, LWP = {1}", pid,
278                 pst.pe_lwp);
279        NativeThreadNetBSD& t = AddThread(pst.pe_lwp);
280        error = t.CopyWatchpointsFrom(
281            static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));
282        if (error.Fail()) {
283          LLDB_LOG(log,
284                   "failed to copy watchpoints to new thread {0}: {1}",
285                   pst.pe_lwp, error);
286          SetState(StateType::eStateInvalid);
287          return;
288        }
289      } break;
290      case PTRACE_LWP_EXIT:
291        LLDB_LOG(log,
292                 "removing exited thread, pid = {0}, LWP = {1}", pid,
293                 pst.pe_lwp);
294        RemoveThread(pst.pe_lwp);
295        break;
296    }
297
298    error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void*>(1), 0);
299    if (error.Fail()) {
300      SetState(StateType::eStateInvalid);
301      return;
302    }
303  } break;
304  case TRAP_DBREG: {
305    if (!thread)
306      break;
307
308    auto &regctx = static_cast<NativeRegisterContextNetBSD &>(
309        thread->GetRegisterContext());
310    uint32_t wp_index = LLDB_INVALID_INDEX32;
311    Status error = regctx.GetWatchpointHitIndex(wp_index,
312        (uintptr_t)info.psi_siginfo.si_addr);
313    if (error.Fail())
314      LLDB_LOG(log,
315               "received error while checking for watchpoint hits, pid = "
316               "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error);
317    if (wp_index != LLDB_INVALID_INDEX32) {
318      thread->SetStoppedByWatchpoint(wp_index);
319      regctx.ClearWatchpointHit(wp_index);
320      SetState(StateType::eStateStopped, true);
321      break;
322    }
323
324    thread->SetStoppedByTrace();
325    SetState(StateType::eStateStopped, true);
326  } break;
327  }
328}
329
330void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
331  ptrace_siginfo_t info;
332  const auto siginfo_err =
333      PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
334
335  for (const auto &abs_thread : m_threads) {
336    NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
337    assert(info.psi_lwpid >= 0);
338    if (info.psi_lwpid == 0 ||
339        static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())
340      thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);
341    else
342      thread.SetStoppedWithNoReason();
343  }
344  SetState(StateType::eStateStopped, true);
345}
346
347Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
348                                          int data, int *result) {
349  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
350  Status error;
351  int ret;
352
353  errno = 0;
354  ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
355
356  if (ret == -1)
357    error.SetErrorToErrno();
358
359  if (result)
360    *result = ret;
361
362  LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
363
364  if (error.Fail())
365    LLDB_LOG(log, "ptrace() failed: {0}", error);
366
367  return error;
368}
369
370static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(
371    const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,
372    const ResumeActionList &resume_actions) {
373  // We need to account for three possible scenarios:
374  // 1. no signal being sent.
375  // 2. a signal being sent to one thread.
376  // 3. a signal being sent to the whole process.
377
378  // Count signaled threads.  While at it, determine which signal is being sent
379  // and ensure there's only one.
380  size_t signaled_threads = 0;
381  int signal = LLDB_INVALID_SIGNAL_NUMBER;
382  lldb::tid_t signaled_lwp;
383  for (const auto &thread : threads) {
384    assert(thread && "thread list should not contain NULL threads");
385    const ResumeAction *action =
386        resume_actions.GetActionForThread(thread->GetID(), true);
387    if (action) {
388      if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) {
389        signaled_threads++;
390        if (action->signal != signal) {
391          if (signal != LLDB_INVALID_SIGNAL_NUMBER)
392            return Status("NetBSD does not support passing multiple signals "
393                          "simultaneously")
394                .ToError();
395          signal = action->signal;
396          signaled_lwp = thread->GetID();
397        }
398      }
399    }
400  }
401
402  if (signaled_threads == 0) {
403    ptrace_siginfo_t siginfo;
404    siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;
405    return siginfo;
406  }
407
408  if (signaled_threads > 1 && signaled_threads < threads.size())
409    return Status("NetBSD does not support passing signal to 1<i<all threads")
410        .ToError();
411
412  ptrace_siginfo_t siginfo;
413  siginfo.psi_siginfo.si_signo = signal;
414  siginfo.psi_siginfo.si_code = SI_USER;
415  siginfo.psi_siginfo.si_pid = getpid();
416  siginfo.psi_siginfo.si_uid = getuid();
417  if (signaled_threads == 1)
418    siginfo.psi_lwpid = signaled_lwp;
419  else // signal for the whole process
420    siginfo.psi_lwpid = 0;
421  return siginfo;
422}
423
424Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
425  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
426  LLDB_LOG(log, "pid {0}", GetID());
427
428  Status ret;
429
430  Expected<ptrace_siginfo_t> siginfo =
431      ComputeSignalInfo(m_threads, resume_actions);
432  if (!siginfo)
433    return Status(siginfo.takeError());
434
435  for (const auto &abs_thread : m_threads) {
436    assert(abs_thread && "thread list should not contain NULL threads");
437    NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
438
439    const ResumeAction *action =
440        resume_actions.GetActionForThread(thread.GetID(), true);
441    // we need to explicit issue suspend requests, so it is simpler to map it
442    // into proper action
443    ResumeAction suspend_action{thread.GetID(), eStateSuspended,
444                                LLDB_INVALID_SIGNAL_NUMBER};
445
446    if (action == nullptr) {
447      LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
448               thread.GetID());
449      action = &suspend_action;
450    }
451
452    LLDB_LOG(
453        log,
454        "processing resume action state {0} signal {1} for pid {2} tid {3}",
455        action->state, action->signal, GetID(), thread.GetID());
456
457    switch (action->state) {
458    case eStateRunning:
459      ret = thread.Resume();
460      break;
461    case eStateStepping:
462      ret = thread.SingleStep();
463      break;
464    case eStateSuspended:
465    case eStateStopped:
466      if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
467        return Status("Passing signal to suspended thread unsupported");
468
469      ret = thread.Suspend();
470      break;
471
472    default:
473      return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
474                    "for pid %" PRIu64 ", tid %" PRIu64,
475                    __FUNCTION__, StateAsCString(action->state), GetID(),
476                    thread.GetID());
477    }
478
479    if (!ret.Success())
480      return ret;
481  }
482
483  int signal = 0;
484  if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {
485    ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),
486                        sizeof(*siginfo));
487    if (!ret.Success())
488      return ret;
489    signal = siginfo->psi_siginfo.si_signo;
490  }
491
492  ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1),
493                      signal);
494  if (ret.Success())
495    SetState(eStateRunning, true);
496  return ret;
497}
498
499Status NativeProcessNetBSD::Halt() {
500  return PtraceWrapper(PT_STOP, GetID());
501}
502
503Status NativeProcessNetBSD::Detach() {
504  Status error;
505
506  // Stop monitoring the inferior.
507  m_sigchld_handle.reset();
508
509  // Tell ptrace to detach from the process.
510  if (GetID() == LLDB_INVALID_PROCESS_ID)
511    return error;
512
513  return PtraceWrapper(PT_DETACH, GetID());
514}
515
516Status NativeProcessNetBSD::Signal(int signo) {
517  Status error;
518
519  if (kill(GetID(), signo))
520    error.SetErrorToErrno();
521
522  return error;
523}
524
525Status NativeProcessNetBSD::Interrupt() {
526  return PtraceWrapper(PT_STOP, GetID());
527}
528
529Status NativeProcessNetBSD::Kill() {
530  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
531  LLDB_LOG(log, "pid {0}", GetID());
532
533  Status error;
534
535  switch (m_state) {
536  case StateType::eStateInvalid:
537  case StateType::eStateExited:
538  case StateType::eStateCrashed:
539  case StateType::eStateDetached:
540  case StateType::eStateUnloaded:
541    // Nothing to do - the process is already dead.
542    LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
543             StateAsCString(m_state));
544    return error;
545
546  case StateType::eStateConnected:
547  case StateType::eStateAttaching:
548  case StateType::eStateLaunching:
549  case StateType::eStateStopped:
550  case StateType::eStateRunning:
551  case StateType::eStateStepping:
552  case StateType::eStateSuspended:
553    // We can try to kill a process in these states.
554    break;
555  }
556
557  if (kill(GetID(), SIGKILL) != 0) {
558    error.SetErrorToErrno();
559    return error;
560  }
561
562  return error;
563}
564
565Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
566                                                MemoryRegionInfo &range_info) {
567
568  if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
569    // We're done.
570    return Status("unsupported");
571  }
572
573  Status error = PopulateMemoryRegionCache();
574  if (error.Fail()) {
575    return error;
576  }
577
578  lldb::addr_t prev_base_address = 0;
579  // FIXME start by finding the last region that is <= target address using
580  // binary search.  Data is sorted.
581  // There can be a ton of regions on pthreads apps with lots of threads.
582  for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
583       ++it) {
584    MemoryRegionInfo &proc_entry_info = it->first;
585    // Sanity check assumption that memory map entries are ascending.
586    assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
587           "descending memory map entries detected, unexpected");
588    prev_base_address = proc_entry_info.GetRange().GetRangeBase();
589    UNUSED_IF_ASSERT_DISABLED(prev_base_address);
590    // If the target address comes before this entry, indicate distance to next
591    // region.
592    if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
593      range_info.GetRange().SetRangeBase(load_addr);
594      range_info.GetRange().SetByteSize(
595          proc_entry_info.GetRange().GetRangeBase() - load_addr);
596      range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
597      range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
598      range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
599      range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
600      return error;
601    } else if (proc_entry_info.GetRange().Contains(load_addr)) {
602      // The target address is within the memory region we're processing here.
603      range_info = proc_entry_info;
604      return error;
605    }
606    // The target memory address comes somewhere after the region we just
607    // parsed.
608  }
609  // If we made it here, we didn't find an entry that contained the given
610  // address. Return the load_addr as start and the amount of bytes betwwen
611  // load address and the end of the memory as size.
612  range_info.GetRange().SetRangeBase(load_addr);
613  range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
614  range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
615  range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
616  range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
617  range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
618  return error;
619}
620
621Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
622  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
623  // If our cache is empty, pull the latest.  There should always be at least
624  // one memory region if memory region handling is supported.
625  if (!m_mem_region_cache.empty()) {
626    LLDB_LOG(log, "reusing {0} cached memory region entries",
627             m_mem_region_cache.size());
628    return Status();
629  }
630
631  struct kinfo_vmentry *vm;
632  size_t count, i;
633  vm = kinfo_getvmmap(GetID(), &count);
634  if (vm == NULL) {
635    m_supports_mem_region = LazyBool::eLazyBoolNo;
636    Status error;
637    error.SetErrorString("not supported");
638    return error;
639  }
640  for (i = 0; i < count; i++) {
641    MemoryRegionInfo info;
642    info.Clear();
643    info.GetRange().SetRangeBase(vm[i].kve_start);
644    info.GetRange().SetRangeEnd(vm[i].kve_end);
645    info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
646
647    if (vm[i].kve_protection & VM_PROT_READ)
648      info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
649    else
650      info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
651
652    if (vm[i].kve_protection & VM_PROT_WRITE)
653      info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
654    else
655      info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
656
657    if (vm[i].kve_protection & VM_PROT_EXECUTE)
658      info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
659    else
660      info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
661
662    if (vm[i].kve_path[0])
663      info.SetName(vm[i].kve_path);
664
665    m_mem_region_cache.emplace_back(
666        info, FileSpec(info.GetName().GetCString()));
667  }
668  free(vm);
669
670  if (m_mem_region_cache.empty()) {
671    // No entries after attempting to read them.  This shouldn't happen. Assume
672    // we don't support map entries.
673    LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
674                  "for memory region metadata retrieval");
675    m_supports_mem_region = LazyBool::eLazyBoolNo;
676    Status error;
677    error.SetErrorString("not supported");
678    return error;
679  }
680  LLDB_LOG(log, "read {0} memory region entries from process {1}",
681           m_mem_region_cache.size(), GetID());
682  // We support memory retrieval, remember that.
683  m_supports_mem_region = LazyBool::eLazyBoolYes;
684  return Status();
685}
686
687Status NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions,
688                                           lldb::addr_t &addr) {
689  return Status("Unimplemented");
690}
691
692Status NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) {
693  return Status("Unimplemented");
694}
695
696lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
697  // punt on this for now
698  return LLDB_INVALID_ADDRESS;
699}
700
701size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
702
703Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
704                                          bool hardware) {
705  if (hardware)
706    return Status("NativeProcessNetBSD does not support hardware breakpoints");
707  else
708    return SetSoftwareBreakpoint(addr, size);
709}
710
711Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
712                                                    FileSpec &file_spec) {
713  return Status("Unimplemented");
714}
715
716Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
717                                               lldb::addr_t &load_addr) {
718  load_addr = LLDB_INVALID_ADDRESS;
719  return Status();
720}
721
722void NativeProcessNetBSD::SigchldHandler() {
723  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
724  // Process all pending waitpid notifications.
725  int status;
726  ::pid_t wait_pid =
727      llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG);
728
729  if (wait_pid == 0)
730    return; // We are done.
731
732  if (wait_pid == -1) {
733    Status error(errno, eErrorTypePOSIX);
734    LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
735  }
736
737  WaitStatus wait_status = WaitStatus::Decode(status);
738  bool exited = wait_status.type == WaitStatus::Exit ||
739                (wait_status.type == WaitStatus::Signal &&
740                 wait_pid == static_cast<::pid_t>(GetID()));
741
742  LLDB_LOG(log,
743           "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
744           GetID(), wait_pid, status, exited);
745
746  if (exited)
747    MonitorExited(wait_pid, wait_status);
748  else {
749    assert(wait_status.type == WaitStatus::Stop);
750    MonitorCallback(wait_pid, wait_status.status);
751  }
752}
753
754bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
755  for (const auto &thread : m_threads) {
756    assert(thread && "thread list should not contain NULL threads");
757    if (thread->GetID() == thread_id) {
758      // We have this thread.
759      return true;
760    }
761  }
762
763  // We don't have this thread.
764  return false;
765}
766
767NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
768  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
769  LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
770
771  assert(thread_id > 0);
772  assert(!HasThreadNoLock(thread_id) &&
773         "attempted to add a thread by id that already exists");
774
775  // If this is the first thread, save it as the current thread
776  if (m_threads.empty())
777    SetCurrentThreadID(thread_id);
778
779  m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id));
780  return static_cast<NativeThreadNetBSD &>(*m_threads.back());
781}
782
783void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {
784  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
785  LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
786
787  assert(thread_id > 0);
788  assert(HasThreadNoLock(thread_id) &&
789         "attempted to remove a thread that does not exist");
790
791  for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
792    if ((*it)->GetID() == thread_id) {
793      m_threads.erase(it);
794      break;
795    }
796  }
797}
798
799Status NativeProcessNetBSD::Attach() {
800  // Attach to the requested process.
801  // An attach will cause the thread to stop with a SIGSTOP.
802  Status status = PtraceWrapper(PT_ATTACH, m_pid);
803  if (status.Fail())
804    return status;
805
806  int wstatus;
807  // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
808  // point we should have a thread stopped if waitpid succeeds.
809  if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid,
810          m_pid, nullptr, WALLSIG)) < 0)
811    return Status(errno, eErrorTypePOSIX);
812
813  /* Initialize threads */
814  status = ReinitializeThreads();
815  if (status.Fail())
816    return status;
817
818  for (const auto &thread : m_threads)
819    static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
820
821  // Let our process instance know the thread has stopped.
822  SetState(StateType::eStateStopped);
823  return Status();
824}
825
826Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,
827                                       size_t size, size_t &bytes_read) {
828  unsigned char *dst = static_cast<unsigned char *>(buf);
829  struct ptrace_io_desc io;
830
831  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
832  LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
833
834  bytes_read = 0;
835  io.piod_op = PIOD_READ_D;
836  io.piod_len = size;
837
838  do {
839    io.piod_offs = (void *)(addr + bytes_read);
840    io.piod_addr = dst + bytes_read;
841
842    Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
843    if (error.Fail() || io.piod_len == 0)
844      return error;
845
846    bytes_read += io.piod_len;
847    io.piod_len = size - bytes_read;
848  } while (bytes_read < size);
849
850  return Status();
851}
852
853Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
854                                        size_t size, size_t &bytes_written) {
855  const unsigned char *src = static_cast<const unsigned char *>(buf);
856  Status error;
857  struct ptrace_io_desc io;
858
859  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
860  LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
861
862  bytes_written = 0;
863  io.piod_op = PIOD_WRITE_D;
864  io.piod_len = size;
865
866  do {
867    io.piod_addr = const_cast<void *>(static_cast<const void *>(src + bytes_written));
868    io.piod_offs = (void *)(addr + bytes_written);
869
870    Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
871    if (error.Fail() || io.piod_len == 0)
872      return error;
873
874    bytes_written += io.piod_len;
875    io.piod_len = size - bytes_written;
876  } while (bytes_written < size);
877
878  return error;
879}
880
881llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
882NativeProcessNetBSD::GetAuxvData() const {
883  /*
884   * ELF_AUX_ENTRIES is currently restricted to kernel
885   * (<sys/exec_elf.h> r. 1.155 specifies 15)
886   *
887   * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
888   * information isn't needed.
889   */
890  size_t auxv_size = 100 * sizeof(AuxInfo);
891
892  ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =
893      llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
894
895  struct ptrace_io_desc io;
896  io.piod_op = PIOD_READ_AUXV;
897  io.piod_offs = 0;
898  io.piod_addr = static_cast<void *>(buf.get()->getBufferStart());
899  io.piod_len = auxv_size;
900
901  Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
902
903  if (error.Fail())
904    return std::error_code(error.GetError(), std::generic_category());
905
906  if (io.piod_len < 1)
907    return std::error_code(ECANCELED, std::generic_category());
908
909  return std::move(buf);
910}
911
912Status NativeProcessNetBSD::ReinitializeThreads() {
913  // Clear old threads
914  m_threads.clear();
915
916  // Initialize new thread
917#ifdef PT_LWPSTATUS
918  struct ptrace_lwpstatus info = {};
919  int op = PT_LWPNEXT;
920#else
921  struct ptrace_lwpinfo info = {};
922  int op = PT_LWPINFO;
923#endif
924
925  Status error = PtraceWrapper(op, GetID(), &info, sizeof(info));
926
927  if (error.Fail()) {
928    return error;
929  }
930  // Reinitialize from scratch threads and register them in process
931  while (info.pl_lwpid != 0) {
932    AddThread(info.pl_lwpid);
933    error = PtraceWrapper(op, GetID(), &info, sizeof(info));
934    if (error.Fail()) {
935      return error;
936    }
937  }
938
939  return error;
940}
941