Skip to content

Commit

Permalink
Add initial support for position-independent executables.
Browse files Browse the repository at this point in the history
  • Loading branch information
lifthrasiir committed Mar 14, 2015
1 parent ddc25d7 commit aab8928
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 12 deletions.
14 changes: 14 additions & 0 deletions src/engines/ptrace.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <phdr_data.h>

#include <unistd.h>
#include <sys/personality.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
Expand Down Expand Up @@ -487,8 +488,21 @@ class Ptrace : public IEngine

/* Executable exists, try to launch it */
if ((child = fork()) == 0) {
int persona;
int res;

/* Avoid address randomization */
persona = personality(0xffffffff);
if (persona < 0) {
perror("Can't get personality");
return false;
}
persona |= 0x0040000; /* ADDR_NO_RANDOMIZE */
if (personality(persona) < 0) {
perror("Can't set personality");
return false;
}

/* And launch the process */
res = ptrace(PTRACE_TRACEME, 0, 0, 0);
if (res < 0) {
Expand Down
5 changes: 5 additions & 0 deletions src/engines/script-engine-base.hh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public:
return true;
}

bool setMainFileRelocation(unsigned long relocation)
{
return true;
}

void registerLineListener(ILineListener &listener)
{
m_lineListeners.push_back(&listener);
Expand Down
16 changes: 16 additions & 0 deletions src/include/file-parser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,22 @@ namespace kcov
*/
virtual bool addFile(const std::string &filename, struct phdr_data_entry *phdr_data = 0) = 0;

/**
* Set the relocation of the main file for the position-independent executable (PIE) support
*
* PIEs have, like shared objects, an unknown load address which can only be
* retrieved from the solib handler. Because of this the parser may defer
* onFile and onLine notifications before this call.
*
* This method, if any, should be called after the initial parse call and
* beefore the following addFile calls for solibs.
*
* @param relocation relocation offset
*
* @return true if the relocation is properly set, false otherwise
*/
virtual bool setMainFileRelocation(unsigned long relocation) = 0;

/**
* Register a listener for source lines.
*
Expand Down
1 change: 1 addition & 0 deletions src/include/phdr_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct phdr_data
{
uint32_t magic;
uint32_t version;
unsigned long relocation; // for PIE
uint32_t n_entries;

struct phdr_data_entry entries[];
Expand Down
5 changes: 5 additions & 0 deletions src/merge-file-parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ class MergeParser :
return true;
}

virtual bool setMainFileRelocation(unsigned long relocation)
{
return true;
}

virtual void registerLineListener(IFileParser::ILineListener &listener)
{
m_lineListeners.push_back(&listener);
Expand Down
61 changes: 50 additions & 11 deletions src/parsers/elf-parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class ElfInstance : public IFileParser
m_filename = "";
m_checksum = 0;
m_elfIs32Bit = true;
m_elfIsShared = false;
m_isMainFile = true;
m_initialized = false;
m_filter = NULL;
Expand Down Expand Up @@ -145,6 +146,7 @@ class ElfInstance : public IFileParser
if (m_isMainFile) {
char *raw;
size_t sz;
uint16_t e_type;

raw = elf_getident(elf, &sz);

Expand All @@ -159,6 +161,9 @@ class ElfInstance : public IFileParser
capabilities.addCapability("handle-solibs");
}

e_type = m_elfIs32Bit ? elf32_getehdr(elf)->e_type : elf64_getehdr(elf)->e_type;

m_elfIsShared = e_type == ET_DYN;
m_checksum = m_elfIs32Bit ? elf32_checksum(elf) : elf64_checksum(elf);
}

Expand All @@ -171,38 +176,71 @@ class ElfInstance : public IFileParser
}

bool parse()
{
// should defer until setMainFileRelocation
if (m_isMainFile && m_elfIsShared)
return true;

if (!doParse(0))
return false;

// After the first, all other are solibs
m_isMainFile = false;
return true;
}

bool doParse(unsigned long relocation)
{
struct stat st;

if (lstat(m_filename.c_str(), &st) < 0)
return 0;
return false;

parseOneElf();

// Gcov data?
if (IConfiguration::getInstance().keyAsInt("gcov") && !m_gcnoFiles.empty())
parseGcnoFiles();
parseGcnoFiles(relocation);
else
parseOneDwarf();
parseOneDwarf(relocation);

// After the first, all other are solibs
m_isMainFile = false;
return true;
}

bool setMainFileRelocation(unsigned long relocation)
{
if (!m_isMainFile)
return false;

kcov_debug(INFO_MSG, "main file relocation = %#lx", relocation);

if (m_elfIsShared) {
if (!doParse(relocation))
return false;
} else {
// this situation is probably problematic, as we have already notified
// segment informations to the listeners.
if (relocation != 0) {
warning("Got a static executable with relocation=%#lx, "
"probably the trace wouldn't work.", relocation);
}
}

return true;
}

void parseGcnoFiles()
void parseGcnoFiles(unsigned long relocation)
{
for (FileList_t::const_iterator it = m_gcnoFiles.begin();
it != m_gcnoFiles.end();
++it) {
const std::string &cur = *it;

parseOneGcno(cur);
parseOneGcno(cur, relocation);
}
}

void parseOneGcno(const std::string &filename)
void parseOneGcno(const std::string &filename, unsigned long relocation)
{
size_t sz;
void *data;
Expand Down Expand Up @@ -234,11 +272,11 @@ class ElfInstance : public IFileParser
it != m_lineListeners.end();
++it)
(*it)->onLine(cur.m_file, cur.m_line,
gcovGetAddress(cur.m_file, cur.m_function, cur.m_basicBlock, cur.m_index));
gcovGetAddress(cur.m_file, cur.m_function, cur.m_basicBlock, cur.m_index) + relocation);
}
}

bool parseOneDwarf()
bool parseOneDwarf(unsigned long relocation)
{
Dwarf_Off offset = 0;
Dwarf_Off last_offset = 0;
Expand Down Expand Up @@ -373,7 +411,7 @@ class ElfInstance : public IFileParser
for (LineListenerList_t::const_iterator it = m_lineListeners.begin();
it != m_lineListeners.end();
++it)
(*it)->onLine(file_path, line_nr, adjustAddressBySegment(addr));
(*it)->onLine(file_path, line_nr, adjustAddressBySegment(addr) + relocation);
}
}
}
Expand Down Expand Up @@ -605,6 +643,7 @@ class ElfInstance : public IFileParser

struct Elf *m_elf;
bool m_elfIs32Bit;
bool m_elfIsShared;
LineListenerList_t m_lineListeners;
FileListenerList_t m_fileListeners;
std::string m_filename;
Expand Down
2 changes: 2 additions & 0 deletions src/solib-handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ class SolibHandler : public ISolibHandler, ICollector::IEventTickListener
if (!p)
return;

m_parser->setMainFileRelocation(p->relocation);

for (unsigned int i = 0; i < p->n_entries; i++)
{
struct phdr_data_entry *cur = &p->entries[i];
Expand Down
6 changes: 6 additions & 0 deletions src/solib-parser/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ static struct phdr_data *phdr_data;

static int phdrCallback(struct dl_phdr_info *info, size_t size, void *data)
{
// the first entry is used to determine the executable's "base address"
// (which is actually the relocation for PIE)
if (phdr_data->n_entries == 0) {
phdr_data->relocation = info->dlpi_addr;
}

phdr_data_add(phdr_data, info);

return 0;
Expand Down
3 changes: 2 additions & 1 deletion src/solib-parser/phdr_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <link.h>

#define KCOV_MAGIC 0x6b636f76 /* "kcov" */
#define KCOV_SOLIB_VERSION 2
#define KCOV_SOLIB_VERSION 3

static uint8_t data_area[4 * 1024 * 1024];

Expand All @@ -23,6 +23,7 @@ struct phdr_data *phdr_data_new(size_t allocSize)

p->magic = KCOV_MAGIC;
p->version = KCOV_SOLIB_VERSION;
p->relocation = 0;
p->n_entries = 0;

return p;
Expand Down

0 comments on commit aab8928

Please sign in to comment.