Formerly two were implemented in ImageFile (from file, via syscalls) and one in SymbolLookup (via the debugger interface). Now there's a base class Image and respective derived classes implementing those methods. * Simplified SymbolIterator. * Moved the classes into sub-namespace BPrivate::Debug. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30142 a95241bf-73f2-0310-859d-f6bbb57e9c96
334 lines
6.9 KiB
C++
334 lines
6.9 KiB
C++
/*
|
|
* Copyright 2005-2009, Ingo Weinhold, [email protected].
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
#include "Image.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
|
|
#include <new>
|
|
|
|
#include <runtime_loader.h>
|
|
#include <syscalls.h>
|
|
|
|
|
|
using namespace BPrivate::Debug;
|
|
|
|
|
|
// #pragma mark - Image
|
|
|
|
|
|
Image::Image()
|
|
{
|
|
}
|
|
|
|
|
|
Image::~Image()
|
|
{
|
|
}
|
|
|
|
|
|
// #pragma mark - SymbolTableBasedImage
|
|
|
|
|
|
SymbolTableBasedImage::SymbolTableBasedImage()
|
|
:
|
|
fInfo(),
|
|
fLoadDelta(0),
|
|
fSymbolTable(NULL),
|
|
fStringTable(NULL),
|
|
fSymbolCount(0),
|
|
fStringTableSize(0)
|
|
{
|
|
}
|
|
|
|
|
|
SymbolTableBasedImage::~SymbolTableBasedImage()
|
|
{
|
|
}
|
|
|
|
|
|
image_id
|
|
SymbolTableBasedImage::ID() const
|
|
{
|
|
return fInfo.id;
|
|
}
|
|
|
|
|
|
const char*
|
|
SymbolTableBasedImage::Name() const
|
|
{
|
|
return fInfo.name;
|
|
}
|
|
|
|
|
|
addr_t
|
|
SymbolTableBasedImage::TextAddress() const
|
|
{
|
|
return (addr_t)fInfo.text;
|
|
}
|
|
|
|
|
|
size_t
|
|
SymbolTableBasedImage::TextSize() const
|
|
{
|
|
return fInfo.text_size;
|
|
}
|
|
|
|
|
|
const Elf32_Sym*
|
|
SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress,
|
|
const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
|
|
{
|
|
const Elf32_Sym* symbolFound = NULL;
|
|
const char* symbolName = NULL;
|
|
bool exactMatch = false;
|
|
addr_t deltaFound = ~(addr_t)0;
|
|
|
|
for (int32 i = 0; i < fSymbolCount; i++) {
|
|
const Elf32_Sym* symbol = &fSymbolTable[i];
|
|
|
|
if (symbol->st_value == 0
|
|
|| symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) {
|
|
continue;
|
|
}
|
|
|
|
addr_t symbolAddress = symbol->st_value + fLoadDelta;
|
|
if (symbolAddress > address)
|
|
continue;
|
|
|
|
addr_t symbolDelta = address - symbolAddress;
|
|
if (symbolDelta >= 0 && symbolDelta < symbol->st_size)
|
|
exactMatch = true;
|
|
|
|
if (exactMatch || symbolDelta < deltaFound) {
|
|
deltaFound = symbolDelta;
|
|
symbolFound = symbol;
|
|
symbolName = fStringTable + symbol->st_name;
|
|
|
|
if (exactMatch)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (symbolFound != NULL) {
|
|
if (_baseAddress != NULL)
|
|
*_baseAddress = symbolFound->st_value + fLoadDelta;
|
|
if (_symbolName != NULL)
|
|
*_symbolName = symbolName;
|
|
if (_exactMatch != NULL)
|
|
*_exactMatch = exactMatch;
|
|
if (_symbolNameLen != NULL)
|
|
*_symbolNameLen = _SymbolNameLen(symbolName);
|
|
}
|
|
|
|
return symbolFound;
|
|
}
|
|
|
|
|
|
status_t
|
|
SymbolTableBasedImage::NextSymbol(int32& iterator, const char** _symbolName,
|
|
size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
|
|
int32* _symbolType) const
|
|
{
|
|
while (true) {
|
|
if (++iterator >= fSymbolCount)
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
const Elf32_Sym* symbol = &fSymbolTable[iterator];
|
|
|
|
if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
|
|
&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
|
|
|| symbol->st_value == 0) {
|
|
continue;
|
|
}
|
|
|
|
*_symbolName = fStringTable + symbol->st_name;
|
|
*_symbolNameLen = _SymbolNameLen(*_symbolName);
|
|
*_symbolAddress = symbol->st_value + fLoadDelta;
|
|
*_symbolSize = symbol->st_size;
|
|
*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
|
|
? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
|
|
|
|
return B_OK;
|
|
}
|
|
}
|
|
|
|
|
|
size_t
|
|
SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const
|
|
{
|
|
if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable
|
|
|| (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) {
|
|
return 0;
|
|
}
|
|
|
|
return strnlen(symbolName,
|
|
(addr_t)fStringTable + fStringTableSize - (addr_t)symbolName);
|
|
}
|
|
|
|
|
|
// #pragma mark - ImageFile
|
|
|
|
|
|
ImageFile::ImageFile()
|
|
:
|
|
fFD(-1),
|
|
fFileSize(0),
|
|
fMappedFile((uint8*)MAP_FAILED)
|
|
{
|
|
}
|
|
|
|
|
|
ImageFile::~ImageFile()
|
|
{
|
|
if (fMappedFile != MAP_FAILED)
|
|
munmap(fMappedFile, fFileSize);
|
|
|
|
if (fFD >= 0)
|
|
close(fFD);
|
|
}
|
|
|
|
|
|
status_t
|
|
ImageFile::Init(const image_info& info)
|
|
{
|
|
fInfo = info;
|
|
|
|
// open and stat() the file
|
|
fFD = open(fInfo.name, O_RDONLY);
|
|
if (fFD < 0)
|
|
return errno;
|
|
|
|
struct stat st;
|
|
if (fstat(fFD, &st) < 0)
|
|
return errno;
|
|
|
|
fFileSize = st.st_size;
|
|
if (fFileSize < sizeof(Elf32_Ehdr))
|
|
return B_NOT_AN_EXECUTABLE;
|
|
|
|
// map it
|
|
fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0);
|
|
if (fMappedFile == MAP_FAILED)
|
|
return errno;
|
|
|
|
// examine the elf header
|
|
Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)fMappedFile;
|
|
if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0)
|
|
return B_NOT_AN_EXECUTABLE;
|
|
|
|
if (elfHeader->e_ident[4] != ELFCLASS32)
|
|
return B_NOT_AN_EXECUTABLE;
|
|
|
|
// verify the location of the program headers
|
|
int32 programHeaderCount = elfHeader->e_phnum;
|
|
if (elfHeader->e_phoff < sizeof(Elf32_Ehdr)
|
|
|| elfHeader->e_phentsize < sizeof(Elf32_Phdr)
|
|
|| elfHeader->e_phoff + programHeaderCount * elfHeader->e_phentsize
|
|
> fFileSize) {
|
|
return B_NOT_AN_EXECUTABLE;
|
|
}
|
|
|
|
Elf32_Phdr* programHeaders
|
|
= (Elf32_Phdr*)(fMappedFile + elfHeader->e_phoff);
|
|
|
|
// verify the location of the section headers
|
|
int32 sectionCount = elfHeader->e_shnum;
|
|
if (elfHeader->e_shoff < sizeof(Elf32_Ehdr)
|
|
|| elfHeader->e_shentsize < sizeof(Elf32_Shdr)
|
|
|| elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize
|
|
> fFileSize) {
|
|
return B_NOT_AN_EXECUTABLE;
|
|
}
|
|
|
|
Elf32_Shdr* sectionHeaders
|
|
= (Elf32_Shdr*)(fMappedFile + elfHeader->e_shoff);
|
|
|
|
// find the first segment -- we need its relative offset
|
|
for (int32 i = 0; i < programHeaderCount; i++) {
|
|
Elf32_Phdr* header = (Elf32_Phdr*)
|
|
((uint8*)programHeaders + i * elfHeader->e_phentsize);
|
|
if (header->p_type == PT_LOAD) {
|
|
fLoadDelta = (addr_t)fInfo.text - header->p_vaddr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// find the symbol table
|
|
for (int32 i = 0; i < elfHeader->e_shnum; i++) {
|
|
Elf32_Shdr* sectionHeader = (Elf32_Shdr*)
|
|
((uint8*)sectionHeaders + i * elfHeader->e_shentsize);
|
|
|
|
if (sectionHeader->sh_type == SHT_SYMTAB) {
|
|
Elf32_Shdr& stringHeader = *(Elf32_Shdr*)
|
|
((uint8*)sectionHeaders
|
|
+ sectionHeader->sh_link * elfHeader->e_shentsize);
|
|
|
|
if (stringHeader.sh_type != SHT_STRTAB)
|
|
return B_BAD_DATA;
|
|
|
|
if (sectionHeader->sh_offset + sectionHeader->sh_size > fFileSize
|
|
|| stringHeader.sh_offset + stringHeader.sh_size > fFileSize) {
|
|
return B_BAD_DATA;
|
|
}
|
|
|
|
fSymbolTable = (Elf32_Sym*)(fMappedFile + sectionHeader->sh_offset);
|
|
fStringTable = (char*)(fMappedFile + stringHeader.sh_offset);
|
|
fSymbolCount = sectionHeader->sh_size / sizeof(Elf32_Sym);
|
|
fStringTableSize = stringHeader.sh_size;
|
|
|
|
return B_OK;
|
|
}
|
|
}
|
|
|
|
return B_BAD_DATA;
|
|
}
|
|
|
|
|
|
// #pragma mark - KernelImage
|
|
|
|
|
|
KernelImage::KernelImage()
|
|
{
|
|
}
|
|
|
|
|
|
KernelImage::~KernelImage()
|
|
{
|
|
delete[] fSymbolTable;
|
|
delete[] fStringTable;
|
|
}
|
|
|
|
|
|
status_t
|
|
KernelImage::Init(const image_info& info)
|
|
{
|
|
fInfo = info;
|
|
|
|
// get the table sizes
|
|
fSymbolCount = 0;
|
|
fStringTableSize = 0;
|
|
status_t error = _kern_read_kernel_image_symbols(fInfo.id,
|
|
NULL, &fSymbolCount, NULL, &fStringTableSize, NULL);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// allocate the tables
|
|
fSymbolTable = new(std::nothrow) Elf32_Sym[fSymbolCount];
|
|
fStringTable = new(std::nothrow) char[fStringTableSize];
|
|
if (fSymbolTable == NULL || fStringTable == NULL)
|
|
return B_NO_MEMORY;
|
|
|
|
// get the info
|
|
return _kern_read_kernel_image_symbols(fInfo.id,
|
|
fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize,
|
|
&fLoadDelta);
|
|
}
|