| 1 | #define _GNU_SOURCE |
| 2 | #include <link.h> |
| 3 | #include <stdint.h> |
| 4 | |
| 5 | struct find_exidx_data { |
| 6 | 	uintptr_t pc, exidx_start; |
| 7 | 	int exidx_len; |
| 8 | }; |
| 9 | |
| 10 | static int find_exidx(struct dl_phdr_info *info, size_t size, void *ptr) |
| 11 | { |
| 12 | 	struct find_exidx_data *data = ptr; |
| 13 | 	const ElfW(Phdr) *phdr = info->dlpi_phdr; |
| 14 | 	uintptr_t addr, exidx_start = 0; |
| 15 | 	int i, match = 0, exidx_len = 0; |
| 16 | |
| 17 | 	for (i = info->dlpi_phnum; i > 0; i--, phdr++) { |
| 18 | 		addr = info->dlpi_addr + phdr->p_vaddr; |
| 19 | 		switch (phdr->p_type) { |
| 20 | 		case PT_LOAD: |
| 21 | 			match |= data->pc >= addr && data->pc < addr + phdr->p_memsz; |
| 22 | 			break; |
| 23 | 		case PT_ARM_EXIDX: |
| 24 | 			exidx_start = addr; |
| 25 | 			exidx_len = phdr->p_memsz; |
| 26 | 			break; |
| 27 | 		} |
| 28 | 	} |
| 29 | 	data->exidx_start = exidx_start; |
| 30 | 	data->exidx_len = exidx_len; |
| 31 | 	return match; |
| 32 | } |
| 33 | |
| 34 | uintptr_t __gnu_Unwind_Find_exidx(uintptr_t pc, int *pcount) |
| 35 | { |
| 36 | 	struct find_exidx_data data; |
| 37 | 	data.pc = pc; |
| 38 | 	if (dl_iterate_phdr(find_exidx, &data) <= 0) |
| 39 | 		return 0; |
| 40 | 	*pcount = data.exidx_len / 8; |
| 41 | 	return data.exidx_start; |
| 42 | } |