summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2008-05-22 10:42:35 +0530
committerAnanth N Mavinakayanahalli <ananth@in.ibm.com>2008-05-22 10:42:35 +0530
commitdbb280c79ba5b82f125153f067cbe6fa24aaae0c (patch)
tree655cc1c6bbd8992a35bbbb66f65c6bd655bd8185
parentaa8a3b1797da54a14d04cd57758a65064056376e (diff)
downloadsystemtap-steved-dbb280c79ba5b82f125153f067cbe6fa24aaae0c.tar.gz
systemtap-steved-dbb280c79ba5b82f125153f067cbe6fa24aaae0c.tar.xz
systemtap-steved-dbb280c79ba5b82f125153f067cbe6fa24aaae0c.zip
powerpc register+arg access
-rw-r--r--ChangeLog4
-rw-r--r--stapfuncs.5.in8
-rw-r--r--tapset/ppc64/registers.stp239
3 files changed, 251 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 38d28928..0036b1ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2008-05-22 Ananth N Mavinakayanahalli <ananth@in.ibm.com>
+ * 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 <fche@elastic.org>
PR 6538
diff --git a/stapfuncs.5.in b/stapfuncs.5.in
index 994b8c06..04e5ea17 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 00000000..d3605c05
--- /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;
+%}