================ @@ -0,0 +1,770 @@ +#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/Core/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::eStrataUser) + 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 + Log *log = GetLog(LLDBLog::DynamicLoader); + LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::CreateInstance: " + "Try to create instance"); + if (!force) { + Module *exec = process->GetTarget().GetExecutableModulePointer(); + // Check if the target is kernel + if (exec && !is_kernel(exec)) { + return nullptr; + } + + 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)) + 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()) + 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(); + } + + if (is_kernel(memory_module_sp.get())) { + ArchSpec kernel_arch( + llvm::ELF::convertEMachineToArchName(header.e_machine)); + + if (!process->GetTarget().GetArchitecture().IsCompatibleMatch(kernel_arch)) + process->GetTarget().SetArchitecture(kernel_arch); + + if (log) { + 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(); + } + + return UUID(); +} + +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.c_str()); + + 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) { + if (log) + 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; ---------------- clayborg wrote:
init this to false https://github.com/llvm/llvm-project/pull/67106 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits