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 | lldb::StreamUP s = target.GetDebugger().GetAsyncOutputStream(); |
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 | target.GetDebugger().GetAsyncOutputStream()->Printf( |
359 | 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 | lldb::StreamUP s = target.GetDebugger().GetAsyncOutputStream(); |
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 | } |
481 | |
482 | return IsLoaded(); |
483 | } |
484 | |
485 | // This function is work for kernel file, others it wil reset load address and |
486 | // return false |
487 | bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingFileAddress( |
488 | lldb_private::Process *process) { |
489 | if (IsLoaded()) |
490 | return true; |
491 | |
492 | if (m_module_sp) { |
493 | bool changed = false; |
494 | if (m_module_sp->SetLoadAddress(target&: process->GetTarget(), value: 0, value_is_offset: true, changed)) |
495 | m_stop_id = process->GetStopID(); |
496 | } |
497 | |
498 | return false; |
499 | } |
500 | |
501 | // Get the head of found_list |
502 | bool DynamicLoaderFreeBSDKernel::() { |
503 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
504 | |
505 | if (m_linker_file_list_struct_addr.IsValid()) { |
506 | // Get tqh_first struct element from linker_files |
507 | Status error; |
508 | addr_t address = m_process->ReadPointerFromMemory( |
509 | vm_addr: m_linker_file_list_struct_addr.GetLoadAddress(target: &m_process->GetTarget()), |
510 | error); |
511 | if (address != LLDB_INVALID_ADDRESS && error.Success()) { |
512 | m_linker_file_head_addr = Address(address); |
513 | } else { |
514 | m_linker_file_list_struct_addr.Clear(); |
515 | return false; |
516 | } |
517 | |
518 | if (!m_linker_file_head_addr.IsValid() || |
519 | m_linker_file_head_addr.GetFileAddress() == 0) { |
520 | m_linker_file_list_struct_addr.Clear(); |
521 | return false; |
522 | } |
523 | } |
524 | return true; |
525 | } |
526 | |
527 | // Parse Kmod info in found_list |
528 | bool DynamicLoaderFreeBSDKernel::ParseKmods(Address linker_files_head_addr) { |
529 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
530 | KModImageInfo::collection_type linker_files_list; |
531 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
532 | |
533 | if (!ReadAllKmods(linker_files_head_address: linker_files_head_addr, kmods_list&: linker_files_list)) |
534 | return false; |
535 | LLDB_LOGF( |
536 | log, |
537 | "Kmod-changed breakpoint hit, there are %zu kernel modules currently.\n" , |
538 | linker_files_list.size()); |
539 | |
540 | ModuleList &modules = m_process->GetTarget().GetImages(); |
541 | ModuleList remove_modules; |
542 | ModuleList add_modules; |
543 | |
544 | for (ModuleSP module : modules.Modules()) { |
545 | if (is_kernel(module: module.get())) |
546 | continue; |
547 | if (is_kmod(module: module.get())) |
548 | remove_modules.AppendIfNeeded(new_module: module); |
549 | } |
550 | |
551 | m_process->GetTarget().ModulesDidUnload(module_list&: remove_modules, delete_locations: false); |
552 | |
553 | for (KModImageInfo &image_info : linker_files_list) { |
554 | auto it = m_kld_name_to_uuid.find(x: image_info.GetName()); |
555 | if (it != m_kld_name_to_uuid.end()) |
556 | image_info.SetUUID(it->second); |
557 | bool failed_to_load = false; |
558 | if (!image_info.LoadImageUsingMemoryModule(process: m_process)) { |
559 | image_info.LoadImageUsingFileAddress(process: m_process); |
560 | failed_to_load = true; |
561 | } else { |
562 | m_linker_files_list.push_back(x: image_info); |
563 | m_kld_name_to_uuid[image_info.GetName()] = image_info.GetUUID(); |
564 | } |
565 | |
566 | if (!failed_to_load) |
567 | add_modules.AppendIfNeeded(new_module: image_info.GetModule()); |
568 | } |
569 | m_process->GetTarget().ModulesDidLoad(module_list&: add_modules); |
570 | return true; |
571 | } |
572 | |
573 | // Read all kmod from a given arrays of list |
574 | bool DynamicLoaderFreeBSDKernel::ReadAllKmods( |
575 | Address linker_files_head_addr, |
576 | KModImageInfo::collection_type &kmods_list) { |
577 | |
578 | // Get offset of next member and load address symbol |
579 | static ConstString kld_off_address_symbol_name("kld_off_address" ); |
580 | static ConstString kld_off_next_symbol_name("kld_off_next" ); |
581 | static ConstString kld_off_filename_symbol_name("kld_off_filename" ); |
582 | static ConstString kld_off_pathname_symbol_name("kld_off_pathname" ); |
583 | const Symbol *kld_off_address_symbol = |
584 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
585 | name: kld_off_address_symbol_name, symbol_type: eSymbolTypeData); |
586 | const Symbol *kld_off_next_symbol = |
587 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
588 | name: kld_off_next_symbol_name, symbol_type: eSymbolTypeData); |
589 | const Symbol *kld_off_filename_symbol = |
590 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
591 | name: kld_off_filename_symbol_name, symbol_type: eSymbolTypeData); |
592 | const Symbol *kld_off_pathname_symbol = |
593 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
594 | name: kld_off_pathname_symbol_name, symbol_type: eSymbolTypeData); |
595 | |
596 | if (!kld_off_address_symbol || !kld_off_next_symbol || |
597 | !kld_off_filename_symbol || !kld_off_pathname_symbol) |
598 | return false; |
599 | |
600 | Status error; |
601 | const int32_t kld_off_address = m_process->ReadSignedIntegerFromMemory( |
602 | load_addr: kld_off_address_symbol->GetAddress().GetLoadAddress( |
603 | target: &m_process->GetTarget()), |
604 | byte_size: 4, fail_value: 0, error); |
605 | if (error.Fail()) |
606 | return false; |
607 | const int32_t kld_off_next = m_process->ReadSignedIntegerFromMemory( |
608 | load_addr: kld_off_next_symbol->GetAddress().GetLoadAddress(target: &m_process->GetTarget()), |
609 | byte_size: 4, fail_value: 0, error); |
610 | if (error.Fail()) |
611 | return false; |
612 | const int32_t kld_off_filename = m_process->ReadSignedIntegerFromMemory( |
613 | load_addr: kld_off_filename_symbol->GetAddress().GetLoadAddress( |
614 | target: &m_process->GetTarget()), |
615 | byte_size: 4, fail_value: 0, error); |
616 | if (error.Fail()) |
617 | return false; |
618 | |
619 | const int32_t kld_off_pathname = m_process->ReadSignedIntegerFromMemory( |
620 | load_addr: kld_off_pathname_symbol->GetAddress().GetLoadAddress( |
621 | target: &m_process->GetTarget()), |
622 | byte_size: 4, fail_value: 0, error); |
623 | if (error.Fail()) |
624 | return false; |
625 | |
626 | // Parse KMods |
627 | addr_t kld_load_addr(LLDB_INVALID_ADDRESS); |
628 | char kld_filename[255]; |
629 | char kld_pathname[255]; |
630 | addr_t current_kld = |
631 | linker_files_head_addr.GetLoadAddress(target: &m_process->GetTarget()); |
632 | |
633 | while (current_kld != 0) { |
634 | addr_t kld_filename_addr = |
635 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_filename, error); |
636 | if (error.Fail()) |
637 | return false; |
638 | addr_t kld_pathname_addr = |
639 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_pathname, error); |
640 | if (error.Fail()) |
641 | return false; |
642 | |
643 | m_process->ReadCStringFromMemory(vm_addr: kld_filename_addr, cstr: kld_filename, |
644 | cstr_max_len: sizeof(kld_filename), error); |
645 | if (error.Fail()) |
646 | return false; |
647 | m_process->ReadCStringFromMemory(vm_addr: kld_pathname_addr, cstr: kld_pathname, |
648 | cstr_max_len: sizeof(kld_pathname), error); |
649 | if (error.Fail()) |
650 | return false; |
651 | kld_load_addr = |
652 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_address, error); |
653 | if (error.Fail()) |
654 | return false; |
655 | |
656 | kmods_list.emplace_back(); |
657 | KModImageInfo &kmod_info = kmods_list.back(); |
658 | kmod_info.SetName(kld_filename); |
659 | kmod_info.SetLoadAddress(kld_load_addr); |
660 | kmod_info.SetPath(kld_pathname); |
661 | |
662 | current_kld = |
663 | m_process->ReadPointerFromMemory(vm_addr: current_kld + kld_off_next, error); |
664 | if (kmod_info.GetName() == "kernel" ) |
665 | kmods_list.pop_back(); |
666 | if (error.Fail()) |
667 | return false; |
668 | } |
669 | |
670 | return true; |
671 | } |
672 | |
673 | // Read all kmods |
674 | void DynamicLoaderFreeBSDKernel::ReadAllKmods() { |
675 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
676 | |
677 | if (ReadKmodsListHeader()) { |
678 | if (m_linker_file_head_addr.IsValid()) { |
679 | if (!ParseKmods(linker_files_head_addr: m_linker_file_head_addr)) |
680 | m_linker_files_list.clear(); |
681 | } |
682 | } |
683 | } |
684 | |
685 | // Load all Kernel Modules |
686 | void DynamicLoaderFreeBSDKernel::LoadKernelModules() { |
687 | Log *log = GetLog(mask: LLDBLog::DynamicLoader); |
688 | LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules " |
689 | "Start loading Kernel Module" ); |
690 | |
691 | // Initialize Kernel Image Information at the first time |
692 | if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) { |
693 | ModuleSP module_sp = m_process->GetTarget().GetExecutableModule(); |
694 | if (is_kernel(module: module_sp.get())) { |
695 | m_kernel_image_info.SetModule(module_sp); |
696 | m_kernel_image_info.SetIsKernel(true); |
697 | } |
698 | |
699 | // Set name for kernel |
700 | llvm::StringRef kernel_name("freebsd_kernel" ); |
701 | module_sp = m_kernel_image_info.GetModule(); |
702 | if (module_sp.get() && module_sp->GetObjectFile() && |
703 | !module_sp->GetObjectFile()->GetFileSpec().GetFilename().IsEmpty()) |
704 | kernel_name = module_sp->GetObjectFile() |
705 | ->GetFileSpec() |
706 | .GetFilename() |
707 | .GetStringRef(); |
708 | m_kernel_image_info.SetName(kernel_name.data()); |
709 | |
710 | if (m_kernel_image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS) { |
711 | m_kernel_image_info.SetLoadAddress(m_kernel_load_address); |
712 | } |
713 | |
714 | // Build In memory Module |
715 | if (m_kernel_image_info.GetLoadAddress() != LLDB_INVALID_ADDRESS) { |
716 | // If the kernel is not loaded in the memory, use file to load |
717 | if (!m_kernel_image_info.LoadImageUsingMemoryModule(process: m_process)) |
718 | m_kernel_image_info.LoadImageUsingFileAddress(process: m_process); |
719 | } |
720 | } |
721 | |
722 | LoadOperatingSystemPlugin(flush: false); |
723 | |
724 | if (!m_kernel_image_info.IsLoaded() || !m_kernel_image_info.GetModule()) { |
725 | m_kernel_image_info.Clear(); |
726 | return; |
727 | } |
728 | |
729 | static ConstString modlist_symbol_name("linker_files" ); |
730 | |
731 | const Symbol *symbol = |
732 | m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType( |
733 | name: modlist_symbol_name, symbol_type: lldb::eSymbolTypeData); |
734 | |
735 | if (symbol) { |
736 | m_linker_file_list_struct_addr = symbol->GetAddress(); |
737 | ReadAllKmods(); |
738 | } else { |
739 | LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules " |
740 | "cannot file modlist symbol" ); |
741 | } |
742 | } |
743 | |
744 | // Update symbol when use kldload by setting callback function on kldload |
745 | void DynamicLoaderFreeBSDKernel::SetNotificationBreakPoint() {} |
746 | |
747 | // Hook called when attach to a process |
748 | void DynamicLoaderFreeBSDKernel::DidAttach() { |
749 | PrivateInitialize(process: m_process); |
750 | Update(); |
751 | } |
752 | |
753 | // Hook called after attach to a process |
754 | void DynamicLoaderFreeBSDKernel::DidLaunch() { |
755 | PrivateInitialize(process: m_process); |
756 | Update(); |
757 | } |
758 | |
759 | // Clear all member except kernel address |
760 | void DynamicLoaderFreeBSDKernel::Clear(bool clear_process) { |
761 | std::lock_guard<decltype(m_mutex)> guard(m_mutex); |
762 | if (clear_process) |
763 | m_process = nullptr; |
764 | m_linker_file_head_addr.Clear(); |
765 | m_linker_file_list_struct_addr.Clear(); |
766 | m_kernel_image_info.Clear(); |
767 | m_linker_files_list.clear(); |
768 | } |
769 | |
770 | // Reinitialize class |
771 | void DynamicLoaderFreeBSDKernel::PrivateInitialize(Process *process) { |
772 | Clear(clear_process: true); |
773 | m_process = process; |
774 | } |
775 | |
776 | ThreadPlanSP DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan( |
777 | lldb_private::Thread &thread, bool stop_others) { |
778 | Log *log = GetLog(mask: LLDBLog::Step); |
779 | LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan is " |
780 | "not yet implemented." ); |
781 | return {}; |
782 | } |
783 | |
784 | Status DynamicLoaderFreeBSDKernel::CanLoadImage() { |
785 | return Status::FromErrorString(str: "shared object cannot be loaded into kernel" ); |
786 | } |
787 | |