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