217 lines · cpp
1//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "DynamicLoaderWindowsDYLD.h"10 11#include "lldb/Core/Module.h"12#include "lldb/Core/PluginManager.h"13#include "lldb/Target/ExecutionContext.h"14#include "lldb/Target/Platform.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/RegisterContext.h"17#include "lldb/Target/Target.h"18#include "lldb/Target/ThreadPlanStepInstruction.h"19#include "lldb/Utility/LLDBLog.h"20#include "lldb/Utility/Log.h"21 22#include "llvm/TargetParser/Triple.h"23 24using namespace lldb;25using namespace lldb_private;26 27LLDB_PLUGIN_DEFINE(DynamicLoaderWindowsDYLD)28 29DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process)30 : DynamicLoader(process) {}31 32DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() = default;33 34void DynamicLoaderWindowsDYLD::Initialize() {35 PluginManager::RegisterPlugin(GetPluginNameStatic(),36 GetPluginDescriptionStatic(), CreateInstance);37}38 39void DynamicLoaderWindowsDYLD::Terminate() {}40 41llvm::StringRef DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic() {42 return "Dynamic loader plug-in that watches for shared library "43 "loads/unloads in Windows processes.";44}45 46DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process,47 bool force) {48 bool should_create = force;49 if (!should_create) {50 const llvm::Triple &triple_ref =51 process->GetTarget().GetArchitecture().GetTriple();52 if (triple_ref.getOS() == llvm::Triple::Win32)53 should_create = true;54 }55 56 if (should_create)57 return new DynamicLoaderWindowsDYLD(process);58 59 return nullptr;60}61 62void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,63 const ModuleSpec module_spec,64 lldb::addr_t module_addr) {65 66 // Resolve the module unless we already have one.67 if (!module_sp) {68 Status error;69 module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, 70 true /* notify */, &error);71 if (error.Fail())72 return;73 }74 75 m_loaded_modules[module_sp] = module_addr;76 UpdateLoadedSectionsCommon(module_sp, module_addr, false);77 ModuleList module_list;78 module_list.Append(module_sp);79 m_process->GetTarget().ModulesDidLoad(module_list);80}81 82void DynamicLoaderWindowsDYLD::OnUnloadModule(lldb::addr_t module_addr) {83 Address resolved_addr;84 if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr))85 return;86 87 ModuleSP module_sp = resolved_addr.GetModule();88 if (module_sp) {89 m_loaded_modules.erase(module_sp);90 UnloadSectionsCommon(module_sp);91 ModuleList module_list;92 module_list.Append(module_sp);93 m_process->GetTarget().ModulesDidUnload(module_list, false);94 }95}96 97lldb::addr_t DynamicLoaderWindowsDYLD::GetLoadAddress(ModuleSP executable) {98 // First, see if the load address is already cached.99 auto it = m_loaded_modules.find(executable);100 if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS)101 return it->second;102 103 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;104 105 // Second, try to get it through the process plugins. For a remote process,106 // the remote platform will be responsible for providing it.107 FileSpec file_spec(executable->GetPlatformFileSpec());108 bool is_loaded = false;109 Status status =110 m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);111 // Servers other than lldb server could respond with a bogus address.112 if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {113 m_loaded_modules[executable] = load_addr;114 return load_addr;115 }116 117 return LLDB_INVALID_ADDRESS;118}119 120void DynamicLoaderWindowsDYLD::DidAttach() {121 Log *log = GetLog(LLDBLog::DynamicLoader);122 LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);123 124 ModuleSP executable = GetTargetExecutable();125 126 if (!executable.get())127 return;128 129 // Try to fetch the load address of the file from the process, since there130 // could be randomization of the load address.131 lldb::addr_t load_addr = GetLoadAddress(executable);132 if (load_addr == LLDB_INVALID_ADDRESS)133 return;134 135 // Request the process base address.136 lldb::addr_t image_base = m_process->GetImageInfoAddress();137 if (image_base == load_addr)138 return;139 140 // Rebase the process's modules if there is a mismatch.141 UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);142 143 ModuleList module_list;144 module_list.Append(executable);145 m_process->GetTarget().ModulesDidLoad(module_list);146 auto error = m_process->LoadModules();147 LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");148}149 150void DynamicLoaderWindowsDYLD::DidLaunch() {151 Log *log = GetLog(LLDBLog::DynamicLoader);152 LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);153 154 ModuleSP executable = GetTargetExecutable();155 if (!executable.get())156 return;157 158 lldb::addr_t load_addr = GetLoadAddress(executable);159 if (load_addr != LLDB_INVALID_ADDRESS) {160 // Update the loaded sections so that the breakpoints can be resolved.161 UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);162 163 ModuleList module_list;164 module_list.Append(executable);165 m_process->GetTarget().ModulesDidLoad(module_list);166 auto error = m_process->LoadModules();167 LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");168 }169}170 171Status DynamicLoaderWindowsDYLD::CanLoadImage() { return Status(); }172 173ThreadPlanSP174DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread,175 bool stop) {176 auto arch = m_process->GetTarget().GetArchitecture();177 if (arch.GetMachine() != llvm::Triple::x86) {178 return ThreadPlanSP();179 }180 181 uint64_t pc = thread.GetRegisterContext()->GetPC();182 // Max size of an instruction in x86 is 15 bytes.183 AddressRange range(pc, 2 * 15);184 185 DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(186 arch, nullptr, nullptr, nullptr, nullptr, m_process->GetTarget(), range);187 if (!disassembler_sp) {188 return ThreadPlanSP();189 }190 191 InstructionList *insn_list = &disassembler_sp->GetInstructionList();192 if (insn_list == nullptr) {193 return ThreadPlanSP();194 }195 196 // First instruction in a x86 Windows trampoline is going to be an indirect197 // jump through the IAT and the next one will be a nop (usually there for198 // alignment purposes). e.g.:199 // 0x70ff4cfc <+956>: jmpl *0x7100c2a8200 // 0x70ff4d02 <+962>: nop201 202 auto first_insn = insn_list->GetInstructionAtIndex(0);203 auto second_insn = insn_list->GetInstructionAtIndex(1);204 205 ExecutionContext exe_ctx(m_process->GetTarget());206 if (first_insn == nullptr || second_insn == nullptr ||207 strcmp(first_insn->GetMnemonic(&exe_ctx), "jmpl") != 0 ||208 strcmp(second_insn->GetMnemonic(&exe_ctx), "nop") != 0) {209 return ThreadPlanSP();210 }211 212 assert(first_insn->DoesBranch() && !second_insn->DoesBranch());213 214 return ThreadPlanSP(new ThreadPlanStepInstruction(215 thread, false, false, eVoteNoOpinion, eVoteNoOpinion));216}217