]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp
Merge ^/vendor/lldb/dist up to its last change, and resolve conflicts.
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / source / Symbol / LocateSymbolFileMacOSX.cpp
1 //===-- LocateSymbolFileMacOSX.cpp ------------------------------*- C++ -*-===//
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 "lldb/Symbol/LocateSymbolFile.h"
10
11 #include <dirent.h>
12 #include <dlfcn.h>
13 #include <pwd.h>
14
15 #include <CoreFoundation/CoreFoundation.h>
16
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/StreamString.h"
31 #include "lldb/Utility/Timer.h"
32 #include "lldb/Utility/UUID.h"
33 #include "mach/machine.h"
34
35 #include "llvm/ADT/ScopeExit.h"
36 #include "llvm/Support/FileSystem.h"
37
38 using namespace lldb;
39 using namespace lldb_private;
40
41 static CFURLRef (*g_dlsym_DBGCopyFullDSYMURLForUUID)(CFUUIDRef uuid, CFURLRef exec_url) = nullptr;
42 static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) = nullptr;
43
44 int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
45                                        ModuleSpec &return_module_spec) {
46   Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
47   if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
48     LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled.");
49     return 0;
50   }
51
52   return_module_spec = module_spec;
53   return_module_spec.GetFileSpec().Clear();
54   return_module_spec.GetSymbolFileSpec().Clear();
55
56   int items_found = 0;
57
58   if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
59       g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
60     void *handle = dlopen ("/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols", RTLD_LAZY | RTLD_LOCAL);
61     if (handle) {
62       g_dlsym_DBGCopyFullDSYMURLForUUID = (CFURLRef (*)(CFUUIDRef, CFURLRef)) dlsym (handle, "DBGCopyFullDSYMURLForUUID");
63       g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef (*)(CFURLRef)) dlsym (handle, "DBGCopyDSYMPropertyLists");
64     }
65   }
66
67   if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
68       g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
69     return items_found;
70   }
71
72   const UUID *uuid = module_spec.GetUUIDPtr();
73   const ArchSpec *arch = module_spec.GetArchitecturePtr();
74
75   if (uuid && uuid->IsValid()) {
76     // Try and locate the dSYM file using DebugSymbols first
77     llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
78     if (module_uuid.size() == 16) {
79       CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
80           NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
81           module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
82           module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
83           module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
84
85       if (module_uuid_ref.get()) {
86         CFCReleaser<CFURLRef> exec_url;
87         const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
88         if (exec_fspec) {
89           char exec_cf_path[PATH_MAX];
90           if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
91             exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
92                 NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
93                 FALSE));
94         }
95
96         CFCReleaser<CFURLRef> dsym_url(
97             g_dlsym_DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
98         char path[PATH_MAX];
99
100         if (dsym_url.get()) {
101           if (::CFURLGetFileSystemRepresentation(
102                   dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
103             if (log) {
104               LLDB_LOGF(log,
105                         "DebugSymbols framework returned dSYM path of %s for "
106                         "UUID %s -- looking for the dSYM",
107                         path, uuid->GetAsString().c_str());
108             }
109             FileSpec dsym_filespec(path);
110             if (path[0] == '~')
111               FileSystem::Instance().Resolve(dsym_filespec);
112
113             if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
114               dsym_filespec =
115                   Symbols::FindSymbolFileInBundle(dsym_filespec, uuid, arch);
116               ++items_found;
117             } else {
118               ++items_found;
119             }
120             return_module_spec.GetSymbolFileSpec() = dsym_filespec;
121           }
122
123           bool success = false;
124           if (log) {
125             if (::CFURLGetFileSystemRepresentation(
126                     dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
127               LLDB_LOGF(log,
128                         "DebugSymbols framework returned dSYM path of %s for "
129                         "UUID %s -- looking for an exec file",
130                         path, uuid->GetAsString().c_str());
131             }
132           }
133
134           CFCReleaser<CFDictionaryRef> dict(
135               g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get()));
136           CFDictionaryRef uuid_dict = NULL;
137           if (dict.get()) {
138             CFCString uuid_cfstr(uuid->GetAsString().c_str());
139             uuid_dict = static_cast<CFDictionaryRef>(
140                 ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
141           }
142           if (uuid_dict) {
143             CFStringRef exec_cf_path =
144                 static_cast<CFStringRef>(::CFDictionaryGetValue(
145                     uuid_dict, CFSTR("DBGSymbolRichExecutable")));
146             if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
147                                     exec_cf_path, path, sizeof(path))) {
148               if (log) {
149                 LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s",
150                           path, uuid->GetAsString().c_str());
151               }
152               ++items_found;
153               FileSpec exec_filespec(path);
154               if (path[0] == '~')
155                 FileSystem::Instance().Resolve(exec_filespec);
156               if (FileSystem::Instance().Exists(exec_filespec)) {
157                 success = true;
158                 return_module_spec.GetFileSpec() = exec_filespec;
159               }
160             }
161           }
162
163           if (!success) {
164             // No dictionary, check near the dSYM bundle for an executable that
165             // matches...
166             if (::CFURLGetFileSystemRepresentation(
167                     dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
168               char *dsym_extension_pos = ::strstr(path, ".dSYM");
169               if (dsym_extension_pos) {
170                 *dsym_extension_pos = '\0';
171                 if (log) {
172                   LLDB_LOGF(log,
173                             "Looking for executable binary next to dSYM "
174                             "bundle with name with name %s",
175                             path);
176                 }
177                 FileSpec file_spec(path);
178                 FileSystem::Instance().Resolve(file_spec);
179                 ModuleSpecList module_specs;
180                 ModuleSpec matched_module_spec;
181                 using namespace llvm::sys::fs;
182                 switch (get_file_type(file_spec.GetPath())) {
183
184                 case file_type::directory_file: // Bundle directory?
185                 {
186                   CFCBundle bundle(path);
187                   CFCReleaser<CFURLRef> bundle_exe_url(
188                       bundle.CopyExecutableURL());
189                   if (bundle_exe_url.get()) {
190                     if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
191                                                            true, (UInt8 *)path,
192                                                            sizeof(path) - 1)) {
193                       FileSpec bundle_exe_file_spec(path);
194                       FileSystem::Instance().Resolve(bundle_exe_file_spec);
195                       if (ObjectFile::GetModuleSpecifications(
196                               bundle_exe_file_spec, 0, 0, module_specs) &&
197                           module_specs.FindMatchingModuleSpec(
198                               module_spec, matched_module_spec))
199
200                       {
201                         ++items_found;
202                         return_module_spec.GetFileSpec() = bundle_exe_file_spec;
203                         if (log) {
204                           LLDB_LOGF(log,
205                                     "Executable binary %s next to dSYM is "
206                                     "compatible; using",
207                                     path);
208                         }
209                       }
210                     }
211                   }
212                 } break;
213
214                 case file_type::fifo_file:      // Forget pipes
215                 case file_type::socket_file:    // We can't process socket files
216                 case file_type::file_not_found: // File doesn't exist...
217                 case file_type::status_error:
218                   break;
219
220                 case file_type::type_unknown:
221                 case file_type::regular_file:
222                 case file_type::symlink_file:
223                 case file_type::block_file:
224                 case file_type::character_file:
225                   if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0,
226                                                           module_specs) &&
227                       module_specs.FindMatchingModuleSpec(module_spec,
228                                                           matched_module_spec))
229
230                   {
231                     ++items_found;
232                     return_module_spec.GetFileSpec() = file_spec;
233                     if (log) {
234                       LLDB_LOGF(log,
235                                 "Executable binary %s next to dSYM is "
236                                 "compatible; using",
237                                 path);
238                     }
239                   }
240                   break;
241                 }
242               }
243             }
244           }
245         }
246       }
247     }
248   }
249
250   return items_found;
251 }
252
253 FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
254                                          const lldb_private::UUID *uuid,
255                                          const ArchSpec *arch) {
256   char path[PATH_MAX];
257   if (dsym_bundle_fspec.GetPath(path, sizeof(path)) == 0)
258     return {};
259
260   ::strncat(path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
261
262   DIR *dirp = opendir(path);
263   if (!dirp)
264     return {};
265
266   // Make sure we close the directory before exiting this scope.
267   auto cleanup_dir = llvm::make_scope_exit([&]() { closedir(dirp); });
268
269   FileSpec dsym_fspec;
270   dsym_fspec.GetDirectory().SetCString(path);
271   struct dirent *dp;
272   while ((dp = readdir(dirp)) != NULL) {
273     // Only search directories
274     if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) {
275       if (dp->d_namlen == 1 && dp->d_name[0] == '.')
276         continue;
277
278       if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
279         continue;
280     }
281
282     if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) {
283       dsym_fspec.GetFilename().SetCString(dp->d_name);
284       ModuleSpecList module_specs;
285       if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) {
286         ModuleSpec spec;
287         for (size_t i = 0; i < module_specs.GetSize(); ++i) {
288           bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
289           UNUSED_IF_ASSERT_DISABLED(got_spec);
290           assert(got_spec);
291           if ((uuid == NULL ||
292                (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
293               (arch == NULL ||
294                (spec.GetArchitecturePtr() &&
295                 spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
296             return dsym_fspec;
297           }
298         }
299       }
300     }
301   }
302
303   return {};
304 }
305
306 static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
307                                                 ModuleSpec &module_spec) {
308   Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
309   bool success = false;
310   if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
311     std::string str;
312     CFStringRef cf_str;
313     CFDictionaryRef cf_dict;
314
315     cf_str = (CFStringRef)CFDictionaryGetValue(
316         (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
317     if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
318       if (CFCString::FileSystemRepresentation(cf_str, str)) {
319         module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native);
320         FileSystem::Instance().Resolve(module_spec.GetFileSpec());
321         if (log) {
322           LLDB_LOGF(log,
323                     "From dsymForUUID plist: Symbol rich executable is at '%s'",
324                     str.c_str());
325         }
326       }
327     }
328
329     cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
330                                                CFSTR("DBGDSYMPath"));
331     if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
332       if (CFCString::FileSystemRepresentation(cf_str, str)) {
333         module_spec.GetSymbolFileSpec().SetFile(str.c_str(),
334                                                 FileSpec::Style::native);
335         FileSystem::Instance().Resolve(module_spec.GetFileSpec());
336         success = true;
337         if (log) {
338           LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'",
339                     str.c_str());
340         }
341       }
342     }
343
344     cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
345                                                CFSTR("DBGArchitecture"));
346     if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
347       if (CFCString::FileSystemRepresentation(cf_str, str))
348         module_spec.GetArchitecture().SetTriple(str.c_str());
349     }
350
351     std::string DBGBuildSourcePath;
352     std::string DBGSourcePath;
353
354     // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
355     // If DBGVersion 2, strip last two components of path remappings from
356     //                  entries to fix an issue with a specific set of
357     //                  DBGSourcePathRemapping entries that lldb worked
358     //                  with.
359     // If DBGVersion 3, trust & use the source path remappings as-is.
360     //
361     cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
362         (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
363     if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
364       // If we see DBGVersion with a value of 2 or higher, this is a new style
365       // DBGSourcePathRemapping dictionary
366       bool new_style_source_remapping_dictionary = false;
367       bool do_truncate_remapping_names = false;
368       std::string original_DBGSourcePath_value = DBGSourcePath;
369       cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
370                                                  CFSTR("DBGVersion"));
371       if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
372         std::string version;
373         CFCString::FileSystemRepresentation(cf_str, version);
374         if (!version.empty() && isdigit(version[0])) {
375           int version_number = atoi(version.c_str());
376           if (version_number > 1) {
377             new_style_source_remapping_dictionary = true;
378           }
379           if (version_number == 2) {
380             do_truncate_remapping_names = true;
381           }
382         }
383       }
384
385       CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
386       if (kv_pair_count > 0) {
387         CFStringRef *keys =
388             (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
389         CFStringRef *values =
390             (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
391         if (keys != nullptr && values != nullptr) {
392           CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
393                                        (const void **)keys,
394                                        (const void **)values);
395         }
396         for (CFIndex i = 0; i < kv_pair_count; i++) {
397           DBGBuildSourcePath.clear();
398           DBGSourcePath.clear();
399           if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
400             CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
401           }
402           if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
403             CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
404           }
405           if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
406             // In the "old style" DBGSourcePathRemapping dictionary, the
407             // DBGSourcePath values (the "values" half of key-value path pairs)
408             // were wrong.  Ignore them and use the universal DBGSourcePath
409             // string from earlier.
410             if (new_style_source_remapping_dictionary &&
411                 !original_DBGSourcePath_value.empty()) {
412               DBGSourcePath = original_DBGSourcePath_value;
413             }
414             if (DBGSourcePath[0] == '~') {
415               FileSpec resolved_source_path(DBGSourcePath.c_str());
416               FileSystem::Instance().Resolve(resolved_source_path);
417               DBGSourcePath = resolved_source_path.GetPath();
418             }
419             // With version 2 of DBGSourcePathRemapping, we can chop off the
420             // last two filename parts from the source remapping and get a more
421             // general source remapping that still works. Add this as another
422             // option in addition to the full source path remap.
423             module_spec.GetSourceMappingList().Append(
424                 ConstString(DBGBuildSourcePath.c_str()),
425                 ConstString(DBGSourcePath.c_str()), true);
426             if (do_truncate_remapping_names) {
427               FileSpec build_path(DBGBuildSourcePath.c_str());
428               FileSpec source_path(DBGSourcePath.c_str());
429               build_path.RemoveLastPathComponent();
430               build_path.RemoveLastPathComponent();
431               source_path.RemoveLastPathComponent();
432               source_path.RemoveLastPathComponent();
433               module_spec.GetSourceMappingList().Append(
434                   ConstString(build_path.GetPath().c_str()),
435                   ConstString(source_path.GetPath().c_str()), true);
436             }
437           }
438         }
439         if (keys)
440           free(keys);
441         if (values)
442           free(values);
443       }
444     }
445
446     // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
447     // source remappings list.
448
449     cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
450                                                CFSTR("DBGBuildSourcePath"));
451     if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
452       CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
453     }
454
455     cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
456                                                CFSTR("DBGSourcePath"));
457     if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
458       CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
459     }
460
461     if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
462       if (DBGSourcePath[0] == '~') {
463         FileSpec resolved_source_path(DBGSourcePath.c_str());
464         FileSystem::Instance().Resolve(resolved_source_path);
465         DBGSourcePath = resolved_source_path.GetPath();
466       }
467       module_spec.GetSourceMappingList().Append(
468           ConstString(DBGBuildSourcePath.c_str()),
469           ConstString(DBGSourcePath.c_str()), true);
470     }
471   }
472   return success;
473 }
474
475 bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
476                                           bool force_lookup) {
477   bool success = false;
478   const UUID *uuid_ptr = module_spec.GetUUIDPtr();
479   const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
480
481   // It's expensive to check for the DBGShellCommands defaults setting, only do
482   // it once per lldb run and cache the result.
483   static bool g_have_checked_for_dbgshell_command = false;
484   static const char *g_dbgshell_command = NULL;
485   if (!g_have_checked_for_dbgshell_command) {
486     g_have_checked_for_dbgshell_command = true;
487     CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
488         CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
489     if (defaults_setting &&
490         CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
491       char cstr_buf[PATH_MAX];
492       if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf,
493                              sizeof(cstr_buf), kCFStringEncodingUTF8)) {
494         g_dbgshell_command =
495             strdup(cstr_buf); // this malloc'ed memory will never be freed
496       }
497     }
498     if (defaults_setting) {
499       CFRelease(defaults_setting);
500     }
501   }
502
503   // When g_dbgshell_command is NULL, the user has not enabled the use of an
504   // external program to find the symbols, don't run it for them.
505   if (!force_lookup && g_dbgshell_command == NULL) {
506     return false;
507   }
508
509   if (uuid_ptr ||
510       (file_spec_ptr && FileSystem::Instance().Exists(*file_spec_ptr))) {
511     static bool g_located_dsym_for_uuid_exe = false;
512     static bool g_dsym_for_uuid_exe_exists = false;
513     static char g_dsym_for_uuid_exe_path[PATH_MAX];
514     if (!g_located_dsym_for_uuid_exe) {
515       g_located_dsym_for_uuid_exe = true;
516       const char *dsym_for_uuid_exe_path_cstr =
517           getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
518       FileSpec dsym_for_uuid_exe_spec;
519       if (dsym_for_uuid_exe_path_cstr) {
520         dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr,
521                                        FileSpec::Style::native);
522         FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
523         g_dsym_for_uuid_exe_exists =
524             FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
525       }
526
527       if (!g_dsym_for_uuid_exe_exists) {
528         dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID",
529                                        FileSpec::Style::native);
530         g_dsym_for_uuid_exe_exists =
531             FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
532         if (!g_dsym_for_uuid_exe_exists) {
533           long bufsize;
534           if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) {
535             char buffer[bufsize];
536             struct passwd pwd;
537             struct passwd *tilde_rc = NULL;
538             // we are a library so we need to use the reentrant version of
539             // getpwnam()
540             if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 &&
541                 tilde_rc && tilde_rc->pw_dir) {
542               std::string dsymforuuid_path(tilde_rc->pw_dir);
543               dsymforuuid_path += "/bin/dsymForUUID";
544               dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(),
545                                              FileSpec::Style::native);
546               g_dsym_for_uuid_exe_exists =
547                   FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
548             }
549           }
550         }
551       }
552       if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) {
553         dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command,
554                                        FileSpec::Style::native);
555         FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
556         g_dsym_for_uuid_exe_exists =
557             FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
558       }
559
560       if (g_dsym_for_uuid_exe_exists)
561         dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path,
562                                        sizeof(g_dsym_for_uuid_exe_path));
563     }
564     if (g_dsym_for_uuid_exe_exists) {
565       std::string uuid_str;
566       char file_path[PATH_MAX];
567       file_path[0] = '\0';
568
569       if (uuid_ptr)
570         uuid_str = uuid_ptr->GetAsString();
571
572       if (file_spec_ptr)
573         file_spec_ptr->GetPath(file_path, sizeof(file_path));
574
575       StreamString command;
576       if (!uuid_str.empty())
577         command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
578                        g_dsym_for_uuid_exe_path, uuid_str.c_str());
579       else if (file_path[0] != '\0')
580         command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
581                        g_dsym_for_uuid_exe_path, file_path);
582
583       if (!command.GetString().empty()) {
584         Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
585         int exit_status = -1;
586         int signo = -1;
587         std::string command_output;
588         if (log) {
589           if (!uuid_str.empty())
590             LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM",
591                       g_dsym_for_uuid_exe_path, uuid_str.c_str());
592           else if (file_path[0] != '\0')
593             LLDB_LOGF(log, "Calling %s with file %s to find dSYM",
594                       g_dsym_for_uuid_exe_path, file_path);
595         }
596         Status error = Host::RunShellCommand(
597             command.GetData(),
598             NULL,            // current working directory
599             &exit_status,    // Exit status
600             &signo,          // Signal int *
601             &command_output, // Command output
602             std::chrono::seconds(
603                120), // Large timeout to allow for long dsym download times
604             false);  // Don't run in a shell (we don't need shell expansion)
605         if (error.Success() && exit_status == 0 && !command_output.empty()) {
606           CFCData data(CFDataCreateWithBytesNoCopy(
607               NULL, (const UInt8 *)command_output.data(), command_output.size(),
608               kCFAllocatorNull));
609
610           CFCReleaser<CFDictionaryRef> plist(
611               (CFDictionaryRef)::CFPropertyListCreateFromXMLData(
612                   NULL, data.get(), kCFPropertyListImmutable, NULL));
613
614           if (plist.get() &&
615               CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) {
616             if (!uuid_str.empty()) {
617               CFCString uuid_cfstr(uuid_str.c_str());
618               CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue(
619                   plist.get(), uuid_cfstr.get());
620               success =
621                   GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec);
622             } else {
623               const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
624               if (num_values > 0) {
625                 std::vector<CFStringRef> keys(num_values, NULL);
626                 std::vector<CFDictionaryRef> values(num_values, NULL);
627                 ::CFDictionaryGetKeysAndValues(plist.get(), NULL,
628                                                (const void **)&values[0]);
629                 if (num_values == 1) {
630                   return GetModuleSpecInfoFromUUIDDictionary(values[0],
631                                                              module_spec);
632                 } else {
633                   for (CFIndex i = 0; i < num_values; ++i) {
634                     ModuleSpec curr_module_spec;
635                     if (GetModuleSpecInfoFromUUIDDictionary(values[i],
636                                                             curr_module_spec)) {
637                       if (module_spec.GetArchitecture().IsCompatibleMatch(
638                               curr_module_spec.GetArchitecture())) {
639                         module_spec = curr_module_spec;
640                         return true;
641                       }
642                     }
643                   }
644                 }
645               }
646             }
647           }
648         } else {
649           if (log) {
650             if (!uuid_str.empty())
651               LLDB_LOGF(log, "Called %s on %s, no matches",
652                         g_dsym_for_uuid_exe_path, uuid_str.c_str());
653             else if (file_path[0] != '\0')
654               LLDB_LOGF(log, "Called %s on %s, no matches",
655                         g_dsym_for_uuid_exe_path, file_path);
656           }
657         }
658       }
659     }
660   }
661   return success;
662 }