misc: tegra-profiler: fix crash in dwarf unwinding
Igor Nabirushkin [Wed, 11 Jan 2017 10:45:30 +0000 (14:45 +0400)]
Do not update sections information in sched context,
it is not safely.

Bug 200246808

Change-Id: Iadca09f29e62d57330430c3325ccbc9ac8280f88
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/1252603
(cherry picked from commit 819e89ac73a5f62f04cbdea328683c25332ba71b)
Reviewed-on: http://git-master/r/1283451
(cherry picked from commit 247a28b42dc1f67c011b5c50af9ebdd35d6eb1c6)
Reviewed-on: http://git-master/r/1302040
(cherry picked from commit 846036e40df43448784389e087e8f9397396a57c)

drivers/misc/tegra-profiler/dwarf_unwind.c
drivers/misc/tegra-profiler/hrt.c
drivers/misc/tegra-profiler/hrt.h

index dd04ade..c9214c3 100644 (file)
@@ -121,6 +121,7 @@ struct stackframe {
        unsigned long cfa;
 
        int mode;
+       int is_sched;
 };
 
 struct dwarf_cpu_context {
@@ -1599,6 +1600,7 @@ dwarf_decode_fde_cie(struct ex_region_info *ri,
 
 static void *
 dwarf_find_fde(struct ex_region_info *ri,
+              struct stackframe *sf,
               void *data,
               unsigned long length,
               unsigned long pc,
@@ -1656,8 +1658,9 @@ dwarf_find_fde(struct ex_region_info *ri,
                        start = fde.initial_location;
                        end = start + fde.address_range;
 
-                       quadd_unwind_set_tail_info(ri->vm_start, secid,
-                                                  start, end);
+                       if (sf && !sf->is_sched)
+                               quadd_unwind_set_tail_info(ri->vm_start, secid,
+                                                          start, end);
                }
 
                pr_debug("pc: %#lx, last bst entry: %#lx - %#lx",
@@ -1697,7 +1700,7 @@ __is_fde_entry_exist(struct ex_region_info *ri, unsigned long addr, int is_eh)
 
        hdr_len = ti->length;
 
-       fde_p = dwarf_find_fde(ri, hdr_start, hdr_len, addr, is_eh);
+       fde_p = dwarf_find_fde(ri, NULL, hdr_start, hdr_len, addr, is_eh);
 
        return fde_p ? 1 : 0;
 }
@@ -1726,6 +1729,7 @@ is_fde_entry_exist(struct ex_region_info *ri,
 
 static long
 dwarf_decode(struct ex_region_info *ri,
+            struct stackframe *sf,
             struct dw_cie *cie,
             struct dw_fde *fde,
             unsigned long pc,
@@ -1751,7 +1755,7 @@ dwarf_decode(struct ex_region_info *ri,
        pr_debug("eh frame hdr: %p - %p\n",
                 hdr_start, hdr_start + hdr_len);
 
-       fde_p = dwarf_find_fde(ri, hdr_start, hdr_len, pc, is_eh);
+       fde_p = dwarf_find_fde(ri, sf, hdr_start, hdr_len, pc, is_eh);
        if (!fde_p)
                return -QUADD_URC_IDX_NOT_FOUND;
 
@@ -1804,7 +1808,7 @@ unwind_frame(struct ex_region_info *ri,
        struct regs_state *rs, *rs_initial;
        int mode = sf->mode;
 
-       err = dwarf_decode(ri, &cie, &fde, pc, is_eh);
+       err = dwarf_decode(ri, sf, &cie, &fde, pc, is_eh);
        if (err < 0)
                return err;
 
@@ -2134,6 +2138,7 @@ quadd_get_user_cc_dwarf(struct quadd_event_context *event_ctx,
                                sizeof(u32) : sizeof(u64);
 
        sf->mode = mode;
+       sf->is_sched = event_ctx->is_sched;
        sf->cfa = 0;
 
        vma = find_vma(mm, ip);
index f6d3d6d..748d243 100644 (file)
@@ -43,7 +43,7 @@
 static struct quadd_hrt_ctx hrt;
 
 static void
-read_all_sources(struct pt_regs *regs, struct task_struct *task);
+read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched);
 
 struct hrt_event_value {
        int event_id;
@@ -67,7 +67,7 @@ static enum hrtimer_restart hrtimer_handler(struct hrtimer *hrtimer)
        qm_debug_handler_sample(regs);
 
        if (regs)
-               read_all_sources(regs, current);
+               read_all_sources(regs, current, 0);
 
        hrtimer_forward_now(hrtimer, ns_to_ktime(hrt.sample_period));
        qm_debug_timer_forward(regs, hrt.sample_period);
@@ -348,7 +348,7 @@ get_stack_offset(struct task_struct *task,
 }
 
 static void
-read_all_sources(struct pt_regs *regs, struct task_struct *task)
+read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched)
 {
        u32 state, extra_data = 0, urcs = 0;
        int i, vec_idx = 0, bt_size = 0;
@@ -402,6 +402,7 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task)
        event_ctx.regs = user_regs;
        event_ctx.task = task;
        event_ctx.user_mode = user_mode(regs);
+       event_ctx.is_sched = is_sched;
 
        if (ctx->param.backtrace) {
                cc->um = hrt.um;
@@ -621,7 +622,7 @@ void __quadd_task_sched_out(struct task_struct *prev,
        if (is_sample_process(prev)) {
                user_regs = task_pt_regs(prev);
                if (user_regs)
-                       read_all_sources(user_regs, prev);
+                       read_all_sources(user_regs, prev, 1);
 
                n = remove_active_thread(cpu_ctx, prev->pid);
                atomic_sub(n, &cpu_ctx->nr_active);
index 2b974db..b2e42f6 100644 (file)
@@ -74,7 +74,9 @@ struct pt_regs;
 struct quadd_event_context {
        struct task_struct *task;
        struct pt_regs *regs;
+
        int user_mode;
+       int is_sched;
 };
 
 #define QUADD_HRT_MIN_FREQ     100