blob: d7bb65294ef4963c3255b022e1ccafdd7830d3d0 [file] [log] [blame]
//===-- sanitizer_symbolizer.cc -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is a stub for LLVM-based symbolizer.
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries. See sanitizer.h for details.
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
void AddressInfo::Clear() {
InternalFree(module);
InternalFree(function);
InternalFree(file);
internal_memset(this, 0, sizeof(AddressInfo));
}
static const int kMaxModuleNameLength = 4096;
struct ModuleDesc {
ModuleDesc *next;
uptr start;
uptr end;
uptr offset;
char *full_name;
char *name;
ModuleDesc(uptr _start, uptr _end, uptr _offset, const char *module_name) {
next = 0;
start = _start;
end = _end;
offset = _offset;
full_name = internal_strdup(module_name);
name = internal_strrchr(module_name, '/');
if (name == 0) {
name = full_name;
} else {
name++;
}
}
};
class Symbolizer {
public:
void GetModuleDescriptions() {
ProcessMaps proc_maps;
uptr start, end, offset;
char *module_name = (char*)InternalAlloc(kMaxModuleNameLength);
ModuleDesc *prev_module = 0;
while (proc_maps.Next(&start, &end, &offset, module_name,
kMaxModuleNameLength)) {
void *mem = InternalAlloc(sizeof(ModuleDesc));
ModuleDesc *cur_module = new(mem) ModuleDesc(start, end, offset,
module_name);
if (!prev_module) {
modules_ = cur_module;
} else {
prev_module->next = cur_module;
}
prev_module = cur_module;
}
InternalFree(module_name);
}
uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
if (max_frames == 0)
return 0;
AddressInfo *info = &frames[0];
info->Clear();
info->address = addr;
if (modules_ == 0) {
GetModuleDescriptions();
}
bool first = true;
for (ModuleDesc *module = modules_; module; module = module->next) {
if (addr >= module->start && addr < module->end) {
info->module = internal_strdup(module->full_name);
// Don't subtract 'start' for the first entry:
// * If a binary is compiled w/o -pie, then the first entry in
// process maps is likely the binary itself (all dynamic libs
// are mapped higher in address space). For such a binary,
// instruction offset in binary coincides with the actual
// instruction address in virtual memory (as code section
// is mapped to a fixed memory range).
// * If a binary is compiled with -pie, all the modules are
// mapped high at address space (in particular, higher than
// shadow memory of the tool), so the module can't be the
// first entry.
info->module_offset = (addr - (first ? 0 : module->start)) +
module->offset;
// FIXME: Fill other fields here as well: create debug
// context for a given module and fetch file/line info from it.
info->function = 0;
info->file = 0;
info->line = 0;
info->column = 0;
return 1;
}
first = false;
}
return 0;
}
private:
ModuleDesc *modules_; // List of module descriptions is leaked.
};
static Symbolizer symbolizer;
uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
return symbolizer.SymbolizeCode(address, frames, max_frames);
}
} // namespace __sanitizer