misc: tegra-profiler: fix dwarf unwinding
Igor Nabirushkin [Sat, 11 Mar 2017 14:21:51 +0000 (18:21 +0400)]
DWARF unwinding: do not stop unwinding if stack is not growing
at the first function in call chain.
This patch fixes broken backtraces in leaf functions with
empty FDE entries.

Bug 1887662

Change-Id: Ib3d577afc20c923b6240e797482717f1a3e00ea4
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/1319323
(cherry picked from commit 82729960283f432cdbfc82af546dbfbde3e2cd7f)

drivers/misc/tegra-profiler/backtrace.c
drivers/misc/tegra-profiler/dwarf_unwind.c

index 6fddc76..f5194ff 100644 (file)
@@ -523,7 +523,7 @@ static unsigned int
 get_user_callchain_mixed(struct quadd_event_context *event_ctx,
                         struct quadd_callchain *cc)
 {
-       int nr_prev, nr_added;
+       int nr_prev, nr_added, is_stack_ok;
        unsigned long pc, prev_sp, align_mask;
        struct quadd_unw_methods *um = &cc->um;
 
@@ -546,19 +546,13 @@ get_user_callchain_mixed(struct quadd_event_context *event_ctx,
                if (um->ut)
                        quadd_get_user_cc_arm32_ehabi(event_ctx, cc);
 
-               if (nr_prev != cc->nr) {
-                       if (cc->curr_sp <= prev_sp ||
-                           cc->curr_sp & align_mask)
-                               break;
-
-                       continue;
-               }
-
-               if (um->fp)
+               if (um->fp && nr_prev == cc->nr)
                        __get_user_callchain_fp(event_ctx, cc);
-       } while (nr_prev != cc->nr &&
-                cc->curr_sp > prev_sp &&
-                !(cc->curr_sp & align_mask));
+
+               is_stack_ok = cc->nr <= 1 ?
+                       cc->curr_sp >= prev_sp : cc->curr_sp > prev_sp;
+               is_stack_ok = (cc->curr_sp & align_mask) ? 0 : is_stack_ok;
+       } while (nr_prev != cc->nr && is_stack_ok);
 
        return cc->nr;
 }
index 9054e52..6afa6d3 100644 (file)
@@ -1952,7 +1952,7 @@ unwind_backtrace(struct quadd_callchain *cc,
 
        while (1) {
                long sp, err;
-               int nr_added;
+               int nr_added, is_stack_ok;
                int __is_eh, __is_debug;
                struct vm_area_struct *vma_pc;
                unsigned long addr, where = sf->pc;
@@ -2033,7 +2033,10 @@ unwind_backtrace(struct quadd_callchain *cc,
                cc->curr_pc = sf->pc;
                cc->curr_lr = sf->vregs[regnum_lr(mode)];
 
-               if (cc->curr_sp <= sp) {
+               is_stack_ok = cc->nr > 0 ?
+                       cc->curr_sp > sp : cc->curr_sp >= sp;
+
+               if (!is_stack_ok) {
                        cc->urc_dwarf = QUADD_URC_SP_INCORRECT;
                        break;
                }