diff options
author | Igor Nabirushkin <inabirushkin@nvidia.com> | 2013-10-24 15:12:53 +0400 |
---|---|---|
committer | Riham Haidar <rhaidar@nvidia.com> | 2013-11-07 12:12:09 -0800 |
commit | 14239d7105ab0d71cf307d3ef7a88a195f63408d (patch) | |
tree | bef763f3edf32eaa9dcb459b7327a041bf7d5de2 | |
parent | a47bc6fd9fd38e7139f36f2686d9d8ad9e32eab3 (diff) |
misc: tegra-profiler: backtraces from the kernel context
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/309768
(cherry picked from commit b5c40f131509f89609283a645f6e9d0b4abed365)
Reviewed-on: http://git-master/r/326027
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r-- | drivers/misc/tegra-profiler/backtrace.c | 16 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/hrt.c | 12 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/main.c | 4 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/quadd_proc.c | 37 | ||||
-rw-r--r-- | drivers/misc/tegra-profiler/version.h | 2 | ||||
-rw-r--r-- | include/linux/tegra_profiler.h | 9 |
6 files changed, 55 insertions, 25 deletions
diff --git a/drivers/misc/tegra-profiler/backtrace.c b/drivers/misc/tegra-profiler/backtrace.c index 340f4faa1405..3191def82ce0 100644 --- a/drivers/misc/tegra-profiler/backtrace.c +++ b/drivers/misc/tegra-profiler/backtrace.c @@ -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(®, (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)) diff --git a/drivers/misc/tegra-profiler/hrt.c b/drivers/misc/tegra-profiler/hrt.c index 0066f3af5520..8bc30727d9bb 100644 --- a/drivers/misc/tegra-profiler/hrt.c +++ b/drivers/misc/tegra-profiler/hrt.c @@ -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); diff --git a/drivers/misc/tegra-profiler/main.c b/drivers/misc/tegra-profiler/main.c index e8856d302d3b..f1ed75cf5833 100644 --- a/drivers/misc/tegra-profiler/main.c +++ b/drivers/misc/tegra-profiler/main.c @@ -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) diff --git a/drivers/misc/tegra-profiler/quadd_proc.c b/drivers/misc/tegra-profiler/quadd_proc.c index dbde7041fa04..980a810f4e40 100644 --- a/drivers/misc/tegra-profiler/quadd_proc.c +++ b/drivers/misc/tegra-profiler/quadd_proc.c @@ -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; diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h index 1b2ecc045aca..32b074609292 100644 --- a/drivers/misc/tegra-profiler/version.h +++ b/drivers/misc/tegra-profiler/version.h @@ -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 */ diff --git a/include/linux/tegra_profiler.h b/include/linux/tegra_profiler.h index 1fda9594ce94..ed21f75e9556 100644 --- a/include/linux/tegra_profiler.h +++ b/include/linux/tegra_profiler.h @@ -20,11 +20,12 @@ #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, |