????
| Current Path : /usr/share/systemtap/tapset/arm/ |
| Current File : //usr/share/systemtap/tapset/arm/registers.stp |
/* Dwarfless register access for arm */
%{
// These functions are largely lifted from arch/arm/kernel/ptrace.c.
static inline unsigned long _stp_kernel_stack_pointer(struct pt_regs *regs)
{
return regs->ARM_sp;
}
/*
* _stp_regs_within_kernel_stack() - check the address in the stack
* @regs: pt_regs which contains kernel stack pointer.
* @addr: address which is checked.
*
* _stp_regs_within_kernel_stack() checks @addr is within the kernel
* stack page(s). If @addr is within the kernel stack, it returns
* true. If not, returns false.
*/
bool _stp_regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
{
return ((addr & ~(THREAD_SIZE - 1)) ==
(_stp_kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
}
/*
* _stp_regs_get_kernel_stack_nth_addr() - get address of the Nth entry of the stack
* @regs: pt_regs which contains kernel stack pointer.
* @n: stack entry number.
*
* _stp_regs_get_kernel_stack_nth_addr() returns the address of the @n
* th entry of the kernel stack which is specified by @regs. If the @n
* th entry is NOT in the kernel stack, this returns 0.
*/
long *
_stp_regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsigned int n)
{
long *addr = (unsigned long *)_stp_kernel_stack_pointer(regs);
addr += n;
if (_stp_regs_within_kernel_stack(regs, (unsigned long)addr))
return addr;
else
return 0;
}
%}
@__private30 global _reg_offsets[30]
probe init {
/* Same order as pt_regs */
_reg_offsets["r0"] = 0 _reg_offsets["a1"] = 0
_reg_offsets["r1"] = 4 _reg_offsets["a2"] = 4
_reg_offsets["r2"] = 8 _reg_offsets["a3"] = 8
_reg_offsets["r3"] = 12 _reg_offsets["a4"] = 12
_reg_offsets["r4"] = 16 _reg_offsets["v1"] = 16
_reg_offsets["r5"] = 20 _reg_offsets["v2"] = 20
_reg_offsets["r6"] = 24 _reg_offsets["v3"] = 24
_reg_offsets["r7"] = 28 _reg_offsets["v4"] = 28
_reg_offsets["r8"] = 32 _reg_offsets["v5"] = 32
_reg_offsets["r9"] = 36 _reg_offsets["v6"] = 36
_reg_offsets["r10"] = 40 _reg_offsets["v7"] = 40
_reg_offsets["fp"] = 44 _reg_offsets["v8"] = 44
_reg_offsets["ip"] = 48
_reg_offsets["sp"] = 52
_reg_offsets["lr"] = 56
_reg_offsets["pc"] = 60
_reg_offsets["cpsr"] = 64
_reg_offsets["orig_r0"] = 68
}
function _stp_get_register_by_offset:long (offset:long) %{ /* pure */
long value;
struct pt_regs *regs;
if (CONTEXT->user_mode_p) {
regs = CONTEXT->uregs;
} else {
regs = CONTEXT->kregs;
}
if (!regs) {
CONTEXT->last_error = "No registers available in this context";
return;
}
if (STAP_ARG_offset < 0 || STAP_ARG_offset > sizeof(struct pt_regs) - sizeof(long)) {
snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
"Bad register offset: %lld", STAP_ARG_offset);
CONTEXT->last_error = CONTEXT->error_buffer;
return;
}
memcpy(&value, ((char *)regs) + STAP_ARG_offset, sizeof(value));
STAP_RETVALUE = value;
%}
function _stp_probing_kernel:long () {
return !user_mode();
}
function arch_bytes:long() %{ /* pure */
STAP_RETVALUE = sizeof(long);
%}
function uarch_bytes:long() {
assert(user_mode(), "requires user mode")
return 4
}
/* Return the named register value as a signed value. */
function register:long (name:string) {
assert(registers_valid(), "cannot access CPU registers in this context")
offset = _reg_offsets[name]
assert(offset != 0 || (name in _reg_offsets), "Unknown register: " . name)
return _stp_get_register_by_offset(offset)
}
/*
* Return the named register value as an unsigned value. Specifically,
* don't sign-extend the register value when promoting it to 64 bits.
*/
function u_register:long (name:string) {
return register(name) & 0xffffffff;
}
function _stp_get_stack_nth:long (n:long)
%{ /* pure */
__label__ deref_fault;
unsigned int n = (unsigned int)STAP_ARG_n;
struct pt_regs *regs;
long *addr;
STAP_RETVALUE = 0;
if (CONTEXT->user_mode_p) {
// This function only handles kernel arguments off the stack.
snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
"cannot access function args in this context");
CONTEXT->last_error = CONTEXT->error_buffer;
return;
}
regs = CONTEXT->kregs;
if (!regs) {
snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
"cannot access function args in this context");
CONTEXT->last_error = CONTEXT->error_buffer;
return;
}
/* Get the address of the nth item on the stack. */
addr = _stp_regs_get_kernel_stack_nth_addr(regs, n);
if (addr == NULL) {
snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
"cannot access stack arg(%d)", n);
CONTEXT->last_error = CONTEXT->error_buffer;
return;
}
STAP_RETVALUE = kread(addr);
return;
deref_fault: /* branched to from kread() */
snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
"kernel fault at %#lx accessing stack arg(%d)",
(unsigned long)addr, n);
CONTEXT->last_error = CONTEXT->error_buffer;
%}
/* Return the value of function arg #argnum (1=first arg) as a signed value.
*
* We don't yet support extracting arg #5 and beyond, which are passed
* on stack
*/
function _stp_arg:long (argnum:long) {
val = 0
assert(!(argnum < 1 || argnum > 7), sprintf("Cannot access arg(%d)", argnum))
if (argnum == 1)
val = register("r0")
else if (argnum == 2)
val = register("r1")
else if (argnum == 3)
val = register("r2")
else if (argnum == 4)
val = register("r3")
else
val = _stp_get_stack_nth(argnum - 5)
return val;
}
/* Return the value of function arg #argnum as a signed int. */
function int_arg:long (argnum:long) {
return _stp_arg(argnum)
}
/* Return the value of function arg #argnum as an unsigned int. */
function uint_arg:long (argnum:long) {
return _stp_arg(argnum) & 0xffffffff;
}
function long_arg:long (argnum:long) {
return int_arg(argnum)
}
function ulong_arg:long (argnum:long) {
return uint_arg(argnum)
}
function longlong_arg:long (argnum:long) {
/*
* gcc has a few odd rules:
* 1) If argnum == 2, the 64-bit arg will start with arg 3.
* 2) If argnum == nr_regarg (4), gcc puts the whole 64-bit
* arg on the stack.
*
* Note that following argument numbers will need to be
* adjusted.
*/
if (argnum == 2 || argnum == 4)
argnum++
lowbits = uint_arg(argnum)
highbits = uint_arg(argnum+1)
return ((highbits << 32) | lowbits)
}
function ulonglong_arg:long (argnum:long) {
return longlong_arg(argnum)
}
function pointer_arg:long (argnum:long) {
return ulong_arg(argnum)
}
function s32_arg:long (argnum:long) {
return int_arg(argnum)
}
function u32_arg:long (argnum:long) {
return uint_arg(argnum)
}
function s64_arg:long (argnum:long) {
return longlong_arg(argnum)
}
function u64_arg:long (argnum:long) {
return ulonglong_arg(argnum)
}
function asmlinkage() %{ /* pure */ %}
function fastcall() %{ /* pure */ %}
function regparm(n:long) %{
snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
"regparm is invalid on arm.");
CONTEXT->last_error = CONTEXT->error_buffer;
%}