2019-05-13 12:42:32 +08:00
|
|
|
//===-- LocateSymbolFileMacOSX.cpp ------------------------------*- C++ -*-===//
|
2010-06-09 00:52:24 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2010-06-09 00:52:24 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
Move Host/Symbols.cpp to Symbols/LocateSymbolFile.cpp
Given that we have a target named Symbols, one wonders why a
file named Symbols.cpp is not in this target. To be clear,
the functions exposed from this file are really focused on
*locating* a symbol file on a given host, which is where the
ambiguity comes in. However, it makes more sense conceptually
to be in the Symbols target. While some of the specific places
to search for symbol files might change depending on the Host,
this is not inherently true in the same way that, for example,
"accessing the file system" or "starting threads" is
fundamentally dependent on the Host.
PDBs, for example, recently became a reality on non-Windows platforms,
and it's theoretically possible that DSYMs could become a thing on non
MacOSX platforms (maybe in a remote debugging scenario). Other types of
symbol files, such as DWO, DWP, etc have never been tied to any Host
platform anyway.
After this patch, there is only one remaining dependency from
Host to Target.
Differential Revision: https://reviews.llvm.org/D58730
llvm-svn: 355032
2019-02-28 05:42:10 +08:00
|
|
|
#include "lldb/Symbol/LocateSymbolFile.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
#include <dirent.h>
|
2019-06-25 06:08:43 +08:00
|
|
|
#include <dlfcn.h>
|
2012-10-31 05:26:30 +08:00
|
|
|
#include <pwd.h>
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
#include "Host/macosx/cfcpp/CFCBundle.h"
|
|
|
|
#include "Host/macosx/cfcpp/CFCData.h"
|
|
|
|
#include "Host/macosx/cfcpp/CFCReleaser.h"
|
|
|
|
#include "Host/macosx/cfcpp/CFCString.h"
|
2018-03-13 04:52:36 +08:00
|
|
|
#include "lldb/Core/ModuleList.h"
|
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-30 05:13:06 +08:00
|
|
|
#include "lldb/Core/ModuleSpec.h"
|
2012-02-01 09:49:50 +08:00
|
|
|
#include "lldb/Host/Host.h"
|
2015-04-25 02:09:54 +08:00
|
|
|
#include "lldb/Symbol/ObjectFile.h"
|
2017-11-14 00:47:37 +08:00
|
|
|
#include "lldb/Utility/ArchSpec.h"
|
2011-02-01 13:15:02 +08:00
|
|
|
#include "lldb/Utility/CleanUp.h"
|
2017-03-04 09:30:05 +08:00
|
|
|
#include "lldb/Utility/DataBuffer.h"
|
|
|
|
#include "lldb/Utility/DataExtractor.h"
|
2017-02-15 03:06:07 +08:00
|
|
|
#include "lldb/Utility/Endian.h"
|
2017-03-04 04:56:28 +08:00
|
|
|
#include "lldb/Utility/Log.h"
|
2017-02-03 05:39:50 +08:00
|
|
|
#include "lldb/Utility/StreamString.h"
|
2017-06-29 23:24:38 +08:00
|
|
|
#include "lldb/Utility/Timer.h"
|
2017-03-04 09:30:05 +08:00
|
|
|
#include "lldb/Utility/UUID.h"
|
2010-09-09 07:01:14 +08:00
|
|
|
#include "mach/machine.h"
|
2010-07-10 04:39:50 +08:00
|
|
|
|
2017-03-09 01:56:08 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
2019-06-25 06:08:43 +08:00
|
|
|
static CFURLRef (*g_dlsym_DBGCopyFullDSYMURLForUUID)(CFUUIDRef uuid, CFURLRef exec_url) = nullptr;
|
|
|
|
static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) = nullptr;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
|
|
|
|
ModuleSpec &return_module_spec) {
|
2018-03-13 04:52:36 +08:00
|
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
|
|
if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
|
|
|
|
if (log)
|
|
|
|
log->Printf("Spotlight lookup for .dSYM bundles is disabled.");
|
|
|
|
return 0;
|
|
|
|
}
|
Move Host/Symbols.cpp to Symbols/LocateSymbolFile.cpp
Given that we have a target named Symbols, one wonders why a
file named Symbols.cpp is not in this target. To be clear,
the functions exposed from this file are really focused on
*locating* a symbol file on a given host, which is where the
ambiguity comes in. However, it makes more sense conceptually
to be in the Symbols target. While some of the specific places
to search for symbol files might change depending on the Host,
this is not inherently true in the same way that, for example,
"accessing the file system" or "starting threads" is
fundamentally dependent on the Host.
PDBs, for example, recently became a reality on non-Windows platforms,
and it's theoretically possible that DSYMs could become a thing on non
MacOSX platforms (maybe in a remote debugging scenario). Other types of
symbol files, such as DWO, DWP, etc have never been tied to any Host
platform anyway.
After this patch, there is only one remaining dependency from
Host to Target.
Differential Revision: https://reviews.llvm.org/D58730
llvm-svn: 355032
2019-02-28 05:42:10 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
return_module_spec = module_spec;
|
|
|
|
return_module_spec.GetFileSpec().Clear();
|
|
|
|
return_module_spec.GetSymbolFileSpec().Clear();
|
|
|
|
|
|
|
|
int items_found = 0;
|
|
|
|
|
2019-06-25 06:08:43 +08:00
|
|
|
if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
|
|
|
|
g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
|
|
|
|
void *handle = dlopen ("/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols", RTLD_LAZY | RTLD_LOCAL);
|
|
|
|
if (handle) {
|
|
|
|
g_dlsym_DBGCopyFullDSYMURLForUUID = (CFURLRef (*)(CFUUIDRef, CFURLRef)) dlsym (handle, "DBGCopyFullDSYMURLForUUID");
|
|
|
|
g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef (*)(CFURLRef)) dlsym (handle, "DBGCopyDSYMPropertyLists");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
|
|
|
|
g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
|
|
|
|
return items_found;
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
|
|
|
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
|
2018-06-21 23:40:33 +08:00
|
|
|
llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
|
|
|
|
if (module_uuid.size() == 16) {
|
2016-09-07 04:57:50 +08:00
|
|
|
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();
|
|
|
|
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));
|
|
|
|
}
|
2015-10-01 17:03:33 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
CFCReleaser<CFURLRef> dsym_url(
|
2019-06-25 06:08:43 +08:00
|
|
|
g_dlsym_DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
|
2016-09-07 04:57:50 +08:00
|
|
|
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());
|
|
|
|
}
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSpec dsym_filespec(path);
|
|
|
|
if (path[0] == '~')
|
|
|
|
FileSystem::Instance().Resolve(dsym_filespec);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2018-11-08 08:14:50 +08:00
|
|
|
if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
|
2016-09-07 04:57:50 +08:00
|
|
|
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(
|
2019-06-25 06:08:43 +08:00
|
|
|
g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get()));
|
2016-09-07 04:57:50 +08:00
|
|
|
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;
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSpec exec_filespec(path);
|
|
|
|
if (path[0] == '~')
|
|
|
|
FileSystem::Instance().Resolve(exec_filespec);
|
2018-11-02 01:09:25 +08:00
|
|
|
if (FileSystem::Instance().Exists(exec_filespec)) {
|
2016-09-07 04:57:50 +08:00
|
|
|
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);
|
|
|
|
}
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSpec file_spec(path);
|
|
|
|
FileSystem::Instance().Resolve(file_spec);
|
2016-09-07 04:57:50 +08:00
|
|
|
ModuleSpecList module_specs;
|
|
|
|
ModuleSpec matched_module_spec;
|
2017-03-09 01:56:08 +08:00
|
|
|
using namespace llvm::sys::fs;
|
|
|
|
switch (get_file_type(file_spec.GetPath())) {
|
|
|
|
|
|
|
|
case file_type::directory_file: // Bundle directory?
|
2015-10-01 17:03:33 +08:00
|
|
|
{
|
2016-09-07 04:57:50 +08:00
|
|
|
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)) {
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSpec bundle_exe_file_spec(path);
|
|
|
|
FileSystem::Instance().Resolve(bundle_exe_file_spec);
|
2016-09-07 04:57:50 +08:00
|
|
|
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);
|
2015-10-09 05:48:35 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2015-10-09 05:48:35 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
2017-03-09 01:56:08 +08:00
|
|
|
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:
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
|
2017-03-09 01:56:08 +08:00
|
|
|
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:
|
2016-09-07 04:57:50 +08:00
|
|
|
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);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
break;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2011-11-04 11:34:56 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
return items_found;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
|
|
|
|
const lldb_private::UUID *uuid,
|
|
|
|
const ArchSpec *arch) {
|
|
|
|
char path[PATH_MAX];
|
2018-02-24 06:08:38 +08:00
|
|
|
if (dsym_bundle_fspec.GetPath(path, sizeof(path)) == 0)
|
|
|
|
return {};
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2018-02-24 06:08:38 +08:00
|
|
|
::strncat(path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2018-02-24 06:08:38 +08:00
|
|
|
DIR *dirp = opendir(path);
|
|
|
|
if (!dirp)
|
|
|
|
return {};
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2018-02-24 06:08:38 +08:00
|
|
|
// 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;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2018-02-24 06:08:38 +08:00
|
|
|
|
|
|
|
return {};
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2012-09-27 11:13:55 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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)) {
|
2018-11-02 05:05:36 +08:00
|
|
|
module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native);
|
|
|
|
FileSystem::Instance().Resolve(module_spec.GetFileSpec());
|
2016-09-07 04:57:50 +08:00
|
|
|
if (log) {
|
|
|
|
log->Printf(
|
|
|
|
"From dsymForUUID plist: Symbol rich executable is at '%s'",
|
|
|
|
str.c_str());
|
2012-09-28 06:26:11 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
|
|
|
|
CFSTR("DBGDSYMPath"));
|
|
|
|
if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
|
|
|
|
if (CFCString::FileSystemRepresentation(cf_str, str)) {
|
2018-11-02 05:05:36 +08:00
|
|
|
module_spec.GetSymbolFileSpec().SetFile(str.c_str(),
|
2018-06-14 06:08:14 +08:00
|
|
|
FileSpec::Style::native);
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSystem::Instance().Resolve(module_spec.GetFileSpec());
|
2016-09-07 04:57:50 +08:00
|
|
|
success = true;
|
|
|
|
if (log) {
|
|
|
|
log->Printf("From dsymForUUID plist: dSYM is at '%s'", str.c_str());
|
2012-09-28 06:26:11 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
2012-09-28 06:26:11 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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());
|
|
|
|
}
|
2012-09-28 06:26:11 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
std::string DBGBuildSourcePath;
|
|
|
|
std::string DBGSourcePath;
|
2012-09-28 06:26:11 +08:00
|
|
|
|
2018-06-12 05:36:40 +08:00
|
|
|
// If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
|
|
|
|
// If DBGVersion 2, strip last two components of path remappings from
|
|
|
|
// entries to fix an issue with a specific set of
|
|
|
|
// DBGSourcePathRemapping entries that lldb worked
|
|
|
|
// with.
|
|
|
|
// If DBGVersion 3, trust & use the source path remappings as-is.
|
|
|
|
//
|
2016-09-07 04:57:50 +08:00
|
|
|
cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
|
|
|
|
(CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
|
|
|
|
if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
|
2016-11-09 11:42:12 +08:00
|
|
|
// If we see DBGVersion with a value of 2 or higher, this is a new style
|
2016-09-07 04:57:50 +08:00
|
|
|
// DBGSourcePathRemapping dictionary
|
|
|
|
bool new_style_source_remapping_dictionary = false;
|
2017-08-24 08:58:14 +08:00
|
|
|
bool do_truncate_remapping_names = false;
|
2016-09-07 04:57:50 +08:00
|
|
|
std::string original_DBGSourcePath_value = DBGSourcePath;
|
2016-11-09 11:42:12 +08:00
|
|
|
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;
|
|
|
|
}
|
2017-08-24 08:58:14 +08:00
|
|
|
if (version_number == 2) {
|
|
|
|
do_truncate_remapping_names = true;
|
|
|
|
}
|
2016-11-09 11:42:12 +08:00
|
|
|
}
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
|
|
|
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);
|
2012-10-09 09:17:11 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
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
|
2018-05-01 00:49:04 +08:00
|
|
|
// DBGSourcePath values (the "values" half of key-value path pairs)
|
|
|
|
// were wrong. Ignore them and use the universal DBGSourcePath
|
|
|
|
// string from earlier.
|
2018-12-15 08:15:33 +08:00
|
|
|
if (new_style_source_remapping_dictionary &&
|
2016-09-07 04:57:50 +08:00
|
|
|
!original_DBGSourcePath_value.empty()) {
|
|
|
|
DBGSourcePath = original_DBGSourcePath_value;
|
|
|
|
}
|
|
|
|
if (DBGSourcePath[0] == '~') {
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSpec resolved_source_path(DBGSourcePath.c_str());
|
|
|
|
FileSystem::Instance().Resolve(resolved_source_path);
|
2016-09-07 04:57:50 +08:00
|
|
|
DBGSourcePath = resolved_source_path.GetPath();
|
|
|
|
}
|
2017-08-24 08:58:14 +08:00
|
|
|
// With version 2 of DBGSourcePathRemapping, we can chop off the
|
2018-05-01 00:49:04 +08:00
|
|
|
// 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.
|
2016-09-07 04:57:50 +08:00
|
|
|
module_spec.GetSourceMappingList().Append(
|
|
|
|
ConstString(DBGBuildSourcePath.c_str()),
|
|
|
|
ConstString(DBGSourcePath.c_str()), true);
|
2017-08-24 08:58:14 +08:00
|
|
|
if (do_truncate_remapping_names) {
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSpec build_path(DBGBuildSourcePath.c_str());
|
|
|
|
FileSpec source_path(DBGSourcePath.c_str());
|
2017-08-24 08:58:14 +08:00
|
|
|
build_path.RemoveLastPathComponent();
|
|
|
|
build_path.RemoveLastPathComponent();
|
|
|
|
source_path.RemoveLastPathComponent();
|
|
|
|
source_path.RemoveLastPathComponent();
|
|
|
|
module_spec.GetSourceMappingList().Append(
|
Move Host/Symbols.cpp to Symbols/LocateSymbolFile.cpp
Given that we have a target named Symbols, one wonders why a
file named Symbols.cpp is not in this target. To be clear,
the functions exposed from this file are really focused on
*locating* a symbol file on a given host, which is where the
ambiguity comes in. However, it makes more sense conceptually
to be in the Symbols target. While some of the specific places
to search for symbol files might change depending on the Host,
this is not inherently true in the same way that, for example,
"accessing the file system" or "starting threads" is
fundamentally dependent on the Host.
PDBs, for example, recently became a reality on non-Windows platforms,
and it's theoretically possible that DSYMs could become a thing on non
MacOSX platforms (maybe in a remote debugging scenario). Other types of
symbol files, such as DWO, DWP, etc have never been tied to any Host
platform anyway.
After this patch, there is only one remaining dependency from
Host to Target.
Differential Revision: https://reviews.llvm.org/D58730
llvm-svn: 355032
2019-02-28 05:42:10 +08:00
|
|
|
ConstString(build_path.GetPath().c_str()),
|
|
|
|
ConstString(source_path.GetPath().c_str()), true);
|
2017-08-24 08:58:14 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2012-10-09 09:17:11 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
if (keys)
|
|
|
|
free(keys);
|
|
|
|
if (values)
|
|
|
|
free(values);
|
|
|
|
}
|
2012-10-09 09:17:11 +08:00
|
|
|
}
|
2018-01-13 06:42:45 +08:00
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
|
|
|
|
// source remappings list.
|
2018-01-13 06:42:45 +08:00
|
|
|
|
|
|
|
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] == '~') {
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSpec resolved_source_path(DBGSourcePath.c_str());
|
|
|
|
FileSystem::Instance().Resolve(resolved_source_path);
|
2018-01-13 06:42:45 +08:00
|
|
|
DBGSourcePath = resolved_source_path.GetPath();
|
|
|
|
}
|
|
|
|
module_spec.GetSourceMappingList().Append(
|
|
|
|
ConstString(DBGBuildSourcePath.c_str()),
|
|
|
|
ConstString(DBGSourcePath.c_str()), true);
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
2012-10-09 09:17:11 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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
|
2018-05-01 00:49:04 +08:00
|
|
|
// it once per lldb run and cache the result.
|
2016-09-07 04:57:50 +08:00
|
|
|
static bool g_have_checked_for_dbgshell_command = false;
|
|
|
|
static const char *g_dbgshell_command = NULL;
|
2018-12-15 08:15:33 +08:00
|
|
|
if (!g_have_checked_for_dbgshell_command) {
|
2016-09-07 04:57:50 +08:00
|
|
|
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
|
|
|
|
}
|
2012-10-09 09:17:11 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
if (defaults_setting) {
|
|
|
|
CFRelease(defaults_setting);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// When g_dbgshell_command is NULL, the user has not enabled the use of an
|
2018-05-01 00:49:04 +08:00
|
|
|
// external program to find the symbols, don't run it for them.
|
2018-12-15 08:15:33 +08:00
|
|
|
if (!force_lookup && g_dbgshell_command == NULL) {
|
2016-09-07 04:57:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-02 01:09:25 +08:00
|
|
|
if (uuid_ptr ||
|
|
|
|
(file_spec_ptr && FileSystem::Instance().Exists(*file_spec_ptr))) {
|
2016-09-07 04:57:50 +08:00
|
|
|
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) {
|
2018-11-02 05:05:36 +08:00
|
|
|
dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr,
|
2018-06-14 06:08:14 +08:00
|
|
|
FileSpec::Style::native);
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
|
2018-11-02 01:09:25 +08:00
|
|
|
g_dsym_for_uuid_exe_exists =
|
|
|
|
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!g_dsym_for_uuid_exe_exists) {
|
2018-11-02 05:05:36 +08:00
|
|
|
dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID",
|
2018-06-14 06:08:14 +08:00
|
|
|
FileSpec::Style::native);
|
2018-11-02 01:09:25 +08:00
|
|
|
g_dsym_for_uuid_exe_exists =
|
|
|
|
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
|
2016-09-07 04:57:50 +08:00
|
|
|
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";
|
2018-11-02 05:05:36 +08:00
|
|
|
dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(),
|
2018-06-14 06:08:14 +08:00
|
|
|
FileSpec::Style::native);
|
2018-11-02 01:09:25 +08:00
|
|
|
g_dsym_for_uuid_exe_exists =
|
|
|
|
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
|
2012-09-27 11:13:55 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) {
|
2018-11-02 05:05:36 +08:00
|
|
|
dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command,
|
2018-06-14 06:08:14 +08:00
|
|
|
FileSpec::Style::native);
|
2018-11-02 05:05:36 +08:00
|
|
|
FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
|
2018-11-02 01:09:25 +08:00
|
|
|
g_dsym_for_uuid_exe_exists =
|
|
|
|
FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2017-05-12 12:51:55 +08:00
|
|
|
Status error = Host::RunShellCommand(
|
2016-09-07 04:57:50 +08:00
|
|
|
command.GetData(),
|
|
|
|
NULL, // current working directory
|
|
|
|
&exit_status, // Exit status
|
|
|
|
&signo, // Signal int *
|
|
|
|
&command_output, // Command output
|
2018-05-10 19:27:43 +08:00
|
|
|
std::chrono::seconds(
|
2019-03-01 11:24:59 +08:00
|
|
|
120), // Large timeout to allow for long dsym download times
|
2018-05-10 19:27:43 +08:00
|
|
|
false); // Don't run in a shell (we don't need shell expansion)
|
2016-09-07 04:57:50 +08:00
|
|
|
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;
|
|
|
|
}
|
2012-10-31 05:26:30 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2012-09-27 11:13:55 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2012-09-27 11:13:55 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (log) {
|
2013-05-04 07:56:12 +08:00
|
|
|
if (!uuid_str.empty())
|
2016-09-07 04:57:50 +08:00
|
|
|
log->Printf("Called %s on %s, no matches",
|
|
|
|
g_dsym_for_uuid_exe_path, uuid_str.c_str());
|
2014-10-17 09:38:10 +08:00
|
|
|
else if (file_path[0] != '\0')
|
2016-09-07 04:57:50 +08:00
|
|
|
log->Printf("Called %s on %s, no matches",
|
|
|
|
g_dsym_for_uuid_exe_path, file_path);
|
|
|
|
}
|
2012-09-27 11:13:55 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2012-09-27 11:13:55 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
return success;
|
2012-09-27 11:13:55 +08:00
|
|
|
}
|