blob: 46dbb0bb9ad6317a2a356d3a99a26c2f0ca50112 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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 Stoneb9c1b512016-09-06 20:57:50 +000013#include "lldb/Utility/SafeMachO.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014#include <dirent.h>
Jason Molenda055c57b2012-10-30 21:26:30 +000015#include <pwd.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000016
17// C++ Includes
18// Other libraries and framework includes
19#include <CoreFoundation/CoreFoundation.h>
20
21// Project includes
Kate Stoneb9c1b512016-09-06 20:57:50 +000022#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 Lattner30fdc8d2010-06-08 16:52:24 +000026#include "lldb/Core/ArchSpec.h"
27#include "lldb/Core/DataBuffer.h"
28#include "lldb/Core/DataExtractor.h"
Jason Molenda08a32582015-07-25 02:39:42 +000029#include "lldb/Core/Log.h"
Greg Claytonb9a01b32012-02-26 05:51:37 +000030#include "lldb/Core/Module.h"
Greg Clayton1f746072012-08-29 21:13:06 +000031#include "lldb/Core/ModuleSpec.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032#include "lldb/Core/Timer.h"
33#include "lldb/Core/UUID.h"
Johnny Chenfdc80a5c2012-02-01 01:49:50 +000034#include "lldb/Host/Host.h"
Robert Flack31870e12015-04-24 18:09:54 +000035#include "lldb/Symbol/ObjectFile.h"
Greg Clayton293d5932011-02-01 05:15:02 +000036#include "lldb/Utility/CleanUp.h"
Zachary Turner01c32432017-02-14 19:06:07 +000037#include "lldb/Utility/Endian.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000038#include "lldb/Utility/StreamString.h"
Chris Lattner311adf32010-09-08 23:01:14 +000039#include "mach/machine.h"
Greg Claytonc982c762010-07-09 20:39:50 +000040
Chris Lattner30fdc8d2010-06-08 16:52:24 +000041using namespace lldb;
42using namespace lldb_private;
Greg Claytone1a916a2010-07-21 22:12:05 +000043using namespace llvm::MachO;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044
Kate Stoneb9c1b512016-09-06 20:57:50 +000045#if !defined(__arm__) && !defined(__arm64__) && \
46 !defined(__aarch64__) // No DebugSymbols on the iOS devices
Chris Lattner30fdc8d2010-06-08 16:52:24 +000047extern "C" {
Greg Claytonc982c762010-07-09 20:39:50 +000048
Kate Stoneb9c1b512016-09-06 20:57:50 +000049CFURLRef DBGCopyFullDSYMURLForUUID(CFUUIDRef uuid, CFURLRef exec_url);
50CFDictionaryRef DBGCopyDSYMPropertyLists(CFURLRef dsym_url);
Greg Claytonc982c762010-07-09 20:39:50 +000051}
Greg Claytondce502e2011-11-04 03:34:56 +000052#endif
Chris Lattner30fdc8d2010-06-08 16:52:24 +000053
Kate Stoneb9c1b512016-09-06 20:57:50 +000054int 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 Molenda8825c5c2015-10-08 21:48:35 +000059
Kate Stoneb9c1b512016-09-06 20:57:50 +000060 int items_found = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000061
Kate Stoneb9c1b512016-09-06 20:57:50 +000062#if !defined(__arm__) && !defined(__arm64__) && \
63 !defined(__aarch64__) // No DebugSymbols on the iOS devices
Greg Claytondce502e2011-11-04 03:34:56 +000064
Kate Stoneb9c1b512016-09-06 20:57:50 +000065 const UUID *uuid = module_spec.GetUUIDPtr();
66 const ArchSpec *arch = module_spec.GetArchitecturePtr();
Greg Claytonb9a01b32012-02-26 05:51:37 +000067
Kate Stoneb9c1b512016-09-06 20:57:50 +000068 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 Lattner30fdc8d2010-06-08 16:52:24 +000077
Kate Stoneb9c1b512016-09-06 20:57:50 +000078 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 Lattner30fdc8d2010-06-08 16:52:24 +000088 }
Greg Claytondce502e2011-11-04 03:34:56 +000089
Kate Stoneb9c1b512016-09-06 20:57:50 +000090 CFCReleaser<CFURLRef> dsym_url(
91 ::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
92 char path[PATH_MAX];
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 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 Lattner30fdc8d2010-06-08 16:52:24 +0000101 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 FileSpec dsym_filespec(path, path[0] == '~');
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000103
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 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 Molenda08a32582015-07-25 02:39:42 +0000110 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 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 Claytonb5f0fea2012-09-27 22:26:11 +0000145 success = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146 return_module_spec.GetFileSpec() = exec_filespec;
147 }
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000148 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 }
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000150
Kate Stoneb9c1b512016-09-06 20:57:50 +0000151 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 Molenda46202862016-07-26 06:33:07 +0000163 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000164 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 Molenda46202862016-07-26 06:33:07 +0000169 {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 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 Molenda46202862016-07-26 06:33:07 +0000190 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191 }
Jason Molenda46202862016-07-26 06:33:07 +0000192 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000193 }
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 Molenda46202862016-07-26 06:33:07 +0000220 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221 }
Jason Molenda46202862016-07-26 06:33:07 +0000222 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223 }
Jason Molenda46202862016-07-26 06:33:07 +0000224 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000225 }
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000226 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000227 }
228#endif // #if !defined (__arm__) && !defined (__arm64__) && !defined
229 // (__aarch64__)
230
231 return items_found;
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000232}
Greg Claytonc8f814d2012-09-27 03:13:55 +0000233
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
235 const lldb_private::UUID *uuid,
236 const ArchSpec *arch) {
237 char path[PATH_MAX];
Greg Claytonc8f814d2012-09-27 03:13:55 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 FileSpec dsym_fspec;
Jason Molendabb860bd2012-10-09 01:17:11 +0000240
Kate Stoneb9c1b512016-09-06 20:57:50 +0000241 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) {
266 assert(module_specs.GetModuleSpecAtIndex(i, spec));
267 if ((uuid == NULL ||
268 (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
269 (arch == NULL ||
270 (spec.GetArchitecturePtr() &&
271 spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
272 return dsym_fspec;
273 }
Jason Molendabb860bd2012-10-09 01:17:11 +0000274 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000275 }
Jason Molendabb860bd2012-10-09 01:17:11 +0000276 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277 }
278 }
279 }
280 dsym_fspec.Clear();
281 return dsym_fspec;
282}
283
284static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
285 ModuleSpec &module_spec) {
286 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
287 bool success = false;
288 if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
289 std::string str;
290 CFStringRef cf_str;
291 CFDictionaryRef cf_dict;
292
293 cf_str = (CFStringRef)CFDictionaryGetValue(
294 (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
295 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
296 if (CFCString::FileSystemRepresentation(cf_str, str)) {
297 module_spec.GetFileSpec().SetFile(str.c_str(), true);
298 if (log) {
299 log->Printf(
300 "From dsymForUUID plist: Symbol rich executable is at '%s'",
301 str.c_str());
Jason Molendabb860bd2012-10-09 01:17:11 +0000302 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000303 }
Jason Molendabb860bd2012-10-09 01:17:11 +0000304 }
305
Kate Stoneb9c1b512016-09-06 20:57:50 +0000306 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
307 CFSTR("DBGDSYMPath"));
308 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
309 if (CFCString::FileSystemRepresentation(cf_str, str)) {
310 module_spec.GetSymbolFileSpec().SetFile(str.c_str(), true);
311 success = true;
312 if (log) {
313 log->Printf("From dsymForUUID plist: dSYM is at '%s'", str.c_str());
314 }
315 }
Jason Molendabb860bd2012-10-09 01:17:11 +0000316 }
317
Kate Stoneb9c1b512016-09-06 20:57:50 +0000318 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
319 CFSTR("DBGArchitecture"));
320 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
321 if (CFCString::FileSystemRepresentation(cf_str, str))
322 module_spec.GetArchitecture().SetTriple(str.c_str());
323 }
324
325 std::string DBGBuildSourcePath;
326 std::string DBGSourcePath;
327
328 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
329 CFSTR("DBGBuildSourcePath"));
330 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
331 CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
332 }
333
334 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
335 CFSTR("DBGSourcePath"));
336 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
337 CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
338 }
339
340 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
341 if (DBGSourcePath[0] == '~') {
342 FileSpec resolved_source_path(DBGSourcePath.c_str(), true);
343 DBGSourcePath = resolved_source_path.GetPath();
344 }
345 module_spec.GetSourceMappingList().Append(
346 ConstString(DBGBuildSourcePath.c_str()),
347 ConstString(DBGSourcePath.c_str()), true);
348 }
349
350 cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
351 (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
352 if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
Jason Molenda73184de2016-11-09 03:42:12 +0000353 // If we see DBGVersion with a value of 2 or higher, this is a new style
Kate Stoneb9c1b512016-09-06 20:57:50 +0000354 // DBGSourcePathRemapping dictionary
355 bool new_style_source_remapping_dictionary = false;
356 std::string original_DBGSourcePath_value = DBGSourcePath;
Jason Molenda73184de2016-11-09 03:42:12 +0000357 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
358 CFSTR("DBGVersion"));
359 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
360 std::string version;
361 CFCString::FileSystemRepresentation(cf_str, version);
362 if (!version.empty() && isdigit(version[0])) {
363 int version_number = atoi(version.c_str());
364 if (version_number > 1) {
365 new_style_source_remapping_dictionary = true;
366 }
367 }
368 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000369
370 CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
371 if (kv_pair_count > 0) {
372 CFStringRef *keys =
373 (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
374 CFStringRef *values =
375 (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
376 if (keys != nullptr && values != nullptr) {
377 CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
378 (const void **)keys,
379 (const void **)values);
380 }
381 for (CFIndex i = 0; i < kv_pair_count; i++) {
382 DBGBuildSourcePath.clear();
383 DBGSourcePath.clear();
384 if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
385 CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
386 }
387 if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
388 CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
389 }
390 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
391 // In the "old style" DBGSourcePathRemapping dictionary, the
392 // DBGSourcePath values
393 // (the "values" half of key-value path pairs) were wrong. Ignore
394 // them and use the
395 // universal DBGSourcePath string from earlier.
396 if (new_style_source_remapping_dictionary == true &&
397 !original_DBGSourcePath_value.empty()) {
398 DBGSourcePath = original_DBGSourcePath_value;
Greg Claytonc8f814d2012-09-27 03:13:55 +0000399 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000400 if (DBGSourcePath[0] == '~') {
401 FileSpec resolved_source_path(DBGSourcePath.c_str(), true);
402 DBGSourcePath = resolved_source_path.GetPath();
403 }
404 module_spec.GetSourceMappingList().Append(
405 ConstString(DBGBuildSourcePath.c_str()),
406 ConstString(DBGSourcePath.c_str()), true);
407 }
408 }
409 if (keys)
410 free(keys);
411 if (values)
412 free(values);
413 }
414 }
415 }
416 return success;
417}
418
419bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
420 bool force_lookup) {
421 bool success = false;
422 const UUID *uuid_ptr = module_spec.GetUUIDPtr();
423 const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
424
425 // It's expensive to check for the DBGShellCommands defaults setting, only do
426 // it once per
427 // lldb run and cache the result.
428 static bool g_have_checked_for_dbgshell_command = false;
429 static const char *g_dbgshell_command = NULL;
430 if (g_have_checked_for_dbgshell_command == false) {
431 g_have_checked_for_dbgshell_command = true;
432 CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
433 CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
434 if (defaults_setting &&
435 CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
436 char cstr_buf[PATH_MAX];
437 if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf,
438 sizeof(cstr_buf), kCFStringEncodingUTF8)) {
439 g_dbgshell_command =
440 strdup(cstr_buf); // this malloc'ed memory will never be freed
441 }
442 }
443 if (defaults_setting) {
444 CFRelease(defaults_setting);
445 }
446 }
447
448 // When g_dbgshell_command is NULL, the user has not enabled the use of an
449 // external program
450 // to find the symbols, don't run it for them.
451 if (force_lookup == false && g_dbgshell_command == NULL) {
452 return false;
453 }
454
455 if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists())) {
456 static bool g_located_dsym_for_uuid_exe = false;
457 static bool g_dsym_for_uuid_exe_exists = false;
458 static char g_dsym_for_uuid_exe_path[PATH_MAX];
459 if (!g_located_dsym_for_uuid_exe) {
460 g_located_dsym_for_uuid_exe = true;
461 const char *dsym_for_uuid_exe_path_cstr =
462 getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
463 FileSpec dsym_for_uuid_exe_spec;
464 if (dsym_for_uuid_exe_path_cstr) {
465 dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true);
466 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
467 }
468
469 if (!g_dsym_for_uuid_exe_exists) {
470 dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false);
471 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
472 if (!g_dsym_for_uuid_exe_exists) {
473 long bufsize;
474 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) {
475 char buffer[bufsize];
476 struct passwd pwd;
477 struct passwd *tilde_rc = NULL;
478 // we are a library so we need to use the reentrant version of
479 // getpwnam()
480 if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 &&
481 tilde_rc && tilde_rc->pw_dir) {
482 std::string dsymforuuid_path(tilde_rc->pw_dir);
483 dsymforuuid_path += "/bin/dsymForUUID";
484 dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false);
485 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
486 }
487 }
488 }
489 }
490 if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) {
491 dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true);
492 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
493 }
494
495 if (g_dsym_for_uuid_exe_exists)
496 dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path,
497 sizeof(g_dsym_for_uuid_exe_path));
498 }
499 if (g_dsym_for_uuid_exe_exists) {
500 std::string uuid_str;
501 char file_path[PATH_MAX];
502 file_path[0] = '\0';
503
504 if (uuid_ptr)
505 uuid_str = uuid_ptr->GetAsString();
506
507 if (file_spec_ptr)
508 file_spec_ptr->GetPath(file_path, sizeof(file_path));
509
510 StreamString command;
511 if (!uuid_str.empty())
512 command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
513 g_dsym_for_uuid_exe_path, uuid_str.c_str());
514 else if (file_path[0] != '\0')
515 command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
516 g_dsym_for_uuid_exe_path, file_path);
517
518 if (!command.GetString().empty()) {
519 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
520 int exit_status = -1;
521 int signo = -1;
522 std::string command_output;
523 if (log) {
524 if (!uuid_str.empty())
525 log->Printf("Calling %s with UUID %s to find dSYM",
526 g_dsym_for_uuid_exe_path, uuid_str.c_str());
527 else if (file_path[0] != '\0')
528 log->Printf("Calling %s with file %s to find dSYM",
529 g_dsym_for_uuid_exe_path, file_path);
530 }
531 Error error = Host::RunShellCommand(
532 command.GetData(),
533 NULL, // current working directory
534 &exit_status, // Exit status
535 &signo, // Signal int *
536 &command_output, // Command output
537 30, // Large timeout to allow for long dsym download times
538 false); // Don't run in a shell (we don't need shell expansion)
539 if (error.Success() && exit_status == 0 && !command_output.empty()) {
540 CFCData data(CFDataCreateWithBytesNoCopy(
541 NULL, (const UInt8 *)command_output.data(), command_output.size(),
542 kCFAllocatorNull));
543
544 CFCReleaser<CFDictionaryRef> plist(
545 (CFDictionaryRef)::CFPropertyListCreateFromXMLData(
546 NULL, data.get(), kCFPropertyListImmutable, NULL));
547
548 if (plist.get() &&
549 CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) {
550 if (!uuid_str.empty()) {
551 CFCString uuid_cfstr(uuid_str.c_str());
552 CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue(
553 plist.get(), uuid_cfstr.get());
554 success =
555 GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec);
556 } else {
557 const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
558 if (num_values > 0) {
559 std::vector<CFStringRef> keys(num_values, NULL);
560 std::vector<CFDictionaryRef> values(num_values, NULL);
561 ::CFDictionaryGetKeysAndValues(plist.get(), NULL,
562 (const void **)&values[0]);
563 if (num_values == 1) {
564 return GetModuleSpecInfoFromUUIDDictionary(values[0],
565 module_spec);
566 } else {
567 for (CFIndex i = 0; i < num_values; ++i) {
568 ModuleSpec curr_module_spec;
569 if (GetModuleSpecInfoFromUUIDDictionary(values[i],
570 curr_module_spec)) {
571 if (module_spec.GetArchitecture().IsCompatibleMatch(
572 curr_module_spec.GetArchitecture())) {
573 module_spec = curr_module_spec;
574 return true;
575 }
Jason Molenda055c57b2012-10-30 21:26:30 +0000576 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000577 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000578 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000579 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000580 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000581 }
582 } else {
583 if (log) {
Jason Molendac16b4af2013-05-03 23:56:12 +0000584 if (!uuid_str.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000585 log->Printf("Called %s on %s, no matches",
586 g_dsym_for_uuid_exe_path, uuid_str.c_str());
Jason Molenda5b941152014-10-17 01:38:10 +0000587 else if (file_path[0] != '\0')
Kate Stoneb9c1b512016-09-06 20:57:50 +0000588 log->Printf("Called %s on %s, no matches",
589 g_dsym_for_uuid_exe_path, file_path);
590 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000591 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000592 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000593 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000594 }
595 return success;
Greg Claytonc8f814d2012-09-27 03:13:55 +0000596}