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