Files
clang-p2996/lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp
Stephen Wilson 2103e25e19 Initial support for a DynamicLoader plugin on Linux.
This patch is enough to have shared objects recognized by LLDB.  We can handle
position independent executables.  We can handle dynamically loaded modules
brought in via dlopen.

The DYLDRendezvous class provides an interface to a structure present in the
address space of ELF-based processes.  This structure provides the address of a
function which is called by the linker each time a shared object is loaded and
unloaded (thus a breakpoint at that address will let LLDB intercept such
events), a list of entries describing the currently loaded shared objects, plus
a few other things.

On Linux, processes are brought up with an auxiliary vector on the stack.  One
element in this vector contains the (possibly dynamic) entry address of the
process.  One does not need to walk the stack to find this information as it is
also available under /proc/<pid>/auxv.  The new AuxVector class provides a
convenient read-only view of this auxiliary vector information.  We use the
dynamic entry address and the address as specified in the object file to compute
the actual load address of the inferior image.  This strategy works for both
normal executables and PIE's.

llvm-svn: 123592
2011-01-16 19:45:39 +00:00

192 lines
4.6 KiB
C++

//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
// C++ Includes
// Other libraries and framework includes
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "AuxVector.h"
using namespace lldb;
using namespace lldb_private;
static bool
GetMaxU64(DataExtractor &data,
uint32_t *offset, uint64_t *value, unsigned int byte_size)
{
uint32_t saved_offset = *offset;
*value = data.GetMaxU64(offset, byte_size);
return *offset != saved_offset;
}
static bool
ParseAuxvEntry(DataExtractor &data, AuxVector::Entry &entry,
uint32_t *offset, unsigned int byte_size)
{
if (!GetMaxU64(data, offset, &entry.type, byte_size))
return false;
if (!GetMaxU64(data, offset, &entry.value, byte_size))
return false;
return true;
}
DataBufferSP
AuxVector::GetAuxvData()
{
static const size_t path_size = 128;
static char path[path_size];
DataBufferSP buf_sp;
int fd;
// Ideally, we would simply create a FileSpec and call ReadFileContents.
// However, files in procfs have zero size (since they are, in general,
// dynamically generated by the kernel) which is incompatible with the
// current ReadFileContents implementation. Therefore we simply stream the
// data into a DataBuffer ourselves.
if (snprintf(path, path_size, "/proc/%d/auxv", m_process->GetID()) < 0)
return buf_sp;
if ((fd = open(path, O_RDONLY, 0)) < 0)
return buf_sp;
size_t bytes_read = 0;
std::auto_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
for (;;)
{
size_t avail = buf_ap->GetByteSize() - bytes_read;
ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail);
if (status < 0)
break;
bytes_read += status;
if (status == 0)
{
buf_ap->SetByteSize(bytes_read);
buf_sp.reset(buf_ap.release());
break;
}
if (avail - status == 0)
buf_ap->SetByteSize(2 * buf_ap->GetByteSize());
}
return buf_sp;
}
void
AuxVector::ParseAuxv(DataExtractor &data)
{
const unsigned int byte_size = m_process->GetAddressByteSize();
uint32_t offset = 0;
for (;;)
{
Entry entry;
if (!ParseAuxvEntry(data, entry, &offset, byte_size))
break;
if (entry.type == AT_NULL)
break;
if (entry.type == AT_IGNORE)
continue;
m_auxv.push_back(entry);
}
}
AuxVector::AuxVector(Process *process)
: m_process(process)
{
DataExtractor data;
LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
data.SetData(GetAuxvData());
data.SetByteOrder(m_process->GetByteOrder());
data.SetAddressByteSize(m_process->GetAddressByteSize());
ParseAuxv(data);
if (log)
DumpToLog(log);
}
AuxVector::iterator
AuxVector::FindEntry(EntryType type) const
{
for (iterator I = begin(); I != end(); ++I)
{
if (I->type == static_cast<uint64_t>(type))
return I;
}
return end();
}
void
AuxVector::DumpToLog(LogSP log) const
{
if (!log)
return;
log->PutCString("AuxVector: ");
for (iterator I = begin(); I != end(); ++I)
{
log->Printf(" %s [%d]: %lx", GetEntryName(*I), I->type, I->value);
}
}
const char *
AuxVector::GetEntryName(EntryType type)
{
const char *name;
#define ENTRY_NAME(_type) _type: name = #_type
switch (type)
{
default:
name = "unkown";
break;
case ENTRY_NAME(AT_NULL); break;
case ENTRY_NAME(AT_IGNORE); break;
case ENTRY_NAME(AT_EXECFD); break;
case ENTRY_NAME(AT_PHDR); break;
case ENTRY_NAME(AT_PHENT); break;
case ENTRY_NAME(AT_PHNUM); break;
case ENTRY_NAME(AT_PAGESZ); break;
case ENTRY_NAME(AT_BASE); break;
case ENTRY_NAME(AT_FLAGS); break;
case ENTRY_NAME(AT_ENTRY); break;
case ENTRY_NAME(AT_NOTELF); break;
case ENTRY_NAME(AT_UID); break;
case ENTRY_NAME(AT_EUID); break;
case ENTRY_NAME(AT_GID); break;
case ENTRY_NAME(AT_EGID); break;
case ENTRY_NAME(AT_CLKTCK); break;
}
#undef ENTRY_NAME
return name;
}