/*
- * drivers/misc/tegra-profiler/exh_tables.c
+ * drivers/misc/tegra-profiler/eh_unwind.c
*
* Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
*
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-/*#pragma message("--- version header: remove for static version ---")*/
-#include <linux/version.h>
-
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/slab.h>
static inline unsigned long
ex_addr_to_mmap_addr(unsigned long addr,
struct ex_region_info *ri,
- int exidx)
+ int sec_type)
{
unsigned long offset;
- struct extab_info *ei;
+ struct extab_info *ti;
- ei = exidx ? &ri->tabs.exidx : &ri->tabs.extab;
- offset = addr - ei->addr;
+ ti = &ri->ex_sec[sec_type];
+ offset = addr - ti->addr;
- return ei->mmap_offset + offset + (unsigned long)ri->mmap->data;
+ return ti->mmap_offset + offset + (unsigned long)ri->mmap->data;
}
static inline unsigned long
mmap_addr_to_ex_addr(unsigned long addr,
struct ex_region_info *ri,
- int exidx)
+ int sec_type)
{
unsigned long offset;
- struct extab_info *ei;
+ struct extab_info *ti;
- ei = exidx ? &ri->tabs.exidx : &ri->tabs.extab;
- offset = addr - ei->mmap_offset - (unsigned long)ri->mmap->data;
+ ti = &ri->ex_sec[sec_type];
+ offset = addr - ti->mmap_offset - (unsigned long)ri->mmap->data;
- return ei->addr + offset;
+ return ti->addr + offset;
}
static inline u32
static unsigned long
mmap_prel31_to_addr(const u32 *ptr, struct ex_region_info *ri,
- int is_src_exidx, int is_dst_exidx, int to_mmap)
+ int src_type, int dst_type, int to_mmap)
{
+ s32 offset;
u32 value, addr;
unsigned long addr_res;
- s32 offset;
- struct extab_info *ei_src, *ei_dst;
-
- ei_src = is_src_exidx ? &ri->tabs.exidx : &ri->tabs.extab;
- ei_dst = is_dst_exidx ? &ri->tabs.exidx : &ri->tabs.extab;
value = *ptr;
offset = (((s32)value) << 1) >> 1;
- addr = mmap_addr_to_ex_addr((unsigned long)ptr, ri, is_src_exidx);
+ addr = mmap_addr_to_ex_addr((unsigned long)ptr, ri, src_type);
addr += offset;
addr_res = addr;
if (to_mmap)
- addr_res = ex_addr_to_mmap_addr(addr_res, ri, is_dst_exidx);
+ addr_res = ex_addr_to_mmap_addr(addr_res, ri, dst_type);
return addr_res;
}
}
static struct ex_region_info *
-search_ex_region(struct ex_region_info *array,
- unsigned long size,
- unsigned long key)
+__search_ex_region(struct ex_region_info *array,
+ unsigned long size,
+ unsigned long key)
{
unsigned int i_min, i_max, mid;
return NULL;
}
-long quadd_search_ex_region(unsigned long key, struct ex_region_info *ri)
+static long
+search_ex_region(unsigned long key, struct ex_region_info *ri)
{
struct regions_data *rd;
struct ex_region_info *ri_p = NULL;
if (!rd)
goto out;
- ri_p = search_ex_region(rd->entries, rd->curr_nr, key);
+ ri_p = __search_ex_region(rd->entries, rd->curr_nr, key);
if (ri_p)
memcpy(ri, ri_p, sizeof(*ri));
return ri_p ? 0 : -ENOENT;
}
+static long
+get_extabs_ehabi(unsigned long key, struct ex_region_info *ri)
+{
+ long err;
+ struct extab_info *ti_extab, *ti_exidx;
+
+ err = search_ex_region(key, ri);
+ if (err < 0)
+ return err;
+
+ ti_extab = &ri->ex_sec[QUADD_SEC_TYPE_EXTAB];
+ ti_exidx = &ri->ex_sec[QUADD_SEC_TYPE_EXIDX];
+
+ return (ti_extab->length && ti_exidx->length) ? 0 : -ENOENT;
+}
+
+long
+quadd_get_extabs_ehframe(unsigned long key, struct ex_region_info *ri)
+{
+ long err;
+ struct extab_info *ti_ehfr, *ti_ehfr_hdr;
+
+ err = search_ex_region(key, ri);
+ if (err < 0)
+ return err;
+
+ ti_ehfr = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME];
+ ti_ehfr_hdr = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+
+ return (ti_ehfr->length && ti_ehfr_hdr->length) ? 0 : -ENOENT;
+}
+
static struct regions_data *rd_alloc(unsigned long size)
{
struct regions_data *rd;
rd_free(rd);
}
-int quadd_unwind_set_extab(struct quadd_extables *extabs,
+int quadd_unwind_set_extab(struct quadd_sections *extabs,
struct quadd_mmap_area *mmap)
{
- int err = 0;
+ int i, err = 0;
unsigned long nr_entries, nr_added, new_size;
struct ex_region_info ri_entry;
struct extab_info *ti;
ri_entry.tf_start = 0;
ri_entry.tf_end = 0;
- ti = &ri_entry.tabs.exidx;
- ti->addr = extabs->exidx.addr;
- ti->length = extabs->exidx.length;
- ti->mmap_offset = extabs->reserved[QUADD_EXT_IDX_EXIDX_OFFSET];
- ctx.ex_tables_size += ti->length;
+ for (i = 0; i < QUADD_SEC_TYPE_MAX; i++) {
+ struct quadd_sec_info *si = &extabs->sec[i];
- ti = &ri_entry.tabs.extab;
- ti->addr = extabs->extab.addr;
- ti->length = extabs->extab.length;
- ti->mmap_offset = extabs->reserved[QUADD_EXT_IDX_EXTAB_OFFSET];
- ctx.ex_tables_size += ti->length;
+ ti = &ri_entry.ex_sec[i];
+
+ if (!si->addr) {
+ ti->addr = 0;
+ ti->length = 0;
+ ti->mmap_offset = 0;
+
+ continue;
+ }
+
+ ti->addr = si->addr;
+ ti->length = si->length;
+ ti->mmap_offset = si->mmap_offset;
+ }
nr_added = add_ex_region(rd_new, &ri_entry);
if (nr_added == 0)
rd_new->curr_nr = nr_entries;
- ri = search_ex_region(rd_new->entries, nr_entries, vm_start);
+ ri = __search_ex_region(rd_new->entries, nr_entries, vm_start);
if (!ri)
goto error_free;
static const struct unwind_idx *
unwind_find_idx(struct ex_region_info *ri, u32 addr)
{
- unsigned long length;
u32 value;
+ unsigned long length;
+ struct extab_info *ti;
struct unwind_idx *start;
struct unwind_idx *stop;
struct unwind_idx *mid = NULL;
- length = ri->tabs.exidx.length / sizeof(*start);
+
+ ti = &ri->ex_sec[QUADD_SEC_TYPE_EXIDX];
+
+ length = ti->length / sizeof(*start);
if (unlikely(!length))
return NULL;
- start = (struct unwind_idx *)((char *)ri->mmap->data +
- ri->tabs.exidx.mmap_offset);
+ start = (struct unwind_idx *)((char *)ri->mmap->data + ti->mmap_offset);
stop = start + length - 1;
- value = (u32)mmap_prel31_to_addr(&start->addr_offset, ri, 1, 0, 0);
+ value = (u32)mmap_prel31_to_addr(&start->addr_offset, ri,
+ QUADD_SEC_TYPE_EXIDX,
+ QUADD_SEC_TYPE_EXTAB, 0);
if (addr < value)
return NULL;
- value = (u32)mmap_prel31_to_addr(&stop->addr_offset, ri, 1, 0, 0);
+ value = (u32)mmap_prel31_to_addr(&stop->addr_offset, ri,
+ QUADD_SEC_TYPE_EXIDX,
+ QUADD_SEC_TYPE_EXTAB, 0);
if (addr >= value)
return NULL;
while (start < stop - 1) {
mid = start + ((stop - start) >> 1);
- value = (u32)mmap_prel31_to_addr(&mid->addr_offset,
- ri, 1, 0, 0);
+ value = (u32)mmap_prel31_to_addr(&mid->addr_offset, ri,
+ QUADD_SEC_TYPE_EXIDX,
+ QUADD_SEC_TYPE_EXTAB, 0);
if (addr < value)
stop = mid;
} else if ((val & 0x80000000) == 0) {
/* prel31 to the unwind table */
ctrl.insn = (u32 *)(unsigned long)
- mmap_prel31_to_addr(&idx->insn, ri, 1, 0, 1);
+ mmap_prel31_to_addr(&idx->insn, ri,
+ QUADD_SEC_TYPE_EXIDX,
+ QUADD_SEC_TYPE_EXTAB, 1);
if (!ctrl.insn)
return -QUADD_URC_EACCESS;
} else if ((val & 0xff000000) == 0x80000000) {
while (1) {
long err;
int nr_added;
+ struct extab_info *ti;
unsigned long where = frame->pc;
struct vm_area_struct *vma_pc;
struct mm_struct *mm = task->mm;
if (!vma_pc)
break;
- if (!is_vma_addr(ri->tabs.exidx.addr, vma_pc, sizeof(u32))) {
- err = quadd_search_ex_region(vma_pc->vm_start, &ri_new);
+ ti = &ri->ex_sec[QUADD_SEC_TYPE_EXIDX];
+
+ if (!is_vma_addr(ti->addr, vma_pc, sizeof(u32))) {
+ err = get_extabs_ehabi(vma_pc->vm_start, &ri_new);
if (err) {
cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
break;
}
unsigned int
-quadd_aarch32_get_user_callchain_ut(struct pt_regs *regs,
- struct quadd_callchain *cc,
- struct task_struct *task)
+quadd_get_user_cc_arm32_ehabi(struct pt_regs *regs,
+ struct quadd_callchain *cc,
+ struct task_struct *task)
{
long err;
int nr_prev = cc->nr;
return 0;
#ifdef CONFIG_ARM64
- if (!compat_user_mode(regs)) {
- pr_warn_once("user_mode 64: unsupported\n");
+ if (!compat_user_mode(regs))
return 0;
- }
#endif
if (cc->unw_rc == QUADD_URC_LEVEL_TOO_DEEP)
if (!vma_sp)
return 0;
- err = quadd_search_ex_region(vma->vm_start, &ri);
+ err = get_extabs_ehabi(vma->vm_start, &ri);
if (err) {
cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
return 0;
unwind_backtrace(cc, &ri, &frame, vma_sp, task);
+ pr_debug("%s: exit, cc->nr: %d --> %d\n",
+ __func__, nr_prev, cc->nr);
+
return cc->nr;
}
int
-quadd_aarch32_is_ex_entry_exist(struct pt_regs *regs,
- unsigned long addr,
- struct task_struct *task)
+quadd_is_ex_entry_exist_arm32_ehabi(struct pt_regs *regs,
+ unsigned long addr,
+ struct task_struct *task)
{
long err;
u32 value;
if (!vma)
return 0;
- err = quadd_search_ex_region(vma->vm_start, &ri);
+ err = get_extabs_ehabi(vma->vm_start, &ri);
if (err)
return 0;
if (err < 0)
return 0;
+ /* EXIDX_CANTUNWIND */
if (value == 1)
return 0;