1 | //===-- DynamicLoaderFreeBSDKernel.cpp |
2 | //------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #include "lldb/Breakpoint/StoppointCallbackContext.h" |
11 | #include "lldb/Core/Debugger.h" |
12 | #include "lldb/Core/Module.h" |
13 | #include "lldb/Core/ModuleSpec.h" |
14 | #include "lldb/Core/PluginManager.h" |
15 | #include "lldb/Core/Section.h" |
16 | #include "lldb/Host/StreamFile.h" |
17 | #include "lldb/Interpreter/OptionValueProperties.h" |
18 | #include "lldb/Symbol/ObjectFile.h" |
19 | #include "lldb/Target/OperatingSystem.h" |
20 | #include "lldb/Target/RegisterContext.h" |
21 | #include "lldb/Target/StackFrame.h" |
22 | #include "lldb/Target/Target.h" |
23 | #include "lldb/Target/Thread.h" |
24 | #include "lldb/Target/ThreadPlanRunToAddress.h" |
25 | #include "lldb/Utility/DataBuffer.h" |
26 | #include "lldb/Utility/DataBufferHeap.h" |
27 | #include "lldb/Utility/LLDBLog.h" |
28 | #include "lldb/Utility/Log.h" |
29 | #include "lldb/Utility/State.h" |
30 | |
31 | #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" |
32 | |
33 | #include "DynamicLoaderFreeBSDKernel.h" |
34 | #include <memory> |
35 | #include <mutex> |
36 | |
37 | using namespace lldb; |
38 | using namespace lldb_private; |
39 | |
40 | LLDB_PLUGIN_DEFINE(DynamicLoaderFreeBSDKernel) |
41 | |
42 | void DynamicLoaderFreeBSDKernel::Initialize() { |
43 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
44 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance, |
45 | debugger_init_callback: DebuggerInit); |
46 | } |
47 | |
48 | void DynamicLoaderFreeBSDKernel::Terminate() { |
49 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
50 | } |
51 | |
52 | llvm::StringRef DynamicLoaderFreeBSDKernel::GetPluginDescriptionStatic() { |
53 | return "The Dynamic Loader Plugin For FreeBSD Kernel" ; |
54 | } |
55 | |
56 | static bool is_kernel(Module *module) { |
57 | if (!module) |
58 | return false; |
59 | |
60 | ObjectFile *objfile = module->GetObjectFile(); |
61 | if (!objfile) |
62 | return false; |
63 | if (objfile->GetType() != ObjectFile::eTypeExecutable) |
64 | return false; |
65 | if (objfile->GetStrata() != ObjectFile::eStrataUnknown && |
66 | objfile->GetStrata() != ObjectFile::eStrataKernel) |
67 | return false; |
68 | |
69 | return true; |
70 | } |
71 | |
72 | static bool is_kmod(Module *module) { |
73 | if (!module) |
74 | return false; |
75 | if (!module->GetObjectFile()) |
76 | return false; |
77 | ObjectFile *objfile = module->GetObjectFile(); |
78 | if (objfile->GetType() != ObjectFile::eTypeObjectFile && |
79 | objfile->GetType() != ObjectFile::eTypeSharedLibrary) |
80 | return false; |
81 | |
82 | return true; |
83 | } |
84 | |
85 | static bool is_reloc(Module *module) { |
86 | if (!module) |
87 | return false; |
88 | if (!module->GetObjectFile()) |
89 | return false; |
90 | ObjectFile *objfile = module->GetObjectFile(); |
91 | if (objfile->GetType() != ObjectFile::eTypeObjectFile) |
92 | return false; |
93 | |
94 | return true; |
95 | } |
96 | |
97 | // Instantiate Function of the FreeBSD Kernel Dynamic Loader Plugin called when |
98 | // Register the Plugin |
99 | DynamicLoader * |
100 | DynamicLoaderFreeBSDKernel::CreateInstance(lldb_private::Process *process, |
101 | bool force) { |
102 | // Check the environment when the plugin is not force loaded |
103 | Module *exec = process->GetTarget().GetExecutableModulePointer(); |
104 | if (exec && !is_kernel(module: exec)) { |
105 | return nullptr; |
106 | } |
107 | if (!force) { |
108 | // Check if the target is kernel |
109 | const llvm::Triple &triple_ref = |
110 | process->GetTarget().GetArchitecture().GetTriple(); |
111 | if (!triple_ref.isOSFreeBSD()) { |
112 | return nullptr; |
113 | } |
114 | } |
115 | |
116 | // At this point we have checked the target is a FreeBSD kernel and all we |
117 | // have to do is to find the kernel address |
118 | const addr_t kernel_address = FindFreeBSDKernel(process); |
119 | |
120 | if (CheckForKernelImageAtAddress(process, address: kernel_address).IsValid()) |
121 | return new DynamicLoaderFreeBSDKernel(process, kernel_address); |
122 | |
123 | return nullptr; |
124 | } |
125 | |
126 | addr_t |
127 | DynamicLoaderFreeBSDKernel::FindFreeBSDKernel(lldb_private::Process *process) { |
128 | addr_t kernel_addr = process->GetImageInfoAddress(); |
129 | if (kernel_addr == LLDB_INVALID_ADDRESS) |
130 | kernel_addr = FindKernelAtLoadAddress(process); |
131 | return kernel_addr; |
132 | } |
133 | |
134 | // Get the kernel address if the kernel is not loaded with a slide |
135 | addr_t DynamicLoaderFreeBSDKernel::FindKernelAtLoadAddress( |
136 | lldb_private::Process *process) { |
137 | Module *exe_module = process->GetTarget().GetExecutableModulePointer(); |
138 | |
139 | if (!is_kernel(module: exe_module)) |
140 | return LLDB_INVALID_ADDRESS; |
141 | |
142 | ObjectFile *exe_objfile = exe_module->GetObjectFile(); |
143 | |
144 | if (!exe_objfile->GetBaseAddress().IsValid()) |
145 | return LLDB_INVALID_ADDRESS; |
146 | |
147 | if (CheckForKernelImageAtAddress( |
148 | process, address: exe_objfile->GetBaseAddress().GetFileAddress()) |
149 | .IsValid()) |
150 | return exe_objfile->GetBaseAddress().GetFileAddress(); |
151 | |
152 | return LLDB_INVALID_ADDRESS; |
153 | } |
154 | |
155 | // Read ELF header from memry and return |
156 | bool DynamicLoaderFreeBSDKernel::(Process *process, |
157 | lldb::addr_t addr, |
158 | llvm::ELF::Elf32_Ehdr &, |
159 | bool *read_error) { |
160 | Status error; |
161 | if (read_error) |
162 | *read_error = false; |
163 | |
164 | if (process->ReadMemory(vm_addr: addr, buf: &header, size: sizeof(header), error) != |
165 | sizeof(header)) { |
166 | if (read_error) |
167 | *read_error = true; |
168 | return false; |
169 | } |
170 | |
171 | if (!header.checkMagic()) |
172 | return false; |
173 | |
174 | return true; |
175 | } |
176 | |
177 | // Check the correctness of Kernel and return UUID |
178 | lldb_private::UUID DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress( |
179 | Process *process, lldb::addr_t addr, bool *read_error) { |
180 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
181 | |
182 | if (addr == LLDB_INVALID_ADDRESS) { |
183 | if (read_error) |
184 | *read_error = true; |
185 | return UUID(); |
186 | } |
187 | |
188 | LLDB_LOGF(log, |
189 | "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress: " |
190 | "looking for kernel binary at 0x%" PRIx64, |
191 | addr); |
192 | |
193 | llvm::ELF::Elf32_Ehdr ; |
194 | if (!ReadELFHeader(process, addr, header)) { |
195 | *read_error = true; |
196 | return UUID(); |
197 | } |
198 | |
199 | // Check header type |
200 | if (header.e_type != llvm::ELF::ET_EXEC) |
201 | return UUID(); |
202 | |
203 | ModuleSP memory_module_sp = |
204 | process->ReadModuleFromMemory(file_spec: FileSpec("temp_freebsd_kernel" ), header_addr: addr); |
205 | |
206 | if (!memory_module_sp.get()) { |
207 | *read_error = true; |
208 | return UUID(); |
209 | } |
210 | |
211 | ObjectFile *exe_objfile = memory_module_sp->GetObjectFile(); |
212 | if (exe_objfile == nullptr) { |
213 | LLDB_LOGF(log, |
214 | "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress " |
215 | "found a binary at 0x%" PRIx64 |
216 | " but could not create an object file from memory" , |
217 | addr); |
218 | return UUID(); |
219 | } |
220 | |
221 | // In here, I should check is_kernel for memory_module_sp |
222 | // However, the ReadModuleFromMemory reads wrong section so that this check |
223 | // will failed |
224 | ArchSpec kernel_arch(llvm::ELF::convertEMachineToArchName(EMachine: header.e_machine)); |
225 | |
226 | if (!process->GetTarget().GetArchitecture().IsCompatibleMatch(rhs: kernel_arch)) |
227 | process->GetTarget().SetArchitecture(arch_spec: kernel_arch); |
228 | |
229 | std::string uuid_str; |
230 | if (memory_module_sp->GetUUID().IsValid()) { |
231 | uuid_str = "with UUID " ; |
232 | uuid_str += memory_module_sp->GetUUID().GetAsString(); |
233 | } else { |
234 | uuid_str = "and no LC_UUID found in load commands " ; |
235 | } |
236 | LLDB_LOGF(log, |
237 | "DynamicLoaderFreeBSDKernel::CheckForKernelImageAtAddress: " |
238 | "kernel binary image found at 0x%" PRIx64 " with arch '%s' %s" , |
239 | addr, kernel_arch.GetTriple().str().c_str(), uuid_str.c_str()); |
240 | |
241 | return memory_module_sp->GetUUID(); |
242 | } |
243 | |
244 | void DynamicLoaderFreeBSDKernel::DebuggerInit( |
245 | lldb_private::Debugger &debugger) {} |
246 | |
247 | DynamicLoaderFreeBSDKernel::DynamicLoaderFreeBSDKernel(Process *process, |
248 | addr_t kernel_address) |
249 | : DynamicLoader(process), m_process(process), |
250 | m_linker_file_list_struct_addr(LLDB_INVALID_ADDRESS), |
251 | m_linker_file_head_addr(LLDB_INVALID_ADDRESS), |
252 | m_kernel_load_address(kernel_address), m_mutex() { |
253 | process->SetCanRunCode(false); |
254 | } |
255 | |
256 | DynamicLoaderFreeBSDKernel::~DynamicLoaderFreeBSDKernel() { Clear(clear_process: true); } |
257 | |
258 | void DynamicLoaderFreeBSDKernel::Update() { |
259 | LoadKernelModules(); |
260 | SetNotificationBreakPoint(); |
261 | } |
262 | |
263 | // Create in memory Module at the load address |
264 | bool DynamicLoaderFreeBSDKernel::KModImageInfo::ReadMemoryModule( |
265 | lldb_private::Process *process) { |
266 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
267 | if (m_memory_module_sp) |
268 | return true; |
269 | if (m_load_address == LLDB_INVALID_ADDRESS) |
270 | return false; |
271 | |
272 | FileSpec file_spec(m_name); |
273 | |
274 | ModuleSP memory_module_sp; |
275 | |
276 | llvm::ELF::Elf32_Ehdr ; |
277 | size_t size_to_read = 512; |
278 | |
279 | if (ReadELFHeader(process, addr: m_load_address, header&: elf_eheader)) { |
280 | if (elf_eheader.e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32) { |
281 | size_to_read = sizeof(llvm::ELF::Elf32_Ehdr) + |
282 | elf_eheader.e_phnum * elf_eheader.e_phentsize; |
283 | } else if (elf_eheader.e_ident[llvm::ELF::EI_CLASS] == |
284 | llvm::ELF::ELFCLASS64) { |
285 | llvm::ELF::Elf64_Ehdr ; |
286 | Status error; |
287 | if (process->ReadMemory(vm_addr: m_load_address, buf: &elf_eheader, size: sizeof(elf_eheader), |
288 | error) == sizeof(elf_eheader)) |
289 | size_to_read = sizeof(llvm::ELF::Elf64_Ehdr) + |
290 | elf_eheader.e_phnum * elf_eheader.e_phentsize; |
291 | } |
292 | } |
293 | |
294 | memory_module_sp = |
295 | process->ReadModuleFromMemory(file_spec, header_addr: m_load_address, size_to_read); |
296 | |
297 | if (!memory_module_sp) |
298 | return false; |
299 | |
300 | bool this_is_kernel = is_kernel(module: memory_module_sp.get()); |
301 | |
302 | if (!m_uuid.IsValid() && memory_module_sp->GetUUID().IsValid()) |
303 | m_uuid = memory_module_sp->GetUUID(); |
304 | |
305 | m_memory_module_sp = memory_module_sp; |
306 | m_is_kernel = this_is_kernel; |
307 | |
308 | // The kernel binary is from memory |
309 | if (this_is_kernel) { |
310 | LLDB_LOGF(log, "KextImageInfo::ReadMemoryModule read the kernel binary out " |
311 | "of memory" ); |
312 | |
313 | if (memory_module_sp->GetArchitecture().IsValid()) |
314 | process->GetTarget().SetArchitecture(arch_spec: memory_module_sp->GetArchitecture()); |
315 | } |
316 | |
317 | return true; |
318 | } |
319 | |
320 | bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule( |
321 | lldb_private::Process *process) { |
322 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
323 | |
324 | if (IsLoaded()) |
325 | return true; |
326 | |
327 | Target &target = process->GetTarget(); |
328 | |
329 | if (IsKernel() && m_uuid.IsValid()) { |
330 | Stream &s = target.GetDebugger().GetOutputStream(); |
331 | s.Printf(format: "Kernel UUID: %s\n" , m_uuid.GetAsString().c_str()); |
332 | s.Printf(format: "Load Address: 0x%" PRIx64 "\n" , m_load_address); |
333 | } |
334 | |
335 | // Test if the module is loaded into the taget, |
336 | // maybe the module is loaded manually by user by doing target module add |
337 | // So that we have to create the module manually |
338 | if (!m_module_sp) { |
339 | const ModuleList &target_images = target.GetImages(); |
340 | m_module_sp = target_images.FindModule(uuid: m_uuid); |
341 | |
342 | // Search in the file system |
343 | if (!m_module_sp) { |
344 | ModuleSpec module_spec(FileSpec(GetPath()), target.GetArchitecture()); |
345 | if (IsKernel()) { |
346 | Status error; |
347 | if (PluginManager::DownloadObjectAndSymbolFile(module_spec, error, |
348 | force_lookup: true)) { |
349 | if (FileSystem::Instance().Exists(file_spec: module_spec.GetFileSpec())) |
350 | m_module_sp = std::make_shared<Module>(args&: module_spec.GetFileSpec(), |
351 | args: target.GetArchitecture()); |
352 | } |
353 | } |
354 | |
355 | if (!m_module_sp) |
356 | m_module_sp = target.GetOrCreateModule(module_spec, notify: true); |
357 | if (IsKernel() && !m_module_sp) { |
358 | Stream &s = target.GetDebugger().GetOutputStream(); |
359 | s.Printf(format: "WARNING: Unable to locate kernel binary on the debugger " |
360 | "system.\n" ); |
361 | } |
362 | } |
363 | |
364 | if (m_module_sp) { |
365 | // If the file is not kernel or kmod, the target should be loaded once and |
366 | // don't reload again |
367 | if (!IsKernel() && !is_kmod(module: m_module_sp.get())) { |
368 | ModuleSP existing_module_sp = target.GetImages().FindModule(uuid: m_uuid); |
369 | if (existing_module_sp && |
370 | existing_module_sp->IsLoadedInTarget(target: &target)) { |
371 | LLDB_LOGF(log, |
372 | "'%s' with UUID %s is not a kmod or kernel, and is " |
373 | "already registered in target, not loading." , |
374 | m_name.c_str(), m_uuid.GetAsString().c_str()); |
375 | return true; |
376 | } |
377 | } |
378 | m_uuid = m_module_sp->GetUUID(); |
379 | |
380 | // or append to the images |
381 | target.GetImages().AppendIfNeeded(new_module: m_module_sp, notify: false); |
382 | } |
383 | } |
384 | |
385 | // If this file is relocatable kernel module(x86_64), adjust it's |
386 | // section(PT_LOAD segment) and return Because the kernel module's load |
387 | // address is the text section. lldb cannot create full memory module upon |
388 | // relocatable file So what we do is to set the load address only. |
389 | if (is_kmod(module: m_module_sp.get()) && is_reloc(module: m_module_sp.get())) { |
390 | m_stop_id = process->GetStopID(); |
391 | bool changed = false; |
392 | m_module_sp->SetLoadAddress(target, value: m_load_address, value_is_offset: true, changed); |
393 | return true; |
394 | } |
395 | |
396 | if (m_module_sp) |
397 | ReadMemoryModule(process); |
398 | |
399 | // Calculate the slides of in memory module |
400 | if (!m_memory_module_sp || !m_module_sp) { |
401 | m_module_sp.reset(); |
402 | return false; |
403 | } |
404 | |
405 | ObjectFile *ondisk_object_file = m_module_sp->GetObjectFile(); |
406 | ObjectFile *memory_object_file = m_memory_module_sp->GetObjectFile(); |
407 | |
408 | if (!ondisk_object_file || !memory_object_file) |
409 | m_module_sp.reset(); |
410 | |
411 | // Find the slide address |
412 | addr_t fixed_slide = LLDB_INVALID_ADDRESS; |
413 | if (llvm::dyn_cast<ObjectFileELF>(Val: memory_object_file)) { |
414 | addr_t load_address = memory_object_file->GetBaseAddress().GetFileAddress(); |
415 | |
416 | if (load_address != LLDB_INVALID_ADDRESS && |
417 | m_load_address != load_address) { |
418 | fixed_slide = m_load_address - load_address; |
419 | LLDB_LOGF(log, |
420 | "kmod %s in-memory LOAD vmaddr is not correct, using a " |
421 | "fixed slide of 0x%" PRIx64, |
422 | m_name.c_str(), fixed_slide); |
423 | } |
424 | } |
425 | |
426 | SectionList *ondisk_section_list = ondisk_object_file->GetSectionList(); |
427 | SectionList *memory_section_list = memory_object_file->GetSectionList(); |
428 | |
429 | if (memory_section_list && ondisk_object_file) { |
430 | const uint32_t num_ondisk_sections = ondisk_section_list->GetSize(); |
431 | uint32_t num_load_sections = 0; |
432 | |
433 | for (uint32_t section_idx = 0; section_idx < num_ondisk_sections; |
434 | ++section_idx) { |
435 | SectionSP on_disk_section_sp = |
436 | ondisk_section_list->GetSectionAtIndex(idx: section_idx); |
437 | |
438 | if (!on_disk_section_sp) |
439 | continue; |
440 | if (fixed_slide != LLDB_INVALID_ADDRESS) { |
441 | target.SetSectionLoadAddress(section: on_disk_section_sp, |
442 | load_addr: on_disk_section_sp->GetFileAddress() + |
443 | fixed_slide); |
444 | |
445 | } else { |
446 | const Section *memory_section = |
447 | memory_section_list |
448 | ->FindSectionByName(section_dstr: on_disk_section_sp->GetName()) |
449 | .get(); |
450 | if (memory_section) { |
451 | target.SetSectionLoadAddress(section: on_disk_section_sp, |
452 | load_addr: memory_section->GetFileAddress()); |
453 | ++num_load_sections; |
454 | } |
455 | } |
456 | } |
457 | |
458 | if (num_load_sections) |
459 | m_stop_id = process->GetStopID(); |
460 | else |
461 | m_module_sp.reset(); |
462 | } else { |
463 | m_module_sp.reset(); |
464 | } |
465 | |
466 | if (IsLoaded() && m_module_sp && IsKernel()) { |
467 | Stream &s = target.GetDebugger().GetOutputStream(); |
468 | ObjectFile *kernel_object_file = m_module_sp->GetObjectFile(); |
469 | if (kernel_object_file) { |
470 | addr_t file_address = |
471 | kernel_object_file->GetBaseAddress().GetFileAddress(); |
472 | if (m_load_address != LLDB_INVALID_ADDRESS && |
473 | file_address != LLDB_INVALID_ADDRESS) { |
474 | s.Printf(format: "Kernel slide 0x%" PRIx64 " in memory.\n" , |
475 | m_load_address - file_address); |
476 | s.Printf(format: "Loaded kernel file %s\n" , |
477 | m_module_sp->GetFileSpec().GetPath().c_str()); |
478 | } |
479 | } |
480 | s.Flush(); |
481 | } |
482 | |
483 | return IsLoaded(); |
484 | } |
485 | |
486 | // This function is work for kernel file, others it wil reset load address and |
487 | // return false |
488 | bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingFileAddress( |
489 | lldb_private::Process *process) { |
490 | if (IsLoaded()) |
491 | return true; |
492 | |
493 | if (m_module_sp) { |
494 | bool changed = false; |
495 | if (m_module_sp->SetLoadAddress(target&: process->GetTarget(), value: 0, value_is_offset: true, changed)) |
496 | m_stop_id = process->GetStopID(); |
497 | } |
498 | |
499 | return false; |
500 | } |
501 | |
502 | // Get the head of found_list |
503 | bool DynamicLoaderFreeBSDKernel::() { |
504 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
505 | |
506 | if (m_linker_file_list_struct_addr.IsValid()) { |
507 | // Get tqh_first struct element from linker_files |
508 | Status error; |
509 | addr_t address = m_process->ReadPointerFromMemory( |
510 | vm_addr: m_linker_file_list_struct_addr.GetLoadAddress(target: &m_process->GetTarget()), |
511 | error); |
512 | if (address != LLDB_INVALID_ADDRESS && error.Success()) { |
513 | m_linker_file_head_addr = Address(address); |
514 | } else { |
515 | m_linker_file_list_struct_addr.Clear(); |
516 | return false; |
517 | } |
518 | |
519 | if (!m_linker_file_head_addr.IsValid() || |
520 | m_linker_file_head_addr.GetFileAddress() == 0) { |
521 | m_linker_file_list_struct_addr.Clear(); |
522 | return false; |
523 | } |
524 | } |
525 | return true; |
526 | } |
527 | |
528 | // Parse Kmod info in found_list |
529 | bool DynamicLoaderFreeBSDKernel::ParseKmods(Address linker_files_head_addr) { |
530 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
531 | KModImageInfo::collection_type linker_files_list; |
532 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
533 | |
534 | if (!ReadAllKmods(linker_files_head_address: linker_files_head_addr, kmods_list&: linker_files_list)) |
535 | return false; |
536 | LLDB_LOGF( |
537 | log, |
538 | "Kmod-changed breakpoint hit, there are %zu kernel modules currently.\n" , |
539 | linker_files_list.size()); |
540 | |
541 | ModuleList &modules = m_process->GetTarget().GetImages(); |
542 | ModuleList remove_modules; |
543 | ModuleList add_modules; |
544 | |
545 | for (ModuleSP module : modules.Modules()) { |
546 | if (is_kernel(module: module.get())) |
547 | continue; |
548 | if (is_kmod(module: module.get())) |
549 | remove_modules.AppendIfNeeded(new_module: module); |
550 | } |
551 | |
552 | m_process->GetTarget().ModulesDidUnload(module_list&: remove_modules, delete_locations: false); |
553 | |
554 | for (KModImageInfo &image_info : linker_files_list) { |
555 | if (m_kld_name_to_uuid.find(x: image_info.GetName()) != |
556 | m_kld_name_to_uuid.end()) |
557 | image_info.SetUUID(m_kld_name_to_uuid[image_info.GetName()]); |
558 | bool failed_to_load = false; |
559 | if (!image_info.LoadImageUsingMemoryModule(process: m_process)) { |
560 | image_info.LoadImageUsingFileAddress(process: m_process); |
561 | failed_to_load = true; |
562 | } else { |
563 | m_linker_files_list.push_back(x: image_info); |
564 | m_kld_name_to_uuid[image_info.GetName()] = image_info.GetUUID(); |
565 | } |
566 | |
567 | if (!failed_to_load) |
568 | add_modules.AppendIfNeeded(new_module: image_info.GetModule()); |
569 | } |
570 | m_process->GetTarget().ModulesDidLoad(module_list&: add_modules); |
571 | return true; |
572 | } |
573 | |
574 | // Read all kmod from a given arrays of list |
575 | bool DynamicLoaderFreeBSDKernel::ReadAllKmods( |
576 | Address linker_files_head_addr, |
577 | KModImageInfo::collection_type &kmods_list) { |
578 | |
579 | // Get offset of next member and load address symbol |
580 | static ConstString kld_off_address_symbol_name("kld_off_address" ); |
581 | static ConstString kld_off_next_symbol_name("kld_off_next" ); |
582 | static ConstString kld_off_filename_symbol_name("kld_off_filename" ); |
583 | static ConstString kld_off_pathname_symbol_name("kld_off_pathname" ); |
584 | const Symbol *kld_off_address_symbol = |
585 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
586 | name: kld_off_address_symbol_name, symbol_type: eSymbolTypeData); |
587 | const Symbol *kld_off_next_symbol = |
588 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
589 | name: kld_off_next_symbol_name, symbol_type: eSymbolTypeData); |
590 | const Symbol *kld_off_filename_symbol = |
591 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
592 | name: kld_off_filename_symbol_name, symbol_type: eSymbolTypeData); |
593 | const Symbol *kld_off_pathname_symbol = |
594 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
595 | name: kld_off_pathname_symbol_name, symbol_type: eSymbolTypeData); |
596 | |
597 | if (!kld_off_address_symbol || !kld_off_next_symbol || |
598 | !kld_off_filename_symbol || !kld_off_pathname_symbol) |
599 | return false; |
600 | |
601 | Status error; |
602 | const int32_t kld_off_address = m_process->ReadSignedIntegerFromMemory( |
603 | load_addr: kld_off_address_symbol->GetAddress().GetLoadAddress( |
604 | target: &m_process->GetTarget()), |
605 | byte_size: 4, fail_value: 0, error); |
606 | if (error.Fail()) |
607 | return false; |
608 | const int32_t kld_off_next = m_process->ReadSignedIntegerFromMemory( |
609 | load_addr: kld_off_next_symbol->GetAddress().GetLoadAddress(target: &m_process->GetTarget()), |
610 | byte_size: 4, fail_value: 0, error); |
611 | if (error.Fail()) |
612 | return false; |
613 | const int32_t kld_off_filename = m_process->ReadSignedIntegerFromMemory( |
614 | load_addr: kld_off_filename_symbol->GetAddress().GetLoadAddress( |
615 | target: &m_process->GetTarget()), |
616 | byte_size: 4, fail_value: 0, error); |
617 | if (error.Fail()) |
618 | return false; |
619 | |
620 | const int32_t kld_off_pathname = m_process->ReadSignedIntegerFromMemory( |
621 | load_addr: kld_off_pathname_symbol->GetAddress().GetLoadAddress( |
622 | target: &m_process->GetTarget()), |
623 | byte_size: 4, fail_value: 0, error); |
624 | if (error.Fail()) |
625 | return false; |
626 | |
627 | // Parse KMods |
628 | addr_t kld_load_addr(LLDB_INVALID_ADDRESS); |
629 | char kld_filename[255]; |
630 | char kld_pathname[255]; |
631 | addr_t current_kld = |
632 | linker_files_head_addr.GetLoadAddress(target: &m_process->GetTarget()); |
633 | |
634 | while (current_kld != 0) { |
635 | addr_t kld_filename_addr = |
636 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_filename, error); |
637 | if (error.Fail()) |
638 | return false; |
639 | addr_t kld_pathname_addr = |
640 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_pathname, error); |
641 | if (error.Fail()) |
642 | return false; |
643 | |
644 | m_process->ReadCStringFromMemory(vm_addr: kld_filename_addr, cstr: kld_filename, |
645 | cstr_max_len: sizeof(kld_filename), error); |
646 | if (error.Fail()) |
647 | return false; |
648 | m_process->ReadCStringFromMemory(vm_addr: kld_pathname_addr, cstr: kld_pathname, |
649 | cstr_max_len: sizeof(kld_pathname), error); |
650 | if (error.Fail()) |
651 | return false; |
652 | kld_load_addr = |
653 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_address, error); |
654 | if (error.Fail()) |
655 | return false; |
656 | |
657 | kmods_list.emplace_back(); |
658 | KModImageInfo &kmod_info = kmods_list.back(); |
659 | kmod_info.SetName(kld_filename); |
660 | kmod_info.SetLoadAddress(kld_load_addr); |
661 | kmod_info.SetPath(kld_pathname); |
662 | |
663 | current_kld = |
664 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_next, error); |
665 | if (kmod_info.GetName() == "kernel" ) |
666 | kmods_list.pop_back(); |
667 | if (error.Fail()) |
668 | return false; |
669 | } |
670 | |
671 | return true; |
672 | } |
673 | |
674 | // Read all kmods |
675 | void DynamicLoaderFreeBSDKernel::ReadAllKmods() { |
676 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
677 | |
678 | if (ReadKmodsListHeader()) { |
679 | if (m_linker_file_head_addr.IsValid()) { |
680 | if (!ParseKmods(linker_files_head_addr: m_linker_file_head_addr)) |
681 | m_linker_files_list.clear(); |
682 | } |
683 | } |
684 | } |
685 | |
686 | // Load all Kernel Modules |
687 | void DynamicLoaderFreeBSDKernel::LoadKernelModules() { |
688 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
689 | LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules " |
690 | "Start loading Kernel Module" ); |
691 | |
692 | // Initialize Kernel Image Information at the first time |
693 | if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) { |
694 | ModuleSP module_sp = m_process->GetTarget().GetExecutableModule(); |
695 | if (is_kernel(module: module_sp.get())) { |
696 | m_kernel_image_info.SetModule(module_sp); |
697 | m_kernel_image_info.SetIsKernel(true); |
698 | } |
699 | |
700 | // Set name for kernel |
701 | llvm::StringRef kernel_name("freebsd_kernel" ); |
702 | module_sp = m_kernel_image_info.GetModule(); |
703 | if (module_sp.get() && module_sp->GetObjectFile() && |
704 | !module_sp->GetObjectFile()->GetFileSpec().GetFilename().IsEmpty()) |
705 | kernel_name = module_sp->GetObjectFile() |
706 | ->GetFileSpec() |
707 | .GetFilename() |
708 | .GetStringRef(); |
709 | m_kernel_image_info.SetName(kernel_name.data()); |
710 | |
711 | if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) { |
712 | m_kernel_image_info.SetLoadAddress(m_kernel_load_address); |
713 | } |
714 | |
715 | // Build In memory Module |
716 | if (m_kernel_image_info.GetLoadAddress() != LLDB_INVALID_ADDRESS) { |
717 | // If the kernel is not loaded in the memory, use file to load |
718 | if (!m_kernel_image_info.LoadImageUsingMemoryModule(process: m_process)) |
719 | m_kernel_image_info.LoadImageUsingFileAddress(process: m_process); |
720 | } |
721 | } |
722 | |
723 | LoadOperatingSystemPlugin(flush: false); |
724 | |
725 | if (!m_kernel_image_info.IsLoaded() || !m_kernel_image_info.GetModule()) { |
726 | m_kernel_image_info.Clear(); |
727 | return; |
728 | } |
729 | |
730 | static ConstString modlist_symbol_name("linker_files" ); |
731 | |
732 | const Symbol *symbol = |
733 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
734 | name: modlist_symbol_name, symbol_type: lldb::eSymbolTypeData); |
735 | |
736 | if (symbol) { |
737 | m_linker_file_list_struct_addr = symbol->GetAddress(); |
738 | ReadAllKmods(); |
739 | } else { |
740 | LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules " |
741 | "cannot file modlist symbol" ); |
742 | } |
743 | } |
744 | |
745 | // Update symbol when use kldload by setting callback function on kldload |
746 | void DynamicLoaderFreeBSDKernel::SetNotificationBreakPoint() {} |
747 | |
748 | // Hook called when attach to a process |
749 | void DynamicLoaderFreeBSDKernel::DidAttach() { |
750 | PrivateInitialize(process: m_process); |
751 | Update(); |
752 | } |
753 | |
754 | // Hook called after attach to a process |
755 | void DynamicLoaderFreeBSDKernel::DidLaunch() { |
756 | PrivateInitialize(process: m_process); |
757 | Update(); |
758 | } |
759 | |
760 | // Clear all member except kernel address |
761 | void DynamicLoaderFreeBSDKernel::Clear(bool clear_process) { |
762 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
763 | if (clear_process) |
764 | m_process = nullptr; |
765 | m_linker_file_head_addr.Clear(); |
766 | m_linker_file_list_struct_addr.Clear(); |
767 | m_kernel_image_info.Clear(); |
768 | m_linker_files_list.clear(); |
769 | } |
770 | |
771 | // Reinitialize class |
772 | void DynamicLoaderFreeBSDKernel::PrivateInitialize(Process *process) { |
773 | Clear(clear_process: true); |
774 | m_process = process; |
775 | } |
776 | |
777 | ThreadPlanSP DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan( |
778 | lldb_private::Thread &thread, bool stop_others) { |
779 | Log *log = GetLog(mask: LLDBLog::Step); |
780 | LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan is " |
781 | "not yet implemented." ); |
782 | return {}; |
783 | } |
784 | |
785 | Status DynamicLoaderFreeBSDKernel::CanLoadImage() { |
786 | Status error("shared object cannot be loaded into kernel" ); |
787 | return error; |
788 | } |
789 | |