From dbb280c79ba5b82f125153f067cbe6fa24aaae0c Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli Date: Thu, 22 May 2008 10:42:35 +0530 Subject: [PATCH] powerpc register+arg access --- ChangeLog | 4 + stapfuncs.5.in | 8 ++ tapset/ppc64/registers.stp | 239 +++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 tapset/ppc64/registers.stp diff --git a/ChangeLog b/ChangeLog index 38d289288..0036b1edf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-05-22 Ananth N Mavinakayanahalli + * tapset/ppc64/registers.stp: Support powerpc register + arg lookup + * stapfuncs.5.in: Add powerpc bits; indicate scope of uarg_* access + 2008-05-20 Frank Ch. Eigler PR 6538 diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 994b8c067..04e5ea17d 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -365,6 +365,11 @@ rip/ip, rsi/si, rsp/sp; 32-bit registers: eax, ebp, ebx, ecx, edx, edi, edx, eip, esi, esp, flags/eflags, orig_eax; segment registers: xcs/cs, xss/ss. + +For powerpc, the following names are recognized: +r1, r2... r31, nip, msr, orig_gpr3, ctr, link, xer, ccr, softe, trap, +dar, dsisr, result; + .TP u_register:long (name:string) Same as register(name), except that @@ -447,6 +452,9 @@ The probed function was built with the gcc \-mregparm=n option. (The i386 kernel is built with \-mregparm=3, so systemtap considers regparm(3) the default for kernel functions on that architecture.) +For some architectures, the *_arg functions may reject unusally high +values of n. + .SS QUEUE_STATS .PP The queue_stats tapset provides functions that, given notifications of diff --git a/tapset/ppc64/registers.stp b/tapset/ppc64/registers.stp new file mode 100644 index 000000000..d3605c051 --- /dev/null +++ b/tapset/ppc64/registers.stp @@ -0,0 +1,239 @@ +/* Dwarfless register access for powerpc */ + +global _reg_offsets, _stp_regs_registered + +function _stp_register_regs() { + /* Same order as pt_regs */ + _reg_offsets["r0"] = 0 + _reg_offsets["r1"] = 8 + _reg_offsets["r2"] = 16 + _reg_offsets["r3"] = 24 + _reg_offsets["r4"] = 32 + _reg_offsets["r5"] = 40 + _reg_offsets["r6"] = 48 + _reg_offsets["r7"] = 56 + _reg_offsets["r8"] = 64 + _reg_offsets["r9"] = 72 + _reg_offsets["r10"] = 80 + _reg_offsets["r11"] = 88 + _reg_offsets["r12"] = 96 + _reg_offsets["r13"] = 104 + _reg_offsets["r14"] = 112 + _reg_offsets["r15"] = 120 + _reg_offsets["r16"] = 128 + _reg_offsets["r17"] = 136 + _reg_offsets["r18"] = 144 + _reg_offsets["r19"] = 152 + _reg_offsets["r20"] = 160 + _reg_offsets["r21"] = 168 + _reg_offsets["r22"] = 176 + _reg_offsets["r23"] = 184 + _reg_offsets["r24"] = 192 + _reg_offsets["r25"] = 200 + _reg_offsets["r26"] = 208 + _reg_offsets["r27"] = 216 + _reg_offsets["r28"] = 224 + _reg_offsets["r29"] = 232 + _reg_offsets["r30"] = 240 + _reg_offsets["r31"] = 248 + _reg_offsets["nip"] = 256 + _reg_offsets["msr"] = 264 + _reg_offsets["orig_gpr3"] = 272 + _reg_offsets["ctr"] = 280 + _reg_offsets["link"] = 288 + _reg_offsets["xer"] = 296 + _reg_offsets["ccr"] = 304 + _reg_offsets["softe"] = 312 + _reg_offsets["trap"] = 320 + _reg_offsets["dar"] = 328 + _reg_offsets["dsisr"] = 336 + _reg_offsets["result"] = 344 + + /* + * If we ever need to support 32bit powerpc, we can + * get to the register offsets by using just a + * reg32_offset = _reg_offsets["reg"]/2 + * or somesuch + */ + _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; +%} + +function _stp_sign_extend32:long (value:long) { + if (value & 0x80000000) + value |= (0xffffffff << 32) + return value +} + +function _stp_probing_32bit_app() %{ + if (!(CONTEXT->regs)) + return 0; + return (user_mode(CONTEXT->regs) && + test_tsk_thread_flag(current, TIF_32BIT)); +%} + +function _stp_register:long (name:string, sign_extend:long) { + if (!_stp_regs_registered) + _stp_register_regs() + offset = _reg_offsets[name] + if (offset == 0 && !(name in _reg_offsets)) { + error("Unknown register: " . name) + return 0 + } + value = _stp_get_register_by_offset(offset) + if (_stp_probing_32bit_app()) { + 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 n; + 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; + + switch (n) { + case 1: + val = u_register("r3"); + break; + case 2: + val = u_register("r4"); + break; + case 3: + val = u_register("r5"); + break; + case 4: + val = u_register("r6"); + break; + case 5: + val = u_register("r7"); + break; + case 6: + val = u_register("r8"); + break; + case 7: + val = u_register("r9"); + break; + case 8: + val = u_register("r10"); + 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; +%} + +/* 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 (_stp_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() %{ + snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "regparm is invalid on powerpc."); + CONTEXT->last_error = CONTEXT->error_buffer; +%} -- 2.43.5