2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Special handling for the ARM architecture
|
|
|
|
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
|
|
|
|
* \date 2010-07-05
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2012-01-03 15:35:05 +01:00
|
|
|
* Copyright (C) 2010-2012 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
#include "rtld.h"
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <machine/elf.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "dl_extensions.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cbass: Added EHABI exception table section type
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#ifndef PT_ARM_EXIDX
|
|
|
|
#define PT_ARM_EXIDX 0x70000001
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern Obj_Entry *obj_list;
|
|
|
|
|
|
|
|
typedef struct exidx_t {
|
|
|
|
unsigned long base;
|
|
|
|
int count;
|
|
|
|
} exidx_t;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan for exception index section and parse information
|
|
|
|
*/
|
|
|
|
static void platform_section(Elf_Phdr *phdr, void **priv)
|
|
|
|
{
|
|
|
|
exidx_t *exidx;
|
|
|
|
switch (phdr->p_type) {
|
|
|
|
|
|
|
|
case PT_ARM_EXIDX:
|
|
|
|
exidx = (exidx_t *)xmalloc(sizeof(exidx_t));
|
|
|
|
exidx->base = phdr->p_vaddr;
|
|
|
|
/* Each exception table entry is 8 Byte */
|
|
|
|
exidx->count = phdr->p_memsz / 8;
|
|
|
|
*priv = (void *)exidx;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read program header and setup exception information
|
|
|
|
*/
|
|
|
|
static void find_exidx(Obj_Entry *obj)
|
|
|
|
{
|
|
|
|
char buf[PAGE_SIZE];
|
|
|
|
|
|
|
|
int fd = open(obj->path, 0);
|
|
|
|
read(fd, buf, PAGE_SIZE);
|
|
|
|
|
|
|
|
Elf_Ehdr *ehdr = (Elf_Ehdr *)buf;
|
|
|
|
Elf_Phdr *ph_table = (Elf_Phdr *)(buf + ehdr->e_phoff);
|
|
|
|
|
|
|
|
unsigned i;
|
|
|
|
size_t start = ~0;
|
|
|
|
size_t end = ~0;
|
|
|
|
|
|
|
|
for (i = 0; i < ehdr->e_phnum; i++) {
|
|
|
|
platform_section(&ph_table[i], &obj->priv);
|
|
|
|
|
|
|
|
/* determine map size */
|
|
|
|
if (ph_table[i].p_type == PT_LOAD) {
|
|
|
|
|
|
|
|
if (start == ~0)
|
|
|
|
start = trunc_page(ph_table[i].p_vaddr);
|
|
|
|
|
|
|
|
end = round_page(ph_table[i].p_vaddr + ph_table[i].p_memsz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* since linker is not setup by map_object map info is not set correctly */
|
|
|
|
if (obj->rtld) {
|
|
|
|
obj->vaddrbase = (Elf_Addr)obj->mapbase;
|
|
|
|
obj->mapsize = end - start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find exceptions index that matches given IP (PC)
|
|
|
|
*/
|
|
|
|
unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount)
|
|
|
|
{
|
|
|
|
Obj_Entry *obj;
|
|
|
|
extern Obj_Entry obj_rtld;
|
|
|
|
caddr_t addr = (caddr_t)pc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Used during startup before ldso's main function is called and therefore
|
|
|
|
* obj_list has not been initialized
|
|
|
|
*/
|
|
|
|
Obj_Entry *list = obj_list;
|
|
|
|
if (!list)
|
|
|
|
list = &obj_rtld;
|
|
|
|
|
|
|
|
for (obj = list; obj != NULL; obj = obj->next) {
|
|
|
|
|
|
|
|
/* initialize exceptions for object */
|
|
|
|
if (!obj->priv)
|
|
|
|
find_exidx(obj);
|
|
|
|
|
|
|
|
if (addr >= obj->mapbase && addr < obj->mapbase + obj->mapsize && obj->priv) {
|
|
|
|
*pcount = ((exidx_t *)obj->priv)->count;
|
|
|
|
return (unsigned long)(((exidx_t *)obj->priv)->base + obj->mapbase - obj->vaddrbase);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*pcount = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|