diff options
author | Jim Keniston <jkenisto@us.ibm.com> | 2008-05-12 12:17:20 -0700 |
---|---|---|
committer | Jim Keniston <jkenisto@us.ibm.com> | 2008-05-12 12:17:20 -0700 |
commit | c7fe0041d2132e801f72e158854d54da50fc651d (patch) | |
tree | 258d955ef4a1ead4ba1102812d962c9c981d873b /tapset/x86_64 | |
parent | 8dd6b23de4dd099aa244402192cb3d7be2bda739 (diff) | |
parent | da3fe5fe9641e7c4cc6ae5c4a289ddbc020aca1a (diff) | |
download | systemtap-steved-c7fe0041d2132e801f72e158854d54da50fc651d.tar.gz systemtap-steved-c7fe0041d2132e801f72e158854d54da50fc651d.tar.xz systemtap-steved-c7fe0041d2132e801f72e158854d54da50fc651d.zip |
Merge commit 'origin/dwarfless'
PR 4311 - Function boundary tracing without debuginfo: Phases 1 and 2
Diffstat (limited to 'tapset/x86_64')
-rw-r--r-- | tapset/x86_64/registers.stp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/tapset/x86_64/registers.stp b/tapset/x86_64/registers.stp new file mode 100644 index 00000000..a5aba55a --- /dev/null +++ b/tapset/x86_64/registers.stp @@ -0,0 +1,243 @@ +global _reg_offsets, _r32_offsets, _stp_regs_registered + +function _stp_register_regs() { + /* Same order as pt_regs */ + _reg_offsets["r15"] = 0 + _reg_offsets["r14"] = 8 + _reg_offsets["r13"] = 16 + _reg_offsets["r12"] = 24 + _reg_offsets["rbp"] = 32 _reg_offsets["bp"] = 32 + _reg_offsets["rbx"] = 40 _reg_offsets["bx"] = 40 + _reg_offsets["r11"] = 48 + _reg_offsets["r10"] = 56 + _reg_offsets["r9"] = 64 + _reg_offsets["r8"] = 72 + _reg_offsets["rax"] = 80 _reg_offsets["ax"] = 80 + _reg_offsets["rcx"] = 88 _reg_offsets["cx"] = 88 + _reg_offsets["rdx"] = 96 _reg_offsets["dx"] = 96 + _reg_offsets["rsi"] = 104 _reg_offsets["si"] = 104 + _reg_offsets["rdi"] = 112 _reg_offsets["di"] = 112 + _reg_offsets["orig_rax"] = 120 _reg_offsets["orig_ax"] = 120 + _reg_offsets["rip"] = 128 _reg_offsets["ip"] = 128 + _reg_offsets["xcs"] = 136 _reg_offsets["cs"] = 136 + _reg_offsets["eflags"] = 144 _reg_offsets["flags"] = 144 + _reg_offsets["rsp"] = 152 _reg_offsets["sp"] = 152 + _reg_offsets["xss"] = 160 _reg_offsets["ss"] = 160 + + _r32_offsets["ebp"] = 32 + _r32_offsets["ebx"] = 40 + _r32_offsets["eax"] = 80 + _r32_offsets["ecx"] = 88 + _r32_offsets["edx"] = 96 + _r32_offsets["esi"] = 104 + _r32_offsets["edi"] = 112 + _r32_offsets["orig_eax"] = 120 + _r32_offsets["eip"] = 128 + _r32_offsets["esp"] = 152 + + _stp_regs_registered = 1 +} + +function _stp_get_register_by_offset:long (offset:long) %{ + long value; + memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + THIS->__retvalue = value; +%} + +/* + * _stp_sign_extend32() is callable from a script function. + * __stp_sign_extend32() (in regs.c) is callable from a C function. + */ +function _stp_sign_extend32:long (value:long) %{ + THIS->__retvalue = __stp_sign_extend32(THIS->value); +%} + +function _stp_register:long (name:string, sign_extend:long) { + reg32 = 0 + if (!_stp_regs_registered) + _stp_register_regs() + offset = _reg_offsets[name] + if (offset == 0 && !(name in _reg_offsets)) { + offset = _r32_offsets[name] + if (offset == 0 && !(name in _r32_offsets)) { + error("Unknown register: " . name) + return 0 + } + reg32 = 1 + } + value = _stp_get_register_by_offset(offset) + if (reg32) { + if (sign_extend) + value = _stp_sign_extend32(value) + else + value &= 0xffffffff + } + return value +} + +/* Return the named register value as a signed value. */ +function register:long (name:string) { + return _stp_register(name, 1) +} + +/* + * 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 _stp_register(name, 0) +} + +/* + * 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, n, nr_regargs; + size_t argsz = sizeof(long); + + THIS->__retvalue = 0; + if (!CONTEXT->regs) { + snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "cannot access function args in this context"); + CONTEXT->last_error = CONTEXT->error_buffer; + return; + } + 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)) { + argsz = sizeof(int); + 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: + /* Arg is in register. */ + break; + case 1: + /* Arg is on kernel stack. */ + val = kread((long *) val); + break; + case 2: + { + /* 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: + snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "cannot access arg(%lld)", THIS->argnum); + CONTEXT->last_error = CONTEXT->error_buffer; + return; + + if (0) { +deref_fault: /* branched to from deref() */ + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "kernel fault at %#lx accessing arg(%lld)", val, + THIS->argnum); + CONTEXT->last_error = CONTEXT->error_buffer; + } +%} + +function probing_32bit_app() %{ + THIS->__retvalue = _stp_probing_32bit_app(CONTEXT->regs); +%} + +/* 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; +%} |