/* -*- linux-c -*- * Functions to access the members of pt_regs struct * Copyright (C) 2005, 2007 Red Hat Inc. * Copyright (C) 2005 Intel Corporation. * Copyright (C) 2007 Quentin Barnes. * * This file is part of systemtap, and is free software. You can * redistribute it and/or modify it under the terms of the GNU General * Public License (GPL); either version 2, or (at your option) any * later version. */ #ifndef _REGS_C_ #define _REGS_C_ #include "regs.h" #if defined(__KERNEL__) #include "linux/regs.c" #elif defined(__DYNINST__) #include "dyninst/regs.c" #endif /* Function arguments */ #define _STP_REGPARM 0x8000 #define _STP_REGPARM_MASK ((_STP_REGPARM) - 1) /* * x86_64 and i386 are especially ugly because: * 1) the pt_reg member names changed as part of the x86 merge. We use * either the pre-merge name or the post-merge name, as needed. * 2) -m32 apps on x86_64 look like i386 apps, so we need to support * those semantics on both i386 and x86_64. */ #ifdef __i386__ static long _stp_get_sp(struct pt_regs *regs) { if (!user_mode(regs)) return (long) &EREG(sp, regs); return EREG(sp, regs); } #endif /* __i386__ */ #ifdef __x86_64__ static long _stp_get_sp(struct pt_regs *regs) { return RREG(sp, regs); } #endif /* __x86_64__ */ #if defined(__x86_64__) || defined(__ia64__) || defined(__i386__) /* Ensure that the upper 32 bits of val are a sign-extension of the lower 32. */ static int64_t __stp_sign_extend32(int64_t val) { int32_t *val_ptr32 = (int32_t*) &val; return *val_ptr32; } /* Ensure that the upper 48 bits of val are a sign-extension of the lower 16. */ static int64_t __stp_sign_extend16(int64_t val) { int16_t *val_ptr16 = (int16_t*) &val; return *val_ptr16; } /* Ensure that the upper 56 bits of val are a sign-extension of the lower 8. */ static int64_t __stp_sign_extend8(int64_t val) { int8_t *val_ptr8 = (int8_t*) &val; return *val_ptr8; } #endif /* __x86_64__ || __ia64__ || __i386__ */ #if defined(__i386__) || defined(__x86_64__) /* * Use this for i386 kernel and apps, and for 32-bit apps running on x86_64. * Does arch-specific work for fetching function arg #argnum (1 = first arg). * nr_regargs is the number of arguments that reside in registers (e.g., * 3 for fastcall functions). * Returns: * 0 if the arg resides in a register. *val contains its value. * 1 if the arg resides on the kernel stack. *val contains its address. * 2 if the arg resides on the user stack. *val contains its address. * -1 if the arg number is invalid. * We assume that the regs pointer is valid. */ #if defined(__i386__) #define ERREG(nm, regs) EREG(nm, regs) #else /* x86_64 */ #define ERREG(nm, regs) RREG(nm, regs) #endif static int _stp_get_arg32_by_number(int n, int nr_regargs, struct pt_regs *regs, long *val) { if (nr_regargs < 0) return -1; if (n > nr_regargs) { /* * The typical case: arg n is on the stack. * stack[0] = return address */ int stack_index = n - nr_regargs; int32_t *stack = (int32_t*) _stp_get_sp(regs); *val = (long) &stack[stack_index]; return (user_mode(regs) ? 2 : 1); } else { switch (n) { case 1: *val = (int32_t)(ERREG(ax, regs)); break; case 2: *val = (int32_t)(ERREG(dx, regs)); break; case 3: *val = (int32_t)(ERREG(cx, regs)); break; default: /* gcc rejects regparm values > 3. */ return -1; } return 0; } } #endif /* __i386__ || __x86_64__ */ #ifdef __x86_64__ /* See _stp_get_arg32_by_number(). */ static int _stp_get_arg64_by_number(int n, int nr_regargs, struct pt_regs *regs, unsigned long *val) { if (nr_regargs < 0) return -1; if (n > nr_regargs) { /* arg n is on the stack. stack[0] = return address */ int stack_index = n - nr_regargs; unsigned long *stack = (unsigned long*) _stp_get_sp(regs); *val = (unsigned long) &stack[stack_index]; return (user_mode(regs) ? 2 : 1); } else { switch (n) { case 1: *val = RREG(di, regs); break; case 2: *val = RREG(si, regs); break; case 3: *val = RREG(dx, regs); break; case 4: *val = RREG(cx, regs); break; case 5: *val = regs->r8; break; case 6: *val = regs->r9; break; default: /* gcc rejects regparm values > 6. */ return -1; } return 0; } } #endif /* __x86_64__ */ /** @} */ #endif /* _REGS_C_ */