Files
haiku-beta6/src/kits/debug/Image.cpp
T
Ingo Weinhold 73677f785a * Some refactoring: There are three ways to access the symbols of an image.
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
2009-04-12 23:57:35 +00:00

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);
}