LLDB  mainline
DynamicLoaderWindowsDYLD.cpp
Go to the documentation of this file.
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
11 #include "lldb/Core/Module.h"
14 #include "lldb/Target/Platform.h"
15 #include "lldb/Target/Process.h"
17 #include "lldb/Target/Target.h"
19 #include "lldb/Utility/Log.h"
20 
21 #include "llvm/ADT/Triple.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
27 
29  : DynamicLoader(process) {}
30 
31 DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() = default;
32 
33 void DynamicLoaderWindowsDYLD::Initialize() {
34  PluginManager::RegisterPlugin(GetPluginNameStatic(),
35  GetPluginDescriptionStatic(), CreateInstance);
36 }
37 
38 void DynamicLoaderWindowsDYLD::Terminate() {}
39 
40 ConstString DynamicLoaderWindowsDYLD::GetPluginNameStatic() {
41  static ConstString g_plugin_name("windows-dyld");
42  return g_plugin_name;
43 }
44 
45 const char *DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic() {
46  return "Dynamic loader plug-in that watches for shared library "
47  "loads/unloads in Windows processes.";
48 }
49 
50 DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process,
51  bool force) {
52  bool should_create = force;
53  if (!should_create) {
54  const llvm::Triple &triple_ref =
55  process->GetTarget().GetArchitecture().GetTriple();
56  if (triple_ref.getOS() == llvm::Triple::Win32)
57  should_create = true;
58  }
59 
60  if (should_create)
61  return new DynamicLoaderWindowsDYLD(process);
62 
63  return nullptr;
64 }
65 
66 void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,
67  const ModuleSpec module_spec,
68  lldb::addr_t module_addr) {
69 
70  // Resolve the module unless we already have one.
71  if (!module_sp) {
72  Status error;
73  module_sp = m_process->GetTarget().GetOrCreateModule(module_spec,
74  true /* notify */, &error);
75  if (error.Fail())
76  return;
77  }
78 
79  m_loaded_modules[module_sp] = module_addr;
80  UpdateLoadedSectionsCommon(module_sp, module_addr, false);
81  ModuleList module_list;
82  module_list.Append(module_sp);
83  m_process->GetTarget().ModulesDidLoad(module_list);
84 }
85 
86 void DynamicLoaderWindowsDYLD::OnUnloadModule(lldb::addr_t module_addr) {
87  Address resolved_addr;
88  if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr))
89  return;
90 
91  ModuleSP module_sp = resolved_addr.GetModule();
92  if (module_sp) {
93  m_loaded_modules.erase(module_sp);
94  UnloadSectionsCommon(module_sp);
95  ModuleList module_list;
96  module_list.Append(module_sp);
97  m_process->GetTarget().ModulesDidUnload(module_list, false);
98  }
99 }
100 
101 lldb::addr_t DynamicLoaderWindowsDYLD::GetLoadAddress(ModuleSP executable) {
102  // First, see if the load address is already cached.
103  auto it = m_loaded_modules.find(executable);
104  if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS)
105  return it->second;
106 
108 
109  // Second, try to get it through the process plugins. For a remote process,
110  // the remote platform will be responsible for providing it.
111  FileSpec file_spec(executable->GetPlatformFileSpec());
112  bool is_loaded = false;
113  Status status =
114  m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);
115  // Servers other than lldb server could respond with a bogus address.
116  if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {
117  m_loaded_modules[executable] = load_addr;
118  return load_addr;
119  }
120 
121  return LLDB_INVALID_ADDRESS;
122 }
123 
124 void DynamicLoaderWindowsDYLD::DidAttach() {
126  LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);
127 
128  ModuleSP executable = GetTargetExecutable();
129 
130  if (!executable.get())
131  return;
132 
133  // Try to fetch the load address of the file from the process, since there
134  // could be randomization of the load address.
135  lldb::addr_t load_addr = GetLoadAddress(executable);
136  if (load_addr == LLDB_INVALID_ADDRESS)
137  return;
138 
139  // Request the process base address.
140  lldb::addr_t image_base = m_process->GetImageInfoAddress();
141  if (image_base == load_addr)
142  return;
143 
144  // Rebase the process's modules if there is a mismatch.
145  UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);
146 
147  ModuleList module_list;
148  module_list.Append(executable);
149  m_process->GetTarget().ModulesDidLoad(module_list);
150  auto error = m_process->LoadModules();
151  LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");
152 }
153 
154 void DynamicLoaderWindowsDYLD::DidLaunch() {
156  LLDB_LOGF(log, "DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);
157 
158  ModuleSP executable = GetTargetExecutable();
159  if (!executable.get())
160  return;
161 
162  lldb::addr_t load_addr = GetLoadAddress(executable);
163  if (load_addr != LLDB_INVALID_ADDRESS) {
164  // Update the loaded sections so that the breakpoints can be resolved.
165  UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);
166 
167  ModuleList module_list;
168  module_list.Append(executable);
169  m_process->GetTarget().ModulesDidLoad(module_list);
170  auto error = m_process->LoadModules();
171  LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");
172  }
173 }
174 
175 Status DynamicLoaderWindowsDYLD::CanLoadImage() { return Status(); }
176 
177 ThreadPlanSP
178 DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread,
179  bool stop) {
180  auto arch = m_process->GetTarget().GetArchitecture();
181  if (arch.GetMachine() != llvm::Triple::x86) {
182  return ThreadPlanSP();
183  }
184 
185  uint64_t pc = thread.GetRegisterContext()->GetPC();
186  // Max size of an instruction in x86 is 15 bytes.
187  AddressRange range(pc, 2 * 15);
188 
189  DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
190  arch, nullptr, nullptr, m_process->GetTarget(), range);
191  if (!disassembler_sp) {
192  return ThreadPlanSP();
193  }
194 
195  InstructionList *insn_list = &disassembler_sp->GetInstructionList();
196  if (insn_list == nullptr) {
197  return ThreadPlanSP();
198  }
199 
200  // First instruction in a x86 Windows trampoline is going to be an indirect
201  // jump through the IAT and the next one will be a nop (usually there for
202  // alignment purposes). e.g.:
203  // 0x70ff4cfc <+956>: jmpl *0x7100c2a8
204  // 0x70ff4d02 <+962>: nop
205 
206  auto first_insn = insn_list->GetInstructionAtIndex(0);
207  auto second_insn = insn_list->GetInstructionAtIndex(1);
208 
209  ExecutionContext exe_ctx(m_process->GetTarget());
210  if (first_insn == nullptr || second_insn == nullptr ||
211  strcmp(first_insn->GetMnemonic(&exe_ctx), "jmpl") != 0 ||
212  strcmp(second_insn->GetMnemonic(&exe_ctx), "nop") != 0) {
213  return ThreadPlanSP();
214  }
215 
216  assert(first_insn->DoesBranch() && !second_insn->DoesBranch());
217 
218  return ThreadPlanSP(new ThreadPlanStepInstruction(
219  thread, false, false, eVoteNoOpinion, eVoteNoOpinion));
220 }
lldb_private::ExecutionContext
Definition: ExecutionContext.h:292
LIBLLDB_LOG_DYNAMIC_LOADER
#define LIBLLDB_LOG_DYNAMIC_LOADER
Definition: Logging.h:17
DynamicLoaderWindowsDYLD.h
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:249
lldb_private::Process
Definition: Process.h:341
Module.h
lldb_private::Process::GetTarget
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1209
lldb_private::eVoteNoOpinion
@ eVoteNoOpinion
Definition: lldb-private-enumerations.h:59
lldb_private::InstructionList::GetInstructionAtIndex
lldb::InstructionSP GetInstructionAtIndex(size_t idx) const
Definition: Disassembler.cpp:945
lldb_private::ArchSpec::GetTriple
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:444
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
pc
@ pc
Definition: CompactUnwindInfo.cpp:1250
lldb_private::ThreadPlanStepInstruction
Definition: ThreadPlanStepInstruction.h:18
Process.h
Target.h
Platform.h
lldb_private::FileSpec
Definition: FileSpec.h:56
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::Status::Success
bool Success() const
Test for success condition.
Definition: Status.cpp:288
lldb_private::InstructionList
Definition: Disassembler.h:267
lldb_private::ModuleList
Definition: ModuleList.h:72
Log.h
lldb_private::Thread
Definition: Thread.h:60
lldb_private::ConstString
Definition: ConstString.h:40
lldb_private::AddressRange
Definition: AddressRange.h:25
lldb_private::DynamicLoader
Definition: DynamicLoader.h:52
lldb_private::ModuleSpec
Definition: ModuleSpec.h:26
lldb_private::Target::GetArchitecture
const ArchSpec & GetArchitecture() const
Definition: Target.h:967
lldb_private::Status
Definition: Status.h:44
lldb_private::Address
Definition: Address.h:59
ThreadPlanStepInstruction.h
PluginManager.h
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:86
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::Address::GetModule
lldb::ModuleSP GetModule() const
Get accessor for the module for this address.
Definition: Address.cpp:282
LLDB_PLUGIN_DEFINE
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
lldb_private::Log
Definition: Log.h:49
lldb_private::DynamicLoaderWindowsDYLD
Definition: DynamicLoaderWindowsDYLD.h:19
lldb_private::GetLogIfAnyCategoriesSet
Log * GetLogIfAnyCategoriesSet(uint32_t mask)
Definition: Logging.cpp:62
lldb_private::Thread::GetRegisterContext
virtual lldb::RegisterContextSP GetRegisterContext()=0
lldb
Definition: SBAddress.h:15
RegisterContext.h
LLDB_LOG_ERROR
#define LLDB_LOG_ERROR(log, error,...)
Definition: Log.h:265
ExecutionContext.h
lldb_private::ModuleList::Append
void Append(const lldb::ModuleSP &module_sp, bool notify=true)
Append a module to the module list.