1268893Sian/*- 2268893Sian * Copyright (c) 2014 Ian Lepore <ian@freebsd.org> 3268893Sian * All rights reserved. 4268893Sian * 5268893Sian * Redistribution and use in source and binary forms, with or without 6268893Sian * modification, are permitted provided that the following conditions 7268893Sian * are met: 8268893Sian * 1. Redistributions of source code must retain the above copyright 9268893Sian * notice, this list of conditions and the following disclaimer. 10268893Sian * 2. Redistributions in binary form must reproduce the above copyright 11268893Sian * notice, this list of conditions and the following disclaimer in the 12268893Sian * documentation and/or other materials provided with the distribution. 13268893Sian * 14268893Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15268893Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16268893Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17268893Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18268893Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19268893Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20268893Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21268893Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22268893Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23268893Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24268893Sian * SUCH DAMAGE. 25268893Sian */ 26268893Sian 27268893Sian#include <sys/cdefs.h> 28268893Sian__FBSDID("$FreeBSD$"); 29268893Sian 30268893Sian#include <sys/types.h> 31268893Sian#include <machine/elf.h> 32268893Sian#include <link.h> 33268893Sian#include <stddef.h> 34268893Sian 35268893Sian/* 36268893Sian * ARM EABI unwind helper. 37268893Sian * 38268893Sian * This finds the exidx section address and size associated with a given code 39268893Sian * address. There are separate implementations for static and dynamic code. 40268893Sian * 41268893Sian * GCC expects this function to exist as __gnu_Unwind_Find_exidx(), clang and 42268893Sian * BSD tools expect it to be dl_unwind_find_exidx(). Both have the same API, so 43268893Sian * we set up an alias for GCC. 44268893Sian */ 45268893Sian__strong_reference(dl_unwind_find_exidx, __gnu_Unwind_Find_exidx); 46268893Sian 47268893Sian/* 48268893Sian * Each entry in the exidx section is a pair of 32-bit words. We don't 49268893Sian * interpret the contents of the entries here; this typedef is just a local 50268893Sian * convenience for using sizeof() and doing pointer math. 51268893Sian */ 52268893Siantypedef struct exidx_entry { 53268893Sian uint32_t data[2]; 54268893Sian} exidx_entry; 55268893Sian 56268893Sian#ifdef __PIC__ 57268893Sian 58268893Sian/* 59268893Sian * Unwind helper for dynamically linked code. 60268893Sian * 61268893Sian * This finds the shared object that contains the given address, and returns the 62268893Sian * address of the exidx section in that shared object along with the number of 63268893Sian * entries in that section, or NULL if it wasn't found. 64268893Sian */ 65268893Sianvoid * 66268893Siandl_unwind_find_exidx(const void *pc, int *pcount) 67268893Sian{ 68268893Sian const Elf_Phdr *hdr; 69268893Sian struct dl_phdr_info info; 70268893Sian int i; 71268893Sian 72268893Sian if (_rtld_addr_phdr(pc, &info)) { 73268893Sian hdr = info.dlpi_phdr; 74268893Sian for (i = 0; i < info.dlpi_phnum; i++, hdr++) { 75268893Sian if (hdr->p_type == PT_ARM_EXIDX) { 76268893Sian *pcount = hdr->p_memsz / sizeof(exidx_entry); 77268893Sian return ((void *)(info.dlpi_addr + hdr->p_vaddr)); 78268893Sian } 79268893Sian } 80268893Sian } 81268893Sian return (NULL); 82268893Sian} 83268893Sian 84268893Sian#else /* !__PIC__ */ 85268893Sian 86268893Sian/* 87268893Sian * Unwind helper for statically linked code. 88268893Sian * 89268893Sian * In a statically linked program, the linker populates a pair of symbols with 90268893Sian * the addresses of the start and end of the exidx table, so returning the 91268893Sian * address and count of elements is pretty straighforward. 92268893Sian */ 93268893Sianvoid * 94268893Siandl_unwind_find_exidx(const void *pc, int *pcount) 95268893Sian{ 96268893Sian extern struct exidx_entry __exidx_start; 97268893Sian extern struct exidx_entry __exidx_end; 98268893Sian 99268893Sian *pcount = (int)(&__exidx_end - &__exidx_start); 100268893Sian return (&__exidx_start); 101268893Sian} 102268893Sian 103268893Sian#endif /* __PIC__ */ 104268893Sian 105