// SPDX-License-Identifier: GPL-2.0
/*
* ARM callchain support
*
* Copyright ( C ) 2009 picoChip Designs , Ltd . , Jamie Iles
* Copyright ( C ) 2010 ARM Ltd . , Will Deacon < will . deacon @ arm . com >
*
* This code is based on the ARM OProfile backtrace code .
*/
#include <linux/perf_event.h>
#include <linux/uaccess.h>
#include <asm /stacktrace.h>
/*
* The registers we ' re interested in are at the end of the variable
* length saved register structure . The fp points at the end of this
* structure so the address of this struct is :
* ( struct frame_tail * ) ( xxx - > fp ) - 1
*
* This code has been adapted from the ARM OProfile support .
*/
struct frame_tail {
struct frame_tail __user *fp;
unsigned long sp;
unsigned long lr;
} __attribute__((packed));
/*
* Get the return address for a single stackframe and return a pointer to the
* next frame tail .
*/
static struct frame_tail __user *
user_backtrace(struct frame_tail __user *tail,
struct perf_callchain_entry_ctx *entry)
{
struct frame_tail buftail;
unsigned long err;
if (!access_ok(tail, sizeof (buftail)))
return NULL;
pagefault_disable();
err = __copy_from_user_inatomic(&buftail, tail, sizeof (buftail));
pagefault_enable();
if (err)
return NULL;
perf_callchain_store(entry, buftail.lr);
/*
* Frame pointers should strictly progress back up the stack
* ( towards higher addresses ) .
*/
if (tail + 1 >= buftail.fp)
return NULL;
return buftail.fp - 1 ;
}
void
perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
{
struct frame_tail __user *tail;
perf_callchain_store(entry, regs->ARM_pc);
if (!current->mm)
return ;
tail = (struct frame_tail __user *)regs->ARM_fp - 1 ;
while ((entry->nr < entry->max_stack) &&
tail && !((unsigned long )tail & 0 x3))
tail = user_backtrace(tail, entry);
}
/*
* Gets called by walk_stackframe ( ) for every stackframe . This will be called
* whist unwinding the stackframe and is like a subroutine return so we use
* the PC .
*/
static bool
callchain_trace(void *data, unsigned long pc)
{
struct perf_callchain_entry_ctx *entry = data;
return perf_callchain_store(entry, pc) == 0 ;
}
void
perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
{
struct stackframe fr;
arm_get_current_stackframe(regs, &fr);
walk_stackframe(&fr, callchain_trace, entry);
}
Messung V0.5 in Prozent C=95 H=91 G=92
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland