blob: 39f326ad7097d796ffb1a7a08d02163aab31c981 [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
13#include <dirent.h>
Jason Molenda055c57b2012-10-30 21:26:30 +000014#include <pwd.h>
Jim Ingham46d005d2014-04-02 22:53:21 +000015#include "lldb/Utility/SafeMachO.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
Chris Lattner30fdc8d2010-06-08 16:52:24 +000022#include "lldb/Core/ArchSpec.h"
23#include "lldb/Core/DataBuffer.h"
24#include "lldb/Core/DataExtractor.h"
Greg Claytonb9a01b32012-02-26 05:51:37 +000025#include "lldb/Core/Module.h"
Greg Clayton1f746072012-08-29 21:13:06 +000026#include "lldb/Core/ModuleSpec.h"
Johnny Chen82e5a262012-08-22 00:18:43 +000027#include "lldb/Core/StreamString.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000028#include "lldb/Core/Timer.h"
29#include "lldb/Core/UUID.h"
Greg Clayton7fb56d02011-02-01 01:31:41 +000030#include "lldb/Host/Endian.h"
Johnny Chenfdc80a5c2012-02-01 01:49:50 +000031#include "lldb/Host/Host.h"
Greg Clayton293d5932011-02-01 05:15:02 +000032#include "lldb/Utility/CleanUp.h"
Daniel Dunbar5ae87322011-10-31 22:50:53 +000033#include "Host/macosx/cfcpp/CFCBundle.h"
Greg Claytonc8f814d2012-09-27 03:13:55 +000034#include "Host/macosx/cfcpp/CFCData.h"
Greg Claytonc982c762010-07-09 20:39:50 +000035#include "Host/macosx/cfcpp/CFCReleaser.h"
Greg Clayton8b82f082011-04-12 05:54:46 +000036#include "Host/macosx/cfcpp/CFCString.h"
Chris Lattner311adf32010-09-08 23:01:14 +000037#include "mach/machine.h"
Greg Claytonc982c762010-07-09 20:39:50 +000038
Greg Claytona63d08c2011-07-19 03:57:15 +000039
Chris Lattner30fdc8d2010-06-08 16:52:24 +000040using namespace lldb;
41using namespace lldb_private;
Greg Claytone1a916a2010-07-21 22:12:05 +000042using namespace llvm::MachO;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000043
Jason Molendaa3329782014-03-29 18:54:20 +000044#if !defined (__arm__) && !defined (__arm64__) // No DebugSymbols on the iOS devices
Chris Lattner30fdc8d2010-06-08 16:52:24 +000045extern "C" {
Greg Claytonc982c762010-07-09 20:39:50 +000046
Chris Lattner30fdc8d2010-06-08 16:52:24 +000047CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url);
48CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url);
Greg Claytonc982c762010-07-09 20:39:50 +000049
50}
Greg Claytondce502e2011-11-04 03:34:56 +000051#endif
Chris Lattner30fdc8d2010-06-08 16:52:24 +000052
53static bool
54SkinnyMachOFileContainsArchAndUUID
55(
56 const FileSpec &file_spec,
57 const ArchSpec *arch,
Greg Clayton60830262011-02-04 18:53:10 +000058 const lldb_private::UUID *uuid, // the UUID we are looking for
Chris Lattner30fdc8d2010-06-08 16:52:24 +000059 off_t file_offset,
60 DataExtractor& data,
Greg Claytonc7bece562013-01-25 18:06:21 +000061 lldb::offset_t data_offset,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000062 const uint32_t magic
63)
64{
Charles Davis510938e2013-08-27 05:04:57 +000065 assert(magic == MH_MAGIC || magic == MH_CIGAM || magic == MH_MAGIC_64 || magic == MH_CIGAM_64);
66 if (magic == MH_MAGIC || magic == MH_MAGIC_64)
Greg Clayton7fb56d02011-02-01 01:31:41 +000067 data.SetByteOrder (lldb::endian::InlHostByteOrder());
68 else if (lldb::endian::InlHostByteOrder() == eByteOrderBig)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000069 data.SetByteOrder (eByteOrderLittle);
70 else
71 data.SetByteOrder (eByteOrderBig);
72
73 uint32_t i;
74 const uint32_t cputype = data.GetU32(&data_offset); // cpu specifier
75 const uint32_t cpusubtype = data.GetU32(&data_offset); // machine specifier
76 data_offset+=4; // Skip mach file type
77 const uint32_t ncmds = data.GetU32(&data_offset); // number of load commands
78 const uint32_t sizeofcmds = data.GetU32(&data_offset); // the size of all the load commands
79 data_offset+=4; // Skip flags
80
81 // Check the architecture if we have a valid arch pointer
82 if (arch)
83 {
Greg Clayton41f92322010-06-11 03:25:34 +000084 ArchSpec file_arch(eArchTypeMachO, cputype, cpusubtype);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000085
Sean Callanan70386272012-12-14 23:43:03 +000086 if (!file_arch.IsCompatibleMatch(*arch))
Chris Lattner30fdc8d2010-06-08 16:52:24 +000087 return false;
88 }
89
90 // The file exists, and if a valid arch pointer was passed in we know
91 // if already matches, so we can return if we aren't looking for a specific
92 // UUID
93 if (uuid == NULL)
94 return true;
95
Charles Davis510938e2013-08-27 05:04:57 +000096 if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000097 data_offset += 4; // Skip reserved field for in mach_header_64
98
99 // Make sure we have enough data for all the load commands
Charles Davis510938e2013-08-27 05:04:57 +0000100 if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000101 {
102 if (data.GetByteSize() < sizeof(struct mach_header_64) + sizeofcmds)
103 {
104 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header_64) + sizeofcmds));
105 data.SetData (data_buffer_sp);
106 }
107 }
108 else
109 {
110 if (data.GetByteSize() < sizeof(struct mach_header) + sizeofcmds)
111 {
112 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header) + sizeofcmds));
113 data.SetData (data_buffer_sp);
114 }
115 }
116
117 for (i=0; i<ncmds; i++)
118 {
Greg Claytonc7bece562013-01-25 18:06:21 +0000119 const lldb::offset_t cmd_offset = data_offset; // Save this data_offset in case parsing of the segment goes awry!
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000120 uint32_t cmd = data.GetU32(&data_offset);
121 uint32_t cmd_size = data.GetU32(&data_offset);
Charles Davis510938e2013-08-27 05:04:57 +0000122 if (cmd == LC_UUID)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000123 {
Greg Clayton60830262011-02-04 18:53:10 +0000124 lldb_private::UUID file_uuid (data.GetData(&data_offset, 16), 16);
Johnny Chenfdc80a5c2012-02-01 01:49:50 +0000125 if (file_uuid == *uuid)
126 return true;
Johnny Chenfdc80a5c2012-02-01 01:49:50 +0000127 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000128 }
129 data_offset = cmd_offset + cmd_size;
130 }
131 return false;
132}
133
134bool
135UniversalMachOFileContainsArchAndUUID
136(
137 const FileSpec &file_spec,
138 const ArchSpec *arch,
Greg Clayton60830262011-02-04 18:53:10 +0000139 const lldb_private::UUID *uuid,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000140 off_t file_offset,
141 DataExtractor& data,
Greg Claytonc7bece562013-01-25 18:06:21 +0000142 lldb::offset_t data_offset,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000143 const uint32_t magic
144)
145{
Charles Davis510938e2013-08-27 05:04:57 +0000146 assert(magic == FAT_MAGIC || magic == FAT_CIGAM);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000147
148 // Universal mach-o files always have their headers encoded as BIG endian
149 data.SetByteOrder(eByteOrderBig);
150
151 uint32_t i;
152 const uint32_t nfat_arch = data.GetU32(&data_offset); // number of structs that follow
153 const uint32_t fat_header_and_arch_size = sizeof(struct fat_header) + nfat_arch * sizeof(struct fat_arch);
154 if (data.GetByteSize() < fat_header_and_arch_size)
155 {
156 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, fat_header_and_arch_size));
157 data.SetData (data_buffer_sp);
158 }
159
160 for (i=0; i<nfat_arch; i++)
161 {
162 cpu_type_t arch_cputype = data.GetU32(&data_offset); // cpu specifier (int)
163 cpu_subtype_t arch_cpusubtype = data.GetU32(&data_offset); // machine specifier (int)
164 uint32_t arch_offset = data.GetU32(&data_offset); // file offset to this object file
165 // uint32_t arch_size = data.GetU32(&data_offset); // size of this object file
166 // uint32_t arch_align = data.GetU32(&data_offset); // alignment as a power of 2
167 data_offset += 8; // Skip size and align as we don't need those
168 // Only process this slice if the cpu type/subtype matches
169 if (arch)
170 {
Greg Clayton41f92322010-06-11 03:25:34 +0000171 ArchSpec fat_arch(eArchTypeMachO, arch_cputype, arch_cpusubtype);
Sean Callananbab7cc42012-12-21 21:32:25 +0000172 if (!fat_arch.IsExactMatch(*arch))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000173 continue;
174 }
175
176 // Create a buffer with only the arch slice date in it
177 DataExtractor arch_data;
178 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset + arch_offset, 0x1000));
179 arch_data.SetData(data_buffer_sp);
Greg Claytonc7bece562013-01-25 18:06:21 +0000180 lldb::offset_t arch_data_offset = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000181 uint32_t arch_magic = arch_data.GetU32(&arch_data_offset);
182
183 switch (arch_magic)
184 {
Charles Davis510938e2013-08-27 05:04:57 +0000185 case MH_MAGIC:
186 case MH_CIGAM:
187 case MH_MAGIC_64:
188 case MH_CIGAM_64:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189 if (SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset + arch_offset, arch_data, arch_data_offset, arch_magic))
190 return true;
191 break;
192 }
193 }
194 return false;
195}
196
197static bool
198FileAtPathContainsArchAndUUID
199(
200 const FileSpec &file_spec,
201 const ArchSpec *arch,
Greg Clayton60830262011-02-04 18:53:10 +0000202 const lldb_private::UUID *uuid
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000203)
204{
205 DataExtractor data;
206 off_t file_offset = 0;
207 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, 0x1000));
208
209 if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0)
210 {
211 data.SetData(data_buffer_sp);
212
Greg Claytonc7bece562013-01-25 18:06:21 +0000213 lldb::offset_t data_offset = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000214 uint32_t magic = data.GetU32(&data_offset);
215
216 switch (magic)
217 {
218 // 32 bit mach-o file
Charles Davis510938e2013-08-27 05:04:57 +0000219 case MH_MAGIC:
220 case MH_CIGAM:
221 case MH_MAGIC_64:
222 case MH_CIGAM_64:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000223 return SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
224
225 // fat mach-o file
Charles Davis510938e2013-08-27 05:04:57 +0000226 case FAT_MAGIC:
227 case FAT_CIGAM:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000228 return UniversalMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
229
230 default:
231 break;
232 }
233 }
234 return false;
235}
236
Greg Clayton103f0282012-09-12 02:03:59 +0000237FileSpec
238Symbols::FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec,
239 const lldb_private::UUID *uuid,
240 const ArchSpec *arch)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000241{
242 char path[PATH_MAX];
243
244 FileSpec dsym_fspec;
245
246 if (dsym_bundle_fspec.GetPath(path, sizeof(path)))
247 {
248 ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
249
Greg Clayton4272cc72011-02-02 02:24:04 +0000250 lldb_utility::CleanUp <DIR *, int> dirp (opendir(path), NULL, closedir);
Greg Clayton293d5932011-02-01 05:15:02 +0000251 if (dirp.is_valid())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000252 {
Greg Clayton274060b2010-10-20 20:54:39 +0000253 dsym_fspec.GetDirectory().SetCString(path);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000254 struct dirent* dp;
Greg Clayton293d5932011-02-01 05:15:02 +0000255 while ((dp = readdir(dirp.get())) != NULL)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000256 {
257 // Only search directories
258 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
259 {
260 if (dp->d_namlen == 1 && dp->d_name[0] == '.')
261 continue;
262
263 if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
264 continue;
265 }
266
267 if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN)
268 {
Greg Clayton274060b2010-10-20 20:54:39 +0000269 dsym_fspec.GetFilename().SetCString(dp->d_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000270 if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid))
271 return dsym_fspec;
272 }
273 }
274 }
275 }
276 dsym_fspec.Clear();
277 return dsym_fspec;
278}
279
280static int
281LocateMacOSXFilesUsingDebugSymbols
282(
Greg Claytonb9a01b32012-02-26 05:51:37 +0000283 const ModuleSpec &module_spec,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000284 FileSpec *out_exec_fspec, // If non-NULL, try and find the executable
285 FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file
286)
287{
288 int items_found = 0;
289
290 if (out_exec_fspec)
291 out_exec_fspec->Clear();
292
293 if (out_dsym_fspec)
294 out_dsym_fspec->Clear();
295
Jason Molendaa3329782014-03-29 18:54:20 +0000296#if !defined (__arm__) && !defined (__arm64__) // No DebugSymbols on the iOS devices
Greg Claytondce502e2011-11-04 03:34:56 +0000297
Greg Claytonb9a01b32012-02-26 05:51:37 +0000298 const UUID *uuid = module_spec.GetUUIDPtr();
299 const ArchSpec *arch = module_spec.GetArchitecturePtr();
300
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000301 if (uuid && uuid->IsValid())
302 {
303 // Try and locate the dSYM file using DebugSymbols first
304 const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
305 if (module_uuid != NULL)
306 {
Greg Claytona63d08c2011-07-19 03:57:15 +0000307 CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes (NULL,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000308 module_uuid[0],
309 module_uuid[1],
310 module_uuid[2],
311 module_uuid[3],
312 module_uuid[4],
313 module_uuid[5],
314 module_uuid[6],
315 module_uuid[7],
316 module_uuid[8],
317 module_uuid[9],
318 module_uuid[10],
319 module_uuid[11],
320 module_uuid[12],
321 module_uuid[13],
322 module_uuid[14],
323 module_uuid[15]));
324
325 if (module_uuid_ref.get())
326 {
327 CFCReleaser<CFURLRef> exec_url;
Greg Claytonb9a01b32012-02-26 05:51:37 +0000328 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000329 if (exec_fspec)
330 {
331 char exec_cf_path[PATH_MAX];
332 if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
333 exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL,
334 (const UInt8 *)exec_cf_path,
335 strlen(exec_cf_path),
336 FALSE));
337 }
338
339 CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
340 char path[PATH_MAX];
341
342 if (dsym_url.get())
343 {
344 if (out_dsym_fspec)
345 {
346 if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
347 {
Jason Molendaa8805d32012-10-05 04:57:34 +0000348 out_dsym_fspec->SetFile(path, path[0] == '~');
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000349
350 if (out_dsym_fspec->GetFileType () == FileSpec::eFileTypeDirectory)
351 {
Greg Clayton103f0282012-09-12 02:03:59 +0000352 *out_dsym_fspec = Symbols::FindSymbolFileInBundle (*out_dsym_fspec, uuid, arch);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000353 if (*out_dsym_fspec)
354 ++items_found;
355 }
356 else
357 {
358 ++items_found;
359 }
360 }
361 }
362
Greg Claytond804d282012-03-15 21:01:31 +0000363 CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));
364 CFDictionaryRef uuid_dict = NULL;
365 if (dict.get())
366 {
Jason Molendac16b4af2013-05-03 23:56:12 +0000367 CFCString uuid_cfstr (uuid->GetAsString().c_str());
Jason Molenda743e43962012-10-02 22:23:42 +0000368 uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get()));
Greg Claytond804d282012-03-15 21:01:31 +0000369 if (uuid_dict)
370 {
371
372 CFStringRef actual_src_cfpath = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSourcePath")));
373 if (actual_src_cfpath)
374 {
375 CFStringRef build_src_cfpath = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGBuildSourcePath")));
376 if (build_src_cfpath)
377 {
378 char actual_src_path[PATH_MAX];
379 char build_src_path[PATH_MAX];
380 ::CFStringGetFileSystemRepresentation (actual_src_cfpath, actual_src_path, sizeof(actual_src_path));
381 ::CFStringGetFileSystemRepresentation (build_src_cfpath, build_src_path, sizeof(build_src_path));
Greg Clayton96816e42012-07-13 01:20:25 +0000382 if (actual_src_path[0] == '~')
383 {
384 FileSpec resolved_source_path(actual_src_path, true);
385 resolved_source_path.GetPath(actual_src_path, sizeof(actual_src_path));
386 }
Greg Claytond804d282012-03-15 21:01:31 +0000387 module_spec.GetSourceMappingList().Append (ConstString(build_src_path), ConstString(actual_src_path), true);
388 }
389 }
390 }
391 }
392
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000393 if (out_exec_fspec)
394 {
Greg Claytonc859e2d2012-02-13 23:10:39 +0000395 bool success = false;
Greg Claytond804d282012-03-15 21:01:31 +0000396 if (uuid_dict)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000397 {
Greg Claytond804d282012-03-15 21:01:31 +0000398 CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable")));
399 if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path)))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000400 {
Greg Claytond804d282012-03-15 21:01:31 +0000401 ++items_found;
402 out_exec_fspec->SetFile(path, path[0] == '~');
403 if (out_exec_fspec->Exists())
404 success = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000405 }
406 }
Greg Claytonc859e2d2012-02-13 23:10:39 +0000407
408 if (!success)
Greg Claytona63d08c2011-07-19 03:57:15 +0000409 {
410 // No dictionary, check near the dSYM bundle for an executable that matches...
411 if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
412 {
413 char *dsym_extension_pos = ::strstr (path, ".dSYM");
414 if (dsym_extension_pos)
415 {
416 *dsym_extension_pos = '\0';
417 FileSpec file_spec (path, true);
418 switch (file_spec.GetFileType())
419 {
420 case FileSpec::eFileTypeDirectory: // Bundle directory?
421 {
422 CFCBundle bundle (path);
423 CFCReleaser<CFURLRef> bundle_exe_url (bundle.CopyExecutableURL ());
424 if (bundle_exe_url.get())
425 {
426 if (::CFURLGetFileSystemRepresentation (bundle_exe_url.get(), true, (UInt8*)path, sizeof(path)-1))
427 {
428 FileSpec bundle_exe_file_spec (path, true);
429
430 if (FileAtPathContainsArchAndUUID (bundle_exe_file_spec, arch, uuid))
431 {
432 ++items_found;
433 *out_exec_fspec = bundle_exe_file_spec;
434 }
435 }
436 }
437 }
438 break;
439
440 case FileSpec::eFileTypePipe: // Forget pipes
441 case FileSpec::eFileTypeSocket: // We can't process socket files
442 case FileSpec::eFileTypeInvalid: // File doesn't exist...
443 break;
444
445 case FileSpec::eFileTypeUnknown:
446 case FileSpec::eFileTypeRegular:
447 case FileSpec::eFileTypeSymbolicLink:
448 case FileSpec::eFileTypeOther:
449 if (FileAtPathContainsArchAndUUID (file_spec, arch, uuid))
450 {
451 ++items_found;
452 *out_exec_fspec = file_spec;
453 }
454 break;
455 }
456 }
457 }
458 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000459 }
460 }
461 }
462 }
463 }
Greg Claytondce502e2011-11-04 03:34:56 +0000464#endif // #if !defined (__arm__)
465
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000466 return items_found;
467}
468
469static bool
Greg Claytonb9a01b32012-02-26 05:51:37 +0000470LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000471{
Greg Claytonb9a01b32012-02-26 05:51:37 +0000472 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000473 if (exec_fspec)
474 {
475 char path[PATH_MAX];
476 if (exec_fspec->GetPath(path, sizeof(path)))
477 {
478 // Make sure the module isn't already just a dSYM file...
479 if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
480 {
481 size_t obj_file_path_length = strlen(path);
Filipe Cabecinhas75bc95e2012-05-06 17:56:42 +0000482 strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
483 strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000484
Greg Clayton274060b2010-10-20 20:54:39 +0000485 dsym_fspec.SetFile(path, false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000486
Greg Claytonb9a01b32012-02-26 05:51:37 +0000487 if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000488 {
489 return true;
490 }
491 else
492 {
493 path[obj_file_path_length] = '\0';
494
495 char *last_dot = strrchr(path, '.');
496 while (last_dot != NULL && last_dot[0])
497 {
498 char *next_slash = strchr(last_dot, '/');
499 if (next_slash != NULL)
500 {
501 *next_slash = '\0';
Filipe Cabecinhas75bc95e2012-05-06 17:56:42 +0000502 strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
503 strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
Greg Clayton274060b2010-10-20 20:54:39 +0000504 dsym_fspec.SetFile(path, false);
Greg Claytonb9a01b32012-02-26 05:51:37 +0000505 if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000506 return true;
507 else
508 {
509 *last_dot = '\0';
510 char *prev_slash = strrchr(path, '/');
511 if (prev_slash != NULL)
512 *prev_slash = '\0';
513 else
514 break;
515 }
516 }
517 else
518 {
519 break;
520 }
521 }
522 }
523 }
524 }
525 }
526 dsym_fspec.Clear();
527 return false;
528}
529
530FileSpec
Greg Claytonb9a01b32012-02-26 05:51:37 +0000531Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000532{
Greg Claytonb9a01b32012-02-26 05:51:37 +0000533 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
534 const ArchSpec *arch = module_spec.GetArchitecturePtr();
535 const UUID *uuid = module_spec.GetUUIDPtr();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000536 Timer scoped_timer (__PRETTY_FUNCTION__,
537 "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
538 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
Greg Clayton64195a22011-02-23 00:35:02 +0000539 arch ? arch->GetArchitectureName() : "<NULL>",
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000540 uuid);
541
542 FileSpec objfile_fspec;
Greg Claytonb9a01b32012-02-26 05:51:37 +0000543 if (exec_fspec && FileAtPathContainsArchAndUUID (exec_fspec, arch, uuid))
544 objfile_fspec = exec_fspec;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000545 else
Greg Claytonb9a01b32012-02-26 05:51:37 +0000546 LocateMacOSXFilesUsingDebugSymbols (module_spec, &objfile_fspec, NULL);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000547 return objfile_fspec;
548}
549
550FileSpec
Greg Claytonb9a01b32012-02-26 05:51:37 +0000551Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000552{
Greg Claytonb9a01b32012-02-26 05:51:37 +0000553 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
554 const ArchSpec *arch = module_spec.GetArchitecturePtr();
555 const UUID *uuid = module_spec.GetUUIDPtr();
556
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000557 Timer scoped_timer (__PRETTY_FUNCTION__,
558 "LocateExecutableSymbolFile (file = %s, arch = %s, uuid = %p)",
559 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
Greg Clayton64195a22011-02-23 00:35:02 +0000560 arch ? arch->GetArchitectureName() : "<NULL>",
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000561 uuid);
562
563 FileSpec symbol_fspec;
564 // First try and find the dSYM in the same directory as the executable or in
565 // an appropriate parent directory
Greg Claytonb9a01b32012-02-26 05:51:37 +0000566 if (LocateDSYMInVincinityOfExecutable (module_spec, symbol_fspec) == false)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000567 {
568 // We failed to easily find the dSYM above, so use DebugSymbols
Greg Claytonb9a01b32012-02-26 05:51:37 +0000569 LocateMacOSXFilesUsingDebugSymbols (module_spec, NULL, &symbol_fspec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000570 }
571 return symbol_fspec;
572}
Greg Claytonc8f814d2012-09-27 03:13:55 +0000573
574
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000575static bool
576GetModuleSpecInfoFromUUIDDictionary (CFDictionaryRef uuid_dict, ModuleSpec &module_spec)
577{
578 bool success = false;
579 if (uuid_dict != NULL && CFGetTypeID (uuid_dict) == CFDictionaryGetTypeID ())
580 {
581 std::string str;
582 CFStringRef cf_str;
583
584 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable"));
585 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
586 {
587 if (CFCString::FileSystemRepresentation(cf_str, str))
588 module_spec.GetFileSpec().SetFile (str.c_str(), true);
589 }
590
591 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGDSYMPath"));
592 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
593 {
594 if (CFCString::FileSystemRepresentation(cf_str, str))
595 {
596 module_spec.GetSymbolFileSpec().SetFile (str.c_str(), true);
597 success = true;
598 }
599 }
600
601 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGArchitecture"));
602 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
603 {
604 if (CFCString::FileSystemRepresentation(cf_str, str))
605 module_spec.GetArchitecture().SetTriple(str.c_str());
606 }
607
608 std::string DBGBuildSourcePath;
609 std::string DBGSourcePath;
610
611 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGBuildSourcePath"));
612 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
613 {
614 CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
615 }
616
617 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSourcePath"));
618 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
619 {
620 CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
621 }
622
623 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
624 {
625 module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true);
626 }
627 }
628 return success;
629}
Greg Claytonc8f814d2012-09-27 03:13:55 +0000630
631
632bool
Jason Molendabb860bd2012-10-09 01:17:11 +0000633Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
Greg Claytonc8f814d2012-09-27 03:13:55 +0000634{
635 bool success = false;
636 const UUID *uuid_ptr = module_spec.GetUUIDPtr();
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000637 const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
Jason Molendabb860bd2012-10-09 01:17:11 +0000638
639 // It's expensive to check for the DBGShellCommands defaults setting, only do it once per
640 // lldb run and cache the result.
641 static bool g_have_checked_for_dbgshell_command = false;
642 static const char *g_dbgshell_command = NULL;
643 if (g_have_checked_for_dbgshell_command == false)
644 {
645 g_have_checked_for_dbgshell_command = true;
646 CFTypeRef defaults_setting = CFPreferencesCopyAppValue (CFSTR ("DBGShellCommands"), CFSTR ("com.apple.DebugSymbols"));
647 if (defaults_setting && CFGetTypeID (defaults_setting) == CFStringGetTypeID())
648 {
649 char cstr_buf[PATH_MAX];
650 if (CFStringGetCString ((CFStringRef) defaults_setting, cstr_buf, sizeof (cstr_buf), kCFStringEncodingUTF8))
651 {
652 g_dbgshell_command = strdup (cstr_buf); // this malloc'ed memory will never be freed
653 }
654 }
655 if (defaults_setting)
656 {
657 CFRelease (defaults_setting);
658 }
659 }
660
661 // When g_dbgshell_command is NULL, the user has not enabled the use of an external program
662 // to find the symbols, don't run it for them.
663 if (force_lookup == false && g_dbgshell_command == NULL)
664 {
665 return false;
666 }
667
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000668 if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists()))
Greg Claytonc8f814d2012-09-27 03:13:55 +0000669 {
670 static bool g_located_dsym_for_uuid_exe = false;
671 static bool g_dsym_for_uuid_exe_exists = false;
672 static char g_dsym_for_uuid_exe_path[PATH_MAX];
673 if (!g_located_dsym_for_uuid_exe)
674 {
675 g_located_dsym_for_uuid_exe = true;
676 const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
677 FileSpec dsym_for_uuid_exe_spec;
678 if (dsym_for_uuid_exe_path_cstr)
679 {
680 dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true);
681 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
682 }
683
684 if (!g_dsym_for_uuid_exe_exists)
685 {
Jason Molenda055c57b2012-10-30 21:26:30 +0000686 dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false);
Greg Claytonc8f814d2012-09-27 03:13:55 +0000687 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
688 if (!g_dsym_for_uuid_exe_exists)
689 {
Greg Claytonc7bece562013-01-25 18:06:21 +0000690 long bufsize;
Jason Molenda055c57b2012-10-30 21:26:30 +0000691 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1)
692 {
693 char buffer[bufsize];
694 struct passwd pwd;
695 struct passwd *tilde_rc = NULL;
696 // we are a library so we need to use the reentrant version of getpwnam()
697 if (getpwnam_r ("rc", &pwd, buffer, bufsize, &tilde_rc) == 0
698 && tilde_rc
699 && tilde_rc->pw_dir)
700 {
701 std::string dsymforuuid_path(tilde_rc->pw_dir);
702 dsymforuuid_path += "/bin/dsymForUUID";
703 dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false);
704 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
705 }
706 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000707 }
708 }
Jason Molendabb860bd2012-10-09 01:17:11 +0000709 if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL)
710 {
711 dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true);
712 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
713 }
714
Greg Claytonc8f814d2012-09-27 03:13:55 +0000715 if (g_dsym_for_uuid_exe_exists)
716 dsym_for_uuid_exe_spec.GetPath (g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path));
717 }
718 if (g_dsym_for_uuid_exe_exists)
719 {
Jason Molendac16b4af2013-05-03 23:56:12 +0000720 std::string uuid_str;
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000721 char file_path[PATH_MAX];
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000722 file_path[0] = '\0';
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000723
724 if (uuid_ptr)
Jason Molendac16b4af2013-05-03 23:56:12 +0000725 uuid_str = uuid_ptr->GetAsString();
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000726
727 if (file_spec_ptr)
728 file_spec_ptr->GetPath(file_path, sizeof(file_path));
729
730 StreamString command;
Jason Molendac16b4af2013-05-03 23:56:12 +0000731 if (!uuid_str.empty())
732 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, uuid_str.c_str());
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000733 else if (file_path && file_path[0])
Jason Molenda743e43962012-10-02 22:23:42 +0000734 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, file_path);
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000735
736 if (!command.GetString().empty())
Greg Claytonc8f814d2012-09-27 03:13:55 +0000737 {
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000738 int exit_status = -1;
739 int signo = -1;
740 std::string command_output;
741 Error error = Host::RunShellCommand (command.GetData(),
742 NULL, // current working directory
743 &exit_status, // Exit status
744 &signo, // Signal int *
745 &command_output, // Command output
746 30, // Large timeout to allow for long dsym download times
747 NULL); // Don't run in a shell (we don't need shell expansion)
748 if (error.Success() && exit_status == 0 && !command_output.empty())
Greg Claytonc8f814d2012-09-27 03:13:55 +0000749 {
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000750 CFCData data (CFDataCreateWithBytesNoCopy (NULL,
751 (const UInt8 *)command_output.data(),
752 command_output.size(),
753 kCFAllocatorNull));
754
755 CFCReleaser<CFDictionaryRef> plist((CFDictionaryRef)::CFPropertyListCreateFromXMLData (NULL, data.get(), kCFPropertyListImmutable, NULL));
756
Sean Callanan29214ab2013-02-08 23:17:17 +0000757 if (plist.get() && CFGetTypeID (plist.get()) == CFDictionaryGetTypeID ())
Greg Claytonc8f814d2012-09-27 03:13:55 +0000758 {
Jason Molendac16b4af2013-05-03 23:56:12 +0000759 if (!uuid_str.empty())
Greg Claytonc8f814d2012-09-27 03:13:55 +0000760 {
Jason Molendac16b4af2013-05-03 23:56:12 +0000761 CFCString uuid_cfstr(uuid_str.c_str());
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000762 CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue (plist.get(), uuid_cfstr.get());
763 success = GetModuleSpecInfoFromUUIDDictionary (uuid_dict, module_spec);
Greg Claytonc8f814d2012-09-27 03:13:55 +0000764 }
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000765 else
Greg Claytonc8f814d2012-09-27 03:13:55 +0000766 {
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000767 const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
768 if (num_values > 0)
Greg Claytonc8f814d2012-09-27 03:13:55 +0000769 {
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000770 std::vector<CFStringRef> keys (num_values, NULL);
771 std::vector<CFDictionaryRef> values (num_values, NULL);
772 ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]);
773 if (num_values == 1)
774 {
775 return GetModuleSpecInfoFromUUIDDictionary (values[0], module_spec);
776 }
777 else
778 {
779 for (CFIndex i=0; i<num_values; ++i)
780 {
781 ModuleSpec curr_module_spec;
782 if (GetModuleSpecInfoFromUUIDDictionary (values[i], curr_module_spec))
783 {
Sean Callananbf4b7be2012-12-13 22:07:14 +0000784 if (module_spec.GetArchitecture().IsCompatibleMatch(curr_module_spec.GetArchitecture()))
Greg Claytonb5f0fea2012-09-27 22:26:11 +0000785 {
786 module_spec = curr_module_spec;
787 return true;
788 }
789 }
790 }
791 }
Greg Claytonc8f814d2012-09-27 03:13:55 +0000792 }
793 }
794 }
795 }
796 }
797 }
798 }
799 return success;
800}
801