[Lldb-commits] [lldb] [lldb][FreeBSD] Add dynamic loader handle class for FreeBSD Kernel (PR #67106)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 29 00:33:48 PDT 2023
https://github.com/aokblast updated https://github.com/llvm/llvm-project/pull/67106
>From 17cad831181b07c4397aa78039ede79fc8b20513 Mon Sep 17 00:00:00 2001
From: aokblast <i19670219111 at kimo.com>
Date: Fri, 29 Sep 2023 15:27:42 +0800
Subject: [PATCH] Add DynamicLoader Plugin Fore FreeBSD Kernel coredump
This patch add dynamicloader plguin for freebsd kernel coredump on lldb.
The implementation is by parsing linker_files structure and get all loaded kernel modules.
This patch was part of FreeBSD's participation in Google Summer of Code 2023
---
.../Plugins/DynamicLoader/CMakeLists.txt | 1 +
.../FreeBSD-Kernel/CMakeLists.txt | 13 +
.../DynamicLoaderFreeBSDKernel.cpp | 789 ++++++++++++++++++
.../DynamicLoaderFreeBSDKernel.h | 171 ++++
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 43 +-
.../FreeBSDKernel/ProcessFreeBSDKernel.cpp | 4 +-
6 files changed, 1014 insertions(+), 7 deletions(-)
create mode 100644 lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt
create mode 100644 lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
create mode 100644 lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h
diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
index f357fea02efbe68..30607159acdc088 100644
--- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
+++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
@@ -1,4 +1,5 @@
add_subdirectory(Darwin-Kernel)
+add_subdirectory(FreeBSD-Kernel)
add_subdirectory(MacOSX-DYLD)
add_subdirectory(POSIX-DYLD)
add_subdirectory(Static)
diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt
new file mode 100644
index 000000000000000..76daf0a327cf97b
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginDynamicLoaderFreeBSDKernel PLUGIN
+ DynamicLoaderFreeBSDKernel.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbHost
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ lldbPluginObjectFileELF
+ )
diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
new file mode 100644
index 000000000000000..bbb83ff0a118400
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
@@ -0,0 +1,789 @@
+//===-- DynamicLoaderFreeBSDKernel.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/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/StreamFile.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Symbol/LocateSymbolFile.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+
+#include "DynamicLoaderFreeBSDKernel.h"
+#include <memory>
+#include <mutex>
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderFreeBSDKernel)
+
+void DynamicLoaderFreeBSDKernel::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInit);
+}
+
+void DynamicLoaderFreeBSDKernel::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef DynamicLoaderFreeBSDKernel::GetPluginDescriptionStatic() {
+ return "The Dynamic Loader Plugin For FreeBSD Kernel";
+}
+
+static bool is_kernel(Module *module) {
+ if (!module)
+ return false;
+
+ ObjectFile *objfile = module->GetObjectFile();
+ if (!objfile)
+ return false;
+ if (objfile->GetType() != ObjectFile::eTypeExecutable)
+ return false;
+ if (objfile->GetStrata() != ObjectFile::eStrataUnknown &&
+ objfile->GetStrata() != ObjectFile::eStrataKernel)
+ return false;
+
+ return true;
+}
+
+static bool is_kmod(Module *module) {
+ if (!module)
+ return false;
+ if (!module->GetObjectFile())
+ return false;
+ ObjectFile *objfile = module->GetObjectFile();
+ if (objfile->GetType() != ObjectFile::eTypeObjectFile &&
+ objfile->GetType() != ObjectFile::eTypeSharedLibrary)
+ return false;
+
+ return true;
+}
+
+static bool is_reloc(Module *module) {
+ if (!module)
+ return false;
+ if (!module->GetObjectFile())
+ return false;
+ ObjectFile *objfile = module->GetObjectFile();
+ if (objfile->GetType() != ObjectFile::eTypeObjectFile)
+ return false;
+
+ return true;
+}
+
+// Instantiate Function of the FreeBSD Kernel Dynamic Loader Plugin called when
+// Register the Plugin
+DynamicLoader *
+DynamicLoaderFreeBSDKernel::CreateInstance(lldb_private::Process *process,
+ bool force) {
+ // Check the environment when the plugin is not force loaded
+ Module *exec = process->GetTarget().GetExecutableModulePointer();
+ if (exec && !is_kernel(exec)) {
+ return nullptr;
+ }
+ if (!force) {
+ // Check if the target is kernel
+ const llvm::Triple &triple_ref =
+ process->GetTarget().GetArchitecture().GetTriple();
+ if (!triple_ref.isOSFreeBSD()) {
+ return nullptr;
+ }
+ }
+
+ // At this point we have checked the target is a FreeBSD kernel and all we
+ // have to do is to find the kernel address
+ const addr_t kernel_address = FindFreeBSDKernel(process);
+
+ if (CheckForKernelImageAtAddress(process, kernel_address).IsValid())
+ return new DynamicLoaderFreeBSDKernel(process, kernel_address);
+
+ return nullptr;
+}
+
+addr_t
+DynamicLoaderFreeBSDKernel::FindFreeBSDKernel(lldb_private::Process *process) {
+ addr_t kernel_addr = process->GetImageInfoAddress();
+ if (kernel_addr == LLDB_INVALID_ADDRESS)
+ kernel_addr = FindKernelAtLoadAddress(process);
+ return kernel_addr;
+}
+
+// Get the kernel address if the kernel is not loaded with a slide
+addr_t DynamicLoaderFreeBSDKernel::FindKernelAtLoadAddress(
+ lldb_private::Process *process) {
+ Module *exe_module = process->GetTarget().GetExecutableModulePointer();
+
+ if (!is_kernel(exe_module))
+ return LLDB_INVALID_ADDRESS;
+
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+
+ if (!exe_objfile->GetBaseAddress().IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ if (CheckForKernelImageAtAddress(
+ process, exe_objfile->GetBaseAddress().GetFileAddress())
+ .IsValid())
+ return exe_objfile->GetBaseAddress().GetFileAddress();
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+// Read ELF header from memry and return
+bool DynamicLoaderFreeBSDKernel::ReadELFHeader(Process *process,
+ lldb::addr_t addr,
+ llvm::ELF::Elf32_Ehdr &header,
+ bool *read_error) {
+ Status error;
+ if (read_error)
+ *read_error = false;
+
+ if (process->ReadMemory(addr, &header, sizeof(header), error) !=
+ sizeof(header)) {
+ if (read_error)
+ *read_error = true;
+ return false;
+ }
+
+ if (!header.checkMagic())
+ return false;
+
+ return true;
+}
+
+// Check the correctness of Kernel and return UUID
+lldb_private::UUID DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress(
+ Process *process, lldb::addr_t addr, bool *read_error) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ if (addr == LLDB_INVALID_ADDRESS) {
+ if (read_error)
+ *read_error = true;
+ return UUID();
+ }
+
+ LLDB_LOGF(log,
+ "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress: "
+ "looking for kernel binary at 0x%" PRIx64,
+ addr);
+
+ llvm::ELF::Elf32_Ehdr header;
+ if (!ReadELFHeader(process, addr, header)) {
+ *read_error = true;
+ return UUID();
+ }
+
+ // Check header type
+ if (header.e_type != llvm::ELF::ET_EXEC)
+ return UUID();
+
+ ModuleSP memory_module_sp =
+ process->ReadModuleFromMemory(FileSpec("temp_freebsd_kernel"), addr);
+
+ if (!memory_module_sp.get()) {
+ *read_error = true;
+ return UUID();
+ }
+
+ ObjectFile *exe_objfile = memory_module_sp->GetObjectFile();
+ if (exe_objfile == nullptr) {
+ LLDB_LOGF(log,
+ "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress "
+ "found a binary at 0x%" PRIx64
+ " but could not create an object file from memory",
+ addr);
+ return UUID();
+ }
+
+ // In here, I should check is_kernel for memory_module_sp
+ // However, the ReadModuleFromMemory reads wrong section so that this check
+ // will failed
+ ArchSpec kernel_arch(llvm::ELF::convertEMachineToArchName(header.e_machine));
+
+ if (!process->GetTarget().GetArchitecture().IsCompatibleMatch(kernel_arch))
+ process->GetTarget().SetArchitecture(kernel_arch);
+
+ std::string uuid_str;
+ if (memory_module_sp->GetUUID().IsValid()) {
+ uuid_str = "with UUID ";
+ uuid_str += memory_module_sp->GetUUID().GetAsString();
+ } else {
+ uuid_str = "and no LC_UUID found in load commands ";
+ }
+ LLDB_LOGF(log,
+ "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress: "
+ "kernel binary image found at 0x%" PRIx64 " with arch '%s' %s",
+ addr, kernel_arch.GetTriple().str().c_str(), uuid_str.c_str());
+
+ return memory_module_sp->GetUUID();
+}
+
+void DynamicLoaderFreeBSDKernel::DebuggerInit(
+ lldb_private::Debugger &debugger) {}
+
+DynamicLoaderFreeBSDKernel::DynamicLoaderFreeBSDKernel(Process *process,
+ addr_t kernel_address)
+ : DynamicLoader(process), m_process(process),
+ m_linker_file_list_struct_addr(LLDB_INVALID_ADDRESS),
+ m_linker_file_head_addr(LLDB_INVALID_ADDRESS),
+ m_kernel_load_address(kernel_address), m_mutex() {
+ process->SetCanRunCode(false);
+}
+
+DynamicLoaderFreeBSDKernel::~DynamicLoaderFreeBSDKernel() { Clear(true); }
+
+void DynamicLoaderFreeBSDKernel::Update() {
+ LoadKernelModules();
+ SetNotificationBreakPoint();
+}
+
+// Create in memory Module at the load address
+bool DynamicLoaderFreeBSDKernel::KModImageInfo::ReadMemoryModule(
+ lldb_private::Process *process) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ if (m_memory_module_sp)
+ return true;
+ if (m_load_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ FileSpec file_spec(m_name);
+
+ ModuleSP memory_module_sp;
+
+ llvm::ELF::Elf32_Ehdr elf_eheader;
+ size_t size_to_read = 512;
+
+ if (ReadELFHeader(process, m_load_address, elf_eheader)) {
+ if (elf_eheader.e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32) {
+ size_to_read = sizeof(llvm::ELF::Elf32_Ehdr) +
+ elf_eheader.e_phnum * elf_eheader.e_phentsize;
+ } else if (elf_eheader.e_ident[llvm::ELF::EI_CLASS] ==
+ llvm::ELF::ELFCLASS64) {
+ llvm::ELF::Elf64_Ehdr elf_eheader;
+ Status error;
+ if (process->ReadMemory(m_load_address, &elf_eheader, sizeof(elf_eheader),
+ error) == sizeof(elf_eheader))
+ size_to_read = sizeof(llvm::ELF::Elf64_Ehdr) +
+ elf_eheader.e_phnum * elf_eheader.e_phentsize;
+ }
+ }
+
+ memory_module_sp =
+ process->ReadModuleFromMemory(file_spec, m_load_address, size_to_read);
+
+ if (!memory_module_sp)
+ return false;
+
+ bool this_is_kernel = is_kernel(memory_module_sp.get());
+
+ if (!m_uuid.IsValid() && memory_module_sp->GetUUID().IsValid())
+ m_uuid = memory_module_sp->GetUUID();
+
+ m_memory_module_sp = memory_module_sp;
+ m_is_kernel = this_is_kernel;
+
+ // The kernel binary is from memory
+ if (this_is_kernel) {
+ LLDB_LOGF(log, "KextImageInfo::ReadMemoryModule read the kernel binary out "
+ "of memory");
+
+ if (memory_module_sp->GetArchitecture().IsValid())
+ process->GetTarget().SetArchitecture(memory_module_sp->GetArchitecture());
+ }
+
+ return true;
+}
+
+bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule(
+ lldb_private::Process *process) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ if (IsLoaded())
+ return true;
+
+ Target &target = process->GetTarget();
+
+ if (IsKernel() && m_uuid.IsValid()) {
+ Stream &s = target.GetDebugger().GetOutputStream();
+ s.Printf("Kernel UUID: %s\n", m_uuid.GetAsString().c_str());
+ s.Printf("Load Address: 0x%" PRIx64 "\n", m_load_address);
+ }
+
+ // Test if the module is loaded into the taget,
+ // maybe the module is loaded manually by user by doing target module add
+ // So that we have to create the module manually
+ if (!m_module_sp) {
+ const ModuleList &target_images = target.GetImages();
+ m_module_sp = target_images.FindModule(m_uuid);
+
+ // Search in the file system
+ if (!m_module_sp) {
+ ModuleSpec module_spec(FileSpec(GetPath()), target.GetArchitecture());
+ if (IsKernel()) {
+ Status error;
+ if (Symbols::DownloadObjectAndSymbolFile(module_spec, error, true)) {
+ if (FileSystem::Instance().Exists(module_spec.GetFileSpec()))
+ m_module_sp = std::make_shared<Module>(module_spec.GetFileSpec(),
+ target.GetArchitecture());
+ }
+ }
+
+ if (!m_module_sp)
+ m_module_sp = target.GetOrCreateModule(module_spec, true);
+ if (IsKernel() && !m_module_sp) {
+ Stream &s = target.GetDebugger().GetOutputStream();
+ s.Printf("WARNING: Unable to locate kernel binary on the debugger "
+ "system.\n");
+ }
+ }
+
+ if (m_module_sp) {
+ // If the file is not kernel or kmod, the target should be loaded once and
+ // don't reload again
+ if (!IsKernel() && !is_kmod(m_module_sp.get())) {
+ ModuleSP existing_module_sp = target.GetImages().FindModule(m_uuid);
+ if (existing_module_sp &&
+ existing_module_sp->IsLoadedInTarget(&target)) {
+ LLDB_LOGF(log,
+ "'%s' with UUID %s is not a kmod or kernel, and is "
+ "already registered in target, not loading.",
+ m_name.c_str(), m_uuid.GetAsString().c_str());
+ return true;
+ }
+ }
+ m_uuid = m_module_sp->GetUUID();
+
+ // or append to the images
+ target.GetImages().AppendIfNeeded(m_module_sp, false);
+ }
+ }
+
+ // If this file is relocatable kernel module(x86_64), adjust it's
+ // section(PT_LOAD segment) and return Because the kernel module's load
+ // address is the text section. lldb cannot create full memory module upon
+ // relocatable file So what we do is to set the load address only.
+ if (is_kmod(m_module_sp.get()) && is_reloc(m_module_sp.get())) {
+ m_stop_id = process->GetStopID();
+ bool changed = false;
+ m_module_sp->SetLoadAddress(target, m_load_address, true, changed);
+ return true;
+ }
+
+ if (m_module_sp)
+ ReadMemoryModule(process);
+
+ // Calculate the slides of in memory module
+ if (!m_memory_module_sp || !m_module_sp) {
+ m_module_sp.reset();
+ return false;
+ }
+
+ ObjectFile *ondisk_object_file = m_module_sp->GetObjectFile();
+ ObjectFile *memory_object_file = m_memory_module_sp->GetObjectFile();
+
+ if (!ondisk_object_file || !memory_object_file)
+ m_module_sp.reset();
+
+ // Find the slide address
+ addr_t fixed_slide = LLDB_INVALID_ADDRESS;
+ if (ObjectFileELF *memory_objfile_elf =
+ llvm::dyn_cast<ObjectFileELF>(memory_object_file)) {
+ addr_t load_address = memory_object_file->GetBaseAddress().GetFileAddress();
+
+ if (load_address != LLDB_INVALID_ADDRESS &&
+ m_load_address != load_address) {
+ fixed_slide = m_load_address - load_address;
+ LLDB_LOGF(log,
+ "kmod %s in-memory LOAD vmaddr is not correct, using a "
+ "fixed slide of 0x%" PRIx64,
+ m_name.c_str(), fixed_slide);
+ }
+ }
+
+ SectionList *ondisk_section_list = ondisk_object_file->GetSectionList();
+ SectionList *memory_section_list = memory_object_file->GetSectionList();
+
+ if (memory_section_list && ondisk_object_file) {
+ const uint32_t num_ondisk_sections = ondisk_section_list->GetSize();
+ uint32_t num_load_sections = 0;
+
+ for (uint32_t section_idx = 0; section_idx < num_ondisk_sections;
+ ++section_idx) {
+ SectionSP on_disk_section_sp =
+ ondisk_section_list->GetSectionAtIndex(section_idx);
+
+ if (!on_disk_section_sp)
+ continue;
+ if (fixed_slide != LLDB_INVALID_ADDRESS) {
+ target.SetSectionLoadAddress(on_disk_section_sp,
+ on_disk_section_sp->GetFileAddress() +
+ fixed_slide);
+
+ } else {
+ const Section *memory_section =
+ memory_section_list
+ ->FindSectionByName(on_disk_section_sp->GetName())
+ .get();
+ if (memory_section) {
+ target.SetSectionLoadAddress(on_disk_section_sp,
+ memory_section->GetFileAddress());
+ ++num_load_sections;
+ }
+ }
+ }
+
+ if (num_load_sections)
+ m_stop_id = process->GetStopID();
+ else
+ m_module_sp.reset();
+ } else {
+ m_module_sp.reset();
+ }
+
+ if (IsLoaded() && m_module_sp && IsKernel()) {
+ Stream &s = target.GetDebugger().GetOutputStream();
+ ObjectFile *kernel_object_file = m_module_sp->GetObjectFile();
+ if (kernel_object_file) {
+ addr_t file_address =
+ kernel_object_file->GetBaseAddress().GetFileAddress();
+ if (m_load_address != LLDB_INVALID_ADDRESS &&
+ file_address != LLDB_INVALID_ADDRESS) {
+ s.Printf("Kernel slide 0x%" PRIx64 " in memory.\n",
+ m_load_address - file_address);
+ s.Printf("Loaded kernel file %s\n",
+ m_module_sp->GetFileSpec().GetPath().c_str());
+ }
+ }
+ s.Flush();
+ }
+
+ return IsLoaded();
+}
+
+// This function is work for kernel file, others it wil reset load address and
+// return false
+bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingFileAddress(
+ lldb_private::Process *process) {
+ if (IsLoaded())
+ return true;
+
+ if (m_module_sp) {
+ bool changed = false;
+ if (m_module_sp->SetLoadAddress(process->GetTarget(), 0, true, changed))
+ m_stop_id = process->GetStopID();
+ }
+
+ return false;
+}
+
+// Get the head of found_list
+bool DynamicLoaderFreeBSDKernel::ReadKmodsListHeader() {
+ std::lock_guard<decltype(m_mutex)> guard(m_mutex);
+
+ if (m_linker_file_list_struct_addr.IsValid()) {
+ // Get tqh_first struct element from linker_files
+ Status error;
+ addr_t address = m_process->ReadPointerFromMemory(
+ m_linker_file_list_struct_addr.GetLoadAddress(&m_process->GetTarget()),
+ error);
+ if (address != LLDB_INVALID_ADDRESS && error.Success()) {
+ m_linker_file_head_addr = Address(address);
+ } else {
+ m_linker_file_list_struct_addr.Clear();
+ return false;
+ }
+
+ if (!m_linker_file_head_addr.IsValid() ||
+ m_linker_file_head_addr.GetFileAddress() == 0) {
+ m_linker_file_list_struct_addr.Clear();
+ return false;
+ }
+ }
+ return true;
+}
+
+// Parse Kmod info in found_list
+bool DynamicLoaderFreeBSDKernel::ParseKmods(Address linker_files_head_addr) {
+ std::lock_guard<decltype(m_mutex)> guard(m_mutex);
+ KModImageInfo::collection_type linker_files_list;
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ if (!ReadAllKmods(linker_files_head_addr, linker_files_list))
+ return false;
+ LLDB_LOGF(
+ log,
+ "Kmod-changed breakpoint hit, there are %lu kernel modules currently.\n",
+ linker_files_list.size());
+
+ ModuleList &modules = m_process->GetTarget().GetImages();
+ ModuleList remove_modules;
+ ModuleList add_modules;
+
+ for (ModuleSP module : modules.Modules()) {
+ if (is_kernel(module.get()))
+ continue;
+ if (is_kmod(module.get()))
+ remove_modules.AppendIfNeeded(module);
+ }
+
+ m_process->GetTarget().ModulesDidUnload(remove_modules, false);
+
+ for (KModImageInfo &image_info : linker_files_list) {
+ if (m_kld_name_to_uuid.find(image_info.GetName()) !=
+ m_kld_name_to_uuid.end())
+ image_info.SetUUID(m_kld_name_to_uuid[image_info.GetName()]);
+ bool failed_to_load = false;
+ if (!image_info.LoadImageUsingMemoryModule(m_process)) {
+ image_info.LoadImageUsingFileAddress(m_process);
+ failed_to_load = true;
+ } else {
+ m_linker_files_list.push_back(image_info);
+ m_kld_name_to_uuid[image_info.GetName()] = image_info.GetUUID();
+ }
+
+ if (!failed_to_load)
+ add_modules.AppendIfNeeded(image_info.GetModule());
+ }
+ m_process->GetTarget().ModulesDidLoad(add_modules);
+ return true;
+}
+
+// Read all kmod from a given arrays of list
+bool DynamicLoaderFreeBSDKernel::ReadAllKmods(
+ Address linker_files_head_addr,
+ KModImageInfo::collection_type &kmods_list) {
+
+ // Get offset of next member and load address symbol
+ static ConstString kld_off_address_symbol_name("kld_off_address");
+ static ConstString kld_off_next_symbol_name("kld_off_next");
+ static ConstString kld_off_filename_symbol_name("kld_off_filename");
+ static ConstString kld_off_pathname_symbol_name("kld_off_pathname");
+ const Symbol *kld_off_address_symbol =
+ m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType(
+ kld_off_address_symbol_name, eSymbolTypeData);
+ const Symbol *kld_off_next_symbol =
+ m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType(
+ kld_off_next_symbol_name, eSymbolTypeData);
+ const Symbol *kld_off_filename_symbol =
+ m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType(
+ kld_off_filename_symbol_name, eSymbolTypeData);
+ const Symbol *kld_off_pathname_symbol =
+ m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType(
+ kld_off_pathname_symbol_name, eSymbolTypeData);
+
+ if (!kld_off_address_symbol || !kld_off_next_symbol ||
+ !kld_off_filename_symbol || !kld_off_pathname_symbol)
+ return false;
+
+ Status error;
+ const int32_t kld_off_address = m_process->ReadSignedIntegerFromMemory(
+ kld_off_address_symbol->GetAddress().GetLoadAddress(
+ &m_process->GetTarget()),
+ 4, 0, error);
+ if (error.Fail())
+ return false;
+ const int32_t kld_off_next = m_process->ReadSignedIntegerFromMemory(
+ kld_off_next_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget()),
+ 4, 0, error);
+ if (error.Fail())
+ return false;
+ const int32_t kld_off_filename = m_process->ReadSignedIntegerFromMemory(
+ kld_off_filename_symbol->GetAddress().GetLoadAddress(
+ &m_process->GetTarget()),
+ 4, 0, error);
+ if (error.Fail())
+ return false;
+
+ const int32_t kld_off_pathname = m_process->ReadSignedIntegerFromMemory(
+ kld_off_pathname_symbol->GetAddress().GetLoadAddress(
+ &m_process->GetTarget()),
+ 4, 0, error);
+ if (error.Fail())
+ return false;
+
+ // Parse KMods
+ addr_t kld_load_addr(LLDB_INVALID_ADDRESS);
+ char kld_filename[255];
+ char kld_pathname[255];
+ addr_t current_kld =
+ linker_files_head_addr.GetLoadAddress(&m_process->GetTarget());
+
+ while (current_kld != 0) {
+ addr_t kld_filename_addr =
+ m_process->ReadPointerFromMemory(current_kld + kld_off_filename, error);
+ if (error.Fail())
+ return false;
+ addr_t kld_pathname_addr =
+ m_process->ReadPointerFromMemory(current_kld + kld_off_pathname, error);
+ if (error.Fail())
+ return false;
+
+ m_process->ReadCStringFromMemory(kld_filename_addr, kld_filename,
+ sizeof(kld_filename), error);
+ if (error.Fail())
+ return false;
+ m_process->ReadCStringFromMemory(kld_pathname_addr, kld_pathname,
+ sizeof(kld_pathname), error);
+ if (error.Fail())
+ return false;
+ kld_load_addr =
+ m_process->ReadPointerFromMemory(current_kld + kld_off_address, error);
+ if (error.Fail())
+ return false;
+
+ kmods_list.emplace_back();
+ KModImageInfo &kmod_info = kmods_list.back();
+ kmod_info.SetName(kld_filename);
+ kmod_info.SetLoadAddress(kld_load_addr);
+ kmod_info.SetPath(kld_pathname);
+
+ current_kld =
+ m_process->ReadPointerFromMemory(current_kld + kld_off_next, error);
+ if (kmod_info.GetName() == "kernel")
+ kmods_list.pop_back();
+ if (error.Fail())
+ return false;
+ }
+
+ return true;
+}
+
+// Read all kmods
+void DynamicLoaderFreeBSDKernel::ReadAllKmods() {
+ std::lock_guard<decltype(m_mutex)> guard(m_mutex);
+
+ if (ReadKmodsListHeader()) {
+ if (m_linker_file_head_addr.IsValid()) {
+ if (!ParseKmods(m_linker_file_head_addr))
+ m_linker_files_list.clear();
+ }
+ }
+}
+
+// Load all Kernel Modules
+void DynamicLoaderFreeBSDKernel::LoadKernelModules() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules "
+ "Start loading Kernel Module");
+
+ // Initialize Kernel Image Information at the first time
+ if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) {
+ ModuleSP module_sp = m_process->GetTarget().GetExecutableModule();
+ if (is_kernel(module_sp.get())) {
+ m_kernel_image_info.SetModule(module_sp);
+ m_kernel_image_info.SetIsKernel(true);
+ }
+
+ // Set name for kernel
+ llvm::StringRef kernel_name("freebsd_kernel");
+ module_sp = m_kernel_image_info.GetModule();
+ if (module_sp.get() && module_sp->GetObjectFile() &&
+ !module_sp->GetObjectFile()->GetFileSpec().GetFilename().IsEmpty())
+ kernel_name = module_sp->GetObjectFile()
+ ->GetFileSpec()
+ .GetFilename()
+ .GetStringRef();
+ m_kernel_image_info.SetName(kernel_name.data());
+
+ if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) {
+ m_kernel_image_info.SetLoadAddress(m_kernel_load_address);
+ }
+
+ // Build In memory Module
+ if (m_kernel_image_info.GetLoadAddress() != LLDB_INVALID_ADDRESS) {
+ // If the kernel is not loaded in the memory, use file to load
+ if (!m_kernel_image_info.LoadImageUsingMemoryModule(m_process))
+ m_kernel_image_info.LoadImageUsingFileAddress(m_process);
+ }
+ }
+
+ LoadOperatingSystemPlugin(false);
+
+ if (!m_kernel_image_info.IsLoaded() || !m_kernel_image_info.GetModule()) {
+ m_kernel_image_info.Clear();
+ return;
+ }
+
+ static ConstString modlist_symbol_name("linker_files");
+
+ const Symbol *symbol =
+ m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType(
+ modlist_symbol_name, lldb::eSymbolTypeData);
+
+ if (symbol) {
+ m_linker_file_list_struct_addr = symbol->GetAddress();
+ ReadAllKmods();
+ } else {
+ LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules "
+ "cannot file modlist symbol");
+ }
+}
+
+// Update symbol when use kldload by setting callback function on kldload
+void DynamicLoaderFreeBSDKernel::SetNotificationBreakPoint() {}
+
+// Hook called when attach to a process
+void DynamicLoaderFreeBSDKernel::DidAttach() {
+ PrivateInitialize(m_process);
+ Update();
+}
+
+// Hook called after attach to a process
+void DynamicLoaderFreeBSDKernel::DidLaunch() {
+ PrivateInitialize(m_process);
+ Update();
+}
+
+// Clear all member except kernel address
+void DynamicLoaderFreeBSDKernel::Clear(bool clear_process) {
+ std::lock_guard<decltype(m_mutex)> guard(m_mutex);
+ if (clear_process)
+ m_process = nullptr;
+ m_linker_file_head_addr.Clear();
+ m_linker_file_list_struct_addr.Clear();
+ m_kernel_image_info.Clear();
+ m_linker_files_list.clear();
+}
+
+// Reinitialize class
+void DynamicLoaderFreeBSDKernel::PrivateInitialize(Process *process) {
+ Clear(true);
+ m_process = process;
+}
+
+ThreadPlanSP DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan(
+ lldb_private::Thread &thread, bool stop_others) {
+ Log *log = GetLog(LLDBLog::Step);
+ LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan is "
+ "not yet implemented.");
+ return {};
+}
+
+Status DynamicLoaderFreeBSDKernel::CanLoadImage() {
+ Status error("shared object cannot be loaded into kernel");
+ return error;
+}
diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h
new file mode 100644
index 000000000000000..d8656e9c49dfe25
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h
@@ -0,0 +1,171 @@
+//===-- DynamicLoaderFreeBSDKernel.h -----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_FREEBSD_KERNEL_DYNAMICLOADERFREEBSDKERNEL_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_FREEBSD_KERNEL_DYNAMICLOADERFREEBSDKERNEL_H
+
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/UUID.h"
+#include "llvm/BinaryFormat/ELF.h"
+
+class DynamicLoaderFreeBSDKernel : public lldb_private::DynamicLoader {
+public:
+ DynamicLoaderFreeBSDKernel(lldb_private::Process *process,
+ lldb::addr_t kernel_addr);
+
+ ~DynamicLoaderFreeBSDKernel() override;
+
+ // Static Functions
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "freebsd-kernel"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process, bool force);
+
+ static void DebuggerInit(lldb_private::Debugger &debugger);
+
+ static lldb::addr_t FindFreeBSDKernel(lldb_private::Process *process);
+
+ // Hooks for time point that after attach to some proccess
+ void DidAttach() override;
+
+ void DidLaunch() override;
+
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others) override;
+
+ lldb_private::Status CanLoadImage() override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+protected:
+ class KModImageInfo {
+ public:
+ KModImageInfo()
+ : m_module_sp(), m_memory_module_sp(), m_uuid(), m_name(), m_path() {}
+
+ void Clear() {
+ m_load_address = LLDB_INVALID_ADDRESS;
+ m_name.clear();
+ m_uuid.Clear();
+ m_module_sp.reset();
+ m_memory_module_sp.reset();
+ m_stop_id = UINT32_MAX;
+ m_path.clear();
+ }
+
+ void SetLoadAddress(lldb::addr_t load_address) {
+ m_load_address = load_address;
+ }
+
+ lldb::addr_t GetLoadAddress() const { return m_load_address; }
+
+ void SetUUID(const lldb_private::UUID uuid) { m_uuid = uuid; }
+
+ lldb_private::UUID GetUUID() const { return m_uuid; }
+
+ void SetName(const char *name) { m_name = name; }
+
+ std::string GetName() const { return m_name; }
+
+ void SetPath(const char *path) { m_path = path; }
+
+ std::string GetPath() const { return m_path; }
+
+ void SetModule(lldb::ModuleSP module) { m_module_sp = module; }
+
+ lldb::ModuleSP GetModule() { return m_module_sp; }
+
+ void SetIsKernel(bool is_kernel) { m_is_kernel = is_kernel; }
+
+ bool IsKernel() const { return m_is_kernel; };
+
+ void SetStopID(uint32_t stop_id) { m_stop_id = stop_id; }
+
+ uint32_t GetStopID() { return m_stop_id; }
+
+ bool IsLoaded() const { return m_stop_id != UINT32_MAX; };
+
+ bool ReadMemoryModule(lldb_private::Process *process);
+
+ bool LoadImageUsingMemoryModule(lldb_private::Process *process);
+
+ bool LoadImageUsingFileAddress(lldb_private::Process *process);
+
+ using collection_type = std::vector<KModImageInfo>;
+
+ private:
+ lldb::ModuleSP m_module_sp;
+ lldb::ModuleSP m_memory_module_sp;
+ lldb::addr_t m_load_address = LLDB_INVALID_ADDRESS;
+ lldb_private::UUID m_uuid;
+ bool m_is_kernel = false;
+ std::string m_name;
+ std::string m_path;
+ uint32_t m_stop_id = UINT32_MAX;
+ };
+
+ void PrivateInitialize(lldb_private::Process *process);
+
+ void Clear(bool clear_process);
+
+ void Update();
+
+ void LoadKernelModules();
+
+ void ReadAllKmods();
+
+ bool ReadAllKmods(lldb_private::Address linker_files_head_address,
+ KModImageInfo::collection_type &kmods_list);
+
+ bool ReadKmodsListHeader();
+
+ bool ParseKmods(lldb_private::Address linker_files_head_address);
+
+ void SetNotificationBreakPoint();
+
+ static lldb_private::UUID
+ CheckForKernelImageAtAddress(lldb_private::Process *process,
+ lldb::addr_t address,
+ bool *read_error = nullptr);
+
+ static lldb::addr_t FindKernelAtLoadAddress(lldb_private::Process *process);
+
+ static bool ReadELFHeader(lldb_private::Process *process,
+ lldb::addr_t address, llvm::ELF::Elf32_Ehdr &header,
+ bool *read_error = nullptr);
+
+ lldb_private::Process *m_process;
+ lldb_private::Address m_linker_file_list_struct_addr;
+ lldb_private::Address m_linker_file_head_addr;
+ lldb::addr_t m_kernel_load_address;
+ KModImageInfo m_kernel_image_info;
+ KModImageInfo::collection_type m_linker_files_list;
+ std::recursive_mutex m_mutex;
+ std::unordered_map<std::string, lldb_private::UUID> m_kld_name_to_uuid;
+
+private:
+ DynamicLoaderFreeBSDKernel(const DynamicLoaderFreeBSDKernel &) = delete;
+
+ const DynamicLoaderFreeBSDKernel &
+ operator=(const DynamicLoaderFreeBSDKernel &) = delete;
+};
+
+#endif
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 2da971dff895b4a..43ab87f08e19251 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -935,6 +935,16 @@ lldb_private::Address ObjectFileELF::GetEntryPointAddress() {
}
Address ObjectFileELF::GetBaseAddress() {
+ if (GetType() == ObjectFile::eTypeObjectFile) {
+ for (SectionHeaderCollIter I = std::next(m_section_headers.begin());
+ I != m_section_headers.end(); ++I) {
+ const ELFSectionHeaderInfo &header = *I;
+ if (header.sh_flags & SHF_ALLOC)
+ return Address(GetSectionList()->FindSectionByID(SectionIndex(I)), 0);
+ }
+ return LLDB_INVALID_ADDRESS;
+ }
+
for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) {
const ELFProgramHeader &H = EnumPHdr.value();
if (H.p_type != PT_LOAD)
@@ -1764,7 +1774,12 @@ class VMAddressProvider {
VMRange GetVMRange(const ELFSectionHeader &H) {
addr_t Address = H.sh_addr;
addr_t Size = H.sh_flags & SHF_ALLOC ? H.sh_size : 0;
- if (ObjectType == ObjectFile::Type::eTypeObjectFile && Segments.empty() && (H.sh_flags & SHF_ALLOC)) {
+
+ // When this is a debug file for relocatable file, the address is all zero
+ // and thus needs to use accumulate method
+ if ((ObjectType == ObjectFile::Type::eTypeObjectFile ||
+ (ObjectType == ObjectFile::Type::eTypeDebugInfo && H.sh_addr == 0)) &&
+ Segments.empty() && (H.sh_flags & SHF_ALLOC)) {
NextVMAddress =
llvm::alignTo(NextVMAddress, std::max<addr_t>(H.sh_addralign, 1));
Address = NextVMAddress;
@@ -3454,10 +3469,28 @@ ObjectFile::Strata ObjectFileELF::CalculateStrata() {
case llvm::ELF::ET_EXEC:
// 2 - Executable file
- // TODO: is there any way to detect that an executable is a kernel
- // related executable by inspecting the program headers, section headers,
- // symbols, or any other flag bits???
- return eStrataUser;
+ {
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ static ConstString loader_section_name(".interp");
+ SectionSP loader_section =
+ section_list->FindSectionByName(loader_section_name);
+ if (loader_section) {
+ char buffer[256];
+ size_t read_size =
+ ReadSectionData(loader_section.get(), 0, buffer, sizeof(buffer));
+
+ // We compare the content of .interp section
+ // It will contains \0 when counting read_size, so the size needs to
+ // decrease by one
+ llvm::StringRef loader_name(buffer, read_size - 1);
+ llvm::StringRef freebsd_kernel_loader_name("/red/herring");
+ if (loader_name.equals(freebsd_kernel_loader_name))
+ return eStrataKernel;
+ }
+ }
+ return eStrataUser;
+ }
case llvm::ELF::ET_DYN:
// 3 - Shared object file
diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
index e3707365a9c3f19..601f5df43dbba4e 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -10,7 +10,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/DynamicLoader.h"
-#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+#include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h"
#include "ProcessFreeBSDKernel.h"
#include "ThreadFreeBSDKernel.h"
@@ -262,7 +262,7 @@ Status ProcessFreeBSDKernel::DoLoadCore() {
DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
if (m_dyld_up.get() == nullptr)
m_dyld_up.reset(DynamicLoader::FindPlugin(
- this, DynamicLoaderStatic::GetPluginNameStatic()));
+ this, DynamicLoaderFreeBSDKernel::GetPluginNameStatic()));
return m_dyld_up.get();
}
More information about the lldb-commits
mailing list