LLDB mainline
SymbolLocatorDebugSymbols.cpp
Go to the documentation of this file.
1//===-- SymbolLocatorDebugSymbols.cpp -------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
12#include "lldb/Core/Debugger.h"
13#include "lldb/Core/Module.h"
17#include "lldb/Core/Progress.h"
18#include "lldb/Core/Section.h"
20#include "lldb/Host/Host.h"
21#include "lldb/Host/HostInfo.h"
23#include "lldb/Target/Target.h"
28#include "lldb/Utility/Log.h"
30#include "lldb/Utility/Timer.h"
31#include "lldb/Utility/UUID.h"
32
33#include "llvm/ADT/SmallSet.h"
34#include "llvm/Support/FileSystem.h"
35#include "llvm/Support/ThreadPool.h"
36
41
42#include "mach/machine.h"
43
44#include <CoreFoundation/CoreFoundation.h>
45
46#include <cstring>
47#include <dirent.h>
48#include <dlfcn.h>
49#include <memory>
50#include <optional>
51#include <pwd.h>
52
53using namespace lldb;
54using namespace lldb_private;
55
56namespace {
57struct DebugSymbolsDylibFunctions {
58 CFURLRef (*DBGCopyFullDSYMURLForUUID)(CFUUIDRef uuid,
59 CFURLRef exec_url) = nullptr;
60 CFDictionaryRef (*DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) = nullptr;
61
62 DebugSymbolsDylibFunctions() {
63 void *handle = dlopen(
64 "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols",
65 RTLD_LAZY | RTLD_LOCAL);
66 if (handle) {
67 DBGCopyFullDSYMURLForUUID = (CFURLRef (*)(CFUUIDRef, CFURLRef))dlsym(
68 handle, "DBGCopyFullDSYMURLForUUID");
69 DBGCopyDSYMPropertyLists = (CFDictionaryRef (*)(CFURLRef))dlsym(
70 handle, "DBGCopyDSYMPropertyLists");
71 }
72 }
73
74 /// Returns true if all DebugSymbols functions were found in the framework.
75 bool FoundFunctions() const {
76 return DBGCopyFullDSYMURLForUUID != nullptr &&
77 DBGCopyDSYMPropertyLists != nullptr;
78 }
79};
80} // namespace
81
82static const DebugSymbolsDylibFunctions &GetDebugSymbolsDylibFunctions() {
83 // This is a static local to avoid race conditions.
84 static DebugSymbolsDylibFunctions g_functions;
85 return g_functions;
86}
87
89
91
98
102
104 return "DebugSymbols symbol locator.";
105}
106
110
112 const ModuleSpec &module_spec) {
113 Log *log = GetLog(LLDBLog::Host);
114 if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
115 LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled.");
116 return {};
117 }
118 ModuleSpec return_module_spec;
119 return_module_spec = module_spec;
120 return_module_spec.GetFileSpec().Clear();
121 return_module_spec.GetSymbolFileSpec().Clear();
122
123 const UUID *uuid = module_spec.GetUUIDPtr();
124 const ArchSpec *arch = module_spec.GetArchitecturePtr();
125
126 int items_found = 0;
127
128 const DebugSymbolsDylibFunctions &dylib_functions =
130 if (!dylib_functions.FoundFunctions())
131 return {};
132
133 if (uuid && uuid->IsValid()) {
134 // Try and locate the dSYM file using DebugSymbols first
135 llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
136 if (module_uuid.size() == 16) {
137 CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
138 NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
139 module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
140 module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
141 module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
142
143 if (module_uuid_ref.get()) {
144 CFCReleaser<CFURLRef> exec_url;
145 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
146 if (exec_fspec) {
147 char exec_cf_path[PATH_MAX];
148 if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
149 exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
150 NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
151 FALSE));
152 }
153
154 CFCReleaser<CFURLRef> dsym_url(
155 dylib_functions.DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(),
156 exec_url.get()));
157 char path[PATH_MAX];
158
159 if (dsym_url.get()) {
160 if (::CFURLGetFileSystemRepresentation(
161 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
162 LLDB_LOGF(log,
163 "DebugSymbols framework returned dSYM path of %s for "
164 "UUID %s -- looking for the dSYM",
165 path, uuid->GetAsString().c_str());
166 FileSpec dsym_filespec(path);
167 if (path[0] == '~')
168 FileSystem::Instance().Resolve(dsym_filespec);
169
170 if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
172 dsym_filespec, uuid, arch);
173 ++items_found;
174 } else {
175 ++items_found;
176 }
177 return_module_spec.GetSymbolFileSpec() = dsym_filespec;
178 }
179
180 bool success = false;
181 if (log) {
182 if (::CFURLGetFileSystemRepresentation(
183 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
184 LLDB_LOGF(log,
185 "DebugSymbols framework returned dSYM path of %s for "
186 "UUID %s -- looking for an exec file",
187 path, uuid->GetAsString().c_str());
188 }
189 }
190
192 dylib_functions.DBGCopyDSYMPropertyLists(dsym_url.get()));
193 CFDictionaryRef uuid_dict = NULL;
194 if (dict.get()) {
195 CFCString uuid_cfstr(uuid->GetAsString().c_str());
196 uuid_dict = static_cast<CFDictionaryRef>(
197 ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
198 }
199
200 // Check to see if we have the file on the local filesystem.
201 if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
202 ModuleSpec exe_spec;
203 exe_spec.GetFileSpec() = module_spec.GetFileSpec();
204 exe_spec.GetUUID() = module_spec.GetUUID();
205 ModuleSP module_sp;
206 module_sp = std::make_shared<Module>(exe_spec);
207 if (module_sp && module_sp->GetObjectFile() &&
208 module_sp->MatchesModuleSpec(exe_spec)) {
209 success = true;
210 return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
211 LLDB_LOGF(log, "using original binary filepath %s for UUID %s",
212 module_spec.GetFileSpec().GetPath().c_str(),
213 uuid->GetAsString().c_str());
214 ++items_found;
215 }
216 }
217
218 // Check if the requested image is in our shared cache.
219 if (!success) {
220 SymbolSharedCacheUse sc_mode =
223 std::string filepath = module_spec.GetFileSpec().GetPath();
224 SharedCacheImageInfo image_info =
225 HostInfo::GetSharedCacheImageInfo(filepath, sc_mode);
226
227 // If we found it and it has the correct UUID, let's proceed with
228 // creating a module from the memory contents.
229 if (image_info.GetUUID() &&
230 (!module_spec.GetUUID() ||
231 module_spec.GetUUID() == image_info.GetUUID())) {
232 success = true;
233 return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
234 LLDB_LOGF(log,
235 "using binary from shared cache for filepath %s for "
236 "UUID %s",
237 module_spec.GetFileSpec().GetPath().c_str(),
238 uuid->GetAsString().c_str());
239 ++items_found;
240 }
241 }
242
243 // Use the DBGSymbolRichExecutable filepath if present
244 if (!success && uuid_dict) {
245 CFStringRef exec_cf_path =
246 static_cast<CFStringRef>(::CFDictionaryGetValue(
247 uuid_dict, CFSTR("DBGSymbolRichExecutable")));
248 if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
249 exec_cf_path, path, sizeof(path))) {
250 LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s",
251 path, uuid->GetAsString().c_str());
252 ++items_found;
253 FileSpec exec_filespec(path);
254 if (path[0] == '~')
255 FileSystem::Instance().Resolve(exec_filespec);
256 if (FileSystem::Instance().Exists(exec_filespec)) {
257 success = true;
258 return_module_spec.GetFileSpec() = exec_filespec;
259 }
260 }
261 }
262
263 // Look next to the dSYM for the binary file.
264 if (!success) {
265 if (::CFURLGetFileSystemRepresentation(
266 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
267 char *dsym_extension_pos = ::strstr(path, ".dSYM");
268 if (dsym_extension_pos) {
269 *dsym_extension_pos = '\0';
270 LLDB_LOGF(log,
271 "Looking for executable binary next to dSYM "
272 "bundle with name with name %s",
273 path);
274 FileSpec file_spec(path);
275 FileSystem::Instance().Resolve(file_spec);
276 ModuleSpec matched_module_spec;
277 using namespace llvm::sys::fs;
278 switch (get_file_type(file_spec.GetPath())) {
279
280 case file_type::directory_file: // Bundle directory?
281 {
282 CFCBundle bundle(path);
283 CFCReleaser<CFURLRef> bundle_exe_url(
284 bundle.CopyExecutableURL());
285 if (bundle_exe_url.get()) {
286 if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
287 true, (UInt8 *)path,
288 sizeof(path) - 1)) {
289 FileSpec bundle_exe_file_spec(path);
290 FileSystem::Instance().Resolve(bundle_exe_file_spec);
291 if (ModuleSpecList module_specs =
293 bundle_exe_file_spec, 0, 0);
294 module_specs.FindMatchingModuleSpec(
295 module_spec, matched_module_spec)) {
296 ++items_found;
297 return_module_spec.GetFileSpec() = bundle_exe_file_spec;
298 LLDB_LOGF(log,
299 "Executable binary %s next to dSYM is "
300 "compatible; using",
301 path);
302 }
303 }
304 }
305 } break;
306
307 case file_type::fifo_file: // Forget pipes
308 case file_type::socket_file: // We can't process socket files
309 case file_type::file_not_found: // File doesn't exist...
310 case file_type::status_error:
311 break;
312
313 case file_type::type_unknown:
314 case file_type::regular_file:
315 case file_type::symlink_file:
316 case file_type::block_file:
317 case file_type::character_file:
318 if (ModuleSpecList module_specs =
320 module_specs.FindMatchingModuleSpec(
321 module_spec, matched_module_spec)) {
322 ++items_found;
323 return_module_spec.GetFileSpec() = file_spec;
324 LLDB_LOGF(log,
325 "Executable binary %s next to dSYM is "
326 "compatible; using",
327 path);
328 }
329 break;
330 }
331 }
332 }
333 }
334 }
335 }
336 }
337 }
338
339 if (items_found)
340 return return_module_spec;
341
342 return {};
343}
344
346 const FileSpec &dsym_bundle_fspec, const UUID *uuid, const ArchSpec *arch) {
347 std::string dsym_bundle_path = dsym_bundle_fspec.GetPath();
348 llvm::SmallString<128> buffer(dsym_bundle_path);
349 llvm::sys::path::append(buffer, "Contents", "Resources", "DWARF");
350
351 std::error_code EC;
352 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs =
354 llvm::vfs::recursive_directory_iterator Iter(*vfs, buffer.str(), EC);
355 llvm::vfs::recursive_directory_iterator End;
356 for (; Iter != End && !EC; Iter.increment(EC)) {
357 llvm::ErrorOr<llvm::vfs::Status> Status = vfs->status(Iter->path());
358 if (Status->isDirectory())
359 continue;
360
361 FileSpec dsym_fspec(Iter->path());
362 ModuleSpecList module_specs =
363 ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0);
364 if (module_specs.GetSize() > 0) {
365 ModuleSpec spec;
366 for (size_t i = 0; i < module_specs.GetSize(); ++i) {
367 bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
368 assert(got_spec); // The call has side-effects so can't be inlined.
370 if ((uuid == nullptr ||
371 (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
372 (arch == nullptr ||
373 (spec.GetArchitecturePtr() &&
374 spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
375 return dsym_fspec;
376 }
377 }
378 }
379 }
380
381 return {};
382}
383
384static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec,
385 const ArchSpec *arch,
386 const lldb_private::UUID *uuid) {
387 ModuleSpecList module_specs =
388 ObjectFile::GetModuleSpecifications(file_fspec, 0, 0);
389 if (module_specs.GetSize() > 0) {
390 ModuleSpec spec;
391 for (size_t i = 0; i < module_specs.GetSize(); ++i) {
392 bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
394 assert(got_spec);
395 if ((uuid == nullptr || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
396 (arch == nullptr ||
397 (spec.GetArchitecturePtr() &&
398 spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
399 return true;
400 }
401 }
402 }
403 return false;
404}
405
406// Given a binary exec_fspec, and a ModuleSpec with an architecture/uuid,
407// return true if there is a matching dSYM bundle next to the exec_fspec,
408// and return that value in dsym_fspec.
409// If there is a .dSYM.yaa compressed archive next to the exec_fspec,
410// call through PluginManager::DownloadObjectAndSymbolFile to download the
411// expanded/uncompressed dSYM and return that filepath in dsym_fspec.
412static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec,
413 const FileSpec &exec_fspec,
414 FileSpec &dsym_fspec) {
415 llvm::StringRef filename = exec_fspec.GetFilename();
416 FileSpec dsym_directory = exec_fspec;
417 dsym_directory.RemoveLastPathComponent();
418
419 std::string dsym_filename = filename.str();
420 dsym_filename += ".dSYM";
421 dsym_directory.AppendPathComponent(dsym_filename);
422 dsym_directory.AppendPathComponent("Contents");
423 dsym_directory.AppendPathComponent("Resources");
424 dsym_directory.AppendPathComponent("DWARF");
425
426 if (FileSystem::Instance().Exists(dsym_directory)) {
427
428 // See if the binary name exists in the dSYM DWARF
429 // subdir.
430 dsym_fspec = dsym_directory;
431 dsym_fspec.AppendPathComponent(filename);
432 if (FileSystem::Instance().Exists(dsym_fspec) &&
434 mod_spec.GetUUIDPtr())) {
435 return true;
436 }
437
438 // See if we have "../CF.framework" - so we'll look for
439 // CF.framework.dSYM/Contents/Resources/DWARF/CF
440 // We need to drop the last suffix after '.' to match
441 // 'CF' in the DWARF subdir.
442 std::string binary_name = filename.str();
443 auto last_dot = binary_name.find_last_of('.');
444 if (last_dot != std::string::npos) {
445 binary_name.erase(last_dot);
446 dsym_fspec = dsym_directory;
447 dsym_fspec.AppendPathComponent(binary_name);
448 if (FileSystem::Instance().Exists(dsym_fspec) &&
450 mod_spec.GetArchitecturePtr(),
451 mod_spec.GetUUIDPtr())) {
452 return true;
453 }
454 }
455 }
456
457 // See if we have a .dSYM.yaa next to this executable path.
458 FileSpec dsym_yaa_fspec = exec_fspec;
459 dsym_yaa_fspec.RemoveLastPathComponent();
460 std::string dsym_yaa_filename = filename.str();
461 dsym_yaa_filename += ".dSYM.yaa";
462 dsym_yaa_fspec.AppendPathComponent(dsym_yaa_filename);
463
464 if (FileSystem::Instance().Exists(dsym_yaa_fspec)) {
465 ModuleSpec mutable_mod_spec = mod_spec;
468 true) &&
469 FileSystem::Instance().Exists(mutable_mod_spec.GetSymbolFileSpec())) {
470 dsym_fspec = mutable_mod_spec.GetSymbolFileSpec();
471 return true;
472 }
473 }
474
475 return false;
476}
477
478// Given a ModuleSpec with a FileSpec and optionally uuid/architecture
479// filled in, look for a .dSYM bundle next to that binary. Returns true
480// if a .dSYM bundle is found, and that path is returned in the dsym_fspec
481// FileSpec.
482//
483// This routine looks a few directory layers above the given exec_path -
484// exec_path might be /System/Library/Frameworks/CF.framework/CF and the
485// dSYM might be /System/Library/Frameworks/CF.framework.dSYM.
486//
487// If there is a .dSYM.yaa compressed archive found next to the binary,
488// we'll call DownloadObjectAndSymbolFile to expand it into a plain .dSYM
489static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
490 FileSpec &dsym_fspec) {
491 Log *log = GetLog(LLDBLog::Host);
492 const FileSpec &exec_fspec = module_spec.GetFileSpec();
493 if (exec_fspec) {
494 if (::LookForDsymNextToExecutablePath(module_spec, exec_fspec,
495 dsym_fspec)) {
496 LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s",
497 dsym_fspec.GetPath().c_str());
498 return true;
499 } else {
500 FileSpec parent_dirs = exec_fspec;
501
502 // Remove the binary name from the FileSpec
503 parent_dirs.RemoveLastPathComponent();
504
505 // Add a ".dSYM" name to each directory component of the path,
506 // stripping off components. e.g. we may have a binary like
507 // /S/L/F/Foundation.framework/Versions/A/Foundation and
508 // /S/L/F/Foundation.framework.dSYM
509 //
510 // so we'll need to start with
511 // /S/L/F/Foundation.framework/Versions/A, add the .dSYM part to the
512 // "A", and if that doesn't exist, strip off the "A" and try it again
513 // with "Versions", etc., until we find a dSYM bundle or we've
514 // stripped off enough path components that there's no need to
515 // continue.
516
517 for (int i = 0; i < 4; i++) {
518 // Does this part of the path have a "." character - could it be a
519 // bundle's top level directory?
520 llvm::StringRef fn = parent_dirs.GetFilename();
521 if (fn.empty())
522 break;
523 if (fn.contains('.')) {
524 if (::LookForDsymNextToExecutablePath(module_spec, parent_dirs,
525 dsym_fspec)) {
526 LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s",
527 dsym_fspec.GetPath().c_str());
528 return true;
529 }
530 }
531 parent_dirs.RemoveLastPathComponent();
532 }
533 }
534 }
535 dsym_fspec.Clear();
536 return false;
537}
538
539static int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
540 ModuleSpec &return_module_spec) {
541 Log *log = GetLog(LLDBLog::Host);
542 if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
543 LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled.");
544 return 0;
545 }
546
547 return_module_spec = module_spec;
548 return_module_spec.GetFileSpec().Clear();
549 return_module_spec.GetSymbolFileSpec().Clear();
550
551 const UUID *uuid = module_spec.GetUUIDPtr();
552 const ArchSpec *arch = module_spec.GetArchitecturePtr();
553
554 int items_found = 0;
555
556 const DebugSymbolsDylibFunctions &dylib_functions =
558 if (!dylib_functions.FoundFunctions())
559 return items_found;
560
561 if (uuid && uuid->IsValid()) {
562 // Try and locate the dSYM file using DebugSymbols first
563 llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
564 if (module_uuid.size() == 16) {
565 CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
566 NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
567 module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
568 module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
569 module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
570
571 if (module_uuid_ref.get()) {
572 CFCReleaser<CFURLRef> exec_url;
573 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
574 if (exec_fspec) {
575 char exec_cf_path[PATH_MAX];
576 if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
577 exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
578 NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
579 FALSE));
580 }
581
582 CFCReleaser<CFURLRef> dsym_url(
583 dylib_functions.DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(),
584 exec_url.get()));
585 char path[PATH_MAX];
586
587 if (dsym_url.get()) {
588 if (::CFURLGetFileSystemRepresentation(
589 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
590 LLDB_LOGF(log,
591 "DebugSymbols framework returned dSYM path of %s for "
592 "UUID %s -- looking for the dSYM",
593 path, uuid->GetAsString().c_str());
594 FileSpec dsym_filespec(path);
595 if (path[0] == '~')
596 FileSystem::Instance().Resolve(dsym_filespec);
597
598 if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
600 dsym_filespec, uuid, arch);
601 ++items_found;
602 } else {
603 ++items_found;
604 }
605 return_module_spec.GetSymbolFileSpec() = dsym_filespec;
606 }
607
608 bool success = false;
609 if (log) {
610 if (::CFURLGetFileSystemRepresentation(
611 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
612 LLDB_LOGF(log,
613 "DebugSymbols framework returned dSYM path of %s for "
614 "UUID %s -- looking for an exec file",
615 path, uuid->GetAsString().c_str());
616 }
617 }
618
620 dylib_functions.DBGCopyDSYMPropertyLists(dsym_url.get()));
621 CFDictionaryRef uuid_dict = NULL;
622 if (dict.get()) {
623 CFCString uuid_cfstr(uuid->GetAsString().c_str());
624 uuid_dict = static_cast<CFDictionaryRef>(
625 ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
626 }
627
628 // Check to see if we have the file on the local filesystem.
629 if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
630 ModuleSpec exe_spec;
631 exe_spec.GetFileSpec() = module_spec.GetFileSpec();
632 exe_spec.GetUUID() = module_spec.GetUUID();
633 ModuleSP module_sp;
634 module_sp = std::make_shared<Module>(exe_spec);
635 if (module_sp && module_sp->GetObjectFile() &&
636 module_sp->MatchesModuleSpec(exe_spec)) {
637 success = true;
638 return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
639 LLDB_LOGF(log, "using original binary filepath %s for UUID %s",
640 module_spec.GetFileSpec().GetPath().c_str(),
641 uuid->GetAsString().c_str());
642 ++items_found;
643 }
644 }
645
646 // Check if the requested image is in our shared cache.
647 if (!success) {
648 SymbolSharedCacheUse sc_mode =
651 std::string filepath = module_spec.GetFileSpec().GetPath();
652 SharedCacheImageInfo image_info =
653 HostInfo::GetSharedCacheImageInfo(filepath, sc_mode);
654
655 // If we found it and it has the correct UUID, let's proceed with
656 // creating a module from the memory contents.
657 if (image_info.GetUUID() &&
658 (!module_spec.GetUUID() ||
659 module_spec.GetUUID() == image_info.GetUUID())) {
660 success = true;
661 return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
662 LLDB_LOGF(log,
663 "using binary from shared cache for filepath %s for "
664 "UUID %s",
665 module_spec.GetFileSpec().GetPath().c_str(),
666 uuid->GetAsString().c_str());
667 ++items_found;
668 }
669 }
670
671 // Use the DBGSymbolRichExecutable filepath if present
672 if (!success && uuid_dict) {
673 CFStringRef exec_cf_path =
674 static_cast<CFStringRef>(::CFDictionaryGetValue(
675 uuid_dict, CFSTR("DBGSymbolRichExecutable")));
676 if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
677 exec_cf_path, path, sizeof(path))) {
678 LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s",
679 path, uuid->GetAsString().c_str());
680 ++items_found;
681 FileSpec exec_filespec(path);
682 if (path[0] == '~')
683 FileSystem::Instance().Resolve(exec_filespec);
684 if (FileSystem::Instance().Exists(exec_filespec)) {
685 success = true;
686 return_module_spec.GetFileSpec() = exec_filespec;
687 }
688 }
689 }
690
691 // Look next to the dSYM for the binary file.
692 if (!success) {
693 if (::CFURLGetFileSystemRepresentation(
694 dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
695 char *dsym_extension_pos = ::strstr(path, ".dSYM");
696 if (dsym_extension_pos) {
697 *dsym_extension_pos = '\0';
698 LLDB_LOGF(log,
699 "Looking for executable binary next to dSYM "
700 "bundle with name with name %s",
701 path);
702 FileSpec file_spec(path);
703 FileSystem::Instance().Resolve(file_spec);
704 ModuleSpec matched_module_spec;
705 using namespace llvm::sys::fs;
706 switch (get_file_type(file_spec.GetPath())) {
707
708 case file_type::directory_file: // Bundle directory?
709 {
710 CFCBundle bundle(path);
711 CFCReleaser<CFURLRef> bundle_exe_url(
712 bundle.CopyExecutableURL());
713 if (bundle_exe_url.get()) {
714 if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
715 true, (UInt8 *)path,
716 sizeof(path) - 1)) {
717 FileSpec bundle_exe_file_spec(path);
718 FileSystem::Instance().Resolve(bundle_exe_file_spec);
719 if (ModuleSpecList module_specs =
721 bundle_exe_file_spec, 0, 0);
722 module_specs.FindMatchingModuleSpec(
723 module_spec, matched_module_spec)) {
724 ++items_found;
725 return_module_spec.GetFileSpec() = bundle_exe_file_spec;
726 LLDB_LOGF(log,
727 "Executable binary %s next to dSYM is "
728 "compatible; using",
729 path);
730 }
731 }
732 }
733 } break;
734
735 case file_type::fifo_file: // Forget pipes
736 case file_type::socket_file: // We can't process socket files
737 case file_type::file_not_found: // File doesn't exist...
738 case file_type::status_error:
739 break;
740
741 case file_type::type_unknown:
742 case file_type::regular_file:
743 case file_type::symlink_file:
744 case file_type::block_file:
745 case file_type::character_file:
746 if (ModuleSpecList module_specs =
748 module_specs.FindMatchingModuleSpec(
749 module_spec, matched_module_spec)) {
750 ++items_found;
751 return_module_spec.GetFileSpec() = file_spec;
752 LLDB_LOGF(log,
753 "Executable binary %s next to dSYM is "
754 "compatible; using",
755 path);
756 }
757 break;
758 }
759 }
760 }
761 }
762 }
763 }
764 }
765 }
766
767 return items_found;
768}
769
771 const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
772 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
773 const ArchSpec *arch = module_spec.GetArchitecturePtr();
774 const UUID *uuid = module_spec.GetUUIDPtr();
775
777 "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
778 exec_fspec ? exec_fspec->GetFilename().nonEmptyOr("<NULL>").str().c_str()
779 : "<NULL>",
780 arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
781
782 Progress progress(
783 "Locating external symbol file",
784 module_spec.GetFileSpec().GetFilename().nonEmptyOr("<Unknown>").str());
785
786 FileSpec symbol_fspec;
787 ModuleSpec dsym_module_spec;
788 // First try and find the dSYM in the same directory as the executable or in
789 // an appropriate parent directory
790 if (!LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec)) {
791 // We failed to easily find the dSYM above, so use DebugSymbols
792 LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec);
793 } else {
794 dsym_module_spec.GetSymbolFileSpec() = symbol_fspec;
795 }
796
797 return dsym_module_spec.GetSymbolFileSpec();
798}
799
800static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
801 ModuleSpec &module_spec,
802 Status &error,
803 const std::string &command) {
804 Log *log = GetLog(LLDBLog::Host);
805 bool success = false;
806 if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
807 std::string str;
808 CFStringRef cf_str;
809 CFDictionaryRef cf_dict;
810
811 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
812 CFSTR("DBGError"));
813 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
814 if (CFCString::FileSystemRepresentation(cf_str, str)) {
815 std::string errorstr = command;
816 errorstr += ":\n";
817 errorstr += str;
818 error = Status(errorstr);
819 }
820 }
821
822 cf_str = (CFStringRef)CFDictionaryGetValue(
823 (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
824 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
825 if (CFCString::FileSystemRepresentation(cf_str, str)) {
826 module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native);
828 LLDB_LOGF(log,
829 "From dsymForUUID plist: Symbol rich executable is at '%s'",
830 str.c_str());
831 }
832 }
833
834 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
835 CFSTR("DBGDSYMPath"));
836 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
837 if (CFCString::FileSystemRepresentation(cf_str, str)) {
838 module_spec.GetSymbolFileSpec().SetFile(str.c_str(),
839 FileSpec::Style::native);
841 success = true;
842 LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'", str.c_str());
843 }
844 }
845
846 std::string DBGBuildSourcePath;
847 std::string DBGSourcePath;
848
849 // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
850 // If DBGVersion 2, strip last two components of path remappings from
851 // entries to fix an issue with a specific set of
852 // DBGSourcePathRemapping entries that lldb worked
853 // with.
854 // If DBGVersion 3, trust & use the source path remappings as-is.
855 //
856 cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
857 (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
858 if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
859 // If we see DBGVersion with a value of 2 or higher, this is a new style
860 // DBGSourcePathRemapping dictionary
861 bool new_style_source_remapping_dictionary = false;
862 bool do_truncate_remapping_names = false;
863 std::string original_DBGSourcePath_value = DBGSourcePath;
864 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
865 CFSTR("DBGVersion"));
866 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
867 std::string version;
869 if (!version.empty() && isdigit(version[0])) {
870 int version_number = atoi(version.c_str());
871 if (version_number > 1) {
872 new_style_source_remapping_dictionary = true;
873 }
874 if (version_number == 2) {
875 do_truncate_remapping_names = true;
876 }
877 }
878 }
879
880 CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
881 if (kv_pair_count > 0) {
882 CFStringRef *keys =
883 (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
884 CFStringRef *values =
885 (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
886 if (keys != nullptr && values != nullptr) {
887 CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
888 (const void **)keys,
889 (const void **)values);
890 }
891 for (CFIndex i = 0; i < kv_pair_count; i++) {
892 DBGBuildSourcePath.clear();
893 DBGSourcePath.clear();
894 if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
895 CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
896 }
897 if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
898 CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
899 }
900 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
901 // In the "old style" DBGSourcePathRemapping dictionary, the
902 // DBGSourcePath values (the "values" half of key-value path pairs)
903 // were wrong. Ignore them and use the universal DBGSourcePath
904 // string from earlier.
905 if (new_style_source_remapping_dictionary &&
906 !original_DBGSourcePath_value.empty()) {
907 DBGSourcePath = original_DBGSourcePath_value;
908 }
909 if (DBGSourcePath[0] == '~') {
910 FileSpec resolved_source_path(DBGSourcePath.c_str());
911 FileSystem::Instance().Resolve(resolved_source_path);
912 DBGSourcePath = resolved_source_path.GetPath();
913 }
914 // With version 2 of DBGSourcePathRemapping, we can chop off the
915 // last two filename parts from the source remapping and get a more
916 // general source remapping that still works. Add this as another
917 // option in addition to the full source path remap.
918 module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
919 DBGSourcePath, true);
920 if (do_truncate_remapping_names) {
921 FileSpec build_path(DBGBuildSourcePath.c_str());
922 FileSpec source_path(DBGSourcePath.c_str());
923 build_path.RemoveLastPathComponent();
924 build_path.RemoveLastPathComponent();
925 source_path.RemoveLastPathComponent();
926 source_path.RemoveLastPathComponent();
927 module_spec.GetSourceMappingList().Append(
928 build_path.GetPath(), source_path.GetPath(), true);
929 }
930 }
931 }
932 if (keys)
933 free(keys);
934 if (values)
935 free(values);
936 }
937 }
938
939 // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
940 // source remappings list.
941
942 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
943 CFSTR("DBGBuildSourcePath"));
944 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
945 CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
946 }
947
948 cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
949 CFSTR("DBGSourcePath"));
950 if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
951 CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
952 }
953
954 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
955 if (DBGSourcePath[0] == '~') {
956 FileSpec resolved_source_path(DBGSourcePath.c_str());
957 FileSystem::Instance().Resolve(resolved_source_path);
958 DBGSourcePath = resolved_source_path.GetPath();
959 }
960 module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
961 DBGSourcePath, true);
962 }
963 }
964 return success;
965}
966
967/// It's expensive to check for the DBGShellCommands defaults setting. Only do
968/// it once per lldb run and cache the result.
969static llvm::StringRef GetDbgShellCommand() {
970 static std::once_flag g_once_flag;
971 static std::string g_dbgshell_command;
972 std::call_once(g_once_flag, [&]() {
973 CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
974 CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
975 if (defaults_setting &&
976 CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
977 char buffer[PATH_MAX];
978 if (CFStringGetCString((CFStringRef)defaults_setting, buffer,
979 sizeof(buffer), kCFStringEncodingUTF8)) {
980 g_dbgshell_command = buffer;
981 }
982 }
983 if (defaults_setting) {
984 CFRelease(defaults_setting);
985 }
986 });
987 return g_dbgshell_command;
988}
989
990/// Get the dsymForUUID executable and cache the result so we don't end up
991/// stat'ing the binary over and over.
993 // The LLDB_APPLE_DSYMFORUUID_EXECUTABLE environment variable is used by the
994 // test suite to override the dsymForUUID location. Because we must be able
995 // to change the value within a single test, don't bother caching it.
996 if (const char *dsymForUUID_env =
997 getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE")) {
998 FileSpec dsymForUUID_executable(dsymForUUID_env);
999 FileSystem::Instance().Resolve(dsymForUUID_executable);
1000 if (FileSystem::Instance().Exists(dsymForUUID_executable))
1001 return dsymForUUID_executable;
1002 }
1003
1004 static std::once_flag g_once_flag;
1005 static FileSpec g_dsymForUUID_executable;
1006 std::call_once(g_once_flag, [&]() {
1007 // Try the DBGShellCommand.
1008 llvm::StringRef dbgshell_command = GetDbgShellCommand();
1009 if (!dbgshell_command.empty()) {
1010 g_dsymForUUID_executable = FileSpec(dbgshell_command);
1011 FileSystem::Instance().Resolve(g_dsymForUUID_executable);
1012 if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
1013 return;
1014 }
1015
1016 // Try dsymForUUID in /usr/local/bin
1017 {
1018 g_dsymForUUID_executable = FileSpec("/usr/local/bin/dsymForUUID");
1019 if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
1020 return;
1021 }
1022
1023 // We couldn't find the dsymForUUID binary.
1024 g_dsymForUUID_executable = {};
1025 });
1026 return g_dsymForUUID_executable;
1027}
1028
1030 ModuleSpec &module_spec, Status &error, bool force_lookup,
1031 bool copy_executable) {
1032 const UUID *uuid_ptr = module_spec.GetUUIDPtr();
1033 const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
1034
1035 // If \a dbgshell_command is set, the user has specified
1036 // forced symbol lookup via that command. We'll get the
1037 // path back from GetDsymForUUIDExecutable() later.
1038 llvm::StringRef dbgshell_command = GetDbgShellCommand();
1039
1040 // If forced lookup isn't set, by the user's \a dbgshell_command or
1041 // by the \a force_lookup argument, exit this method.
1042 if (!force_lookup && dbgshell_command.empty())
1043 return false;
1044
1045 // We need a UUID or valid existing FileSpec.
1046 if (!uuid_ptr &&
1047 (!file_spec_ptr || !FileSystem::Instance().Exists(*file_spec_ptr)))
1048 return false;
1049
1050 // We need a dsymForUUID binary or an equivalent executable/script.
1051 FileSpec dsymForUUID_exe_spec = GetDsymForUUIDExecutable();
1052 if (!dsymForUUID_exe_spec)
1053 return false;
1054
1055 // Create the dsymForUUID command.
1056 const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath();
1057 const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : "";
1058
1059 std::string lookup_arg = uuid_str;
1060 if (lookup_arg.empty())
1061 lookup_arg = file_spec_ptr ? file_spec_ptr->GetPath() : "";
1062 if (lookup_arg.empty())
1063 return false;
1064
1065 StreamString command;
1066 command << dsymForUUID_exe_path << " --ignoreNegativeCache ";
1067 if (copy_executable)
1068 command << "--copyExecutable ";
1069 command << lookup_arg;
1070
1071 // Log and report progress.
1072 std::string lookup_desc;
1073 if (uuid_ptr && file_spec_ptr)
1074 lookup_desc = llvm::formatv("{0} ({1})", file_spec_ptr->GetFilename(),
1075 uuid_ptr->GetAsString());
1076 else if (uuid_ptr)
1077 lookup_desc = uuid_ptr->GetAsString();
1078 else if (file_spec_ptr)
1079 lookup_desc = file_spec_ptr->GetFilename().str();
1080
1081 Log *log = GetLog(LLDBLog::Host);
1082 LLDB_LOG(log, "Calling {0} for {1} to find dSYM: {2}", dsymForUUID_exe_path,
1083 lookup_desc, command.GetString());
1084
1085 Progress progress("Downloading symbol file for", lookup_desc);
1086
1087 // Invoke dsymForUUID.
1088 int exit_status = -1;
1089 int signo = -1;
1090 std::string command_output;
1091 std::string error_output;
1093 command.GetData(),
1094 FileSpec(), // current working directory
1095 &exit_status, // Exit status
1096 &signo, // Signal int *
1097 &command_output, // Command output
1098 &error_output, // Command error output
1099 std::chrono::seconds(
1100 640), // Large timeout to allow for long dsym download times
1101 false); // Don't run in a shell (we don't need shell expansion)
1102
1103 if (error.Fail() || exit_status != 0 || command_output.empty()) {
1104 LLDB_LOGF(log,
1105 "'%s' failed (exit status: %d, error: '%s', stdout: '%s', "
1106 "stderr: '%s')",
1107 command.GetData(), exit_status, error.AsCString(),
1108 command_output.c_str(), error_output.c_str());
1109 return false;
1110 }
1111
1112 CFCData data(
1113 CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)command_output.data(),
1114 command_output.size(), kCFAllocatorNull));
1115
1117 (CFDictionaryRef)::CFPropertyListCreateWithData(
1118 NULL, data.get(), kCFPropertyListImmutable, NULL, NULL));
1119
1120 if (!plist.get()) {
1121 LLDB_LOGF(log, "'%s' failed: output is not a valid plist",
1122 command.GetData());
1123 LLDB_LOGF(log, "Response:\n%s\n", command_output.c_str());
1124 return false;
1125 }
1126
1127 if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) {
1128 LLDB_LOGF(log, "'%s' failed: output plist is not a valid CFDictionary",
1129 command.GetData());
1130 return false;
1131 }
1132
1133 if (!uuid_str.empty()) {
1134 CFCString uuid_cfstr(uuid_str.c_str());
1135 CFDictionaryRef uuid_dict =
1136 (CFDictionaryRef)CFDictionaryGetValue(plist.get(), uuid_cfstr.get());
1137 return GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec, error,
1138 command.GetData());
1139 }
1140
1141 if (const CFIndex num_values = ::CFDictionaryGetCount(plist.get())) {
1142 std::vector<CFStringRef> keys(num_values, NULL);
1143 std::vector<CFDictionaryRef> values(num_values, NULL);
1144 ::CFDictionaryGetKeysAndValues(plist.get(), NULL,
1145 (const void **)&values[0]);
1146 if (num_values == 1) {
1147 return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec, error,
1148 command.GetData());
1149 }
1150
1151 for (CFIndex i = 0; i < num_values; ++i) {
1152 ModuleSpec curr_module_spec;
1153 if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec,
1154 error, command.GetData())) {
1155 if (module_spec.GetArchitecture().IsCompatibleMatch(
1156 curr_module_spec.GetArchitecture())) {
1157 module_spec = curr_module_spec;
1158 return true;
1159 }
1160 }
1161 }
1162 }
1163
1164 return false;
1165}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
#define LLDB_LOGF(log,...)
Definition Log.h:389
#define LLDB_PLUGIN_DEFINE(PluginName)
static llvm::StringRef GetDbgShellCommand()
It's expensive to check for the DBGShellCommands defaults setting.
static const DebugSymbolsDylibFunctions & GetDebugSymbolsDylibFunctions()
static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, FileSpec &dsym_fspec)
static int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, ModuleSpec &return_module_spec)
static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec, const ArchSpec *arch, const lldb_private::UUID *uuid)
static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec, const FileSpec &exec_fspec, FileSpec &dsym_fspec)
static FileSpec GetDsymForUUIDExecutable()
Get the dsymForUUID executable and cache the result so we don't end up stat'ing the binary over and o...
static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, ModuleSpec &module_spec, Status &error, const std::string &command)
#define LLDB_SCOPED_TIMERF(...)
Definition Timer.h:86
CFURLRef CopyExecutableURL() const
Definition CFCBundle.cpp:71
void reset(T ptr=NULL)
Definition CFCReleaser.h:86
static const char * FileSystemRepresentation(CFStringRef cf_str, std::string &str)
An architecture specification class.
Definition ArchSpec.h:32
bool IsCompatibleMatch(const ArchSpec &rhs) const
Shorthand for IsMatch(rhs, CompatibleMatch).
Definition ArchSpec.h:596
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition ArchSpec.cpp:740
A file collection class.
A file utility class.
Definition FileSpec.h:56
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition FileSpec.cpp:174
void AppendPathComponent(llvm::StringRef component)
Definition FileSpec.cpp:454
bool RemoveLastPathComponent()
Removes the last path component by replacing the current path with its parent.
Definition FileSpec.cpp:465
llvm::StringRef GetFilename() const
Filename string const get accessor.
Definition FileSpec.h:248
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
void Clear()
Clears the object state.
Definition FileSpec.cpp:265
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > GetVirtualFileSystem()
Definition FileSystem.h:205
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
static Status RunShellCommand(llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, std::string *error_output, const Timeout< std::micro > &timeout, bool run_in_shell=true)
Run a shell command.
lldb::SymbolSharedCacheUse GetSharedCacheBinaryLoading() const
static ModuleListProperties & GetGlobalModuleListProperties()
bool GetModuleSpecAtIndex(size_t i, ModuleSpec &module_spec) const
Definition ModuleSpec.h:386
PathMappingList & GetSourceMappingList() const
Definition ModuleSpec.h:138
FileSpec & GetFileSpec()
Definition ModuleSpec.h:57
ArchSpec & GetArchitecture()
Definition ModuleSpec.h:93
FileSpec * GetFileSpecPtr()
Definition ModuleSpec.h:51
FileSpec & GetSymbolFileSpec()
Definition ModuleSpec.h:81
ArchSpec * GetArchitecturePtr()
Definition ModuleSpec.h:85
static ModuleSpecList GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset, lldb::offset_t file_size, lldb::DataExtractorSP=lldb::DataExtractorSP())
void Append(llvm::StringRef path, llvm::StringRef replacement, bool notify)
static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, Status &error, bool force_lookup=true, bool copy_executable=true)
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, const UUID *uuid, const ArchSpec *arch)
A Progress indicator helper class.
Definition Progress.h:60
An error handling class.
Definition Status.h:118
const char * GetData() const
llvm::StringRef GetString() const
static std::optional< ModuleSpec > LocateExecutableObjectFile(const ModuleSpec &module_spec)
static lldb_private::SymbolLocator * CreateInstance()
static std::optional< FileSpec > LocateExecutableSymbolFile(const ModuleSpec &module_spec, const FileSpecList &default_search_paths)
static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, Status &error, bool force_lookup, bool copy_executable)
static std::optional< FileSpec > FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, const UUID *uuid, const ArchSpec *arch)
Represents UUID's of various sizes.
Definition UUID.h:27
llvm::ArrayRef< uint8_t > GetBytes() const
Definition UUID.h:66
std::string GetAsString(llvm::StringRef separator="-") const
Definition UUID.cpp:54
bool IsValid() const
Definition UUID.h:69
#define UNUSED_IF_ASSERT_DISABLED(x)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
std::shared_ptr< lldb_private::Module > ModuleSP
#define PATH_MAX