aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/DynamicLoader
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/DynamicLoader')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp788
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h171
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp600
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h134
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp370
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h244
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp792
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h369
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp883
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h179
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp150
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h53
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp216
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h53
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp82
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h52
16 files changed, 5136 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
new file mode 100644
index 000000000000..e504e6cbf692
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
@@ -0,0 +1,788 @@
+//===-- 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/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 (PluginManager::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 (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 %zu 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/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h
new file mode 100644
index 000000000000..d8656e9c49df
--- /dev/null
+++ b/contrib/llvm-project/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/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
new file mode 100644
index 000000000000..96c94535c623
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
@@ -0,0 +1,600 @@
+//===-- DynamicLoaderHexagonDYLD.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/BreakpointLocation.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include "DynamicLoaderHexagonDYLD.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderHexagonDYLD)
+
+// Aidan 21/05/2014
+//
+// Notes about hexagon dynamic loading:
+//
+// When we connect to a target we find the dyld breakpoint address. We put
+// a
+// breakpoint there with a callback 'RendezvousBreakpointHit()'.
+//
+// It is possible to find the dyld structure address from the ELF symbol
+// table,
+// but in the case of the simulator it has not been initialized before the
+// target calls dlinit().
+//
+// We can only safely parse the dyld structure after we hit the dyld
+// breakpoint
+// since at that time we know dlinit() must have been called.
+//
+
+// Find the load address of a symbol
+static lldb::addr_t findSymbolAddress(Process *proc, ConstString findName) {
+ assert(proc != nullptr);
+
+ ModuleSP module = proc->GetTarget().GetExecutableModule();
+ assert(module.get() != nullptr);
+
+ ObjectFile *exe = module->GetObjectFile();
+ assert(exe != nullptr);
+
+ lldb_private::Symtab *symtab = exe->GetSymtab();
+ assert(symtab != nullptr);
+
+ for (size_t i = 0; i < symtab->GetNumSymbols(); i++) {
+ const Symbol *sym = symtab->SymbolAtIndex(i);
+ assert(sym != nullptr);
+ ConstString symName = sym->GetName();
+
+ if (ConstString::Compare(findName, symName) == 0) {
+ Address addr = sym->GetAddress();
+ return addr.GetLoadAddress(&proc->GetTarget());
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+void DynamicLoaderHexagonDYLD::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void DynamicLoaderHexagonDYLD::Terminate() {}
+
+llvm::StringRef DynamicLoaderHexagonDYLD::GetPluginDescriptionStatic() {
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in Hexagon processes.";
+}
+
+DynamicLoader *DynamicLoaderHexagonDYLD::CreateInstance(Process *process,
+ bool force) {
+ bool create = force;
+ if (!create) {
+ const llvm::Triple &triple_ref =
+ process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getArch() == llvm::Triple::hexagon)
+ create = true;
+ }
+
+ if (create)
+ return new DynamicLoaderHexagonDYLD(process);
+ return nullptr;
+}
+
+DynamicLoaderHexagonDYLD::DynamicLoaderHexagonDYLD(Process *process)
+ : DynamicLoader(process), m_rendezvous(process),
+ m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS),
+ m_dyld_bid(LLDB_INVALID_BREAK_ID) {}
+
+DynamicLoaderHexagonDYLD::~DynamicLoaderHexagonDYLD() {
+ if (m_dyld_bid != LLDB_INVALID_BREAK_ID) {
+ m_process->GetTarget().RemoveBreakpointByID(m_dyld_bid);
+ m_dyld_bid = LLDB_INVALID_BREAK_ID;
+ }
+}
+
+void DynamicLoaderHexagonDYLD::DidAttach() {
+ ModuleSP executable;
+ addr_t load_offset;
+
+ executable = GetTargetExecutable();
+
+ // Find the difference between the desired load address in the elf file and
+ // the real load address in memory
+ load_offset = ComputeLoadOffset();
+
+ // Check that there is a valid executable
+ if (executable.get() == nullptr)
+ return;
+
+ // Disable JIT for hexagon targets because its not supported
+ m_process->SetCanJIT(false);
+
+ // Enable Interpreting of function call expressions
+ m_process->SetCanInterpretFunctionCalls(true);
+
+ // Add the current executable to the module list
+ ModuleList module_list;
+ module_list.Append(executable);
+
+ // Map the loaded sections of this executable
+ if (load_offset != LLDB_INVALID_ADDRESS)
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true);
+
+ // AD: confirm this?
+ // Load into LLDB all of the currently loaded executables in the stub
+ LoadAllCurrentModules();
+
+ // AD: confirm this?
+ // Callback for the target to give it the loaded module list
+ m_process->GetTarget().ModulesDidLoad(module_list);
+
+ // Try to set a breakpoint at the rendezvous breakpoint. DidLaunch uses
+ // ProbeEntry() instead. That sets a breakpoint, at the dyld breakpoint
+ // address, with a callback so that when hit, the dyld structure can be
+ // parsed.
+ if (!SetRendezvousBreakpoint()) {
+ // fail
+ }
+}
+
+void DynamicLoaderHexagonDYLD::DidLaunch() {}
+
+/// Checks to see if the target module has changed, updates the target
+/// accordingly and returns the target executable module.
+ModuleSP DynamicLoaderHexagonDYLD::GetTargetExecutable() {
+ Target &target = m_process->GetTarget();
+ ModuleSP executable = target.GetExecutableModule();
+
+ // There is no executable
+ if (!executable.get())
+ return executable;
+
+ // The target executable file does not exits
+ if (!FileSystem::Instance().Exists(executable->GetFileSpec()))
+ return executable;
+
+ // Prep module for loading
+ ModuleSpec module_spec(executable->GetFileSpec(),
+ executable->GetArchitecture());
+ ModuleSP module_sp(new Module(module_spec));
+
+ // Check if the executable has changed and set it to the target executable if
+ // they differ.
+ if (module_sp.get() && module_sp->GetUUID().IsValid() &&
+ executable->GetUUID().IsValid()) {
+ // if the executable has changed ??
+ if (module_sp->GetUUID() != executable->GetUUID())
+ executable.reset();
+ } else if (executable->FileHasChanged())
+ executable.reset();
+
+ if (executable.get())
+ return executable;
+
+ // TODO: What case is this code used?
+ executable = target.GetOrCreateModule(module_spec, true /* notify */);
+ if (executable.get() != target.GetExecutableModulePointer()) {
+ // Don't load dependent images since we are in dyld where we will know and
+ // find out about all images that are loaded
+ target.SetExecutableModule(executable, eLoadDependentsNo);
+ }
+
+ return executable;
+}
+
+// AD: Needs to be updated?
+Status DynamicLoaderHexagonDYLD::CanLoadImage() { return Status(); }
+
+void DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module,
+ addr_t link_map_addr,
+ addr_t base_addr,
+ bool base_addr_is_offset) {
+ Target &target = m_process->GetTarget();
+ const SectionList *sections = GetSectionListFromModule(module);
+
+ assert(sections && "SectionList missing from loaded module.");
+
+ m_loaded_modules[module] = link_map_addr;
+
+ const size_t num_sections = sections->GetSize();
+
+ for (unsigned i = 0; i < num_sections; ++i) {
+ SectionSP section_sp(sections->GetSectionAtIndex(i));
+ lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr;
+
+ // AD: 02/05/14
+ // since our memory map starts from address 0, we must not ignore
+ // sections that load to address 0. This violates the reference
+ // ELF spec, however is used for Hexagon.
+
+ // If the file address of the section is zero then this is not an
+ // allocatable/loadable section (property of ELF sh_addr). Skip it.
+ // if (new_load_addr == base_addr)
+ // continue;
+
+ target.SetSectionLoadAddress(section_sp, new_load_addr);
+ }
+}
+
+/// Removes the loaded sections from the target in \p module.
+///
+/// \param module The module to traverse.
+void DynamicLoaderHexagonDYLD::UnloadSections(const ModuleSP module) {
+ Target &target = m_process->GetTarget();
+ const SectionList *sections = GetSectionListFromModule(module);
+
+ assert(sections && "SectionList missing from unloaded module.");
+
+ m_loaded_modules.erase(module);
+
+ const size_t num_sections = sections->GetSize();
+ for (size_t i = 0; i < num_sections; ++i) {
+ SectionSP section_sp(sections->GetSectionAtIndex(i));
+ target.SetSectionUnloaded(section_sp);
+ }
+}
+
+// Place a breakpoint on <_rtld_debug_state>
+bool DynamicLoaderHexagonDYLD::SetRendezvousBreakpoint() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ // This is the original code, which want to look in the rendezvous structure
+ // to find the breakpoint address. Its backwards for us, since we can easily
+ // find the breakpoint address, since it is exported in our executable. We
+ // however know that we cant read the Rendezvous structure until we have hit
+ // the breakpoint once.
+ const ConstString dyldBpName("_rtld_debug_state");
+ addr_t break_addr = findSymbolAddress(m_process, dyldBpName);
+
+ Target &target = m_process->GetTarget();
+
+ // Do not try to set the breakpoint if we don't know where to put it
+ if (break_addr == LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log, "Unable to locate _rtld_debug_state breakpoint address");
+
+ return false;
+ }
+
+ // Save the address of the rendezvous structure
+ m_rendezvous.SetBreakAddress(break_addr);
+
+ // If we haven't set the breakpoint before then set it
+ if (m_dyld_bid == LLDB_INVALID_BREAK_ID) {
+ Breakpoint *dyld_break =
+ target.CreateBreakpoint(break_addr, true, false).get();
+ dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
+ dyld_break->SetBreakpointKind("shared-library-event");
+ m_dyld_bid = dyld_break->GetID();
+
+ // Make sure our breakpoint is at the right address.
+ assert(target.GetBreakpointByID(m_dyld_bid)
+ ->FindLocationByAddress(break_addr)
+ ->GetBreakpoint()
+ .GetID() == m_dyld_bid);
+
+ if (log && dyld_break == nullptr)
+ LLDB_LOGF(log, "Failed to create _rtld_debug_state breakpoint");
+
+ // check we have successfully set bp
+ return (dyld_break != nullptr);
+ } else
+ // rendezvous already set
+ return true;
+}
+
+// We have just hit our breakpoint at <_rtld_debug_state>
+bool DynamicLoaderHexagonDYLD::RendezvousBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ LLDB_LOGF(log, "Rendezvous breakpoint hit!");
+
+ DynamicLoaderHexagonDYLD *dyld_instance = nullptr;
+ dyld_instance = static_cast<DynamicLoaderHexagonDYLD *>(baton);
+
+ // if the dyld_instance is still not valid then try to locate it on the
+ // symbol table
+ if (!dyld_instance->m_rendezvous.IsValid()) {
+ Process *proc = dyld_instance->m_process;
+
+ const ConstString dyldStructName("_rtld_debug");
+ addr_t structAddr = findSymbolAddress(proc, dyldStructName);
+
+ if (structAddr != LLDB_INVALID_ADDRESS) {
+ dyld_instance->m_rendezvous.SetRendezvousAddress(structAddr);
+
+ LLDB_LOGF(log, "Found _rtld_debug structure @ 0x%08" PRIx64, structAddr);
+ } else {
+ LLDB_LOGF(log, "Unable to resolve the _rtld_debug structure");
+ }
+ }
+
+ dyld_instance->RefreshModules();
+
+ // Return true to stop the target, false to just let the target run.
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+/// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+/// of loaded modules.
+void DynamicLoaderHexagonDYLD::RefreshModules() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ if (!m_rendezvous.Resolve())
+ return;
+
+ HexagonDYLDRendezvous::iterator I;
+ HexagonDYLDRendezvous::iterator E;
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+
+ if (m_rendezvous.ModulesDidLoad()) {
+ ModuleList new_modules;
+
+ E = m_rendezvous.loaded_end();
+ for (I = m_rendezvous.loaded_begin(); I != E; ++I) {
+ FileSpec file(I->path);
+ FileSystem::Instance().Resolve(file);
+ ModuleSP module_sp =
+ LoadModuleAtAddress(file, I->link_addr, I->base_addr, true);
+ if (module_sp.get()) {
+ loaded_modules.AppendIfNeeded(module_sp);
+ new_modules.Append(module_sp);
+ }
+
+ if (log) {
+ LLDB_LOGF(log, "Target is loading '%s'", I->path.c_str());
+ if (!module_sp.get())
+ LLDB_LOGF(log, "LLDB failed to load '%s'", I->path.c_str());
+ else
+ LLDB_LOGF(log, "LLDB successfully loaded '%s'", I->path.c_str());
+ }
+ }
+ m_process->GetTarget().ModulesDidLoad(new_modules);
+ }
+
+ if (m_rendezvous.ModulesDidUnload()) {
+ ModuleList old_modules;
+
+ E = m_rendezvous.unloaded_end();
+ for (I = m_rendezvous.unloaded_begin(); I != E; ++I) {
+ FileSpec file(I->path);
+ FileSystem::Instance().Resolve(file);
+ ModuleSpec module_spec(file);
+ ModuleSP module_sp = loaded_modules.FindFirstModule(module_spec);
+
+ if (module_sp.get()) {
+ old_modules.Append(module_sp);
+ UnloadSections(module_sp);
+ }
+
+ LLDB_LOGF(log, "Target is unloading '%s'", I->path.c_str());
+ }
+ loaded_modules.Remove(old_modules);
+ m_process->GetTarget().ModulesDidUnload(old_modules, false);
+ }
+}
+
+// AD: This is very different to the Static Loader code.
+// It may be wise to look over this and its relation to stack
+// unwinding.
+ThreadPlanSP
+DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) {
+ ThreadPlanSP thread_plan_sp;
+
+ StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *sym = context.symbol;
+
+ if (sym == nullptr || !sym->IsTrampoline())
+ return thread_plan_sp;
+
+ const ConstString sym_name =
+ sym->GetMangled().GetName(Mangled::ePreferMangled);
+ if (!sym_name)
+ return thread_plan_sp;
+
+ SymbolContextList target_symbols;
+ Target &target = thread.GetProcess()->GetTarget();
+ const ModuleList &images = target.GetImages();
+
+ images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
+ if (target_symbols.GetSize() == 0)
+ return thread_plan_sp;
+
+ typedef std::vector<lldb::addr_t> AddressVector;
+ AddressVector addrs;
+ for (const SymbolContext &context : target_symbols) {
+ AddressRange range;
+ context.GetAddressRange(eSymbolContextEverything, 0, false, range);
+ lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addrs.push_back(addr);
+ }
+
+ if (addrs.size() > 0) {
+ AddressVector::iterator start = addrs.begin();
+ AddressVector::iterator end = addrs.end();
+
+ llvm::sort(start, end);
+ addrs.erase(std::unique(start, end), end);
+ thread_plan_sp =
+ std::make_shared<ThreadPlanRunToAddress>(thread, addrs, stop);
+ }
+
+ return thread_plan_sp;
+}
+
+/// Helper for the entry breakpoint callback. Resolves the load addresses
+/// of all dependent modules.
+void DynamicLoaderHexagonDYLD::LoadAllCurrentModules() {
+ HexagonDYLDRendezvous::iterator I;
+ HexagonDYLDRendezvous::iterator E;
+ ModuleList module_list;
+
+ if (!m_rendezvous.Resolve()) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(
+ log,
+ "DynamicLoaderHexagonDYLD::%s unable to resolve rendezvous address",
+ __FUNCTION__);
+ return;
+ }
+
+ // The rendezvous class doesn't enumerate the main module, so track that
+ // ourselves here.
+ ModuleSP executable = GetTargetExecutable();
+ m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
+
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) {
+ const char *module_path = I->path.c_str();
+ FileSpec file(module_path);
+ ModuleSP module_sp =
+ LoadModuleAtAddress(file, I->link_addr, I->base_addr, true);
+ if (module_sp.get()) {
+ module_list.Append(module_sp);
+ } else {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log,
+ "DynamicLoaderHexagonDYLD::%s failed loading module %s at "
+ "0x%" PRIx64,
+ __FUNCTION__, module_path, I->base_addr);
+ }
+ }
+
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+/// Computes a value for m_load_offset returning the computed address on
+/// success and LLDB_INVALID_ADDRESS on failure.
+addr_t DynamicLoaderHexagonDYLD::ComputeLoadOffset() {
+ // Here we could send a GDB packet to know the load offset
+ //
+ // send: $qOffsets#4b
+ // get: Text=0;Data=0;Bss=0
+ //
+ // Currently qOffsets is not supported by pluginProcessGDBRemote
+ //
+ return 0;
+}
+
+// Here we must try to read the entry point directly from the elf header. This
+// is possible if the process is not relocatable or dynamically linked.
+//
+// an alternative is to look at the PC if we can be sure that we have connected
+// when the process is at the entry point.
+// I dont think that is reliable for us.
+addr_t DynamicLoaderHexagonDYLD::GetEntryPoint() {
+ if (m_entry_point != LLDB_INVALID_ADDRESS)
+ return m_entry_point;
+ // check we have a valid process
+ if (m_process == nullptr)
+ return LLDB_INVALID_ADDRESS;
+ // Get the current executable module
+ Module &module = *(m_process->GetTarget().GetExecutableModule().get());
+ // Get the object file (elf file) for this module
+ lldb_private::ObjectFile &object = *(module.GetObjectFile());
+ // Check if the file is executable (ie, not shared object or relocatable)
+ if (object.IsExecutable()) {
+ // Get the entry point address for this object
+ lldb_private::Address entry = object.GetEntryPointAddress();
+ // Return the entry point address
+ return entry.GetFileAddress();
+ }
+ // No idea so back out
+ return LLDB_INVALID_ADDRESS;
+}
+
+const SectionList *DynamicLoaderHexagonDYLD::GetSectionListFromModule(
+ const ModuleSP module) const {
+ SectionList *sections = nullptr;
+ if (module.get()) {
+ ObjectFile *obj_file = module->GetObjectFile();
+ if (obj_file) {
+ sections = obj_file->GetSectionList();
+ }
+ }
+ return sections;
+}
+
+static int ReadInt(Process *process, addr_t addr) {
+ Status error;
+ int value = (int)process->ReadUnsignedIntegerFromMemory(
+ addr, sizeof(uint32_t), 0, error);
+ if (error.Fail())
+ return -1;
+ else
+ return value;
+}
+
+lldb::addr_t
+DynamicLoaderHexagonDYLD::GetThreadLocalData(const lldb::ModuleSP module,
+ const lldb::ThreadSP thread,
+ lldb::addr_t tls_file_addr) {
+ auto it = m_loaded_modules.find(module);
+ if (it == m_loaded_modules.end())
+ return LLDB_INVALID_ADDRESS;
+
+ addr_t link_map = it->second;
+ if (link_map == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ const HexagonDYLDRendezvous::ThreadInfo &metadata =
+ m_rendezvous.GetThreadInfo();
+ if (!metadata.valid)
+ return LLDB_INVALID_ADDRESS;
+
+ // Get the thread pointer.
+ addr_t tp = thread->GetThreadPointer();
+ if (tp == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ // Find the module's modid.
+ int modid = ReadInt(m_process, link_map + metadata.modid_offset);
+ if (modid == -1)
+ return LLDB_INVALID_ADDRESS;
+
+ // Lookup the DTV structure for this thread.
+ addr_t dtv_ptr = tp + metadata.dtv_offset;
+ addr_t dtv = ReadPointer(dtv_ptr);
+ if (dtv == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ // Find the TLS block for this module.
+ addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid;
+ addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset);
+
+ Module *mod = module.get();
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log,
+ "DynamicLoaderHexagonDYLD::Performed TLS lookup: "
+ "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64
+ ", modid=%i, tls_block=0x%" PRIx64,
+ mod->GetObjectName().AsCString(""), link_map, tp, modid, tls_block);
+
+ if (tls_block == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+ else
+ return tls_block + tls_file_addr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h
new file mode 100644
index 000000000000..54711f5e6bb3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h
@@ -0,0 +1,134 @@
+//===-- DynamicLoaderHexagonDYLD.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_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "HexagonDYLDRendezvous.h"
+
+class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader {
+public:
+ DynamicLoaderHexagonDYLD(lldb_private::Process *process);
+
+ ~DynamicLoaderHexagonDYLD() override;
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "hexagon-dyld"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process, bool force);
+
+ // DynamicLoader protocol
+
+ void DidAttach() override;
+
+ void DidLaunch() override;
+
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others) override;
+
+ lldb_private::Status CanLoadImage() override;
+
+ lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module,
+ const lldb::ThreadSP thread,
+ lldb::addr_t tls_file_addr) override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+protected:
+ /// Runtime linker rendezvous structure.
+ HexagonDYLDRendezvous m_rendezvous;
+
+ /// Virtual load address of the inferior process.
+ lldb::addr_t m_load_offset;
+
+ /// Virtual entry address of the inferior process.
+ lldb::addr_t m_entry_point;
+
+ /// Rendezvous breakpoint.
+ lldb::break_id_t m_dyld_bid;
+
+ /// Loaded module list. (link map for each module)
+ std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
+ m_loaded_modules;
+
+ /// Enables a breakpoint on a function called by the runtime
+ /// linker each time a module is loaded or unloaded.
+ bool SetRendezvousBreakpoint();
+
+ /// Callback routine which updates the current list of loaded modules based
+ /// on the information supplied by the runtime linker.
+ static bool RendezvousBreakpointHit(
+ void *baton, lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+ /// of loaded modules.
+ void RefreshModules();
+
+ /// Updates the load address of every allocatable section in \p module.
+ ///
+ /// \param module The module to traverse.
+ ///
+ /// \param link_map_addr The virtual address of the link map for the @p
+ /// module.
+ ///
+ /// \param base_addr The virtual base address \p module is loaded at.
+ void UpdateLoadedSections(lldb::ModuleSP module, lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr,
+ bool base_addr_is_offset) override;
+
+ /// Removes the loaded sections from the target in \p module.
+ ///
+ /// \param module The module to traverse.
+ void UnloadSections(const lldb::ModuleSP module) override;
+
+ /// Callback routine invoked when we hit the breakpoint on process entry.
+ ///
+ /// This routine is responsible for resolving the load addresses of all
+ /// dependent modules required by the inferior and setting up the rendezvous
+ /// breakpoint.
+ static bool
+ EntryBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ /// Helper for the entry breakpoint callback. Resolves the load addresses
+ /// of all dependent modules.
+ void LoadAllCurrentModules();
+
+ /// Computes a value for m_load_offset returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t ComputeLoadOffset();
+
+ /// Computes a value for m_entry_point returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t GetEntryPoint();
+
+ /// Checks to see if the target module has changed, updates the target
+ /// accordingly and returns the target executable module.
+ lldb::ModuleSP GetTargetExecutable();
+
+ /// return the address of the Rendezvous breakpoint
+ lldb::addr_t FindRendezvousBreakpointAddress();
+
+private:
+ const lldb_private::SectionList *
+ GetSectionListFromModule(const lldb::ModuleSP module) const;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
new file mode 100644
index 000000000000..d2bf2586cd82
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
@@ -0,0 +1,370 @@
+//===-- HexagonDYLDRendezvous.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/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "HexagonDYLDRendezvous.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// Locates the address of the rendezvous structure. Returns the address on
+/// success and LLDB_INVALID_ADDRESS on failure.
+static addr_t ResolveRendezvousAddress(Process *process) {
+ addr_t info_location;
+ addr_t info_addr;
+ Status error;
+
+ info_location = process->GetImageInfoAddress();
+
+ if (info_location == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ info_addr = process->ReadPointerFromMemory(info_location, error);
+ if (error.Fail())
+ return LLDB_INVALID_ADDRESS;
+
+ if (info_addr == 0)
+ return LLDB_INVALID_ADDRESS;
+
+ return info_addr;
+}
+
+HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process)
+ : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
+ m_previous(), m_soentries(), m_added_soentries(), m_removed_soentries() {
+ m_thread_info.valid = false;
+ m_thread_info.dtv_offset = 0;
+ m_thread_info.dtv_slot_size = 0;
+ m_thread_info.modid_offset = 0;
+ m_thread_info.tls_offset = 0;
+
+ // Cache a copy of the executable path
+ if (m_process) {
+ Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
+ if (exe_mod)
+ exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+ }
+}
+
+bool HexagonDYLDRendezvous::Resolve() {
+ const size_t word_size = 4;
+ Rendezvous info;
+ size_t address_size;
+ size_t padding;
+ addr_t info_addr;
+ addr_t cursor;
+
+ address_size = m_process->GetAddressByteSize();
+ padding = address_size - word_size;
+
+ if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
+ cursor = info_addr = ResolveRendezvousAddress(m_process);
+ else
+ cursor = info_addr = m_rendezvous_addr;
+
+ if (cursor == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (!(cursor = ReadWord(cursor, &info.version, word_size)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor, &info.brk)))
+ return false;
+
+ if (!(cursor = ReadWord(cursor, &info.state, word_size)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
+ return false;
+
+ // The rendezvous was successfully read. Update our internal state.
+ m_rendezvous_addr = info_addr;
+ m_previous = m_current;
+ m_current = info;
+
+ return UpdateSOEntries();
+}
+
+void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) {
+ m_rendezvous_addr = addr;
+}
+
+bool HexagonDYLDRendezvous::IsValid() {
+ return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
+}
+
+bool HexagonDYLDRendezvous::UpdateSOEntries() {
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ // When the previous and current states are consistent this is the first time
+ // we have been asked to update. Just take a snapshot of the currently
+ // loaded modules.
+ if (m_previous.state == eConsistent && m_current.state == eConsistent)
+ return TakeSnapshot(m_soentries);
+
+ // If we are about to add or remove a shared object clear out the current
+ // state and take a snapshot of the currently loaded images.
+ if (m_current.state == eAdd || m_current.state == eDelete) {
+ // this is a fudge so that we can clear the assert below.
+ m_previous.state = eConsistent;
+ // We hit this assert on the 2nd run of this function after running the
+ // calc example
+ assert(m_previous.state == eConsistent);
+ m_soentries.clear();
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
+ return TakeSnapshot(m_soentries);
+ }
+ assert(m_current.state == eConsistent);
+
+ // Otherwise check the previous state to determine what to expect and update
+ // accordingly.
+ if (m_previous.state == eAdd)
+ return UpdateSOEntriesForAddition();
+ else if (m_previous.state == eDelete)
+ return UpdateSOEntriesForDeletion();
+
+ return false;
+}
+
+bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() {
+ SOEntry entry;
+ iterator pos;
+
+ assert(m_previous.state == eAdd);
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable. On Linux this is
+ // indicated by an empty path in the entry. On FreeBSD it is the name of
+ // the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ if (!llvm::is_contained(m_soentries, entry)) {
+ m_soentries.push_back(entry);
+ m_added_soentries.push_back(entry);
+ }
+ }
+
+ return true;
+}
+
+bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() {
+ SOEntryList entry_list;
+ iterator pos;
+
+ assert(m_previous.state == eDelete);
+
+ if (!TakeSnapshot(entry_list))
+ return false;
+
+ for (iterator I = begin(); I != end(); ++I) {
+ if (!llvm::is_contained(entry_list, *I))
+ m_removed_soentries.push_back(*I);
+ }
+
+ m_soentries = entry_list;
+ return true;
+}
+
+bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable. On Linux this is
+ // indicated by an empty path in the entry. On FreeBSD it is the name of
+ // the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ entry_list.push_back(entry);
+ }
+
+ return true;
+}
+
+addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,
+ size_t size) {
+ Status error;
+
+ *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
+ if (error.Fail())
+ return 0;
+
+ return addr + size;
+}
+
+addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
+ Status error;
+
+ *dst = m_process->ReadPointerFromMemory(addr, error);
+ if (error.Fail())
+ return 0;
+
+ return addr + m_process->GetAddressByteSize();
+}
+
+std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) {
+ std::string str;
+ Status error;
+ size_t size;
+ char c;
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ return std::string();
+
+ for (;;) {
+ size = m_process->ReadMemory(addr, &c, 1, error);
+ if (size != 1 || error.Fail())
+ return std::string();
+ if (c == 0)
+ break;
+ else {
+ str.push_back(c);
+ addr++;
+ }
+ }
+
+ return str;
+}
+
+bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr,
+ SOEntry &entry) {
+ entry.clear();
+ entry.link_addr = addr;
+
+ if (!(addr = ReadPointer(addr, &entry.base_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.path_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.next)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.prev)))
+ return false;
+
+ entry.path = ReadStringFromMemory(entry.path_addr);
+
+ return true;
+}
+
+bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field,
+ uint32_t &value) {
+ Target &target = m_process->GetTarget();
+
+ SymbolContextList list;
+ target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
+ eSymbolTypeAny, list);
+ if (list.IsEmpty())
+ return false;
+
+ Address address = list[0].symbol->GetAddress();
+ addr_t addr = address.GetLoadAddress(&target);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Status error;
+ value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
+ addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
+ if (error.Fail())
+ return false;
+
+ if (field == eSize)
+ value /= 8; // convert bits to bytes
+
+ return true;
+}
+
+const HexagonDYLDRendezvous::ThreadInfo &
+HexagonDYLDRendezvous::GetThreadInfo() {
+ if (!m_thread_info.valid) {
+ bool ok = true;
+
+ ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
+ m_thread_info.dtv_offset);
+ ok &=
+ FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
+ ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
+ m_thread_info.modid_offset);
+ ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
+ m_thread_info.tls_offset);
+
+ if (ok)
+ m_thread_info.valid = true;
+ }
+
+ return m_thread_info;
+}
+
+void HexagonDYLDRendezvous::DumpToLog(Log *log) const {
+ int state = GetState();
+
+ if (!log)
+ return;
+
+ log->PutCString("HexagonDYLDRendezvous:");
+ LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress());
+ LLDB_LOGF(log, " Version: %" PRIu64, GetVersion());
+ LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress());
+ LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress());
+ LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase());
+ LLDB_LOGF(log, " State : %s",
+ (state == eConsistent)
+ ? "consistent"
+ : (state == eAdd) ? "add"
+ : (state == eDelete) ? "delete" : "unknown");
+
+ iterator I = begin();
+ iterator E = end();
+
+ if (I != E)
+ log->PutCString("HexagonDYLDRendezvous SOEntries:");
+
+ for (int i = 1; I != E; ++I, ++i) {
+ LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->path.c_str());
+ LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr);
+ LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr);
+ LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr);
+ LLDB_LOGF(log, " Next : %" PRIx64, I->next);
+ LLDB_LOGF(log, " Prev : %" PRIx64, I->prev);
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h
new file mode 100644
index 000000000000..c34e02ed5678
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h
@@ -0,0 +1,244 @@
+//===-- HexagonDYLDRendezvous.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_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H
+
+#include <limits.h>
+#include <list>
+#include <map>
+#include <string>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+class Process;
+}
+
+/// \class HexagonDYLDRendezvous
+/// Interface to the runtime linker.
+///
+/// A structure is present in a processes memory space which is updated by the
+/// runtime liker each time a module is loaded or unloaded. This class
+/// provides an interface to this structure and maintains a consistent
+/// snapshot of the currently loaded modules.
+class HexagonDYLDRendezvous {
+
+ // This structure is used to hold the contents of the debug rendezvous
+ // information (struct r_debug) as found in the inferiors memory. Note that
+ // the layout of this struct is not binary compatible, it is simply large
+ // enough to hold the information on both 32 and 64 bit platforms.
+ struct Rendezvous {
+ uint64_t version = 0;
+ lldb::addr_t map_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t brk = LLDB_INVALID_ADDRESS;
+ uint64_t state = 0;
+ lldb::addr_t ldbase = 0;
+
+ Rendezvous() = default;
+ };
+
+public:
+ // Various metadata supplied by the inferior's threading library to describe
+ // the per-thread state.
+ struct ThreadInfo {
+ bool valid; // whether we read valid metadata
+ uint32_t dtv_offset; // offset of DTV pointer within pthread
+ uint32_t dtv_slot_size; // size of one DTV slot
+ uint32_t modid_offset; // offset of module ID within link_map
+ uint32_t tls_offset; // offset of TLS pointer within DTV slot
+ };
+
+ HexagonDYLDRendezvous(lldb_private::Process *process);
+
+ /// Update the internal snapshot of runtime linker rendezvous and recompute
+ /// the currently loaded modules.
+ ///
+ /// This method should be called once one start up, then once each time the
+ /// runtime linker enters the function given by GetBreakAddress().
+ ///
+ /// \returns true on success and false on failure.
+ ///
+ /// \see GetBreakAddress().
+ bool Resolve();
+
+ /// \returns true if this rendezvous has been located in the inferiors
+ /// address space and false otherwise.
+ bool IsValid();
+
+ /// \returns the address of the rendezvous structure in the inferiors
+ /// address space.
+ lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }
+
+ /// Provide the dyld structure address
+ void SetRendezvousAddress(lldb::addr_t);
+
+ /// \returns the version of the rendezvous protocol being used.
+ uint64_t GetVersion() const { return m_current.version; }
+
+ /// \returns address in the inferiors address space containing the linked
+ /// list of shared object descriptors.
+ lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; }
+
+ /// A breakpoint should be set at this address and Resolve called on each
+ /// hit.
+ ///
+ /// \returns the address of a function called by the runtime linker each
+ /// time a module is loaded/unloaded, or about to be loaded/unloaded.
+ ///
+ /// \see Resolve()
+ lldb::addr_t GetBreakAddress() const { return m_current.brk; }
+
+ /// In hexagon it is possible that we can know the dyld breakpoint without
+ /// having to find it from the rendezvous structure
+ ///
+ void SetBreakAddress(lldb::addr_t addr) { m_current.brk = addr; }
+
+ /// Returns the current state of the rendezvous structure.
+ uint64_t GetState() const { return m_current.state; }
+
+ /// \returns the base address of the runtime linker in the inferiors address
+ /// space.
+ lldb::addr_t GetLDBase() const { return m_current.ldbase; }
+
+ /// \returns the thread layout metadata from the inferiors thread library.
+ const ThreadInfo &GetThreadInfo();
+
+ /// \returns true if modules have been loaded into the inferior since the
+ /// last call to Resolve().
+ bool ModulesDidLoad() const { return !m_added_soentries.empty(); }
+
+ /// \returns true if modules have been unloaded from the inferior since the
+ /// last call to Resolve().
+ bool ModulesDidUnload() const { return !m_removed_soentries.empty(); }
+
+ void DumpToLog(lldb_private::Log *log) const;
+
+ /// Constants describing the state of the rendezvous.
+ ///
+ /// \see GetState().
+ enum RendezvousState {
+ eConsistent = 0,
+ eAdd,
+ eDelete,
+ };
+
+ /// Structure representing the shared objects currently loaded into the
+ /// inferior process.
+ ///
+ /// This object is a rough analogue to the struct link_map object which
+ /// actually lives in the inferiors memory.
+ struct SOEntry {
+ lldb::addr_t link_addr; ///< Address of this link_map.
+ lldb::addr_t base_addr; ///< Base address of the loaded object.
+ lldb::addr_t path_addr; ///< String naming the shared object.
+ lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
+ lldb::addr_t next; ///< Address of next so_entry.
+ lldb::addr_t prev; ///< Address of previous so_entry.
+ std::string path; ///< File name of shared object.
+
+ SOEntry() { clear(); }
+
+ bool operator==(const SOEntry &entry) { return this->path == entry.path; }
+
+ void clear() {
+ link_addr = 0;
+ base_addr = 0;
+ path_addr = 0;
+ dyn_addr = 0;
+ next = 0;
+ prev = 0;
+ path.clear();
+ }
+ };
+
+protected:
+ typedef std::list<SOEntry> SOEntryList;
+
+public:
+ typedef SOEntryList::const_iterator iterator;
+
+ /// Iterators over all currently loaded modules.
+ iterator begin() const { return m_soentries.begin(); }
+ iterator end() const { return m_soentries.end(); }
+
+ /// Iterators over all modules loaded into the inferior since the last call
+ /// to Resolve().
+ iterator loaded_begin() const { return m_added_soentries.begin(); }
+ iterator loaded_end() const { return m_added_soentries.end(); }
+
+ /// Iterators over all modules unloaded from the inferior since the last
+ /// call to Resolve().
+ iterator unloaded_begin() const { return m_removed_soentries.begin(); }
+ iterator unloaded_end() const { return m_removed_soentries.end(); }
+
+protected:
+ lldb_private::Process *m_process;
+
+ // Cached copy of executable pathname
+ char m_exe_path[PATH_MAX];
+
+ /// Location of the r_debug structure in the inferiors address space.
+ lldb::addr_t m_rendezvous_addr;
+
+ /// Current and previous snapshots of the rendezvous structure.
+ Rendezvous m_current;
+ Rendezvous m_previous;
+
+ /// List of SOEntry objects corresponding to the current link map state.
+ SOEntryList m_soentries;
+
+ /// List of SOEntry's added to the link map since the last call to
+ /// Resolve().
+ SOEntryList m_added_soentries;
+
+ /// List of SOEntry's removed from the link map since the last call to
+ /// Resolve().
+ SOEntryList m_removed_soentries;
+
+ /// Threading metadata read from the inferior.
+ ThreadInfo m_thread_info;
+
+ /// Reads an unsigned integer of \p size bytes from the inferior's address
+ /// space starting at \p addr.
+ ///
+ /// \returns addr + size if the read was successful and false otherwise.
+ lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
+
+ /// Reads an address from the inferior's address space starting at \p addr.
+ ///
+ /// \returns addr + target address size if the read was successful and
+ /// 0 otherwise.
+ lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);
+
+ /// Reads a null-terminated C string from the memory location starting at @p
+ /// addr.
+ std::string ReadStringFromMemory(lldb::addr_t addr);
+
+ /// Reads an SOEntry starting at \p addr.
+ bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
+
+ /// Updates the current set of SOEntries, the set of added entries, and the
+ /// set of removed entries.
+ bool UpdateSOEntries();
+
+ bool UpdateSOEntriesForAddition();
+
+ bool UpdateSOEntriesForDeletion();
+
+ /// Reads the current list of shared objects according to the link map
+ /// supplied by the runtime linker.
+ bool TakeSnapshot(SOEntryList &entry_list);
+
+ enum PThreadField { eSize, eNElem, eOffset };
+
+ bool FindMetadata(const char *name, PThreadField field, uint32_t &value);
+};
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
new file mode 100644
index 000000000000..1a9c4593b1b4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -0,0 +1,792 @@
+//===-- DYLDRendezvous.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/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+
+#include "llvm/Support/Path.h"
+
+#include "DYLDRendezvous.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *DYLDRendezvous::StateToCStr(RendezvousState state) {
+ switch (state) {
+ case DYLDRendezvous::eConsistent:
+ return "eConsistent";
+ case DYLDRendezvous::eAdd:
+ return "eAdd";
+ case DYLDRendezvous::eDelete:
+ return "eDelete";
+ }
+ return "<invalid RendezvousState>";
+}
+
+const char *DYLDRendezvous::ActionToCStr(RendezvousAction action) {
+ switch (action) {
+ case DYLDRendezvous::RendezvousAction::eTakeSnapshot:
+ return "eTakeSnapshot";
+ case DYLDRendezvous::RendezvousAction::eAddModules:
+ return "eAddModules";
+ case DYLDRendezvous::RendezvousAction::eRemoveModules:
+ return "eRemoveModules";
+ case DYLDRendezvous::RendezvousAction::eNoAction:
+ return "eNoAction";
+ }
+ return "<invalid RendezvousAction>";
+}
+
+DYLDRendezvous::DYLDRendezvous(Process *process)
+ : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS),
+ m_executable_interpreter(false), m_current(), m_previous(),
+ m_loaded_modules(), m_soentries(), m_added_soentries(),
+ m_removed_soentries() {
+ m_thread_info.valid = false;
+ UpdateExecutablePath();
+}
+
+addr_t DYLDRendezvous::ResolveRendezvousAddress() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ addr_t info_location;
+ addr_t info_addr;
+ Status error;
+
+ if (!m_process) {
+ LLDB_LOGF(log, "%s null process provided", __FUNCTION__);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Try to get it from our process. This might be a remote process and might
+ // grab it via some remote-specific mechanism.
+ info_location = m_process->GetImageInfoAddress();
+ LLDB_LOGF(log, "%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
+
+ // If the process fails to return an address, fall back to seeing if the
+ // local object file can help us find it.
+ if (info_location == LLDB_INVALID_ADDRESS) {
+ Target *target = &m_process->GetTarget();
+ if (target) {
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(target);
+
+ if (addr.IsValid()) {
+ info_location = addr.GetLoadAddress(target);
+ LLDB_LOGF(log,
+ "%s resolved via direct object file approach to 0x%" PRIx64,
+ __FUNCTION__, info_location);
+ } else {
+ const Symbol *_r_debug =
+ target->GetExecutableModule()->FindFirstSymbolWithNameAndType(
+ ConstString("_r_debug"));
+ if (_r_debug) {
+ info_addr = _r_debug->GetAddress().GetLoadAddress(target);
+ if (info_addr != LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log,
+ "%s resolved by finding symbol '_r_debug' whose value is "
+ "0x%" PRIx64,
+ __FUNCTION__, info_addr);
+ m_executable_interpreter = true;
+ return info_addr;
+ }
+ }
+ LLDB_LOGF(log,
+ "%s FAILED - direct object file approach did not yield a "
+ "valid address",
+ __FUNCTION__);
+ }
+ }
+ }
+
+ if (info_location == LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log, "%s FAILED - invalid info address", __FUNCTION__);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ LLDB_LOGF(log, "%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64,
+ __FUNCTION__, m_process->GetAddressByteSize(), info_location);
+
+ info_addr = m_process->ReadPointerFromMemory(info_location, error);
+ if (error.Fail()) {
+ LLDB_LOGF(log, "%s FAILED - could not read from the info location: %s",
+ __FUNCTION__, error.AsCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ if (info_addr == 0) {
+ LLDB_LOGF(log,
+ "%s FAILED - the rendezvous address contained at 0x%" PRIx64
+ " returned a null value",
+ __FUNCTION__, info_location);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ return info_addr;
+}
+
+void DYLDRendezvous::UpdateExecutablePath() {
+ if (m_process) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
+ if (exe_mod) {
+ m_exe_file_spec = exe_mod->GetPlatformFileSpec();
+ LLDB_LOGF(log, "DYLDRendezvous::%s exe module executable path set: '%s'",
+ __FUNCTION__, m_exe_file_spec.GetPath().c_str());
+ } else {
+ LLDB_LOGF(log,
+ "DYLDRendezvous::%s cannot cache exe module path: null "
+ "executable module pointer",
+ __FUNCTION__);
+ }
+ }
+}
+
+void DYLDRendezvous::Rendezvous::DumpToLog(Log *log, const char *label) {
+ LLDB_LOGF(log, "%s Rendezvous: version = %" PRIu64 ", map_addr = 0x%16.16"
+ PRIx64 ", brk = 0x%16.16" PRIx64 ", state = %" PRIu64
+ " (%s), ldbase = 0x%16.16" PRIx64, label ? label : "", version,
+ map_addr, brk, state, StateToCStr((RendezvousState)state), ldbase);
+}
+
+bool DYLDRendezvous::Resolve() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ const size_t word_size = 4;
+ Rendezvous info;
+ size_t address_size;
+ size_t padding;
+ addr_t info_addr;
+ addr_t cursor;
+
+ address_size = m_process->GetAddressByteSize();
+ padding = address_size - word_size;
+ LLDB_LOGF(log,
+ "DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64,
+ __FUNCTION__, uint64_t(address_size), uint64_t(padding));
+
+ if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
+ cursor = info_addr =
+ ResolveRendezvousAddress();
+ else
+ cursor = info_addr = m_rendezvous_addr;
+ LLDB_LOGF(log, "DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__,
+ cursor);
+
+ if (cursor == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (!(cursor = ReadWord(cursor, &info.version, word_size)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor, &info.brk)))
+ return false;
+
+ if (!(cursor = ReadWord(cursor, &info.state, word_size)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
+ return false;
+
+ // The rendezvous was successfully read. Update our internal state.
+ m_rendezvous_addr = info_addr;
+ m_previous = m_current;
+ m_current = info;
+
+ m_previous.DumpToLog(log, "m_previous");
+ m_current.DumpToLog(log, "m_current ");
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ if (UpdateSOEntriesFromRemote())
+ return true;
+
+ return UpdateSOEntries();
+}
+
+bool DYLDRendezvous::IsValid() {
+ return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
+}
+
+DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const {
+ // If we have a core file, we will read the current rendezvous state
+ // from the core file's memory into m_current which can be in an inconsistent
+ // state, so we can't rely on its state to determine what we should do. We
+ // always need it to load all of the shared libraries one time when we attach
+ // to a core file.
+ if (IsCoreFile())
+ return eTakeSnapshot;
+
+ switch (m_current.state) {
+
+ case eConsistent:
+ switch (m_previous.state) {
+ // When the previous and current states are consistent this is the first
+ // time we have been asked to update. Just take a snapshot of the
+ // currently loaded modules.
+ case eConsistent:
+ return eTakeSnapshot;
+ // If we are about to add or remove a shared object clear out the current
+ // state and take a snapshot of the currently loaded images.
+ case eAdd:
+ return eAddModules;
+ case eDelete:
+ return eRemoveModules;
+ }
+ break;
+
+ case eAdd:
+ // If the main executable or a shared library defines a publicly visible
+ // symbol named "_r_debug", then it will cause problems once the executable
+ // that contains the symbol is loaded into the process. The correct
+ // "_r_debug" structure is currently found by LLDB by looking through
+ // the .dynamic section in the main executable and finding the DT_DEBUG tag
+ // entry.
+ //
+ // An issue comes up if someone defines another publicly visible "_r_debug"
+ // struct in their program. Sample code looks like:
+ //
+ // #include <link.h>
+ // r_debug _r_debug;
+ //
+ // If code like this is in an executable or shared library, this creates a
+ // new "_r_debug" structure and it causes problems once the executable is
+ // loaded due to the way symbol lookups happen in linux: the shared library
+ // list from _r_debug.r_map will be searched for a symbol named "_r_debug"
+ // and the first match will be the new version that is used. The dynamic
+ // loader is always last in this list. So at some point the dynamic loader
+ // will start updating the copy of "_r_debug" that gets found first. The
+ // issue is that LLDB will only look at the copy that is pointed to by the
+ // DT_DEBUG entry, or the initial version from the ld.so binary.
+ //
+ // Steps that show the problem are:
+ //
+ // - LLDB finds the "_r_debug" structure via the DT_DEBUG entry in the
+ // .dynamic section and this points to the "_r_debug" in ld.so
+ // - ld.so uodates its copy of "_r_debug" with "state = eAdd" before it
+ // loads the dependent shared libraries for the main executable and
+ // any dependencies of all shared libraries from the executable's list
+ // and ld.so code calls the debugger notification function
+ // that LLDB has set a breakpoint on.
+ // - LLDB hits the breakpoint and the breakpoint has a callback function
+ // where we read the _r_debug.state (eAdd) state and we do nothing as the
+ // "eAdd" state indicates that the shared libraries are about to be added.
+ // - ld.so finishes loading the main executable and any dependent shared
+ // libraries and it will update the "_r_debug.state" member with a
+ // "eConsistent", but it now updates the "_r_debug" in the a.out program
+ // and it calls the debugger notification function.
+ // - lldb hits the notification breakpoint and checks the ld.so copy of
+ // "_r_debug.state" which still has a state of "eAdd", but LLDB needs to see a
+ // "eConsistent" state to trigger the shared libraries to get loaded into
+ // the debug session, but LLDB the ld.so _r_debug.state which still
+ // contains "eAdd" and doesn't do anyhing and library load is missed.
+ // The "_r_debug" in a.out has the state set correctly to "eConsistent"
+ // but LLDB is still looking at the "_r_debug" from ld.so.
+ //
+ // So if we detect two "eAdd" states in a row, we assume this is the issue
+ // and we now load shared libraries correctly and will emit a log message
+ // in the "log enable lldb dyld" log channel which states there might be
+ // multiple "_r_debug" structs causing problems.
+ //
+ // The correct solution is that no one should be adding a duplicate
+ // publicly visible "_r_debug" symbols to their binaries, but we have
+ // programs that are doing this already and since it can be done, we should
+ // be able to work with this and keep debug sessions working as expected.
+ //
+ // If a user includes the <link.h> file, they can just use the existing
+ // "_r_debug" structure as it is defined in this header file as "extern
+ // struct r_debug _r_debug;" and no local copies need to be made.
+ if (m_previous.state == eAdd) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOG(log, "DYLDRendezvous::GetAction() found two eAdd states in a "
+ "row, check process for multiple \"_r_debug\" symbols. "
+ "Returning eAddModules to ensure shared libraries get loaded "
+ "correctly");
+ return eAddModules;
+ }
+ return eNoAction;
+ case eDelete:
+ return eNoAction;
+ }
+
+ return eNoAction;
+}
+
+bool DYLDRendezvous::UpdateSOEntriesFromRemote() {
+ const auto action = GetAction();
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOG(log, "{0} action = {1}", LLVM_PRETTY_FUNCTION, ActionToCStr(action));
+
+ if (action == eNoAction)
+ return false;
+
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
+ if (action == eTakeSnapshot) {
+ // We already have the loaded list from the previous update so no need to
+ // find all the modules again.
+ if (!m_loaded_modules.m_list.empty())
+ return true;
+ }
+
+ llvm::Expected<LoadedModuleInfoList> module_list =
+ m_process->GetLoadedModuleList();
+ if (!module_list) {
+ llvm::consumeError(module_list.takeError());
+ return false;
+ }
+
+ switch (action) {
+ case eTakeSnapshot:
+ m_soentries.clear();
+ return SaveSOEntriesFromRemote(*module_list);
+ case eAddModules:
+ return AddSOEntriesFromRemote(*module_list);
+ case eRemoveModules:
+ return RemoveSOEntriesFromRemote(*module_list);
+ case eNoAction:
+ return false;
+ }
+ llvm_unreachable("Fully covered switch above!");
+}
+
+bool DYLDRendezvous::UpdateSOEntries() {
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
+ const auto action = GetAction();
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOG(log, "{0} action = {1}", LLVM_PRETTY_FUNCTION, ActionToCStr(action));
+ switch (action) {
+ case eTakeSnapshot:
+ m_soentries.clear();
+ return TakeSnapshot(m_soentries);
+ case eAddModules:
+ return AddSOEntries();
+ case eRemoveModules:
+ return RemoveSOEntries();
+ case eNoAction:
+ return false;
+ }
+ llvm_unreachable("Fully covered switch above!");
+}
+
+bool DYLDRendezvous::FillSOEntryFromModuleInfo(
+ LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry) {
+ addr_t link_map_addr;
+ addr_t base_addr;
+ addr_t dyn_addr;
+ std::string name;
+
+ if (!modInfo.get_link_map(link_map_addr) || !modInfo.get_base(base_addr) ||
+ !modInfo.get_dynamic(dyn_addr) || !modInfo.get_name(name))
+ return false;
+
+ entry.link_addr = link_map_addr;
+ entry.base_addr = base_addr;
+ entry.dyn_addr = dyn_addr;
+
+ entry.file_spec.SetFile(name, FileSpec::Style::native);
+
+ UpdateBaseAddrIfNecessary(entry, name);
+
+ // not needed if we're using ModuleInfos
+ entry.next = 0;
+ entry.prev = 0;
+ entry.path_addr = 0;
+
+ return true;
+}
+
+bool DYLDRendezvous::SaveSOEntriesFromRemote(
+ const LoadedModuleInfoList &module_list) {
+ for (auto const &modInfo : module_list.m_list) {
+ SOEntry entry;
+ if (!FillSOEntryFromModuleInfo(modInfo, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ if (!SOEntryIsMainExecutable(entry)) {
+ UpdateFileSpecIfNecessary(entry);
+ m_soentries.push_back(entry);
+ }
+ }
+
+ m_loaded_modules = module_list;
+ return true;
+}
+
+bool DYLDRendezvous::AddSOEntriesFromRemote(
+ const LoadedModuleInfoList &module_list) {
+ for (auto const &modInfo : module_list.m_list) {
+ bool found = false;
+ for (auto const &existing : m_loaded_modules.m_list) {
+ if (modInfo == existing) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ SOEntry entry;
+ if (!FillSOEntryFromModuleInfo(modInfo, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ if (!SOEntryIsMainExecutable(entry)) {
+ UpdateFileSpecIfNecessary(entry);
+ m_soentries.push_back(entry);
+ m_added_soentries.push_back(entry);
+ }
+ }
+
+ m_loaded_modules = module_list;
+ return true;
+}
+
+bool DYLDRendezvous::RemoveSOEntriesFromRemote(
+ const LoadedModuleInfoList &module_list) {
+ for (auto const &existing : m_loaded_modules.m_list) {
+ bool found = false;
+ for (auto const &modInfo : module_list.m_list) {
+ if (modInfo == existing) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ SOEntry entry;
+ if (!FillSOEntryFromModuleInfo(existing, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ if (!SOEntryIsMainExecutable(entry)) {
+ auto pos = llvm::find(m_soentries, entry);
+ if (pos == m_soentries.end())
+ return false;
+
+ m_soentries.erase(pos);
+ m_removed_soentries.push_back(entry);
+ }
+ }
+
+ m_loaded_modules = module_list;
+ return true;
+}
+
+bool DYLDRendezvous::AddSOEntries() {
+ SOEntry entry;
+ iterator pos;
+
+ assert(m_previous.state == eAdd);
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ if (SOEntryIsMainExecutable(entry))
+ continue;
+
+ UpdateFileSpecIfNecessary(entry);
+
+ if (!llvm::is_contained(m_soentries, entry)) {
+ m_soentries.push_back(entry);
+ m_added_soentries.push_back(entry);
+ }
+ }
+
+ return true;
+}
+
+bool DYLDRendezvous::RemoveSOEntries() {
+ SOEntryList entry_list;
+ iterator pos;
+
+ assert(m_previous.state == eDelete);
+
+ if (!TakeSnapshot(entry_list))
+ return false;
+
+ for (iterator I = begin(); I != end(); ++I) {
+ if (!llvm::is_contained(entry_list, *I))
+ m_removed_soentries.push_back(*I);
+ }
+
+ m_soentries = entry_list;
+ return true;
+}
+
+bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
+ // On some systes the executable is indicated by an empty path in the entry.
+ // On others it is the full path to the executable.
+
+ auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
+ switch (triple.getOS()) {
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ case llvm::Triple::OpenBSD:
+ return entry.file_spec == m_exe_file_spec;
+ case llvm::Triple::Linux:
+ if (triple.isAndroid())
+ return entry.file_spec == m_exe_file_spec;
+ // If we are debugging ld.so, then all SOEntries should be treated as
+ // libraries, including the "main" one (denoted by an empty string).
+ if (!entry.file_spec && m_executable_interpreter)
+ return false;
+ return !entry.file_spec;
+ default:
+ return false;
+ }
+}
+
+bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ // Clear previous entries since we are about to obtain an up to date list.
+ entry_list.clear();
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ if (SOEntryIsMainExecutable(entry))
+ continue;
+
+ UpdateFileSpecIfNecessary(entry);
+
+ entry_list.push_back(entry);
+ }
+
+ return true;
+}
+
+addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
+ Status error;
+
+ *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
+ if (error.Fail())
+ return 0;
+
+ return addr + size;
+}
+
+addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
+ Status error;
+
+ *dst = m_process->ReadPointerFromMemory(addr, error);
+ if (error.Fail())
+ return 0;
+
+ return addr + m_process->GetAddressByteSize();
+}
+
+std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) {
+ std::string str;
+ Status error;
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ return std::string();
+
+ m_process->ReadCStringFromMemory(addr, str, error);
+
+ return str;
+}
+
+// Returns true if the load bias reported by the linker is incorrect for the
+// given entry. This function is used to handle cases where we want to work
+// around a bug in the system linker.
+static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) {
+ // On Android L (API 21, 22) the load address of the "/system/bin/linker"
+ // isn't filled in correctly.
+ unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor();
+ return target.GetArchitecture().GetTriple().isAndroid() &&
+ (os_major == 21 || os_major == 22) &&
+ (file_path == "/system/bin/linker" ||
+ file_path == "/system/bin/linker64");
+}
+
+void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry,
+ std::string const &file_path) {
+ // If the load bias reported by the linker is incorrect then fetch the load
+ // address of the file from the proc file system.
+ if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) {
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ bool is_loaded = false;
+ Status error =
+ m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
+ if (error.Success() && is_loaded)
+ entry.base_addr = load_addr;
+ }
+}
+
+void DYLDRendezvous::UpdateFileSpecIfNecessary(SOEntry &entry) {
+ // Updates filename if empty. It is useful while debugging ld.so,
+ // when the link map returns empty string for the main executable.
+ if (!entry.file_spec) {
+ MemoryRegionInfo region;
+ Status region_status =
+ m_process->GetMemoryRegionInfo(entry.dyn_addr, region);
+ if (!region.GetName().IsEmpty())
+ entry.file_spec.SetFile(region.GetName().AsCString(),
+ FileSpec::Style::native);
+ }
+}
+
+bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
+ entry.clear();
+
+ entry.link_addr = addr;
+
+ if (!(addr = ReadPointer(addr, &entry.base_addr)))
+ return false;
+
+ // mips adds an extra load offset field to the link map struct on FreeBSD and
+ // NetBSD (need to validate other OSes).
+ // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
+ const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
+ if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
+ arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
+ arch.IsMIPS()) {
+ addr_t mips_l_offs;
+ if (!(addr = ReadPointer(addr, &mips_l_offs)))
+ return false;
+ if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
+ return false;
+ }
+
+ if (!(addr = ReadPointer(addr, &entry.path_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.next)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.prev)))
+ return false;
+
+ std::string file_path = ReadStringFromMemory(entry.path_addr);
+ entry.file_spec.SetFile(file_path, FileSpec::Style::native);
+
+ UpdateBaseAddrIfNecessary(entry, file_path);
+
+ return true;
+}
+
+bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field,
+ uint32_t &value) {
+ Target &target = m_process->GetTarget();
+
+ SymbolContextList list;
+ target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
+ eSymbolTypeAny, list);
+ if (list.IsEmpty())
+ return false;
+
+ Address address = list[0].symbol->GetAddress();
+ address.SetOffset(address.GetOffset() + field * sizeof(uint32_t));
+
+ // Read from target memory as this allows us to try process memory and
+ // fallback to reading from read only sections from the object files. Here we
+ // are reading read only data from libpthread.so to find data in the thread
+ // specific area for the data we want and this won't be saved into process
+ // memory due to it being read only.
+ Status error;
+ value =
+ target.ReadUnsignedIntegerFromMemory(address, sizeof(uint32_t), 0, error);
+ if (error.Fail())
+ return false;
+
+ if (field == eSize)
+ value /= 8; // convert bits to bytes
+
+ return true;
+}
+
+const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() {
+ if (!m_thread_info.valid) {
+ bool ok = true;
+
+ ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
+ m_thread_info.dtv_offset);
+ ok &=
+ FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
+ ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
+ m_thread_info.modid_offset);
+ ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
+ m_thread_info.tls_offset);
+
+ if (ok)
+ m_thread_info.valid = true;
+ }
+
+ return m_thread_info;
+}
+
+void DYLDRendezvous::DumpToLog(Log *log) const {
+ int state = GetState();
+
+ if (!log)
+ return;
+
+ log->PutCString("DYLDRendezvous:");
+ LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress());
+ LLDB_LOGF(log, " Version: %" PRIu64, GetVersion());
+ LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress());
+ LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress());
+ LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase());
+ LLDB_LOGF(log, " State : %s",
+ (state == eConsistent)
+ ? "consistent"
+ : (state == eAdd) ? "add"
+ : (state == eDelete) ? "delete" : "unknown");
+
+ iterator I = begin();
+ iterator E = end();
+
+ if (I != E)
+ log->PutCString("DYLDRendezvous SOEntries:");
+
+ for (int i = 1; I != E; ++I, ++i) {
+ LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->file_spec.GetPath().c_str());
+ LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr);
+ LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr);
+ LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr);
+ LLDB_LOGF(log, " Next : %" PRIx64, I->next);
+ LLDB_LOGF(log, " Prev : %" PRIx64, I->prev);
+ }
+}
+
+bool DYLDRendezvous::IsCoreFile() const {
+ return !m_process->IsLiveDebugSession();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
new file mode 100644
index 000000000000..b8bdf78fbdfa
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
@@ -0,0 +1,369 @@
+//===-- DYLDRendezvous.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_POSIX_DYLD_DYLDRENDEZVOUS_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYLDRENDEZVOUS_H
+
+#include <list>
+#include <string>
+
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+#include "lldb/Core/LoadedModuleInfoList.h"
+
+using lldb_private::LoadedModuleInfoList;
+
+namespace lldb_private {
+class Log;
+class Process;
+}
+
+/// \class DYLDRendezvous
+/// Interface to the runtime linker.
+///
+/// A structure is present in a processes memory space which is updated by the
+/// dynamic linker each time a module is loaded or unloaded. This class
+/// provides an interface to this structure and maintains a consistent
+/// snapshot of the currently loaded modules.
+///
+/// In the dynamic loader sources, this structure has a type of "r_debug" and
+/// the name of the structure us "_r_debug". The structure looks like:
+///
+/// struct r_debug {
+/// // Version number for this protocol.
+/// int r_version;
+/// // Head of the chain of loaded objects.
+/// struct link_map *r_map;
+/// // The address the debugger should set a breakpoint at in order to get
+/// // notified when shared libraries are added or removed
+/// uintptr_t r_brk;
+/// // This state value describes the mapping change taking place when the
+/// // 'r_brk' address is called.
+/// enum {
+/// RT_CONSISTENT, // Mapping change is complete.
+/// RT_ADD, // Beginning to add a new object.
+/// RT_DELETE, // Beginning to remove an object mapping.
+/// } r_state;
+/// // Base address the linker is loaded at.
+/// uintptr_t r_ldbase;
+/// };
+///
+/// The dynamic linker then defines a global variable using this type named
+/// "_r_debug":
+///
+/// r_debug _r_debug;
+///
+/// The DYLDRendezvous class defines a local version of this structure named
+/// DYLDRendezvous::Rendezvous. See the definition inside the class definition
+/// for DYLDRendezvous.
+///
+/// This structure can be located by looking through the .dynamic section in
+/// the main executable and finding the DT_DEBUG tag entry. This value starts
+/// out with a value of zero when the program first is initially loaded, but
+/// the address of the "_r_debug" structure from ld.so is filled in by the
+/// dynamic loader during program initialization code in ld.so prior to loading
+/// or unloading and shared libraries.
+///
+/// The dynamic loader will update this structure as shared libraries are
+/// loaded and will call a specific function that LLDB knows to set a
+/// breakpoint on (from _r_debug.r_brk) so LLDB will find out when shared
+/// libraries are loaded or unloaded. Each time this breakpoint is hit, LLDB
+/// looks at the contents of this structure and the contents tell LLDB what
+/// needs to be done.
+///
+/// Currently we expect the "state" in this structure to change as things
+/// happen.
+///
+/// When any shared libraries are loaded the following happens:
+/// - _r_debug.r_map is updated with the new shared libraries. This is a
+/// doubly linked list of "link_map *" entries.
+/// - _r_debug.r_state is set to RT_ADD and the debugger notification
+/// function is called notifying the debugger that shared libraries are
+/// about to be added, but are not yet ready for use.
+/// - Once the the shared libraries are fully loaded, _r_debug.r_state is set
+/// to RT_CONSISTENT and the debugger notification function is called again
+/// notifying the debugger that shared libraries are ready for use.
+/// DYLDRendezvous must remember that the previous state was RT_ADD when it
+/// receives a RT_CONSISTENT in order to know to add libraries
+///
+/// When any shared libraries are unloaded the following happens:
+/// - _r_debug.r_map is updated and the unloaded libraries are removed.
+/// - _r_debug.r_state is set to RT_DELETE and the debugger notification
+/// function is called notifying the debugger that shared libraries are
+/// about to be removed.
+/// - Once the the shared libraries are removed _r_debug.r_state is set to
+/// RT_CONSISTENT and the debugger notification function is called again
+/// notifying the debugger that shared libraries have been removed.
+/// DYLDRendezvous must remember that the previous state was RT_DELETE when
+/// it receives a RT_CONSISTENT in order to know to remove libraries
+///
+class DYLDRendezvous {
+
+ // This structure is used to hold the contents of the debug rendezvous
+ // information (struct r_debug) as found in the inferiors memory. Note that
+ // the layout of this struct is not binary compatible, it is simply large
+ // enough to hold the information on both 32 and 64 bit platforms.
+ struct Rendezvous {
+ uint64_t version = 0;
+ lldb::addr_t map_addr = 0;
+ lldb::addr_t brk = 0;
+ uint64_t state = 0;
+ lldb::addr_t ldbase = 0;
+
+ Rendezvous() = default;
+
+ void DumpToLog(lldb_private::Log *log, const char *label);
+ };
+
+ /// Locates the address of the rendezvous structure. It updates
+ /// m_executable_interpreter if address is extracted from _r_debug.
+ ///
+ /// \returns address on success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t ResolveRendezvousAddress();
+
+public:
+ // Various metadata supplied by the inferior's threading library to describe
+ // the per-thread state.
+ struct ThreadInfo {
+ bool valid; // whether we read valid metadata
+ uint32_t dtv_offset; // offset of DTV pointer within pthread
+ uint32_t dtv_slot_size; // size of one DTV slot
+ uint32_t modid_offset; // offset of module ID within link_map
+ uint32_t tls_offset; // offset of TLS pointer within DTV slot
+ };
+
+ DYLDRendezvous(lldb_private::Process *process);
+
+ /// Update the cached executable path.
+ void UpdateExecutablePath();
+
+ /// Update the internal snapshot of runtime linker rendezvous and recompute
+ /// the currently loaded modules.
+ ///
+ /// This method should be called once one start up, then once each time the
+ /// runtime linker enters the function given by GetBreakAddress().
+ ///
+ /// \returns true on success and false on failure.
+ ///
+ /// \see GetBreakAddress().
+ bool Resolve();
+
+ /// \returns true if this rendezvous has been located in the inferiors
+ /// address space and false otherwise.
+ bool IsValid();
+
+ /// \returns the address of the rendezvous structure in the inferiors
+ /// address space.
+ lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }
+
+ /// \returns the version of the rendezvous protocol being used.
+ uint64_t GetVersion() const { return m_current.version; }
+
+ /// \returns address in the inferiors address space containing the linked
+ /// list of shared object descriptors.
+ lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; }
+
+ /// A breakpoint should be set at this address and Resolve called on each
+ /// hit.
+ ///
+ /// \returns the address of a function called by the runtime linker each
+ /// time a module is loaded/unloaded, or about to be loaded/unloaded.
+ ///
+ /// \see Resolve()
+ lldb::addr_t GetBreakAddress() const { return m_current.brk; }
+
+ /// Returns the current state of the rendezvous structure.
+ uint64_t GetState() const { return m_current.state; }
+
+ /// \returns the base address of the runtime linker in the inferiors address
+ /// space.
+ lldb::addr_t GetLDBase() const { return m_current.ldbase; }
+
+ /// \returns the thread layout metadata from the inferiors thread library.
+ const ThreadInfo &GetThreadInfo();
+
+ /// \returns true if modules have been loaded into the inferior since the
+ /// last call to Resolve().
+ bool ModulesDidLoad() const { return !m_added_soentries.empty(); }
+
+ /// \returns true if modules have been unloaded from the inferior since the
+ /// last call to Resolve().
+ bool ModulesDidUnload() const { return !m_removed_soentries.empty(); }
+
+ void DumpToLog(lldb_private::Log *log) const;
+
+ /// Constants describing the state of the rendezvous.
+ ///
+ /// These values are defined to match the r_debug.r_state enum from the
+ /// actual dynamic loader sources.
+ ///
+ /// \see GetState().
+ enum RendezvousState {
+ eConsistent, // RT_CONSISTENT
+ eAdd, // RT_ADD
+ eDelete // RT_DELETE
+ };
+
+ /// Structure representing the shared objects currently loaded into the
+ /// inferior process.
+ ///
+ /// This object is a rough analogue to the struct link_map object which
+ /// actually lives in the inferiors memory.
+ struct SOEntry {
+ lldb::addr_t link_addr; ///< Address of this link_map.
+ lldb::addr_t base_addr; ///< Base address of the loaded object.
+ lldb::addr_t path_addr; ///< String naming the shared object.
+ lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
+ lldb::addr_t next; ///< Address of next so_entry.
+ lldb::addr_t prev; ///< Address of previous so_entry.
+ lldb_private::FileSpec file_spec; ///< File spec of shared object.
+
+ SOEntry() { clear(); }
+
+ bool operator==(const SOEntry &entry) {
+ return file_spec == entry.file_spec;
+ }
+
+ void clear() {
+ link_addr = 0;
+ base_addr = 0;
+ path_addr = 0;
+ dyn_addr = 0;
+ next = 0;
+ prev = 0;
+ file_spec.Clear();
+ }
+ };
+
+protected:
+ typedef std::list<SOEntry> SOEntryList;
+
+public:
+ typedef SOEntryList::const_iterator iterator;
+
+ /// Iterators over all currently loaded modules.
+ iterator begin() const { return m_soentries.begin(); }
+ iterator end() const { return m_soentries.end(); }
+
+ /// Iterators over all modules loaded into the inferior since the last call
+ /// to Resolve().
+ iterator loaded_begin() const { return m_added_soentries.begin(); }
+ iterator loaded_end() const { return m_added_soentries.end(); }
+
+ /// Iterators over all modules unloaded from the inferior since the last
+ /// call to Resolve().
+ iterator unloaded_begin() const { return m_removed_soentries.begin(); }
+ iterator unloaded_end() const { return m_removed_soentries.end(); }
+
+protected:
+ lldb_private::Process *m_process;
+
+ // Cached copy of executable file spec
+ lldb_private::FileSpec m_exe_file_spec;
+
+ /// Location of the r_debug structure in the inferiors address space.
+ lldb::addr_t m_rendezvous_addr;
+
+ // True if the main program is the dynamic linker/loader/program interpreter.
+ bool m_executable_interpreter;
+
+ /// Current and previous snapshots of the rendezvous structure.
+ Rendezvous m_current;
+ Rendezvous m_previous;
+
+ /// List of currently loaded SO modules
+ LoadedModuleInfoList m_loaded_modules;
+
+ /// List of SOEntry objects corresponding to the current link map state.
+ SOEntryList m_soentries;
+
+ /// List of SOEntry's added to the link map since the last call to
+ /// Resolve().
+ SOEntryList m_added_soentries;
+
+ /// List of SOEntry's removed from the link map since the last call to
+ /// Resolve().
+ SOEntryList m_removed_soentries;
+
+ /// Threading metadata read from the inferior.
+ ThreadInfo m_thread_info;
+
+ /// Reads an unsigned integer of \p size bytes from the inferior's address
+ /// space starting at \p addr.
+ ///
+ /// \returns addr + size if the read was successful and false otherwise.
+ lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
+
+ /// Reads an address from the inferior's address space starting at \p addr.
+ ///
+ /// \returns addr + target address size if the read was successful and
+ /// 0 otherwise.
+ lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);
+
+ /// Reads a null-terminated C string from the memory location starting at @p
+ /// addr.
+ std::string ReadStringFromMemory(lldb::addr_t addr);
+
+ /// Reads an SOEntry starting at \p addr.
+ bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
+
+ /// Updates the current set of SOEntries, the set of added entries, and the
+ /// set of removed entries.
+ bool UpdateSOEntries();
+
+ /// Same as UpdateSOEntries but it gets the list of loaded modules from the
+ /// remote debug server (faster when supported).
+ bool UpdateSOEntriesFromRemote();
+
+ bool FillSOEntryFromModuleInfo(
+ LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry);
+
+ bool SaveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
+
+ bool AddSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
+
+ bool RemoveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
+
+ bool AddSOEntries();
+
+ bool RemoveSOEntries();
+
+ void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path);
+
+ void UpdateFileSpecIfNecessary(SOEntry &entry);
+
+ bool SOEntryIsMainExecutable(const SOEntry &entry);
+
+ /// Reads the current list of shared objects according to the link map
+ /// supplied by the runtime linker.
+ bool TakeSnapshot(SOEntryList &entry_list);
+
+ enum PThreadField { eSize, eNElem, eOffset };
+
+ bool FindMetadata(const char *name, PThreadField field, uint32_t &value);
+
+ bool IsCoreFile() const;
+
+ enum RendezvousAction {
+ eNoAction,
+ eTakeSnapshot,
+ eAddModules,
+ eRemoveModules
+ };
+
+ static const char *StateToCStr(RendezvousState state);
+ static const char *ActionToCStr(RendezvousAction action);
+
+ /// Returns the current action to be taken given the current and previous
+ /// state
+ RendezvousAction GetAction() const;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
new file mode 100644
index 000000000000..51e4b3e6728f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -0,0 +1,883 @@
+//===-- DynamicLoaderPOSIXDYLD.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
+//
+//===----------------------------------------------------------------------===//
+
+// Main header include
+#include "DynamicLoaderPOSIXDYLD.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
+
+#include <memory>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE_ADV(DynamicLoaderPOSIXDYLD, DynamicLoaderPosixDYLD)
+
+void DynamicLoaderPOSIXDYLD::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void DynamicLoaderPOSIXDYLD::Terminate() {}
+
+llvm::StringRef DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic() {
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in POSIX processes.";
+}
+
+DynamicLoader *DynamicLoaderPOSIXDYLD::CreateInstance(Process *process,
+ bool force) {
+ bool create = force;
+ if (!create) {
+ const llvm::Triple &triple_ref =
+ process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getOS() == llvm::Triple::FreeBSD ||
+ triple_ref.getOS() == llvm::Triple::Linux ||
+ triple_ref.getOS() == llvm::Triple::NetBSD ||
+ triple_ref.getOS() == llvm::Triple::OpenBSD)
+ create = true;
+ }
+
+ if (create)
+ return new DynamicLoaderPOSIXDYLD(process);
+ return nullptr;
+}
+
+DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process)
+ : DynamicLoader(process), m_rendezvous(process),
+ m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS),
+ m_auxv(), m_dyld_bid(LLDB_INVALID_BREAK_ID),
+ m_vdso_base(LLDB_INVALID_ADDRESS),
+ m_interpreter_base(LLDB_INVALID_ADDRESS), m_initial_modules_added(false) {
+}
+
+DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() {
+ if (m_dyld_bid != LLDB_INVALID_BREAK_ID) {
+ m_process->GetTarget().RemoveBreakpointByID(m_dyld_bid);
+ m_dyld_bid = LLDB_INVALID_BREAK_ID;
+ }
+}
+
+void DynamicLoaderPOSIXDYLD::DidAttach() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64, __FUNCTION__,
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
+ m_auxv = std::make_unique<AuxVector>(m_process->GetAuxvData());
+
+ LLDB_LOGF(
+ log, "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data",
+ __FUNCTION__, m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
+
+ ModuleSP executable_sp = GetTargetExecutable();
+ ResolveExecutableModule(executable_sp);
+ m_rendezvous.UpdateExecutablePath();
+
+ // find the main process load offset
+ addr_t load_offset = ComputeLoadOffset();
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
+ " executable '%s', load_offset 0x%" PRIx64,
+ __FUNCTION__,
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID,
+ executable_sp ? executable_sp->GetFileSpec().GetPath().c_str()
+ : "<null executable>",
+ load_offset);
+
+ EvalSpecialModulesStatus();
+
+ // if we dont have a load address we cant re-base
+ bool rebase_exec = load_offset != LLDB_INVALID_ADDRESS;
+
+ // if we have a valid executable
+ if (executable_sp.get()) {
+ lldb_private::ObjectFile *obj = executable_sp->GetObjectFile();
+ if (obj) {
+ // don't rebase if the module already has a load address
+ Target &target = m_process->GetTarget();
+ Address addr = obj->GetImageInfoAddress(&target);
+ if (addr.GetLoadAddress(&target) != LLDB_INVALID_ADDRESS)
+ rebase_exec = false;
+ }
+ } else {
+ // no executable, nothing to re-base
+ rebase_exec = false;
+ }
+
+ // if the target executable should be re-based
+ if (rebase_exec) {
+ ModuleList module_list;
+
+ module_list.Append(executable_sp);
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
+ " added executable '%s' to module load list",
+ __FUNCTION__,
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID,
+ executable_sp->GetFileSpec().GetPath().c_str());
+
+ UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset,
+ true);
+
+ LoadAllCurrentModules();
+
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ if (log) {
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s told the target about the "
+ "modules that loaded:",
+ __FUNCTION__);
+ for (auto module_sp : module_list.Modules()) {
+ LLDB_LOGF(log, "-- [module] %s (pid %" PRIu64 ")",
+ module_sp ? module_sp->GetFileSpec().GetPath().c_str()
+ : "<null>",
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
+ }
+ }
+ }
+
+ if (executable_sp.get()) {
+ if (!SetRendezvousBreakpoint()) {
+ // If we cannot establish rendezvous breakpoint right now we'll try again
+ // at entry point.
+ ProbeEntry();
+ }
+ }
+}
+
+void DynamicLoaderPOSIXDYLD::DidLaunch() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s()", __FUNCTION__);
+
+ ModuleSP executable;
+ addr_t load_offset;
+
+ m_auxv = std::make_unique<AuxVector>(m_process->GetAuxvData());
+
+ executable = GetTargetExecutable();
+ load_offset = ComputeLoadOffset();
+ EvalSpecialModulesStatus();
+
+ if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) {
+ ModuleList module_list;
+ module_list.Append(executable);
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true);
+
+ LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()",
+ __FUNCTION__);
+
+ if (!SetRendezvousBreakpoint()) {
+ // If we cannot establish rendezvous breakpoint right now we'll try again
+ // at entry point.
+ ProbeEntry();
+ }
+
+ LoadVDSO();
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ }
+}
+
+Status DynamicLoaderPOSIXDYLD::CanLoadImage() { return Status(); }
+
+void DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module,
+ addr_t link_map_addr,
+ addr_t base_addr,
+ bool base_addr_is_offset) {
+ m_loaded_modules[module] = link_map_addr;
+ UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset);
+}
+
+void DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) {
+ m_loaded_modules.erase(module);
+
+ UnloadSectionsCommon(module);
+}
+
+void DynamicLoaderPOSIXDYLD::ProbeEntry() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ // If we have a core file, we don't need any breakpoints.
+ if (IsCoreFile())
+ return;
+
+ const addr_t entry = GetEntryPoint();
+ if (entry == LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(
+ log,
+ "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
+ " GetEntryPoint() returned no address, not setting entry breakpoint",
+ __FUNCTION__, m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
+ return;
+ }
+
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
+ " GetEntryPoint() returned address 0x%" PRIx64
+ ", setting entry breakpoint",
+ __FUNCTION__,
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, entry);
+
+ if (m_process) {
+ Breakpoint *const entry_break =
+ m_process->GetTarget().CreateBreakpoint(entry, true, false).get();
+ entry_break->SetCallback(EntryBreakpointHit, this, true);
+ entry_break->SetBreakpointKind("shared-library-event");
+
+ // Shoudn't hit this more than once.
+ entry_break->SetOneShot(true);
+ }
+}
+
+// The runtime linker has run and initialized the rendezvous structure once the
+// process has hit its entry point. When we hit the corresponding breakpoint
+// we interrogate the rendezvous structure to get the load addresses of all
+// dependent modules for the process. Similarly, we can discover the runtime
+// linker function and setup a breakpoint to notify us of any dynamically
+// loaded modules (via dlopen).
+bool DynamicLoaderPOSIXDYLD::EntryBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false;
+
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ DynamicLoaderPOSIXDYLD *const dyld_instance =
+ static_cast<DynamicLoaderPOSIXDYLD *>(baton);
+ LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64,
+ __FUNCTION__,
+ dyld_instance->m_process ? dyld_instance->m_process->GetID()
+ : LLDB_INVALID_PROCESS_ID);
+
+ // Disable the breakpoint --- if a stop happens right after this, which we've
+ // seen on occasion, we don't want the breakpoint stepping thread-plan logic
+ // to show a breakpoint instruction at the disassembled entry point to the
+ // program. Disabling it prevents it. (One-shot is not enough - one-shot
+ // removal logic only happens after the breakpoint goes public, which wasn't
+ // happening in our scenario).
+ if (dyld_instance->m_process) {
+ BreakpointSP breakpoint_sp =
+ dyld_instance->m_process->GetTarget().GetBreakpointByID(break_id);
+ if (breakpoint_sp) {
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
+ " disabling breakpoint id %" PRIu64,
+ __FUNCTION__, dyld_instance->m_process->GetID(), break_id);
+ breakpoint_sp->SetEnabled(false);
+ } else {
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
+ " failed to find breakpoint for breakpoint id %" PRIu64,
+ __FUNCTION__, dyld_instance->m_process->GetID(), break_id);
+ }
+ } else {
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s breakpoint id %" PRIu64
+ " no Process instance! Cannot disable breakpoint",
+ __FUNCTION__, break_id);
+ }
+
+ dyld_instance->LoadAllCurrentModules();
+ dyld_instance->SetRendezvousBreakpoint();
+ return false; // Continue running.
+}
+
+bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ // If we have a core file, we don't need any breakpoints.
+ if (IsCoreFile())
+ return false;
+
+ if (m_dyld_bid != LLDB_INVALID_BREAK_ID) {
+ LLDB_LOG(log,
+ "Rendezvous breakpoint breakpoint id {0} for pid {1}"
+ "is already set.",
+ m_dyld_bid,
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
+ return true;
+ }
+
+ addr_t break_addr;
+ Target &target = m_process->GetTarget();
+ BreakpointSP dyld_break;
+ if (m_rendezvous.IsValid() && m_rendezvous.GetBreakAddress() != 0) {
+ break_addr = m_rendezvous.GetBreakAddress();
+ LLDB_LOG(log, "Setting rendezvous break address for pid {0} at {1:x}",
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID,
+ break_addr);
+ dyld_break = target.CreateBreakpoint(break_addr, true, false);
+ } else {
+ LLDB_LOG(log, "Rendezvous structure is not set up yet. "
+ "Trying to locate rendezvous breakpoint in the interpreter "
+ "by symbol name.");
+ // Function names from different dynamic loaders that are known to be
+ // used as rendezvous between the loader and debuggers.
+ static std::vector<std::string> DebugStateCandidates{
+ "_dl_debug_state", "rtld_db_dlactivity", "__dl_rtld_db_dlactivity",
+ "r_debug_state", "_r_debug_state", "_rtld_debug_state",
+ };
+
+ ModuleSP interpreter = LoadInterpreterModule();
+ FileSpecList containingModules;
+ if (interpreter)
+ containingModules.Append(interpreter->GetFileSpec());
+ else
+ containingModules.Append(
+ m_process->GetTarget().GetExecutableModulePointer()->GetFileSpec());
+
+ dyld_break = target.CreateBreakpoint(
+ &containingModules, /*containingSourceFiles=*/nullptr,
+ DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC,
+ /*m_offset=*/0,
+ /*skip_prologue=*/eLazyBoolNo,
+ /*internal=*/true,
+ /*request_hardware=*/false);
+ }
+
+ if (dyld_break->GetNumResolvedLocations() != 1) {
+ LLDB_LOG(
+ log,
+ "Rendezvous breakpoint has abnormal number of"
+ " resolved locations ({0}) in pid {1}. It's supposed to be exactly 1.",
+ dyld_break->GetNumResolvedLocations(),
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
+
+ target.RemoveBreakpointByID(dyld_break->GetID());
+ return false;
+ }
+
+ BreakpointLocationSP location = dyld_break->GetLocationAtIndex(0);
+ LLDB_LOG(log,
+ "Successfully set rendezvous breakpoint at address {0:x} "
+ "for pid {1}",
+ location->GetLoadAddress(),
+ m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
+
+ dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
+ dyld_break->SetBreakpointKind("shared-library-event");
+ m_dyld_bid = dyld_break->GetID();
+ return true;
+}
+
+bool DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false;
+
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ DynamicLoaderPOSIXDYLD *const dyld_instance =
+ static_cast<DynamicLoaderPOSIXDYLD *>(baton);
+ LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64,
+ __FUNCTION__,
+ dyld_instance->m_process ? dyld_instance->m_process->GetID()
+ : LLDB_INVALID_PROCESS_ID);
+
+ dyld_instance->RefreshModules();
+
+ // Return true to stop the target, false to just let the target run.
+ const bool stop_when_images_change = dyld_instance->GetStopWhenImagesChange();
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
+ " stop_when_images_change=%s",
+ __FUNCTION__,
+ dyld_instance->m_process ? dyld_instance->m_process->GetID()
+ : LLDB_INVALID_PROCESS_ID,
+ stop_when_images_change ? "true" : "false");
+ return stop_when_images_change;
+}
+
+void DynamicLoaderPOSIXDYLD::RefreshModules() {
+ if (!m_rendezvous.Resolve())
+ return;
+
+ // The rendezvous class doesn't enumerate the main module, so track that
+ // ourselves here.
+ ModuleSP executable = GetTargetExecutable();
+ m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
+
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+
+ if (m_rendezvous.ModulesDidLoad() || !m_initial_modules_added) {
+ ModuleList new_modules;
+
+ // If this is the first time rendezvous breakpoint fires, we need
+ // to take care of adding all the initial modules reported by
+ // the loader. This is necessary to list ld-linux.so on Linux,
+ // and all DT_NEEDED entries on *BSD.
+ if (m_initial_modules_added) {
+ I = m_rendezvous.loaded_begin();
+ E = m_rendezvous.loaded_end();
+ } else {
+ I = m_rendezvous.begin();
+ E = m_rendezvous.end();
+ m_initial_modules_added = true;
+ }
+ for (; I != E; ++I) {
+ // Don't load a duplicate copy of ld.so if we have already loaded it
+ // earlier in LoadInterpreterModule. If we instead loaded then unloaded it
+ // later, the section information for ld.so would be removed. That
+ // information is required for placing breakpoints on Arm/Thumb systems.
+ if ((m_interpreter_module.lock() != nullptr) &&
+ (I->base_addr == m_interpreter_base))
+ continue;
+
+ ModuleSP module_sp =
+ LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true);
+ if (!module_sp.get())
+ continue;
+
+ if (module_sp->GetObjectFile()->GetBaseAddress().GetLoadAddress(
+ &m_process->GetTarget()) == m_interpreter_base) {
+ ModuleSP interpreter_sp = m_interpreter_module.lock();
+ if (m_interpreter_module.lock() == nullptr) {
+ m_interpreter_module = module_sp;
+ } else if (module_sp == interpreter_sp) {
+ // Module already loaded.
+ continue;
+ }
+ }
+
+ loaded_modules.AppendIfNeeded(module_sp);
+ new_modules.Append(module_sp);
+ }
+ m_process->GetTarget().ModulesDidLoad(new_modules);
+ }
+
+ if (m_rendezvous.ModulesDidUnload()) {
+ ModuleList old_modules;
+
+ E = m_rendezvous.unloaded_end();
+ for (I = m_rendezvous.unloaded_begin(); I != E; ++I) {
+ ModuleSpec module_spec{I->file_spec};
+ ModuleSP module_sp = loaded_modules.FindFirstModule(module_spec);
+
+ if (module_sp.get()) {
+ old_modules.Append(module_sp);
+ UnloadSections(module_sp);
+ }
+ }
+ loaded_modules.Remove(old_modules);
+ m_process->GetTarget().ModulesDidUnload(old_modules, false);
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) {
+ ThreadPlanSP thread_plan_sp;
+
+ StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *sym = context.symbol;
+
+ if (sym == nullptr || !sym->IsTrampoline())
+ return thread_plan_sp;
+
+ ConstString sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
+ if (!sym_name)
+ return thread_plan_sp;
+
+ SymbolContextList target_symbols;
+ Target &target = thread.GetProcess()->GetTarget();
+ const ModuleList &images = target.GetImages();
+
+ llvm::StringRef target_name = sym_name.GetStringRef();
+ // On AArch64, the trampoline name has a prefix (__AArch64ADRPThunk_ or
+ // __AArch64AbsLongThunk_) added to the function name. If we detect a
+ // trampoline with the prefix, we need to remove the prefix to find the
+ // function symbol.
+ if (target_name.consume_front("__AArch64ADRPThunk_") ||
+ target_name.consume_front("__AArch64AbsLongThunk_")) {
+ // An empty target name can happen for trampolines generated for
+ // section-referencing relocations.
+ if (!target_name.empty()) {
+ sym_name = ConstString(target_name);
+ }
+ }
+ images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
+ if (!target_symbols.GetSize())
+ return thread_plan_sp;
+
+ typedef std::vector<lldb::addr_t> AddressVector;
+ AddressVector addrs;
+ for (const SymbolContext &context : target_symbols) {
+ AddressRange range;
+ context.GetAddressRange(eSymbolContextEverything, 0, false, range);
+ lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addrs.push_back(addr);
+ }
+
+ if (addrs.size() > 0) {
+ AddressVector::iterator start = addrs.begin();
+ AddressVector::iterator end = addrs.end();
+
+ llvm::sort(start, end);
+ addrs.erase(std::unique(start, end), end);
+ thread_plan_sp =
+ std::make_shared<ThreadPlanRunToAddress>(thread, addrs, stop);
+ }
+
+ return thread_plan_sp;
+}
+
+void DynamicLoaderPOSIXDYLD::LoadVDSO() {
+ if (m_vdso_base == LLDB_INVALID_ADDRESS)
+ return;
+
+ FileSpec file("[vdso]");
+
+ MemoryRegionInfo info;
+ Status status = m_process->GetMemoryRegionInfo(m_vdso_base, info);
+ if (status.Fail()) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOG(log, "Failed to get vdso region info: {0}", status);
+ return;
+ }
+
+ if (ModuleSP module_sp = m_process->ReadModuleFromMemory(
+ file, m_vdso_base, info.GetRange().GetByteSize())) {
+ UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_vdso_base, false);
+ m_process->GetTarget().GetImages().AppendIfNeeded(module_sp);
+ }
+}
+
+ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() {
+ if (m_interpreter_base == LLDB_INVALID_ADDRESS)
+ return nullptr;
+
+ MemoryRegionInfo info;
+ Target &target = m_process->GetTarget();
+ Status status = m_process->GetMemoryRegionInfo(m_interpreter_base, info);
+ if (status.Fail() || info.GetMapped() != MemoryRegionInfo::eYes ||
+ info.GetName().IsEmpty()) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOG(log, "Failed to get interpreter region info: {0}", status);
+ return nullptr;
+ }
+
+ FileSpec file(info.GetName().GetCString());
+ ModuleSpec module_spec(file, target.GetArchitecture());
+
+ // Don't notify that module is added here because its loading section
+ // addresses are not updated yet. We manually notify it below.
+ if (ModuleSP module_sp =
+ target.GetOrCreateModule(module_spec, /*notify=*/false)) {
+ UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base,
+ false);
+ // Manually notify that dynamic linker is loaded after updating load section
+ // addersses so that breakpoints can be resolved.
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ target.ModulesDidLoad(module_list);
+ m_interpreter_module = module_sp;
+ return module_sp;
+ }
+ return nullptr;
+}
+
+ModuleSP DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file,
+ addr_t link_map_addr,
+ addr_t base_addr,
+ bool base_addr_is_offset) {
+ if (ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress(
+ file, link_map_addr, base_addr, base_addr_is_offset))
+ return module_sp;
+
+ // This works around an dynamic linker "bug" on android <= 23, where the
+ // dynamic linker would report the application name
+ // (e.g. com.example.myapplication) instead of the main process binary
+ // (/system/bin/app_process(32)). The logic is not sound in general (it
+ // assumes base_addr is the real address, even though it actually is a load
+ // bias), but it happens to work on android because app_process has a file
+ // address of zero.
+ // This should be removed after we drop support for android-23.
+ if (m_process->GetTarget().GetArchitecture().GetTriple().isAndroid()) {
+ MemoryRegionInfo memory_info;
+ Status error = m_process->GetMemoryRegionInfo(base_addr, memory_info);
+ if (error.Success() && memory_info.GetMapped() &&
+ memory_info.GetRange().GetRangeBase() == base_addr &&
+ !(memory_info.GetName().IsEmpty())) {
+ if (ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress(
+ FileSpec(memory_info.GetName().GetStringRef()), link_map_addr,
+ base_addr, base_addr_is_offset))
+ return module_sp;
+ }
+ }
+
+ return nullptr;
+}
+
+void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+ ModuleList module_list;
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ LoadVDSO();
+
+ if (!m_rendezvous.Resolve()) {
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD "
+ "rendezvous address",
+ __FUNCTION__);
+ return;
+ }
+
+ // The rendezvous class doesn't enumerate the main module, so track that
+ // ourselves here.
+ ModuleSP executable = GetTargetExecutable();
+ m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
+
+ std::vector<FileSpec> module_names;
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
+ module_names.push_back(I->file_spec);
+ m_process->PrefetchModuleSpecs(
+ module_names, m_process->GetTarget().GetArchitecture().GetTriple());
+
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) {
+ ModuleSP module_sp =
+ LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true);
+ if (module_sp.get()) {
+ LLDB_LOG(log, "LoadAllCurrentModules loading module: {0}",
+ I->file_spec.GetFilename());
+ module_list.Append(module_sp);
+ } else {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(
+ log,
+ "DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64,
+ __FUNCTION__, I->file_spec.GetPath().c_str(), I->base_addr);
+ }
+ }
+
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ m_initial_modules_added = true;
+}
+
+addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() {
+ addr_t virt_entry;
+
+ if (m_load_offset != LLDB_INVALID_ADDRESS)
+ return m_load_offset;
+
+ if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ ModuleSP module = m_process->GetTarget().GetExecutableModule();
+ if (!module)
+ return LLDB_INVALID_ADDRESS;
+
+ ObjectFile *exe = module->GetObjectFile();
+ if (!exe)
+ return LLDB_INVALID_ADDRESS;
+
+ Address file_entry = exe->GetEntryPointAddress();
+
+ if (!file_entry.IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ m_load_offset = virt_entry - file_entry.GetFileAddress();
+ return m_load_offset;
+}
+
+void DynamicLoaderPOSIXDYLD::EvalSpecialModulesStatus() {
+ if (std::optional<uint64_t> vdso_base =
+ m_auxv->GetAuxValue(AuxVector::AUXV_AT_SYSINFO_EHDR))
+ m_vdso_base = *vdso_base;
+
+ if (std::optional<uint64_t> interpreter_base =
+ m_auxv->GetAuxValue(AuxVector::AUXV_AT_BASE))
+ m_interpreter_base = *interpreter_base;
+}
+
+addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() {
+ if (m_entry_point != LLDB_INVALID_ADDRESS)
+ return m_entry_point;
+
+ if (m_auxv == nullptr)
+ return LLDB_INVALID_ADDRESS;
+
+ std::optional<uint64_t> entry_point =
+ m_auxv->GetAuxValue(AuxVector::AUXV_AT_ENTRY);
+ if (!entry_point)
+ return LLDB_INVALID_ADDRESS;
+
+ m_entry_point = static_cast<addr_t>(*entry_point);
+
+ const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
+
+ // On ppc64, the entry point is actually a descriptor. Dereference it.
+ if (arch.GetMachine() == llvm::Triple::ppc64)
+ m_entry_point = ReadUnsignedIntWithSizeInBytes(m_entry_point, 8);
+
+ return m_entry_point;
+}
+
+lldb::addr_t
+DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp,
+ const lldb::ThreadSP thread,
+ lldb::addr_t tls_file_addr) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ auto it = m_loaded_modules.find(module_sp);
+ if (it == m_loaded_modules.end()) {
+ LLDB_LOGF(
+ log, "GetThreadLocalData error: module(%s) not found in loaded modules",
+ module_sp->GetObjectName().AsCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ addr_t link_map = it->second;
+ if (link_map == LLDB_INVALID_ADDRESS || link_map == 0) {
+ LLDB_LOGF(log,
+ "GetThreadLocalData error: invalid link map address=0x%" PRIx64,
+ link_map);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo();
+ if (!metadata.valid) {
+ LLDB_LOGF(log,
+ "GetThreadLocalData error: fail to read thread info metadata");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ LLDB_LOGF(log,
+ "GetThreadLocalData info: link_map=0x%" PRIx64
+ ", thread info metadata: "
+ "modid_offset=0x%" PRIx32 ", dtv_offset=0x%" PRIx32
+ ", tls_offset=0x%" PRIx32 ", dtv_slot_size=%" PRIx32 "\n",
+ link_map, metadata.modid_offset, metadata.dtv_offset,
+ metadata.tls_offset, metadata.dtv_slot_size);
+
+ // Get the thread pointer.
+ addr_t tp = thread->GetThreadPointer();
+ if (tp == LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log, "GetThreadLocalData error: fail to read thread pointer");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Find the module's modid.
+ int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit
+ int64_t modid = ReadUnsignedIntWithSizeInBytes(
+ link_map + metadata.modid_offset, modid_size);
+ if (modid == -1) {
+ LLDB_LOGF(log, "GetThreadLocalData error: fail to read modid");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Lookup the DTV structure for this thread.
+ addr_t dtv_ptr = tp + metadata.dtv_offset;
+ addr_t dtv = ReadPointer(dtv_ptr);
+ if (dtv == LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log, "GetThreadLocalData error: fail to read dtv");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Find the TLS block for this module.
+ addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid;
+ addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset);
+
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::Performed TLS lookup: "
+ "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64
+ ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n",
+ module_sp->GetObjectName().AsCString(""), link_map, tp,
+ (int64_t)modid, tls_block);
+
+ if (tls_block == LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log, "GetThreadLocalData error: fail to read tls_block");
+ return LLDB_INVALID_ADDRESS;
+ } else
+ return tls_block + tls_file_addr;
+}
+
+void DynamicLoaderPOSIXDYLD::ResolveExecutableModule(
+ lldb::ModuleSP &module_sp) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ if (m_process == nullptr)
+ return;
+
+ auto &target = m_process->GetTarget();
+ const auto platform_sp = target.GetPlatform();
+
+ ProcessInstanceInfo process_info;
+ if (!m_process->GetProcessInfo(process_info)) {
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s - failed to get process info for "
+ "pid %" PRIu64,
+ __FUNCTION__, m_process->GetID());
+ return;
+ }
+
+ LLDB_LOGF(
+ log, "DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s",
+ __FUNCTION__, m_process->GetID(),
+ process_info.GetExecutableFile().GetPath().c_str());
+
+ ModuleSpec module_spec(process_info.GetExecutableFile(),
+ process_info.GetArchitecture());
+ if (module_sp && module_sp->MatchesModuleSpec(module_spec))
+ return;
+
+ const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths());
+ auto error = platform_sp->ResolveExecutable(
+ module_spec, module_sp,
+ !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr);
+ if (error.Fail()) {
+ StreamString stream;
+ module_spec.Dump(stream);
+
+ LLDB_LOGF(log,
+ "DynamicLoaderPOSIXDYLD::%s - failed to resolve executable "
+ "with module spec \"%s\": %s",
+ __FUNCTION__, stream.GetData(), error.AsCString());
+ return;
+ }
+
+ target.SetExecutableModule(module_sp, eLoadDependentsNo);
+}
+
+bool DynamicLoaderPOSIXDYLD::AlwaysRelyOnEHUnwindInfo(
+ lldb_private::SymbolContext &sym_ctx) {
+ ModuleSP module_sp;
+ if (sym_ctx.symbol)
+ module_sp = sym_ctx.symbol->GetAddressRef().GetModule();
+ if (!module_sp && sym_ctx.function)
+ module_sp =
+ sym_ctx.function->GetAddressRange().GetBaseAddress().GetModule();
+ if (!module_sp)
+ return false;
+
+ return module_sp->GetFileSpec().GetPath() == "[vdso]";
+}
+
+bool DynamicLoaderPOSIXDYLD::IsCoreFile() const {
+ return !m_process->IsLiveDebugSession();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
new file mode 100644
index 000000000000..4c92335602cd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -0,0 +1,179 @@
+//===-- DynamicLoaderPOSIXDYLD.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_POSIX_DYLD_DYNAMICLOADERPOSIXDYLD_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYNAMICLOADERPOSIXDYLD_H
+
+#include <map>
+#include <memory>
+
+#include "DYLDRendezvous.h"
+#include "Plugins/Process/Utility/AuxVector.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Target/DynamicLoader.h"
+
+class AuxVector;
+
+class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader {
+public:
+ DynamicLoaderPOSIXDYLD(lldb_private::Process *process);
+
+ ~DynamicLoaderPOSIXDYLD() override;
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "posix-dyld"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process, bool force);
+
+ // DynamicLoader protocol
+
+ void DidAttach() override;
+
+ void DidLaunch() override;
+
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others) override;
+
+ lldb_private::Status CanLoadImage() override;
+
+ lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module,
+ const lldb::ThreadSP thread,
+ lldb::addr_t tls_file_addr) override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ lldb::ModuleSP LoadModuleAtAddress(const lldb_private::FileSpec &file,
+ lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr,
+ bool base_addr_is_offset) override;
+
+protected:
+ /// Runtime linker rendezvous structure.
+ DYLDRendezvous m_rendezvous;
+
+ /// Virtual load address of the inferior process.
+ lldb::addr_t m_load_offset;
+
+ /// Virtual entry address of the inferior process.
+ lldb::addr_t m_entry_point;
+
+ /// Auxiliary vector of the inferior process.
+ std::unique_ptr<AuxVector> m_auxv;
+
+ /// Rendezvous breakpoint.
+ lldb::break_id_t m_dyld_bid;
+
+ /// Contains AT_SYSINFO_EHDR, which means a vDSO has been
+ /// mapped to the address space
+ lldb::addr_t m_vdso_base;
+
+ /// Contains AT_BASE, which means a dynamic loader has been
+ /// mapped to the address space
+ lldb::addr_t m_interpreter_base;
+
+ /// Contains the pointer to the interpret module, if loaded.
+ std::weak_ptr<lldb_private::Module> m_interpreter_module;
+
+ /// Loaded module list. (link map for each module)
+ std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
+ m_loaded_modules;
+
+ /// Returns true if the process is for a core file.
+ bool IsCoreFile() const;
+
+ /// If possible sets a breakpoint on a function called by the runtime
+ /// linker each time a module is loaded or unloaded.
+ bool SetRendezvousBreakpoint();
+
+ /// Callback routine which updates the current list of loaded modules based
+ /// on the information supplied by the runtime linker.
+ static bool RendezvousBreakpointHit(
+ void *baton, lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ /// Indicates whether the initial set of modules was reported added.
+ bool m_initial_modules_added;
+
+ /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+ /// of loaded modules.
+ void RefreshModules();
+
+ /// Updates the load address of every allocatable section in \p module.
+ ///
+ /// \param module The module to traverse.
+ ///
+ /// \param link_map_addr The virtual address of the link map for the @p
+ /// module.
+ ///
+ /// \param base_addr The virtual base address \p module is loaded at.
+ void UpdateLoadedSections(lldb::ModuleSP module, lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr,
+ bool base_addr_is_offset) override;
+
+ /// Removes the loaded sections from the target in \p module.
+ ///
+ /// \param module The module to traverse.
+ void UnloadSections(const lldb::ModuleSP module) override;
+
+ /// Resolves the entry point for the current inferior process and sets a
+ /// breakpoint at that address.
+ void ProbeEntry();
+
+ /// Callback routine invoked when we hit the breakpoint on process entry.
+ ///
+ /// This routine is responsible for resolving the load addresses of all
+ /// dependent modules required by the inferior and setting up the rendezvous
+ /// breakpoint.
+ static bool
+ EntryBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ /// Helper for the entry breakpoint callback. Resolves the load addresses
+ /// of all dependent modules.
+ virtual void LoadAllCurrentModules();
+
+ void LoadVDSO();
+
+ // Loading an interpreter module (if present) assuming m_interpreter_base
+ // already points to its base address.
+ lldb::ModuleSP LoadInterpreterModule();
+
+ /// Computes a value for m_load_offset returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t ComputeLoadOffset();
+
+ /// Computes a value for m_entry_point returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t GetEntryPoint();
+
+ /// Evaluate if Aux vectors contain vDSO and LD information
+ /// in case they do, read and assign the address to m_vdso_base
+ /// and m_interpreter_base.
+ void EvalSpecialModulesStatus();
+
+ /// Loads Module from inferior process.
+ void ResolveExecutableModule(lldb::ModuleSP &module_sp);
+
+ bool AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override;
+
+private:
+ DynamicLoaderPOSIXDYLD(const DynamicLoaderPOSIXDYLD &) = delete;
+ const DynamicLoaderPOSIXDYLD &
+ operator=(const DynamicLoaderPOSIXDYLD &) = delete;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYNAMICLOADERPOSIXDYLD_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
new file mode 100644
index 000000000000..545998123dda
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
@@ -0,0 +1,150 @@
+//===-- DynamicLoaderStatic.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/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+
+#include "DynamicLoaderStatic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderStatic)
+
+// Create an instance of this class. This function is filled into the plugin
+// info class that gets handed out by the plugin factory and allows the lldb to
+// instantiate an instance of this class.
+DynamicLoader *DynamicLoaderStatic::CreateInstance(Process *process,
+ bool force) {
+ bool create = force;
+ if (!create) {
+ const llvm::Triple &triple_ref =
+ process->GetTarget().GetArchitecture().GetTriple();
+ const llvm::Triple::OSType os_type = triple_ref.getOS();
+ const llvm::Triple::ArchType arch_type = triple_ref.getArch();
+ if (os_type == llvm::Triple::UnknownOS) {
+ // The WASM and Hexagon plugin check the ArchType rather than the OSType,
+ // so explicitly reject those here.
+ switch(arch_type) {
+ case llvm::Triple::hexagon:
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ break;
+ default:
+ create = true;
+ }
+ }
+ }
+
+ if (!create) {
+ Module *exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module) {
+ ObjectFile *object_file = exe_module->GetObjectFile();
+ if (object_file) {
+ create = (object_file->GetStrata() == ObjectFile::eStrataRawImage);
+ }
+ }
+ }
+
+ if (create)
+ return new DynamicLoaderStatic(process);
+ return nullptr;
+}
+
+// Constructor
+DynamicLoaderStatic::DynamicLoaderStatic(Process *process)
+ : DynamicLoader(process) {}
+
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+void DynamicLoaderStatic::DidAttach() { LoadAllImagesAtFileAddresses(); }
+
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+void DynamicLoaderStatic::DidLaunch() { LoadAllImagesAtFileAddresses(); }
+
+void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() {
+ const ModuleList &module_list = m_process->GetTarget().GetImages();
+
+ ModuleList loaded_module_list;
+
+ // Disable JIT for static dynamic loader targets
+ m_process->SetCanJIT(false);
+
+ Target &target = m_process->GetTarget();
+ for (ModuleSP module_sp : module_list.Modules()) {
+ if (module_sp) {
+ bool changed = false;
+ bool no_load_addresses = true;
+ // If this module has a section with a load address set in
+ // the target, assume all necessary work is already done. There
+ // may be sections without a load address set intentionally
+ // and we don't want to mutate that.
+ // For a module with no load addresses set, set the load addresses
+ // to slide == 0, the same as the file addresses, in the target.
+ ObjectFile *image_object_file = module_sp->GetObjectFile();
+ if (image_object_file) {
+ SectionList *section_list = image_object_file->GetSectionList();
+ if (section_list) {
+ const size_t num_sections = section_list->GetSize();
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
+ SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+ if (section_sp) {
+ if (target.GetSectionLoadList().GetSectionLoadAddress(
+ section_sp) != LLDB_INVALID_ADDRESS) {
+ no_load_addresses = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (no_load_addresses)
+ module_sp->SetLoadAddress(target, 0, true /*value_is_offset*/, changed);
+
+ if (changed)
+ loaded_module_list.AppendIfNeeded(module_sp);
+ }
+ }
+
+ target.ModulesDidLoad(loaded_module_list);
+}
+
+ThreadPlanSP
+DynamicLoaderStatic::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop_others) {
+ return ThreadPlanSP();
+}
+
+Status DynamicLoaderStatic::CanLoadImage() {
+ Status error;
+ error.SetErrorString("can't load images on with a static debug session");
+ return error;
+}
+
+void DynamicLoaderStatic::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void DynamicLoaderStatic::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef DynamicLoaderStatic::GetPluginDescriptionStatic() {
+ return "Dynamic loader plug-in that will load any images at the static "
+ "addresses contained in each image.";
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
new file mode 100644
index 000000000000..dac19dcd38d7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
@@ -0,0 +1,53 @@
+//===-- DynamicLoaderStatic.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_STATIC_DYNAMICLOADERSTATIC_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_STATIC_DYNAMICLOADERSTATIC_H
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/UUID.h"
+
+class DynamicLoaderStatic : public lldb_private::DynamicLoader {
+public:
+ DynamicLoaderStatic(lldb_private::Process *process);
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "static"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process, bool force);
+
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ void DidAttach() override;
+
+ void DidLaunch() override;
+
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others) override;
+
+ lldb_private::Status CanLoadImage() override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+private:
+ void LoadAllImagesAtFileAddresses();
+};
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_STATIC_DYNAMICLOADERSTATIC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
new file mode 100644
index 000000000000..f044aa786806
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
@@ -0,0 +1,216 @@
+//===-- DynamicLoaderWindowsDYLD.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 "DynamicLoaderWindowsDYLD.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/TargetParser/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderWindowsDYLD)
+
+DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process)
+ : DynamicLoader(process) {}
+
+DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() = default;
+
+void DynamicLoaderWindowsDYLD::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void DynamicLoaderWindowsDYLD::Terminate() {}
+
+llvm::StringRef DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic() {
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in Windows processes.";
+}
+
+DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process,
+ bool force) {
+ bool should_create = force;
+ if (!should_create) {
+ const llvm::Triple &triple_ref =
+ process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getOS() == llvm::Triple::Win32)
+ should_create = true;
+ }
+
+ if (should_create)
+ return new DynamicLoaderWindowsDYLD(process);
+
+ return nullptr;
+}
+
+void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,
+ const ModuleSpec module_spec,
+ lldb::addr_t module_addr) {
+
+ // Resolve the module unless we already have one.
+ if (!module_sp) {
+ Status error;
+ module_sp = m_process->GetTarget().GetOrCreateModule(module_spec,
+ true /* notify */, &error);
+ if (error.Fail())
+ return;
+ }
+
+ m_loaded_modules[module_sp] = module_addr;
+ UpdateLoadedSectionsCommon(module_sp, module_addr, false);
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+void DynamicLoaderWindowsDYLD::OnUnloadModule(lldb::addr_t module_addr) {
+ Address resolved_addr;
+ if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr))
+ return;
+
+ ModuleSP module_sp = resolved_addr.GetModule();
+ if (module_sp) {
+ m_loaded_modules.erase(module_sp);
+ UnloadSectionsCommon(module_sp);
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ m_process->GetTarget().ModulesDidUnload(module_list, false);
+ }
+}
+
+lldb::addr_t DynamicLoaderWindowsDYLD::GetLoadAddress(ModuleSP executable) {
+ // First, see if the load address is already cached.
+ auto it = m_loaded_modules.find(executable);
+ if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS)
+ return it->second;
+
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+
+ // Second, try to get it through the process plugins. For a remote process,
+ // the remote platform will be responsible for providing it.
+ FileSpec file_spec(executable->GetPlatformFileSpec());
+ bool is_loaded = false;
+ Status status =
+ m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);
+ // Servers other than lldb server could respond with a bogus address.
+ if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {
+ m_loaded_modules[executable] = load_addr;
+ return load_addr;
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+void DynamicLoaderWindowsDYLD::DidAttach() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);
+
+ ModuleSP executable = GetTargetExecutable();
+
+ if (!executable.get())
+ return;
+
+ // Try to fetch the load address of the file from the process, since there
+ // could be randomization of the load address.
+ lldb::addr_t load_addr = GetLoadAddress(executable);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ // Request the process base address.
+ lldb::addr_t image_base = m_process->GetImageInfoAddress();
+ if (image_base == load_addr)
+ return;
+
+ // Rebase the process's modules if there is a mismatch.
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);
+
+ ModuleList module_list;
+ module_list.Append(executable);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ auto error = m_process->LoadModules();
+ LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");
+}
+
+void DynamicLoaderWindowsDYLD::DidLaunch() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);
+
+ ModuleSP executable = GetTargetExecutable();
+ if (!executable.get())
+ return;
+
+ lldb::addr_t load_addr = GetLoadAddress(executable);
+ if (load_addr != LLDB_INVALID_ADDRESS) {
+ // Update the loaded sections so that the breakpoints can be resolved.
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);
+
+ ModuleList module_list;
+ module_list.Append(executable);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ auto error = m_process->LoadModules();
+ LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");
+ }
+}
+
+Status DynamicLoaderWindowsDYLD::CanLoadImage() { return Status(); }
+
+ThreadPlanSP
+DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) {
+ auto arch = m_process->GetTarget().GetArchitecture();
+ if (arch.GetMachine() != llvm::Triple::x86) {
+ return ThreadPlanSP();
+ }
+
+ uint64_t pc = thread.GetRegisterContext()->GetPC();
+ // Max size of an instruction in x86 is 15 bytes.
+ AddressRange range(pc, 2 * 15);
+
+ DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+ arch, nullptr, nullptr, m_process->GetTarget(), range);
+ if (!disassembler_sp) {
+ return ThreadPlanSP();
+ }
+
+ InstructionList *insn_list = &disassembler_sp->GetInstructionList();
+ if (insn_list == nullptr) {
+ return ThreadPlanSP();
+ }
+
+ // First instruction in a x86 Windows trampoline is going to be an indirect
+ // jump through the IAT and the next one will be a nop (usually there for
+ // alignment purposes). e.g.:
+ // 0x70ff4cfc <+956>: jmpl *0x7100c2a8
+ // 0x70ff4d02 <+962>: nop
+
+ auto first_insn = insn_list->GetInstructionAtIndex(0);
+ auto second_insn = insn_list->GetInstructionAtIndex(1);
+
+ ExecutionContext exe_ctx(m_process->GetTarget());
+ if (first_insn == nullptr || second_insn == nullptr ||
+ strcmp(first_insn->GetMnemonic(&exe_ctx), "jmpl") != 0 ||
+ strcmp(second_insn->GetMnemonic(&exe_ctx), "nop") != 0) {
+ return ThreadPlanSP();
+ }
+
+ assert(first_insn->DoesBranch() && !second_insn->DoesBranch());
+
+ return ThreadPlanSP(new ThreadPlanStepInstruction(
+ thread, false, false, eVoteNoOpinion, eVoteNoOpinion));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
new file mode 100644
index 000000000000..42ea5aacecb4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
@@ -0,0 +1,53 @@
+//===-- DynamicLoaderWindowsDYLD.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_WINDOWS_DYLD_DYNAMICLOADERWINDOWSDYLD_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_WINDOWS_DYLD_DYNAMICLOADERWINDOWSDYLD_H
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/lldb-forward.h"
+
+#include <map>
+
+namespace lldb_private {
+
+class DynamicLoaderWindowsDYLD : public DynamicLoader {
+public:
+ DynamicLoaderWindowsDYLD(Process *process);
+
+ ~DynamicLoaderWindowsDYLD() override;
+
+ static void Initialize();
+ static void Terminate();
+ static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; }
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static DynamicLoader *CreateInstance(Process *process, bool force);
+
+ void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec,
+ lldb::addr_t module_addr);
+ void OnUnloadModule(lldb::addr_t module_addr);
+
+ void DidAttach() override;
+ void DidLaunch() override;
+ Status CanLoadImage() override;
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+protected:
+ lldb::addr_t GetLoadAddress(lldb::ModuleSP executable);
+
+private:
+ std::map<lldb::ModuleSP, lldb::addr_t> m_loaded_modules;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_WINDOWS_DYLD_DYNAMICLOADERWINDOWSDYLD_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
new file mode 100644
index 000000000000..d019415cb67a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
@@ -0,0 +1,82 @@
+//===-- DynamicLoaderWasmDYLD.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 "DynamicLoaderWasmDYLD.h"
+
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderWasmDYLD)
+
+DynamicLoaderWasmDYLD::DynamicLoaderWasmDYLD(Process *process)
+ : DynamicLoader(process) {}
+
+void DynamicLoaderWasmDYLD::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+llvm::StringRef DynamicLoaderWasmDYLD::GetPluginDescriptionStatic() {
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in WebAssembly engines.";
+}
+
+DynamicLoader *DynamicLoaderWasmDYLD::CreateInstance(Process *process,
+ bool force) {
+ bool should_create = force;
+ if (!should_create) {
+ should_create =
+ (process->GetTarget().GetArchitecture().GetTriple().getArch() ==
+ llvm::Triple::wasm32);
+ }
+
+ if (should_create)
+ return new DynamicLoaderWasmDYLD(process);
+
+ return nullptr;
+}
+
+void DynamicLoaderWasmDYLD::DidAttach() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderWasmDYLD::%s()", __FUNCTION__);
+
+ // Ask the process for the list of loaded WebAssembly modules.
+ auto error = m_process->LoadModules();
+ LLDB_LOG_ERROR(log, std::move(error), "Couldn't load modules: {0}");
+}
+
+ThreadPlanSP DynamicLoaderWasmDYLD::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) {
+ return ThreadPlanSP();
+}
+
+lldb::ModuleSP DynamicLoaderWasmDYLD::LoadModuleAtAddress(
+ const lldb_private::FileSpec &file, lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr, bool base_addr_is_offset) {
+ if (ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress(
+ file, link_map_addr, base_addr, base_addr_is_offset))
+ return module_sp;
+
+ if (ModuleSP module_sp = m_process->ReadModuleFromMemory(file, base_addr)) {
+ UpdateLoadedSections(module_sp, link_map_addr, base_addr, false);
+ m_process->GetTarget().GetImages().AppendIfNeeded(module_sp);
+ return module_sp;
+ }
+
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h
new file mode 100644
index 000000000000..5ed855395cca
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h
@@ -0,0 +1,52 @@
+//===-- DynamicLoaderWasmDYLD.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 liblldb_Plugins_DynamicLoaderWasmDYLD_h_
+#define liblldb_Plugins_DynamicLoaderWasmDYLD_h_
+
+#include "lldb/Target/DynamicLoader.h"
+
+namespace lldb_private {
+namespace wasm {
+
+class DynamicLoaderWasmDYLD : public DynamicLoader {
+public:
+ DynamicLoaderWasmDYLD(Process *process);
+
+ static void Initialize();
+ static void Terminate() {}
+
+ static llvm::StringRef GetPluginNameStatic() { return "wasm-dyld"; }
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static DynamicLoader *CreateInstance(Process *process, bool force);
+
+ /// DynamicLoader
+ /// \{
+ void DidAttach() override;
+ void DidLaunch() override {}
+ Status CanLoadImage() override { return Status(); }
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) override;
+ lldb::ModuleSP LoadModuleAtAddress(const lldb_private::FileSpec &file,
+ lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr,
+ bool base_addr_is_offset) override;
+
+ /// \}
+
+ /// PluginInterface protocol.
+ /// \{
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+ /// \}
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // liblldb_Plugins_DynamicLoaderWasmDYLD_h_