10eae32dcSDimitry Andric //===-- ProcessFreeBSDKernel.cpp ------------------------------------------===//
20eae32dcSDimitry Andric //
30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60eae32dcSDimitry Andric //
70eae32dcSDimitry Andric //===----------------------------------------------------------------------===//
80eae32dcSDimitry Andric
90eae32dcSDimitry Andric #include "lldb/Core/Module.h"
100eae32dcSDimitry Andric #include "lldb/Core/PluginManager.h"
110eae32dcSDimitry Andric #include "lldb/Target/DynamicLoader.h"
120eae32dcSDimitry Andric
135f757f3fSDimitry Andric #include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h"
140eae32dcSDimitry Andric #include "ProcessFreeBSDKernel.h"
150eae32dcSDimitry Andric #include "ThreadFreeBSDKernel.h"
160eae32dcSDimitry Andric
170eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
180eae32dcSDimitry Andric #include <fvc.h>
190eae32dcSDimitry Andric #endif
200eae32dcSDimitry Andric #if defined(__FreeBSD__)
210eae32dcSDimitry Andric #include <kvm.h>
220eae32dcSDimitry Andric #endif
230eae32dcSDimitry Andric
240eae32dcSDimitry Andric using namespace lldb;
250eae32dcSDimitry Andric using namespace lldb_private;
260eae32dcSDimitry Andric
270eae32dcSDimitry Andric LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel)
280eae32dcSDimitry Andric
290eae32dcSDimitry Andric namespace {
300eae32dcSDimitry Andric
310eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
320eae32dcSDimitry Andric class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel {
330eae32dcSDimitry Andric public:
340eae32dcSDimitry Andric ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener,
35*0fca6ea1SDimitry Andric fvc_t *fvc, const FileSpec &core_file);
360eae32dcSDimitry Andric
370eae32dcSDimitry Andric ~ProcessFreeBSDKernelFVC();
380eae32dcSDimitry Andric
390eae32dcSDimitry Andric size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
400eae32dcSDimitry Andric lldb_private::Status &error) override;
410eae32dcSDimitry Andric
420eae32dcSDimitry Andric private:
430eae32dcSDimitry Andric fvc_t *m_fvc;
440eae32dcSDimitry Andric
450eae32dcSDimitry Andric const char *GetError();
460eae32dcSDimitry Andric };
470eae32dcSDimitry Andric #endif // LLDB_ENABLE_FBSDVMCORE
480eae32dcSDimitry Andric
490eae32dcSDimitry Andric #if defined(__FreeBSD__)
500eae32dcSDimitry Andric class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel {
510eae32dcSDimitry Andric public:
520eae32dcSDimitry Andric ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener,
53*0fca6ea1SDimitry Andric kvm_t *fvc, const FileSpec &core_file);
540eae32dcSDimitry Andric
550eae32dcSDimitry Andric ~ProcessFreeBSDKernelKVM();
560eae32dcSDimitry Andric
570eae32dcSDimitry Andric size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
580eae32dcSDimitry Andric lldb_private::Status &error) override;
590eae32dcSDimitry Andric
600eae32dcSDimitry Andric private:
610eae32dcSDimitry Andric kvm_t *m_kvm;
620eae32dcSDimitry Andric
630eae32dcSDimitry Andric const char *GetError();
640eae32dcSDimitry Andric };
650eae32dcSDimitry Andric #endif // defined(__FreeBSD__)
660eae32dcSDimitry Andric
670eae32dcSDimitry Andric } // namespace
680eae32dcSDimitry Andric
ProcessFreeBSDKernel(lldb::TargetSP target_sp,ListenerSP listener_sp,const FileSpec & core_file)690eae32dcSDimitry Andric ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp,
70*0fca6ea1SDimitry Andric ListenerSP listener_sp,
71*0fca6ea1SDimitry Andric const FileSpec &core_file)
72*0fca6ea1SDimitry Andric : PostMortemProcess(target_sp, listener_sp, core_file) {}
730eae32dcSDimitry Andric
CreateInstance(lldb::TargetSP target_sp,ListenerSP listener_sp,const FileSpec * crash_file,bool can_connect)740eae32dcSDimitry Andric lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp,
750eae32dcSDimitry Andric ListenerSP listener_sp,
760eae32dcSDimitry Andric const FileSpec *crash_file,
770eae32dcSDimitry Andric bool can_connect) {
780eae32dcSDimitry Andric ModuleSP executable = target_sp->GetExecutableModule();
790eae32dcSDimitry Andric if (crash_file && !can_connect && executable) {
800eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
810eae32dcSDimitry Andric fvc_t *fvc =
820eae32dcSDimitry Andric fvc_open(executable->GetFileSpec().GetPath().c_str(),
830eae32dcSDimitry Andric crash_file->GetPath().c_str(), nullptr, nullptr, nullptr);
840eae32dcSDimitry Andric if (fvc)
850eae32dcSDimitry Andric return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp,
86*0fca6ea1SDimitry Andric fvc, *crash_file);
870eae32dcSDimitry Andric #endif
880eae32dcSDimitry Andric
890eae32dcSDimitry Andric #if defined(__FreeBSD__)
900eae32dcSDimitry Andric kvm_t *kvm =
910eae32dcSDimitry Andric kvm_open2(executable->GetFileSpec().GetPath().c_str(),
920eae32dcSDimitry Andric crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr);
930eae32dcSDimitry Andric if (kvm)
940eae32dcSDimitry Andric return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp,
95*0fca6ea1SDimitry Andric kvm, *crash_file);
960eae32dcSDimitry Andric #endif
970eae32dcSDimitry Andric }
980eae32dcSDimitry Andric return nullptr;
990eae32dcSDimitry Andric }
1000eae32dcSDimitry Andric
Initialize()1010eae32dcSDimitry Andric void ProcessFreeBSDKernel::Initialize() {
1020eae32dcSDimitry Andric static llvm::once_flag g_once_flag;
1030eae32dcSDimitry Andric
1040eae32dcSDimitry Andric llvm::call_once(g_once_flag, []() {
1050eae32dcSDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
1060eae32dcSDimitry Andric GetPluginDescriptionStatic(), CreateInstance);
1070eae32dcSDimitry Andric });
1080eae32dcSDimitry Andric }
1090eae32dcSDimitry Andric
Terminate()1100eae32dcSDimitry Andric void ProcessFreeBSDKernel::Terminate() {
1110eae32dcSDimitry Andric PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance);
1120eae32dcSDimitry Andric }
1130eae32dcSDimitry Andric
DoDestroy()1140eae32dcSDimitry Andric Status ProcessFreeBSDKernel::DoDestroy() { return Status(); }
1150eae32dcSDimitry Andric
CanDebug(lldb::TargetSP target_sp,bool plugin_specified_by_name)1160eae32dcSDimitry Andric bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp,
1170eae32dcSDimitry Andric bool plugin_specified_by_name) {
1180eae32dcSDimitry Andric return true;
1190eae32dcSDimitry Andric }
1200eae32dcSDimitry Andric
RefreshStateAfterStop()1210eae32dcSDimitry Andric void ProcessFreeBSDKernel::RefreshStateAfterStop() {}
1220eae32dcSDimitry Andric
DoUpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)1230eae32dcSDimitry Andric bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
1240eae32dcSDimitry Andric ThreadList &new_thread_list) {
1250eae32dcSDimitry Andric if (old_thread_list.GetSize(false) == 0) {
1260eae32dcSDimitry Andric // Make up the thread the first time this is called so we can set our one
1270eae32dcSDimitry Andric // and only core thread state up.
1280eae32dcSDimitry Andric
1290eae32dcSDimitry Andric // We cannot construct a thread without a register context as that crashes
1300eae32dcSDimitry Andric // LLDB but we can construct a process without threads to provide minimal
1310eae32dcSDimitry Andric // memory reading support.
1320eae32dcSDimitry Andric switch (GetTarget().GetArchitecture().GetMachine()) {
1330eae32dcSDimitry Andric case llvm::Triple::aarch64:
1340eae32dcSDimitry Andric case llvm::Triple::x86:
1350eae32dcSDimitry Andric case llvm::Triple::x86_64:
1360eae32dcSDimitry Andric break;
1370eae32dcSDimitry Andric default:
1380eae32dcSDimitry Andric return false;
1390eae32dcSDimitry Andric }
1400eae32dcSDimitry Andric
14104eeddc0SDimitry Andric Status error;
14204eeddc0SDimitry Andric
14304eeddc0SDimitry Andric // struct field offsets are written as symbols so that we don't have
14404eeddc0SDimitry Andric // to figure them out ourselves
14504eeddc0SDimitry Andric int32_t offset_p_list = ReadSignedIntegerFromMemory(
14604eeddc0SDimitry Andric FindSymbol("proc_off_p_list"), 4, -1, error);
14704eeddc0SDimitry Andric int32_t offset_p_pid =
14804eeddc0SDimitry Andric ReadSignedIntegerFromMemory(FindSymbol("proc_off_p_pid"), 4, -1, error);
14904eeddc0SDimitry Andric int32_t offset_p_threads = ReadSignedIntegerFromMemory(
15004eeddc0SDimitry Andric FindSymbol("proc_off_p_threads"), 4, -1, error);
15104eeddc0SDimitry Andric int32_t offset_p_comm = ReadSignedIntegerFromMemory(
15204eeddc0SDimitry Andric FindSymbol("proc_off_p_comm"), 4, -1, error);
15304eeddc0SDimitry Andric
15404eeddc0SDimitry Andric int32_t offset_td_tid = ReadSignedIntegerFromMemory(
15504eeddc0SDimitry Andric FindSymbol("thread_off_td_tid"), 4, -1, error);
15604eeddc0SDimitry Andric int32_t offset_td_plist = ReadSignedIntegerFromMemory(
15704eeddc0SDimitry Andric FindSymbol("thread_off_td_plist"), 4, -1, error);
15804eeddc0SDimitry Andric int32_t offset_td_pcb = ReadSignedIntegerFromMemory(
15904eeddc0SDimitry Andric FindSymbol("thread_off_td_pcb"), 4, -1, error);
16004eeddc0SDimitry Andric int32_t offset_td_oncpu = ReadSignedIntegerFromMemory(
16104eeddc0SDimitry Andric FindSymbol("thread_off_td_oncpu"), 4, -1, error);
16204eeddc0SDimitry Andric int32_t offset_td_name = ReadSignedIntegerFromMemory(
16304eeddc0SDimitry Andric FindSymbol("thread_off_td_name"), 4, -1, error);
16404eeddc0SDimitry Andric
16504eeddc0SDimitry Andric // fail if we were not able to read any of the offsets
16604eeddc0SDimitry Andric if (offset_p_list == -1 || offset_p_pid == -1 || offset_p_threads == -1 ||
16704eeddc0SDimitry Andric offset_p_comm == -1 || offset_td_tid == -1 || offset_td_plist == -1 ||
16804eeddc0SDimitry Andric offset_td_pcb == -1 || offset_td_oncpu == -1 || offset_td_name == -1)
16904eeddc0SDimitry Andric return false;
17004eeddc0SDimitry Andric
17104eeddc0SDimitry Andric // dumptid contains the thread-id of the crashing thread
17204eeddc0SDimitry Andric // dumppcb contains its PCB
17304eeddc0SDimitry Andric int32_t dumptid =
17404eeddc0SDimitry Andric ReadSignedIntegerFromMemory(FindSymbol("dumptid"), 4, -1, error);
17504eeddc0SDimitry Andric lldb::addr_t dumppcb = FindSymbol("dumppcb");
17604eeddc0SDimitry Andric
17704eeddc0SDimitry Andric // stoppcbs is an array of PCBs on all CPUs
17804eeddc0SDimitry Andric // each element is of size pcb_size
17904eeddc0SDimitry Andric int32_t pcbsize =
18004eeddc0SDimitry Andric ReadSignedIntegerFromMemory(FindSymbol("pcb_size"), 4, -1, error);
18104eeddc0SDimitry 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);
18704eeddc0SDimitry Andric
18804eeddc0SDimitry Andric // from FreeBSD sys/param.h
18904eeddc0SDimitry Andric constexpr size_t fbsd_maxcomlen = 19;
19004eeddc0SDimitry Andric
19104eeddc0SDimitry Andric // iterate through a linked list of all processes
19204eeddc0SDimitry Andric // allproc is a pointer to the first list element, p_list field
19304eeddc0SDimitry Andric // (found at offset_p_list) specifies the next element
19404eeddc0SDimitry Andric for (lldb::addr_t proc =
19504eeddc0SDimitry Andric ReadPointerFromMemory(FindSymbol("allproc"), error);
19604eeddc0SDimitry Andric proc != 0 && proc != LLDB_INVALID_ADDRESS;
19704eeddc0SDimitry Andric proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
19804eeddc0SDimitry Andric int32_t pid =
19904eeddc0SDimitry Andric ReadSignedIntegerFromMemory(proc + offset_p_pid, 4, -1, error);
20004eeddc0SDimitry Andric // process' command-line string
20104eeddc0SDimitry Andric char comm[fbsd_maxcomlen + 1];
20204eeddc0SDimitry Andric ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error);
20304eeddc0SDimitry Andric
20404eeddc0SDimitry Andric // iterate through a linked list of all process' threads
20504eeddc0SDimitry Andric // the initial thread is found in process' p_threads, subsequent
20604eeddc0SDimitry Andric // elements are linked via td_plist field
20704eeddc0SDimitry Andric for (lldb::addr_t td =
20804eeddc0SDimitry Andric ReadPointerFromMemory(proc + offset_p_threads, error);
20904eeddc0SDimitry Andric td != 0; td = ReadPointerFromMemory(td + offset_td_plist, error)) {
21004eeddc0SDimitry Andric int32_t tid =
21104eeddc0SDimitry Andric ReadSignedIntegerFromMemory(td + offset_td_tid, 4, -1, error);
21204eeddc0SDimitry Andric lldb::addr_t pcb_addr =
21304eeddc0SDimitry Andric ReadPointerFromMemory(td + offset_td_pcb, error);
21404eeddc0SDimitry Andric // whether process was on CPU (-1 if not, otherwise CPU number)
21504eeddc0SDimitry Andric int32_t oncpu =
21604eeddc0SDimitry Andric ReadSignedIntegerFromMemory(td + offset_td_oncpu, 4, -2, error);
21704eeddc0SDimitry Andric // thread name
21804eeddc0SDimitry Andric char thread_name[fbsd_maxcomlen + 1];
21904eeddc0SDimitry Andric ReadCStringFromMemory(td + offset_td_name, thread_name,
22004eeddc0SDimitry Andric sizeof(thread_name), error);
22104eeddc0SDimitry Andric
22204eeddc0SDimitry Andric // if we failed to read TID, ignore this thread
22304eeddc0SDimitry Andric if (tid == -1)
22404eeddc0SDimitry Andric continue;
22504eeddc0SDimitry Andric
22604eeddc0SDimitry Andric std::string thread_desc = llvm::formatv("(pid {0}) {1}", pid, comm);
22704eeddc0SDimitry Andric if (*thread_name && strcmp(thread_name, comm)) {
22804eeddc0SDimitry Andric thread_desc += '/';
22904eeddc0SDimitry Andric thread_desc += thread_name;
23004eeddc0SDimitry Andric }
23104eeddc0SDimitry Andric
23204eeddc0SDimitry Andric // roughly:
23304eeddc0SDimitry Andric // 1. if the thread crashed, its PCB is going to be at "dumppcb"
23404eeddc0SDimitry Andric // 2. if the thread was on CPU, its PCB is going to be on the CPU
23504eeddc0SDimitry Andric // 3. otherwise, its PCB is in the thread struct
23604eeddc0SDimitry Andric if (tid == dumptid) {
23704eeddc0SDimitry Andric // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed
23804eeddc0SDimitry Andric pcb_addr = dumppcb;
23904eeddc0SDimitry Andric thread_desc += " (crashed)";
24004eeddc0SDimitry Andric } else if (oncpu != -1) {
24104eeddc0SDimitry Andric // if we managed to read stoppcbs and pcb_size, use them to find
24204eeddc0SDimitry Andric // the correct PCB
24304eeddc0SDimitry Andric if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0)
24404eeddc0SDimitry Andric pcb_addr = stoppcbs + oncpu * pcbsize;
24504eeddc0SDimitry Andric else
24604eeddc0SDimitry Andric pcb_addr = LLDB_INVALID_ADDRESS;
24704eeddc0SDimitry Andric thread_desc += llvm::formatv(" (on CPU {0})", oncpu);
24804eeddc0SDimitry Andric }
24904eeddc0SDimitry Andric
25004eeddc0SDimitry Andric ThreadSP thread_sp{
25104eeddc0SDimitry Andric new ThreadFreeBSDKernel(*this, tid, pcb_addr, thread_desc)};
2520eae32dcSDimitry Andric new_thread_list.AddThread(thread_sp);
25304eeddc0SDimitry Andric }
25404eeddc0SDimitry Andric }
2550eae32dcSDimitry Andric } else {
2560eae32dcSDimitry Andric const uint32_t num_threads = old_thread_list.GetSize(false);
2570eae32dcSDimitry Andric for (uint32_t i = 0; i < num_threads; ++i)
2580eae32dcSDimitry Andric new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));
2590eae32dcSDimitry Andric }
2600eae32dcSDimitry Andric return new_thread_list.GetSize(false) > 0;
2610eae32dcSDimitry Andric }
2620eae32dcSDimitry Andric
DoLoadCore()2630eae32dcSDimitry Andric Status ProcessFreeBSDKernel::DoLoadCore() {
2640eae32dcSDimitry Andric // The core is already loaded by CreateInstance().
2650eae32dcSDimitry Andric return Status();
2660eae32dcSDimitry Andric }
2670eae32dcSDimitry Andric
GetDynamicLoader()2680eae32dcSDimitry Andric DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
2690eae32dcSDimitry Andric if (m_dyld_up.get() == nullptr)
2700eae32dcSDimitry Andric m_dyld_up.reset(DynamicLoader::FindPlugin(
2715f757f3fSDimitry Andric this, DynamicLoaderFreeBSDKernel::GetPluginNameStatic()));
2720eae32dcSDimitry Andric return m_dyld_up.get();
2730eae32dcSDimitry Andric }
2740eae32dcSDimitry Andric
FindSymbol(const char * name)27504eeddc0SDimitry Andric lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) {
27604eeddc0SDimitry Andric ModuleSP mod_sp = GetTarget().GetExecutableModule();
27704eeddc0SDimitry Andric const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name));
27804eeddc0SDimitry Andric return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
27904eeddc0SDimitry Andric }
28004eeddc0SDimitry Andric
2810eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE
2820eae32dcSDimitry Andric
ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,ListenerSP listener_sp,fvc_t * fvc,const FileSpec & core_file)2830eae32dcSDimitry Andric ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,
2840eae32dcSDimitry Andric ListenerSP listener_sp,
285*0fca6ea1SDimitry Andric fvc_t *fvc,
286*0fca6ea1SDimitry Andric const FileSpec &core_file)
287*0fca6ea1SDimitry Andric : ProcessFreeBSDKernel(target_sp, listener_sp, crash_file), m_fvc(fvc) {}
2880eae32dcSDimitry Andric
~ProcessFreeBSDKernelFVC()2890eae32dcSDimitry Andric ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() {
2900eae32dcSDimitry Andric if (m_fvc)
2910eae32dcSDimitry Andric fvc_close(m_fvc);
2920eae32dcSDimitry Andric }
2930eae32dcSDimitry Andric
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)2940eae32dcSDimitry Andric size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf,
2950eae32dcSDimitry Andric size_t size, Status &error) {
2960eae32dcSDimitry Andric ssize_t rd = 0;
2970eae32dcSDimitry Andric rd = fvc_read(m_fvc, addr, buf, size);
2980eae32dcSDimitry Andric if (rd < 0 || static_cast<size_t>(rd) != size) {
2990eae32dcSDimitry Andric error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
3000eae32dcSDimitry Andric return rd > 0 ? rd : 0;
3010eae32dcSDimitry Andric }
3020eae32dcSDimitry Andric return rd;
3030eae32dcSDimitry Andric }
3040eae32dcSDimitry Andric
GetError()3050eae32dcSDimitry Andric const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); }
3060eae32dcSDimitry Andric
3070eae32dcSDimitry Andric #endif // LLDB_ENABLE_FBSDVMCORE
3080eae32dcSDimitry Andric
3090eae32dcSDimitry Andric #if defined(__FreeBSD__)
3100eae32dcSDimitry Andric
ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,ListenerSP listener_sp,kvm_t * fvc,const FileSpec & core_file)3110eae32dcSDimitry Andric ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,
3120eae32dcSDimitry Andric ListenerSP listener_sp,
313*0fca6ea1SDimitry Andric kvm_t *fvc,
314*0fca6ea1SDimitry Andric const FileSpec &core_file)
315*0fca6ea1SDimitry Andric : ProcessFreeBSDKernel(target_sp, listener_sp, core_file), m_kvm(fvc) {}
3160eae32dcSDimitry Andric
~ProcessFreeBSDKernelKVM()3170eae32dcSDimitry Andric ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() {
3180eae32dcSDimitry Andric if (m_kvm)
3190eae32dcSDimitry Andric kvm_close(m_kvm);
3200eae32dcSDimitry Andric }
3210eae32dcSDimitry Andric
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)3220eae32dcSDimitry Andric size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf,
3230eae32dcSDimitry Andric size_t size, Status &error) {
3240eae32dcSDimitry Andric ssize_t rd = 0;
3250eae32dcSDimitry Andric rd = kvm_read2(m_kvm, addr, buf, size);
3260eae32dcSDimitry Andric if (rd < 0 || static_cast<size_t>(rd) != size) {
3270eae32dcSDimitry Andric error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
3280eae32dcSDimitry Andric return rd > 0 ? rd : 0;
3290eae32dcSDimitry Andric }
3300eae32dcSDimitry Andric return rd;
3310eae32dcSDimitry Andric }
3320eae32dcSDimitry Andric
GetError()3330eae32dcSDimitry Andric const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
3340eae32dcSDimitry Andric
3350eae32dcSDimitry Andric #endif // defined(__FreeBSD__)
336