24#include "llvm/Support/Error.h"
25#include "llvm/Support/SaveAndRestore.h"
39#define LLDB_PROPERTIES_processfreebsdkernelcore
40#include "ProcessFreeBSDKernelCoreProperties.inc"
43#define LLDB_PROPERTIES_processfreebsdkernelcore
44#include "ProcessFreeBSDKernelCorePropertiesEnum.inc"
49 static llvm::StringRef GetSettingName() {
53 PluginProperties() : Properties() {
54 m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
55 m_collection_sp->Initialize(g_processfreebsdkernelcore_properties_def);
58 ~PluginProperties()
override =
default;
60 bool GetReadOnly()
const {
61 const uint32_t idx = ePropertyReadOnly;
62 return GetPropertyAtIndexAs<bool>(idx,
true);
69 static PluginProperties g_settings;
77 FileSpec object_file =
module->GetFileSpec();
80 FileSpec symbol_file =
module->GetSymbolFileFileSpec();
83 if (symbol_file && symbol_file != object_file)
86 auto *
elf = llvm::dyn_cast_or_null<ObjectFileELF>(module->GetObjectFile());
92 (void)
elf->GetSectionList();
93 std::optional<FileSpec> debug_link =
elf->GetDebugLink();
94 if (!debug_link || debug_link->GetFilename().empty())
100 std::string object_path = object_file.
GetPath();
103 std::string sysroot_path = sysroot.
GetPath();
104 llvm::StringRef relative_path(object_path);
105 if (!relative_path.consume_front(sysroot_path))
107 relative_path = relative_path.ltrim(
"/\\");
109 FileSpec relative_file(relative_path);
118 module->SetSymbolFileFileSpec(debug_file);
131 interpreter,
"process plugin refresh-threads",
132 "Refresh the thread list from the FreeBSD kernel core. The thread "
133 "list and related data structures may be being read from live "
134 "memory (/dev/mem), which may have changed since the last refresh. "
135 "This command clears LLDB's thread list and memory cache then "
136 "re-reads the kernel's allproc/zombie lists to rebuild the thread "
137 "list from scratch.",
138 "process plugin refresh-threads",
139 eCommandRequiresProcess | eCommandTryTargetAPILock) {}
161 process->m_thread_list_real.Clear();
162 process->m_thread_list.Clear();
165 const uint32_t num_threads =
166 process->GetThreadList().GetSize(
true);
168 "Thread list refreshed, {0} thread{1} found.", num_threads,
169 num_threads == 1 ?
"" :
"s");
191 const FileSpec *crash_file,
bool can_connect) {
192 ModuleSP executable = target_sp->GetExecutableModule();
193 if (crash_file && !can_connect && executable) {
194 char errbuf[_POSIX2_LINE_MAX];
195 kvm_t *kvm =
OpenKVM(executable, *crash_file, O_RDONLY, errbuf);
198 return std::make_shared<ProcessFreeBSDKernelCore>(target_sp, listener_sp,
214 debugger, PluginProperties::GetSettingName())) {
215 const bool is_global_setting =
true;
218 "Properties for the freebsd-kernel process plug-in.",
228 bool plugin_specified_by_name) {
236 m_command_sp = std::make_unique<CommandObjectMultiword>(
237 interp,
"process plugin",
238 "Commands for the FreeBSD kernel process plug-in.",
239 "process plugin <subcommand> [<subcommand-options>]");
252 "ProcessFreeBSDKernelCore: no executable module set on target");
256 char errbuf[_POSIX2_LINE_MAX];
264 "ProcessFreeBSDKernelCore: kvm_open2 failed for core '%s' "
267 executable->GetFileSpec().GetPath().c_str());
272 if (symbols_changed) {
274 modules.
Append(executable);
304 const void *buf,
size_t size,
308 "Memory writes are currently disabled. You can enable them with "
309 "`settings set plugin.process.freebsd-kernel-core.read-only false`.");
314 rd = kvm_write(
m_kvm, addr, buf, size);
315 if (rd < 0 ||
static_cast<size_t>(rd) != size) {
318 return rd > 0 ? rd : 0;
325 if (old_thread_list.
GetSize(
false) == 0) {
332 switch (
GetTarget().GetArchitecture().GetMachine()) {
333 case llvm::Triple::arm:
334 case llvm::Triple::aarch64:
335 case llvm::Triple::ppc64le:
336 case llvm::Triple::riscv64:
337 case llvm::Triple::x86:
338 case llvm::Triple::x86_64:
354 int32_t offset_p_pid =
396 if (offset_p_list == -1 || offset_p_pid == -1 || offset_p_threads == -1 ||
397 offset_p_comm == -1 || offset_td_tid == -1 || offset_td_plist == -1 ||
398 offset_td_pcb == -1 || offset_td_oncpu == -1 || offset_td_name == -1)
422 llvm::Expected<lldb::addr_t> stoppcbs_or_err =
424 if (!stoppcbs_or_err || *stoppcbs_or_err == 0) {
426 "FreeBSD-Kernel-Core: Could not find stoppcbs");
430 stoppcbs = *stoppcbs_or_err;
435 uint32_t mp_maxid = 0;
446 uint32_t long_bit = long_size_bytes * 8;
448 if (
auto type_system_or_err =
454 long_size_bytes = *size;
455 long_bit = long_size_bytes * 8;
457 llvm::consumeError(type_system_or_err.takeError());
460 constexpr size_t fbsd_maxcomlen = 19;
470 std::vector<std::pair<lldb::addr_t, int32_t>> process_addrs;
471 llvm::Expected<lldb::addr_t> proc_or_err =
473 for (; proc_or_err && *proc_or_err != 0;
480 process_addrs.emplace_back(proc, pid);
484 llvm::consumeError(proc_or_err.takeError());
488 std::sort(process_addrs.begin(), process_addrs.end(),
489 [](
const auto &a,
const auto &b) { return a.second < b.second; });
491 for (
auto [proc, pid] : process_addrs) {
493 char comm[fbsd_maxcomlen + 1];
502 llvm::Expected<lldb::addr_t> td_or_err =
504 for (; td_or_err && *td_or_err != 0;
512 llvm::Expected<lldb::addr_t> pcb_addr_or_err =
514 if (!pcb_addr_or_err) {
515 llvm::consumeError(pcb_addr_or_err.takeError());
527 char thread_name[fbsd_maxcomlen + 1];
529 sizeof(thread_name),
error);
537 std::string thread_desc = llvm::formatv(
"(pid {0}) {1}", pid, comm);
538 if (*thread_name && strcmp(thread_name, comm)) {
540 thread_desc += thread_name;
547 if (tid == dumptid) {
550 thread_desc +=
" (crashed)";
551 }
else if (oncpu != -1) {
554 bool is_stopped =
false;
555 if (oncpu >= 0 &&
static_cast<uint32_t
>(oncpu) <= mp_maxid &&
557 uint32_t
bit = oncpu % long_bit;
558 uint32_t word = oncpu / long_bit;
559 lldb::addr_t mask_addr = stopped_cpus + word * long_size_bytes;
561 mask_addr, long_size_bytes, 0,
error);
563 is_stopped = (mask & (1ULL <<
bit)) != 0;
569 pcb_addr = stoppcbs + oncpu * pcbsize;
573 thread_desc += llvm::formatv(
" (on CPU {0})", oncpu);
580 thread->SetIsCrashedThread(
true);
587 llvm::consumeError(td_or_err.takeError());
592 const uint32_t num_threads = old_thread_list.
GetSize(
false);
593 for (uint32_t i = 0; i < num_threads; ++i)
596 return new_thread_list.
GetSize(
false) > 0;
604 rd = kvm_read2(
m_kvm, addr, buf, size);
605 if (rd < 0 ||
static_cast<size_t>(rd) != size) {
608 return rd > 0 ? rd : 0;
638 const FileSpec &core_file,
int flags,
641 kernel_module.get());
642 return kvm_open2(kernel_module->GetFileSpec().GetPath().c_str(),
643 core_file.
GetPath().c_str(), flags, errbuf,
648 kssize_t displacement = kvm_kerndisp(
m_kvm);
652 if (!kernel_module_sp)
655 bool changed =
false;
656 kernel_module_sp->SetLoadAddress(target,
662 loaded_module_list.
Append(kernel_module_sp);
679 llvm::Expected<lldb::addr_t> msgbufp_or_err =
681 if (!msgbufp_or_err) {
682 llvm::consumeError(msgbufp_or_err.takeError());
692 uint64_t offset_msg_ptr = 0;
693 uint64_t offset_msg_size = 0;
694 uint64_t offset_msg_wseq = 0;
695 uint64_t offset_msg_rseq = 0;
704 for (uint32_t i = 0; i < num_fields; i++) {
705 std::string field_name;
706 uint64_t field_offset = 0;
711 if (field_name ==
"msg_ptr") {
712 offset_msg_ptr = field_offset / 8;
714 }
else if (field_name ==
"msg_size") {
715 offset_msg_size = field_offset / 8;
717 }
else if (field_name ==
"msg_wseq") {
718 offset_msg_wseq = field_offset / 8;
720 }
else if (field_name ==
"msg_rseq") {
721 offset_msg_rseq = field_offset / 8;
726 if (field_found != 4) {
729 "FreeBSD-Kernel-Core: Could not find all required fields for msgbuf");
742 offset_msg_size = ptr_size + 4;
743 offset_msg_wseq = ptr_size + 8;
744 offset_msg_rseq = ptr_size + 12;
748 llvm::Expected<lldb::addr_t> bufp_or_err =
751 llvm::consumeError(bufp_or_err.takeError());
758 if (
error.Fail() || size == 0)
773 uint32_t rseq_pos = rseq % size;
774 uint32_t wseq_pos = wseq % size;
776 if (rseq_pos == wseq_pos)
784 stream_sp->PutCString(
"\nUnread portion of the kernel message buffer:\n");
787 if (rseq_pos < wseq_pos) {
789 size_t len = wseq_pos - rseq_pos;
790 std::string buf(len,
'\0');
792 if (
error.Success() && bytes_read > 0) {
793 buf.resize(bytes_read);
798 size_t len1 = size - rseq_pos;
799 std::string buf1(len1,
'\0');
800 size_t bytes_read1 =
ReadMemory(bufp + rseq_pos, &buf1[0], len1,
error);
801 if (
error.Success() && bytes_read1 > 0) {
802 buf1.resize(bytes_read1);
807 std::string buf2(wseq_pos,
'\0');
809 if (
error.Success() && bytes_read2 > 0) {
810 buf2.resize(bytes_read2);
816 stream_sp->PutChar(
'\n');
static llvm::raw_ostream & error(Stream &strm)
static PluginProperties & GetGlobalPluginProperties()
#define LLDB_LOGF(log,...)
#define LLDB_PLUGIN_DEFINE(PluginName)
static PluginProperties & GetGlobalPluginProperties()
static bool SetKernelDebugFile(const ModuleSP &module)
void DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectProcessFreeBSDKernelCoreRefreshThreads(CommandInterpreter &interpreter)
~CommandObjectProcessFreeBSDKernelCoreRefreshThreads() override=default
static llvm::StringRef GetPluginNameStatic()
lldb_private::Status DoDestroy() override
static llvm::StringRef GetPluginNameStatic()
void PrintUnreadMessage()
ProcessFreeBSDKernelCore(lldb::TargetSP target_sp, lldb::ListenerSP listener, const lldb_private::FileSpec &core_file)
lldb::addr_t FindSymbol(const char *name)
~ProcessFreeBSDKernelCore()
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, const lldb_private::FileSpec *crash_file_path, bool can_connect)
void RefreshStateAfterStop() override
Currently called as part of ShouldStop.
static void DebuggerInitialize(lldb_private::Debugger &debugger)
static llvm::StringRef GetPluginDescriptionStatic()
lldb_private::Status DoLoadCore() override
static int ResolveKVMSymbol(const char *name, kvaddr_t *value)
lldb_private::CommandObject * GetPluginCommandObject() override
Return a multi-word command object that can be used to expose plug-in specific commands.
void SetKernelDisplacement()
static thread_local lldb_private::Module * g_kvm_kernel_module
friend class CommandObjectProcessFreeBSDKernelCoreRefreshThreads
lldb_private::DynamicLoader * GetDynamicLoader() override
Get the dynamic loader plug-in for this process.
size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size, lldb_private::Status &error) override
Actually do the writing of memory to a process.
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override
Update the thread list following process plug-in's specific logic.
static kvm_t * OpenKVM(const lldb::ModuleSP &kernel_module, const lldb_private::FileSpec &core_file, int flags, char *errbuf)
size_t DoReadMemory(const lldb_private::ProcessAddress &addr, void *buf, size_t size, lldb_private::Status &error) override
Actually do the reading of memory from a process.
bool m_printed_unread_message
bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override
Check if a plug-in instance can debug the file in module.
std::unique_ptr< lldb_private::CommandObjectMultiword > m_command_sp
A command line argument class.
CommandObjectParsed(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
CommandInterpreter & m_interpreter
void SetStatus(lldb::ReturnStatus status)
void void AppendMessageWithFormatv(const char *format, Args &&...args)
Generic representation of a type in a programming language.
CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) const
Create related types using the current type's AST.
CompilerType GetFieldAtIndex(size_t idx, std::string &name, uint64_t *bit_offset_ptr, uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) const
llvm::Expected< uint64_t > GetByteSize(ExecutionContextScope *exe_scope) const
Return the size of the type in bytes.
uint32_t GetNumFields() const
A uniqued constant string class.
CommandInterpreter & GetCommandInterpreter()
lldb::StreamUP GetAsyncOutputStream()
static DynamicLoader * FindPlugin(Process *process, llvm::StringRef plugin_name)
Find a dynamic loader plugin for a given process.
void AppendPathComponent(llvm::StringRef component)
bool RemoveLastPathComponent()
Removes the last path component by replacing the current path with its parent.
llvm::StringRef GetDirectory() const
Directory string const get accessor.
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
void Clear(bool clear_invalid_ranges=false)
A collection class for Module objects.
void FindTypes(Module *search_first, const TypeQuery &query, lldb_private::TypeResults &results) const
Find types using a type-matching object that contains all search parameters.
void Append(const lldb::ModuleSP &module_sp, bool notify=true)
Append a module to the module list.
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool CreateSettingForProcessPlugin(Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, llvm::StringRef description, bool is_global_property)
static lldb::OptionValuePropertiesSP GetSettingForProcessPlugin(Debugger &debugger, llvm::StringRef setting_name)
static bool UnregisterPlugin(ABICreateInstance create_callback)
PostMortemProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec &core_file)
FileSpec GetCoreFile() const override
Provide a way to retrieve the core dump file that is loaded for debugging.
An address in a process, qualified by an address space.
lldb::addr_t GetValue() const
int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, int64_t fail_value, Status &error)
size_t ReadCStringFromMemory(lldb::addr_t vm_addr, char *cstr, size_t cstr_max_len, Status &error)
Read a null-terminated C string from memory.
virtual size_t ReadMemory(const ProcessAddress &process_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
lldb::DynamicLoaderUP m_dyld_up
llvm::Expected< lldb::addr_t > ReadPointerFromMemory(lldb::addr_t vm_addr)
uint64_t ReadUnsignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, uint64_t fail_value, Status &error)
Reads an unsigned integer of the specified byte size from process memory.
MemoryCache m_memory_cache
uint32_t GetAddressByteSize() const
virtual void Finalize(bool destructing)
This object is about to be destroyed, do any necessary cleanup.
ThreadList m_thread_list
The threads for this process as the user will see them.
friend class DynamicLoader
Target & GetTarget()
Get the target object pointer for this module.
lldb::OptionValuePropertiesSP GetValueProperties() const
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
lldb::addr_t GetLoadAddress(Target *target) const
lldb::addr_t GetFileAddress() const
void ModulesDidLoad(ModuleList &module_list)
This call may preload module symbols, and may do so in parallel depending on the following target set...
void SymbolsDidLoad(ModuleList &module_list)
Debugger & GetDebugger() const
lldb::ModuleSP GetExecutableModule()
Gets the module for the main executable.
const ModuleList & GetImages() const
Get accessor for the images for this process.
void AddThread(const lldb::ThreadSP &thread_sp)
uint32_t GetSize(bool can_update=true)
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
lldb::TypeSP GetTypeAtIndex(uint32_t idx)
A class that contains all state required for type lookups.
This class tracks the state and results of a TypeQuery.
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
@ eLanguageTypeC
Non-standardized C, such as K&R.
std::shared_ptr< lldb_private::Stream > StreamSP
std::shared_ptr< lldb_private::Process > ProcessSP
@ eReturnStatusSuccessFinishResult
std::shared_ptr< lldb_private::Listener > ListenerSP
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::Module > ModuleSP