forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			560 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			560 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- Symbols.cpp ---------------------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "lldb/Host/Symbols.h"
 | |
| 
 | |
| // C Includes
 | |
| #include <dirent.h>
 | |
| #include <pwd.h>
 | |
| #include "lldb/Utility/SafeMachO.h"
 | |
| 
 | |
| // C++ Includes
 | |
| // Other libraries and framework includes
 | |
| #include <CoreFoundation/CoreFoundation.h>
 | |
| 
 | |
| // Project includes
 | |
| #include "lldb/Core/ArchSpec.h"
 | |
| #include "lldb/Core/DataBuffer.h"
 | |
| #include "lldb/Core/DataExtractor.h"
 | |
| #include "lldb/Core/Log.h"
 | |
| #include "lldb/Core/Module.h"
 | |
| #include "lldb/Core/ModuleSpec.h"
 | |
| #include "lldb/Core/StreamString.h"
 | |
| #include "lldb/Core/Timer.h"
 | |
| #include "lldb/Core/UUID.h"
 | |
| #include "lldb/Host/Endian.h"
 | |
| #include "lldb/Host/Host.h"
 | |
| #include "lldb/Symbol/ObjectFile.h"
 | |
| #include "lldb/Utility/CleanUp.h"
 | |
| #include "Host/macosx/cfcpp/CFCBundle.h"
 | |
| #include "Host/macosx/cfcpp/CFCData.h"
 | |
| #include "Host/macosx/cfcpp/CFCReleaser.h"
 | |
| #include "Host/macosx/cfcpp/CFCString.h"
 | |
| #include "mach/machine.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| using namespace llvm::MachO;
 | |
| 
 | |
| #if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__) // No DebugSymbols on the iOS devices
 | |
| extern "C" {
 | |
| 
 | |
| CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url);
 | |
| CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url);
 | |
| 
 | |
| }
 | |
| #endif
 | |
| 
 | |
| int
 | |
| LocateMacOSXFilesUsingDebugSymbols
 | |
| (
 | |
|     const ModuleSpec &module_spec,
 | |
|     ModuleSpec &return_module_spec
 | |
| )
 | |
| {
 | |
|     return_module_spec = module_spec;
 | |
|     return_module_spec.GetFileSpec().Clear();
 | |
|     return_module_spec.GetSymbolFileSpec().Clear();
 | |
| 
 | |
|     int items_found = 0;
 | |
| 
 | |
| #if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__) // No DebugSymbols on the iOS devices
 | |
| 
 | |
|     const UUID *uuid = module_spec.GetUUIDPtr();
 | |
|     const ArchSpec *arch = module_spec.GetArchitecturePtr();
 | |
| 
 | |
|     if (uuid && uuid->IsValid())
 | |
|     {
 | |
|         // Try and locate the dSYM file using DebugSymbols first
 | |
|         const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
 | |
|         if (module_uuid != NULL)
 | |
|         {
 | |
|             CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes (NULL,
 | |
|                                                                             module_uuid[0],
 | |
|                                                                             module_uuid[1],
 | |
|                                                                             module_uuid[2],
 | |
|                                                                             module_uuid[3],
 | |
|                                                                             module_uuid[4],
 | |
|                                                                             module_uuid[5],
 | |
|                                                                             module_uuid[6],
 | |
|                                                                             module_uuid[7],
 | |
|                                                                             module_uuid[8],
 | |
|                                                                             module_uuid[9],
 | |
|                                                                             module_uuid[10],
 | |
|                                                                             module_uuid[11],
 | |
|                                                                             module_uuid[12],
 | |
|                                                                             module_uuid[13],
 | |
|                                                                             module_uuid[14],
 | |
|                                                                             module_uuid[15]));
 | |
| 
 | |
|             if (module_uuid_ref.get())
 | |
|             {
 | |
|                 CFCReleaser<CFURLRef> exec_url;
 | |
|                 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
 | |
|                 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
 | |
|                 if (exec_fspec)
 | |
|                 {
 | |
|                     char exec_cf_path[PATH_MAX];
 | |
|                     if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
 | |
|                         exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL,
 | |
|                                                                                   (const UInt8 *)exec_cf_path,
 | |
|                                                                                   strlen(exec_cf_path),
 | |
|                                                                                   FALSE));
 | |
|                 }
 | |
| 
 | |
|                 CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
 | |
|                 char path[PATH_MAX];
 | |
| 
 | |
|                 if (dsym_url.get())
 | |
|                 {
 | |
|                     if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
 | |
|                     {
 | |
|                         if (log)
 | |
|                         {
 | |
|                             log->Printf ("DebugSymbols framework returned dSYM path of %s for UUID %s -- looking for the dSYM", path, uuid->GetAsString().c_str());
 | |
|                         }
 | |
|                         FileSpec dsym_filespec(path, path[0] == '~');
 | |
| 
 | |
|                         if (dsym_filespec.GetFileType () == FileSpec::eFileTypeDirectory)
 | |
|                         {
 | |
|                             dsym_filespec = Symbols::FindSymbolFileInBundle (dsym_filespec, uuid, arch);
 | |
|                             ++items_found;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             ++items_found;
 | |
|                         }
 | |
|                         return_module_spec.GetSymbolFileSpec() = dsym_filespec;
 | |
|                     }
 | |
| 
 | |
|                     bool success = false;
 | |
|                     if (log)
 | |
|                     {
 | |
|                         if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
 | |
|                         {
 | |
|                             log->Printf ("DebugSymbols framework returned dSYM path of %s for UUID %s -- looking for an exec file", path, uuid->GetAsString().c_str());
 | |
|                         }
 | |
| 
 | |
|                     }
 | |
| 
 | |
|                     CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));
 | |
|                     CFDictionaryRef uuid_dict = NULL;
 | |
|                     if (dict.get())
 | |
|                     {
 | |
|                         CFCString uuid_cfstr (uuid->GetAsString().c_str());
 | |
|                         uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get()));
 | |
|                     }
 | |
|                     if (uuid_dict)
 | |
|                     {
 | |
|                         CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable")));
 | |
|                         if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path)))
 | |
|                         {
 | |
|                             if (log)
 | |
|                             {
 | |
|                                 log->Printf ("plist bundle has exec path of %s for UUID %s", path, uuid->GetAsString().c_str());
 | |
|                             }
 | |
|                             ++items_found;
 | |
|                             FileSpec exec_filespec (path, path[0] == '~');
 | |
|                             if (exec_filespec.Exists())
 | |
|                             {
 | |
|                                 success = true;
 | |
|                                 return_module_spec.GetFileSpec() = exec_filespec;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if (!success)
 | |
|                     {
 | |
|                         // No dictionary, check near the dSYM bundle for an executable that matches...
 | |
|                         if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
 | |
|                         {
 | |
|                             char *dsym_extension_pos = ::strstr (path, ".dSYM");
 | |
|                             if (dsym_extension_pos)
 | |
|                             {
 | |
|                                 *dsym_extension_pos = '\0';
 | |
|                                 if (log)
 | |
|                                 {
 | |
|                                     log->Printf ("Looking for executable binary next to dSYM bundle with name with name %s", path);
 | |
|                                 }
 | |
|                                 FileSpec file_spec (path, true);
 | |
|                                 ModuleSpecList module_specs;
 | |
|                                 ModuleSpec matched_module_spec;
 | |
|                                 switch (file_spec.GetFileType())
 | |
|                                 {
 | |
|                                     case FileSpec::eFileTypeDirectory:  // Bundle directory?
 | |
|                                         {
 | |
|                                             CFCBundle bundle (path);
 | |
|                                             CFCReleaser<CFURLRef> bundle_exe_url (bundle.CopyExecutableURL ());
 | |
|                                             if (bundle_exe_url.get())
 | |
|                                             {
 | |
|                                                 if (::CFURLGetFileSystemRepresentation (bundle_exe_url.get(), true, (UInt8*)path, sizeof(path)-1))
 | |
|                                                 {
 | |
|                                                     FileSpec bundle_exe_file_spec (path, true);
 | |
|                                                     if (ObjectFile::GetModuleSpecifications(bundle_exe_file_spec, 0, 0, module_specs) &&
 | |
|                                                         module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
 | |
| 
 | |
|                                                     {
 | |
|                                                         ++items_found;
 | |
|                                                         return_module_spec.GetFileSpec() = bundle_exe_file_spec;
 | |
|                                                         if (log)
 | |
|                                                         {
 | |
|                                                             log->Printf ("Executable binary %s next to dSYM is compatible; using", path);
 | |
|                                                         }
 | |
|                                                     }
 | |
|                                                 }
 | |
|                                             }
 | |
|                                         }
 | |
|                                         break;
 | |
| 
 | |
|                                     case FileSpec::eFileTypePipe:       // Forget pipes
 | |
|                                     case FileSpec::eFileTypeSocket:     // We can't process socket files
 | |
|                                     case FileSpec::eFileTypeInvalid:    // File doesn't exist...
 | |
|                                         break;
 | |
| 
 | |
|                                     case FileSpec::eFileTypeUnknown:
 | |
|                                     case FileSpec::eFileTypeRegular:
 | |
|                                     case FileSpec::eFileTypeSymbolicLink:
 | |
|                                     case FileSpec::eFileTypeOther:
 | |
|                                         if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, module_specs) &&
 | |
|                                             module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
 | |
| 
 | |
|                                         {
 | |
|                                             ++items_found;
 | |
|                                             return_module_spec.GetFileSpec() = file_spec;
 | |
|                                             if (log)
 | |
|                                             {
 | |
|                                                 log->Printf ("Executable binary %s next to dSYM is compatible; using", path);
 | |
|                                             }
 | |
|                                         }
 | |
|                                         break;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| #endif // #if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__)
 | |
| 
 | |
|     return items_found;
 | |
| }
 | |
| 
 | |
| FileSpec
 | |
| Symbols::FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec,
 | |
|                                  const lldb_private::UUID *uuid,
 | |
|                                  const ArchSpec *arch)
 | |
| {
 | |
|     char path[PATH_MAX];
 | |
| 
 | |
|     FileSpec dsym_fspec;
 | |
| 
 | |
|     if (dsym_bundle_fspec.GetPath(path, sizeof(path)))
 | |
|     {
 | |
|         ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
 | |
| 
 | |
|         lldb_utility::CleanUp <DIR *, int> dirp (opendir(path), NULL, closedir);
 | |
|         if (dirp.is_valid())
 | |
|         {
 | |
|             dsym_fspec.GetDirectory().SetCString(path);
 | |
|             struct dirent* dp;
 | |
|             while ((dp = readdir(dirp.get())) != NULL)
 | |
|             {
 | |
|                 // Only search directories
 | |
|                 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
 | |
|                 {
 | |
|                     if (dp->d_namlen == 1 && dp->d_name[0] == '.')
 | |
|                         continue;
 | |
| 
 | |
|                     if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
 | |
|                         continue;
 | |
|                 }
 | |
| 
 | |
|                 if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN)
 | |
|                 {
 | |
|                     dsym_fspec.GetFilename().SetCString(dp->d_name);
 | |
|                     ModuleSpecList module_specs;
 | |
|                     if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs))
 | |
|                     {
 | |
|                         ModuleSpec spec;
 | |
|                         for (size_t i = 0; i < module_specs.GetSize(); ++i)
 | |
|                         {
 | |
|                             assert(module_specs.GetModuleSpecAtIndex(i, spec));
 | |
|                             if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
 | |
|                                 (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch))))
 | |
|                             {
 | |
|                                 return dsym_fspec;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     dsym_fspec.Clear();
 | |
|     return dsym_fspec;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| GetModuleSpecInfoFromUUIDDictionary (CFDictionaryRef uuid_dict, ModuleSpec &module_spec)
 | |
| {
 | |
|     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
 | |
|     bool success = false;
 | |
|     if (uuid_dict != NULL && CFGetTypeID (uuid_dict) == CFDictionaryGetTypeID ())
 | |
|     {
 | |
|         std::string str;
 | |
|         CFStringRef cf_str;
 | |
|         
 | |
|         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable"));
 | |
|         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
 | |
|         {
 | |
|             if (CFCString::FileSystemRepresentation(cf_str, str))
 | |
|             {
 | |
|                 module_spec.GetFileSpec().SetFile (str.c_str(), true);
 | |
|                 if (log)
 | |
|                 {
 | |
|                     log->Printf ("From dsymForUUID plist: Symbol rich executable is at '%s'", str.c_str());
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGDSYMPath"));
 | |
|         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
 | |
|         {
 | |
|             if (CFCString::FileSystemRepresentation(cf_str, str))
 | |
|             {
 | |
|                 module_spec.GetSymbolFileSpec().SetFile (str.c_str(), true);
 | |
|                 success = true;
 | |
|                 if (log)
 | |
|                 {
 | |
|                     log->Printf ("From dsymForUUID plist: dSYM is at '%s'", str.c_str());
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGArchitecture"));
 | |
|         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
 | |
|         {
 | |
|             if (CFCString::FileSystemRepresentation(cf_str, str))
 | |
|                 module_spec.GetArchitecture().SetTriple(str.c_str());
 | |
|         }
 | |
| 
 | |
|         std::string DBGBuildSourcePath;
 | |
|         std::string DBGSourcePath;
 | |
| 
 | |
|         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGBuildSourcePath"));
 | |
|         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
 | |
|         {
 | |
|             CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
 | |
|         }
 | |
| 
 | |
|         cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSourcePath"));
 | |
|         if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
 | |
|         {
 | |
|             CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
 | |
|         }
 | |
|         
 | |
|         if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
 | |
|         {
 | |
|             module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true);
 | |
|         }
 | |
|     }
 | |
|     return success;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool
 | |
| Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
 | |
| {
 | |
|     bool success = false;
 | |
|     const UUID *uuid_ptr = module_spec.GetUUIDPtr();
 | |
|     const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
 | |
| 
 | |
|     // It's expensive to check for the DBGShellCommands defaults setting, only do it once per
 | |
|     // lldb run and cache the result.  
 | |
|     static bool g_have_checked_for_dbgshell_command = false;
 | |
|     static const char *g_dbgshell_command = NULL;
 | |
|     if (g_have_checked_for_dbgshell_command == false)
 | |
|     {
 | |
|         g_have_checked_for_dbgshell_command = true;
 | |
|         CFTypeRef defaults_setting = CFPreferencesCopyAppValue (CFSTR ("DBGShellCommands"), CFSTR ("com.apple.DebugSymbols"));
 | |
|         if (defaults_setting && CFGetTypeID (defaults_setting) == CFStringGetTypeID())
 | |
|         { 
 | |
|             char cstr_buf[PATH_MAX];
 | |
|             if (CFStringGetCString ((CFStringRef) defaults_setting, cstr_buf, sizeof (cstr_buf), kCFStringEncodingUTF8))
 | |
|             {
 | |
|                 g_dbgshell_command = strdup (cstr_buf);  // this malloc'ed memory will never be freed
 | |
|             }
 | |
|         }
 | |
|         if (defaults_setting)
 | |
|         {
 | |
|             CFRelease (defaults_setting);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // When g_dbgshell_command is NULL, the user has not enabled the use of an external program
 | |
|     // to find the symbols, don't run it for them.
 | |
|     if (force_lookup == false && g_dbgshell_command == NULL)
 | |
|     {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists()))
 | |
|     {
 | |
|         static bool g_located_dsym_for_uuid_exe = false;
 | |
|         static bool g_dsym_for_uuid_exe_exists = false;
 | |
|         static char g_dsym_for_uuid_exe_path[PATH_MAX];
 | |
|         if (!g_located_dsym_for_uuid_exe)
 | |
|         {
 | |
|             g_located_dsym_for_uuid_exe = true;
 | |
|             const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
 | |
|             FileSpec dsym_for_uuid_exe_spec;
 | |
|             if (dsym_for_uuid_exe_path_cstr)
 | |
|             {
 | |
|                 dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true);
 | |
|                 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
 | |
|             }
 | |
|             
 | |
|             if (!g_dsym_for_uuid_exe_exists)
 | |
|             {
 | |
|                 dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false);
 | |
|                 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
 | |
|                 if (!g_dsym_for_uuid_exe_exists)
 | |
|                 {
 | |
|                     long bufsize;
 | |
|                     if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1)
 | |
|                     {
 | |
|                         char buffer[bufsize];
 | |
|                         struct passwd pwd;
 | |
|                         struct passwd *tilde_rc = NULL;
 | |
|                         // we are a library so we need to use the reentrant version of getpwnam()
 | |
|                         if (getpwnam_r ("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 
 | |
|                             && tilde_rc 
 | |
|                             && tilde_rc->pw_dir)
 | |
|                         {
 | |
|                             std::string dsymforuuid_path(tilde_rc->pw_dir);
 | |
|                             dsymforuuid_path += "/bin/dsymForUUID";
 | |
|                             dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false);
 | |
|                             g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL)
 | |
|             {
 | |
|                 dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true);
 | |
|                 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
 | |
|             }
 | |
| 
 | |
|             if (g_dsym_for_uuid_exe_exists)
 | |
|                 dsym_for_uuid_exe_spec.GetPath (g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path));
 | |
|         }
 | |
|         if (g_dsym_for_uuid_exe_exists)
 | |
|         {
 | |
|             std::string uuid_str;
 | |
|             char file_path[PATH_MAX];
 | |
|             file_path[0] = '\0';
 | |
| 
 | |
|             if (uuid_ptr)
 | |
|                 uuid_str = uuid_ptr->GetAsString();
 | |
| 
 | |
|             if (file_spec_ptr)
 | |
|                 file_spec_ptr->GetPath(file_path, sizeof(file_path));
 | |
|             
 | |
|             StreamString command;
 | |
|             if (!uuid_str.empty())
 | |
|                 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, uuid_str.c_str());
 | |
|             else if (file_path[0] != '\0')
 | |
|                 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, file_path);
 | |
|             
 | |
|             if (!command.GetString().empty())
 | |
|             {
 | |
|                 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
 | |
|                 int exit_status = -1;
 | |
|                 int signo = -1;
 | |
|                 std::string command_output;
 | |
|                 if (log)
 | |
|                 {
 | |
|                     if (!uuid_str.empty())
 | |
|                         log->Printf("Calling %s with UUID %s to find dSYM", g_dsym_for_uuid_exe_path, uuid_str.c_str());
 | |
|                     else if (file_path[0] != '\0')
 | |
|                         log->Printf("Calling %s with file %s to find dSYM", g_dsym_for_uuid_exe_path, file_path);
 | |
|                 }
 | |
|                 Error error = Host::RunShellCommand (command.GetData(),
 | |
|                                                      NULL,              // current working directory
 | |
|                                                      &exit_status,      // Exit status
 | |
|                                                      &signo,            // Signal int *
 | |
|                                                      &command_output,   // Command output
 | |
|                                                      30,                // Large timeout to allow for long dsym download times
 | |
|                                                      false);            // Don't run in a shell (we don't need shell expansion)
 | |
|                 if (error.Success() && exit_status == 0 && !command_output.empty())
 | |
|                 {
 | |
|                     CFCData data (CFDataCreateWithBytesNoCopy (NULL,
 | |
|                                                                (const UInt8 *)command_output.data(),
 | |
|                                                                command_output.size(),
 | |
|                                                                kCFAllocatorNull));
 | |
|                     
 | |
|                     CFCReleaser<CFDictionaryRef> plist((CFDictionaryRef)::CFPropertyListCreateFromXMLData (NULL, data.get(), kCFPropertyListImmutable, NULL));
 | |
|                     
 | |
|                     if (plist.get() && CFGetTypeID (plist.get()) == CFDictionaryGetTypeID ())
 | |
|                     {
 | |
|                         if (!uuid_str.empty())
 | |
|                         {
 | |
|                             CFCString uuid_cfstr(uuid_str.c_str());
 | |
|                             CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue (plist.get(), uuid_cfstr.get());
 | |
|                             success = GetModuleSpecInfoFromUUIDDictionary (uuid_dict, module_spec);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
 | |
|                             if (num_values > 0)
 | |
|                             {
 | |
|                                 std::vector<CFStringRef> keys (num_values, NULL);
 | |
|                                 std::vector<CFDictionaryRef> values (num_values, NULL);
 | |
|                                 ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]);
 | |
|                                 if (num_values == 1)
 | |
|                                 {
 | |
|                                     return GetModuleSpecInfoFromUUIDDictionary (values[0], module_spec);
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     for (CFIndex i=0; i<num_values; ++i)
 | |
|                                     {
 | |
|                                         ModuleSpec curr_module_spec;
 | |
|                                         if (GetModuleSpecInfoFromUUIDDictionary (values[i], curr_module_spec))
 | |
|                                         {
 | |
|                                             if (module_spec.GetArchitecture().IsCompatibleMatch(curr_module_spec.GetArchitecture()))
 | |
|                                             {
 | |
|                                                 module_spec = curr_module_spec;
 | |
|                                                 return true;
 | |
|                                             }
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (log)
 | |
|                     {
 | |
|                         if (!uuid_str.empty())
 | |
|                             log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, uuid_str.c_str());
 | |
|                         else if (file_path[0] != '\0')
 | |
|                             log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, file_path);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return success;
 | |
| }
 | |
| 
 |