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