blob: bd49e83ed85d02af332a539fdee3dfc333615a31 [file] [log] [blame]
Chris Lattner24943d22010-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>
Greg Clayton1674b122010-07-21 22:12:05 +000014#include "llvm/Support/MachO.h"
Chris Lattner24943d22010-06-08 16:52:24 +000015
16// C++ Includes
17// Other libraries and framework includes
18#include <CoreFoundation/CoreFoundation.h>
19
20// Project includes
Chris Lattner24943d22010-06-08 16:52:24 +000021#include "lldb/Core/ArchSpec.h"
22#include "lldb/Core/DataBuffer.h"
23#include "lldb/Core/DataExtractor.h"
24#include "lldb/Core/Timer.h"
25#include "lldb/Core/UUID.h"
Greg Claytoncd548032011-02-01 01:31:41 +000026#include "lldb/Host/Endian.h"
Greg Claytonad400272011-02-01 05:15:02 +000027#include "lldb/Utility/CleanUp.h"
Daniel Dunbara1ebbd22011-10-31 22:50:53 +000028#include "Host/macosx/cfcpp/CFCBundle.h"
Greg Clayton54e7afa2010-07-09 20:39:50 +000029#include "Host/macosx/cfcpp/CFCReleaser.h"
Greg Claytonb72d0f02011-04-12 05:54:46 +000030#include "Host/macosx/cfcpp/CFCString.h"
Chris Lattner5bc7b672010-09-08 23:01:14 +000031#include "mach/machine.h"
Greg Clayton54e7afa2010-07-09 20:39:50 +000032
Greg Clayton0fa51242011-07-19 03:57:15 +000033
Chris Lattner24943d22010-06-08 16:52:24 +000034using namespace lldb;
35using namespace lldb_private;
Greg Clayton1674b122010-07-21 22:12:05 +000036using namespace llvm::MachO;
Chris Lattner24943d22010-06-08 16:52:24 +000037
38extern "C" {
Greg Clayton54e7afa2010-07-09 20:39:50 +000039
Chris Lattner24943d22010-06-08 16:52:24 +000040CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url);
41CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url);
Greg Clayton54e7afa2010-07-09 20:39:50 +000042
43}
Chris Lattner24943d22010-06-08 16:52:24 +000044
45static bool
46SkinnyMachOFileContainsArchAndUUID
47(
48 const FileSpec &file_spec,
49 const ArchSpec *arch,
Greg Clayton0467c782011-02-04 18:53:10 +000050 const lldb_private::UUID *uuid, // the UUID we are looking for
Chris Lattner24943d22010-06-08 16:52:24 +000051 off_t file_offset,
52 DataExtractor& data,
53 uint32_t data_offset,
54 const uint32_t magic
55)
56{
Greg Clayton1674b122010-07-21 22:12:05 +000057 assert(magic == HeaderMagic32 || magic == HeaderMagic32Swapped || magic == HeaderMagic64 || magic == HeaderMagic64Swapped);
58 if (magic == HeaderMagic32 || magic == HeaderMagic64)
Greg Claytoncd548032011-02-01 01:31:41 +000059 data.SetByteOrder (lldb::endian::InlHostByteOrder());
60 else if (lldb::endian::InlHostByteOrder() == eByteOrderBig)
Chris Lattner24943d22010-06-08 16:52:24 +000061 data.SetByteOrder (eByteOrderLittle);
62 else
63 data.SetByteOrder (eByteOrderBig);
64
65 uint32_t i;
66 const uint32_t cputype = data.GetU32(&data_offset); // cpu specifier
67 const uint32_t cpusubtype = data.GetU32(&data_offset); // machine specifier
68 data_offset+=4; // Skip mach file type
69 const uint32_t ncmds = data.GetU32(&data_offset); // number of load commands
70 const uint32_t sizeofcmds = data.GetU32(&data_offset); // the size of all the load commands
71 data_offset+=4; // Skip flags
72
73 // Check the architecture if we have a valid arch pointer
74 if (arch)
75 {
Greg Claytoncf015052010-06-11 03:25:34 +000076 ArchSpec file_arch(eArchTypeMachO, cputype, cpusubtype);
Chris Lattner24943d22010-06-08 16:52:24 +000077
78 if (file_arch != *arch)
79 return false;
80 }
81
82 // The file exists, and if a valid arch pointer was passed in we know
83 // if already matches, so we can return if we aren't looking for a specific
84 // UUID
85 if (uuid == NULL)
86 return true;
87
Greg Clayton1674b122010-07-21 22:12:05 +000088 if (magic == HeaderMagic64Swapped || magic == HeaderMagic64)
Chris Lattner24943d22010-06-08 16:52:24 +000089 data_offset += 4; // Skip reserved field for in mach_header_64
90
91 // Make sure we have enough data for all the load commands
Greg Clayton1674b122010-07-21 22:12:05 +000092 if (magic == HeaderMagic64Swapped || magic == HeaderMagic64)
Chris Lattner24943d22010-06-08 16:52:24 +000093 {
94 if (data.GetByteSize() < sizeof(struct mach_header_64) + sizeofcmds)
95 {
96 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header_64) + sizeofcmds));
97 data.SetData (data_buffer_sp);
98 }
99 }
100 else
101 {
102 if (data.GetByteSize() < sizeof(struct mach_header) + sizeofcmds)
103 {
104 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header) + sizeofcmds));
105 data.SetData (data_buffer_sp);
106 }
107 }
108
109 for (i=0; i<ncmds; i++)
110 {
111 const uint32_t cmd_offset = data_offset; // Save this data_offset in case parsing of the segment goes awry!
112 uint32_t cmd = data.GetU32(&data_offset);
113 uint32_t cmd_size = data.GetU32(&data_offset);
Greg Clayton1674b122010-07-21 22:12:05 +0000114 if (cmd == LoadCommandUUID)
Chris Lattner24943d22010-06-08 16:52:24 +0000115 {
Greg Clayton0467c782011-02-04 18:53:10 +0000116 lldb_private::UUID file_uuid (data.GetData(&data_offset, 16), 16);
Chris Lattner24943d22010-06-08 16:52:24 +0000117 return file_uuid == *uuid;
118 }
119 data_offset = cmd_offset + cmd_size;
120 }
121 return false;
122}
123
124bool
125UniversalMachOFileContainsArchAndUUID
126(
127 const FileSpec &file_spec,
128 const ArchSpec *arch,
Greg Clayton0467c782011-02-04 18:53:10 +0000129 const lldb_private::UUID *uuid,
Chris Lattner24943d22010-06-08 16:52:24 +0000130 off_t file_offset,
131 DataExtractor& data,
132 uint32_t data_offset,
133 const uint32_t magic
134)
135{
Greg Clayton1674b122010-07-21 22:12:05 +0000136 assert(magic == UniversalMagic || magic == UniversalMagicSwapped);
Chris Lattner24943d22010-06-08 16:52:24 +0000137
138 // Universal mach-o files always have their headers encoded as BIG endian
139 data.SetByteOrder(eByteOrderBig);
140
141 uint32_t i;
142 const uint32_t nfat_arch = data.GetU32(&data_offset); // number of structs that follow
143 const uint32_t fat_header_and_arch_size = sizeof(struct fat_header) + nfat_arch * sizeof(struct fat_arch);
144 if (data.GetByteSize() < fat_header_and_arch_size)
145 {
146 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, fat_header_and_arch_size));
147 data.SetData (data_buffer_sp);
148 }
149
150 for (i=0; i<nfat_arch; i++)
151 {
152 cpu_type_t arch_cputype = data.GetU32(&data_offset); // cpu specifier (int)
153 cpu_subtype_t arch_cpusubtype = data.GetU32(&data_offset); // machine specifier (int)
154 uint32_t arch_offset = data.GetU32(&data_offset); // file offset to this object file
155 // uint32_t arch_size = data.GetU32(&data_offset); // size of this object file
156 // uint32_t arch_align = data.GetU32(&data_offset); // alignment as a power of 2
157 data_offset += 8; // Skip size and align as we don't need those
158 // Only process this slice if the cpu type/subtype matches
159 if (arch)
160 {
Greg Claytoncf015052010-06-11 03:25:34 +0000161 ArchSpec fat_arch(eArchTypeMachO, arch_cputype, arch_cpusubtype);
Chris Lattner24943d22010-06-08 16:52:24 +0000162 if (fat_arch != *arch)
163 continue;
164 }
165
166 // Create a buffer with only the arch slice date in it
167 DataExtractor arch_data;
168 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset + arch_offset, 0x1000));
169 arch_data.SetData(data_buffer_sp);
170 uint32_t arch_data_offset = 0;
171 uint32_t arch_magic = arch_data.GetU32(&arch_data_offset);
172
173 switch (arch_magic)
174 {
Greg Clayton1674b122010-07-21 22:12:05 +0000175 case HeaderMagic32:
176 case HeaderMagic32Swapped:
177 case HeaderMagic64:
178 case HeaderMagic64Swapped:
Chris Lattner24943d22010-06-08 16:52:24 +0000179 if (SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset + arch_offset, arch_data, arch_data_offset, arch_magic))
180 return true;
181 break;
182 }
183 }
184 return false;
185}
186
187static bool
188FileAtPathContainsArchAndUUID
189(
190 const FileSpec &file_spec,
191 const ArchSpec *arch,
Greg Clayton0467c782011-02-04 18:53:10 +0000192 const lldb_private::UUID *uuid
Chris Lattner24943d22010-06-08 16:52:24 +0000193)
194{
195 DataExtractor data;
196 off_t file_offset = 0;
197 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, 0x1000));
198
199 if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0)
200 {
201 data.SetData(data_buffer_sp);
202
203 uint32_t data_offset = 0;
204 uint32_t magic = data.GetU32(&data_offset);
205
206 switch (magic)
207 {
208 // 32 bit mach-o file
Greg Clayton1674b122010-07-21 22:12:05 +0000209 case HeaderMagic32:
210 case HeaderMagic32Swapped:
211 case HeaderMagic64:
212 case HeaderMagic64Swapped:
Chris Lattner24943d22010-06-08 16:52:24 +0000213 return SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
214
215 // fat mach-o file
Greg Clayton1674b122010-07-21 22:12:05 +0000216 case UniversalMagic:
217 case UniversalMagicSwapped:
Chris Lattner24943d22010-06-08 16:52:24 +0000218 return UniversalMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
219
220 default:
221 break;
222 }
223 }
224 return false;
225}
226
227static FileSpec
228LocateDSYMMachFileInDSYMBundle
229(
230 const FileSpec& dsym_bundle_fspec,
Greg Clayton0467c782011-02-04 18:53:10 +0000231 const lldb_private::UUID *uuid,
Chris Lattner24943d22010-06-08 16:52:24 +0000232 const ArchSpec *arch)
233{
234 char path[PATH_MAX];
235
236 FileSpec dsym_fspec;
237
238 if (dsym_bundle_fspec.GetPath(path, sizeof(path)))
239 {
240 ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
241
Greg Clayton52fd9842011-02-02 02:24:04 +0000242 lldb_utility::CleanUp <DIR *, int> dirp (opendir(path), NULL, closedir);
Greg Claytonad400272011-02-01 05:15:02 +0000243 if (dirp.is_valid())
Chris Lattner24943d22010-06-08 16:52:24 +0000244 {
Greg Clayton537a7a82010-10-20 20:54:39 +0000245 dsym_fspec.GetDirectory().SetCString(path);
Chris Lattner24943d22010-06-08 16:52:24 +0000246 struct dirent* dp;
Greg Claytonad400272011-02-01 05:15:02 +0000247 while ((dp = readdir(dirp.get())) != NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000248 {
249 // Only search directories
250 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
251 {
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 {
Greg Clayton537a7a82010-10-20 20:54:39 +0000261 dsym_fspec.GetFilename().SetCString(dp->d_name);
Chris Lattner24943d22010-06-08 16:52:24 +0000262 if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid))
263 return dsym_fspec;
264 }
265 }
266 }
267 }
268 dsym_fspec.Clear();
269 return dsym_fspec;
270}
271
272static int
273LocateMacOSXFilesUsingDebugSymbols
274(
275 const FileSpec *exec_fspec, // An executable path that may or may not be correct if UUID is specified
276 const ArchSpec* arch, // Limit the search to files with this architecture if non-NULL
Greg Clayton0467c782011-02-04 18:53:10 +0000277 const lldb_private::UUID *uuid, // Match the UUID value if non-NULL,
Chris Lattner24943d22010-06-08 16:52:24 +0000278 FileSpec *out_exec_fspec, // If non-NULL, try and find the executable
279 FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file
280)
281{
282 int items_found = 0;
283
284 if (out_exec_fspec)
285 out_exec_fspec->Clear();
286
287 if (out_dsym_fspec)
288 out_dsym_fspec->Clear();
289
290 if (uuid && uuid->IsValid())
291 {
292 // Try and locate the dSYM file using DebugSymbols first
293 const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
294 if (module_uuid != NULL)
295 {
Greg Clayton0fa51242011-07-19 03:57:15 +0000296 CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes (NULL,
Chris Lattner24943d22010-06-08 16:52:24 +0000297 module_uuid[0],
298 module_uuid[1],
299 module_uuid[2],
300 module_uuid[3],
301 module_uuid[4],
302 module_uuid[5],
303 module_uuid[6],
304 module_uuid[7],
305 module_uuid[8],
306 module_uuid[9],
307 module_uuid[10],
308 module_uuid[11],
309 module_uuid[12],
310 module_uuid[13],
311 module_uuid[14],
312 module_uuid[15]));
313
314 if (module_uuid_ref.get())
315 {
316 CFCReleaser<CFURLRef> exec_url;
317
318 if (exec_fspec)
319 {
320 char exec_cf_path[PATH_MAX];
321 if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
322 exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL,
323 (const UInt8 *)exec_cf_path,
324 strlen(exec_cf_path),
325 FALSE));
326 }
327
328 CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
329 char path[PATH_MAX];
330
331 if (dsym_url.get())
332 {
333 if (out_dsym_fspec)
334 {
335 if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
336 {
Greg Clayton537a7a82010-10-20 20:54:39 +0000337 out_dsym_fspec->SetFile(path, false);
Chris Lattner24943d22010-06-08 16:52:24 +0000338
339 if (out_dsym_fspec->GetFileType () == FileSpec::eFileTypeDirectory)
340 {
341 *out_dsym_fspec = LocateDSYMMachFileInDSYMBundle (*out_dsym_fspec, uuid, arch);
342 if (*out_dsym_fspec)
343 ++items_found;
344 }
345 else
346 {
347 ++items_found;
348 }
349 }
350 }
351
352 if (out_exec_fspec)
353 {
354 CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));;
355 if (dict.get())
356 {
Greg Claytonb72d0f02011-04-12 05:54:46 +0000357 char uuid_cstr_buf[64];
358 const char *uuid_cstr = uuid->GetAsCString (uuid_cstr_buf, sizeof(uuid_cstr_buf));
359 CFCString uuid_cfstr (uuid_cstr);
360 CFDictionaryRef uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get()));
361 if (uuid_dict)
Chris Lattner24943d22010-06-08 16:52:24 +0000362 {
Greg Claytonb72d0f02011-04-12 05:54:46 +0000363 CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable")));
364 if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path)))
365 {
366 ++items_found;
367 out_exec_fspec->SetFile(path, path[0] == '~');
368 }
Chris Lattner24943d22010-06-08 16:52:24 +0000369 }
370 }
Greg Clayton0fa51242011-07-19 03:57:15 +0000371 else
372 {
373 // No dictionary, check near the dSYM bundle for an executable that matches...
374 if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
375 {
376 char *dsym_extension_pos = ::strstr (path, ".dSYM");
377 if (dsym_extension_pos)
378 {
379 *dsym_extension_pos = '\0';
380 FileSpec file_spec (path, true);
381 switch (file_spec.GetFileType())
382 {
383 case FileSpec::eFileTypeDirectory: // Bundle directory?
384 {
385 CFCBundle bundle (path);
386 CFCReleaser<CFURLRef> bundle_exe_url (bundle.CopyExecutableURL ());
387 if (bundle_exe_url.get())
388 {
389 if (::CFURLGetFileSystemRepresentation (bundle_exe_url.get(), true, (UInt8*)path, sizeof(path)-1))
390 {
391 FileSpec bundle_exe_file_spec (path, true);
392
393 if (FileAtPathContainsArchAndUUID (bundle_exe_file_spec, arch, uuid))
394 {
395 ++items_found;
396 *out_exec_fspec = bundle_exe_file_spec;
397 }
398 }
399 }
400 }
401 break;
402
403 case FileSpec::eFileTypePipe: // Forget pipes
404 case FileSpec::eFileTypeSocket: // We can't process socket files
405 case FileSpec::eFileTypeInvalid: // File doesn't exist...
406 break;
407
408 case FileSpec::eFileTypeUnknown:
409 case FileSpec::eFileTypeRegular:
410 case FileSpec::eFileTypeSymbolicLink:
411 case FileSpec::eFileTypeOther:
412 if (FileAtPathContainsArchAndUUID (file_spec, arch, uuid))
413 {
414 ++items_found;
415 *out_exec_fspec = file_spec;
416 }
417 break;
418 }
419 }
420 }
421 }
Chris Lattner24943d22010-06-08 16:52:24 +0000422 }
423 }
424 }
425 }
426 }
427 return items_found;
428}
429
430static bool
Greg Clayton0467c782011-02-04 18:53:10 +0000431LocateDSYMInVincinityOfExecutable (const FileSpec *exec_fspec, const ArchSpec* arch, const lldb_private::UUID *uuid, FileSpec &dsym_fspec)
Chris Lattner24943d22010-06-08 16:52:24 +0000432{
433 if (exec_fspec)
434 {
435 char path[PATH_MAX];
436 if (exec_fspec->GetPath(path, sizeof(path)))
437 {
438 // Make sure the module isn't already just a dSYM file...
439 if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
440 {
441 size_t obj_file_path_length = strlen(path);
442 strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
443 strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
444
Greg Clayton537a7a82010-10-20 20:54:39 +0000445 dsym_fspec.SetFile(path, false);
Chris Lattner24943d22010-06-08 16:52:24 +0000446
447 if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid))
448 {
449 return true;
450 }
451 else
452 {
453 path[obj_file_path_length] = '\0';
454
455 char *last_dot = strrchr(path, '.');
456 while (last_dot != NULL && last_dot[0])
457 {
458 char *next_slash = strchr(last_dot, '/');
459 if (next_slash != NULL)
460 {
461 *next_slash = '\0';
462 strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
463 strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
Greg Clayton537a7a82010-10-20 20:54:39 +0000464 dsym_fspec.SetFile(path, false);
Chris Lattner24943d22010-06-08 16:52:24 +0000465 if (dsym_fspec.Exists())
466 return true;
467 else
468 {
469 *last_dot = '\0';
470 char *prev_slash = strrchr(path, '/');
471 if (prev_slash != NULL)
472 *prev_slash = '\0';
473 else
474 break;
475 }
476 }
477 else
478 {
479 break;
480 }
481 }
482 }
483 }
484 }
485 }
486 dsym_fspec.Clear();
487 return false;
488}
489
490FileSpec
Greg Clayton0467c782011-02-04 18:53:10 +0000491Symbols::LocateExecutableObjectFile (const FileSpec *exec_fspec, const ArchSpec* arch, const lldb_private::UUID *uuid)
Chris Lattner24943d22010-06-08 16:52:24 +0000492{
493 Timer scoped_timer (__PRETTY_FUNCTION__,
494 "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
495 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
Greg Clayton940b1032011-02-23 00:35:02 +0000496 arch ? arch->GetArchitectureName() : "<NULL>",
Chris Lattner24943d22010-06-08 16:52:24 +0000497 uuid);
498
499 FileSpec objfile_fspec;
500 if (exec_fspec && FileAtPathContainsArchAndUUID (*exec_fspec, arch, uuid))
501 objfile_fspec = *exec_fspec;
502 else
503 LocateMacOSXFilesUsingDebugSymbols (exec_fspec, arch, uuid, &objfile_fspec, NULL);
504 return objfile_fspec;
505}
506
507FileSpec
Greg Clayton0467c782011-02-04 18:53:10 +0000508Symbols::LocateExecutableSymbolFile (const FileSpec *exec_fspec, const ArchSpec* arch, const lldb_private::UUID *uuid)
Chris Lattner24943d22010-06-08 16:52:24 +0000509{
510 Timer scoped_timer (__PRETTY_FUNCTION__,
511 "LocateExecutableSymbolFile (file = %s, arch = %s, uuid = %p)",
512 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
Greg Clayton940b1032011-02-23 00:35:02 +0000513 arch ? arch->GetArchitectureName() : "<NULL>",
Chris Lattner24943d22010-06-08 16:52:24 +0000514 uuid);
515
516 FileSpec symbol_fspec;
517 // First try and find the dSYM in the same directory as the executable or in
518 // an appropriate parent directory
519 if (LocateDSYMInVincinityOfExecutable (exec_fspec, arch, uuid, symbol_fspec) == false)
520 {
521 // We failed to easily find the dSYM above, so use DebugSymbols
522 LocateMacOSXFilesUsingDebugSymbols (exec_fspec, arch, uuid, NULL, &symbol_fspec);
523 }
524 return symbol_fspec;
525}