LLDB mainline
LocateSymbolFileMacOSX.cpp
Go to the documentation of this file.
1//===-- LocateSymbolFileMacOSX.cpp ----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include <dirent.h>
12#include <dlfcn.h>
13#include <pwd.h>
14
15#include <CoreFoundation/CoreFoundation.h>
16
21#include "lldb/Core/Module.h"
24#include "lldb/Host/Host.h"
25#include "lldb/Host/HostInfo.h"
30#include "lldb/Utility/Endian.h"
32#include "lldb/Utility/Log.h"
34#include "lldb/Utility/Timer.h"
35#include "lldb/Utility/UUID.h"
36#include "mach/machine.h"
37
38#include "llvm/ADT/ScopeExit.h"
39#include "llvm/Support/FileSystem.h"
40
41using namespace lldb;
42using namespace lldb_private;
43
45 CFUUIDRef uuid, CFURLRef exec_url) = nullptr;
46static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) =
47 nullptr;
48
50 ModuleSpec &return_module_spec) {
51 Log *log = GetLog(LLDBLog::Host);
52 if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
53 LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled.");
54 return 0;
55 }
56
57 return_module_spec = module_spec;
58 return_module_spec.GetFileSpec().Clear();
59 return_module_spec.GetSymbolFileSpec().Clear();
60
61 const UUID *uuid = module_spec.GetUUIDPtr();
62 const ArchSpec *arch = module_spec.GetArchitecturePtr();
63
64 int items_found = 0;
65
66 if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
68 void *handle = dlopen(
69 "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols",
70 RTLD_LAZY | RTLD_LOCAL);
71 if (handle) {
73 (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle,
74 "DBGCopyFullDSYMURLForUUID");
75 g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym(
76 handle, "DBGCopyDSYMPropertyLists");
77 }
78 }
79
80 if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
82 return items_found;
83 }
84
85 if (uuid && uuid->IsValid()) {
86 // Try and locate the dSYM file using DebugSymbols first
87 llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
88 if (module_uuid.size() == 16) {
89 CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
90 NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
91 module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
92 module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
93 module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
94
95 if (module_uuid_ref.get()) {
96 CFCReleaser<CFURLRef> exec_url;
97 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
98 if (exec_fspec) {
99 char exec_cf_path[PATH_MAX];
100 if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
101 exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
102 NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
103 FALSE));
104 }
105
107 module_uuid_ref.get(), exec_url.get()));
108 char path[PATH_MAX];
109
110 if (dsym_url.get()) {
111 if (::CFURLGetFileSystemRepresentation(
112 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
113 LLDB_LOGF(log,
114 "DebugSymbols framework returned dSYM path of %s for "
115 "UUID %s -- looking for the dSYM",
116 path, uuid->GetAsString().c_str());
117 FileSpec dsym_filespec(path);
118 if (path[0] == '~')
119 FileSystem::Instance().Resolve(dsym_filespec);
120
121 if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
122 dsym_filespec =
123 Symbols::FindSymbolFileInBundle(dsym_filespec, uuid, arch);
124 ++items_found;
125 } else {
126 ++items_found;
127 }
128 return_module_spec.GetSymbolFileSpec() = dsym_filespec;
129 }
130
131 bool success = false;
132 if (log) {
133 if (::CFURLGetFileSystemRepresentation(
134 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
135 LLDB_LOGF(log,
136 "DebugSymbols framework returned dSYM path of %s for "
137 "UUID %s -- looking for an exec file",
138 path, uuid->GetAsString().c_str());
139 }
140 }
141
144 CFDictionaryRef uuid_dict = NULL;
145 if (dict.get()) {
146 CFCString uuid_cfstr(uuid->GetAsString().c_str());
147 uuid_dict = static_cast<CFDictionaryRef>(
148 ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
149 }
150
151 // Check to see if we have the file on the local filesystem.
152 if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
153 ModuleSpec exe_spec;
154 exe_spec.GetFileSpec() = module_spec.GetFileSpec();
155 exe_spec.GetUUID() = module_spec.GetUUID();
156 ModuleSP module_sp;
157 module_sp.reset(new Module(exe_spec));
158 if (module_sp && module_sp->GetObjectFile() &&
159 module_sp->MatchesModuleSpec(exe_spec)) {
160 success = true;
161 return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
162 LLDB_LOGF(log, "using original binary filepath %s for UUID %s",
163 module_spec.GetFileSpec().GetPath().c_str(),
164 uuid->GetAsString().c_str());
165 ++items_found;
166 }
167 }
168
169 // Check if the requested image is in our shared cache.
170 if (!success) {
171 SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo(
172 module_spec.GetFileSpec().GetPath());
173
174 // If we found it and it has the correct UUID, let's proceed with
175 // creating a module from the memory contents.
176 if (image_info.uuid && (!module_spec.GetUUID() ||
177 module_spec.GetUUID() == image_info.uuid)) {
178 success = true;
179 return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
180 LLDB_LOGF(log,
181 "using binary from shared cache for filepath %s for "
182 "UUID %s",
183 module_spec.GetFileSpec().GetPath().c_str(),
184 uuid->GetAsString().c_str());
185 ++items_found;
186 }
187 }
188
189 // Use the DBGSymbolRichExecutable filepath if present
190 if (!success && uuid_dict) {
191 CFStringRef exec_cf_path =
192 static_cast<CFStringRef>(::CFDictionaryGetValue(
193 uuid_dict, CFSTR("DBGSymbolRichExecutable")));
194 if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
195 exec_cf_path, path, sizeof(path))) {
196 LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s",
197 path, uuid->GetAsString().c_str());
198 ++items_found;
199 FileSpec exec_filespec(path);
200 if (path[0] == '~')
201 FileSystem::Instance().Resolve(exec_filespec);
202 if (FileSystem::Instance().Exists(exec_filespec)) {
203 success = true;
204 return_module_spec.GetFileSpec() = exec_filespec;
205 }
206 }
207 }
208
209 // Look next to the dSYM for the binary file.
210 if (!success) {
211 if (::CFURLGetFileSystemRepresentation(
212 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
213 char *dsym_extension_pos = ::strstr(path, ".dSYM");
214 if (dsym_extension_pos) {
215 *dsym_extension_pos = '\0';
216 LLDB_LOGF(log,
217 "Looking for executable binary next to dSYM "
218 "bundle with name with name %s",
219 path);
220 FileSpec file_spec(path);
221 FileSystem::Instance().Resolve(file_spec);
222 ModuleSpecList module_specs;
223 ModuleSpec matched_module_spec;
224 using namespace llvm::sys::fs;
225 switch (get_file_type(file_spec.GetPath())) {
226
227 case file_type::directory_file: // Bundle directory?
228 {
229 CFCBundle bundle(path);
230 CFCReleaser<CFURLRef> bundle_exe_url(
231 bundle.CopyExecutableURL());
232 if (bundle_exe_url.get()) {
233 if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
234 true, (UInt8 *)path,
235 sizeof(path) - 1)) {
236 FileSpec bundle_exe_file_spec(path);
237 FileSystem::Instance().Resolve(bundle_exe_file_spec);
239 bundle_exe_file_spec, 0, 0, module_specs) &&
240 module_specs.FindMatchingModuleSpec(
241 module_spec, matched_module_spec))
242
243 {
244 ++items_found;
245 return_module_spec.GetFileSpec() = bundle_exe_file_spec;
246 LLDB_LOGF(log,
247 "Executable binary %s next to dSYM is "
248 "compatible; using",
249 path);
250 }
251 }
252 }
253 } break;
254
255 case file_type::fifo_file: // Forget pipes
256 case file_type::socket_file: // We can't process socket files
257 case file_type::file_not_found: // File doesn't exist...
258 case file_type::status_error:
259 break;
260
261 case file_type::type_unknown:
262 case file_type::regular_file:
263 case file_type::symlink_file:
264 case file_type::block_file:
265 case file_type::character_file:
266 if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0,
267 module_specs) &&
268 module_specs.FindMatchingModuleSpec(module_spec,
269 matched_module_spec))
270
271 {
272 ++items_found;
273 return_module_spec.GetFileSpec() = file_spec;
274 LLDB_LOGF(log,
275 "Executable binary %s next to dSYM is "
276 "compatible; using",
277 path);
278 }
279 break;
280 }
281 }
282 }
283 }
284 }
285 }
286 }
287 }
288
289 return items_found;
290}
291
292FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
293 const lldb_private::UUID *uuid,
294 const ArchSpec *arch) {
295 std::string dsym_bundle_path = dsym_bundle_fspec.GetPath();
296 llvm::SmallString<128> buffer(dsym_bundle_path);
297 llvm::sys::path::append(buffer, "Contents", "Resources", "DWARF");
298
299 std::error_code EC;
300 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs =
302 llvm::vfs::recursive_directory_iterator Iter(*vfs, buffer.str(), EC);
303 llvm::vfs::recursive_directory_iterator End;
304 for (; Iter != End && !EC; Iter.increment(EC)) {
305 llvm::ErrorOr<llvm::vfs::Status> Status = vfs->status(Iter->path());
306 if (Status->isDirectory())
307 continue;
308
309 FileSpec dsym_fspec(Iter->path());
310 ModuleSpecList module_specs;
311 if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) {
312 ModuleSpec spec;
313 for (size_t i = 0; i < module_specs.GetSize(); ++i) {
314 bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
315 assert(got_spec); // The call has side-effects so can't be inlined.
317 if ((uuid == nullptr ||
318 (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
319 (arch == nullptr ||
320 (spec.GetArchitecturePtr() &&
321 spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
322 return dsym_fspec;
323 }
324 }
325 }
326 }
327
328 return {};
329}
330
331static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
332 ModuleSpec &module_spec,
333 Status &error,
334 const std::string &command) {
335 Log *log = GetLog(LLDBLog::Host);
336 bool success = false;
337 if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
338 std::string str;
339 CFStringRef cf_str;
340 CFDictionaryRef cf_dict;
341
342 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
343 CFSTR("DBGError"));
344 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
345 if (CFCString::FileSystemRepresentation(cf_str, str)) {
346 std::string errorstr = command;
347 errorstr += ":\n";
348 errorstr += str;
349 error.SetErrorString(errorstr);
350 }
351 }
352
353 cf_str = (CFStringRef)CFDictionaryGetValue(
354 (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
355 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
356 if (CFCString::FileSystemRepresentation(cf_str, str)) {
357 module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native);
359 LLDB_LOGF(log,
360 "From dsymForUUID plist: Symbol rich executable is at '%s'",
361 str.c_str());
362 }
363 }
364
365 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
366 CFSTR("DBGDSYMPath"));
367 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
368 if (CFCString::FileSystemRepresentation(cf_str, str)) {
369 module_spec.GetSymbolFileSpec().SetFile(str.c_str(),
370 FileSpec::Style::native);
372 success = true;
373 LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'", str.c_str());
374 }
375 }
376
377 std::string DBGBuildSourcePath;
378 std::string DBGSourcePath;
379
380 // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
381 // If DBGVersion 2, strip last two components of path remappings from
382 // entries to fix an issue with a specific set of
383 // DBGSourcePathRemapping entries that lldb worked
384 // with.
385 // If DBGVersion 3, trust & use the source path remappings as-is.
386 //
387 cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
388 (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
389 if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
390 // If we see DBGVersion with a value of 2 or higher, this is a new style
391 // DBGSourcePathRemapping dictionary
392 bool new_style_source_remapping_dictionary = false;
393 bool do_truncate_remapping_names = false;
394 std::string original_DBGSourcePath_value = DBGSourcePath;
395 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
396 CFSTR("DBGVersion"));
397 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
398 std::string version;
400 if (!version.empty() && isdigit(version[0])) {
401 int version_number = atoi(version.c_str());
402 if (version_number > 1) {
403 new_style_source_remapping_dictionary = true;
404 }
405 if (version_number == 2) {
406 do_truncate_remapping_names = true;
407 }
408 }
409 }
410
411 CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
412 if (kv_pair_count > 0) {
413 CFStringRef *keys =
414 (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
415 CFStringRef *values =
416 (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
417 if (keys != nullptr && values != nullptr) {
418 CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
419 (const void **)keys,
420 (const void **)values);
421 }
422 for (CFIndex i = 0; i < kv_pair_count; i++) {
423 DBGBuildSourcePath.clear();
424 DBGSourcePath.clear();
425 if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
426 CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
427 }
428 if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
429 CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
430 }
431 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
432 // In the "old style" DBGSourcePathRemapping dictionary, the
433 // DBGSourcePath values (the "values" half of key-value path pairs)
434 // were wrong. Ignore them and use the universal DBGSourcePath
435 // string from earlier.
436 if (new_style_source_remapping_dictionary &&
437 !original_DBGSourcePath_value.empty()) {
438 DBGSourcePath = original_DBGSourcePath_value;
439 }
440 if (DBGSourcePath[0] == '~') {
441 FileSpec resolved_source_path(DBGSourcePath.c_str());
442 FileSystem::Instance().Resolve(resolved_source_path);
443 DBGSourcePath = resolved_source_path.GetPath();
444 }
445 // With version 2 of DBGSourcePathRemapping, we can chop off the
446 // last two filename parts from the source remapping and get a more
447 // general source remapping that still works. Add this as another
448 // option in addition to the full source path remap.
449 module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
450 DBGSourcePath, true);
451 if (do_truncate_remapping_names) {
452 FileSpec build_path(DBGBuildSourcePath.c_str());
453 FileSpec source_path(DBGSourcePath.c_str());
454 build_path.RemoveLastPathComponent();
455 build_path.RemoveLastPathComponent();
456 source_path.RemoveLastPathComponent();
457 source_path.RemoveLastPathComponent();
458 module_spec.GetSourceMappingList().Append(
459 build_path.GetPath(), source_path.GetPath(), true);
460 }
461 }
462 }
463 if (keys)
464 free(keys);
465 if (values)
466 free(values);
467 }
468 }
469
470 // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
471 // source remappings list.
472
473 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
474 CFSTR("DBGBuildSourcePath"));
475 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
476 CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
477 }
478
479 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
480 CFSTR("DBGSourcePath"));
481 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
482 CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
483 }
484
485 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
486 if (DBGSourcePath[0] == '~') {
487 FileSpec resolved_source_path(DBGSourcePath.c_str());
488 FileSystem::Instance().Resolve(resolved_source_path);
489 DBGSourcePath = resolved_source_path.GetPath();
490 }
491 module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
492 DBGSourcePath, true);
493 }
494 }
495 return success;
496}
497
498/// It's expensive to check for the DBGShellCommands defaults setting. Only do
499/// it once per lldb run and cache the result.
500static llvm::StringRef GetDbgShellCommand() {
501 static std::once_flag g_once_flag;
502 static std::string g_dbgshell_command;
503 std::call_once(g_once_flag, [&]() {
504 CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
505 CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
506 if (defaults_setting &&
507 CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
508 char buffer[PATH_MAX];
509 if (CFStringGetCString((CFStringRef)defaults_setting, buffer,
510 sizeof(buffer), kCFStringEncodingUTF8)) {
511 g_dbgshell_command = buffer;
512 }
513 }
514 if (defaults_setting) {
515 CFRelease(defaults_setting);
516 }
517 });
518 return g_dbgshell_command;
519}
520
521/// Get the dsymForUUID executable and cache the result so we don't end up
522/// stat'ing the binary over and over.
524 // The LLDB_APPLE_DSYMFORUUID_EXECUTABLE environment variable is used by the
525 // test suite to override the dsymForUUID location. Because we must be able
526 // to change the value within a single test, don't bother caching it.
527 if (const char *dsymForUUID_env =
528 getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE")) {
529 FileSpec dsymForUUID_executable(dsymForUUID_env);
530 FileSystem::Instance().Resolve(dsymForUUID_executable);
531 if (FileSystem::Instance().Exists(dsymForUUID_executable))
532 return dsymForUUID_executable;
533 }
534
535 static std::once_flag g_once_flag;
536 static FileSpec g_dsymForUUID_executable;
537 std::call_once(g_once_flag, [&]() {
538 // Try the DBGShellCommand.
539 llvm::StringRef dbgshell_command = GetDbgShellCommand();
540 if (!dbgshell_command.empty()) {
541 g_dsymForUUID_executable = FileSpec(dbgshell_command);
542 FileSystem::Instance().Resolve(g_dsymForUUID_executable);
543 if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
544 return;
545 }
546
547 // Try dsymForUUID in /usr/local/bin
548 {
549 g_dsymForUUID_executable = FileSpec("/usr/local/bin/dsymForUUID");
550 if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
551 return;
552 }
553
554 // We couldn't find the dsymForUUID binary.
555 g_dsymForUUID_executable = {};
556 });
557 return g_dsymForUUID_executable;
558}
559
561 Status &error, bool force_lookup,
562 bool copy_executable) {
563 const UUID *uuid_ptr = module_spec.GetUUIDPtr();
564 const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
565
566 // If \a dbgshell_command is set, the user has specified
567 // forced symbol lookup via that command. We'll get the
568 // path back from GetDsymForUUIDExecutable() later.
569 llvm::StringRef dbgshell_command = GetDbgShellCommand();
570
571 // If forced lookup isn't set, by the user's \a dbgshell_command or
572 // by the \a force_lookup argument, exit this method.
573 if (!force_lookup && dbgshell_command.empty())
574 return false;
575
576 // We need a UUID or valid existing FileSpec.
577 if (!uuid_ptr &&
578 (!file_spec_ptr || !FileSystem::Instance().Exists(*file_spec_ptr)))
579 return false;
580
581 // We need a dsymForUUID binary or an equivalent executable/script.
582 FileSpec dsymForUUID_exe_spec = GetDsymForUUIDExecutable();
583 if (!dsymForUUID_exe_spec)
584 return false;
585
586 const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath();
587 const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : "";
588 const std::string file_path_str =
589 file_spec_ptr ? file_spec_ptr->GetPath() : "";
590
591 Log *log = GetLog(LLDBLog::Host);
592
593 // Create the dsymForUUID command.
594 StreamString command;
595 const char *copy_executable_arg = copy_executable ? "--copyExecutable " : "";
596 if (!uuid_str.empty()) {
597 command.Printf("%s --ignoreNegativeCache %s%s",
598 dsymForUUID_exe_path.c_str(), copy_executable_arg,
599 uuid_str.c_str());
600 LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM: %s",
601 dsymForUUID_exe_path.c_str(), uuid_str.c_str(),
602 command.GetString().data());
603 } else if (!file_path_str.empty()) {
604 command.Printf("%s --ignoreNegativeCache %s%s",
605 dsymForUUID_exe_path.c_str(), copy_executable_arg,
606 file_path_str.c_str());
607 LLDB_LOGF(log, "Calling %s with file %s to find dSYM: %s",
608 dsymForUUID_exe_path.c_str(), file_path_str.c_str(),
609 command.GetString().data());
610 } else {
611 return false;
612 }
613
614 // Invoke dsymForUUID.
615 int exit_status = -1;
616 int signo = -1;
617 std::string command_output;
619 command.GetData(),
620 FileSpec(), // current working directory
621 &exit_status, // Exit status
622 &signo, // Signal int *
623 &command_output, // Command output
624 std::chrono::seconds(
625 640), // Large timeout to allow for long dsym download times
626 false); // Don't run in a shell (we don't need shell expansion)
627
628 if (error.Fail() || exit_status != 0 || command_output.empty()) {
629 LLDB_LOGF(log, "'%s' failed (exit status: %d, error: '%s', output: '%s')",
630 command.GetData(), exit_status, error.AsCString(),
631 command_output.c_str());
632 return false;
633 }
634
635 CFCData data(
636 CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)command_output.data(),
637 command_output.size(), kCFAllocatorNull));
638
640 (CFDictionaryRef)::CFPropertyListCreateWithData(
641 NULL, data.get(), kCFPropertyListImmutable, NULL, NULL));
642
643 if (!plist.get()) {
644 LLDB_LOGF(log, "'%s' failed: output is not a valid plist",
645 command.GetData());
646 return false;
647 }
648
649 if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) {
650 LLDB_LOGF(log, "'%s' failed: output plist is not a valid CFDictionary",
651 command.GetData());
652 return false;
653 }
654
655 if (!uuid_str.empty()) {
656 CFCString uuid_cfstr(uuid_str.c_str());
657 CFDictionaryRef uuid_dict =
658 (CFDictionaryRef)CFDictionaryGetValue(plist.get(), uuid_cfstr.get());
659 return GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec, error,
660 command.GetData());
661 }
662
663 if (const CFIndex num_values = ::CFDictionaryGetCount(plist.get())) {
664 std::vector<CFStringRef> keys(num_values, NULL);
665 std::vector<CFDictionaryRef> values(num_values, NULL);
666 ::CFDictionaryGetKeysAndValues(plist.get(), NULL,
667 (const void **)&values[0]);
668 if (num_values == 1) {
669 return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec, error,
670 command.GetData());
671 }
672
673 for (CFIndex i = 0; i < num_values; ++i) {
674 ModuleSpec curr_module_spec;
675 if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec,
676 error, command.GetData())) {
677 if (module_spec.GetArchitecture().IsCompatibleMatch(
678 curr_module_spec.GetArchitecture())) {
679 module_spec = curr_module_spec;
680 return true;
681 }
682 }
683 }
684 }
685
686 return false;
687}
static llvm::raw_ostream & error(Stream &strm)
static llvm::StringRef GetDbgShellCommand()
It's expensive to check for the DBGShellCommands defaults setting.
int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, ModuleSpec &return_module_spec)
static CFDictionaryRef(* g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url)
static CFURLRef(* g_dlsym_DBGCopyFullDSYMURLForUUID)(CFUUIDRef uuid, CFURLRef exec_url)
static FileSpec GetDsymForUUIDExecutable()
Get the dsymForUUID executable and cache the result so we don't end up stat'ing the binary over and o...
static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, ModuleSpec &module_spec, Status &error, const std::string &command)
#define LLDB_LOGF(log,...)
Definition: Log.h:349
CFURLRef CopyExecutableURL() const
Definition: CFCBundle.cpp:71
void reset(T ptr=NULL)
Definition: CFCReleaser.h:86
static const char * FileSystemRepresentation(CFStringRef cf_str, std::string &str)
Definition: CFCString.cpp:126
An architecture specification class.
Definition: ArchSpec.h:31
bool IsCompatibleMatch(const ArchSpec &rhs) const
Shorthand for IsMatch(rhs, CompatibleMatch).
Definition: ArchSpec.h:502
A file utility class.
Definition: FileSpec.h:56
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:174
bool RemoveLastPathComponent()
Removes the last path component by replacing the current path with its parent.
Definition: FileSpec.cpp:458
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:367
void Clear()
Clears the object state.
Definition: FileSpec.cpp:259
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
bool Exists(const FileSpec &file_spec) const
Returns whether the given file exists.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > GetVirtualFileSystem()
Definition: FileSystem.h:201
static FileSystem & Instance()
static Status RunShellCommand(llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, const Timeout< std::micro > &timeout, bool run_in_shell=true, bool hide_stderr=false)
Run a shell command.
static ModuleListProperties & GetGlobalModuleListProperties()
Definition: ModuleList.cpp:751
bool GetModuleSpecAtIndex(size_t i, ModuleSpec &module_spec) const
Definition: ModuleSpec.h:323
bool FindMatchingModuleSpec(const ModuleSpec &module_spec, ModuleSpec &match_module_spec) const
Definition: ModuleSpec.h:333
PathMappingList & GetSourceMappingList() const
Definition: ModuleSpec.h:125
FileSpec & GetFileSpec()
Definition: ModuleSpec.h:53
ArchSpec & GetArchitecture()
Definition: ModuleSpec.h:89
FileSpec * GetFileSpecPtr()
Definition: ModuleSpec.h:47
FileSpec & GetSymbolFileSpec()
Definition: ModuleSpec.h:77
ArchSpec * GetArchitecturePtr()
Definition: ModuleSpec.h:81
A class that describes an executable image and its associated object and symbol files.
Definition: Module.h:88
static size_t GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset, lldb::offset_t file_size, ModuleSpecList &specs, lldb::DataBufferSP data_sp=lldb::DataBufferSP())
Definition: ObjectFile.cpp:187
void Append(llvm::StringRef path, llvm::StringRef replacement, bool notify)
An error handling class.
Definition: Status.h:44
const char * GetData() const
Definition: StreamString.h:43
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, Status &error, bool force_lookup=true, bool copy_executable=true)
static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, const lldb_private::UUID *uuid, const ArchSpec *arch)
llvm::ArrayRef< uint8_t > GetBytes() const
Definition: UUID.h:66
std::string GetAsString(llvm::StringRef separator="-") const
Definition: UUID.cpp:49
bool IsValid() const
Definition: UUID.h:69
#define UNUSED_IF_ASSERT_DISABLED(x)
Definition: lldb-defines.h:128
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:354
#define PATH_MAX