tegra-profiler: backtraces from the kernel context
Igor Nabirushkin [Thu, 24 Oct 2013 11:12:53 +0000 (15:12 +0400)]
Tegra Profiler: collect backtraces from the kernel context

Bug 1394804

Change-Id: I1db7435c9e1fc753dd8c02252076287572f5f5af
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/324091
(cherry picked from commit f7213f6e694089f866ccfcbca02c1e61648048db)
Reviewed-on: http://git-master/r/340016
Reviewed-by: Harry Hong <hhong@nvidia.com>
Tested-by: Harry Hong <hhong@nvidia.com>

drivers/misc/tegra-profiler/backtrace.c
drivers/misc/tegra-profiler/hrt.c
drivers/misc/tegra-profiler/main.c
drivers/misc/tegra-profiler/quadd_proc.c
drivers/misc/tegra-profiler/version.h
include/linux/tegra_profiler.h

index 340f4fa..3191def 100644 (file)
@@ -17,7 +17,9 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/module.h>
-#include <asm-generic/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
 
 #include <linux/tegra_profiler.h>
 
@@ -111,7 +113,7 @@ quadd_get_user_callchain(struct pt_regs *regs,
 
        callchain_data->nr = 0;
 
-       if (!regs || !user_mode(regs) || !mm)
+       if (!regs || !mm)
                return 0;
 
        if (thumb_mode(regs))
@@ -126,12 +128,18 @@ quadd_get_user_callchain(struct pt_regs *regs,
                return 0;
 
        vma = find_vma(mm, sp);
+       if (!vma)
+               return 0;
+
        if (check_vma_address(fp, vma))
                return 0;
 
-       if (__copy_from_user_inatomic(&reg, (unsigned long __user *)fp,
-                                     sizeof(unsigned long)))
+       if (probe_kernel_address(fp, reg)) {
+               pr_warn_once("frame error: sp/fp: %#lx/%#lx, pc/lr: %#lx/%#lx, vma: %#lx-%#lx\n",
+                            sp, fp, regs->ARM_pc, regs->ARM_lr,
+                            vma->vm_start, vma->vm_end);
                return 0;
+       }
 
        if (thumb_mode(regs)) {
                if (reg <= fp || check_vma_address(reg, vma))
index 0066f3a..8bc3072 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/cpu.h>
 #include <linux/ratelimit.h>
 #include <asm/irq_regs.h>
+#include <linux/ptrace.h>
 
 #include <linux/tegra_profiler.h>
 
@@ -241,6 +242,7 @@ static void read_source(struct quadd_event_source_interface *source,
        struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
        struct quadd_callchain *callchain_data = &cpu_ctx->callchain_data;
        struct quadd_ctx *quadd_ctx = hrt.quadd_ctx;
+       struct pt_regs *user_regs;
 
        if (!source)
                return;
@@ -256,8 +258,14 @@ static void read_source(struct quadd_event_source_interface *source,
        if (atomic_read(&cpu_ctx->nr_active) == 0)
                return;
 
-       if (user_mode(regs) && hrt.quadd_ctx->param.backtrace) {
-               callchain_nr = quadd_get_user_callchain(regs, callchain_data);
+       if (user_mode(regs))
+               user_regs = regs;
+       else
+               user_regs = task_pt_regs(current);
+
+       if (hrt.quadd_ctx->param.backtrace) {
+               callchain_nr =
+                       quadd_get_user_callchain(user_regs, callchain_data);
                if (callchain_nr > 0) {
                        extra_data = (char *)cpu_ctx->callchain_data.callchain;
                        extra_length = callchain_nr * sizeof(u32);
index e8856d3..f1ed75c 100644 (file)
@@ -246,6 +246,7 @@ static int set_parameters(struct quadd_parameters *param, uid_t *debug_app_uid)
 static void get_capabilities(struct quadd_comm_cap *cap)
 {
        int i, event;
+       unsigned int extra = 0;
        struct quadd_events_cap *events_cap = &cap->events_cap;
 
        cap->pmu = ctx.pmu ? 1 : 0;
@@ -357,6 +358,9 @@ static void get_capabilities(struct quadd_comm_cap *cap)
        cap->tegra_lp_cluster = quadd_is_cpu_with_lp_cluster();
        cap->power_rate = 1;
        cap->blocked_read = 1;
+
+       extra |= QUADD_COMM_CAP_EXTRA_BT_KERNEL_CTX;
+       cap->reserved[QUADD_COMM_CAP_IDX_EXTRA] = extra;
 }
 
 void quadd_get_state(struct quadd_module_state *state)
index dbde704..980a810 100644 (file)
@@ -56,47 +56,50 @@ static int show_capabilities(struct seq_file *f, void *offset)
 {
        struct quadd_comm_cap *cap = &ctx->cap;
        struct quadd_events_cap *event = &cap->events_cap;
+       unsigned int extra = cap->reserved[QUADD_COMM_CAP_IDX_EXTRA];
 
-       seq_printf(f, "pmu:                    %s\n",
+       seq_printf(f, "pmu:                           %s\n",
                   YES_NO(cap->pmu));
-       seq_printf(f, "tegra 3 LP cluster:     %s\n",
+       seq_printf(f, "tegra 3 LP cluster:            %s\n",
                   YES_NO(cap->tegra_lp_cluster));
-       seq_printf(f, "power rate samples:     %s\n",
+       seq_printf(f, "power rate samples:            %s\n",
                   YES_NO(cap->power_rate));
 
-       seq_printf(f, "l2 cache:               %s\n",
+       seq_printf(f, "l2 cache:                      %s\n",
                   YES_NO(cap->l2_cache));
        if (cap->l2_cache) {
-               seq_printf(f, "Multiple l2 events:     %s\n",
+               seq_printf(f, "multiple l2 events:            %s\n",
                           YES_NO(cap->l2_multiple_events));
        }
 
-       seq_printf(f, "support polling mode:   %s\n",
+       seq_printf(f, "support polling mode:          %s\n",
                   YES_NO(cap->blocked_read));
+       seq_printf(f, "backtrace from the kernel ctx: %s\n",
+                  YES_NO(extra & QUADD_COMM_CAP_EXTRA_BT_KERNEL_CTX));
 
        seq_puts(f, "\n");
        seq_puts(f, "Supported events:\n");
-       seq_printf(f, "cpu_cycles:             %s\n",
+       seq_printf(f, "cpu_cycles:                    %s\n",
                   YES_NO(event->cpu_cycles));
-       seq_printf(f, "instructions:           %s\n",
+       seq_printf(f, "instructions:                  %s\n",
                   YES_NO(event->instructions));
-       seq_printf(f, "branch_instructions:    %s\n",
+       seq_printf(f, "branch_instructions:           %s\n",
                   YES_NO(event->branch_instructions));
-       seq_printf(f, "branch_misses:          %s\n",
+       seq_printf(f, "branch_misses:                 %s\n",
                   YES_NO(event->branch_misses));
-       seq_printf(f, "bus_cycles:             %s\n",
+       seq_printf(f, "bus_cycles:                    %s\n",
                   YES_NO(event->bus_cycles));
-       seq_printf(f, "l1_dcache_read_misses:  %s\n",
+       seq_printf(f, "l1_dcache_read_misses:         %s\n",
                   YES_NO(event->l1_dcache_read_misses));
-       seq_printf(f, "l1_dcache_write_misses: %s\n",
+       seq_printf(f, "l1_dcache_write_misses:        %s\n",
                   YES_NO(event->l1_dcache_write_misses));
-       seq_printf(f, "l1_icache_misses:       %s\n",
+       seq_printf(f, "l1_icache_misses:              %s\n",
                   YES_NO(event->l1_icache_misses));
-       seq_printf(f, "l2_dcache_read_misses:  %s\n",
+       seq_printf(f, "l2_dcache_read_misses:         %s\n",
                   YES_NO(event->l2_dcache_read_misses));
-       seq_printf(f, "l2_dcache_write_misses: %s\n",
+       seq_printf(f, "l2_dcache_write_misses:        %s\n",
                   YES_NO(event->l2_dcache_write_misses));
-       seq_printf(f, "l2_icache_misses:       %s\n",
+       seq_printf(f, "l2_icache_misses:              %s\n",
                   YES_NO(event->l2_icache_misses));
 
        return 0;
index 1b2ecc0..32b0746 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __QUADD_VERSION_H
 #define __QUADD_VERSION_H
 
-#define QUADD_MODULE_VERSION           "1.36"
+#define QUADD_MODULE_VERSION           "1.37"
 #define QUADD_MODULE_BRANCH            "Dev"
 
 #endif /* __QUADD_VERSION_H */
index 1fda959..ed21f75 100644 (file)
 #include <linux/ioctl.h>
 
 #define QUADD_SAMPLES_VERSION  17
-#define QUADD_IO_VERSION       7
+#define QUADD_IO_VERSION       8
 
 #define QUADD_IO_VERSION_DYNAMIC_RB            5
 #define QUADD_IO_VERSION_RB_MAX_FILL_COUNT     6
 #define QUADD_IO_VERSION_MOD_STATE_STATUS_FIELD        7
+#define QUADD_IO_VERSION_BT_KERNEL_CTX         8
 
 #define QUADD_SAMPLE_VERSION_THUMB_MODE_FLAG   17
 
@@ -275,6 +276,12 @@ struct quadd_events_cap {
                l2_icache_misses:1;
 };
 
+enum {
+       QUADD_COMM_CAP_IDX_EXTRA = 0,
+};
+
+#define QUADD_COMM_CAP_EXTRA_BT_KERNEL_CTX     (1 << 0)
+
 struct quadd_comm_cap {
        u32     pmu:1,
                power_rate:1,