/** * \brief GCC excption handling support * \author Sebastian Sumpf * \date 2015-03-12 */ /* * Copyright (C) 2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #include using namespace Linker; /********* ** x86 ** *********/ /** * "Walk through shared objects" support, see man page of 'dl_iterate_phdr' */ struct Phdr_info { Elf::Addr addr; /* module relocation base */ char const *name; /* module name */ Elf::Phdr const *phdr; /* pointer to module's phdr */ Elf::Half phnum; /* number of entries in phdr */ }; extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, Genode::size_t size, void *data), void *data) { int err = 0; Phdr_info info; Genode::Lock::Guard guard(Object::lock()); for (Object *e = obj_list_head();e; e = e->next_obj()) { info.addr = e->reloc_base(); info.name = e->name(); info.phdr = e->file()->phdr.phdr; info.phnum = e->file()->phdr.count; if (verbose_exception) PDBG("%s reloc " EFMT, e->name(), e->reloc_base()); if ((err = callback(&info, sizeof(Phdr_info), data))) break; } return err; } /********* ** ARM ** *********/ /** * Return EXIDX program header */ static Elf::Phdr const *phdr_exidx(File const *file) { for (unsigned i = 0; i < file->elf_phdr_count(); i++) { Elf::Phdr const *ph = file->elf_phdr(i); if (ph->p_type == PT_ARM_EXIDX) return ph; } return 0; } /** * Find ELF and exceptions table segment that that is located under 'pc', * address of exception table and number of entries 'pcount' */ extern "C" unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount) { /* size of exception table entries */ enum { EXIDX_ENTRY_SIZE = 8 }; *pcount = 0; /* * Since this function may be called before the main function, load linker's * program header now */ load_linker_phdr(); for (Object *e = obj_list_head(); e; e = e->next_obj()) { /* address of first PT_LOAD header */ Genode::addr_t base = e->reloc_base() + e->file()->start; /* is the 'pc' somewhere within this ELF image */ if ((pc < base) || (pc >= base + e->file()->size)) continue; /* retrieve PHDR of exception-table segment */ Elf::Phdr const *exidx = phdr_exidx(e->file()); if (!exidx) continue; *pcount = exidx->p_memsz / EXIDX_ENTRY_SIZE; return exidx->p_vaddr + e->reloc_base(); } return 0; }