misc: tegra-profiler: support eh_frame sections
Igor Nabirushkin [Fri, 13 Feb 2015 17:35:02 +0000 (21:35 +0400)]
Support dwarf unwinding for arm32 files (based on
eh_frame sections).

Bug 1611069

Change-Id: Ie057ebcfcff75ccb2d3e62aa7cb85ac4b090930c
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/707903
(cherry picked from commit 950855f44e647b22508f2d31fe373fffd9e0642f)
Reviewed-on: http://git-master/r/747745
GVS: Gerrit_Virtual_Submit
Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>

drivers/misc/tegra-profiler/backtrace.c
drivers/misc/tegra-profiler/comm.c
drivers/misc/tegra-profiler/comm.h
drivers/misc/tegra-profiler/dwarf_unwind.c
drivers/misc/tegra-profiler/dwarf_unwind.h
drivers/misc/tegra-profiler/eh_unwind.c
drivers/misc/tegra-profiler/eh_unwind.h
drivers/misc/tegra-profiler/main.c
drivers/misc/tegra-profiler/version.h
include/linux/tegra_profiler.h

index 5c03114..352095b 100644 (file)
@@ -120,12 +120,8 @@ is_ex_entry_exist(struct pt_regs *regs,
                  unsigned long addr,
                  struct task_struct *task)
 {
-#ifdef CONFIG_ARM64
-       if (!compat_user_mode(regs))
-               return quadd_aarch64_is_ex_entry_exist(regs, addr, task);
-#endif
-
-       return quadd_aarch32_is_ex_entry_exist(regs, addr, task);
+       return quadd_is_ex_entry_exist_dwarf(regs, addr, task) ||
+              quadd_is_ex_entry_exist_arm32_ehabi(regs, addr, task);
 }
 
 static unsigned long __user *
@@ -537,11 +533,21 @@ get_user_callchain_ut(struct pt_regs *regs,
                      struct quadd_callchain *cc,
                      struct task_struct *task)
 {
-#ifdef CONFIG_ARM64
-       if (!compat_user_mode(regs))
-               return quadd_aarch64_get_user_callchain_ut(regs, cc, task);
-#endif
-       return quadd_aarch32_get_user_callchain_ut(regs, cc, task);
+       int nr_prev;
+
+       do {
+               nr_prev = cc->nr;
+
+               quadd_get_user_cc_dwarf(regs, cc, task);
+               if (nr_prev > 0 && cc->nr == nr_prev)
+                       break;
+
+               nr_prev = cc->nr;
+
+               quadd_get_user_cc_arm32_ehabi(regs, cc, task);
+       } while (nr_prev != cc->nr);
+
+       return cc->nr;
 }
 
 static unsigned int
@@ -554,11 +560,9 @@ get_user_callchain_mixed(struct pt_regs *regs,
        do {
                nr_prev = cc->nr;
 
-               get_user_callchain_ut(regs, cc, task);
-               if (nr_prev > 0 && cc->nr == nr_prev)
-                       break;
+               quadd_get_user_cc_dwarf(regs, cc, task);
 
-               nr_prev = cc->nr;
+               quadd_get_user_cc_arm32_ehabi(regs, cc, task);
 
                __get_user_callchain_fp(regs, cc, task);
        } while (nr_prev != cc->nr);
index 8f42289..7c4b6fc 100644 (file)
@@ -440,13 +440,12 @@ device_ioctl(struct file *file,
             unsigned long ioctl_param)
 {
        int err = 0;
-       u64 *mmap_vm_start;
        struct quadd_mmap_area *mmap;
        struct quadd_parameters *user_params;
        struct quadd_comm_cap cap;
        struct quadd_module_state state;
        struct quadd_module_version versions;
-       struct quadd_extables extabs;
+       struct quadd_sections extabs;
        struct quadd_mmap_rb_info mmap_rb;
 
        if (ioctl_num != IOCTL_SETUP &&
@@ -576,19 +575,22 @@ device_ioctl(struct file *file,
                }
                break;
 
-       case IOCTL_SET_EXTAB:
+       case IOCTL_SET_SECTIONS_INFO:
                if (copy_from_user(&extabs, (void __user *)ioctl_param,
                                   sizeof(extabs))) {
-                       pr_err("error: set_extab failed\n");
+                       pr_err("error: set_sections_info failed\n");
                        err = -EFAULT;
                        goto error_out;
                }
 
-               mmap_vm_start = (u64 *)
-                       &extabs.reserved[QUADD_EXT_IDX_MMAP_VM_START];
+               pr_debug("%s: user_mmap_start: %#llx, sections vma: %#llx - %#llx\n",
+                        __func__,
+                        (unsigned long long)extabs.user_mmap_start,
+                        (unsigned long long)extabs.vm_start,
+                        (unsigned long long)extabs.vm_end);
 
                spin_lock(&comm_ctx.mmaps_lock);
-               mmap = find_mmap((unsigned long)*mmap_vm_start);
+               mmap = find_mmap(extabs.user_mmap_start);
                if (!mmap) {
                        pr_err("%s: error: mmap is not found\n", __func__);
                        err = -ENXIO;
@@ -602,7 +604,7 @@ device_ioctl(struct file *file,
                err = comm_ctx.control->set_extab(&extabs, mmap);
                spin_unlock(&comm_ctx.mmaps_lock);
                if (err) {
-                       pr_err("error: set_extab\n");
+                       pr_err("error: set_sections_info\n");
                        goto error_out;
                }
                break;
index 66945ab..c89acd7 100644 (file)
@@ -24,7 +24,7 @@ struct quadd_comm_cap;
 struct quadd_module_state;
 struct miscdevice;
 struct quadd_parameters;
-struct quadd_extables;
+struct quadd_sections;
 struct quadd_unwind_ctx;
 struct quadd_ring_buffer;
 
@@ -58,8 +58,7 @@ struct quadd_comm_control_interface {
                              uid_t *debug_app_uid);
        void (*get_capabilities)(struct quadd_comm_cap *cap);
        void (*get_state)(struct quadd_module_state *state);
-
-       int (*set_extab)(struct quadd_extables *extabs,
+       int (*set_extab)(struct quadd_sections *extabs,
                         struct quadd_mmap_area *mmap);
        void (*delete_mmap)(struct quadd_mmap_area *mmap);
 };
index 8699bec..9121a83 100644 (file)
@@ -43,16 +43,28 @@ enum {
 };
 
 #define QUADD_AARCH64_REGISTERS        32
+#define QUADD_AARCH32_REGISTERS        16
 
-enum regs {
-       FP = 29,
-       LR = 30,
-       SP = 31,
+#define QUADD_NUM_REGS QUADD_AARCH64_REGISTERS
+
+enum regs32 {
+       ARM32_FP_THUMB = 7,
+       ARM32_FP = 11,
+
+       ARM32_SP = 13,
+       ARM32_LR = 14,
+       ARM32_PC = 15
+};
+
+enum regs64 {
+       ARM64_FP = 29,
+       ARM64_LR = 30,
+       ARM64_SP = 31,
 };
 
 enum {
-       DW_SEC_TYPE_IDX,
-       DW_SEC_TYPE_TAB,
+       DW_MODE_ARM32,
+       DW_MODE_ARM64,
 };
 
 union dw_loc {
@@ -85,10 +97,10 @@ struct dw_fde_table {
 };
 
 struct regs_state {
-       struct reg_info reg[QUADD_AARCH64_REGISTERS];
+       struct reg_info reg[QUADD_NUM_REGS];
 
        long cfa_offset;
-       unsigned int cfa_register;
+       int cfa_register;
 
        unsigned char *cfa_expr;
        unsigned int cfa_expr_len;
@@ -101,6 +113,8 @@ struct regs_state {
 struct dwarf_cpu_context {
        struct regs_state rs_stack[DW_MAX_RS_STACK_DEPTH];
        int depth;
+
+       int dw_word_size;
 };
 
 struct quadd_dwarf_context {
@@ -110,14 +124,14 @@ struct quadd_dwarf_context {
 
 struct stackframe {
        unsigned long pc;
-       unsigned long lr;
-       unsigned long sp;
-       unsigned long fp;
+       unsigned long vregs[QUADD_NUM_REGS];
 
        struct regs_state rs;
        struct regs_state rs_initial;
 
        unsigned long cfa;
+
+       int mode;
 };
 
 struct dw_cie {
@@ -165,8 +179,6 @@ struct eh_sec_data {
        unsigned char *data;
 };
 
-typedef        u64 dw_word_t;
-
 #define read_user_data(addr, retval)                           \
 ({                                                             \
        long ret;                                               \
@@ -186,21 +198,47 @@ typedef   u64 dw_word_t;
 
 static struct quadd_dwarf_context ctx;
 
+static inline int regnum_sp(int mode)
+{
+       return (mode == DW_MODE_ARM32) ?
+               ARM32_SP : ARM64_SP;
+}
+
+static inline int regnum_fp(int mode)
+{
+       return (mode == DW_MODE_ARM32) ?
+               ARM32_FP : ARM64_FP;
+}
+
+static inline int regnum_lr(int mode)
+{
+       return (mode == DW_MODE_ARM32) ?
+               ARM32_LR : ARM64_LR;
+}
+
+static inline unsigned long
+get_user_reg_size(int mode)
+{
+       return (mode == DW_MODE_ARM32) ?
+               sizeof(u32) : sizeof(u64);
+}
+
 static inline int
 validate_addr(struct ex_region_info *ri,
              unsigned long addr,
              unsigned long nbytes,
              int st)
 {
-       struct extab_info *ei;
+       struct extab_info *ti;
        struct quadd_mmap_area *mmap;
        unsigned long start, end;
 
        mmap = ri->mmap;
-       ei = (st == DW_SEC_TYPE_IDX) ? &ri->tabs.exidx : &ri->tabs.extab;
 
-       start = (unsigned long)mmap->data + ei->mmap_offset;
-       end = start + ei->length;
+       ti = &ri->ex_sec[st];
+
+       start = (unsigned long)mmap->data + ti->mmap_offset;
+       end = start + ti->length;
 
        if (unlikely(addr < start || addr > end - nbytes)) {
                pr_err_once("%s: error: addr: %#lx, len: %ld, data: %#lx-%#lx\n",
@@ -327,12 +365,12 @@ ex_addr_to_mmap_addr(unsigned long addr,
                     struct ex_region_info *ri, int st)
 {
        unsigned long offset;
-       struct extab_info *ei;
+       struct extab_info *ti;
 
-       ei = (st == DW_SEC_TYPE_IDX) ? &ri->tabs.exidx : &ri->tabs.extab;
-       offset = addr - ei->addr;
+       ti = &ri->ex_sec[st];
+       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
@@ -340,12 +378,12 @@ mmap_addr_to_ex_addr(unsigned long addr,
                     struct ex_region_info *ri, int st)
 {
        unsigned long offset;
-       struct extab_info *ei;
+       struct extab_info *ti;
 
-       ei = (st == DW_SEC_TYPE_IDX) ? &ri->tabs.exidx : &ri->tabs.extab;
-       offset = addr - ei->mmap_offset - (unsigned long)ri->mmap->data;
+       ti = &ri->ex_sec[st];
+       offset = addr - ti->mmap_offset - (unsigned long)ri->mmap->data;
 
-       return ei->addr + offset;
+       return ti->addr + offset;
 }
 
 static inline int validate_regnum(struct regs_state *rs, int regnum)
@@ -516,12 +554,15 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
                         char encoding,
                         int st)
 {
-       int count = 0;
+       int dw_word_size, count = 0;
        long stmp = 0, err = 0;
        unsigned long utmp, res = 0;
+       struct dwarf_cpu_context *cpu_ctx = this_cpu_ptr(ctx.cpu_ctx);
 
        pr_debug("encoding: %#x\n", encoding);
 
+       dw_word_size = cpu_ctx->dw_word_size;
+
        if (encoding == DW_EH_PE_omit) {
                pr_debug("DW_EH_PE_omit\n");
 
@@ -529,13 +570,13 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
                return 0;
        } else if (encoding == DW_EH_PE_aligned) {
                unsigned long aligned = ALIGN((unsigned long)addr,
-                                             sizeof(dw_word_t));
+                                             dw_word_size);
 
                pr_debug("DW_EH_PE_aligned\n");
 
-               if (sizeof(dw_word_t) == 4) {
+               if (dw_word_size == 4) {
                        *val = read_mmap_data_u32(ri, (u32 *)aligned, st, &err);
-               } else if (sizeof(dw_word_t) == 8) {
+               } else if (dw_word_size == 8) {
                        *val = read_mmap_data_u64(ri, (u64 *)aligned, st, &err);
                } else {
                        pr_err_once("%s: error: encoding\n", __func__);
@@ -545,16 +586,16 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
                if (err)
                        return err;
 
-               return sizeof(dw_word_t);
+               return dw_word_size;
        }
 
        switch (encoding & 0x0f) {
        case DW_EH_PE_absptr:
                pr_debug("%s: absptr encoding\n", __func__);
 
-               if (sizeof(dw_word_t) == 4) {
+               if (dw_word_size == 4) {
                        *val = read_mmap_data_u32(ri, (u32 *)addr, st, &err);
-               } else if (sizeof(dw_word_t) == 8) {
+               } else if (dw_word_size == 8) {
                        *val = read_mmap_data_u64(ri, (u64 *)addr, st, &err);
                } else {
                        pr_err_once("error: wrong dwarf size\n");
@@ -564,7 +605,7 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
                if (err)
                        return err;
 
-               return sizeof(dw_word_t);
+               return dw_word_size;
 
        case DW_EH_PE_sdata2:
        case DW_EH_PE_udata2:
@@ -653,10 +694,10 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
                if (encoding & DW_EH_PE_indirect) {
                        pr_debug("DW_EH_PE_indirect\n");
 
-                       if (sizeof(dw_word_t) == 4) {
+                       if (dw_word_size == 4) {
                                res = read_mmap_data_u32(ri, (u32 *)res,
                                                         st, &err);
-                       } else if (sizeof(dw_word_t) == 8) {
+                       } else if (dw_word_size == 8) {
                                res = read_mmap_data_u64(ri, (u64 *)res,
                                                         st, &err);
                        } else {
@@ -700,7 +741,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
        c_insn = insn_start;
 
        while (c_insn < insn_end && sf->pc <= pc) {
-               insn = read_mmap_data_u8(ri, c_insn++, DW_SEC_TYPE_TAB, &err);
+               insn = read_mmap_data_u8(ri, c_insn++,
+                                        QUADD_SEC_TYPE_EH_FRAME, &err);
                if (err)
                        return err;
 
@@ -716,7 +758,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
                case DW_CFA_offset:
                        reg = dw_cfa_operand(insn);
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -744,7 +787,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_advance_loc1:
                        delta = read_mmap_data_u8(ri, c_insn++,
-                                                 DW_SEC_TYPE_TAB, &err);
+                                                 QUADD_SEC_TYPE_EH_FRAME,
+                                                 &err);
                        if (err)
                                return err;
 
@@ -756,7 +800,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_advance_loc2:
                        delta = read_mmap_data_u16(ri, (u16 *)c_insn,
-                                                  DW_SEC_TYPE_TAB, &err);
+                                                  QUADD_SEC_TYPE_EH_FRAME,
+                                                  &err);
                        if (err)
                                return err;
 
@@ -769,7 +814,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_advance_loc4:
                        delta = read_mmap_data_u32(ri, (u32 *)c_insn,
-                                                  DW_SEC_TYPE_TAB, &err);
+                                                  QUADD_SEC_TYPE_EH_FRAME,
+                                                  &err);
                        if (err)
                                return err;
 
@@ -782,13 +828,15 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_offset_extended:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        reg = utmp;
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -799,7 +847,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_restore_extended:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -808,7 +857,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_undefined:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -818,13 +868,15 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_def_cfa:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        rs->cfa_register = utmp;
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -836,7 +888,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_def_cfa_register:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -847,7 +900,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_def_cfa_offset:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -858,7 +912,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_def_cfa_expression:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -875,14 +930,16 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_expression:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        set_rule_exp(rs, reg, DW_WHERE_EXPR, c_insn);
 
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -893,12 +950,14 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_offset_extended_sf:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -910,12 +969,14 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_val_offset:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -927,12 +988,13 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_val_offset_sf:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                               DW_SEC_TYPE_TAB, &err);
+                               QUADD_SEC_TYPE_EH_FRAME, &err);
                        if (err)
                                return err;
 
                        c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -944,7 +1006,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_GNU_args_size:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -953,12 +1016,14 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_GNU_negative_offset_extended:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -992,12 +1057,14 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_def_cfa_sf:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -1012,7 +1079,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_def_cfa_offset_sf:
                        c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -1023,7 +1091,8 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_same_value:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -1033,13 +1102,15 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
 
                case DW_CFA_val_expression:
                        c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
                        set_rule_exp(rs, reg, DW_WHERE_VAL_EXPR, c_insn);
                        c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                        if (err)
                                return err;
 
@@ -1073,7 +1144,7 @@ decode_cie_entry(struct ex_region_info *ri,
 
        p += sizeof(u32);
 
-       id = read_mmap_data_u32(ri, (u32 *)p, DW_SEC_TYPE_TAB, &err);
+       id = read_mmap_data_u32(ri, (u32 *)p, QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
@@ -1082,7 +1153,7 @@ decode_cie_entry(struct ex_region_info *ri,
        if (id != 0)
                return -QUADD_URC_TBL_IS_CORRUPT;
 
-       cie_version = read_mmap_data_u8(ri, p++, DW_SEC_TYPE_TAB, &err);
+       cie_version = read_mmap_data_u8(ri, p++, QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
@@ -1105,22 +1176,24 @@ decode_cie_entry(struct ex_region_info *ri,
        pr_debug("aug_string: %s\n", cie->aug_string);
 
        p += dwarf_read_uleb128(ri, p, &cie->code_align_factor,
-                               DW_SEC_TYPE_TAB, &err);
+                               QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
        p += dwarf_read_sleb128(ri, p, &cie->data_align_factor,
-                               DW_SEC_TYPE_TAB, &err);
+                               QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
        if (cie_version == 1) {
                cie->retaddr_reg = read_mmap_data_u8(ri, p++,
-                                                    DW_SEC_TYPE_TAB, &err);
+                                                    QUADD_SEC_TYPE_EH_FRAME,
+                                                    &err);
                if (err)
                        return err;
        } else {
-               p += dwarf_read_uleb128(ri, p, &utmp, DW_SEC_TYPE_TAB, &err);
+               p += dwarf_read_uleb128(ri, p, &utmp,
+                                       QUADD_SEC_TYPE_EH_FRAME, &err);
                if (err)
                        return err;
 
@@ -1137,7 +1210,7 @@ decode_cie_entry(struct ex_region_info *ri,
 
        if (*aug == 'z') {
                p += dwarf_read_uleb128(ri, p, &cie->aug_size,
-                                       DW_SEC_TYPE_TAB, &err);
+                                       QUADD_SEC_TYPE_EH_FRAME, &err);
                if (err)
                        return err;
 
@@ -1158,24 +1231,26 @@ decode_cie_entry(struct ex_region_info *ri,
                        return -QUADD_URC_TBL_IS_CORRUPT;
 
                if (*aug == 'L') {
-                       cie->lsda_encoding = read_mmap_data_u8(ri, p++,
-                                                              DW_SEC_TYPE_TAB,
-                                                              &err);
+                       cie->lsda_encoding =
+                               read_mmap_data_u8(ri, p++,
+                                                 QUADD_SEC_TYPE_EH_FRAME,
+                                                 &err);
                        if (err)
                                return err;
 
                        aug++;
                } else if (*aug == 'R') {
-                       cie->fde_encoding = read_mmap_data_u8(ri, p++,
-                                                             DW_SEC_TYPE_TAB,
-                                                             &err);
+                       cie->fde_encoding =
+                               read_mmap_data_u8(ri, p++,
+                                                 QUADD_SEC_TYPE_EH_FRAME,
+                                                 &err);
                        if (err)
                                return err;
 
                        aug++;
                        pr_debug("fde_encoding: %#x\n", cie->fde_encoding);
                } else if (*aug == 'P') {
-                       int count;
+                       int cnt;
                        void *pcrel_base;
                        unsigned char handler_encoding;
                        unsigned long personality;
@@ -1184,18 +1259,19 @@ decode_cie_entry(struct ex_region_info *ri,
 
                        pcrel_base = (void *)
                                mmap_addr_to_ex_addr((unsigned long)p,
-                                                    ri, DW_SEC_TYPE_TAB);
-
-                       count = dwarf_read_encoded_value(ri, p, pcrel_base,
-                                                        &personality,
-                                                        handler_encoding,
-                                                        DW_SEC_TYPE_TAB);
-                       if (count < 0) {
+                                                    ri,
+                                                    QUADD_SEC_TYPE_EH_FRAME);
+
+                       cnt = dwarf_read_encoded_value(ri, p, pcrel_base,
+                                                      &personality,
+                                                      handler_encoding,
+                                                      QUADD_SEC_TYPE_EH_FRAME);
+                       if (cnt < 0) {
                                pr_err_once("%s: error: personality routine\n",
                                            __func__);
-                               return count;
+                               return cnt;
                        }
-                       p += count;
+                       p += cnt;
 
                        pr_debug("personality: %#lx\n", personality);
                        cie->personality = (void *)personality;
@@ -1244,19 +1320,20 @@ decode_fde_entry(struct ex_region_info *ri,
        p += sizeof(u32);
 
        pcrel_base = (unsigned char *)
-               mmap_addr_to_ex_addr((unsigned long)p, ri, DW_SEC_TYPE_TAB);
+               mmap_addr_to_ex_addr((unsigned long)p, ri,
+                                    QUADD_SEC_TYPE_EH_FRAME);
 
        count = dwarf_read_encoded_value(ri, p, pcrel_base,
                                         &fde->initial_location,
                                         cie->fde_encoding,
-                                        DW_SEC_TYPE_TAB);
+                                        QUADD_SEC_TYPE_EH_FRAME);
        if (count < 0)
                return count;
 
        p += count;
 
        fde->address_range = read_mmap_data_u32(ri, (u32 *)p,
-                                               DW_SEC_TYPE_TAB, &err);
+                                               QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
@@ -1266,7 +1343,8 @@ decode_fde_entry(struct ex_region_info *ri,
        pr_debug("address_range: %#lx\n", fde->address_range);
 
        if (cie->z_aug) {
-               p += dwarf_read_uleb128(ri, p, &utmp, DW_SEC_TYPE_TAB, &err);
+               p += dwarf_read_uleb128(ri, p, &utmp,
+                                       QUADD_SEC_TYPE_EH_FRAME, &err);
                if (err)
                        return err;
 
@@ -1344,6 +1422,8 @@ dwarf_get_bs_table(struct ex_region_info *ri,
 
        end = data + length;
 
+       pr_debug("hdr: %p\n", hdr);
+
        if (hdr->version != 1) {
                pr_warn_once("warning: unknown eh hdr format\n");
                return NULL;
@@ -1354,7 +1434,7 @@ dwarf_get_bs_table(struct ex_region_info *ri,
                count = dwarf_read_encoded_value(ri, p, (void *)data_base,
                                                 &frame_ptr,
                                                 hdr->eh_frame_ptr_enc,
-                                                DW_SEC_TYPE_IDX);
+                                                QUADD_SEC_TYPE_EH_FRAME_HDR);
                if (count < 0)
                        return NULL;
 
@@ -1366,7 +1446,7 @@ dwarf_get_bs_table(struct ex_region_info *ri,
 
        count = dwarf_read_encoded_value(ri, p, (void *)data_base,
                                         &fde_count, hdr->fde_count_enc,
-                                        DW_SEC_TYPE_IDX);
+                                        QUADD_SEC_TYPE_EH_FRAME_HDR);
        if (count < 0)
                return NULL;
 
@@ -1401,19 +1481,23 @@ dwarf_decode_fde_cie(struct ex_region_info *ri,
        unsigned long cie_pointer, length;
        unsigned char *frame_start;
        unsigned long frame_len, addr;
+       struct extab_info *ti;
+
+       ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME];
 
-       addr = ri->tabs.extab.addr;
+       addr = ti->addr;
 
        frame_start = (unsigned char *)
-               ex_addr_to_mmap_addr(addr, ri, DW_SEC_TYPE_TAB);
-       frame_len = ri->tabs.extab.length;
+               ex_addr_to_mmap_addr(addr, ri, QUADD_SEC_TYPE_EH_FRAME);
+
+       frame_len = ti->length;
 
        pr_debug("eh frame: %p - %p\n",
                 frame_start, frame_start + frame_len);
 
        p = (u32 *)fde_p;
 
-       length = read_mmap_data_u32(ri, p++, DW_SEC_TYPE_TAB, &err);
+       length = read_mmap_data_u32(ri, p++, QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
@@ -1428,14 +1512,15 @@ dwarf_decode_fde_cie(struct ex_region_info *ri,
        pr_debug("FDE: fde_p: %p, offset: %#lx, len: %#lx\n",
                 fde_p, fde->offset, fde->length);
 
-       cie_pointer = read_mmap_data_u32(ri, p, DW_SEC_TYPE_TAB, &err);
+       cie_pointer = read_mmap_data_u32(ri, p, QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
        fde->cie_pointer = cie_pointer;
        cie_p = (unsigned char *)p - cie_pointer;
 
-       length = read_mmap_data_u32(ri, (u32 *)cie_p, DW_SEC_TYPE_TAB, &err);
+       length = read_mmap_data_u32(ri, (u32 *)cie_p,
+                                   QUADD_SEC_TYPE_EH_FRAME, &err);
        if (err)
                return err;
 
@@ -1474,8 +1559,10 @@ dwarf_find_fde(struct ex_region_info *ri,
        unsigned long fde_count = 0, data_base;
        unsigned long fde_addr, init_loc;
        struct dw_fde_table *bst;
+       struct extab_info *ti;
 
-       data_base = ri->tabs.exidx.addr;
+       ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+       data_base = ti->addr;
 
        bst = dwarf_get_bs_table(ri, data, length, data_base, &fde_count);
        if (!bst || fde_count == 0) {
@@ -1490,7 +1577,8 @@ dwarf_find_fde(struct ex_region_info *ri,
                unsigned long start, end;
 
                fde_addr = dw_bst_get_fde_addr(fi, data_base);
-               fde_addr = ex_addr_to_mmap_addr(fde_addr, ri, DW_SEC_TYPE_TAB);
+               fde_addr = ex_addr_to_mmap_addr(fde_addr, ri,
+                                               QUADD_SEC_TYPE_EH_FRAME);
 
                if (pc == init_loc)
                        return (void *)fde_addr;
@@ -1522,7 +1610,7 @@ dwarf_find_fde(struct ex_region_info *ri,
                return NULL;
 
        fde_addr = dw_bst_get_fde_addr(fi, data_base);
-       fde_addr = ex_addr_to_mmap_addr(fde_addr, ri, DW_SEC_TYPE_TAB);
+       fde_addr = ex_addr_to_mmap_addr(fde_addr, ri, QUADD_SEC_TYPE_EH_FRAME);
 
        return (void *)fde_addr;
 }
@@ -1537,12 +1625,16 @@ dwarf_decode(struct ex_region_info *ri,
        unsigned char *fde_p;
        unsigned char *hdr_start;
        unsigned long hdr_len, addr;
+       struct extab_info *ti;
 
-       addr = ri->tabs.exidx.addr;
+       ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+
+       addr = ti->addr;
 
        hdr_start = (unsigned char *)
-               ex_addr_to_mmap_addr(addr, ri, DW_SEC_TYPE_IDX);
-       hdr_len = ri->tabs.exidx.length;
+               ex_addr_to_mmap_addr(addr, ri, QUADD_SEC_TYPE_EH_FRAME_HDR);
+
+       hdr_len = ti->length;
 
        pr_debug("eh frame hdr: %p - %p\n",
                 hdr_start, hdr_start + hdr_len);
@@ -1566,19 +1658,39 @@ dwarf_decode(struct ex_region_info *ri,
        return 0;
 }
 
+static long def_cfa(struct stackframe *sf, struct regs_state *rs)
+{
+       int reg = rs->cfa_register;
+
+       if (reg >= 0) {
+               if (reg >= QUADD_NUM_REGS)
+                       return -QUADD_URC_TBL_IS_CORRUPT;
+
+               pr_debug("r%d --> cfa (%#lx)\n", reg, sf->cfa);
+               sf->cfa = sf->vregs[reg];
+       }
+
+       sf->cfa += rs->cfa_offset;
+       pr_debug("cfa += %#lx (%#lx)\n", rs->cfa_offset, sf->cfa);
+
+       return 0;
+}
+
 static long
 unwind_frame(struct ex_region_info *ri,
             struct stackframe *sf,
             struct vm_area_struct *vma_sp,
             unsigned int *unw_type)
 {
+       int i;
        long err;
        unsigned char *insn_end;
-       unsigned long addr, return_addr, fp;
+       unsigned long addr, return_addr, val, user_reg_size;
        struct dw_fde fde;
        struct dw_cie cie;
        unsigned long pc = sf->pc;
        struct regs_state *rs, *rs_initial;
+       int mode = sf->mode;
 
        err = dwarf_decode(ri, &cie, &fde, pc);
        if (err < 0)
@@ -1589,7 +1701,12 @@ unwind_frame(struct ex_region_info *ri,
        rs = &sf->rs;
        rs_initial = &sf->rs_initial;
 
-       set_rule(rs, LR, DW_WHERE_UNDEF, 0);
+       rs->cfa_register = -1;
+       rs_initial->cfa_register = -1;
+
+       rs->cfa_register = 0;
+
+       set_rule(rs, regnum_lr(mode), DW_WHERE_UNDEF, 0);
 
        if (cie.initial_insn) {
                insn_end = cie.initial_insn + cie.initial_insn_len;
@@ -1609,61 +1726,86 @@ unwind_frame(struct ex_region_info *ri,
                        return err;
        }
 
-       if (!sf->cfa)
-               sf->cfa = sf->sp + rs->cfa_offset;
-       else
-               sf->cfa += rs->cfa_offset;
+       pr_debug("mode: %s\n", (mode == DW_MODE_ARM32) ? "arm32" : "arm64");
+       pr_debug("initial cfa: %#lx\n", sf->cfa);
 
-       pr_debug("pc: %#lx, lr: %#lx\n", sf->pc, sf->lr);
-       pr_debug("sp: %#lx, fp: %#lx\n", sf->sp, sf->fp);
+       user_reg_size = get_user_reg_size(mode);
 
-       pr_debug("fp rule: %#lx/%ld\n",
-                rs->reg[FP].loc.reg, rs->reg[FP].loc.offset);
-       pr_debug("lr rule: %#lx/%ld\n",
-                rs->reg[LR].loc.reg, rs->reg[LR].loc.offset);
+       err = def_cfa(sf, rs);
+       if (err < 0)
+               return err;
+
+       pr_debug("pc: %#lx, lr: %#lx\n", sf->pc, sf->vregs[regnum_lr(mode)]);
+
+       pr_debug("sp: %#lx, fp: %#lx, fp_thumb: %#lx\n",
+                sf->vregs[regnum_sp(mode)],
+                sf->vregs[regnum_fp(mode)],
+                sf->vregs[ARM32_FP_THUMB]);
+
+       pr_debug("lr rule: %#lx/%ld (where: %u)\n",
+                rs->reg[regnum_lr(mode)].loc.reg,
+                rs->reg[regnum_lr(mode)].loc.offset,
+                rs->reg[regnum_lr(mode)].where);
+
+       pr_debug("fp rule: %#lx/%ld (where: %u)\n",
+                rs->reg[regnum_fp(mode)].loc.reg,
+                rs->reg[regnum_fp(mode)].loc.offset,
+                rs->reg[regnum_fp(mode)].where);
+
+       pr_debug("fp_thumb rule: %#lx/%ld (where: %u)\n",
+                rs->reg[ARM32_FP_THUMB].loc.reg,
+                rs->reg[ARM32_FP_THUMB].loc.offset,
+                rs->reg[ARM32_FP_THUMB].where);
 
        pr_debug("cfa_offset: %ld (%#lx)\n",
                 rs->cfa_offset, rs->cfa_offset);
        pr_debug("cfa_register: %u\n", rs->cfa_register);
-       pr_debug("sf->cfa: %#lx\n", sf->cfa);
+       pr_debug("new cfa: %#lx\n", sf->cfa);
 
-       if (rs->reg[LR].where == DW_WHERE_CFAREL) {
-               addr = sf->cfa + rs->reg[LR].loc.offset;
-               pr_debug("lr: cfa addr: %#lx\n", addr);
+       for (i = 0; i < QUADD_NUM_REGS; i++) {
+               switch (rs->reg[i].where) {
+               case DW_WHERE_UNDEF:
+                       break;
 
-               if (!validate_stack_addr(addr, vma_sp, sizeof(unsigned long)))
-                       return -QUADD_URC_SP_INCORRECT;
+               case DW_WHERE_SAME:
+                       break;
 
-               err = read_user_data((unsigned long __user *)addr, return_addr);
-               if (err < 0)
-                       return err;
+               case DW_WHERE_CFAREL:
+                       addr = sf->cfa + rs->reg[i].loc.offset;
 
-               *unw_type = QUADD_UNW_TYPE_UT;
-       } else {
-               return_addr = sf->lr;
-               *unw_type = QUADD_UNW_TYPE_LR_UT;
-       }
+                       if (!validate_stack_addr(addr, vma_sp, user_reg_size))
+                               return -QUADD_URC_SP_INCORRECT;
 
-       if (!validate_pc_addr(return_addr, sizeof(unsigned long)))
-               return -QUADD_URC_PC_INCORRECT;
+                       if (mode == DW_MODE_ARM32)
+                               err = read_user_data((u32 __user *)addr, val);
+                       else
+                               err = read_user_data((unsigned long __user *)
+                                                    addr, val);
 
-       sf->pc = return_addr;
-
-       if (rs->reg[FP].where == DW_WHERE_CFAREL) {
-               addr = sf->cfa + rs->reg[FP].loc.offset;
-               pr_debug("fp: cfa addr: %#lx\n", addr);
+                       if (err < 0)
+                               return err;
 
-               if (!validate_stack_addr(addr, vma_sp, sizeof(unsigned long)))
-                       return -QUADD_URC_SP_INCORRECT;
+                       sf->vregs[i] = val;
+                       pr_debug("[r%d] DW_WHERE_CFAREL: new val: %#lx\n",
+                                i, val);
 
-               err = read_user_data((unsigned long __user *)addr, fp);
-               if (err < 0)
-                       return err;
+                       break;
 
-               sf->fp = fp;
+               default:
+                       pr_err_once("[r%d] error: unsupported rule\n",
+                                   rs->reg[i].where);
+                       break;
+               }
        }
 
-       sf->sp = sf->cfa;
+       return_addr = sf->vregs[regnum_lr(mode)];
+       pr_debug("return_addr: %#lx\n", return_addr);
+
+       if (!validate_pc_addr(return_addr, user_reg_size))
+               return -QUADD_URC_PC_INCORRECT;
+
+       sf->pc = return_addr;
+       sf->vregs[regnum_sp(mode)] = sf->cfa;
 
        return 0;
 }
@@ -1675,22 +1817,28 @@ unwind_backtrace(struct quadd_callchain *cc,
                 struct vm_area_struct *vma_sp,
                 struct task_struct *task)
 {
-       unsigned int unw_type = QUADD_UNW_TYPE_UT;
+       unsigned long user_reg_size;
        struct ex_region_info ri_new;
+       unsigned int unw_type = QUADD_UNW_TYPE_UT;
+       int mode = sf->mode;
 
        cc->unw_rc = QUADD_URC_FAILURE;
+       user_reg_size = get_user_reg_size(mode);
 
        while (1) {
-               long err;
+               long sp, err;
                int nr_added;
                struct vm_area_struct *vma_pc;
                unsigned long addr, where = sf->pc;
                struct mm_struct *mm = task->mm;
+               struct extab_info *ti;
 
                if (!mm)
                        break;
 
-               if (!validate_stack_addr(sf->sp, vma_sp, sizeof(sf->sp))) {
+               sp = sf->vregs[regnum_sp(mode)];
+
+               if (!validate_stack_addr(sp, vma_sp, user_reg_size)) {
                        cc->unw_rc = -QUADD_URC_SP_INCORRECT;
                        break;
                }
@@ -1699,10 +1847,12 @@ unwind_backtrace(struct quadd_callchain *cc,
                if (!vma_pc)
                        break;
 
-               addr = ri->tabs.exidx.addr;
+               ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+               addr = ti->addr;
 
-               if (!is_vma_addr(addr, vma_pc, sizeof(unsigned long))) {
-                       err = quadd_search_ex_region(vma_pc->vm_start, &ri_new);
+               if (!is_vma_addr(addr, vma_pc, user_reg_size)) {
+                       err = quadd_get_extabs_ehframe(vma_pc->vm_start,
+                                                      &ri_new);
                        if (err) {
                                cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
                                break;
@@ -1720,8 +1870,8 @@ unwind_backtrace(struct quadd_callchain *cc,
                pr_debug("function at [<%08lx>] from [<%08lx>]\n",
                         where, sf->pc);
 
-               cc->curr_sp = sf->sp;
-               cc->curr_fp = sf->fp;
+               cc->curr_sp = sf->vregs[regnum_sp(mode)];
+               cc->curr_fp = sf->vregs[regnum_fp(mode)];
                cc->curr_pc = sf->pc;
 
                nr_added = quadd_callchain_store(cc, sf->pc, unw_type);
@@ -1731,9 +1881,9 @@ unwind_backtrace(struct quadd_callchain *cc,
 }
 
 int
-quadd_aarch64_is_ex_entry_exist(struct pt_regs *regs,
-                               unsigned long addr,
-                               struct task_struct *task)
+quadd_is_ex_entry_exist_dwarf(struct pt_regs *regs,
+                             unsigned long addr,
+                             struct task_struct *task)
 {
        long err;
        unsigned char *fde_p;
@@ -1742,6 +1892,7 @@ quadd_aarch64_is_ex_entry_exist(struct pt_regs *regs,
        unsigned long hdr_len, a;
        struct vm_area_struct *vma;
        struct mm_struct *mm = task->mm;
+       struct extab_info *ti;
 
        if (!regs || !mm)
                return 0;
@@ -1750,15 +1901,18 @@ quadd_aarch64_is_ex_entry_exist(struct pt_regs *regs,
        if (!vma)
                return 0;
 
-       err = quadd_search_ex_region(vma->vm_start, &ri);
+       err = quadd_get_extabs_ehframe(vma->vm_start, &ri);
        if (err)
                return 0;
 
-       a = ri.tabs.exidx.addr;
+       ti = &ri.ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+
+       a = ti->addr;
 
        hdr_start = (unsigned char *)
-               ex_addr_to_mmap_addr(a, &ri, DW_SEC_TYPE_IDX);
-       hdr_len = ri.tabs.exidx.length;
+               ex_addr_to_mmap_addr(a, &ri, QUADD_SEC_TYPE_EH_FRAME_HDR);
+
+       hdr_len = ti->length;
 
        fde_p = dwarf_find_fde(&ri, hdr_start, hdr_len, addr);
        if (!fde_p)
@@ -1768,17 +1922,18 @@ quadd_aarch64_is_ex_entry_exist(struct pt_regs *regs,
 }
 
 unsigned int
-quadd_aarch64_get_user_callchain_ut(struct pt_regs *regs,
-                                   struct quadd_callchain *cc,
-                                   struct task_struct *task)
+quadd_get_user_cc_dwarf(struct pt_regs *regs,
+                       struct quadd_callchain *cc,
+                       struct task_struct *task)
 {
        long err;
-       int i, nr_prev = cc->nr;
-       unsigned long ip, lr, sp, fp;
+       int i, mode, nr_prev = cc->nr;
+       unsigned long ip, lr, sp, fp, fp_thumb;
        struct vm_area_struct *vma, *vma_sp;
        struct mm_struct *mm = task->mm;
        struct ex_region_info ri;
        struct stackframe sf;
+       struct dwarf_cpu_context *cpu_ctx = this_cpu_ptr(ctx.cpu_ctx);
 
        if (!regs || !mm)
                return 0;
@@ -1792,25 +1947,56 @@ quadd_aarch64_get_user_callchain_ut(struct pt_regs *regs,
                ip = cc->curr_pc;
                sp = cc->curr_sp;
                fp = cc->curr_fp;
+               fp_thumb = 0;
                lr = 0;
        } else {
                ip = instruction_pointer(regs);
                lr = quadd_user_link_register(regs);
                sp = quadd_user_stack_pointer(regs);
-               fp = quadd_get_user_frame_pointer(regs);
+
+#ifdef CONFIG_ARM64
+               if (compat_user_mode(regs)) {
+                       fp = regs->compat_usr(11);
+                       fp_thumb = regs->compat_usr(7);
+               } else {
+                       fp = regs->regs[29];
+                       fp_thumb = 0;
+               }
+#else
+               fp = regs->ARM_fp;
+               fp_thumb = regs->ARM_r7;
+#endif
        }
 
+#ifdef CONFIG_ARM64
+       if (compat_user_mode(regs))
+               mode = DW_MODE_ARM32;
+       else
+               mode = DW_MODE_ARM64;
+#else
+       mode = DW_MODE_ARM32;
+#endif
+
+
        pr_debug("%s: pc: %#lx, lr: %#lx\n", __func__, ip, lr);
-       pr_debug("%s: sp: %#lx, fp: %#lx\n", __func__, sp, fp);
+       pr_debug("%s: sp: %#lx, fp: %#lx, fp_thumb: %#lx\n",
+                __func__, sp, fp, fp_thumb);
 
+       sf.vregs[regnum_lr(mode)] = lr;
        sf.pc = ip;
-       sf.lr = lr;
-       sf.sp = sp;
-       sf.fp = fp;
 
+       sf.vregs[regnum_sp(mode)] = sp;
+       sf.vregs[regnum_fp(mode)] = fp;
+
+       sf.vregs[ARM32_FP_THUMB] = fp_thumb;
+
+       cpu_ctx->dw_word_size = (mode == DW_MODE_ARM32) ?
+                               sizeof(u32) : sizeof(u64);
+
+       sf.mode = mode;
        sf.cfa = 0;
 
-       for (i = 0; i < ARRAY_SIZE(sf.rs.reg); i++)
+       for (i = 0; i < QUADD_NUM_REGS; i++)
                set_rule(&sf.rs, i, DW_WHERE_UNDEF, 0);
 
        vma = find_vma(mm, ip);
@@ -1821,7 +2007,7 @@ quadd_aarch64_get_user_callchain_ut(struct pt_regs *regs,
        if (!vma_sp)
                return 0;
 
-       err = quadd_search_ex_region(vma->vm_start, &ri);
+       err = quadd_get_extabs_ehframe(vma->vm_start, &ri);
        if (err) {
                cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
                return 0;
@@ -1829,6 +2015,10 @@ quadd_aarch64_get_user_callchain_ut(struct pt_regs *regs,
 
        unwind_backtrace(cc, &ri, &sf, vma_sp, task);
 
+       pr_debug("%s: mode: %s, cc->nr: %d --> %d\n", __func__,
+                (mode == DW_MODE_ARM32) ? "arm32" : "arm64",
+                nr_prev, cc->nr);
+
        return cc->nr;
 }
 
index a17afb7..de5d308 100644 (file)
@@ -21,15 +21,15 @@ struct pt_regs;
 struct quadd_callchain;
 struct task_struct;
 
-unsigned int
-quadd_aarch64_get_user_callchain_ut(struct pt_regs *regs,
-                                   struct quadd_callchain *cc,
-                                   struct task_struct *task);
-
 int
-quadd_aarch64_is_ex_entry_exist(struct pt_regs *regs,
-                               unsigned long addr,
-                               struct task_struct *task);
+quadd_is_ex_entry_exist_dwarf(struct pt_regs *regs,
+                             unsigned long addr,
+                             struct task_struct *task);
+
+unsigned int
+quadd_get_user_cc_dwarf(struct pt_regs *regs,
+                       struct quadd_callchain *cc,
+                       struct task_struct *task);
 
 int quadd_dwarf_unwind_start(void);
 void quadd_dwarf_unwind_stop(void);
index 0fecf0b..1c3e680 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * drivers/misc/tegra-profiler/exh_tables.c
+ * drivers/misc/tegra-profiler/eh_unwind.c
  *
  * Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
  *
@@ -16,9 +16,6 @@
 
 #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>
@@ -149,29 +146,29 @@ read_mmap_data(struct quadd_mmap_area *mmap, const u32 *addr, u32 *retval)
 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
@@ -190,25 +187,21 @@ prel31_to_addr(const u32 *ptr)
 
 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;
 }
@@ -313,9 +306,9 @@ remove_ex_region(struct regions_data *rd,
 }
 
 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;
 
@@ -340,7 +333,8 @@ search_ex_region(struct ex_region_info *array,
        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;
@@ -351,7 +345,7 @@ long quadd_search_ex_region(unsigned long key, struct ex_region_info *ri)
        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));
 
@@ -360,6 +354,38 @@ out:
        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;
@@ -394,10 +420,10 @@ static void rd_free_rcu(struct rcu_head *rh)
        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;
@@ -443,17 +469,23 @@ int quadd_unwind_set_extab(struct quadd_extables *extabs,
        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)
@@ -517,7 +549,7 @@ quadd_unwind_set_tail_info(unsigned long vm_start,
 
        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;
 
@@ -599,33 +631,41 @@ error_out:
 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;
@@ -946,7 +986,9 @@ unwind_frame(struct ex_region_info *ri,
        } 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) {
@@ -1027,6 +1069,7 @@ unwind_backtrace(struct quadd_callchain *cc,
        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;
@@ -1043,8 +1086,10 @@ unwind_backtrace(struct quadd_callchain *cc,
                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;
@@ -1074,9 +1119,9 @@ unwind_backtrace(struct quadd_callchain *cc,
 }
 
 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;
@@ -1090,10 +1135,8 @@ quadd_aarch32_get_user_callchain_ut(struct pt_regs *regs,
                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)
@@ -1134,7 +1177,7 @@ quadd_aarch32_get_user_callchain_ut(struct pt_regs *regs,
        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;
@@ -1142,13 +1185,16 @@ quadd_aarch32_get_user_callchain_ut(struct pt_regs *regs,
 
        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;
@@ -1164,7 +1210,7 @@ quadd_aarch32_is_ex_entry_exist(struct pt_regs *regs,
        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;
 
@@ -1176,6 +1222,7 @@ quadd_aarch32_is_ex_entry_exist(struct pt_regs *regs,
        if (err < 0)
                return 0;
 
+       /* EXIDX_CANTUNWIND */
        if (value == 1)
                return 0;
 
index 77fdfc9..7ce0f82 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef __QUADD_EH_UNWIND_H__
 #define __QUADD_EH_UNWIND_H__
 
+#include <linux/tegra_profiler.h>
+
 struct pt_regs;
 struct quadd_callchain;
 struct quadd_ctx;
@@ -25,9 +27,9 @@ struct task_struct;
 struct quadd_mmap_area;
 
 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);
 
 int quadd_unwind_init(void);
 void quadd_unwind_deinit(void);
@@ -35,20 +37,21 @@ void quadd_unwind_deinit(void);
 int quadd_unwind_start(struct task_struct *task);
 void quadd_unwind_stop(void);
 
-int quadd_unwind_set_extab(struct quadd_extables *extabs,
+int quadd_unwind_set_extab(struct quadd_sections *extabs,
                           struct quadd_mmap_area *mmap);
 void quadd_unwind_delete_mmap(struct quadd_mmap_area *mmap);
 
 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);
 
 void
 quadd_unwind_set_tail_info(unsigned long vm_start,
                           unsigned long tf_start,
                           unsigned long tf_end);
 
+
 struct extab_info {
        unsigned long addr;
        unsigned long length;
@@ -56,16 +59,11 @@ struct extab_info {
        unsigned long mmap_offset;
 };
 
-struct extables {
-       struct extab_info extab;
-       struct extab_info exidx;
-};
-
 struct ex_region_info {
        unsigned long vm_start;
        unsigned long vm_end;
 
-       struct extables tabs;
+       struct extab_info ex_sec[QUADD_SEC_TYPE_MAX];
        struct quadd_mmap_area *mmap;
 
        struct list_head list;
@@ -74,6 +72,7 @@ struct ex_region_info {
        unsigned long tf_end;
 };
 
-long quadd_search_ex_region(unsigned long key, struct ex_region_info *ri);
+long
+quadd_get_extabs_ehframe(unsigned long key, struct ex_region_info *ri);
 
 #endif /* __QUADD_EH_UNWIND_H__ */
index 0f1237f..b737f99 100644 (file)
@@ -463,7 +463,7 @@ void quadd_get_state(struct quadd_module_state *state)
 }
 
 static int
-set_extab(struct quadd_extables *extabs,
+set_extab(struct quadd_sections *extabs,
          struct quadd_mmap_area *mmap)
 {
        return quadd_unwind_set_extab(extabs, mmap);
index 7b3fc20..fb60632 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __QUADD_VERSION_H
 #define __QUADD_VERSION_H
 
-#define QUADD_MODULE_VERSION           "1.88"
+#define QUADD_MODULE_VERSION           "1.89"
 #define QUADD_MODULE_BRANCH            "Dev"
 
 #endif /* __QUADD_VERSION_H */
index 4225e7e..1aa39a4 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/ioctl.h>
 
 #define QUADD_SAMPLES_VERSION  31
-#define QUADD_IO_VERSION       16
+#define QUADD_IO_VERSION       17
 
 #define QUADD_IO_VERSION_DYNAMIC_RB            5
 #define QUADD_IO_VERSION_RB_MAX_FILL_COUNT     6
@@ -34,6 +34,7 @@
 #define QUADD_IO_VERSION_DATA_MMAP             14
 #define QUADD_IO_VERSION_BT_LOWER_BOUND                15
 #define QUADD_IO_VERSION_STACK_OFFSET          16
+#define QUADD_IO_VERSION_SECTIONS_INFO         17
 
 #define QUADD_SAMPLE_VERSION_THUMB_MODE_FLAG   17
 #define QUADD_SAMPLE_VERSION_GROUP_SAMPLES     18
 
 /*
  * Send exception-handling tables info
+ * This ioctl is obsolete
  */
-#define IOCTL_SET_EXTAB _IOW(QUADD_IOCTL, 6, struct quadd_extables)
+/*#define IOCTL_SET_EXTAB _IOW(QUADD_IOCTL, 6, struct quadd_extables)*/
 
 /*
  * Send ring buffer mmap info
  */
 #define IOCTL_SET_MMAP_RB _IOW(QUADD_IOCTL, 7, struct quadd_mmap_rb_info)
 
+/*
+ * Send sections info
+ */
+#define IOCTL_SET_SECTIONS_INFO _IOW(QUADD_IOCTL, 8, struct quadd_sections)
+
 #define QUADD_CPUMODE_TEGRA_POWER_CLUSTER_LP   (1 << 29)       /* LP CPU */
 #define QUADD_CPUMODE_THUMB                    (1 << 30)       /* thumb mode */
 
@@ -455,25 +462,35 @@ struct quadd_module_version {
        u32 reserved[4];        /* reserved fields for future extensions */
 };
 
+enum {
+       QUADD_SEC_TYPE_EXTAB = 0,
+       QUADD_SEC_TYPE_EXIDX,
+
+       QUADD_SEC_TYPE_EH_FRAME,
+       QUADD_SEC_TYPE_EH_FRAME_HDR,
+
+       QUADD_SEC_TYPE_DEBUG_FRAME,
+       QUADD_SEC_TYPE_DEBUG_FRAME_HDR,
+
+       QUADD_SEC_TYPE_MAX,
+};
+
 struct quadd_sec_info {
        u64 addr;
        u64 length;
-};
 
-enum {
-       QUADD_EXT_IDX_EXTAB_OFFSET = 0,
-       QUADD_EXT_IDX_EXIDX_OFFSET = 1,
-       QUADD_EXT_IDX_MMAP_VM_START = 2,
+       u64 mmap_offset;
 };
 
-struct quadd_extables {
+struct quadd_sections {
        u64 vm_start;
        u64 vm_end;
 
-       struct quadd_sec_info extab;
-       struct quadd_sec_info exidx;
+       struct quadd_sec_info sec[QUADD_SEC_TYPE_MAX];
 
-       u32 reserved[4];        /* reserved fields for future extensions */
+       u64 user_mmap_start;
+
+       u64 reserved[4];        /* reserved fields for future extensions */
 };
 
 struct quadd_mmap_rb_info {