Skip to content

Commit bd3976f

Browse files
committed
[lldb] Refactor Symbols::DownloadObjectAndSymbolFile
- Reduce indentation - Extract caching of the DbgShellCommand and the dsymForUUID executable (or equivalent) - Check the DBGShellCommands before falling back to /usr/local/bin/dsymForUUID - Don't check ~rc/bin/dsymForUUID - Improve error reporting - Don't cache the value of LLDB_APPLE_DSYMFORUUID_EXECUTABLE Differential revision: https://reviews.llvm.org/D131303
1 parent 1438639 commit bd3976f

File tree

1 file changed

+158
-164
lines changed

1 file changed

+158
-164
lines changed

lldb/source/Symbol/LocateSymbolFileMacOSX.cpp

Lines changed: 158 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -491,190 +491,184 @@ static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
491491
return success;
492492
}
493493

494-
bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
495-
Status &error, bool force_lookup) {
496-
bool success = false;
497-
const UUID *uuid_ptr = module_spec.GetUUIDPtr();
498-
const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
499-
500-
// It's expensive to check for the DBGShellCommands defaults setting, only do
501-
// it once per lldb run and cache the result.
502-
static bool g_have_checked_for_dbgshell_command = false;
503-
static const char *g_dbgshell_command = NULL;
504-
if (!g_have_checked_for_dbgshell_command) {
505-
g_have_checked_for_dbgshell_command = true;
494+
/// It's expensive to check for the DBGShellCommands defaults setting. Only do
495+
/// it once per lldb run and cache the result.
496+
static llvm::StringRef GetDbgShellCommand() {
497+
static std::once_flag g_once_flag;
498+
static std::string g_dbgshell_command;
499+
std::call_once(g_once_flag, [&]() {
506500
CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
507501
CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
508502
if (defaults_setting &&
509503
CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
510-
char cstr_buf[PATH_MAX];
511-
if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf,
512-
sizeof(cstr_buf), kCFStringEncodingUTF8)) {
513-
g_dbgshell_command =
514-
strdup(cstr_buf); // this malloc'ed memory will never be freed
504+
char buffer[PATH_MAX];
505+
if (CFStringGetCString((CFStringRef)defaults_setting, buffer,
506+
sizeof(buffer), kCFStringEncodingUTF8)) {
507+
g_dbgshell_command = buffer;
515508
}
516509
}
517510
if (defaults_setting) {
518511
CFRelease(defaults_setting);
519512
}
513+
});
514+
return g_dbgshell_command;
515+
}
516+
517+
/// Get the dsymForUUID executable and cache the result so we don't end up
518+
/// stat'ing the binary over and over.
519+
static FileSpec GetDsymForUUIDExecutable() {
520+
// The LLDB_APPLE_DSYMFORUUID_EXECUTABLE environment variable is used by the
521+
// test suite to override the dsymForUUID location. Because we must be able
522+
// to change the value within a single test, don't bother caching it.
523+
if (const char *dsymForUUID_env =
524+
getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE")) {
525+
FileSpec dsymForUUID_executable(dsymForUUID_env);
526+
FileSystem::Instance().Resolve(dsymForUUID_executable);
527+
if (FileSystem::Instance().Exists(dsymForUUID_executable))
528+
return dsymForUUID_executable;
520529
}
521530

522-
// When g_dbgshell_command is NULL, the user has not enabled the use of an
531+
static std::once_flag g_once_flag;
532+
static FileSpec g_dsymForUUID_executable;
533+
std::call_once(g_once_flag, [&]() {
534+
// Try the DBGShellCommand.
535+
llvm::StringRef dbgshell_command = GetDbgShellCommand();
536+
if (!dbgshell_command.empty()) {
537+
g_dsymForUUID_executable = FileSpec(dbgshell_command);
538+
FileSystem::Instance().Resolve(g_dsymForUUID_executable);
539+
if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
540+
return;
541+
}
542+
543+
// Try dsymForUUID in /usr/local/bin
544+
{
545+
g_dsymForUUID_executable = FileSpec("/usr/local/bin/dsymForUUID");
546+
if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
547+
return;
548+
}
549+
550+
// We couldn't find the dsymForUUID binary.
551+
g_dsymForUUID_executable = {};
552+
});
553+
return g_dsymForUUID_executable;
554+
}
555+
556+
bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
557+
Status &error, bool force_lookup) {
558+
const UUID *uuid_ptr = module_spec.GetUUIDPtr();
559+
const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
560+
561+
llvm::StringRef dbgshell_command = GetDbgShellCommand();
562+
563+
// When dbgshell_command is empty, the user has not enabled the use of an
523564
// external program to find the symbols, don't run it for them.
524-
if (!force_lookup && g_dbgshell_command == NULL) {
565+
if (!force_lookup && dbgshell_command.empty())
566+
return false;
567+
568+
// We need a UUID or valid (existing FileSpec.
569+
if (!uuid_ptr &&
570+
(!file_spec_ptr || !FileSystem::Instance().Exists(*file_spec_ptr)))
571+
return false;
572+
573+
// We need a dsymForUUID binary or an equivalent executable/script.
574+
FileSpec dsymForUUID_exe_spec = GetDsymForUUIDExecutable();
575+
if (!dsymForUUID_exe_spec)
576+
return false;
577+
578+
const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath();
579+
const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : "";
580+
const std::string file_path_str =
581+
file_spec_ptr ? file_spec_ptr->GetPath() : "";
582+
583+
Log *log = GetLog(LLDBLog::Host);
584+
585+
// Create the dsymForUUID command.
586+
StreamString command;
587+
if (!uuid_str.empty()) {
588+
command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
589+
dsymForUUID_exe_path.c_str(), uuid_str.c_str());
590+
LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM: %s",
591+
dsymForUUID_exe_path.c_str(), uuid_str.c_str(),
592+
command.GetString().data());
593+
} else if (!file_path_str.empty()) {
594+
command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
595+
dsymForUUID_exe_path.c_str(), file_path_str.c_str());
596+
LLDB_LOGF(log, "Calling %s with file %s to find dSYM: %s",
597+
dsymForUUID_exe_path.c_str(), file_path_str.c_str(),
598+
command.GetString().data());
599+
} else {
525600
return false;
526601
}
527602

528-
if (uuid_ptr ||
529-
(file_spec_ptr && FileSystem::Instance().Exists(*file_spec_ptr))) {
530-
static bool g_located_dsym_for_uuid_exe = false;
531-
static bool g_dsym_for_uuid_exe_exists = false;
532-
static char g_dsym_for_uuid_exe_path[PATH_MAX];
533-
if (!g_located_dsym_for_uuid_exe) {
534-
g_located_dsym_for_uuid_exe = true;
535-
const char *dsym_for_uuid_exe_path_cstr =
536-
getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
537-
FileSpec dsym_for_uuid_exe_spec;
538-
if (dsym_for_uuid_exe_path_cstr) {
539-
dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr,
540-
FileSpec::Style::native);
541-
FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
542-
g_dsym_for_uuid_exe_exists =
543-
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
544-
}
603+
// Invoke dsymForUUID.
604+
int exit_status = -1;
605+
int signo = -1;
606+
std::string command_output;
607+
error = Host::RunShellCommand(
608+
command.GetData(),
609+
FileSpec(), // current working directory
610+
&exit_status, // Exit status
611+
&signo, // Signal int *
612+
&command_output, // Command output
613+
std::chrono::seconds(
614+
640), // Large timeout to allow for long dsym download times
615+
false); // Don't run in a shell (we don't need shell expansion)
616+
617+
if (error.Fail() || exit_status != 0 || command_output.empty()) {
618+
LLDB_LOGF(log, "'%s' failed (exit status: %d, error: '%s', output: '%s')",
619+
command.GetData(), exit_status, error.AsCString(),
620+
command_output.c_str());
621+
return false;
622+
}
545623

546-
if (!g_dsym_for_uuid_exe_exists) {
547-
dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID",
548-
FileSpec::Style::native);
549-
g_dsym_for_uuid_exe_exists =
550-
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
551-
if (!g_dsym_for_uuid_exe_exists) {
552-
long bufsize;
553-
if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) {
554-
char buffer[bufsize];
555-
struct passwd pwd;
556-
struct passwd *tilde_rc = NULL;
557-
// we are a library so we need to use the reentrant version of
558-
// getpwnam()
559-
if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 &&
560-
tilde_rc && tilde_rc->pw_dir) {
561-
std::string dsymforuuid_path(tilde_rc->pw_dir);
562-
dsymforuuid_path += "/bin/dsymForUUID";
563-
dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(),
564-
FileSpec::Style::native);
565-
g_dsym_for_uuid_exe_exists =
566-
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
567-
}
568-
}
569-
}
570-
}
571-
if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) {
572-
dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command,
573-
FileSpec::Style::native);
574-
FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
575-
g_dsym_for_uuid_exe_exists =
576-
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
577-
}
624+
CFCData data(
625+
CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)command_output.data(),
626+
command_output.size(), kCFAllocatorNull));
627+
628+
CFCReleaser<CFDictionaryRef> plist(
629+
(CFDictionaryRef)::CFPropertyListCreateFromXMLData(
630+
NULL, data.get(), kCFPropertyListImmutable, NULL));
631+
632+
if (!plist.get()) {
633+
LLDB_LOGF(log, "'%s' failed: output is not a valid plist",
634+
command.GetData());
635+
return false;
636+
}
637+
638+
if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) {
639+
LLDB_LOGF(log, "'%s' failed: output plist is not a valid CFDictionary",
640+
command.GetData());
641+
return false;
642+
}
578643

579-
if (g_dsym_for_uuid_exe_exists)
580-
dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path,
581-
sizeof(g_dsym_for_uuid_exe_path));
644+
if (!uuid_str.empty()) {
645+
CFCString uuid_cfstr(uuid_str.c_str());
646+
CFDictionaryRef uuid_dict =
647+
(CFDictionaryRef)CFDictionaryGetValue(plist.get(), uuid_cfstr.get());
648+
return GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec, error);
649+
}
650+
651+
if (const CFIndex num_values = ::CFDictionaryGetCount(plist.get())) {
652+
std::vector<CFStringRef> keys(num_values, NULL);
653+
std::vector<CFDictionaryRef> values(num_values, NULL);
654+
::CFDictionaryGetKeysAndValues(plist.get(), NULL,
655+
(const void **)&values[0]);
656+
if (num_values == 1) {
657+
return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec, error);
582658
}
583-
if (g_dsym_for_uuid_exe_exists) {
584-
std::string uuid_str;
585-
char file_path[PATH_MAX];
586-
file_path[0] = '\0';
587-
588-
if (uuid_ptr)
589-
uuid_str = uuid_ptr->GetAsString();
590-
591-
if (file_spec_ptr)
592-
file_spec_ptr->GetPath(file_path, sizeof(file_path));
593-
594-
StreamString command;
595-
if (!uuid_str.empty())
596-
command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
597-
g_dsym_for_uuid_exe_path, uuid_str.c_str());
598-
else if (file_path[0] != '\0')
599-
command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
600-
g_dsym_for_uuid_exe_path, file_path);
601-
602-
if (!command.GetString().empty()) {
603-
Log *log = GetLog(LLDBLog::Host);
604-
int exit_status = -1;
605-
int signo = -1;
606-
std::string command_output;
607-
if (log) {
608-
if (!uuid_str.empty())
609-
LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM",
610-
g_dsym_for_uuid_exe_path, uuid_str.c_str());
611-
else if (file_path[0] != '\0')
612-
LLDB_LOGF(log, "Calling %s with file %s to find dSYM",
613-
g_dsym_for_uuid_exe_path, file_path);
614-
}
615-
error = Host::RunShellCommand(
616-
command.GetData(),
617-
FileSpec(), // current working directory
618-
&exit_status, // Exit status
619-
&signo, // Signal int *
620-
&command_output, // Command output
621-
std::chrono::seconds(
622-
640), // Large timeout to allow for long dsym download times
623-
false); // Don't run in a shell (we don't need shell expansion)
624-
if (error.Success() && exit_status == 0 && !command_output.empty()) {
625-
CFCData data(CFDataCreateWithBytesNoCopy(
626-
NULL, (const UInt8 *)command_output.data(), command_output.size(),
627-
kCFAllocatorNull));
628-
629-
CFCReleaser<CFDictionaryRef> plist(
630-
(CFDictionaryRef)::CFPropertyListCreateFromXMLData(
631-
NULL, data.get(), kCFPropertyListImmutable, NULL));
632-
633-
if (plist.get() &&
634-
CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) {
635-
if (!uuid_str.empty()) {
636-
CFCString uuid_cfstr(uuid_str.c_str());
637-
CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue(
638-
plist.get(), uuid_cfstr.get());
639-
success = GetModuleSpecInfoFromUUIDDictionary(uuid_dict,
640-
module_spec, error);
641-
} else {
642-
const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
643-
if (num_values > 0) {
644-
std::vector<CFStringRef> keys(num_values, NULL);
645-
std::vector<CFDictionaryRef> values(num_values, NULL);
646-
::CFDictionaryGetKeysAndValues(plist.get(), NULL,
647-
(const void **)&values[0]);
648-
if (num_values == 1) {
649-
success = GetModuleSpecInfoFromUUIDDictionary(
650-
values[0], module_spec, error);
651-
return success;
652-
} else {
653-
for (CFIndex i = 0; i < num_values; ++i) {
654-
ModuleSpec curr_module_spec;
655-
if (GetModuleSpecInfoFromUUIDDictionary(
656-
values[i], curr_module_spec, error)) {
657-
if (module_spec.GetArchitecture().IsCompatibleMatch(
658-
curr_module_spec.GetArchitecture())) {
659-
module_spec = curr_module_spec;
660-
return true;
661-
}
662-
}
663-
}
664-
}
665-
}
666-
}
667-
}
668-
} else {
669-
if (!uuid_str.empty())
670-
LLDB_LOGF(log, "Called %s on %s, no matches",
671-
g_dsym_for_uuid_exe_path, uuid_str.c_str());
672-
else if (file_path[0] != '\0')
673-
LLDB_LOGF(log, "Called %s on %s, no matches",
674-
g_dsym_for_uuid_exe_path, file_path);
659+
660+
for (CFIndex i = 0; i < num_values; ++i) {
661+
ModuleSpec curr_module_spec;
662+
if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec,
663+
error)) {
664+
if (module_spec.GetArchitecture().IsCompatibleMatch(
665+
curr_module_spec.GetArchitecture())) {
666+
module_spec = curr_module_spec;
667+
return true;
675668
}
676669
}
677670
}
678671
}
679-
return success;
672+
673+
return false;
680674
}

0 commit comments

Comments
 (0)