#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"
callchain_data->nr = 0;
- if (!regs || !user_mode(regs) || !mm)
+ if (!regs || !mm)
return 0;
if (thumb_mode(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))
#include <linux/cpu.h>
#include <linux/ratelimit.h>
#include <asm/irq_regs.h>
+#include <linux/ptrace.h>
#include <linux/tegra_profiler.h>
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;
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);
{
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;