Path: blob/main/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
39654 views
//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "DynamicLoaderWindowsDYLD.h"910#include "lldb/Core/Module.h"11#include "lldb/Core/PluginManager.h"12#include "lldb/Target/ExecutionContext.h"13#include "lldb/Target/Platform.h"14#include "lldb/Target/Process.h"15#include "lldb/Target/RegisterContext.h"16#include "lldb/Target/Target.h"17#include "lldb/Target/ThreadPlanStepInstruction.h"18#include "lldb/Utility/LLDBLog.h"19#include "lldb/Utility/Log.h"2021#include "llvm/TargetParser/Triple.h"2223using namespace lldb;24using namespace lldb_private;2526LLDB_PLUGIN_DEFINE(DynamicLoaderWindowsDYLD)2728DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process)29: DynamicLoader(process) {}3031DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() = default;3233void DynamicLoaderWindowsDYLD::Initialize() {34PluginManager::RegisterPlugin(GetPluginNameStatic(),35GetPluginDescriptionStatic(), CreateInstance);36}3738void DynamicLoaderWindowsDYLD::Terminate() {}3940llvm::StringRef DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic() {41return "Dynamic loader plug-in that watches for shared library "42"loads/unloads in Windows processes.";43}4445DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process,46bool force) {47bool should_create = force;48if (!should_create) {49const llvm::Triple &triple_ref =50process->GetTarget().GetArchitecture().GetTriple();51if (triple_ref.getOS() == llvm::Triple::Win32)52should_create = true;53}5455if (should_create)56return new DynamicLoaderWindowsDYLD(process);5758return nullptr;59}6061void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,62const ModuleSpec module_spec,63lldb::addr_t module_addr) {6465// Resolve the module unless we already have one.66if (!module_sp) {67Status error;68module_sp = m_process->GetTarget().GetOrCreateModule(module_spec,69true /* notify */, &error);70if (error.Fail())71return;72}7374m_loaded_modules[module_sp] = module_addr;75UpdateLoadedSectionsCommon(module_sp, module_addr, false);76ModuleList module_list;77module_list.Append(module_sp);78m_process->GetTarget().ModulesDidLoad(module_list);79}8081void DynamicLoaderWindowsDYLD::OnUnloadModule(lldb::addr_t module_addr) {82Address resolved_addr;83if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr))84return;8586ModuleSP module_sp = resolved_addr.GetModule();87if (module_sp) {88m_loaded_modules.erase(module_sp);89UnloadSectionsCommon(module_sp);90ModuleList module_list;91module_list.Append(module_sp);92m_process->GetTarget().ModulesDidUnload(module_list, false);93}94}9596lldb::addr_t DynamicLoaderWindowsDYLD::GetLoadAddress(ModuleSP executable) {97// First, see if the load address is already cached.98auto it = m_loaded_modules.find(executable);99if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS)100return it->second;101102lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;103104// Second, try to get it through the process plugins. For a remote process,105// the remote platform will be responsible for providing it.106FileSpec file_spec(executable->GetPlatformFileSpec());107bool is_loaded = false;108Status status =109m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);110// Servers other than lldb server could respond with a bogus address.111if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {112m_loaded_modules[executable] = load_addr;113return load_addr;114}115116return LLDB_INVALID_ADDRESS;117}118119void DynamicLoaderWindowsDYLD::DidAttach() {120Log *log = GetLog(LLDBLog::DynamicLoader);121LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);122123ModuleSP executable = GetTargetExecutable();124125if (!executable.get())126return;127128// Try to fetch the load address of the file from the process, since there129// could be randomization of the load address.130lldb::addr_t load_addr = GetLoadAddress(executable);131if (load_addr == LLDB_INVALID_ADDRESS)132return;133134// Request the process base address.135lldb::addr_t image_base = m_process->GetImageInfoAddress();136if (image_base == load_addr)137return;138139// Rebase the process's modules if there is a mismatch.140UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);141142ModuleList module_list;143module_list.Append(executable);144m_process->GetTarget().ModulesDidLoad(module_list);145auto error = m_process->LoadModules();146LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");147}148149void DynamicLoaderWindowsDYLD::DidLaunch() {150Log *log = GetLog(LLDBLog::DynamicLoader);151LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);152153ModuleSP executable = GetTargetExecutable();154if (!executable.get())155return;156157lldb::addr_t load_addr = GetLoadAddress(executable);158if (load_addr != LLDB_INVALID_ADDRESS) {159// Update the loaded sections so that the breakpoints can be resolved.160UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);161162ModuleList module_list;163module_list.Append(executable);164m_process->GetTarget().ModulesDidLoad(module_list);165auto error = m_process->LoadModules();166LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");167}168}169170Status DynamicLoaderWindowsDYLD::CanLoadImage() { return Status(); }171172ThreadPlanSP173DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread,174bool stop) {175auto arch = m_process->GetTarget().GetArchitecture();176if (arch.GetMachine() != llvm::Triple::x86) {177return ThreadPlanSP();178}179180uint64_t pc = thread.GetRegisterContext()->GetPC();181// Max size of an instruction in x86 is 15 bytes.182AddressRange range(pc, 2 * 15);183184DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(185arch, nullptr, nullptr, m_process->GetTarget(), range);186if (!disassembler_sp) {187return ThreadPlanSP();188}189190InstructionList *insn_list = &disassembler_sp->GetInstructionList();191if (insn_list == nullptr) {192return ThreadPlanSP();193}194195// First instruction in a x86 Windows trampoline is going to be an indirect196// jump through the IAT and the next one will be a nop (usually there for197// alignment purposes). e.g.:198// 0x70ff4cfc <+956>: jmpl *0x7100c2a8199// 0x70ff4d02 <+962>: nop200201auto first_insn = insn_list->GetInstructionAtIndex(0);202auto second_insn = insn_list->GetInstructionAtIndex(1);203204ExecutionContext exe_ctx(m_process->GetTarget());205if (first_insn == nullptr || second_insn == nullptr ||206strcmp(first_insn->GetMnemonic(&exe_ctx), "jmpl") != 0 ||207strcmp(second_insn->GetMnemonic(&exe_ctx), "nop") != 0) {208return ThreadPlanSP();209}210211assert(first_insn->DoesBranch() && !second_insn->DoesBranch());212213return ThreadPlanSP(new ThreadPlanStepInstruction(214thread, false, false, eVoteNoOpinion, eVoteNoOpinion));215}216217218