• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Symbols.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/Symbols.h"
11 
12 // C Includes
13 #include <dirent.h>
14 #include <pwd.h>
15 #include "llvm/Support/MachO.h"
16 
17 // C++ Includes
18 // Other libraries and framework includes
19 #include <CoreFoundation/CoreFoundation.h>
20 
21 // Project includes
22 #include "lldb/Core/ArchSpec.h"
23 #include "lldb/Core/DataBuffer.h"
24 #include "lldb/Core/DataExtractor.h"
25 #include "lldb/Core/Module.h"
26 #include "lldb/Core/ModuleSpec.h"
27 #include "lldb/Core/StreamString.h"
28 #include "lldb/Core/Timer.h"
29 #include "lldb/Core/UUID.h"
30 #include "lldb/Host/Endian.h"
31 #include "lldb/Host/Host.h"
32 #include "lldb/Utility/CleanUp.h"
33 #include "Host/macosx/cfcpp/CFCBundle.h"
34 #include "Host/macosx/cfcpp/CFCData.h"
35 #include "Host/macosx/cfcpp/CFCReleaser.h"
36 #include "Host/macosx/cfcpp/CFCString.h"
37 #include "mach/machine.h"
38 
39 
40 using namespace lldb;
41 using namespace lldb_private;
42 using namespace llvm::MachO;
43 
44 #if !defined (__arm__) // No DebugSymbols on the iOS devices
45 extern "C" {
46 
47 CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url);
48 CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url);
49 
50 }
51 #endif
52 
53 static bool
SkinnyMachOFileContainsArchAndUUID(const FileSpec & file_spec,const ArchSpec * arch,const lldb_private::UUID * uuid,off_t file_offset,DataExtractor & data,lldb::offset_t data_offset,const uint32_t magic)54 SkinnyMachOFileContainsArchAndUUID
55 (
56     const FileSpec &file_spec,
57     const ArchSpec *arch,
58     const lldb_private::UUID *uuid,   // the UUID we are looking for
59     off_t file_offset,
60     DataExtractor& data,
61     lldb::offset_t data_offset,
62     const uint32_t magic
63 )
64 {
65     assert(magic == HeaderMagic32 || magic == HeaderMagic32Swapped || magic == HeaderMagic64 || magic == HeaderMagic64Swapped);
66     if (magic == HeaderMagic32 || magic == HeaderMagic64)
67         data.SetByteOrder (lldb::endian::InlHostByteOrder());
68     else if (lldb::endian::InlHostByteOrder() == eByteOrderBig)
69         data.SetByteOrder (eByteOrderLittle);
70     else
71         data.SetByteOrder (eByteOrderBig);
72 
73     uint32_t i;
74     const uint32_t cputype      = data.GetU32(&data_offset);    // cpu specifier
75     const uint32_t cpusubtype   = data.GetU32(&data_offset);    // machine specifier
76     data_offset+=4; // Skip mach file type
77     const uint32_t ncmds        = data.GetU32(&data_offset);    // number of load commands
78     const uint32_t sizeofcmds   = data.GetU32(&data_offset);    // the size of all the load commands
79     data_offset+=4; // Skip flags
80 
81     // Check the architecture if we have a valid arch pointer
82     if (arch)
83     {
84         ArchSpec file_arch(eArchTypeMachO, cputype, cpusubtype);
85 
86         if (!file_arch.IsCompatibleMatch(*arch))
87             return false;
88     }
89 
90     // The file exists, and if a valid arch pointer was passed in we know
91     // if already matches, so we can return if we aren't looking for a specific
92     // UUID
93     if (uuid == NULL)
94         return true;
95 
96     if (magic == HeaderMagic64Swapped || magic == HeaderMagic64)
97         data_offset += 4;   // Skip reserved field for in mach_header_64
98 
99     // Make sure we have enough data for all the load commands
100     if (magic == HeaderMagic64Swapped || magic == HeaderMagic64)
101     {
102         if (data.GetByteSize() < sizeof(struct mach_header_64) + sizeofcmds)
103         {
104             DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header_64) + sizeofcmds));
105             data.SetData (data_buffer_sp);
106         }
107     }
108     else
109     {
110         if (data.GetByteSize() < sizeof(struct mach_header) + sizeofcmds)
111         {
112             DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header) + sizeofcmds));
113             data.SetData (data_buffer_sp);
114         }
115     }
116 
117     for (i=0; i<ncmds; i++)
118     {
119         const lldb::offset_t cmd_offset = data_offset;    // Save this data_offset in case parsing of the segment goes awry!
120         uint32_t cmd        = data.GetU32(&data_offset);
121         uint32_t cmd_size   = data.GetU32(&data_offset);
122         if (cmd == LoadCommandUUID)
123         {
124             lldb_private::UUID file_uuid (data.GetData(&data_offset, 16), 16);
125             if (file_uuid == *uuid)
126                 return true;
127             return false;
128         }
129         data_offset = cmd_offset + cmd_size;
130     }
131     return false;
132 }
133 
134 bool
UniversalMachOFileContainsArchAndUUID(const FileSpec & file_spec,const ArchSpec * arch,const lldb_private::UUID * uuid,off_t file_offset,DataExtractor & data,lldb::offset_t data_offset,const uint32_t magic)135 UniversalMachOFileContainsArchAndUUID
136 (
137     const FileSpec &file_spec,
138     const ArchSpec *arch,
139     const lldb_private::UUID *uuid,
140     off_t file_offset,
141     DataExtractor& data,
142     lldb::offset_t data_offset,
143     const uint32_t magic
144 )
145 {
146     assert(magic == UniversalMagic || magic == UniversalMagicSwapped);
147 
148     // Universal mach-o files always have their headers encoded as BIG endian
149     data.SetByteOrder(eByteOrderBig);
150 
151     uint32_t i;
152     const uint32_t nfat_arch = data.GetU32(&data_offset);   // number of structs that follow
153     const uint32_t fat_header_and_arch_size = sizeof(struct fat_header) + nfat_arch * sizeof(struct fat_arch);
154     if (data.GetByteSize() < fat_header_and_arch_size)
155     {
156         DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, fat_header_and_arch_size));
157         data.SetData (data_buffer_sp);
158     }
159 
160     for (i=0; i<nfat_arch; i++)
161     {
162         cpu_type_t      arch_cputype        = data.GetU32(&data_offset);    // cpu specifier (int)
163         cpu_subtype_t   arch_cpusubtype     = data.GetU32(&data_offset);    // machine specifier (int)
164         uint32_t        arch_offset         = data.GetU32(&data_offset);    // file offset to this object file
165     //  uint32_t        arch_size           = data.GetU32(&data_offset);    // size of this object file
166     //  uint32_t        arch_align          = data.GetU32(&data_offset);    // alignment as a power of 2
167         data_offset += 8;   // Skip size and align as we don't need those
168         // Only process this slice if the cpu type/subtype matches
169         if (arch)
170         {
171             ArchSpec fat_arch(eArchTypeMachO, arch_cputype, arch_cpusubtype);
172             if (!fat_arch.IsExactMatch(*arch))
173                 continue;
174         }
175 
176         // Create a buffer with only the arch slice date in it
177         DataExtractor arch_data;
178         DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset + arch_offset, 0x1000));
179         arch_data.SetData(data_buffer_sp);
180         lldb::offset_t arch_data_offset = 0;
181         uint32_t arch_magic = arch_data.GetU32(&arch_data_offset);
182 
183         switch (arch_magic)
184         {
185         case HeaderMagic32:
186         case HeaderMagic32Swapped:
187         case HeaderMagic64:
188         case HeaderMagic64Swapped:
189             if (SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset + arch_offset, arch_data, arch_data_offset, arch_magic))
190                 return true;
191             break;
192         }
193     }
194     return false;
195 }
196 
197 static bool
FileAtPathContainsArchAndUUID(const FileSpec & file_spec,const ArchSpec * arch,const lldb_private::UUID * uuid)198 FileAtPathContainsArchAndUUID
199 (
200     const FileSpec &file_spec,
201     const ArchSpec *arch,
202     const lldb_private::UUID *uuid
203 )
204 {
205     DataExtractor data;
206     off_t file_offset = 0;
207     DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, 0x1000));
208 
209     if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0)
210     {
211         data.SetData(data_buffer_sp);
212 
213         lldb::offset_t data_offset = 0;
214         uint32_t magic = data.GetU32(&data_offset);
215 
216         switch (magic)
217         {
218         // 32 bit mach-o file
219         case HeaderMagic32:
220         case HeaderMagic32Swapped:
221         case HeaderMagic64:
222         case HeaderMagic64Swapped:
223             return SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
224 
225         // fat mach-o file
226         case UniversalMagic:
227         case UniversalMagicSwapped:
228             return UniversalMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
229 
230         default:
231             break;
232         }
233     }
234     return false;
235 }
236 
237 FileSpec
FindSymbolFileInBundle(const FileSpec & dsym_bundle_fspec,const lldb_private::UUID * uuid,const ArchSpec * arch)238 Symbols::FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec,
239                                  const lldb_private::UUID *uuid,
240                                  const ArchSpec *arch)
241 {
242     char path[PATH_MAX];
243 
244     FileSpec dsym_fspec;
245 
246     if (dsym_bundle_fspec.GetPath(path, sizeof(path)))
247     {
248         ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
249 
250         lldb_utility::CleanUp <DIR *, int> dirp (opendir(path), NULL, closedir);
251         if (dirp.is_valid())
252         {
253             dsym_fspec.GetDirectory().SetCString(path);
254             struct dirent* dp;
255             while ((dp = readdir(dirp.get())) != NULL)
256             {
257                 // Only search directories
258                 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
259                 {
260                     if (dp->d_namlen == 1 && dp->d_name[0] == '.')
261                         continue;
262 
263                     if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
264                         continue;
265                 }
266 
267                 if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN)
268                 {
269                     dsym_fspec.GetFilename().SetCString(dp->d_name);
270                     if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid))
271                         return dsym_fspec;
272                 }
273             }
274         }
275     }
276     dsym_fspec.Clear();
277     return dsym_fspec;
278 }
279 
280 static int
LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec & module_spec,FileSpec * out_exec_fspec,FileSpec * out_dsym_fspec)281 LocateMacOSXFilesUsingDebugSymbols
282 (
283     const ModuleSpec &module_spec,
284     FileSpec *out_exec_fspec,   // If non-NULL, try and find the executable
285     FileSpec *out_dsym_fspec    // If non-NULL try and find the debug symbol file
286 )
287 {
288     int items_found = 0;
289 
290     if (out_exec_fspec)
291         out_exec_fspec->Clear();
292 
293     if (out_dsym_fspec)
294         out_dsym_fspec->Clear();
295 
296 #if !defined (__arm__) // No DebugSymbols on the iOS devices
297 
298     const UUID *uuid = module_spec.GetUUIDPtr();
299     const ArchSpec *arch = module_spec.GetArchitecturePtr();
300 
301     if (uuid && uuid->IsValid())
302     {
303         // Try and locate the dSYM file using DebugSymbols first
304         const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
305         if (module_uuid != NULL)
306         {
307             CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes (NULL,
308                                                                             module_uuid[0],
309                                                                             module_uuid[1],
310                                                                             module_uuid[2],
311                                                                             module_uuid[3],
312                                                                             module_uuid[4],
313                                                                             module_uuid[5],
314                                                                             module_uuid[6],
315                                                                             module_uuid[7],
316                                                                             module_uuid[8],
317                                                                             module_uuid[9],
318                                                                             module_uuid[10],
319                                                                             module_uuid[11],
320                                                                             module_uuid[12],
321                                                                             module_uuid[13],
322                                                                             module_uuid[14],
323                                                                             module_uuid[15]));
324 
325             if (module_uuid_ref.get())
326             {
327                 CFCReleaser<CFURLRef> exec_url;
328                 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
329                 if (exec_fspec)
330                 {
331                     char exec_cf_path[PATH_MAX];
332                     if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
333                         exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL,
334                                                                                   (const UInt8 *)exec_cf_path,
335                                                                                   strlen(exec_cf_path),
336                                                                                   FALSE));
337                 }
338 
339                 CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
340                 char path[PATH_MAX];
341 
342                 if (dsym_url.get())
343                 {
344                     if (out_dsym_fspec)
345                     {
346                         if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
347                         {
348                             out_dsym_fspec->SetFile(path, path[0] == '~');
349 
350                             if (out_dsym_fspec->GetFileType () == FileSpec::eFileTypeDirectory)
351                             {
352                                 *out_dsym_fspec = Symbols::FindSymbolFileInBundle (*out_dsym_fspec, uuid, arch);
353                                 if (*out_dsym_fspec)
354                                     ++items_found;
355                             }
356                             else
357                             {
358                                 ++items_found;
359                             }
360                         }
361                     }
362 
363                     CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));
364                     CFDictionaryRef uuid_dict = NULL;
365                     if (dict.get())
366                     {
367                         CFCString uuid_cfstr (uuid->GetAsString().c_str());
368                         uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get()));
369                         if (uuid_dict)
370                         {
371 
372                             CFStringRef actual_src_cfpath = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSourcePath")));
373                             if (actual_src_cfpath)
374                             {
375                                 CFStringRef build_src_cfpath = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGBuildSourcePath")));
376                                 if (build_src_cfpath)
377                                 {
378                                     char actual_src_path[PATH_MAX];
379                                     char build_src_path[PATH_MAX];
380                                     ::CFStringGetFileSystemRepresentation (actual_src_cfpath, actual_src_path, sizeof(actual_src_path));
381                                     ::CFStringGetFileSystemRepresentation (build_src_cfpath, build_src_path, sizeof(build_src_path));
382                                     if (actual_src_path[0] == '~')
383                                     {
384                                         FileSpec resolved_source_path(actual_src_path, true);
385                                         resolved_source_path.GetPath(actual_src_path, sizeof(actual_src_path));
386                                     }
387                                     module_spec.GetSourceMappingList().Append (ConstString(build_src_path), ConstString(actual_src_path), true);
388                                 }
389                             }
390                         }
391                     }
392 
393                     if (out_exec_fspec)
394                     {
395                         bool success = false;
396                         if (uuid_dict)
397                         {
398                             CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable")));
399                             if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path)))
400                             {
401                                 ++items_found;
402                                 out_exec_fspec->SetFile(path, path[0] == '~');
403                                 if (out_exec_fspec->Exists())
404                                     success = true;
405                             }
406                         }
407 
408                         if (!success)
409                         {
410                             // No dictionary, check near the dSYM bundle for an executable that matches...
411                             if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
412                             {
413                                 char *dsym_extension_pos = ::strstr (path, ".dSYM");
414                                 if (dsym_extension_pos)
415                                 {
416                                     *dsym_extension_pos = '\0';
417                                     FileSpec file_spec (path, true);
418                                     switch (file_spec.GetFileType())
419                                     {
420                                         case FileSpec::eFileTypeDirectory:  // Bundle directory?
421                                             {
422                                                 CFCBundle bundle (path);
423                                                 CFCReleaser<CFURLRef> bundle_exe_url (bundle.CopyExecutableURL ());
424                                                 if (bundle_exe_url.get())
425                                                 {
426                                                     if (::CFURLGetFileSystemRepresentation (bundle_exe_url.get(), true, (UInt8*)path, sizeof(path)-1))
427                                                     {
428                                                         FileSpec bundle_exe_file_spec (path, true);
429 
430                                                         if (FileAtPathContainsArchAndUUID (bundle_exe_file_spec, arch, uuid))
431                                                         {
432                                                             ++items_found;
433                                                             *out_exec_fspec = bundle_exe_file_spec;
434                                                         }
435                                                     }
436                                                 }
437                                             }
438                                             break;
439 
440                                         case FileSpec::eFileTypePipe:       // Forget pipes
441                                         case FileSpec::eFileTypeSocket:     // We can't process socket files
442                                         case FileSpec::eFileTypeInvalid:    // File doesn't exist...
443                                             break;
444 
445                                         case FileSpec::eFileTypeUnknown:
446                                         case FileSpec::eFileTypeRegular:
447                                         case FileSpec::eFileTypeSymbolicLink:
448                                         case FileSpec::eFileTypeOther:
449                                             if (FileAtPathContainsArchAndUUID (file_spec, arch, uuid))
450                                             {
451                                                 ++items_found;
452                                                 *out_exec_fspec = file_spec;
453                                             }
454                                             break;
455                                     }
456                                 }
457                             }
458                         }
459                     }
460                 }
461             }
462         }
463     }
464 #endif // #if !defined (__arm__)
465 
466     return items_found;
467 }
468 
469 static bool
LocateDSYMInVincinityOfExecutable(const ModuleSpec & module_spec,FileSpec & dsym_fspec)470 LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec)
471 {
472     const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
473     if (exec_fspec)
474     {
475         char path[PATH_MAX];
476         if (exec_fspec->GetPath(path, sizeof(path)))
477         {
478             // Make sure the module isn't already just a dSYM file...
479             if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
480             {
481                 size_t obj_file_path_length = strlen(path);
482                 strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
483                 strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
484 
485                 dsym_fspec.SetFile(path, false);
486 
487                 if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
488                 {
489                     return true;
490                 }
491                 else
492                 {
493                     path[obj_file_path_length] = '\0';
494 
495                     char *last_dot = strrchr(path, '.');
496                     while (last_dot != NULL && last_dot[0])
497                     {
498                         char *next_slash = strchr(last_dot, '/');
499                         if (next_slash != NULL)
500                         {
501                             *next_slash = '\0';
502                             strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
503                             strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
504                             dsym_fspec.SetFile(path, false);
505                             if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
506                                 return true;
507                             else
508                             {
509                                 *last_dot = '\0';
510                                 char *prev_slash = strrchr(path, '/');
511                                 if (prev_slash != NULL)
512                                     *prev_slash = '\0';
513                                 else
514                                     break;
515                             }
516                         }
517                         else
518                         {
519                             break;
520                         }
521                     }
522                 }
523             }
524         }
525     }
526     dsym_fspec.Clear();
527     return false;
528 }
529 
530 FileSpec
LocateExecutableObjectFile(const ModuleSpec & module_spec)531 Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
532 {
533     const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
534     const ArchSpec *arch = module_spec.GetArchitecturePtr();
535     const UUID *uuid = module_spec.GetUUIDPtr();
536     Timer scoped_timer (__PRETTY_FUNCTION__,
537                         "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
538                         exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
539                         arch ? arch->GetArchitectureName() : "<NULL>",
540                         uuid);
541 
542     FileSpec objfile_fspec;
543     if (exec_fspec && FileAtPathContainsArchAndUUID (exec_fspec, arch, uuid))
544         objfile_fspec = exec_fspec;
545     else
546         LocateMacOSXFilesUsingDebugSymbols (module_spec, &objfile_fspec, NULL);
547     return objfile_fspec;
548 }
549 
550 FileSpec
LocateExecutableSymbolFile(const ModuleSpec & module_spec)551 Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
552 {
553     const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
554     const ArchSpec *arch = module_spec.GetArchitecturePtr();
555     const UUID *uuid = module_spec.GetUUIDPtr();
556 
557     Timer scoped_timer (__PRETTY_FUNCTION__,
558                         "LocateExecutableSymbolFile (file = %s, arch = %s, uuid = %p)",
559                         exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
560                         arch ? arch->GetArchitectureName() : "<NULL>",
561                         uuid);
562 
563     FileSpec symbol_fspec;
564     // First try and find the dSYM in the same directory as the executable or in
565     // an appropriate parent directory
566     if (LocateDSYMInVincinityOfExecutable (module_spec, symbol_fspec) == false)
567     {
568         // We failed to easily find the dSYM above, so use DebugSymbols
569         LocateMacOSXFilesUsingDebugSymbols (module_spec, NULL, &symbol_fspec);
570     }
571     return symbol_fspec;
572 }
573 
574 
575 static bool
GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,ModuleSpec & module_spec)576 GetModuleSpecInfoFromUUIDDictionary (CFDictionaryRef uuid_dict, ModuleSpec &module_spec)
577 {
578     bool success = false;
579     if (uuid_dict != NULL && CFGetTypeID (uuid_dict) == CFDictionaryGetTypeID ())
580     {
581         std::string str;
582         CFStringRef cf_str;
583 
584         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable"));
585         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
586         {
587             if (CFCString::FileSystemRepresentation(cf_str, str))
588                 module_spec.GetFileSpec().SetFile (str.c_str(), true);
589         }
590 
591         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGDSYMPath"));
592         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
593         {
594             if (CFCString::FileSystemRepresentation(cf_str, str))
595             {
596                 module_spec.GetSymbolFileSpec().SetFile (str.c_str(), true);
597                 success = true;
598             }
599         }
600 
601         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGArchitecture"));
602         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
603         {
604             if (CFCString::FileSystemRepresentation(cf_str, str))
605                 module_spec.GetArchitecture().SetTriple(str.c_str());
606         }
607 
608         std::string DBGBuildSourcePath;
609         std::string DBGSourcePath;
610 
611         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGBuildSourcePath"));
612         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
613         {
614             CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
615         }
616 
617         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSourcePath"));
618         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
619         {
620             CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
621         }
622 
623         if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
624         {
625             module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true);
626         }
627     }
628     return success;
629 }
630 
631 
632 bool
DownloadObjectAndSymbolFile(ModuleSpec & module_spec,bool force_lookup)633 Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
634 {
635     bool success = false;
636     const UUID *uuid_ptr = module_spec.GetUUIDPtr();
637     const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
638 
639     // It's expensive to check for the DBGShellCommands defaults setting, only do it once per
640     // lldb run and cache the result.
641     static bool g_have_checked_for_dbgshell_command = false;
642     static const char *g_dbgshell_command = NULL;
643     if (g_have_checked_for_dbgshell_command == false)
644     {
645         g_have_checked_for_dbgshell_command = true;
646         CFTypeRef defaults_setting = CFPreferencesCopyAppValue (CFSTR ("DBGShellCommands"), CFSTR ("com.apple.DebugSymbols"));
647         if (defaults_setting && CFGetTypeID (defaults_setting) == CFStringGetTypeID())
648         {
649             char cstr_buf[PATH_MAX];
650             if (CFStringGetCString ((CFStringRef) defaults_setting, cstr_buf, sizeof (cstr_buf), kCFStringEncodingUTF8))
651             {
652                 g_dbgshell_command = strdup (cstr_buf);  // this malloc'ed memory will never be freed
653             }
654         }
655         if (defaults_setting)
656         {
657             CFRelease (defaults_setting);
658         }
659     }
660 
661     // When g_dbgshell_command is NULL, the user has not enabled the use of an external program
662     // to find the symbols, don't run it for them.
663     if (force_lookup == false && g_dbgshell_command == NULL)
664     {
665         return false;
666     }
667 
668     if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists()))
669     {
670         static bool g_located_dsym_for_uuid_exe = false;
671         static bool g_dsym_for_uuid_exe_exists = false;
672         static char g_dsym_for_uuid_exe_path[PATH_MAX];
673         if (!g_located_dsym_for_uuid_exe)
674         {
675             g_located_dsym_for_uuid_exe = true;
676             const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
677             FileSpec dsym_for_uuid_exe_spec;
678             if (dsym_for_uuid_exe_path_cstr)
679             {
680                 dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true);
681                 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
682             }
683 
684             if (!g_dsym_for_uuid_exe_exists)
685             {
686                 dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false);
687                 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
688                 if (!g_dsym_for_uuid_exe_exists)
689                 {
690                     long bufsize;
691                     if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1)
692                     {
693                         char buffer[bufsize];
694                         struct passwd pwd;
695                         struct passwd *tilde_rc = NULL;
696                         // we are a library so we need to use the reentrant version of getpwnam()
697                         if (getpwnam_r ("rc", &pwd, buffer, bufsize, &tilde_rc) == 0
698                             && tilde_rc
699                             && tilde_rc->pw_dir)
700                         {
701                             std::string dsymforuuid_path(tilde_rc->pw_dir);
702                             dsymforuuid_path += "/bin/dsymForUUID";
703                             dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false);
704                             g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
705                         }
706                     }
707                 }
708             }
709             if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL)
710             {
711                 dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true);
712                 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
713             }
714 
715             if (g_dsym_for_uuid_exe_exists)
716                 dsym_for_uuid_exe_spec.GetPath (g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path));
717         }
718         if (g_dsym_for_uuid_exe_exists)
719         {
720             std::string uuid_str;
721             char file_path[PATH_MAX];
722             file_path[0] = '\0';
723 
724             if (uuid_ptr)
725                 uuid_str = uuid_ptr->GetAsString();
726 
727             if (file_spec_ptr)
728                 file_spec_ptr->GetPath(file_path, sizeof(file_path));
729 
730             StreamString command;
731             if (!uuid_str.empty())
732                 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, uuid_str.c_str());
733             else if (file_path && file_path[0])
734                 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, file_path);
735 
736             if (!command.GetString().empty())
737             {
738                 int exit_status = -1;
739                 int signo = -1;
740                 std::string command_output;
741                 Error error = Host::RunShellCommand (command.GetData(),
742                                                      NULL,              // current working directory
743                                                      &exit_status,      // Exit status
744                                                      &signo,            // Signal int *
745                                                      &command_output,   // Command output
746                                                      30,                // Large timeout to allow for long dsym download times
747                                                      NULL);             // Don't run in a shell (we don't need shell expansion)
748                 if (error.Success() && exit_status == 0 && !command_output.empty())
749                 {
750                     CFCData data (CFDataCreateWithBytesNoCopy (NULL,
751                                                                (const UInt8 *)command_output.data(),
752                                                                command_output.size(),
753                                                                kCFAllocatorNull));
754 
755                     CFCReleaser<CFDictionaryRef> plist((CFDictionaryRef)::CFPropertyListCreateFromXMLData (NULL, data.get(), kCFPropertyListImmutable, NULL));
756 
757                     if (plist.get() && CFGetTypeID (plist.get()) == CFDictionaryGetTypeID ())
758                     {
759                         if (!uuid_str.empty())
760                         {
761                             CFCString uuid_cfstr(uuid_str.c_str());
762                             CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue (plist.get(), uuid_cfstr.get());
763                             success = GetModuleSpecInfoFromUUIDDictionary (uuid_dict, module_spec);
764                         }
765                         else
766                         {
767                             const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
768                             if (num_values > 0)
769                             {
770                                 std::vector<CFStringRef> keys (num_values, NULL);
771                                 std::vector<CFDictionaryRef> values (num_values, NULL);
772                                 ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]);
773                                 if (num_values == 1)
774                                 {
775                                     return GetModuleSpecInfoFromUUIDDictionary (values[0], module_spec);
776                                 }
777                                 else
778                                 {
779                                     for (CFIndex i=0; i<num_values; ++i)
780                                     {
781                                         ModuleSpec curr_module_spec;
782                                         if (GetModuleSpecInfoFromUUIDDictionary (values[i], curr_module_spec))
783                                         {
784                                             if (module_spec.GetArchitecture().IsCompatibleMatch(curr_module_spec.GetArchitecture()))
785                                             {
786                                                 module_spec = curr_module_spec;
787                                                 return true;
788                                             }
789                                         }
790                                     }
791                                 }
792                             }
793                         }
794                     }
795                 }
796             }
797         }
798     }
799     return success;
800 }
801 
802