summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Nabirushkin <inabirushkin@nvidia.com>2013-10-24 15:12:53 +0400
committerHarry Hong <hhong@nvidia.com>2013-12-10 16:23:02 -0800
commitb8d7347b29a301713bac8f044bfbfa30ae1c6d31 (patch)
treebaf4863833b90771eae54fe3f2c02a5f65489108
parent64bafeb857ee6da6a27aed623535b0a630da53eb (diff)
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/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>
-rw-r--r--drivers/misc/tegra-profiler/backtrace.c16
-rw-r--r--drivers/misc/tegra-profiler/hrt.c12
-rw-r--r--drivers/misc/tegra-profiler/main.c4
-rw-r--r--drivers/misc/tegra-profiler/quadd_proc.c37
-rw-r--r--drivers/misc/tegra-profiler/version.h2
-rw-r--r--include/linux/tegra_profiler.h9
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(&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))
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,