Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 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 |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 13 | #include "lldb/Utility/SafeMachO.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 14 | #include <dirent.h> |
Jason Molenda | 055c57b | 2012-10-30 21:26:30 +0000 | [diff] [blame] | 15 | #include <pwd.h> |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 16 | |
| 17 | // C++ Includes |
| 18 | // Other libraries and framework includes |
| 19 | #include <CoreFoundation/CoreFoundation.h> |
| 20 | |
| 21 | // Project includes |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 22 | #include "Host/macosx/cfcpp/CFCBundle.h" |
| 23 | #include "Host/macosx/cfcpp/CFCData.h" |
| 24 | #include "Host/macosx/cfcpp/CFCReleaser.h" |
| 25 | #include "Host/macosx/cfcpp/CFCString.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 26 | #include "lldb/Core/ArchSpec.h" |
| 27 | #include "lldb/Core/DataBuffer.h" |
| 28 | #include "lldb/Core/DataExtractor.h" |
Greg Clayton | b9a01b3 | 2012-02-26 05:51:37 +0000 | [diff] [blame] | 29 | #include "lldb/Core/Module.h" |
Greg Clayton | 1f74607 | 2012-08-29 21:13:06 +0000 | [diff] [blame] | 30 | #include "lldb/Core/ModuleSpec.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 31 | #include "lldb/Core/Timer.h" |
Zachary Turner | 0e1d52a | 2017-03-04 01:28:55 +0000 | [diff] [blame^] | 32 | #include "lldb/Utility/UUID.h" |
Johnny Chen | fdc80a5c | 2012-02-01 01:49:50 +0000 | [diff] [blame] | 33 | #include "lldb/Host/Host.h" |
Robert Flack | 31870e1 | 2015-04-24 18:09:54 +0000 | [diff] [blame] | 34 | #include "lldb/Symbol/ObjectFile.h" |
Greg Clayton | 293d593 | 2011-02-01 05:15:02 +0000 | [diff] [blame] | 35 | #include "lldb/Utility/CleanUp.h" |
Zachary Turner | 01c3243 | 2017-02-14 19:06:07 +0000 | [diff] [blame] | 36 | #include "lldb/Utility/Endian.h" |
Zachary Turner | 6f9e690 | 2017-03-03 20:56:28 +0000 | [diff] [blame] | 37 | #include "lldb/Utility/Log.h" |
Zachary Turner | bf9a773 | 2017-02-02 21:39:50 +0000 | [diff] [blame] | 38 | #include "lldb/Utility/StreamString.h" |
Chris Lattner | 311adf3 | 2010-09-08 23:01:14 +0000 | [diff] [blame] | 39 | #include "mach/machine.h" |
Greg Clayton | c982c76 | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 40 | |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 41 | using namespace lldb; |
| 42 | using namespace lldb_private; |
Greg Clayton | e1a916a | 2010-07-21 22:12:05 +0000 | [diff] [blame] | 43 | using namespace llvm::MachO; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 44 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 45 | #if !defined(__arm__) && !defined(__arm64__) && \ |
| 46 | !defined(__aarch64__) // No DebugSymbols on the iOS devices |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 47 | extern "C" { |
Greg Clayton | c982c76 | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 48 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 49 | CFURLRef DBGCopyFullDSYMURLForUUID(CFUUIDRef uuid, CFURLRef exec_url); |
| 50 | CFDictionaryRef DBGCopyDSYMPropertyLists(CFURLRef dsym_url); |
Greg Clayton | c982c76 | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 51 | } |
Greg Clayton | dce502e | 2011-11-04 03:34:56 +0000 | [diff] [blame] | 52 | #endif |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 53 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 54 | int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, |
| 55 | ModuleSpec &return_module_spec) { |
| 56 | return_module_spec = module_spec; |
| 57 | return_module_spec.GetFileSpec().Clear(); |
| 58 | return_module_spec.GetSymbolFileSpec().Clear(); |
Jason Molenda | 8825c5c | 2015-10-08 21:48:35 +0000 | [diff] [blame] | 59 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 60 | int items_found = 0; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 61 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 62 | #if !defined(__arm__) && !defined(__arm64__) && \ |
| 63 | !defined(__aarch64__) // No DebugSymbols on the iOS devices |
Greg Clayton | dce502e | 2011-11-04 03:34:56 +0000 | [diff] [blame] | 64 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 65 | const UUID *uuid = module_spec.GetUUIDPtr(); |
| 66 | const ArchSpec *arch = module_spec.GetArchitecturePtr(); |
Greg Clayton | b9a01b3 | 2012-02-26 05:51:37 +0000 | [diff] [blame] | 67 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 68 | if (uuid && uuid->IsValid()) { |
| 69 | // Try and locate the dSYM file using DebugSymbols first |
| 70 | const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes(); |
| 71 | if (module_uuid != NULL) { |
| 72 | CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes( |
| 73 | NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3], |
| 74 | module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7], |
| 75 | module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11], |
| 76 | module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15])); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 77 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 78 | if (module_uuid_ref.get()) { |
| 79 | CFCReleaser<CFURLRef> exec_url; |
| 80 | const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); |
| 81 | Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); |
| 82 | if (exec_fspec) { |
| 83 | char exec_cf_path[PATH_MAX]; |
| 84 | if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path))) |
| 85 | exec_url.reset(::CFURLCreateFromFileSystemRepresentation( |
| 86 | NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path), |
| 87 | FALSE)); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 88 | } |
Greg Clayton | dce502e | 2011-11-04 03:34:56 +0000 | [diff] [blame] | 89 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 90 | CFCReleaser<CFURLRef> dsym_url( |
| 91 | ::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get())); |
| 92 | char path[PATH_MAX]; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 93 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 94 | if (dsym_url.get()) { |
| 95 | if (::CFURLGetFileSystemRepresentation( |
| 96 | dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { |
| 97 | if (log) { |
| 98 | log->Printf("DebugSymbols framework returned dSYM path of %s for " |
| 99 | "UUID %s -- looking for the dSYM", |
| 100 | path, uuid->GetAsString().c_str()); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 101 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 102 | FileSpec dsym_filespec(path, path[0] == '~'); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 103 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 104 | if (dsym_filespec.GetFileType() == FileSpec::eFileTypeDirectory) { |
| 105 | dsym_filespec = |
| 106 | Symbols::FindSymbolFileInBundle(dsym_filespec, uuid, arch); |
| 107 | ++items_found; |
| 108 | } else { |
| 109 | ++items_found; |
Jason Molenda | 08a3258 | 2015-07-25 02:39:42 +0000 | [diff] [blame] | 110 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 111 | return_module_spec.GetSymbolFileSpec() = dsym_filespec; |
| 112 | } |
| 113 | |
| 114 | bool success = false; |
| 115 | if (log) { |
| 116 | if (::CFURLGetFileSystemRepresentation( |
| 117 | dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { |
| 118 | log->Printf("DebugSymbols framework returned dSYM path of %s for " |
| 119 | "UUID %s -- looking for an exec file", |
| 120 | path, uuid->GetAsString().c_str()); |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | CFCReleaser<CFDictionaryRef> dict( |
| 125 | ::DBGCopyDSYMPropertyLists(dsym_url.get())); |
| 126 | CFDictionaryRef uuid_dict = NULL; |
| 127 | if (dict.get()) { |
| 128 | CFCString uuid_cfstr(uuid->GetAsString().c_str()); |
| 129 | uuid_dict = static_cast<CFDictionaryRef>( |
| 130 | ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get())); |
| 131 | } |
| 132 | if (uuid_dict) { |
| 133 | CFStringRef exec_cf_path = |
| 134 | static_cast<CFStringRef>(::CFDictionaryGetValue( |
| 135 | uuid_dict, CFSTR("DBGSymbolRichExecutable"))); |
| 136 | if (exec_cf_path && ::CFStringGetFileSystemRepresentation( |
| 137 | exec_cf_path, path, sizeof(path))) { |
| 138 | if (log) { |
| 139 | log->Printf("plist bundle has exec path of %s for UUID %s", |
| 140 | path, uuid->GetAsString().c_str()); |
| 141 | } |
| 142 | ++items_found; |
| 143 | FileSpec exec_filespec(path, path[0] == '~'); |
| 144 | if (exec_filespec.Exists()) { |
Greg Clayton | b5f0fea | 2012-09-27 22:26:11 +0000 | [diff] [blame] | 145 | success = true; |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 146 | return_module_spec.GetFileSpec() = exec_filespec; |
| 147 | } |
Greg Clayton | b5f0fea | 2012-09-27 22:26:11 +0000 | [diff] [blame] | 148 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 149 | } |
Greg Clayton | b5f0fea | 2012-09-27 22:26:11 +0000 | [diff] [blame] | 150 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 151 | if (!success) { |
| 152 | // No dictionary, check near the dSYM bundle for an executable that |
| 153 | // matches... |
| 154 | if (::CFURLGetFileSystemRepresentation( |
| 155 | dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { |
| 156 | char *dsym_extension_pos = ::strstr(path, ".dSYM"); |
| 157 | if (dsym_extension_pos) { |
| 158 | *dsym_extension_pos = '\0'; |
| 159 | if (log) { |
| 160 | log->Printf("Looking for executable binary next to dSYM " |
| 161 | "bundle with name with name %s", |
| 162 | path); |
Jason Molenda | 4620286 | 2016-07-26 06:33:07 +0000 | [diff] [blame] | 163 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 164 | FileSpec file_spec(path, true); |
| 165 | ModuleSpecList module_specs; |
| 166 | ModuleSpec matched_module_spec; |
| 167 | switch (file_spec.GetFileType()) { |
| 168 | case FileSpec::eFileTypeDirectory: // Bundle directory? |
Jason Molenda | 4620286 | 2016-07-26 06:33:07 +0000 | [diff] [blame] | 169 | { |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 170 | CFCBundle bundle(path); |
| 171 | CFCReleaser<CFURLRef> bundle_exe_url( |
| 172 | bundle.CopyExecutableURL()); |
| 173 | if (bundle_exe_url.get()) { |
| 174 | if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(), |
| 175 | true, (UInt8 *)path, |
| 176 | sizeof(path) - 1)) { |
| 177 | FileSpec bundle_exe_file_spec(path, true); |
| 178 | if (ObjectFile::GetModuleSpecifications( |
| 179 | bundle_exe_file_spec, 0, 0, module_specs) && |
| 180 | module_specs.FindMatchingModuleSpec( |
| 181 | module_spec, matched_module_spec)) |
| 182 | |
| 183 | { |
| 184 | ++items_found; |
| 185 | return_module_spec.GetFileSpec() = bundle_exe_file_spec; |
| 186 | if (log) { |
| 187 | log->Printf("Executable binary %s next to dSYM is " |
| 188 | "compatible; using", |
| 189 | path); |
Jason Molenda | 4620286 | 2016-07-26 06:33:07 +0000 | [diff] [blame] | 190 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 191 | } |
Jason Molenda | 4620286 | 2016-07-26 06:33:07 +0000 | [diff] [blame] | 192 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 193 | } |
| 194 | } break; |
| 195 | |
| 196 | case FileSpec::eFileTypePipe: // Forget pipes |
| 197 | case FileSpec::eFileTypeSocket: // We can't process socket files |
| 198 | case FileSpec::eFileTypeInvalid: // File doesn't exist... |
| 199 | break; |
| 200 | |
| 201 | case FileSpec::eFileTypeUnknown: |
| 202 | case FileSpec::eFileTypeRegular: |
| 203 | case FileSpec::eFileTypeSymbolicLink: |
| 204 | case FileSpec::eFileTypeOther: |
| 205 | if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, |
| 206 | module_specs) && |
| 207 | module_specs.FindMatchingModuleSpec(module_spec, |
| 208 | matched_module_spec)) |
| 209 | |
| 210 | { |
| 211 | ++items_found; |
| 212 | return_module_spec.GetFileSpec() = file_spec; |
| 213 | if (log) { |
| 214 | log->Printf("Executable binary %s next to dSYM is " |
| 215 | "compatible; using", |
| 216 | path); |
| 217 | } |
| 218 | } |
| 219 | break; |
Jason Molenda | 4620286 | 2016-07-26 06:33:07 +0000 | [diff] [blame] | 220 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 221 | } |
Jason Molenda | 4620286 | 2016-07-26 06:33:07 +0000 | [diff] [blame] | 222 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 223 | } |
Jason Molenda | 4620286 | 2016-07-26 06:33:07 +0000 | [diff] [blame] | 224 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 225 | } |
Greg Clayton | b5f0fea | 2012-09-27 22:26:11 +0000 | [diff] [blame] | 226 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 227 | } |
| 228 | #endif // #if !defined (__arm__) && !defined (__arm64__) && !defined |
| 229 | // (__aarch64__) |
| 230 | |
| 231 | return items_found; |
Greg Clayton | b5f0fea | 2012-09-27 22:26:11 +0000 | [diff] [blame] | 232 | } |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 233 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 234 | FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, |
| 235 | const lldb_private::UUID *uuid, |
| 236 | const ArchSpec *arch) { |
| 237 | char path[PATH_MAX]; |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 238 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 239 | FileSpec dsym_fspec; |
Jason Molenda | bb860bd | 2012-10-09 01:17:11 +0000 | [diff] [blame] | 240 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 241 | if (dsym_bundle_fspec.GetPath(path, sizeof(path))) { |
| 242 | ::strncat(path, "/Contents/Resources/DWARF", |
| 243 | sizeof(path) - strlen(path) - 1); |
| 244 | |
| 245 | lldb_utility::CleanUp<DIR *, int> dirp(opendir(path), NULL, closedir); |
| 246 | if (dirp.is_valid()) { |
| 247 | dsym_fspec.GetDirectory().SetCString(path); |
| 248 | struct dirent *dp; |
| 249 | while ((dp = readdir(dirp.get())) != NULL) { |
| 250 | // Only search directories |
| 251 | if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { |
| 252 | if (dp->d_namlen == 1 && dp->d_name[0] == '.') |
| 253 | continue; |
| 254 | |
| 255 | if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') |
| 256 | continue; |
| 257 | } |
| 258 | |
| 259 | if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) { |
| 260 | dsym_fspec.GetFilename().SetCString(dp->d_name); |
| 261 | ModuleSpecList module_specs; |
| 262 | if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, |
| 263 | module_specs)) { |
| 264 | ModuleSpec spec; |
| 265 | for (size_t i = 0; i < module_specs.GetSize(); ++i) { |
Jason Molenda | a1a8646 | 2017-02-16 02:08:33 +0000 | [diff] [blame] | 266 | bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); |
| 267 | assert(got_spec); |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 268 | if ((uuid == NULL || |
| 269 | (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && |
| 270 | (arch == NULL || |
| 271 | (spec.GetArchitecturePtr() && |
| 272 | spec.GetArchitecture().IsCompatibleMatch(*arch)))) { |
| 273 | return dsym_fspec; |
| 274 | } |
Jason Molenda | bb860bd | 2012-10-09 01:17:11 +0000 | [diff] [blame] | 275 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 276 | } |
Jason Molenda | bb860bd | 2012-10-09 01:17:11 +0000 | [diff] [blame] | 277 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 278 | } |
| 279 | } |
| 280 | } |
| 281 | dsym_fspec.Clear(); |
| 282 | return dsym_fspec; |
| 283 | } |
| 284 | |
| 285 | static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, |
| 286 | ModuleSpec &module_spec) { |
| 287 | Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); |
| 288 | bool success = false; |
| 289 | if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) { |
| 290 | std::string str; |
| 291 | CFStringRef cf_str; |
| 292 | CFDictionaryRef cf_dict; |
| 293 | |
| 294 | cf_str = (CFStringRef)CFDictionaryGetValue( |
| 295 | (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable")); |
| 296 | if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { |
| 297 | if (CFCString::FileSystemRepresentation(cf_str, str)) { |
| 298 | module_spec.GetFileSpec().SetFile(str.c_str(), true); |
| 299 | if (log) { |
| 300 | log->Printf( |
| 301 | "From dsymForUUID plist: Symbol rich executable is at '%s'", |
| 302 | str.c_str()); |
Jason Molenda | bb860bd | 2012-10-09 01:17:11 +0000 | [diff] [blame] | 303 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 304 | } |
Jason Molenda | bb860bd | 2012-10-09 01:17:11 +0000 | [diff] [blame] | 305 | } |
| 306 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 307 | cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, |
| 308 | CFSTR("DBGDSYMPath")); |
| 309 | if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { |
| 310 | if (CFCString::FileSystemRepresentation(cf_str, str)) { |
| 311 | module_spec.GetSymbolFileSpec().SetFile(str.c_str(), true); |
| 312 | success = true; |
| 313 | if (log) { |
| 314 | log->Printf("From dsymForUUID plist: dSYM is at '%s'", str.c_str()); |
| 315 | } |
| 316 | } |
Jason Molenda | bb860bd | 2012-10-09 01:17:11 +0000 | [diff] [blame] | 317 | } |
| 318 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 319 | cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, |
| 320 | CFSTR("DBGArchitecture")); |
| 321 | if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { |
| 322 | if (CFCString::FileSystemRepresentation(cf_str, str)) |
| 323 | module_spec.GetArchitecture().SetTriple(str.c_str()); |
| 324 | } |
| 325 | |
| 326 | std::string DBGBuildSourcePath; |
| 327 | std::string DBGSourcePath; |
| 328 | |
| 329 | cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, |
| 330 | CFSTR("DBGBuildSourcePath")); |
| 331 | if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { |
| 332 | CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath); |
| 333 | } |
| 334 | |
| 335 | cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, |
| 336 | CFSTR("DBGSourcePath")); |
| 337 | if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { |
| 338 | CFCString::FileSystemRepresentation(cf_str, DBGSourcePath); |
| 339 | } |
| 340 | |
| 341 | if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { |
| 342 | if (DBGSourcePath[0] == '~') { |
| 343 | FileSpec resolved_source_path(DBGSourcePath.c_str(), true); |
| 344 | DBGSourcePath = resolved_source_path.GetPath(); |
| 345 | } |
| 346 | module_spec.GetSourceMappingList().Append( |
| 347 | ConstString(DBGBuildSourcePath.c_str()), |
| 348 | ConstString(DBGSourcePath.c_str()), true); |
| 349 | } |
| 350 | |
| 351 | cf_dict = (CFDictionaryRef)CFDictionaryGetValue( |
| 352 | (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping")); |
| 353 | if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) { |
Jason Molenda | 73184de | 2016-11-09 03:42:12 +0000 | [diff] [blame] | 354 | // If we see DBGVersion with a value of 2 or higher, this is a new style |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 355 | // DBGSourcePathRemapping dictionary |
| 356 | bool new_style_source_remapping_dictionary = false; |
| 357 | std::string original_DBGSourcePath_value = DBGSourcePath; |
Jason Molenda | 73184de | 2016-11-09 03:42:12 +0000 | [diff] [blame] | 358 | cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, |
| 359 | CFSTR("DBGVersion")); |
| 360 | if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { |
| 361 | std::string version; |
| 362 | CFCString::FileSystemRepresentation(cf_str, version); |
| 363 | if (!version.empty() && isdigit(version[0])) { |
| 364 | int version_number = atoi(version.c_str()); |
| 365 | if (version_number > 1) { |
| 366 | new_style_source_remapping_dictionary = true; |
| 367 | } |
| 368 | } |
| 369 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 370 | |
| 371 | CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict); |
| 372 | if (kv_pair_count > 0) { |
| 373 | CFStringRef *keys = |
| 374 | (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); |
| 375 | CFStringRef *values = |
| 376 | (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); |
| 377 | if (keys != nullptr && values != nullptr) { |
| 378 | CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict, |
| 379 | (const void **)keys, |
| 380 | (const void **)values); |
| 381 | } |
| 382 | for (CFIndex i = 0; i < kv_pair_count; i++) { |
| 383 | DBGBuildSourcePath.clear(); |
| 384 | DBGSourcePath.clear(); |
| 385 | if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) { |
| 386 | CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath); |
| 387 | } |
| 388 | if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) { |
| 389 | CFCString::FileSystemRepresentation(values[i], DBGSourcePath); |
| 390 | } |
| 391 | if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { |
| 392 | // In the "old style" DBGSourcePathRemapping dictionary, the |
| 393 | // DBGSourcePath values |
| 394 | // (the "values" half of key-value path pairs) were wrong. Ignore |
| 395 | // them and use the |
| 396 | // universal DBGSourcePath string from earlier. |
| 397 | if (new_style_source_remapping_dictionary == true && |
| 398 | !original_DBGSourcePath_value.empty()) { |
| 399 | DBGSourcePath = original_DBGSourcePath_value; |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 400 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 401 | if (DBGSourcePath[0] == '~') { |
| 402 | FileSpec resolved_source_path(DBGSourcePath.c_str(), true); |
| 403 | DBGSourcePath = resolved_source_path.GetPath(); |
| 404 | } |
| 405 | module_spec.GetSourceMappingList().Append( |
| 406 | ConstString(DBGBuildSourcePath.c_str()), |
| 407 | ConstString(DBGSourcePath.c_str()), true); |
| 408 | } |
| 409 | } |
| 410 | if (keys) |
| 411 | free(keys); |
| 412 | if (values) |
| 413 | free(values); |
| 414 | } |
| 415 | } |
| 416 | } |
| 417 | return success; |
| 418 | } |
| 419 | |
| 420 | bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, |
| 421 | bool force_lookup) { |
| 422 | bool success = false; |
| 423 | const UUID *uuid_ptr = module_spec.GetUUIDPtr(); |
| 424 | const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); |
| 425 | |
| 426 | // It's expensive to check for the DBGShellCommands defaults setting, only do |
| 427 | // it once per |
| 428 | // lldb run and cache the result. |
| 429 | static bool g_have_checked_for_dbgshell_command = false; |
| 430 | static const char *g_dbgshell_command = NULL; |
| 431 | if (g_have_checked_for_dbgshell_command == false) { |
| 432 | g_have_checked_for_dbgshell_command = true; |
| 433 | CFTypeRef defaults_setting = CFPreferencesCopyAppValue( |
| 434 | CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols")); |
| 435 | if (defaults_setting && |
| 436 | CFGetTypeID(defaults_setting) == CFStringGetTypeID()) { |
| 437 | char cstr_buf[PATH_MAX]; |
| 438 | if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf, |
| 439 | sizeof(cstr_buf), kCFStringEncodingUTF8)) { |
| 440 | g_dbgshell_command = |
| 441 | strdup(cstr_buf); // this malloc'ed memory will never be freed |
| 442 | } |
| 443 | } |
| 444 | if (defaults_setting) { |
| 445 | CFRelease(defaults_setting); |
| 446 | } |
| 447 | } |
| 448 | |
| 449 | // When g_dbgshell_command is NULL, the user has not enabled the use of an |
| 450 | // external program |
| 451 | // to find the symbols, don't run it for them. |
| 452 | if (force_lookup == false && g_dbgshell_command == NULL) { |
| 453 | return false; |
| 454 | } |
| 455 | |
| 456 | if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists())) { |
| 457 | static bool g_located_dsym_for_uuid_exe = false; |
| 458 | static bool g_dsym_for_uuid_exe_exists = false; |
| 459 | static char g_dsym_for_uuid_exe_path[PATH_MAX]; |
| 460 | if (!g_located_dsym_for_uuid_exe) { |
| 461 | g_located_dsym_for_uuid_exe = true; |
| 462 | const char *dsym_for_uuid_exe_path_cstr = |
| 463 | getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE"); |
| 464 | FileSpec dsym_for_uuid_exe_spec; |
| 465 | if (dsym_for_uuid_exe_path_cstr) { |
| 466 | dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true); |
| 467 | g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); |
| 468 | } |
| 469 | |
| 470 | if (!g_dsym_for_uuid_exe_exists) { |
| 471 | dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false); |
| 472 | g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); |
| 473 | if (!g_dsym_for_uuid_exe_exists) { |
| 474 | long bufsize; |
| 475 | if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) { |
| 476 | char buffer[bufsize]; |
| 477 | struct passwd pwd; |
| 478 | struct passwd *tilde_rc = NULL; |
| 479 | // we are a library so we need to use the reentrant version of |
| 480 | // getpwnam() |
| 481 | if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 && |
| 482 | tilde_rc && tilde_rc->pw_dir) { |
| 483 | std::string dsymforuuid_path(tilde_rc->pw_dir); |
| 484 | dsymforuuid_path += "/bin/dsymForUUID"; |
| 485 | dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false); |
| 486 | g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); |
| 487 | } |
| 488 | } |
| 489 | } |
| 490 | } |
| 491 | if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) { |
| 492 | dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true); |
| 493 | g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); |
| 494 | } |
| 495 | |
| 496 | if (g_dsym_for_uuid_exe_exists) |
| 497 | dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path, |
| 498 | sizeof(g_dsym_for_uuid_exe_path)); |
| 499 | } |
| 500 | if (g_dsym_for_uuid_exe_exists) { |
| 501 | std::string uuid_str; |
| 502 | char file_path[PATH_MAX]; |
| 503 | file_path[0] = '\0'; |
| 504 | |
| 505 | if (uuid_ptr) |
| 506 | uuid_str = uuid_ptr->GetAsString(); |
| 507 | |
| 508 | if (file_spec_ptr) |
| 509 | file_spec_ptr->GetPath(file_path, sizeof(file_path)); |
| 510 | |
| 511 | StreamString command; |
| 512 | if (!uuid_str.empty()) |
| 513 | command.Printf("%s --ignoreNegativeCache --copyExecutable %s", |
| 514 | g_dsym_for_uuid_exe_path, uuid_str.c_str()); |
| 515 | else if (file_path[0] != '\0') |
| 516 | command.Printf("%s --ignoreNegativeCache --copyExecutable %s", |
| 517 | g_dsym_for_uuid_exe_path, file_path); |
| 518 | |
| 519 | if (!command.GetString().empty()) { |
| 520 | Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); |
| 521 | int exit_status = -1; |
| 522 | int signo = -1; |
| 523 | std::string command_output; |
| 524 | if (log) { |
| 525 | if (!uuid_str.empty()) |
| 526 | log->Printf("Calling %s with UUID %s to find dSYM", |
| 527 | g_dsym_for_uuid_exe_path, uuid_str.c_str()); |
| 528 | else if (file_path[0] != '\0') |
| 529 | log->Printf("Calling %s with file %s to find dSYM", |
| 530 | g_dsym_for_uuid_exe_path, file_path); |
| 531 | } |
| 532 | Error error = Host::RunShellCommand( |
| 533 | command.GetData(), |
| 534 | NULL, // current working directory |
| 535 | &exit_status, // Exit status |
| 536 | &signo, // Signal int * |
| 537 | &command_output, // Command output |
| 538 | 30, // Large timeout to allow for long dsym download times |
| 539 | false); // Don't run in a shell (we don't need shell expansion) |
| 540 | if (error.Success() && exit_status == 0 && !command_output.empty()) { |
| 541 | CFCData data(CFDataCreateWithBytesNoCopy( |
| 542 | NULL, (const UInt8 *)command_output.data(), command_output.size(), |
| 543 | kCFAllocatorNull)); |
| 544 | |
| 545 | CFCReleaser<CFDictionaryRef> plist( |
| 546 | (CFDictionaryRef)::CFPropertyListCreateFromXMLData( |
| 547 | NULL, data.get(), kCFPropertyListImmutable, NULL)); |
| 548 | |
| 549 | if (plist.get() && |
| 550 | CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) { |
| 551 | if (!uuid_str.empty()) { |
| 552 | CFCString uuid_cfstr(uuid_str.c_str()); |
| 553 | CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue( |
| 554 | plist.get(), uuid_cfstr.get()); |
| 555 | success = |
| 556 | GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec); |
| 557 | } else { |
| 558 | const CFIndex num_values = ::CFDictionaryGetCount(plist.get()); |
| 559 | if (num_values > 0) { |
| 560 | std::vector<CFStringRef> keys(num_values, NULL); |
| 561 | std::vector<CFDictionaryRef> values(num_values, NULL); |
| 562 | ::CFDictionaryGetKeysAndValues(plist.get(), NULL, |
| 563 | (const void **)&values[0]); |
| 564 | if (num_values == 1) { |
| 565 | return GetModuleSpecInfoFromUUIDDictionary(values[0], |
| 566 | module_spec); |
| 567 | } else { |
| 568 | for (CFIndex i = 0; i < num_values; ++i) { |
| 569 | ModuleSpec curr_module_spec; |
| 570 | if (GetModuleSpecInfoFromUUIDDictionary(values[i], |
| 571 | curr_module_spec)) { |
| 572 | if (module_spec.GetArchitecture().IsCompatibleMatch( |
| 573 | curr_module_spec.GetArchitecture())) { |
| 574 | module_spec = curr_module_spec; |
| 575 | return true; |
| 576 | } |
Jason Molenda | 055c57b | 2012-10-30 21:26:30 +0000 | [diff] [blame] | 577 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 578 | } |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 579 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 580 | } |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 581 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 582 | } |
| 583 | } else { |
| 584 | if (log) { |
Jason Molenda | c16b4af | 2013-05-03 23:56:12 +0000 | [diff] [blame] | 585 | if (!uuid_str.empty()) |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 586 | log->Printf("Called %s on %s, no matches", |
| 587 | g_dsym_for_uuid_exe_path, uuid_str.c_str()); |
Jason Molenda | 5b94115 | 2014-10-17 01:38:10 +0000 | [diff] [blame] | 588 | else if (file_path[0] != '\0') |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 589 | log->Printf("Called %s on %s, no matches", |
| 590 | g_dsym_for_uuid_exe_path, file_path); |
| 591 | } |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 592 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 593 | } |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 594 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 595 | } |
| 596 | return success; |
Greg Clayton | c8f814d | 2012-09-27 03:13:55 +0000 | [diff] [blame] | 597 | } |