blob: 37e9b8c79e844dfcf76fcc5c3c3966137e2ad321 [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"
Greg Claytonb9a01b32012-02-26 05:51:37 +000029#include "lldb/Core/Module.h"
Greg Clayton1f746072012-08-29 21:13:06 +000030#include "lldb/Core/ModuleSpec.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000031#include "lldb/Core/Timer.h"
Zachary Turner0e1d52a2017-03-04 01:28:55 +000032#include "lldb/Utility/UUID.h"
Johnny Chenfdc80a5c2012-02-01 01:49:50 +000033#include "lldb/Host/Host.h"
Robert Flack31870e12015-04-24 18:09:54 +000034#include "lldb/Symbol/ObjectFile.h"
Greg Clayton293d5932011-02-01 05:15:02 +000035#include "lldb/Utility/CleanUp.h"
Zachary Turner01c32432017-02-14 19:06:07 +000036#include "lldb/Utility/Endian.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000037#include "lldb/Utility/Log.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) {
Jason Molendaa1a86462017-02-16 02:08:33 +0000266 bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
267 assert(got_spec);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000268 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 Molendabb860bd2012-10-09 01:17:11 +0000275 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000276 }
Jason Molendabb860bd2012-10-09 01:17:11 +0000277 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278 }
279 }
280 }
281 dsym_fspec.Clear();
282 return dsym_fspec;
283}
284
285static 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 Molendabb860bd2012-10-09 01:17:11 +0000303 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 }
Jason Molendabb860bd2012-10-09 01:17:11 +0000305 }
306
Kate Stoneb9c1b512016-09-06 20:57:50 +0000307 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 Molendabb860bd2012-10-09 01:17:11 +0000317 }
318
Kate Stoneb9c1b512016-09-06 20:57:50 +0000319 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 Molenda73184de2016-11-09 03:42:12 +0000354 // If we see DBGVersion with a value of 2 or higher, this is a new style
Kate Stoneb9c1b512016-09-06 20:57:50 +0000355 // DBGSourcePathRemapping dictionary
356 bool new_style_source_remapping_dictionary = false;
357 std::string original_DBGSourcePath_value = DBGSourcePath;
Jason Molenda73184de2016-11-09 03:42:12 +0000358 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 Stoneb9c1b512016-09-06 20:57:50 +0000370
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 Claytonc8f814d2012-09-27 03:13:55 +0000400 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000401 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
420bool 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 Molenda055c57b2012-10-30 21:26:30 +0000577 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000578 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000579 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000580 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000581 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000582 }
583 } else {
584 if (log) {
Jason Molendac16b4af2013-05-03 23:56:12 +0000585 if (!uuid_str.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000586 log->Printf("Called %s on %s, no matches",
587 g_dsym_for_uuid_exe_path, uuid_str.c_str());
Jason Molenda5b941152014-10-17 01:38:10 +0000588 else if (file_path[0] != '\0')
Kate Stoneb9c1b512016-09-06 20:57:50 +0000589 log->Printf("Called %s on %s, no matches",
590 g_dsym_for_uuid_exe_path, file_path);
591 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000592 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000594 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000595 }
596 return success;
Greg Claytonc8f814d2012-09-27 03:13:55 +0000597}