1 //===-- LocateSymbolFileMacOSX.cpp ----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Symbol/LocateSymbolFile.h"
15 #include <CoreFoundation/CoreFoundation.h>
17 #include "Host/macosx/cfcpp/CFCBundle.h"
18 #include "Host/macosx/cfcpp/CFCData.h"
19 #include "Host/macosx/cfcpp/CFCReleaser.h"
20 #include "Host/macosx/cfcpp/CFCString.h"
21 #include "lldb/Core/ModuleList.h"
22 #include "lldb/Core/ModuleSpec.h"
23 #include "lldb/Host/Host.h"
24 #include "lldb/Symbol/ObjectFile.h"
25 #include "lldb/Utility/ArchSpec.h"
26 #include "lldb/Utility/DataBuffer.h"
27 #include "lldb/Utility/DataExtractor.h"
28 #include "lldb/Utility/Endian.h"
29 #include "lldb/Utility/Log.h"
30 #include "lldb/Utility/ReproducerProvider.h"
31 #include "lldb/Utility/StreamString.h"
32 #include "lldb/Utility/Timer.h"
33 #include "lldb/Utility/UUID.h"
34 #include "mach/machine.h"
36 #include "llvm/ADT/ScopeExit.h"
37 #include "llvm/Support/FileSystem.h"
40 using namespace lldb_private
;
42 static CFURLRef (*g_dlsym_DBGCopyFullDSYMURLForUUID
)(CFUUIDRef uuid
, CFURLRef exec_url
) = nullptr;
43 static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists
)(CFURLRef dsym_url
) = nullptr;
45 int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec
&module_spec
,
46 ModuleSpec
&return_module_spec
) {
47 Log
*log
= lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST
);
48 if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
49 LLDB_LOGF(log
, "Spotlight lookup for .dSYM bundles is disabled.");
53 return_module_spec
= module_spec
;
54 return_module_spec
.GetFileSpec().Clear();
55 return_module_spec
.GetSymbolFileSpec().Clear();
57 const UUID
*uuid
= module_spec
.GetUUIDPtr();
58 const ArchSpec
*arch
= module_spec
.GetArchitecturePtr();
60 if (repro::Loader
*l
= repro::Reproducer::Instance().GetLoader()) {
61 static repro::SymbolFileLoader
symbol_file_loader(l
);
62 std::pair
<FileSpec
, FileSpec
> paths
= symbol_file_loader
.GetPaths(uuid
);
63 return_module_spec
.GetFileSpec() = paths
.first
;
64 return_module_spec
.GetSymbolFileSpec() = paths
.second
;
70 if (g_dlsym_DBGCopyFullDSYMURLForUUID
== nullptr ||
71 g_dlsym_DBGCopyDSYMPropertyLists
== nullptr) {
72 void *handle
= dlopen ("/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols", RTLD_LAZY
| RTLD_LOCAL
);
74 g_dlsym_DBGCopyFullDSYMURLForUUID
= (CFURLRef (*)(CFUUIDRef
, CFURLRef
)) dlsym (handle
, "DBGCopyFullDSYMURLForUUID");
75 g_dlsym_DBGCopyDSYMPropertyLists
= (CFDictionaryRef (*)(CFURLRef
)) dlsym (handle
, "DBGCopyDSYMPropertyLists");
79 if (g_dlsym_DBGCopyFullDSYMURLForUUID
== nullptr ||
80 g_dlsym_DBGCopyDSYMPropertyLists
== nullptr) {
84 if (uuid
&& uuid
->IsValid()) {
85 // Try and locate the dSYM file using DebugSymbols first
86 llvm::ArrayRef
<uint8_t> module_uuid
= uuid
->GetBytes();
87 if (module_uuid
.size() == 16) {
88 CFCReleaser
<CFUUIDRef
> module_uuid_ref(::CFUUIDCreateWithBytes(
89 NULL
, module_uuid
[0], module_uuid
[1], module_uuid
[2], module_uuid
[3],
90 module_uuid
[4], module_uuid
[5], module_uuid
[6], module_uuid
[7],
91 module_uuid
[8], module_uuid
[9], module_uuid
[10], module_uuid
[11],
92 module_uuid
[12], module_uuid
[13], module_uuid
[14], module_uuid
[15]));
94 if (module_uuid_ref
.get()) {
95 CFCReleaser
<CFURLRef
> exec_url
;
96 const FileSpec
*exec_fspec
= module_spec
.GetFileSpecPtr();
98 char exec_cf_path
[PATH_MAX
];
99 if (exec_fspec
->GetPath(exec_cf_path
, sizeof(exec_cf_path
)))
100 exec_url
.reset(::CFURLCreateFromFileSystemRepresentation(
101 NULL
, (const UInt8
*)exec_cf_path
, strlen(exec_cf_path
),
105 CFCReleaser
<CFURLRef
> dsym_url(
106 g_dlsym_DBGCopyFullDSYMURLForUUID(module_uuid_ref
.get(), exec_url
.get()));
109 if (dsym_url
.get()) {
110 if (::CFURLGetFileSystemRepresentation(
111 dsym_url
.get(), true, (UInt8
*)path
, sizeof(path
) - 1)) {
114 "DebugSymbols framework returned dSYM path of %s for "
115 "UUID %s -- looking for the dSYM",
116 path
, uuid
->GetAsString().c_str());
118 FileSpec
dsym_filespec(path
);
120 FileSystem::Instance().Resolve(dsym_filespec
);
122 if (FileSystem::Instance().IsDirectory(dsym_filespec
)) {
124 Symbols::FindSymbolFileInBundle(dsym_filespec
, uuid
, arch
);
129 return_module_spec
.GetSymbolFileSpec() = dsym_filespec
;
132 bool success
= false;
134 if (::CFURLGetFileSystemRepresentation(
135 dsym_url
.get(), true, (UInt8
*)path
, sizeof(path
) - 1)) {
137 "DebugSymbols framework returned dSYM path of %s for "
138 "UUID %s -- looking for an exec file",
139 path
, uuid
->GetAsString().c_str());
143 CFCReleaser
<CFDictionaryRef
> dict(
144 g_dlsym_DBGCopyDSYMPropertyLists(dsym_url
.get()));
145 CFDictionaryRef uuid_dict
= NULL
;
147 CFCString
uuid_cfstr(uuid
->GetAsString().c_str());
148 uuid_dict
= static_cast<CFDictionaryRef
>(
149 ::CFDictionaryGetValue(dict
.get(), uuid_cfstr
.get()));
152 CFStringRef exec_cf_path
=
153 static_cast<CFStringRef
>(::CFDictionaryGetValue(
154 uuid_dict
, CFSTR("DBGSymbolRichExecutable")));
155 if (exec_cf_path
&& ::CFStringGetFileSystemRepresentation(
156 exec_cf_path
, path
, sizeof(path
))) {
158 LLDB_LOGF(log
, "plist bundle has exec path of %s for UUID %s",
159 path
, uuid
->GetAsString().c_str());
162 FileSpec
exec_filespec(path
);
164 FileSystem::Instance().Resolve(exec_filespec
);
165 if (FileSystem::Instance().Exists(exec_filespec
)) {
167 return_module_spec
.GetFileSpec() = exec_filespec
;
173 // No dictionary, check near the dSYM bundle for an executable that
175 if (::CFURLGetFileSystemRepresentation(
176 dsym_url
.get(), true, (UInt8
*)path
, sizeof(path
) - 1)) {
177 char *dsym_extension_pos
= ::strstr(path
, ".dSYM");
178 if (dsym_extension_pos
) {
179 *dsym_extension_pos
= '\0';
182 "Looking for executable binary next to dSYM "
183 "bundle with name with name %s",
186 FileSpec
file_spec(path
);
187 FileSystem::Instance().Resolve(file_spec
);
188 ModuleSpecList module_specs
;
189 ModuleSpec matched_module_spec
;
190 using namespace llvm::sys::fs
;
191 switch (get_file_type(file_spec
.GetPath())) {
193 case file_type::directory_file
: // Bundle directory?
195 CFCBundle
bundle(path
);
196 CFCReleaser
<CFURLRef
> bundle_exe_url(
197 bundle
.CopyExecutableURL());
198 if (bundle_exe_url
.get()) {
199 if (::CFURLGetFileSystemRepresentation(bundle_exe_url
.get(),
202 FileSpec
bundle_exe_file_spec(path
);
203 FileSystem::Instance().Resolve(bundle_exe_file_spec
);
204 if (ObjectFile::GetModuleSpecifications(
205 bundle_exe_file_spec
, 0, 0, module_specs
) &&
206 module_specs
.FindMatchingModuleSpec(
207 module_spec
, matched_module_spec
))
211 return_module_spec
.GetFileSpec() = bundle_exe_file_spec
;
214 "Executable binary %s next to dSYM is "
223 case file_type::fifo_file
: // Forget pipes
224 case file_type::socket_file
: // We can't process socket files
225 case file_type::file_not_found
: // File doesn't exist...
226 case file_type::status_error
:
229 case file_type::type_unknown
:
230 case file_type::regular_file
:
231 case file_type::symlink_file
:
232 case file_type::block_file
:
233 case file_type::character_file
:
234 if (ObjectFile::GetModuleSpecifications(file_spec
, 0, 0,
236 module_specs
.FindMatchingModuleSpec(module_spec
,
237 matched_module_spec
))
241 return_module_spec
.GetFileSpec() = file_spec
;
244 "Executable binary %s next to dSYM is "
259 if (repro::Generator
*g
= repro::Reproducer::Instance().GetGenerator()) {
260 g
->GetOrCreate
<repro::SymbolFileProvider
>().AddSymbolFile(
261 uuid
, return_module_spec
.GetFileSpec(),
262 return_module_spec
.GetSymbolFileSpec());
268 FileSpec
Symbols::FindSymbolFileInBundle(const FileSpec
&dsym_bundle_fspec
,
269 const lldb_private::UUID
*uuid
,
270 const ArchSpec
*arch
) {
271 std::string dsym_bundle_path
= dsym_bundle_fspec
.GetPath();
272 llvm::SmallString
<128> buffer(dsym_bundle_path
);
273 llvm::sys::path::append(buffer
, "Contents", "Resources", "DWARF");
276 llvm::IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> vfs
=
277 FileSystem::Instance().GetVirtualFileSystem();
278 llvm::vfs::recursive_directory_iterator
Iter(*vfs
, buffer
.str(), EC
);
279 llvm::vfs::recursive_directory_iterator End
;
280 for (; Iter
!= End
&& !EC
; Iter
.increment(EC
)) {
281 llvm::ErrorOr
<llvm::vfs::Status
> Status
= vfs
->status(Iter
->path());
282 if (Status
->isDirectory())
285 FileSpec
dsym_fspec(Iter
->path());
286 ModuleSpecList module_specs
;
287 if (ObjectFile::GetModuleSpecifications(dsym_fspec
, 0, 0, module_specs
)) {
289 for (size_t i
= 0; i
< module_specs
.GetSize(); ++i
) {
290 bool got_spec
= module_specs
.GetModuleSpecAtIndex(i
, spec
);
291 assert(got_spec
); // The call has side-effects so can't be inlined.
292 UNUSED_IF_ASSERT_DISABLED(got_spec
);
293 if ((uuid
== nullptr ||
294 (spec
.GetUUIDPtr() && spec
.GetUUID() == *uuid
)) &&
296 (spec
.GetArchitecturePtr() &&
297 spec
.GetArchitecture().IsCompatibleMatch(*arch
)))) {
307 static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict
,
308 ModuleSpec
&module_spec
) {
309 Log
*log
= lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST
);
310 bool success
= false;
311 if (uuid_dict
!= NULL
&& CFGetTypeID(uuid_dict
) == CFDictionaryGetTypeID()) {
314 CFDictionaryRef cf_dict
;
316 cf_str
= (CFStringRef
)CFDictionaryGetValue(
317 (CFDictionaryRef
)uuid_dict
, CFSTR("DBGSymbolRichExecutable"));
318 if (cf_str
&& CFGetTypeID(cf_str
) == CFStringGetTypeID()) {
319 if (CFCString::FileSystemRepresentation(cf_str
, str
)) {
320 module_spec
.GetFileSpec().SetFile(str
.c_str(), FileSpec::Style::native
);
321 FileSystem::Instance().Resolve(module_spec
.GetFileSpec());
324 "From dsymForUUID plist: Symbol rich executable is at '%s'",
330 cf_str
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)uuid_dict
,
331 CFSTR("DBGDSYMPath"));
332 if (cf_str
&& CFGetTypeID(cf_str
) == CFStringGetTypeID()) {
333 if (CFCString::FileSystemRepresentation(cf_str
, str
)) {
334 module_spec
.GetSymbolFileSpec().SetFile(str
.c_str(),
335 FileSpec::Style::native
);
336 FileSystem::Instance().Resolve(module_spec
.GetFileSpec());
339 LLDB_LOGF(log
, "From dsymForUUID plist: dSYM is at '%s'",
345 std::string DBGBuildSourcePath
;
346 std::string DBGSourcePath
;
348 // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
349 // If DBGVersion 2, strip last two components of path remappings from
350 // entries to fix an issue with a specific set of
351 // DBGSourcePathRemapping entries that lldb worked
353 // If DBGVersion 3, trust & use the source path remappings as-is.
355 cf_dict
= (CFDictionaryRef
)CFDictionaryGetValue(
356 (CFDictionaryRef
)uuid_dict
, CFSTR("DBGSourcePathRemapping"));
357 if (cf_dict
&& CFGetTypeID(cf_dict
) == CFDictionaryGetTypeID()) {
358 // If we see DBGVersion with a value of 2 or higher, this is a new style
359 // DBGSourcePathRemapping dictionary
360 bool new_style_source_remapping_dictionary
= false;
361 bool do_truncate_remapping_names
= false;
362 std::string original_DBGSourcePath_value
= DBGSourcePath
;
363 cf_str
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)uuid_dict
,
364 CFSTR("DBGVersion"));
365 if (cf_str
&& CFGetTypeID(cf_str
) == CFStringGetTypeID()) {
367 CFCString::FileSystemRepresentation(cf_str
, version
);
368 if (!version
.empty() && isdigit(version
[0])) {
369 int version_number
= atoi(version
.c_str());
370 if (version_number
> 1) {
371 new_style_source_remapping_dictionary
= true;
373 if (version_number
== 2) {
374 do_truncate_remapping_names
= true;
379 CFIndex kv_pair_count
= CFDictionaryGetCount((CFDictionaryRef
)uuid_dict
);
380 if (kv_pair_count
> 0) {
382 (CFStringRef
*)malloc(kv_pair_count
* sizeof(CFStringRef
));
383 CFStringRef
*values
=
384 (CFStringRef
*)malloc(kv_pair_count
* sizeof(CFStringRef
));
385 if (keys
!= nullptr && values
!= nullptr) {
386 CFDictionaryGetKeysAndValues((CFDictionaryRef
)uuid_dict
,
388 (const void **)values
);
390 for (CFIndex i
= 0; i
< kv_pair_count
; i
++) {
391 DBGBuildSourcePath
.clear();
392 DBGSourcePath
.clear();
393 if (keys
[i
] && CFGetTypeID(keys
[i
]) == CFStringGetTypeID()) {
394 CFCString::FileSystemRepresentation(keys
[i
], DBGBuildSourcePath
);
396 if (values
[i
] && CFGetTypeID(values
[i
]) == CFStringGetTypeID()) {
397 CFCString::FileSystemRepresentation(values
[i
], DBGSourcePath
);
399 if (!DBGBuildSourcePath
.empty() && !DBGSourcePath
.empty()) {
400 // In the "old style" DBGSourcePathRemapping dictionary, the
401 // DBGSourcePath values (the "values" half of key-value path pairs)
402 // were wrong. Ignore them and use the universal DBGSourcePath
403 // string from earlier.
404 if (new_style_source_remapping_dictionary
&&
405 !original_DBGSourcePath_value
.empty()) {
406 DBGSourcePath
= original_DBGSourcePath_value
;
408 if (DBGSourcePath
[0] == '~') {
409 FileSpec
resolved_source_path(DBGSourcePath
.c_str());
410 FileSystem::Instance().Resolve(resolved_source_path
);
411 DBGSourcePath
= resolved_source_path
.GetPath();
413 // With version 2 of DBGSourcePathRemapping, we can chop off the
414 // last two filename parts from the source remapping and get a more
415 // general source remapping that still works. Add this as another
416 // option in addition to the full source path remap.
417 module_spec
.GetSourceMappingList().Append(DBGBuildSourcePath
,
418 DBGSourcePath
, true);
419 if (do_truncate_remapping_names
) {
420 FileSpec
build_path(DBGBuildSourcePath
.c_str());
421 FileSpec
source_path(DBGSourcePath
.c_str());
422 build_path
.RemoveLastPathComponent();
423 build_path
.RemoveLastPathComponent();
424 source_path
.RemoveLastPathComponent();
425 source_path
.RemoveLastPathComponent();
426 module_spec
.GetSourceMappingList().Append(
427 build_path
.GetPath(), source_path
.GetPath(), true);
438 // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
439 // source remappings list.
441 cf_str
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)uuid_dict
,
442 CFSTR("DBGBuildSourcePath"));
443 if (cf_str
&& CFGetTypeID(cf_str
) == CFStringGetTypeID()) {
444 CFCString::FileSystemRepresentation(cf_str
, DBGBuildSourcePath
);
447 cf_str
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)uuid_dict
,
448 CFSTR("DBGSourcePath"));
449 if (cf_str
&& CFGetTypeID(cf_str
) == CFStringGetTypeID()) {
450 CFCString::FileSystemRepresentation(cf_str
, DBGSourcePath
);
453 if (!DBGBuildSourcePath
.empty() && !DBGSourcePath
.empty()) {
454 if (DBGSourcePath
[0] == '~') {
455 FileSpec
resolved_source_path(DBGSourcePath
.c_str());
456 FileSystem::Instance().Resolve(resolved_source_path
);
457 DBGSourcePath
= resolved_source_path
.GetPath();
459 module_spec
.GetSourceMappingList().Append(DBGBuildSourcePath
,
460 DBGSourcePath
, true);
466 bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec
&module_spec
,
468 bool success
= false;
469 const UUID
*uuid_ptr
= module_spec
.GetUUIDPtr();
470 const FileSpec
*file_spec_ptr
= module_spec
.GetFileSpecPtr();
472 if (repro::Loader
*l
= repro::Reproducer::Instance().GetLoader()) {
473 static repro::SymbolFileLoader
symbol_file_loader(l
);
474 std::pair
<FileSpec
, FileSpec
> paths
= symbol_file_loader
.GetPaths(uuid_ptr
);
476 module_spec
.GetFileSpec() = paths
.first
;
478 module_spec
.GetSymbolFileSpec() = paths
.second
;
482 // Lambda to capture the state of module_spec before returning from this
484 auto RecordResult
= [&]() {
485 if (repro::Generator
*g
= repro::Reproducer::Instance().GetGenerator()) {
486 g
->GetOrCreate
<repro::SymbolFileProvider
>().AddSymbolFile(
487 uuid_ptr
, module_spec
.GetFileSpec(), module_spec
.GetSymbolFileSpec());
491 // It's expensive to check for the DBGShellCommands defaults setting, only do
492 // it once per lldb run and cache the result.
493 static bool g_have_checked_for_dbgshell_command
= false;
494 static const char *g_dbgshell_command
= NULL
;
495 if (!g_have_checked_for_dbgshell_command
) {
496 g_have_checked_for_dbgshell_command
= true;
497 CFTypeRef defaults_setting
= CFPreferencesCopyAppValue(
498 CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
499 if (defaults_setting
&&
500 CFGetTypeID(defaults_setting
) == CFStringGetTypeID()) {
501 char cstr_buf
[PATH_MAX
];
502 if (CFStringGetCString((CFStringRef
)defaults_setting
, cstr_buf
,
503 sizeof(cstr_buf
), kCFStringEncodingUTF8
)) {
505 strdup(cstr_buf
); // this malloc'ed memory will never be freed
508 if (defaults_setting
) {
509 CFRelease(defaults_setting
);
513 // When g_dbgshell_command is NULL, the user has not enabled the use of an
514 // external program to find the symbols, don't run it for them.
515 if (!force_lookup
&& g_dbgshell_command
== NULL
) {
521 (file_spec_ptr
&& FileSystem::Instance().Exists(*file_spec_ptr
))) {
522 static bool g_located_dsym_for_uuid_exe
= false;
523 static bool g_dsym_for_uuid_exe_exists
= false;
524 static char g_dsym_for_uuid_exe_path
[PATH_MAX
];
525 if (!g_located_dsym_for_uuid_exe
) {
526 g_located_dsym_for_uuid_exe
= true;
527 const char *dsym_for_uuid_exe_path_cstr
=
528 getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
529 FileSpec dsym_for_uuid_exe_spec
;
530 if (dsym_for_uuid_exe_path_cstr
) {
531 dsym_for_uuid_exe_spec
.SetFile(dsym_for_uuid_exe_path_cstr
,
532 FileSpec::Style::native
);
533 FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec
);
534 g_dsym_for_uuid_exe_exists
=
535 FileSystem::Instance().Exists(dsym_for_uuid_exe_spec
);
538 if (!g_dsym_for_uuid_exe_exists
) {
539 dsym_for_uuid_exe_spec
.SetFile("/usr/local/bin/dsymForUUID",
540 FileSpec::Style::native
);
541 g_dsym_for_uuid_exe_exists
=
542 FileSystem::Instance().Exists(dsym_for_uuid_exe_spec
);
543 if (!g_dsym_for_uuid_exe_exists
) {
545 if ((bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
)) != -1) {
546 char buffer
[bufsize
];
548 struct passwd
*tilde_rc
= NULL
;
549 // we are a library so we need to use the reentrant version of
551 if (getpwnam_r("rc", &pwd
, buffer
, bufsize
, &tilde_rc
) == 0 &&
552 tilde_rc
&& tilde_rc
->pw_dir
) {
553 std::string
dsymforuuid_path(tilde_rc
->pw_dir
);
554 dsymforuuid_path
+= "/bin/dsymForUUID";
555 dsym_for_uuid_exe_spec
.SetFile(dsymforuuid_path
.c_str(),
556 FileSpec::Style::native
);
557 g_dsym_for_uuid_exe_exists
=
558 FileSystem::Instance().Exists(dsym_for_uuid_exe_spec
);
563 if (!g_dsym_for_uuid_exe_exists
&& g_dbgshell_command
!= NULL
) {
564 dsym_for_uuid_exe_spec
.SetFile(g_dbgshell_command
,
565 FileSpec::Style::native
);
566 FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec
);
567 g_dsym_for_uuid_exe_exists
=
568 FileSystem::Instance().Exists(dsym_for_uuid_exe_spec
);
571 if (g_dsym_for_uuid_exe_exists
)
572 dsym_for_uuid_exe_spec
.GetPath(g_dsym_for_uuid_exe_path
,
573 sizeof(g_dsym_for_uuid_exe_path
));
575 if (g_dsym_for_uuid_exe_exists
) {
576 std::string uuid_str
;
577 char file_path
[PATH_MAX
];
581 uuid_str
= uuid_ptr
->GetAsString();
584 file_spec_ptr
->GetPath(file_path
, sizeof(file_path
));
586 StreamString command
;
587 if (!uuid_str
.empty())
588 command
.Printf("%s --ignoreNegativeCache --copyExecutable %s",
589 g_dsym_for_uuid_exe_path
, uuid_str
.c_str());
590 else if (file_path
[0] != '\0')
591 command
.Printf("%s --ignoreNegativeCache --copyExecutable %s",
592 g_dsym_for_uuid_exe_path
, file_path
);
594 if (!command
.GetString().empty()) {
595 Log
*log
= lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST
);
596 int exit_status
= -1;
598 std::string command_output
;
600 if (!uuid_str
.empty())
601 LLDB_LOGF(log
, "Calling %s with UUID %s to find dSYM",
602 g_dsym_for_uuid_exe_path
, uuid_str
.c_str());
603 else if (file_path
[0] != '\0')
604 LLDB_LOGF(log
, "Calling %s with file %s to find dSYM",
605 g_dsym_for_uuid_exe_path
, file_path
);
607 Status error
= Host::RunShellCommand(
609 FileSpec(), // current working directory
610 &exit_status
, // Exit status
611 &signo
, // Signal int *
612 &command_output
, // Command output
613 std::chrono::seconds(
614 640), // Large timeout to allow for long dsym download times
615 false); // Don't run in a shell (we don't need shell expansion)
616 if (error
.Success() && exit_status
== 0 && !command_output
.empty()) {
617 CFCData
data(CFDataCreateWithBytesNoCopy(
618 NULL
, (const UInt8
*)command_output
.data(), command_output
.size(),
621 CFCReleaser
<CFDictionaryRef
> plist(
622 (CFDictionaryRef
)::CFPropertyListCreateFromXMLData(
623 NULL
, data
.get(), kCFPropertyListImmutable
, NULL
));
626 CFGetTypeID(plist
.get()) == CFDictionaryGetTypeID()) {
627 if (!uuid_str
.empty()) {
628 CFCString
uuid_cfstr(uuid_str
.c_str());
629 CFDictionaryRef uuid_dict
= (CFDictionaryRef
)CFDictionaryGetValue(
630 plist
.get(), uuid_cfstr
.get());
632 GetModuleSpecInfoFromUUIDDictionary(uuid_dict
, module_spec
);
634 const CFIndex num_values
= ::CFDictionaryGetCount(plist
.get());
635 if (num_values
> 0) {
636 std::vector
<CFStringRef
> keys(num_values
, NULL
);
637 std::vector
<CFDictionaryRef
> values(num_values
, NULL
);
638 ::CFDictionaryGetKeysAndValues(plist
.get(), NULL
,
639 (const void **)&values
[0]);
640 if (num_values
== 1) {
641 success
= GetModuleSpecInfoFromUUIDDictionary(values
[0],
646 for (CFIndex i
= 0; i
< num_values
; ++i
) {
647 ModuleSpec curr_module_spec
;
648 if (GetModuleSpecInfoFromUUIDDictionary(values
[i
],
650 if (module_spec
.GetArchitecture().IsCompatibleMatch(
651 curr_module_spec
.GetArchitecture())) {
652 module_spec
= curr_module_spec
;
664 if (!uuid_str
.empty())
665 LLDB_LOGF(log
, "Called %s on %s, no matches",
666 g_dsym_for_uuid_exe_path
, uuid_str
.c_str());
667 else if (file_path
[0] != '\0')
668 LLDB_LOGF(log
, "Called %s on %s, no matches",
669 g_dsym_for_uuid_exe_path
, file_path
);