Files
clang-p2996/lldb/source/Host/macosx/Symbols.cpp
Vedant Kumar ebc6bc8188 [Utility] Simplify and generalize the CleanUp helper, NFC
Removing the template arguments and most of the mutating methods from
CleanUp makes it easier to understand and reuse.

In its present state, CleanUp would be too cumbersome to adapt to cases
where multiple objects need to be released. Take for example this change
in swift-lldb:

  https://github.com/apple/swift-lldb/pull/334/files#diff-6f474df750f75c8ba675f2a8408a5629R219

This change is simple to express with the new CleanUp, but not so simple
with the old version.

Differential Revision: https://reviews.llvm.org/D43662

llvm-svn: 325964
2018-02-23 22:08:38 +00:00

631 lines
25 KiB
C++

//===-- Symbols.cpp ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Host/Symbols.h"
// C Includes
#include "lldb/Utility/SafeMachO.h"
#include <dirent.h>
#include <pwd.h>
// C++ Includes
// Other libraries and framework includes
#include <CoreFoundation/CoreFoundation.h>
// Project includes
#include "Host/macosx/cfcpp/CFCBundle.h"
#include "Host/macosx/cfcpp/CFCData.h"
#include "Host/macosx/cfcpp/CFCReleaser.h"
#include "Host/macosx/cfcpp/CFCString.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/CleanUp.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/Endian.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
#include "lldb/Utility/UUID.h"
#include "mach/machine.h"
#include "llvm/Support/FileSystem.h"
using namespace lldb;
using namespace lldb_private;
using namespace llvm::MachO;
#if !defined(__arm__) && !defined(__arm64__) && \
!defined(__aarch64__) // No DebugSymbols on the iOS devices
extern "C" {
CFURLRef DBGCopyFullDSYMURLForUUID(CFUUIDRef uuid, CFURLRef exec_url);
CFDictionaryRef DBGCopyDSYMPropertyLists(CFURLRef dsym_url);
}
#endif
int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
ModuleSpec &return_module_spec) {
return_module_spec = module_spec;
return_module_spec.GetFileSpec().Clear();
return_module_spec.GetSymbolFileSpec().Clear();
int items_found = 0;
#if !defined(__arm__) && !defined(__arm64__) && \
!defined(__aarch64__) // No DebugSymbols on the iOS devices
const UUID *uuid = module_spec.GetUUIDPtr();
const ArchSpec *arch = module_spec.GetArchitecturePtr();
if (uuid && uuid->IsValid()) {
// Try and locate the dSYM file using DebugSymbols first
const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
if (module_uuid != NULL) {
CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
if (module_uuid_ref.get()) {
CFCReleaser<CFURLRef> exec_url;
const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (exec_fspec) {
char exec_cf_path[PATH_MAX];
if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
FALSE));
}
CFCReleaser<CFURLRef> dsym_url(
::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
char path[PATH_MAX];
if (dsym_url.get()) {
if (::CFURLGetFileSystemRepresentation(
dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
if (log) {
log->Printf("DebugSymbols framework returned dSYM path of %s for "
"UUID %s -- looking for the dSYM",
path, uuid->GetAsString().c_str());
}
FileSpec dsym_filespec(path, path[0] == '~');
if (llvm::sys::fs::is_directory(dsym_filespec.GetPath())) {
dsym_filespec =
Symbols::FindSymbolFileInBundle(dsym_filespec, uuid, arch);
++items_found;
} else {
++items_found;
}
return_module_spec.GetSymbolFileSpec() = dsym_filespec;
}
bool success = false;
if (log) {
if (::CFURLGetFileSystemRepresentation(
dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
log->Printf("DebugSymbols framework returned dSYM path of %s for "
"UUID %s -- looking for an exec file",
path, uuid->GetAsString().c_str());
}
}
CFCReleaser<CFDictionaryRef> dict(
::DBGCopyDSYMPropertyLists(dsym_url.get()));
CFDictionaryRef uuid_dict = NULL;
if (dict.get()) {
CFCString uuid_cfstr(uuid->GetAsString().c_str());
uuid_dict = static_cast<CFDictionaryRef>(
::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
}
if (uuid_dict) {
CFStringRef exec_cf_path =
static_cast<CFStringRef>(::CFDictionaryGetValue(
uuid_dict, CFSTR("DBGSymbolRichExecutable")));
if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
exec_cf_path, path, sizeof(path))) {
if (log) {
log->Printf("plist bundle has exec path of %s for UUID %s",
path, uuid->GetAsString().c_str());
}
++items_found;
FileSpec exec_filespec(path, path[0] == '~');
if (exec_filespec.Exists()) {
success = true;
return_module_spec.GetFileSpec() = exec_filespec;
}
}
}
if (!success) {
// No dictionary, check near the dSYM bundle for an executable that
// matches...
if (::CFURLGetFileSystemRepresentation(
dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
char *dsym_extension_pos = ::strstr(path, ".dSYM");
if (dsym_extension_pos) {
*dsym_extension_pos = '\0';
if (log) {
log->Printf("Looking for executable binary next to dSYM "
"bundle with name with name %s",
path);
}
FileSpec file_spec(path, true);
ModuleSpecList module_specs;
ModuleSpec matched_module_spec;
using namespace llvm::sys::fs;
switch (get_file_type(file_spec.GetPath())) {
case file_type::directory_file: // Bundle directory?
{
CFCBundle bundle(path);
CFCReleaser<CFURLRef> bundle_exe_url(
bundle.CopyExecutableURL());
if (bundle_exe_url.get()) {
if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
true, (UInt8 *)path,
sizeof(path) - 1)) {
FileSpec bundle_exe_file_spec(path, true);
if (ObjectFile::GetModuleSpecifications(
bundle_exe_file_spec, 0, 0, module_specs) &&
module_specs.FindMatchingModuleSpec(
module_spec, matched_module_spec))
{
++items_found;
return_module_spec.GetFileSpec() = bundle_exe_file_spec;
if (log) {
log->Printf("Executable binary %s next to dSYM is "
"compatible; using",
path);
}
}
}
}
} break;
case file_type::fifo_file: // Forget pipes
case file_type::socket_file: // We can't process socket files
case file_type::file_not_found: // File doesn't exist...
case file_type::status_error:
break;
case file_type::type_unknown:
case file_type::regular_file:
case file_type::symlink_file:
case file_type::block_file:
case file_type::character_file:
if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0,
module_specs) &&
module_specs.FindMatchingModuleSpec(module_spec,
matched_module_spec))
{
++items_found;
return_module_spec.GetFileSpec() = file_spec;
if (log) {
log->Printf("Executable binary %s next to dSYM is "
"compatible; using",
path);
}
}
break;
}
}
}
}
}
}
}
}
#endif // #if !defined (__arm__) && !defined (__arm64__) && !defined
// (__aarch64__)
return items_found;
}
FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
const lldb_private::UUID *uuid,
const ArchSpec *arch) {
char path[PATH_MAX];
if (dsym_bundle_fspec.GetPath(path, sizeof(path)) == 0)
return {};
::strncat(path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
DIR *dirp = opendir(path);
if (!dirp)
return {};
// Make sure we close the directory before exiting this scope.
CleanUp cleanup_dir(closedir, dirp);
FileSpec dsym_fspec;
dsym_fspec.GetDirectory().SetCString(path);
struct dirent *dp;
while ((dp = readdir(dirp)) != NULL) {
// Only search directories
if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) {
if (dp->d_namlen == 1 && dp->d_name[0] == '.')
continue;
if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
continue;
}
if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) {
dsym_fspec.GetFilename().SetCString(dp->d_name);
ModuleSpecList module_specs;
if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) {
ModuleSpec spec;
for (size_t i = 0; i < module_specs.GetSize(); ++i) {
bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
UNUSED_IF_ASSERT_DISABLED(got_spec);
assert(got_spec);
if ((uuid == NULL ||
(spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
(arch == NULL ||
(spec.GetArchitecturePtr() &&
spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
return dsym_fspec;
}
}
}
}
}
return {};
}
static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
ModuleSpec &module_spec) {
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
bool success = false;
if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
std::string str;
CFStringRef cf_str;
CFDictionaryRef cf_dict;
cf_str = (CFStringRef)CFDictionaryGetValue(
(CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
if (CFCString::FileSystemRepresentation(cf_str, str)) {
module_spec.GetFileSpec().SetFile(str.c_str(), true);
if (log) {
log->Printf(
"From dsymForUUID plist: Symbol rich executable is at '%s'",
str.c_str());
}
}
}
cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
CFSTR("DBGDSYMPath"));
if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
if (CFCString::FileSystemRepresentation(cf_str, str)) {
module_spec.GetSymbolFileSpec().SetFile(str.c_str(), true);
success = true;
if (log) {
log->Printf("From dsymForUUID plist: dSYM is at '%s'", str.c_str());
}
}
}
cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
CFSTR("DBGArchitecture"));
if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
if (CFCString::FileSystemRepresentation(cf_str, str))
module_spec.GetArchitecture().SetTriple(str.c_str());
}
std::string DBGBuildSourcePath;
std::string DBGSourcePath;
// If DBGVersion value 2 or higher, look for
// DBGSourcePathRemapping dictionary and append the key-value pairs
// to our remappings.
cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
(CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
// If we see DBGVersion with a value of 2 or higher, this is a new style
// DBGSourcePathRemapping dictionary
bool new_style_source_remapping_dictionary = false;
bool do_truncate_remapping_names = false;
std::string original_DBGSourcePath_value = DBGSourcePath;
cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
CFSTR("DBGVersion"));
if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
std::string version;
CFCString::FileSystemRepresentation(cf_str, version);
if (!version.empty() && isdigit(version[0])) {
int version_number = atoi(version.c_str());
if (version_number > 1) {
new_style_source_remapping_dictionary = true;
}
if (version_number == 2) {
do_truncate_remapping_names = true;
}
}
}
CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
if (kv_pair_count > 0) {
CFStringRef *keys =
(CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
CFStringRef *values =
(CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
if (keys != nullptr && values != nullptr) {
CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
(const void **)keys,
(const void **)values);
}
for (CFIndex i = 0; i < kv_pair_count; i++) {
DBGBuildSourcePath.clear();
DBGSourcePath.clear();
if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
}
if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
}
if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
// In the "old style" DBGSourcePathRemapping dictionary, the
// DBGSourcePath values
// (the "values" half of key-value path pairs) were wrong. Ignore
// them and use the
// universal DBGSourcePath string from earlier.
if (new_style_source_remapping_dictionary == true &&
!original_DBGSourcePath_value.empty()) {
DBGSourcePath = original_DBGSourcePath_value;
}
if (DBGSourcePath[0] == '~') {
FileSpec resolved_source_path(DBGSourcePath.c_str(), true);
DBGSourcePath = resolved_source_path.GetPath();
}
// With version 2 of DBGSourcePathRemapping, we can chop off the
// last two filename parts from the source remapping and get a
// more general source remapping that still works. Add this as
// another option in addition to the full source path remap.
module_spec.GetSourceMappingList().Append(
ConstString(DBGBuildSourcePath.c_str()),
ConstString(DBGSourcePath.c_str()), true);
if (do_truncate_remapping_names) {
FileSpec build_path(DBGBuildSourcePath.c_str(), false);
FileSpec source_path(DBGSourcePath.c_str(), false);
build_path.RemoveLastPathComponent();
build_path.RemoveLastPathComponent();
source_path.RemoveLastPathComponent();
source_path.RemoveLastPathComponent();
module_spec.GetSourceMappingList().Append(
ConstString(build_path.GetPath().c_str()),
ConstString(source_path.GetPath().c_str()), true);
}
}
}
if (keys)
free(keys);
if (values)
free(values);
}
}
// If we have a DBGBuildSourcePath + DBGSourcePath pair,
// append them to the source remappings list.
cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
CFSTR("DBGBuildSourcePath"));
if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
}
cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
CFSTR("DBGSourcePath"));
if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
}
if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
if (DBGSourcePath[0] == '~') {
FileSpec resolved_source_path(DBGSourcePath.c_str(), true);
DBGSourcePath = resolved_source_path.GetPath();
}
module_spec.GetSourceMappingList().Append(
ConstString(DBGBuildSourcePath.c_str()),
ConstString(DBGSourcePath.c_str()), true);
}
}
return success;
}
bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
bool force_lookup) {
bool success = false;
const UUID *uuid_ptr = module_spec.GetUUIDPtr();
const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
// It's expensive to check for the DBGShellCommands defaults setting, only do
// it once per
// lldb run and cache the result.
static bool g_have_checked_for_dbgshell_command = false;
static const char *g_dbgshell_command = NULL;
if (g_have_checked_for_dbgshell_command == false) {
g_have_checked_for_dbgshell_command = true;
CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
if (defaults_setting &&
CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
char cstr_buf[PATH_MAX];
if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf,
sizeof(cstr_buf), kCFStringEncodingUTF8)) {
g_dbgshell_command =
strdup(cstr_buf); // this malloc'ed memory will never be freed
}
}
if (defaults_setting) {
CFRelease(defaults_setting);
}
}
// When g_dbgshell_command is NULL, the user has not enabled the use of an
// external program
// to find the symbols, don't run it for them.
if (force_lookup == false && g_dbgshell_command == NULL) {
return false;
}
if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists())) {
static bool g_located_dsym_for_uuid_exe = false;
static bool g_dsym_for_uuid_exe_exists = false;
static char g_dsym_for_uuid_exe_path[PATH_MAX];
if (!g_located_dsym_for_uuid_exe) {
g_located_dsym_for_uuid_exe = true;
const char *dsym_for_uuid_exe_path_cstr =
getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
FileSpec dsym_for_uuid_exe_spec;
if (dsym_for_uuid_exe_path_cstr) {
dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true);
g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
}
if (!g_dsym_for_uuid_exe_exists) {
dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false);
g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
if (!g_dsym_for_uuid_exe_exists) {
long bufsize;
if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) {
char buffer[bufsize];
struct passwd pwd;
struct passwd *tilde_rc = NULL;
// we are a library so we need to use the reentrant version of
// getpwnam()
if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 &&
tilde_rc && tilde_rc->pw_dir) {
std::string dsymforuuid_path(tilde_rc->pw_dir);
dsymforuuid_path += "/bin/dsymForUUID";
dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false);
g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
}
}
}
}
if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) {
dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true);
g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
}
if (g_dsym_for_uuid_exe_exists)
dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path,
sizeof(g_dsym_for_uuid_exe_path));
}
if (g_dsym_for_uuid_exe_exists) {
std::string uuid_str;
char file_path[PATH_MAX];
file_path[0] = '\0';
if (uuid_ptr)
uuid_str = uuid_ptr->GetAsString();
if (file_spec_ptr)
file_spec_ptr->GetPath(file_path, sizeof(file_path));
StreamString command;
if (!uuid_str.empty())
command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
g_dsym_for_uuid_exe_path, uuid_str.c_str());
else if (file_path[0] != '\0')
command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
g_dsym_for_uuid_exe_path, file_path);
if (!command.GetString().empty()) {
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
int exit_status = -1;
int signo = -1;
std::string command_output;
if (log) {
if (!uuid_str.empty())
log->Printf("Calling %s with UUID %s to find dSYM",
g_dsym_for_uuid_exe_path, uuid_str.c_str());
else if (file_path[0] != '\0')
log->Printf("Calling %s with file %s to find dSYM",
g_dsym_for_uuid_exe_path, file_path);
}
Status error = Host::RunShellCommand(
command.GetData(),
NULL, // current working directory
&exit_status, // Exit status
&signo, // Signal int *
&command_output, // Command output
30, // Large timeout to allow for long dsym download times
false); // Don't run in a shell (we don't need shell expansion)
if (error.Success() && exit_status == 0 && !command_output.empty()) {
CFCData data(CFDataCreateWithBytesNoCopy(
NULL, (const UInt8 *)command_output.data(), command_output.size(),
kCFAllocatorNull));
CFCReleaser<CFDictionaryRef> plist(
(CFDictionaryRef)::CFPropertyListCreateFromXMLData(
NULL, data.get(), kCFPropertyListImmutable, NULL));
if (plist.get() &&
CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) {
if (!uuid_str.empty()) {
CFCString uuid_cfstr(uuid_str.c_str());
CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue(
plist.get(), uuid_cfstr.get());
success =
GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec);
} else {
const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
if (num_values > 0) {
std::vector<CFStringRef> keys(num_values, NULL);
std::vector<CFDictionaryRef> values(num_values, NULL);
::CFDictionaryGetKeysAndValues(plist.get(), NULL,
(const void **)&values[0]);
if (num_values == 1) {
return GetModuleSpecInfoFromUUIDDictionary(values[0],
module_spec);
} else {
for (CFIndex i = 0; i < num_values; ++i) {
ModuleSpec curr_module_spec;
if (GetModuleSpecInfoFromUUIDDictionary(values[i],
curr_module_spec)) {
if (module_spec.GetArchitecture().IsCompatibleMatch(
curr_module_spec.GetArchitecture())) {
module_spec = curr_module_spec;
return true;
}
}
}
}
}
}
}
} else {
if (log) {
if (!uuid_str.empty())
log->Printf("Called %s on %s, no matches",
g_dsym_for_uuid_exe_path, uuid_str.c_str());
else if (file_path[0] != '\0')
log->Printf("Called %s on %s, no matches",
g_dsym_for_uuid_exe_path, file_path);
}
}
}
}
}
return success;
}