Fix LLDB so that it can correctly track down dependent shared libraries that use @rpath.

<rdar://problem/8371885>

llvm-svn: 238886
This commit is contained in:
Greg Clayton 2015-06-02 22:43:29 +00:00
parent 677324e0b5
commit 5a27195b1a
3 changed files with 77 additions and 7 deletions

View File

@ -638,6 +638,13 @@ public:
lldb::DataBufferSP
ReadFileContentsAsCString(Error *error_ptr = NULL);
//------------------------------------------------------------------
/// Normalize a pathname by collapsing redundant separators and
/// up-level references.
//------------------------------------------------------------------
void
NormalizePath ();
//------------------------------------------------------------------
/// Run through the input string, replaying the effect of any ".." and produce
/// the resultant path. The input path is not required to be in the host file system

View File

@ -545,6 +545,14 @@ FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_ba
}
}
void
FileSpec::NormalizePath ()
{
ConstString normalized_directory;
FileSpec::RemoveBackupDots(m_directory, normalized_directory);
m_directory = normalized_directory;
}
void
FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str)
{

View File

@ -4788,6 +4788,8 @@ ObjectFileMachO::GetDependentModules (FileSpecList& files)
lldb_private::Mutex::Locker locker(module_sp->GetMutex());
struct load_command load_cmd;
lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
std::vector<std::string> rpath_paths;
std::vector<std::string> rpath_relative_paths;
const bool resolve_path = false; // Don't resolve the dependent file paths since they may not reside on this system
uint32_t i;
for (i=0; i<m_header.ncmds; ++i)
@ -4798,6 +4800,7 @@ ObjectFileMachO::GetDependentModules (FileSpecList& files)
switch (load_cmd.cmd)
{
case LC_RPATH:
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
@ -4807,14 +4810,24 @@ ObjectFileMachO::GetDependentModules (FileSpecList& files)
{
uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
const char *path = m_data.PeekCStr(name_offset);
// Skip any path that starts with '@' since these are usually:
// @executable_path/.../file
// @rpath/.../file
if (path && path[0] != '@')
if (path)
{
FileSpec file_spec(path, resolve_path);
if (files.AppendIfUnique(file_spec))
count++;
if (load_cmd.cmd == LC_RPATH)
rpath_paths.push_back(path);
else
{
if (path[0] == '@')
{
if (strncmp(path, "@rpath", strlen("@rpath")) == 0)
rpath_relative_paths.push_back(path + strlen("@rpath"));
}
else
{
FileSpec file_spec(path, resolve_path);
if (files.AppendIfUnique(file_spec))
count++;
}
}
}
}
break;
@ -4824,6 +4837,48 @@ ObjectFileMachO::GetDependentModules (FileSpecList& files)
}
offset = cmd_offset + load_cmd.cmdsize;
}
if (!rpath_paths.empty())
{
// Fixup all LC_RPATH values to be absolute paths
FileSpec this_file_spec(m_file);
this_file_spec.ResolvePath();
std::string loader_path("@loader_path");
std::string executable_path("@executable_path");
for (auto &rpath : rpath_paths)
{
if (rpath.find(loader_path) == 0)
{
rpath.erase(0, loader_path.size());
rpath.insert(0, this_file_spec.GetDirectory().GetCString());
}
else if (rpath.find(executable_path) == 0)
{
rpath.erase(0, executable_path.size());
rpath.insert(0, this_file_spec.GetDirectory().GetCString());
}
}
for (const auto &rpath_relative_path : rpath_relative_paths)
{
for (const auto &rpath : rpath_paths)
{
std::string path = rpath;
path += rpath_relative_path;
// It is OK to resolve this path because we must find a file on
// disk for us to accept it anyway if it is rpath relative.
FileSpec file_spec(path, true);
// Remove any redundant parts of the path (like "../foo") since
// LC_RPATH values often contain "..".
file_spec.NormalizePath ();
if (file_spec.Exists() && files.AppendIfUnique(file_spec))
{
count++;
break;
}
}
}
}
}
return count;
}