summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
blob: 327e25acd5895ae030d12bbc8808949b47c5f99d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//===-- ProcessFreeBSDKernel.cpp ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/DynamicLoader.h"

#include "ProcessFreeBSDKernel.h"
#include "ThreadFreeBSDKernel.h"
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"

#include <fvc.h>

using namespace lldb;
using namespace lldb_private;

LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel)

ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp,
                                           ListenerSP listener_sp,
                                           const FileSpec &core_file, void *fvc)
    : PostMortemProcess(target_sp, listener_sp), m_fvc(fvc) {}

ProcessFreeBSDKernel::~ProcessFreeBSDKernel() {
  if (m_fvc)
    fvc_close(static_cast<fvc_t *>(m_fvc));
}

lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp,
                                                     ListenerSP listener_sp,
                                                     const FileSpec *crash_file,
                                                     bool can_connect) {
  lldb::ProcessSP process_sp;
  ModuleSP executable = target_sp->GetExecutableModule();
  if (crash_file && !can_connect && executable) {
    fvc_t *fvc = fvc_open(
        executable->GetFileSpec().GetPath().c_str(),
        crash_file->GetPath().c_str(), nullptr, nullptr, nullptr);
    if (fvc)
      process_sp = std::make_shared<ProcessFreeBSDKernel>(
          target_sp, listener_sp, *crash_file, fvc);
  }
  return process_sp;
}

void ProcessFreeBSDKernel::Initialize() {
  static llvm::once_flag g_once_flag;

  llvm::call_once(g_once_flag, []() {
    PluginManager::RegisterPlugin(GetPluginNameStatic(),
                                  GetPluginDescriptionStatic(), CreateInstance);
  });
}

void ProcessFreeBSDKernel::Terminate() {
  PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance);
}

Status ProcessFreeBSDKernel::DoDestroy() { return Status(); }

bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp,
                                    bool plugin_specified_by_name) {
  return true;
}

void ProcessFreeBSDKernel::RefreshStateAfterStop() {}

bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
                                              ThreadList &new_thread_list) {
  if (old_thread_list.GetSize(false) == 0) {
    // Make up the thread the first time this is called so we can set our one
    // and only core thread state up.

    // We cannot construct a thread without a register context as that crashes
    // LLDB but we can construct a process without threads to provide minimal
    // memory reading support.
    switch (GetTarget().GetArchitecture().GetMachine()) {
    case llvm::Triple::aarch64:
    case llvm::Triple::x86:
    case llvm::Triple::x86_64:
      break;
    default:
      return false;
    }

    const Symbol *pcb_sym =
        GetTarget().GetExecutableModule()->FindFirstSymbolWithNameAndType(
            ConstString("dumppcb"));
    ThreadSP thread_sp(new ThreadFreeBSDKernel(
        *this, 1, pcb_sym ? pcb_sym->GetFileAddress() : LLDB_INVALID_ADDRESS));
    new_thread_list.AddThread(thread_sp);
  } else {
    const uint32_t num_threads = old_thread_list.GetSize(false);
    for (uint32_t i = 0; i < num_threads; ++i)
      new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));
  }
  return new_thread_list.GetSize(false) > 0;
}

Status ProcessFreeBSDKernel::DoLoadCore() {
  // The core is already loaded by CreateInstance().
  return Status();
}

size_t ProcessFreeBSDKernel::DoReadMemory(lldb::addr_t addr, void *buf,
                                          size_t size, Status &error) {
  ssize_t rd = fvc_read(static_cast<fvc_t *>(m_fvc), addr, buf, size);
  if (rd < 0 || static_cast<size_t>(rd) != size) {
    error.SetErrorStringWithFormat("Reading memory failed: %s",
                                   fvc_geterr(static_cast<fvc_t *>(m_fvc)));
    return rd > 0 ? rd : 0;
  }
  return rd;
}

DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
  if (m_dyld_up.get() == nullptr)
    m_dyld_up.reset(DynamicLoader::FindPlugin(
        this, DynamicLoaderStatic::GetPluginNameStatic()));
  return m_dyld_up.get();
}