]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
tegra-profiler: backtraces from the kernel context
authorIgor Nabirushkin <inabirushkin@nvidia.com>
Thu, 24 Oct 2013 11:12:53 +0000 (15:12 +0400)
committerBharat Nihalani <bnihalani@nvidia.com>
Thu, 31 Oct 2013 10:28:31 +0000 (03:28 -0700)
Tegra Profiler: collect backtraces from the kernel context

Bug 1394804

Change-Id: I02ad4d0798802a4515e9f015c83d0dfc1d06ed6d
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/303305
Reviewed-by: Daniel Horowitz <dhorowitz@nvidia.com>
GVS: Gerrit_Virtual_Submit
Tested-by: Maxim Morin <mmorin@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@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 6ac559d4c5cfc8ff2b2facd5b53bcf62ccce95d4..3191def82ce00730509ac2064ea345b4b40d5123 100644 (file)
 #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>
-#include <linux/mm.h>
 
 #include "backtrace.h"
 
@@ -112,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))
@@ -127,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 0066f3af55204c3832ce00ed1334adf73c98c724..1206196fbe74e7b7577b32cf2e9cf0c666514b48 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 = current_pt_regs();
+
+       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 c8a741e9ca2dbb4972d44417a4f188474c6d7d9e..2ee8a8530e1ed0c8b3fb5aac2f7239c6e6c1ab84 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 dbde7041fa0460c215313648de36487c1a37b302..980a810f4e40f9a3a74d7430c4d4c0a07c8fba50 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 1b2ecc045aca786925279f7841abf7ee1604338f..32b0746092927a773eed4f53f16306c6b68afd34 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 1fda9594ce94c691687f99b2574fe4c4a705f160..ed21f75e955609bc248b8d686a002ffecbb6ee0d 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,