File: | build/source/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp |
Warning: | line 310, column 7 Value stored to 'found_main_binary_definitively' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- ProcessMachCore.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 <cerrno> |
10 | #include <cstdlib> |
11 | |
12 | #include "llvm/Support/MathExtras.h" |
13 | #include "llvm/Support/Threading.h" |
14 | |
15 | #include "lldb/Core/Debugger.h" |
16 | #include "lldb/Core/Module.h" |
17 | #include "lldb/Core/ModuleSpec.h" |
18 | #include "lldb/Core/PluginManager.h" |
19 | #include "lldb/Core/Section.h" |
20 | #include "lldb/Host/Host.h" |
21 | #include "lldb/Symbol/LocateSymbolFile.h" |
22 | #include "lldb/Symbol/ObjectFile.h" |
23 | #include "lldb/Target/MemoryRegionInfo.h" |
24 | #include "lldb/Target/SectionLoadList.h" |
25 | #include "lldb/Target/Target.h" |
26 | #include "lldb/Target/Thread.h" |
27 | #include "lldb/Utility/DataBuffer.h" |
28 | #include "lldb/Utility/LLDBLog.h" |
29 | #include "lldb/Utility/Log.h" |
30 | #include "lldb/Utility/State.h" |
31 | |
32 | #include "ProcessMachCore.h" |
33 | #include "Plugins/Process/Utility/StopInfoMachException.h" |
34 | #include "ThreadMachCore.h" |
35 | |
36 | // Needed for the plug-in names for the dynamic loaders. |
37 | #include "lldb/Host/SafeMachO.h" |
38 | |
39 | #include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" |
40 | #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" |
41 | #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" |
42 | #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" |
43 | #include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h" |
44 | |
45 | #include <memory> |
46 | #include <mutex> |
47 | |
48 | using namespace lldb; |
49 | using namespace lldb_private; |
50 | |
51 | LLDB_PLUGIN_DEFINE(ProcessMachCore)namespace lldb_private { void lldb_initialize_ProcessMachCore () { ProcessMachCore::Initialize(); } void lldb_terminate_ProcessMachCore () { ProcessMachCore::Terminate(); } } |
52 | |
53 | llvm::StringRef ProcessMachCore::GetPluginDescriptionStatic() { |
54 | return "Mach-O core file debugging plug-in."; |
55 | } |
56 | |
57 | void ProcessMachCore::Terminate() { |
58 | PluginManager::UnregisterPlugin(ProcessMachCore::CreateInstance); |
59 | } |
60 | |
61 | lldb::ProcessSP ProcessMachCore::CreateInstance(lldb::TargetSP target_sp, |
62 | ListenerSP listener_sp, |
63 | const FileSpec *crash_file, |
64 | bool can_connect) { |
65 | lldb::ProcessSP process_sp; |
66 | if (crash_file && !can_connect) { |
67 | const size_t header_size = sizeof(llvm::MachO::mach_header); |
68 | auto data_sp = FileSystem::Instance().CreateDataBuffer( |
69 | crash_file->GetPath(), header_size, 0); |
70 | if (data_sp && data_sp->GetByteSize() == header_size) { |
71 | DataExtractor data(data_sp, lldb::eByteOrderLittle, 4); |
72 | |
73 | lldb::offset_t data_offset = 0; |
74 | llvm::MachO::mach_header mach_header; |
75 | if (ObjectFileMachO::ParseHeader(data, &data_offset, mach_header)) { |
76 | if (mach_header.filetype == llvm::MachO::MH_CORE) |
77 | process_sp = std::make_shared<ProcessMachCore>(target_sp, listener_sp, |
78 | *crash_file); |
79 | } |
80 | } |
81 | } |
82 | return process_sp; |
83 | } |
84 | |
85 | bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp, |
86 | bool plugin_specified_by_name) { |
87 | if (plugin_specified_by_name) |
88 | return true; |
89 | |
90 | // For now we are just making sure the file exists for a given module |
91 | if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { |
92 | // Don't add the Target's architecture to the ModuleSpec - we may be |
93 | // working with a core file that doesn't have the correct cpusubtype in the |
94 | // header but we should still try to use it - |
95 | // ModuleSpecList::FindMatchingModuleSpec enforces a strict arch mach. |
96 | ModuleSpec core_module_spec(m_core_file); |
97 | Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, |
98 | nullptr, nullptr, nullptr)); |
99 | |
100 | if (m_core_module_sp) { |
101 | ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); |
102 | if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile) |
103 | return true; |
104 | } |
105 | } |
106 | return false; |
107 | } |
108 | |
109 | // ProcessMachCore constructor |
110 | ProcessMachCore::ProcessMachCore(lldb::TargetSP target_sp, |
111 | ListenerSP listener_sp, |
112 | const FileSpec &core_file) |
113 | : PostMortemProcess(target_sp, listener_sp), m_core_aranges(), |
114 | m_core_range_infos(), m_core_module_sp(), m_core_file(core_file), |
115 | m_dyld_addr(LLDB_INVALID_ADDRESS(18446744073709551615UL)), |
116 | m_mach_kernel_addr(LLDB_INVALID_ADDRESS(18446744073709551615UL)) {} |
117 | |
118 | // Destructor |
119 | ProcessMachCore::~ProcessMachCore() { |
120 | Clear(); |
121 | // We need to call finalize on the process before destroying ourselves to |
122 | // make sure all of the broadcaster cleanup goes as planned. If we destruct |
123 | // this class, then Process::~Process() might have problems trying to fully |
124 | // destroy the broadcaster. |
125 | Finalize(); |
126 | } |
127 | |
128 | bool ProcessMachCore::CheckAddressForDyldOrKernel(lldb::addr_t addr, |
129 | addr_t &dyld, |
130 | addr_t &kernel) { |
131 | Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process)); |
132 | llvm::MachO::mach_header header; |
133 | Status error; |
134 | dyld = kernel = LLDB_INVALID_ADDRESS(18446744073709551615UL); |
135 | if (DoReadMemory(addr, &header, sizeof(header), error) != sizeof(header)) |
136 | return false; |
137 | if (header.magic == llvm::MachO::MH_CIGAM || |
138 | header.magic == llvm::MachO::MH_CIGAM_64) { |
139 | header.magic = llvm::byteswap<uint32_t>(header.magic); |
140 | header.cputype = llvm::byteswap<uint32_t>(header.cputype); |
141 | header.cpusubtype = llvm::byteswap<uint32_t>(header.cpusubtype); |
142 | header.filetype = llvm::byteswap<uint32_t>(header.filetype); |
143 | header.ncmds = llvm::byteswap<uint32_t>(header.ncmds); |
144 | header.sizeofcmds = llvm::byteswap<uint32_t>(header.sizeofcmds); |
145 | header.flags = llvm::byteswap<uint32_t>(header.flags); |
146 | } |
147 | |
148 | if (header.magic == llvm::MachO::MH_MAGIC || |
149 | header.magic == llvm::MachO::MH_MAGIC_64) { |
150 | // Check MH_EXECUTABLE to see if we can find the mach image that contains |
151 | // the shared library list. The dynamic loader (dyld) is what contains the |
152 | // list for user applications, and the mach kernel contains a global that |
153 | // has the list of kexts to load |
154 | switch (header.filetype) { |
155 | case llvm::MachO::MH_DYLINKER: |
156 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a user " "process dyld binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0) |
157 | "ProcessMachCore::%s found a user "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a user " "process dyld binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0) |
158 | "process dyld binary image at 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a user " "process dyld binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0) |
159 | __FUNCTION__, addr)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a user " "process dyld binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0); |
160 | dyld = addr; |
161 | return true; |
162 | |
163 | case llvm::MachO::MH_EXECUTE: |
164 | // Check MH_EXECUTABLE file types to see if the dynamic link object flag |
165 | // is NOT set. If it isn't, then we have a mach_kernel. |
166 | if ((header.flags & llvm::MachO::MH_DYLDLINK) == 0) { |
167 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a mach " "kernel binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0) |
168 | "ProcessMachCore::%s found a mach "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a mach " "kernel binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0) |
169 | "kernel binary image at 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a mach " "kernel binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0) |
170 | __FUNCTION__, addr)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s found a mach " "kernel binary image at 0x%" "l" "x", __FUNCTION__, addr); } while (0); |
171 | // Address of the mach kernel "struct mach_header" in the core file. |
172 | kernel = addr; |
173 | return true; |
174 | } |
175 | break; |
176 | } |
177 | } |
178 | return false; |
179 | } |
180 | |
181 | void ProcessMachCore::CreateMemoryRegions() { |
182 | ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); |
183 | SectionList *section_list = core_objfile->GetSectionList(); |
184 | const uint32_t num_sections = section_list->GetNumSections(0); |
185 | |
186 | bool ranges_are_sorted = true; |
187 | addr_t vm_addr = 0; |
188 | for (uint32_t i = 0; i < num_sections; ++i) { |
189 | Section *section = section_list->GetSectionAtIndex(i).get(); |
190 | if (section && section->GetFileSize() > 0) { |
191 | lldb::addr_t section_vm_addr = section->GetFileAddress(); |
192 | FileRange file_range(section->GetFileOffset(), section->GetFileSize()); |
193 | VMRangeToFileOffset::Entry range_entry( |
194 | section_vm_addr, section->GetByteSize(), file_range); |
195 | |
196 | if (vm_addr > section_vm_addr) |
197 | ranges_are_sorted = false; |
198 | vm_addr = section->GetFileAddress(); |
199 | VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); |
200 | |
201 | if (last_entry && |
202 | last_entry->GetRangeEnd() == range_entry.GetRangeBase() && |
203 | last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { |
204 | last_entry->SetRangeEnd(range_entry.GetRangeEnd()); |
205 | last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd()); |
206 | } else { |
207 | m_core_aranges.Append(range_entry); |
208 | } |
209 | // Some core files don't fill in the permissions correctly. If that is |
210 | // the case assume read + execute so clients don't think the memory is |
211 | // not readable, or executable. The memory isn't writable since this |
212 | // plug-in doesn't implement DoWriteMemory. |
213 | uint32_t permissions = section->GetPermissions(); |
214 | if (permissions == 0) |
215 | permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; |
216 | m_core_range_infos.Append(VMRangeToPermissions::Entry( |
217 | section_vm_addr, section->GetByteSize(), permissions)); |
218 | } |
219 | } |
220 | if (!ranges_are_sorted) { |
221 | m_core_aranges.Sort(); |
222 | m_core_range_infos.Sort(); |
223 | } |
224 | } |
225 | |
226 | void ProcessMachCore::LoadBinariesViaMetadata() { |
227 | Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process)); |
228 | ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); |
229 | bool found_main_binary_definitively = false; |
230 | |
231 | addr_t objfile_binary_value; |
232 | bool objfile_binary_value_is_offset; |
233 | UUID objfile_binary_uuid; |
234 | ObjectFile::BinaryType type; |
235 | |
236 | if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_value, |
237 | objfile_binary_value_is_offset, |
238 | objfile_binary_uuid, type)) { |
239 | if (log) { |
240 | log->Printf("ProcessMachCore::LoadBinariesViaMetadata: using binary hint " |
241 | "from 'main bin spec' " |
242 | "LC_NOTE with UUID %s value 0x%" PRIx64"l" "x" |
243 | " value is offset %d and type %d", |
244 | objfile_binary_uuid.GetAsString().c_str(), |
245 | objfile_binary_value, objfile_binary_value_is_offset, type); |
246 | } |
247 | |
248 | // If this is the xnu kernel, don't load it now. Note the correct |
249 | // DynamicLoader plugin to use, and the address of the kernel, and |
250 | // let the DynamicLoader handle the finding & loading of the binary. |
251 | if (type == ObjectFile::eBinaryTypeKernel) { |
252 | m_mach_kernel_addr = objfile_binary_value; |
253 | m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); |
254 | found_main_binary_definitively = true; |
255 | } else { |
256 | const bool force_symbol_search = true; |
257 | const bool notify = true; |
258 | if (DynamicLoader::LoadBinaryWithUUIDAndAddress( |
259 | this, llvm::StringRef(), objfile_binary_uuid, |
260 | objfile_binary_value, objfile_binary_value_is_offset, |
261 | force_symbol_search, notify)) { |
262 | found_main_binary_definitively = true; |
263 | m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic(); |
264 | } |
265 | if (type == ObjectFile::eBinaryTypeUser) { |
266 | m_dyld_addr = objfile_binary_value; |
267 | m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); |
268 | } |
269 | } |
270 | } |
271 | |
272 | // This checks for the presence of an LC_IDENT string in a core file; |
273 | // LC_IDENT is very obsolete and should not be used in new code, but if the |
274 | // load command is present, let's use the contents. |
275 | UUID ident_uuid; |
276 | addr_t ident_binary_addr = LLDB_INVALID_ADDRESS(18446744073709551615UL); |
277 | if (!found_main_binary_definitively) { |
278 | std::string corefile_identifier = core_objfile->GetIdentifierString(); |
279 | |
280 | // Search for UUID= and stext= strings in the identifier str. |
281 | if (corefile_identifier.find("UUID=") != std::string::npos) { |
282 | size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); |
283 | std::string uuid_str = corefile_identifier.substr(p, 36); |
284 | ident_uuid.SetFromStringRef(uuid_str); |
285 | if (log) |
286 | log->Printf("Got a UUID from LC_IDENT/kern ver str LC_NOTE: %s", |
287 | ident_uuid.GetAsString().c_str()); |
288 | } |
289 | if (corefile_identifier.find("stext=") != std::string::npos) { |
290 | size_t p = corefile_identifier.find("stext=") + strlen("stext="); |
291 | if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') { |
292 | ident_binary_addr = |
293 | ::strtoul(corefile_identifier.c_str() + p, nullptr, 16); |
294 | if (log) |
295 | log->Printf("Got a load address from LC_IDENT/kern ver str " |
296 | "LC_NOTE: 0x%" PRIx64"l" "x", |
297 | ident_binary_addr); |
298 | } |
299 | } |
300 | |
301 | // Search for a "Darwin Kernel" str indicating kernel; else treat as |
302 | // standalone |
303 | if (corefile_identifier.find("Darwin Kernel") != std::string::npos && |
304 | ident_uuid.IsValid() && ident_binary_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
305 | if (log) |
306 | log->Printf( |
307 | "ProcessMachCore::LoadBinariesViaMetadata: Found kernel binary via " |
308 | "LC_IDENT/kern ver str LC_NOTE"); |
309 | m_mach_kernel_addr = ident_binary_addr; |
310 | found_main_binary_definitively = true; |
Value stored to 'found_main_binary_definitively' is never read | |
311 | } else if (ident_uuid.IsValid()) { |
312 | // We have no address specified, only a UUID. Load it at the file |
313 | // address. |
314 | const bool value_is_offset = false; |
315 | const bool force_symbol_search = true; |
316 | const bool notify = true; |
317 | if (DynamicLoader::LoadBinaryWithUUIDAndAddress( |
318 | this, llvm::StringRef(), ident_uuid, ident_binary_addr, |
319 | value_is_offset, force_symbol_search, notify)) { |
320 | found_main_binary_definitively = true; |
321 | m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic(); |
322 | } |
323 | } |
324 | } |
325 | |
326 | // Finally, load any binaries noted by "load binary" LC_NOTEs in the |
327 | // corefile |
328 | core_objfile->LoadCoreFileImages(*this); |
329 | |
330 | // LoadCoreFileImges may have set the dynamic loader, e.g. in |
331 | // PlatformDarwinKernel::LoadPlatformBinaryAndSetup(). |
332 | // If we now have a dynamic loader, save its name so we don't |
333 | // un-set it later. |
334 | if (m_dyld_up) |
335 | m_dyld_plugin_name = GetDynamicLoader()->GetPluginName(); |
336 | } |
337 | |
338 | void ProcessMachCore::LoadBinariesViaExhaustiveSearch() { |
339 | Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process)); |
340 | |
341 | // Search the pages of the corefile for dyld or mach kernel |
342 | // binaries. There may be multiple things that look like a kernel |
343 | // in the corefile; disambiguating to the correct one can be difficult. |
344 | |
345 | std::vector<addr_t> dylds_found; |
346 | std::vector<addr_t> kernels_found; |
347 | |
348 | const size_t num_core_aranges = m_core_aranges.GetSize(); |
349 | for (size_t i = 0; i < num_core_aranges; ++i) { |
350 | const VMRangeToFileOffset::Entry *entry = m_core_aranges.GetEntryAtIndex(i); |
351 | lldb::addr_t section_vm_addr_start = entry->GetRangeBase(); |
352 | lldb::addr_t section_vm_addr_end = entry->GetRangeEnd(); |
353 | for (lldb::addr_t section_vm_addr = section_vm_addr_start; |
354 | section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) { |
355 | addr_t dyld, kernel; |
356 | if (CheckAddressForDyldOrKernel(section_vm_addr, dyld, kernel)) { |
357 | if (dyld != LLDB_INVALID_ADDRESS(18446744073709551615UL)) |
358 | dylds_found.push_back(dyld); |
359 | if (kernel != LLDB_INVALID_ADDRESS(18446744073709551615UL)) |
360 | kernels_found.push_back(kernel); |
361 | } |
362 | } |
363 | } |
364 | |
365 | // If we found more than one dyld mach-o header in the corefile, |
366 | // pick the first one. |
367 | if (dylds_found.size() > 0) |
368 | m_dyld_addr = dylds_found[0]; |
369 | if (kernels_found.size() > 0) |
370 | m_mach_kernel_addr = kernels_found[0]; |
371 | |
372 | // Zero or one kernels found, we're done. |
373 | if (kernels_found.size() < 2) |
374 | return; |
375 | |
376 | // In the case of multiple kernel images found in the core file via |
377 | // exhaustive search, we may not pick the correct one. See if the |
378 | // DynamicLoaderDarwinKernel's search heuristics might identify the correct |
379 | // one. |
380 | |
381 | // SearchForDarwinKernel will call this class' GetImageInfoAddress method |
382 | // which will give it the addresses we already have. |
383 | // Save those aside and set |
384 | // m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so |
385 | // DynamicLoaderDarwinKernel does a real search for the kernel using its |
386 | // own heuristics. |
387 | |
388 | addr_t saved_mach_kernel_addr = m_mach_kernel_addr; |
389 | addr_t saved_user_dyld_addr = m_dyld_addr; |
390 | m_mach_kernel_addr = LLDB_INVALID_ADDRESS(18446744073709551615UL); |
391 | m_dyld_addr = LLDB_INVALID_ADDRESS(18446744073709551615UL); |
392 | |
393 | addr_t better_kernel_address = |
394 | DynamicLoaderDarwinKernel::SearchForDarwinKernel(this); |
395 | |
396 | m_mach_kernel_addr = saved_mach_kernel_addr; |
397 | m_dyld_addr = saved_user_dyld_addr; |
398 | |
399 | if (better_kernel_address != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
400 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using " "the kernel address " "from DynamicLoaderDarwinKernel", __FUNCTION__); } while (0) |
401 | "ProcessMachCore::%s: Using "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using " "the kernel address " "from DynamicLoaderDarwinKernel", __FUNCTION__); } while (0) |
402 | "the kernel address "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using " "the kernel address " "from DynamicLoaderDarwinKernel", __FUNCTION__); } while (0) |
403 | "from DynamicLoaderDarwinKernel",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using " "the kernel address " "from DynamicLoaderDarwinKernel", __FUNCTION__); } while (0) |
404 | __FUNCTION__)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using " "the kernel address " "from DynamicLoaderDarwinKernel", __FUNCTION__); } while (0); |
405 | m_mach_kernel_addr = better_kernel_address; |
406 | } |
407 | } |
408 | |
409 | void ProcessMachCore::LoadBinariesAndSetDYLD() { |
410 | Log *log(GetLog(LLDBLog::DynamicLoader | LLDBLog::Process)); |
411 | |
412 | LoadBinariesViaMetadata(); |
413 | if (m_dyld_plugin_name.empty()) |
414 | LoadBinariesViaExhaustiveSearch(); |
415 | |
416 | if (m_dyld_plugin_name.empty()) { |
417 | // If we found both a user-process dyld and a kernel binary, we need to |
418 | // decide which to prefer. |
419 | if (GetCorefilePreference() == eKernelCorefile) { |
420 | if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
421 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
422 | "ProcessMachCore::%s: Using kernel "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
423 | "corefile image "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
424 | "at 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
425 | __FUNCTION__, m_mach_kernel_addr)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0); |
426 | m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); |
427 | } else if (m_dyld_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
428 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0) |
429 | "ProcessMachCore::%s: Using user process dyld "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0) |
430 | "image at 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0) |
431 | __FUNCTION__, m_dyld_addr)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0); |
432 | m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); |
433 | } |
434 | } else { |
435 | if (m_dyld_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
436 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0) |
437 | "ProcessMachCore::%s: Using user process dyld "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0) |
438 | "image at 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0) |
439 | __FUNCTION__, m_dyld_addr)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using user process dyld " "image at 0x%" "l" "x", __FUNCTION__, m_dyld_addr); } while ( 0); |
440 | m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); |
441 | } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
442 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
443 | "ProcessMachCore::%s: Using kernel "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
444 | "corefile image "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
445 | "at 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0) |
446 | __FUNCTION__, m_mach_kernel_addr)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("ProcessMachCore::%s: Using kernel " "corefile image " "at 0x%" "l" "x", __FUNCTION__, m_mach_kernel_addr ); } while (0); |
447 | m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); |
448 | } |
449 | } |
450 | } |
451 | } |
452 | |
453 | void ProcessMachCore::CleanupMemoryRegionPermissions() { |
454 | if (m_dyld_plugin_name != DynamicLoaderMacOSXDYLD::GetPluginNameStatic()) { |
455 | // For non-user process core files, the permissions on the core file |
456 | // segments are usually meaningless, they may be just "read", because we're |
457 | // dealing with kernel coredumps or early startup coredumps and the dumper |
458 | // is grabbing pages of memory without knowing what they are. If they |
459 | // aren't marked as "executable", that can break the unwinder which will |
460 | // check a pc value to see if it is in an executable segment and stop the |
461 | // backtrace early if it is not ("executable" and "unknown" would both be |
462 | // fine, but "not executable" will break the unwinder). |
463 | size_t core_range_infos_size = m_core_range_infos.GetSize(); |
464 | for (size_t i = 0; i < core_range_infos_size; i++) { |
465 | VMRangeToPermissions::Entry *ent = |
466 | m_core_range_infos.GetMutableEntryAtIndex(i); |
467 | ent->data = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; |
468 | } |
469 | } |
470 | } |
471 | |
472 | // Process Control |
473 | Status ProcessMachCore::DoLoadCore() { |
474 | Status error; |
475 | if (!m_core_module_sp) { |
476 | error.SetErrorString("invalid core module"); |
477 | return error; |
478 | } |
479 | |
480 | ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); |
481 | if (core_objfile == nullptr) { |
482 | error.SetErrorString("invalid core object file"); |
483 | return error; |
484 | } |
485 | |
486 | SetCanJIT(false); |
487 | |
488 | // The corefile's architecture is our best starting point. |
489 | ArchSpec arch(m_core_module_sp->GetArchitecture()); |
490 | if (arch.IsValid()) |
491 | GetTarget().SetArchitecture(arch); |
492 | |
493 | CreateMemoryRegions(); |
494 | |
495 | LoadBinariesAndSetDYLD(); |
496 | |
497 | CleanupMemoryRegionPermissions(); |
498 | |
499 | addr_t address_mask = core_objfile->GetAddressMask(); |
500 | if (address_mask != 0) { |
501 | SetCodeAddressMask(address_mask); |
502 | SetDataAddressMask(address_mask); |
503 | } |
504 | return error; |
505 | } |
506 | |
507 | lldb_private::DynamicLoader *ProcessMachCore::GetDynamicLoader() { |
508 | if (m_dyld_up.get() == nullptr) |
509 | m_dyld_up.reset(DynamicLoader::FindPlugin(this, m_dyld_plugin_name)); |
510 | return m_dyld_up.get(); |
511 | } |
512 | |
513 | bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list, |
514 | ThreadList &new_thread_list) { |
515 | if (old_thread_list.GetSize(false) == 0) { |
516 | // Make up the thread the first time this is called so we can setup our one |
517 | // and only core thread state. |
518 | ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); |
519 | |
520 | if (core_objfile) { |
521 | const uint32_t num_threads = core_objfile->GetNumThreadContexts(); |
522 | for (lldb::tid_t tid = 0; tid < num_threads; ++tid) { |
523 | ThreadSP thread_sp(new ThreadMachCore(*this, tid)); |
524 | new_thread_list.AddThread(thread_sp); |
525 | } |
526 | } |
527 | } else { |
528 | const uint32_t num_threads = old_thread_list.GetSize(false); |
529 | for (uint32_t i = 0; i < num_threads; ++i) |
530 | new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false)); |
531 | } |
532 | return new_thread_list.GetSize(false) > 0; |
533 | } |
534 | |
535 | void ProcessMachCore::RefreshStateAfterStop() { |
536 | // Let all threads recover from stopping and do any clean up based on the |
537 | // previous thread state (if any). |
538 | m_thread_list.RefreshStateAfterStop(); |
539 | // SetThreadStopInfo (m_last_stop_packet); |
540 | } |
541 | |
542 | Status ProcessMachCore::DoDestroy() { return Status(); } |
543 | |
544 | // Process Queries |
545 | |
546 | bool ProcessMachCore::IsAlive() { return true; } |
547 | |
548 | bool ProcessMachCore::WarnBeforeDetach() const { return false; } |
549 | |
550 | // Process Memory |
551 | size_t ProcessMachCore::ReadMemory(addr_t addr, void *buf, size_t size, |
552 | Status &error) { |
553 | // Don't allow the caching that lldb_private::Process::ReadMemory does since |
554 | // in core files we have it all cached our our core file anyway. |
555 | return DoReadMemory(addr, buf, size, error); |
556 | } |
557 | |
558 | size_t ProcessMachCore::DoReadMemory(addr_t addr, void *buf, size_t size, |
559 | Status &error) { |
560 | ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); |
561 | size_t bytes_read = 0; |
562 | |
563 | if (core_objfile) { |
564 | // Segments are not always contiguous in mach-o core files. We have core |
565 | // files that have segments like: |
566 | // Address Size File off File size |
567 | // ---------- ---------- ---------- ---------- |
568 | // LC_SEGMENT 0x000f6000 0x00001000 0x1d509ee8 0x00001000 --- --- 0 |
569 | // 0x00000000 __TEXT LC_SEGMENT 0x0f600000 0x00100000 0x1d50aee8 0x00100000 |
570 | // --- --- 0 0x00000000 __TEXT LC_SEGMENT 0x000f7000 0x00001000 |
571 | // 0x1d60aee8 0x00001000 --- --- 0 0x00000000 __TEXT |
572 | // |
573 | // Any if the user executes the following command: |
574 | // |
575 | // (lldb) mem read 0xf6ff0 |
576 | // |
577 | // We would attempt to read 32 bytes from 0xf6ff0 but would only get 16 |
578 | // unless we loop through consecutive memory ranges that are contiguous in |
579 | // the address space, but not in the file data. |
580 | while (bytes_read < size) { |
581 | const addr_t curr_addr = addr + bytes_read; |
582 | const VMRangeToFileOffset::Entry *core_memory_entry = |
583 | m_core_aranges.FindEntryThatContains(curr_addr); |
584 | |
585 | if (core_memory_entry) { |
586 | const addr_t offset = curr_addr - core_memory_entry->GetRangeBase(); |
587 | const addr_t bytes_left = core_memory_entry->GetRangeEnd() - curr_addr; |
588 | const size_t bytes_to_read = |
589 | std::min(size - bytes_read, (size_t)bytes_left); |
590 | const size_t curr_bytes_read = core_objfile->CopyData( |
591 | core_memory_entry->data.GetRangeBase() + offset, bytes_to_read, |
592 | (char *)buf + bytes_read); |
593 | if (curr_bytes_read == 0) |
594 | break; |
595 | bytes_read += curr_bytes_read; |
596 | } else { |
597 | // Only set the error if we didn't read any bytes |
598 | if (bytes_read == 0) |
599 | error.SetErrorStringWithFormat( |
600 | "core file does not contain 0x%" PRIx64"l" "x", curr_addr); |
601 | break; |
602 | } |
603 | } |
604 | } |
605 | |
606 | return bytes_read; |
607 | } |
608 | |
609 | Status ProcessMachCore::DoGetMemoryRegionInfo(addr_t load_addr, |
610 | MemoryRegionInfo ®ion_info) { |
611 | region_info.Clear(); |
612 | const VMRangeToPermissions::Entry *permission_entry = |
613 | m_core_range_infos.FindEntryThatContainsOrFollows(load_addr); |
614 | if (permission_entry) { |
615 | if (permission_entry->Contains(load_addr)) { |
616 | region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase()); |
617 | region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd()); |
618 | const Flags permissions(permission_entry->data); |
619 | region_info.SetReadable(permissions.Test(ePermissionsReadable) |
620 | ? MemoryRegionInfo::eYes |
621 | : MemoryRegionInfo::eNo); |
622 | region_info.SetWritable(permissions.Test(ePermissionsWritable) |
623 | ? MemoryRegionInfo::eYes |
624 | : MemoryRegionInfo::eNo); |
625 | region_info.SetExecutable(permissions.Test(ePermissionsExecutable) |
626 | ? MemoryRegionInfo::eYes |
627 | : MemoryRegionInfo::eNo); |
628 | region_info.SetMapped(MemoryRegionInfo::eYes); |
629 | } else if (load_addr < permission_entry->GetRangeBase()) { |
630 | region_info.GetRange().SetRangeBase(load_addr); |
631 | region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase()); |
632 | region_info.SetReadable(MemoryRegionInfo::eNo); |
633 | region_info.SetWritable(MemoryRegionInfo::eNo); |
634 | region_info.SetExecutable(MemoryRegionInfo::eNo); |
635 | region_info.SetMapped(MemoryRegionInfo::eNo); |
636 | } |
637 | return Status(); |
638 | } |
639 | |
640 | region_info.GetRange().SetRangeBase(load_addr); |
641 | region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS(18446744073709551615UL)); |
642 | region_info.SetReadable(MemoryRegionInfo::eNo); |
643 | region_info.SetWritable(MemoryRegionInfo::eNo); |
644 | region_info.SetExecutable(MemoryRegionInfo::eNo); |
645 | region_info.SetMapped(MemoryRegionInfo::eNo); |
646 | return Status(); |
647 | } |
648 | |
649 | void ProcessMachCore::Clear() { m_thread_list.Clear(); } |
650 | |
651 | void ProcessMachCore::Initialize() { |
652 | static llvm::once_flag g_once_flag; |
653 | |
654 | llvm::call_once(g_once_flag, []() { |
655 | PluginManager::RegisterPlugin(GetPluginNameStatic(), |
656 | GetPluginDescriptionStatic(), CreateInstance); |
657 | }); |
658 | } |
659 | |
660 | addr_t ProcessMachCore::GetImageInfoAddress() { |
661 | // If we found both a user-process dyld and a kernel binary, we need to |
662 | // decide which to prefer. |
663 | if (GetCorefilePreference() == eKernelCorefile) { |
664 | if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
665 | return m_mach_kernel_addr; |
666 | } |
667 | return m_dyld_addr; |
668 | } else { |
669 | if (m_dyld_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) { |
670 | return m_dyld_addr; |
671 | } |
672 | return m_mach_kernel_addr; |
673 | } |
674 | } |
675 | |
676 | lldb_private::ObjectFile *ProcessMachCore::GetCoreObjectFile() { |
677 | return m_core_module_sp->GetObjectFile(); |
678 | } |