mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-01-08 18:33:42 +01:00
ARM extbl cleanup.
Move code that does not necessarily need to reside in the ex_tables.h header file into ex_tables.c. Add comments and remove unused code. Signed-off-by: Ken Werner <ken.werner@linaro.org>
This commit is contained in:
parent
6e25c11505
commit
fb325c895e
2 changed files with 42 additions and 187 deletions
|
@ -41,7 +41,6 @@ struct arm_exidx_table {
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
typedef enum arm_exbuf_cmd {
|
||||
ARM_EXIDX_CMD_FINISH,
|
||||
ARM_EXIDX_CMD_DATA_PUSH,
|
||||
|
@ -55,47 +54,21 @@ typedef enum arm_exbuf_cmd {
|
|||
ARM_EXIDX_CMD_REFUSED,
|
||||
} arm_exbuf_cmd_t;
|
||||
|
||||
enum arm_exbuf_cmd_flags {
|
||||
ARM_EXIDX_VFP_SHIFT_16 = 1 << 16,
|
||||
ARM_EXIDX_VFP_DOUBLE = 1 << 17,
|
||||
};
|
||||
|
||||
#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f)
|
||||
#define ARM_EXBUF_COUNT(x) ((x) & 0x0f)
|
||||
#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
|
||||
|
||||
struct arm_exbuf_data
|
||||
{
|
||||
arm_exbuf_cmd_t cmd;
|
||||
uint32_t data;
|
||||
};
|
||||
|
||||
static inline void *
|
||||
prel31_to_addr (void *addr)
|
||||
{
|
||||
uint32_t offset = ((long)*(uint32_t *)addr << 1) >> 1;
|
||||
return (char *)addr + offset;
|
||||
}
|
||||
|
||||
int arm_exidx_init_local (const char *appname);
|
||||
|
||||
int arm_exidx_table_add (const char *name,
|
||||
struct arm_exidx_entry *start, struct arm_exidx_entry *end);
|
||||
int arm_exidx_table_add (const char *name, struct arm_exidx_entry *start,
|
||||
struct arm_exidx_entry *end);
|
||||
struct arm_exidx_table *arm_exidx_table_find (void *pc);
|
||||
struct arm_exidx_entry *arm_exidx_table_lookup (
|
||||
struct arm_exidx_table *table, void *pc);
|
||||
|
||||
void arm_exidx_section_find (struct elf_image *ei,
|
||||
Elf_W (Shdr) **exidx, Elf_W (Shdr) **extbl);
|
||||
int arm_exidx_entry_lookup (struct elf_image *ei,
|
||||
Elf_W (Shdr) *exidx, uint32_t ip);
|
||||
int arm_exidx_entry_extract (struct elf_image *ei,
|
||||
Elf_W (Shdr) *exidx, Elf_W (Shdr) *extbl,
|
||||
unsigned i, uint8_t *buf);
|
||||
struct arm_exidx_entry *arm_exidx_table_lookup (struct arm_exidx_table *table,
|
||||
void *pc);
|
||||
int arm_exidx_extract (struct arm_exidx_entry *entry, uint8_t *buf);
|
||||
|
||||
int arm_exidx_decode (const uint8_t *buf, uint8_t len,
|
||||
struct dwarf_cursor *c);
|
||||
int arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c);
|
||||
int arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c);
|
||||
|
||||
#endif // ARM_EX_TABLES_H
|
||||
|
|
|
@ -24,11 +24,20 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|||
|
||||
#include "libunwind_i.h"
|
||||
|
||||
#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f)
|
||||
#define ARM_EXBUF_COUNT(x) ((x) & 0x0f)
|
||||
#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
|
||||
|
||||
#define ARM_EXIDX_CANT_UNWIND 0x00000001
|
||||
#define ARM_EXIDX_COMPACT 0x80000000
|
||||
|
||||
#define ARM_EXTBL_OP_FINISH 0xb0
|
||||
|
||||
enum arm_exbuf_cmd_flags {
|
||||
ARM_EXIDX_VFP_SHIFT_16 = 1 << 16,
|
||||
ARM_EXIDX_VFP_DOUBLE = 1 << 17,
|
||||
};
|
||||
|
||||
#ifdef ARM_EXIDX_TABLE_MALLOC
|
||||
static struct arm_exidx_table *arm_exidx_table_list;
|
||||
#else
|
||||
|
@ -38,6 +47,19 @@ static unsigned arm_exidx_table_count = 0;
|
|||
#endif
|
||||
static const char *arm_exidx_appname;
|
||||
|
||||
static inline uint32_t
|
||||
prel31_read (uint32_t prel31)
|
||||
{
|
||||
return ((int32_t)prel31 << 1) >> 1;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
prel31_to_addr (void *addr)
|
||||
{
|
||||
uint32_t offset = ((long)*(uint32_t *)addr << 1) >> 1;
|
||||
return (char *)addr + offset;
|
||||
}
|
||||
|
||||
static void
|
||||
arm_exidx_table_reset_all (void)
|
||||
{
|
||||
|
@ -79,7 +101,7 @@ arm_exidx_table_add (const char *name,
|
|||
}
|
||||
|
||||
/**
|
||||
* Located the appropriate unwind table
|
||||
* Locate the appropriate unwind table from the given PC.
|
||||
*/
|
||||
HIDDEN struct arm_exidx_table *
|
||||
arm_exidx_table_find (void *pc)
|
||||
|
@ -100,7 +122,9 @@ arm_exidx_table_find (void *pc)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Based on Linux arm/arm/kernel/unwind.c:search_index() */
|
||||
/**
|
||||
* Finds the corresponding arm_exidx_entry from a given index table and PC.
|
||||
*/
|
||||
HIDDEN struct arm_exidx_entry *
|
||||
arm_exidx_table_lookup (struct arm_exidx_table *table, void *pc)
|
||||
{
|
||||
|
@ -190,7 +214,10 @@ arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c)
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes the given unwind instructions into arm_exbuf_data and calls
|
||||
* arm_exidx_apply_cmd that applies the command onto the dwarf_cursor.
|
||||
*/
|
||||
HIDDEN int
|
||||
arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c)
|
||||
{
|
||||
|
@ -323,59 +350,11 @@ arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
prel31_read (uint32_t prel31)
|
||||
{
|
||||
return ((int32_t)prel31 << 1) >> 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the index of the table entry for the given address
|
||||
* using a binary search.
|
||||
* @returns The table index (or -1 if not found).
|
||||
* Reads the given entry and extracts the unwind instructions into buf.
|
||||
* Returns the number of the extracted unwind insns or -UNW_ESTOPUNWIND
|
||||
* if the special bit pattern ARM_EXIDX_CANT_UNWIND (0x1) was found.
|
||||
*/
|
||||
HIDDEN int
|
||||
arm_exidx_lookup (uint32_t *exidx_data, uint32_t exidx_size, uint32_t ip)
|
||||
{
|
||||
unsigned lo = 0, hi = exidx_size / 8;
|
||||
while (lo < hi)
|
||||
{
|
||||
unsigned mid = (lo + hi) / 2;
|
||||
uint32_t base = (uint32_t)(exidx_data + mid * 2);
|
||||
uint32_t addr = base + prel31_read (exidx_data[mid * 2]);
|
||||
if (ip < addr)
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid + 1;
|
||||
}
|
||||
return hi - 1;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
arm_exidx_entry_lookup (struct elf_image *ei,
|
||||
Elf_W (Shdr) *exidx, uint32_t ip)
|
||||
{
|
||||
#if 1
|
||||
return arm_exidx_lookup (ei->image + exidx->sh_offset, exidx->sh_size, ip);
|
||||
#else
|
||||
unsigned n_entries = exidx->sh_size / 8;
|
||||
uint32_t *exidx_data = ei->image + exidx->sh_offset;
|
||||
unsigned lo = 0, hi = n_entries;
|
||||
|
||||
while (lo < hi)
|
||||
{
|
||||
unsigned mid = (lo + hi) / 2;
|
||||
uint32_t base = exidx->sh_addr + mid * 8;
|
||||
uint32_t addr = base + prel31_read (exidx_data[mid * 2]);
|
||||
if (ip < addr)
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid + 1;
|
||||
}
|
||||
return hi - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
arm_exidx_extract (struct arm_exidx_entry *entry, uint8_t *buf)
|
||||
{
|
||||
|
@ -417,7 +396,7 @@ arm_exidx_extract (struct arm_exidx_entry *entry, uint8_t *buf)
|
|||
else
|
||||
{
|
||||
void *pers = prel31_to_addr (extbl_data);
|
||||
Debug (2, "%p Personality routine: %8.8x\n", addr, pers);
|
||||
Debug (2, "%p Personality routine: %8p\n", addr, pers);
|
||||
n_table_words = extbl_data[1] >> 24;
|
||||
buf[nbuf++] = extbl_data[1] >> 16;
|
||||
buf[nbuf++] = extbl_data[1] >> 8;
|
||||
|
@ -442,105 +421,8 @@ arm_exidx_extract (struct arm_exidx_entry *entry, uint8_t *buf)
|
|||
return nbuf;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
arm_exidx_entry_extract (struct elf_image *ei,
|
||||
Elf_W (Shdr) *exidx, Elf_W (Shdr) *extbl,
|
||||
unsigned i, uint8_t *buf)
|
||||
{
|
||||
int nbuf = 0;
|
||||
uint32_t *exidx_data = ei->image + exidx->sh_offset;
|
||||
uint32_t base = exidx->sh_addr + i * 8;
|
||||
uint32_t one = base + prel31_read (exidx_data[i * 2]);
|
||||
|
||||
uint32_t two = exidx_data[i * 2 + 1];
|
||||
if (two == ARM_EXIDX_CANT_UNWIND)
|
||||
printf ("0x1 [can't unwind]\n");
|
||||
else if (two & ARM_EXIDX_COMPACT)
|
||||
{
|
||||
printf ("compact model %d [%8.8x]\n", (two >> 24) & 0x7f, two);
|
||||
buf[nbuf++] = two >> 16;
|
||||
buf[nbuf++] = two >> 8;
|
||||
buf[nbuf++] = two;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (NULL != extbl);
|
||||
two = base + prel31_read (two) + 4;
|
||||
uint32_t *extbl_data = ei->image + extbl->sh_offset
|
||||
+ (two - extbl->sh_addr);
|
||||
two = extbl_data[0];
|
||||
unsigned int n_table_words = 0;
|
||||
if (two & ARM_EXIDX_COMPACT)
|
||||
{
|
||||
int pers = (two >> 24) & 0x0f;
|
||||
printf ("compact model %d [%8.8x]\n", pers, two);
|
||||
if (pers == 1 || pers == 2)
|
||||
{
|
||||
n_table_words = (two >> 16) & 0xff;
|
||||
extbl_data += 1;
|
||||
}
|
||||
else
|
||||
buf[nbuf++] = two >> 16;
|
||||
buf[nbuf++] = two >> 8;
|
||||
buf[nbuf++] = two;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t pers = prel31_read (extbl_data[0]);
|
||||
pers += extbl->sh_addr + i * 8 + 4;
|
||||
printf ("Personality routine: %8.8x\n", pers);
|
||||
n_table_words = extbl_data[1] >> 24;
|
||||
buf[nbuf++] = extbl_data[1] >> 16;
|
||||
buf[nbuf++] = extbl_data[1] >> 8;
|
||||
buf[nbuf++] = extbl_data[1];
|
||||
extbl_data += 2;
|
||||
}
|
||||
assert (n_table_words <= 5);
|
||||
unsigned j;
|
||||
for (j = 0; j < n_table_words; j++)
|
||||
{
|
||||
two = *extbl_data++;
|
||||
buf[nbuf++] = two >> 24;
|
||||
buf[nbuf++] = two >> 16;
|
||||
buf[nbuf++] = two >> 8;
|
||||
buf[nbuf++] = two >> 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (nbuf > 0 && buf[nbuf - 1] != ARM_EXTBL_OP_FINISH)
|
||||
buf[nbuf++] = ARM_EXTBL_OP_FINISH;
|
||||
|
||||
return nbuf;
|
||||
}
|
||||
|
||||
HIDDEN void
|
||||
arm_exidx_section_find (struct elf_image *ei,
|
||||
Elf_W (Shdr) **exidx, Elf_W (Shdr) **extbl)
|
||||
{
|
||||
Elf_W (Ehdr) *ehdr = ei->image;
|
||||
Elf_W (Shdr) *shdr;
|
||||
shdr = (Elf_W (Shdr) *)((char *)ei->image + ehdr->e_shoff);
|
||||
char *names = (char *)ei->image + shdr[ehdr->e_shstrndx].sh_offset;
|
||||
int i = 0;
|
||||
for (i = 0; i < ehdr->e_shnum; i++)
|
||||
{
|
||||
char *name = names + shdr[i].sh_name;
|
||||
switch (shdr[i].sh_type)
|
||||
{
|
||||
case SHT_ARM_EXIDX:
|
||||
*exidx = shdr + i;
|
||||
break;
|
||||
case SHT_PROGBITS:
|
||||
if (strcmp (name, ".ARM.extab") != 0)
|
||||
break;
|
||||
*extbl = shdr + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to dl_iterate_phr to find each library's unwind table.
|
||||
* Callback to dl_iterate_phdr to find the unwind tables.
|
||||
* If found, calls arm_exidx_table_add to remember it for later lookups.
|
||||
*/
|
||||
static int
|
||||
|
@ -570,13 +452,13 @@ arm_exidx_init_local_cb (struct dl_phdr_info *info, size_t size, void *data)
|
|||
}
|
||||
|
||||
/**
|
||||
* Must be called for local process lookups.
|
||||
* Traverse the program headers of the executable and its loaded
|
||||
* shared objects to collect the unwind tables.
|
||||
*/
|
||||
HIDDEN int
|
||||
arm_exidx_init_local (const char *appname)
|
||||
{
|
||||
arm_exidx_appname = appname;
|
||||
// traverse all libraries and find unwind tables
|
||||
arm_exidx_table_reset_all();
|
||||
return dl_iterate_phdr (&arm_exidx_init_local_cb, NULL);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue