diff options
author | Jim Keniston <jkenisto@us.ibm.com> | 2008-05-05 17:03:49 -0700 |
---|---|---|
committer | Jim Keniston <jkenisto@us.ibm.com> | 2008-05-05 17:03:49 -0700 |
commit | 9addf322a677eef2ee0efeca8bc41a9bda58de94 (patch) | |
tree | 6aed722c05e4de268544d211d0b1d321be92593b /tapset/x86_64 | |
parent | 5edbdffdc71747c402b781b2720228406eda7666 (diff) | |
download | systemtap-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.stp | 148 |
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, ®32); + 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; +%} |