[asan] use dl_iterate_phdr for pre-symbolization on linux instead of parsing /proc/self/maps

llvm-svn: 147628
This commit is contained in:
Kostya Serebryany 2012-01-05 23:50:34 +00:00
parent 2a189134b9
commit 3b7fb102c4
3 changed files with 62 additions and 24 deletions

View File

@ -24,17 +24,16 @@
#include <sys/syscall.h>
#include <sys/types.h>
#include <fcntl.h>
#include <link.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
extern char _DYNAMIC[];
namespace __asan {
void *AsanDoesNotSupportStaticLinkage() {
// This will fail to link with -static.
return &_DYNAMIC;
return &_DYNAMIC; // defined in link.h
}
static void *asan_mmap(void *addr, size_t length, int prot, int flags,
@ -120,20 +119,20 @@ void AsanProcMaps::Reset() {
current_ = proc_self_maps_buff_;
}
bool AsanProcMaps::Next(uint64_t *start, uint64_t *end,
uint64_t *offset, char filename[],
bool AsanProcMaps::Next(uintptr_t *start, uintptr_t *end,
uintptr_t *offset, char filename[],
size_t filename_size) {
char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
if (current_ >= last) return false;
int consumed = 0;
char flags[10];
int major, minor;
uint64_t inode;
uintptr_t inode;
char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
if (next_line == NULL)
next_line = last;
if (SScanf(current_,
"%llx-%llx %4s %llx %x:%x %lld %n",
"%lx-%lx %4s %lx %x:%x %ld %n",
start, end, flags, offset, &major, &minor,
&inode, &consumed) != 7)
return false;
@ -154,6 +153,50 @@ bool AsanProcMaps::Next(uint64_t *start, uint64_t *end,
return true;
}
struct DlIterateData {
int count;
uintptr_t addr;
uintptr_t offset;
char *filename;
size_t filename_size;
};
static int dl_iterate_phdr_callback(struct dl_phdr_info *info,
size_t size, void *raw_data) {
DlIterateData *data = (DlIterateData*)raw_data;
int count = data->count++;
if (info->dlpi_addr > data->addr)
return 0;
if (count == 0) {
// The first item (the main executable) does not have a so name,
// but we can just read it from /proc/self/exe.
ssize_t path_len = readlink("/proc/self/exe",
data->filename, data->filename_size - 1);
data->filename[path_len] = 0;
} else {
CHECK(info->dlpi_name);
real_strncpy(data->filename, info->dlpi_name, data->filename_size);
}
data->offset = data->addr - info->dlpi_addr;
return 1;
}
// Gets the object name and the offset using dl_iterate_phdr.
bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
char filename[],
size_t filename_size) {
DlIterateData data;
data.count = 0;
data.addr = addr;
data.filename = filename;
data.filename_size = filename_size;
if (dl_iterate_phdr(dl_iterate_phdr_callback, &data)) {
*offset = data.offset;
return true;
}
return false;
}
void AsanThread::SetThreadStackTopAndBottom() {
if (tid() == 0) {
// This is the main thread. Libpthread may not be initialized yet.
@ -162,8 +205,8 @@ void AsanThread::SetThreadStackTopAndBottom() {
// Find the mapping that contains a stack variable.
AsanProcMaps proc_maps;
uint64_t start, end, offset;
uint64_t prev_end = 0;
uintptr_t start, end, offset;
uintptr_t prev_end = 0;
while (proc_maps.Next(&start, &end, &offset, NULL, 0)) {
if ((uintptr_t)&rl < end)
break;

View File

@ -21,9 +21,13 @@ namespace __asan {
class AsanProcMaps {
public:
AsanProcMaps();
bool Next(uint64_t *start, uint64_t *end, uint64_t *offset,
bool Next(uintptr_t *start, uintptr_t *end, uintptr_t *offset,
char filename[], size_t filename_size);
void Reset();
// Gets the object file name and the offset in that object for a given
// address 'addr'. Returns true on success.
bool GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
char filename[], size_t filename_size);
~AsanProcMaps();
private:
#if defined __linux__

View File

@ -133,21 +133,12 @@ void AsanStackTrace::PrintStack(uintptr_t *addr, size_t size) {
for (size_t i = 0; i < size && addr[i]; i++) {
proc_maps.Reset();
uintptr_t pc = addr[i];
uint64_t start, end, offset;
uintptr_t offset;
char filename[4096];
bool found = 0;
int map_idx = 0;
while (proc_maps.Next(&start, &end, &offset,
filename, sizeof(filename))) {
if (pc >= start && pc <= end) {
found = true;
uintptr_t relative_pc = (map_idx == 0) ? pc : (pc - start);
Printf(" #%ld 0x%lx (%s+0x%lx)\n", i, pc, filename, relative_pc);
break;
}
map_idx++;
}
if (!found) {
if (proc_maps.GetObjectNameAndOffset(pc, &offset,
filename, sizeof(filename))) {
Printf(" #%ld 0x%lx (%s+0x%lx)\n", i, pc, filename, offset);
} else {
Printf(" #%ld 0x%lx\n", i, pc);
}
}