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