summaryrefslogtreecommitdiffstats
path: root/tapset/x86_64
diff options
context:
space:
mode:
authorJim Keniston <jkenisto@us.ibm.com>2008-05-05 17:03:49 -0700
committerJim Keniston <jkenisto@us.ibm.com>2008-05-05 17:03:49 -0700
commit9addf322a677eef2ee0efeca8bc41a9bda58de94 (patch)
tree6aed722c05e4de268544d211d0b1d321be92593b /tapset/x86_64
parent5edbdffdc71747c402b781b2720228406eda7666 (diff)
downloadsystemtap-steved-9addf322a677eef2ee0efeca8bc41a9bda58de94.tar.gz
systemtap-steved-9addf322a677eef2ee0efeca8bc41a9bda58de94.tar.xz
systemtap-steved-9addf322a677eef2ee0efeca8bc41a9bda58de94.zip
Replaced [u_]arg() with [u]int_arg(), [u]long_arg(), {s|u}32_arg(),
{s|u}64_arg(), etc. Added asmlinkage(), fastcall(), regparm(). Dealt with some surprises -- e.g., rax is ZERO-extended eax. Seems to work well with -m32 and -m64 user apps, and with a (small) dwarfless subset of syscall.stp.
Diffstat (limited to 'tapset/x86_64')
-rw-r--r--tapset/x86_64/registers.stp148
1 files changed, 115 insertions, 33 deletions
diff --git a/tapset/x86_64/registers.stp b/tapset/x86_64/registers.stp
index 375be396..45acddd1 100644
--- a/tapset/x86_64/registers.stp
+++ b/tapset/x86_64/registers.stp
@@ -1,22 +1,27 @@
/* Return the named register value as a signed value. */
function register:long (name:string) %{ /* pure */
- if (CONTEXT->regs)
- THIS->__retvalue = (int64_t)
- _stp_get_reg64_by_name(THIS->name, CONTEXT->regs);
- else
- THIS->__retvalue = 0;
+ int reg32 = 0;
+ THIS->__retvalue = (int64_t) _stp_get_reg64_by_name(THIS->name,
+ CONTEXT->regs, &reg32);
+ if (reg32)
+ THIS->__retvalue = _stp_sign_extend32(THIS->__retvalue);
%}
/* Return the named register value as an unsigned value. */
-function u_register:long (name:string) {
- return register(name)
-}
+function u_register:long (name:string) %{
+ THIS->__retvalue = (int64_t) _stp_get_reg64_by_name(THIS->name,
+ CONTEXT->regs, NULL);
+%}
-/* Return the value of function arg #argnum (1=first arg) as a signed value. */
-function arg:long (argnum:long) %{
+/*
+ * Return the value of function arg #argnum (1=first arg).
+ * If truncate=1, mask off the top 32 bits.
+ * If sign_extend=1 and (truncate=1 or the probepoint we've hit is in a
+ * 32-bit app), sign-extend the 32-bit value.
+ */
+function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{
long val;
- int result;
- int n;
+ int result, n, nr_regargs;
size_t argsz = sizeof(long);
THIS->__retvalue = 0;
@@ -29,33 +34,46 @@ function arg:long (argnum:long) %{
if (THIS->argnum < 1)
goto bad_argnum;
n = (int) THIS->argnum;
+ nr_regargs = _stp_get_regparm(CONTEXT->regparm, CONTEXT->regs);
if (_stp_probing_32bit_app(CONTEXT->regs)) {
- // TODO: Get nr_regargs from .linkage clause.
argsz = sizeof(int);
- result = _stp_get_arg32_by_number(n, 0, CONTEXT->regs, &val);
- } else {
- // TODO: Get nr_regargs from .linkage clause.
- result = _stp_get_arg64_by_number(n, 6, CONTEXT->regs, &val);
- }
+ result = _stp_get_arg32_by_number(n, nr_regargs, CONTEXT->regs,
+ &val);
+ } else
+ result = _stp_get_arg64_by_number(n, nr_regargs, CONTEXT->regs,
+ &val);
switch (result) {
case 0:
- THIS->__retvalue = (int64_t) val;
+ /* Arg is in register. */
break;
case 1:
- THIS->__retvalue = kread((long *) val);
+ /* Arg is on kernel stack. */
+ val = kread((long *) val);
break;
case 2:
- /*
- * Is copy_from_user satisfactory, since uprobe
- * handlers can block?
- */
- snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
- "arg() not yet implemented for user functions");
- CONTEXT->last_error = CONTEXT->error_buffer;
+ {
+ /* Arg is on user stack. */
+ const char __user *vaddr = (const char __user*) val;
+ if (_stp_copy_from_user((char*)&val, vaddr, argsz) != 0) {
+ /* Stack page not resident. */
+ _stp_warn("cannot access arg(%d) "
+ "at user stack address %p\n", n, vaddr);
+ THIS->__retvalue = 0;
+ return;
+ }
break;
+ }
default:
goto bad_argnum;
}
+ if (THIS->truncate || argsz == sizeof(int)) {
+ if (THIS->sign_extend)
+ THIS->__retvalue = (int64_t) _stp_sign_extend32(val);
+ else
+ /* High bits may be garbage. */
+ THIS->__retvalue = (int64_t) (val & 0xffffffff);
+ } else
+ THIS->__retvalue = (int64_t) val;
return;
bad_argnum:
@@ -77,10 +95,74 @@ function probing_32bit_app() %{
THIS->__retvalue = _stp_probing_32bit_app(CONTEXT->regs);
%}
-/* Return the value of function arg #argnum as an unsigned value. */
-function u_arg:long (argnum:long) {
- if (probing_32bit_app())
- return arg(argnum) & 0xffffffff
- else
- return arg(argnum)
+/* Return the value of function arg #argnum (1=first arg) as a signed int. */
+function int_arg:long (argnum:long) {
+ return _stp_arg(argnum, 1, 1)
+}
+
+/* Return the value of function arg #argnum (1=first arg) as an unsigned int. */
+function uint_arg:long (argnum:long) {
+ return _stp_arg(argnum, 0, 1)
+}
+
+function long_arg:long (argnum:long) {
+ return _stp_arg(argnum, 1, 0)
+}
+
+function ulong_arg:long (argnum:long) {
+ return _stp_arg(argnum, 0, 0)
+}
+
+function longlong_arg:long (argnum:long) {
+ if (probing_32bit_app()) {
+ lowbits = _stp_arg(argnum, 0, 1)
+ highbits = _stp_arg(argnum+1, 0, 1)
+ return ((highbits << 32) | lowbits)
+ } else
+ return _stp_arg(argnum, 0, 0)
+}
+
+function ulonglong_arg:long (argnum:long) {
+ return longlong_arg(argnum)
+}
+
+function pointer_arg:long (argnum:long) {
+ return _stp_arg(argnum, 0, 0)
}
+
+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() {
+}
+
+function fastcall() {
+}
+
+function regparm(n) %{
+ if (_stp_probing_32bit_app(CONTEXT->regs) &&
+ (THIS->n < 0 || THIS->n > 3)) {
+ snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
+ "For -m32 programs, "
+ "regparm value must be in the range 0-3.");
+ CONTEXT->last_error = CONTEXT->error_buffer;
+ } else if (THIS->n < 0 || THIS->n > 6) {
+ snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
+ "For x86_64, regparm value must be in the range 0-6.");
+ CONTEXT->last_error = CONTEXT->error_buffer;
+ } else
+ CONTEXT->regparm = _STP_REGPARM | (int) n;
+%}