xref: /src/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
177fc4c14SDimitry Andric //===-- ProcessFreeBSDKernel.cpp ------------------------------------------===//
277fc4c14SDimitry Andric //
377fc4c14SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
477fc4c14SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
577fc4c14SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
677fc4c14SDimitry Andric //
777fc4c14SDimitry Andric //===----------------------------------------------------------------------===//
877fc4c14SDimitry Andric 
977fc4c14SDimitry Andric #include "lldb/Core/Module.h"
1077fc4c14SDimitry Andric #include "lldb/Core/PluginManager.h"
1177fc4c14SDimitry Andric #include "lldb/Target/DynamicLoader.h"
1277fc4c14SDimitry Andric 
135f757f3fSDimitry Andric #include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h"
1477fc4c14SDimitry Andric #include "ProcessFreeBSDKernel.h"
1577fc4c14SDimitry Andric #include "ThreadFreeBSDKernel.h"
1677fc4c14SDimitry Andric 
1777fc4c14SDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
1877fc4c14SDimitry Andric #include <fvc.h>
1977fc4c14SDimitry Andric #endif
2077fc4c14SDimitry Andric #if defined(__FreeBSD__)
2177fc4c14SDimitry Andric #include <kvm.h>
2277fc4c14SDimitry Andric #endif
2377fc4c14SDimitry Andric 
2477fc4c14SDimitry Andric using namespace lldb;
2577fc4c14SDimitry Andric using namespace lldb_private;
2677fc4c14SDimitry Andric 
2777fc4c14SDimitry Andric LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel)
2877fc4c14SDimitry Andric 
2977fc4c14SDimitry Andric namespace {
3077fc4c14SDimitry Andric 
3177fc4c14SDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
3277fc4c14SDimitry Andric class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel {
3377fc4c14SDimitry Andric public:
3477fc4c14SDimitry Andric   ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener,
350fca6ea1SDimitry Andric                           fvc_t *fvc, const FileSpec &core_file);
3677fc4c14SDimitry Andric 
3777fc4c14SDimitry Andric   ~ProcessFreeBSDKernelFVC();
3877fc4c14SDimitry Andric 
3977fc4c14SDimitry Andric   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
4077fc4c14SDimitry Andric                       lldb_private::Status &error) override;
4177fc4c14SDimitry Andric 
4277fc4c14SDimitry Andric private:
4377fc4c14SDimitry Andric   fvc_t *m_fvc;
4477fc4c14SDimitry Andric 
4577fc4c14SDimitry Andric   const char *GetError();
4677fc4c14SDimitry Andric };
4777fc4c14SDimitry Andric #endif // LLDB_ENABLE_FBSDVMCORE
4877fc4c14SDimitry Andric 
4977fc4c14SDimitry Andric #if defined(__FreeBSD__)
5077fc4c14SDimitry Andric class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel {
5177fc4c14SDimitry Andric public:
5277fc4c14SDimitry Andric   ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener,
530fca6ea1SDimitry Andric                           kvm_t *fvc, const FileSpec &core_file);
5477fc4c14SDimitry Andric 
5577fc4c14SDimitry Andric   ~ProcessFreeBSDKernelKVM();
5677fc4c14SDimitry Andric 
5777fc4c14SDimitry Andric   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
5877fc4c14SDimitry Andric                       lldb_private::Status &error) override;
5977fc4c14SDimitry Andric 
6077fc4c14SDimitry Andric private:
6177fc4c14SDimitry Andric   kvm_t *m_kvm;
6277fc4c14SDimitry Andric 
6377fc4c14SDimitry Andric   const char *GetError();
6477fc4c14SDimitry Andric };
6577fc4c14SDimitry Andric #endif // defined(__FreeBSD__)
6677fc4c14SDimitry Andric 
6777fc4c14SDimitry Andric } // namespace
6877fc4c14SDimitry Andric 
ProcessFreeBSDKernel(lldb::TargetSP target_sp,ListenerSP listener_sp,const FileSpec & core_file)6977fc4c14SDimitry Andric ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp,
700fca6ea1SDimitry Andric                                            ListenerSP listener_sp,
710fca6ea1SDimitry Andric                                            const FileSpec &core_file)
720fca6ea1SDimitry Andric     : PostMortemProcess(target_sp, listener_sp, core_file) {}
7377fc4c14SDimitry Andric 
CreateInstance(lldb::TargetSP target_sp,ListenerSP listener_sp,const FileSpec * crash_file,bool can_connect)7477fc4c14SDimitry Andric lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp,
7577fc4c14SDimitry Andric                                                      ListenerSP listener_sp,
7677fc4c14SDimitry Andric                                                      const FileSpec *crash_file,
7777fc4c14SDimitry Andric                                                      bool can_connect) {
7877fc4c14SDimitry Andric   ModuleSP executable = target_sp->GetExecutableModule();
7977fc4c14SDimitry Andric   if (crash_file && !can_connect && executable) {
8077fc4c14SDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
8177fc4c14SDimitry Andric     fvc_t *fvc =
8277fc4c14SDimitry Andric         fvc_open(executable->GetFileSpec().GetPath().c_str(),
8377fc4c14SDimitry Andric                  crash_file->GetPath().c_str(), nullptr, nullptr, nullptr);
8477fc4c14SDimitry Andric     if (fvc)
8577fc4c14SDimitry Andric       return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp,
860fca6ea1SDimitry Andric                                                        fvc, *crash_file);
8777fc4c14SDimitry Andric #endif
8877fc4c14SDimitry Andric 
8977fc4c14SDimitry Andric #if defined(__FreeBSD__)
9077fc4c14SDimitry Andric     kvm_t *kvm =
9177fc4c14SDimitry Andric         kvm_open2(executable->GetFileSpec().GetPath().c_str(),
9277fc4c14SDimitry Andric                   crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr);
9377fc4c14SDimitry Andric     if (kvm)
9477fc4c14SDimitry Andric       return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp,
950fca6ea1SDimitry Andric                                                        kvm, *crash_file);
9677fc4c14SDimitry Andric #endif
9777fc4c14SDimitry Andric   }
9877fc4c14SDimitry Andric   return nullptr;
9977fc4c14SDimitry Andric }
10077fc4c14SDimitry Andric 
Initialize()10177fc4c14SDimitry Andric void ProcessFreeBSDKernel::Initialize() {
10277fc4c14SDimitry Andric   static llvm::once_flag g_once_flag;
10377fc4c14SDimitry Andric 
10477fc4c14SDimitry Andric   llvm::call_once(g_once_flag, []() {
10577fc4c14SDimitry Andric     PluginManager::RegisterPlugin(GetPluginNameStatic(),
10677fc4c14SDimitry Andric                                   GetPluginDescriptionStatic(), CreateInstance);
10777fc4c14SDimitry Andric   });
10877fc4c14SDimitry Andric }
10977fc4c14SDimitry Andric 
Terminate()11077fc4c14SDimitry Andric void ProcessFreeBSDKernel::Terminate() {
11177fc4c14SDimitry Andric   PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance);
11277fc4c14SDimitry Andric }
11377fc4c14SDimitry Andric 
DoDestroy()11477fc4c14SDimitry Andric Status ProcessFreeBSDKernel::DoDestroy() { return Status(); }
11577fc4c14SDimitry Andric 
CanDebug(lldb::TargetSP target_sp,bool plugin_specified_by_name)11677fc4c14SDimitry Andric bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp,
11777fc4c14SDimitry Andric                                     bool plugin_specified_by_name) {
11877fc4c14SDimitry Andric   return true;
11977fc4c14SDimitry Andric }
12077fc4c14SDimitry Andric 
RefreshStateAfterStop()12177fc4c14SDimitry Andric void ProcessFreeBSDKernel::RefreshStateAfterStop() {}
12277fc4c14SDimitry Andric 
DoUpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)12377fc4c14SDimitry Andric bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
12477fc4c14SDimitry Andric                                               ThreadList &new_thread_list) {
12577fc4c14SDimitry Andric   if (old_thread_list.GetSize(false) == 0) {
12677fc4c14SDimitry Andric     // Make up the thread the first time this is called so we can set our one
12777fc4c14SDimitry Andric     // and only core thread state up.
12877fc4c14SDimitry Andric 
12977fc4c14SDimitry Andric     // We cannot construct a thread without a register context as that crashes
13077fc4c14SDimitry Andric     // LLDB but we can construct a process without threads to provide minimal
13177fc4c14SDimitry Andric     // memory reading support.
13277fc4c14SDimitry Andric     switch (GetTarget().GetArchitecture().GetMachine()) {
13377fc4c14SDimitry Andric     case llvm::Triple::aarch64:
13477fc4c14SDimitry Andric     case llvm::Triple::x86:
13577fc4c14SDimitry Andric     case llvm::Triple::x86_64:
13677fc4c14SDimitry Andric       break;
13777fc4c14SDimitry Andric     default:
13877fc4c14SDimitry Andric       return false;
13977fc4c14SDimitry Andric     }
14077fc4c14SDimitry Andric 
1416f8fc217SDimitry Andric     Status error;
1426f8fc217SDimitry Andric 
1436f8fc217SDimitry Andric     // struct field offsets are written as symbols so that we don't have
1446f8fc217SDimitry Andric     // to figure them out ourselves
1456f8fc217SDimitry Andric     int32_t offset_p_list = ReadSignedIntegerFromMemory(
1466f8fc217SDimitry Andric         FindSymbol("proc_off_p_list"), 4, -1, error);
1476f8fc217SDimitry Andric     int32_t offset_p_pid =
1486f8fc217SDimitry Andric         ReadSignedIntegerFromMemory(FindSymbol("proc_off_p_pid"), 4, -1, error);
1496f8fc217SDimitry Andric     int32_t offset_p_threads = ReadSignedIntegerFromMemory(
1506f8fc217SDimitry Andric         FindSymbol("proc_off_p_threads"), 4, -1, error);
1516f8fc217SDimitry Andric     int32_t offset_p_comm = ReadSignedIntegerFromMemory(
1526f8fc217SDimitry Andric         FindSymbol("proc_off_p_comm"), 4, -1, error);
1536f8fc217SDimitry Andric 
1546f8fc217SDimitry Andric     int32_t offset_td_tid = ReadSignedIntegerFromMemory(
1556f8fc217SDimitry Andric         FindSymbol("thread_off_td_tid"), 4, -1, error);
1566f8fc217SDimitry Andric     int32_t offset_td_plist = ReadSignedIntegerFromMemory(
1576f8fc217SDimitry Andric         FindSymbol("thread_off_td_plist"), 4, -1, error);
1586f8fc217SDimitry Andric     int32_t offset_td_pcb = ReadSignedIntegerFromMemory(
1596f8fc217SDimitry Andric         FindSymbol("thread_off_td_pcb"), 4, -1, error);
1606f8fc217SDimitry Andric     int32_t offset_td_oncpu = ReadSignedIntegerFromMemory(
1616f8fc217SDimitry Andric         FindSymbol("thread_off_td_oncpu"), 4, -1, error);
1626f8fc217SDimitry Andric     int32_t offset_td_name = ReadSignedIntegerFromMemory(
1636f8fc217SDimitry Andric         FindSymbol("thread_off_td_name"), 4, -1, error);
1646f8fc217SDimitry Andric 
1656f8fc217SDimitry Andric     // fail if we were not able to read any of the offsets
1666f8fc217SDimitry Andric     if (offset_p_list == -1 || offset_p_pid == -1 || offset_p_threads == -1 ||
1676f8fc217SDimitry Andric         offset_p_comm == -1 || offset_td_tid == -1 || offset_td_plist == -1 ||
1686f8fc217SDimitry Andric         offset_td_pcb == -1 || offset_td_oncpu == -1 || offset_td_name == -1)
1696f8fc217SDimitry Andric       return false;
1706f8fc217SDimitry Andric 
1716f8fc217SDimitry Andric     // dumptid contains the thread-id of the crashing thread
1726f8fc217SDimitry Andric     // dumppcb contains its PCB
1736f8fc217SDimitry Andric     int32_t dumptid =
1746f8fc217SDimitry Andric         ReadSignedIntegerFromMemory(FindSymbol("dumptid"), 4, -1, error);
1756f8fc217SDimitry Andric     lldb::addr_t dumppcb = FindSymbol("dumppcb");
1766f8fc217SDimitry Andric 
1776f8fc217SDimitry Andric     // stoppcbs is an array of PCBs on all CPUs
1786f8fc217SDimitry Andric     // each element is of size pcb_size
1796f8fc217SDimitry Andric     int32_t pcbsize =
1806f8fc217SDimitry Andric         ReadSignedIntegerFromMemory(FindSymbol("pcb_size"), 4, -1, error);
1816f8fc217SDimitry Andric     lldb::addr_t stoppcbs = FindSymbol("stoppcbs");
1820f2bb40bSEd Maste     // In later FreeBSD versions stoppcbs is a pointer to the array.
1830f2bb40bSEd Maste     int32_t osreldate =
1840f2bb40bSEd Maste         ReadSignedIntegerFromMemory(FindSymbol("osreldate"), 4, -1, error);
1850f2bb40bSEd Maste     if (stoppcbs != LLDB_INVALID_ADDRESS && osreldate >= 1400089)
1860f2bb40bSEd Maste         stoppcbs = ReadPointerFromMemory(stoppcbs, error);
1876f8fc217SDimitry Andric 
1886f8fc217SDimitry Andric     // from FreeBSD sys/param.h
1896f8fc217SDimitry Andric     constexpr size_t fbsd_maxcomlen = 19;
1906f8fc217SDimitry Andric 
1916f8fc217SDimitry Andric     // iterate through a linked list of all processes
1926f8fc217SDimitry Andric     // allproc is a pointer to the first list element, p_list field
1936f8fc217SDimitry Andric     // (found at offset_p_list) specifies the next element
1946f8fc217SDimitry Andric     for (lldb::addr_t proc =
1956f8fc217SDimitry Andric              ReadPointerFromMemory(FindSymbol("allproc"), error);
1966f8fc217SDimitry Andric          proc != 0 && proc != LLDB_INVALID_ADDRESS;
1976f8fc217SDimitry Andric          proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
1986f8fc217SDimitry Andric       int32_t pid =
1996f8fc217SDimitry Andric           ReadSignedIntegerFromMemory(proc + offset_p_pid, 4, -1, error);
2006f8fc217SDimitry Andric       // process' command-line string
2016f8fc217SDimitry Andric       char comm[fbsd_maxcomlen + 1];
2026f8fc217SDimitry Andric       ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error);
2036f8fc217SDimitry Andric 
2046f8fc217SDimitry Andric       // iterate through a linked list of all process' threads
2056f8fc217SDimitry Andric       // the initial thread is found in process' p_threads, subsequent
2066f8fc217SDimitry Andric       // elements are linked via td_plist field
2076f8fc217SDimitry Andric       for (lldb::addr_t td =
2086f8fc217SDimitry Andric                ReadPointerFromMemory(proc + offset_p_threads, error);
2096f8fc217SDimitry Andric            td != 0; td = ReadPointerFromMemory(td + offset_td_plist, error)) {
2106f8fc217SDimitry Andric         int32_t tid =
2116f8fc217SDimitry Andric             ReadSignedIntegerFromMemory(td + offset_td_tid, 4, -1, error);
2126f8fc217SDimitry Andric         lldb::addr_t pcb_addr =
2136f8fc217SDimitry Andric             ReadPointerFromMemory(td + offset_td_pcb, error);
2146f8fc217SDimitry Andric         // whether process was on CPU (-1 if not, otherwise CPU number)
2156f8fc217SDimitry Andric         int32_t oncpu =
2166f8fc217SDimitry Andric             ReadSignedIntegerFromMemory(td + offset_td_oncpu, 4, -2, error);
2176f8fc217SDimitry Andric         // thread name
2186f8fc217SDimitry Andric         char thread_name[fbsd_maxcomlen + 1];
2196f8fc217SDimitry Andric         ReadCStringFromMemory(td + offset_td_name, thread_name,
2206f8fc217SDimitry Andric                               sizeof(thread_name), error);
2216f8fc217SDimitry Andric 
2226f8fc217SDimitry Andric         // if we failed to read TID, ignore this thread
2236f8fc217SDimitry Andric         if (tid == -1)
2246f8fc217SDimitry Andric           continue;
2256f8fc217SDimitry Andric 
2266f8fc217SDimitry Andric         std::string thread_desc = llvm::formatv("(pid {0}) {1}", pid, comm);
2276f8fc217SDimitry Andric         if (*thread_name && strcmp(thread_name, comm)) {
2286f8fc217SDimitry Andric           thread_desc += '/';
2296f8fc217SDimitry Andric           thread_desc += thread_name;
2306f8fc217SDimitry Andric         }
2316f8fc217SDimitry Andric 
2326f8fc217SDimitry Andric         // roughly:
2336f8fc217SDimitry Andric         // 1. if the thread crashed, its PCB is going to be at "dumppcb"
2346f8fc217SDimitry Andric         // 2. if the thread was on CPU, its PCB is going to be on the CPU
2356f8fc217SDimitry Andric         // 3. otherwise, its PCB is in the thread struct
2366f8fc217SDimitry Andric         if (tid == dumptid) {
2376f8fc217SDimitry Andric           // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed
2386f8fc217SDimitry Andric           pcb_addr = dumppcb;
2396f8fc217SDimitry Andric           thread_desc += " (crashed)";
2406f8fc217SDimitry Andric         } else if (oncpu != -1) {
2416f8fc217SDimitry Andric           // if we managed to read stoppcbs and pcb_size, use them to find
2426f8fc217SDimitry Andric           // the correct PCB
2436f8fc217SDimitry Andric           if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0)
2446f8fc217SDimitry Andric             pcb_addr = stoppcbs + oncpu * pcbsize;
2456f8fc217SDimitry Andric           else
2466f8fc217SDimitry Andric             pcb_addr = LLDB_INVALID_ADDRESS;
2476f8fc217SDimitry Andric           thread_desc += llvm::formatv(" (on CPU {0})", oncpu);
2486f8fc217SDimitry Andric         }
2496f8fc217SDimitry Andric 
2506f8fc217SDimitry Andric         ThreadSP thread_sp{
2516f8fc217SDimitry Andric             new ThreadFreeBSDKernel(*this, tid, pcb_addr, thread_desc)};
25277fc4c14SDimitry Andric         new_thread_list.AddThread(thread_sp);
2536f8fc217SDimitry Andric       }
2546f8fc217SDimitry Andric     }
25577fc4c14SDimitry Andric   } else {
25677fc4c14SDimitry Andric     const uint32_t num_threads = old_thread_list.GetSize(false);
25777fc4c14SDimitry Andric     for (uint32_t i = 0; i < num_threads; ++i)
25877fc4c14SDimitry Andric       new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));
25977fc4c14SDimitry Andric   }
26077fc4c14SDimitry Andric   return new_thread_list.GetSize(false) > 0;
26177fc4c14SDimitry Andric }
26277fc4c14SDimitry Andric 
DoLoadCore()26377fc4c14SDimitry Andric Status ProcessFreeBSDKernel::DoLoadCore() {
26477fc4c14SDimitry Andric   // The core is already loaded by CreateInstance().
26577fc4c14SDimitry Andric   return Status();
26677fc4c14SDimitry Andric }
26777fc4c14SDimitry Andric 
GetDynamicLoader()26877fc4c14SDimitry Andric DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
26977fc4c14SDimitry Andric   if (m_dyld_up.get() == nullptr)
27077fc4c14SDimitry Andric     m_dyld_up.reset(DynamicLoader::FindPlugin(
2715f757f3fSDimitry Andric         this, DynamicLoaderFreeBSDKernel::GetPluginNameStatic()));
27277fc4c14SDimitry Andric   return m_dyld_up.get();
27377fc4c14SDimitry Andric }
27477fc4c14SDimitry Andric 
FindSymbol(const char * name)2756f8fc217SDimitry Andric lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) {
2766f8fc217SDimitry Andric   ModuleSP mod_sp = GetTarget().GetExecutableModule();
2776f8fc217SDimitry Andric   const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name));
2786f8fc217SDimitry Andric   return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
2796f8fc217SDimitry Andric }
2806f8fc217SDimitry Andric 
28177fc4c14SDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
28277fc4c14SDimitry Andric 
ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,ListenerSP listener_sp,fvc_t * fvc,const FileSpec & core_file)28377fc4c14SDimitry Andric ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,
28477fc4c14SDimitry Andric                                                  ListenerSP listener_sp,
2850fca6ea1SDimitry Andric                                                  fvc_t *fvc,
2860fca6ea1SDimitry Andric                                                  const FileSpec &core_file)
2870fca6ea1SDimitry Andric     : ProcessFreeBSDKernel(target_sp, listener_sp, crash_file), m_fvc(fvc) {}
28877fc4c14SDimitry Andric 
~ProcessFreeBSDKernelFVC()28977fc4c14SDimitry Andric ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() {
29077fc4c14SDimitry Andric   if (m_fvc)
29177fc4c14SDimitry Andric     fvc_close(m_fvc);
29277fc4c14SDimitry Andric }
29377fc4c14SDimitry Andric 
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)29477fc4c14SDimitry Andric size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf,
29577fc4c14SDimitry Andric                                              size_t size, Status &error) {
29677fc4c14SDimitry Andric   ssize_t rd = 0;
29777fc4c14SDimitry Andric   rd = fvc_read(m_fvc, addr, buf, size);
29877fc4c14SDimitry Andric   if (rd < 0 || static_cast<size_t>(rd) != size) {
29977fc4c14SDimitry Andric     error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
30077fc4c14SDimitry Andric     return rd > 0 ? rd : 0;
30177fc4c14SDimitry Andric   }
30277fc4c14SDimitry Andric   return rd;
30377fc4c14SDimitry Andric }
30477fc4c14SDimitry Andric 
GetError()30577fc4c14SDimitry Andric const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); }
30677fc4c14SDimitry Andric 
30777fc4c14SDimitry Andric #endif // LLDB_ENABLE_FBSDVMCORE
30877fc4c14SDimitry Andric 
30977fc4c14SDimitry Andric #if defined(__FreeBSD__)
31077fc4c14SDimitry Andric 
ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,ListenerSP listener_sp,kvm_t * fvc,const FileSpec & core_file)31177fc4c14SDimitry Andric ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,
31277fc4c14SDimitry Andric                                                  ListenerSP listener_sp,
3130fca6ea1SDimitry Andric                                                  kvm_t *fvc,
3140fca6ea1SDimitry Andric                                                  const FileSpec &core_file)
3150fca6ea1SDimitry Andric     : ProcessFreeBSDKernel(target_sp, listener_sp, core_file), m_kvm(fvc) {}
31677fc4c14SDimitry Andric 
~ProcessFreeBSDKernelKVM()31777fc4c14SDimitry Andric ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() {
31877fc4c14SDimitry Andric   if (m_kvm)
31977fc4c14SDimitry Andric     kvm_close(m_kvm);
32077fc4c14SDimitry Andric }
32177fc4c14SDimitry Andric 
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)32277fc4c14SDimitry Andric size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf,
32377fc4c14SDimitry Andric                                              size_t size, Status &error) {
32477fc4c14SDimitry Andric   ssize_t rd = 0;
32577fc4c14SDimitry Andric   rd = kvm_read2(m_kvm, addr, buf, size);
32677fc4c14SDimitry Andric   if (rd < 0 || static_cast<size_t>(rd) != size) {
32777fc4c14SDimitry Andric     error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
32877fc4c14SDimitry Andric     return rd > 0 ? rd : 0;
32977fc4c14SDimitry Andric   }
33077fc4c14SDimitry Andric   return rd;
33177fc4c14SDimitry Andric }
33277fc4c14SDimitry Andric 
GetError()33377fc4c14SDimitry Andric const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
33477fc4c14SDimitry Andric 
33577fc4c14SDimitry Andric #endif // defined(__FreeBSD__)
336