From d9aed31e5e4e35fc37d8f2c67def982c1389bd92 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Fri, 16 Sep 2011 14:33:06 +0200 Subject: [PATCH] Split kregs and uregs in probe context. Keep track of kernel registers and user registers for a probe context separately in anticipation of k/uregs "recovery". This patch simply replaces the regs field of common_probe_context.h with a kregs and uregs field, plus changes all over to use one or the other to store or fetch the appropriate registers. --- runtime/common_probe_context.h | 10 +++-- runtime/loc2c-runtime.h | 82 ++++++++++++++++++++-------------- runtime/stack.c | 9 ++-- tapset-itrace.cxx | 2 +- tapset-perfmon.cxx | 9 ++-- tapset-timers.cxx | 8 +++- tapset-utrace.cxx | 2 +- tapset/arm/registers.stp | 10 ++++- tapset/context-symbols.stp | 26 ++++++----- tapset/context.stp | 18 +++++--- tapset/errno.stp | 20 +++++++-- tapset/i386/registers.stp | 20 ++++++--- tapset/powerpc/registers.stp | 10 +++-- tapset/s390/registers.stp | 14 +++--- tapset/syscalls2.stp | 2 +- tapset/utrace.stp | 12 ++--- tapset/x86_64/registers.stp | 28 +++++++----- tapsets.cxx | 36 ++++++++------- 18 files changed, 200 insertions(+), 118 deletions(-) diff --git a/runtime/common_probe_context.h b/runtime/common_probe_context.h index fff16d2ba..df07b90c1 100644 --- a/runtime/common_probe_context.h +++ b/runtime/common_probe_context.h @@ -63,10 +63,12 @@ const char *last_error; /* Last statement (token) executed. Often set together with last_error. */ const char *last_stmt; -/* Set when probe handler gets pt_regs handed to it. This can be either - the kernel registers or the user space registers. The probe_flags field - will indicate which and whether the user registers are complete. */ -struct pt_regs *regs; +/* Set when probe handler gets pt_regs handed to it. kregs holds the kernel + registers when availble. uregs holds the user registers when available. + uregs are at least available when probe_flags contains + _STP_PROBE_STATE_USER_MODE. */ +struct pt_regs *kregs; +struct pt_regs *uregs; /* unwaddr is caching unwound address in each probe handler on ia64. */ #if defined __ia64__ diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index e36a38f80..ef7d279e8 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -44,10 +44,15 @@ can be pasted into an identifier name. These definitions turn it into a per-register macro, defined below for machines with individually-named registers. */ +#define pt_regs_fetch_register(pt_regs, regno) \ + ((intptr_t) k_dwarf_register_##regno (pt_regs)) +#define pt_regs_store_register(pt_regs, regno, value) \ + (k_dwarf_register_##regno (pt_regs) = (value)) + #define k_fetch_register(regno) \ - ((intptr_t) k_dwarf_register_##regno (c->regs)) + pt_regs_fetch_register(c->kregs, regno) #define k_store_register(regno, value) \ - (k_dwarf_register_##regno (c->regs) = (value)) + pt_regs_store_register(c->kregs, regno, value) /* The deref and store_deref macros are called to safely access addresses @@ -104,7 +109,11 @@ a % b; \ }) -/* PR 10601: user-space (user_regset) register access. */ +/* PR 10601: user-space (user_regset) register access. + Needs arch specific code, only i386 and x86_64 for now. */ +#if ((defined(STAPCONF_REGSET) || defined(STAPCONF_UTRACE_REGSET)) \ + && (defined (__i386__) || defined (__x86_64__))) + #if defined(STAPCONF_REGSET) #include #endif @@ -117,8 +126,6 @@ #define task_user_regset_view utrace_native_view #endif -#if defined(STAPCONF_REGSET) || defined(STAPCONF_UTRACE_REGSET) - struct usr_regset_lut { char *name; unsigned rsn; @@ -130,6 +137,7 @@ struct usr_regset_lut { The register numbers come from the processor-specific ELF documents. The user-regset bank/offset values come from kernel $ARCH/include/asm/user*.h or $ARCH/kernel/ptrace.c. */ +#if defined (__i386__) || defined (__x86_64__) static const struct usr_regset_lut url_i386[] = { { "ax", NT_PRSTATUS, 6*4 }, { "cx", NT_PRSTATUS, 1*4 }, @@ -141,7 +149,9 @@ static const struct usr_regset_lut url_i386[] = { { "di", NT_PRSTATUS, 4*4 }, { "ip", NT_PRSTATUS, 12*4 }, }; +#endif +#if defined (__x86_64__) static const struct usr_regset_lut url_x86_64[] = { { "rax", NT_PRSTATUS, 10*8 }, { "rdx", NT_PRSTATUS, 12*8 }, @@ -165,6 +175,7 @@ static const struct usr_regset_lut url_x86_64[] = { /* XXX: FP registers %st0-%st7 */ /* XXX: MMX registers %mm0-%mm7 */ }; +#endif /* XXX: insert other architectures here. */ @@ -316,22 +327,17 @@ static void ursl_store64 (const struct usr_regset_lut* lut,unsigned lutsize, in #elif defined (__x86_64__) -#define u_fetch_register(regno) (_stp_probing_32bit_app(c->regs) ? ursl_fetch32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno) : ursl_fetch64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno)) -#define u_store_register(regno,value) (_stp_probing_32bit_app(c->regs) ? ursl_store32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno, value) : ursl_store64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno, value)) - -#else - -/* Some other architecture; downgrade to kernel register access. */ -#define u_fetch_register(regno) k_fetch_register(regno) -#define u_store_register(regno,value) k_store_register(regno,value) +#define u_fetch_register(regno) (_stp_probing_32bit_app(c->uregs) ? ursl_fetch32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno) : ursl_fetch64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno)) +#define u_store_register(regno,value) (_stp_probing_32bit_app(c->uregs) ? ursl_store32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno, value) : ursl_store64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno, value)) #endif - #else /* ! STAPCONF_REGSET */ -/* Downgrade to kernel register access. */ -#define u_fetch_register(regno) k_fetch_register(regno) -#define u_store_register(regno,value) k_store_register(regno,value) +/* Downgrade to k_dwarf_register access. */ +#define u_fetch_register(regno) \ + pt_regs_fetch_register(c->uregs, regno) +#define u_store_register(regno, value) \ + pt_regs_store_register(c->uregs, regno, value) #endif @@ -383,11 +389,14 @@ static void ursl_store64 (const struct usr_regset_lut* lut,unsigned lutsize, in #define k_dwarf_register_7(regs) regs->edi #elif defined __ia64__ -#undef k_fetch_register -#undef k_store_register -#define k_fetch_register(regno) ia64_fetch_register(regno, c->regs, &c->unwaddr) -#define k_store_register(regno,value) ia64_store_register(regno, c->regs, value) +#undef pt_regs_fetch_register +#undef pt_regs_store_register + +#define pt_regs_fetch_register(pt_regs,(regno) \ + ia64_fetch_register(regno, pt_regs, &c->unwaddr) +#define pt_regs_store_register(pt_regs,regno,value) \ + ia64_store_register(regno, pt_regs, value) #elif defined __x86_64__ @@ -410,23 +419,30 @@ static void ursl_store64 (const struct usr_regset_lut* lut,unsigned lutsize, in #elif defined __powerpc__ -#undef k_fetch_register -#undef k_store_register -#define k_fetch_register(regno) ((intptr_t) c->regs->gpr[regno]) -#define k_store_register(regno,value) (c->regs->gpr[regno] = (value)) +#undef pt_regs_fetch_register +#undef pt_regs_store_register +#define pt_regs_fetch_register(pt_regs,regno) \ + ((intptr_t) pt_regs->gpr[regno]) +#define pt_regs_store_register(pt_regs,regno,value) \ + (pt_regs->gpr[regno] = (value)) #elif defined (__arm__) -#undef k_fetch_register -#undef k_store_register -#define k_fetch_register(regno) ((long) c->regs->uregs[regno]) -#define k_store_register(regno,value) (c->regs->uregs[regno] = (value)) +#undef pt_regs_fetch_register +#undef pt_regs_store_register +#define pt_regs_fetch_register(pt_regs,regno) \ + ((long) pt_regs->uregs[regno]) +#define pt_regs_store_register(pt_regs,regno,value) \ + (pt_regs->uregs[regno] = (value)) #elif defined (__s390__) || defined (__s390x__) -#undef k_fetch_register -#undef k_store_register -#define k_fetch_register(regno) ((intptr_t) c->regs->gprs[regno]) -#define k_store_register(regno,value) (c->regs->gprs[regno] = (value)) + +#undef pt_regs_fetch_register +#undef pt_regs_store_register +#define pt_regs_fetch_register(pt_regs,regno) \ + ((intptr_t) pt_regs->gprs[regno]) +#define pt_regs_store_register(pt_regs,regno,value) \ + (pt_regs->gprs[regno] = (value)) #endif diff --git a/runtime/stack.c b/runtime/stack.c index 4dfb4b219..62836bebd 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -167,8 +167,7 @@ static void _stp_stack_print(struct context *c, int sym_flags, int stack_flags) ri = NULL; if (stack_flags == _STP_STACK_KERNEL) { - if (! c->regs - || (c->probe_flags & _STP_PROBE_STATE_USER_MODE)) { + if (! c->kregs) { /* For the kernel we can use an inexact fallback. When compiled with frame pointers we can do a pretty good guess at the stack value, @@ -195,15 +194,15 @@ static void _stp_stack_print(struct context *c, int sym_flags, int stack_flags) #endif return; } else { - regs = c->regs; + regs = c->kregs; ri = NULL; /* This is a hint for GCC so that it can eliminate the call to uprobe_get_pc() in __stp_stack_print() below. */ } } else if (stack_flags == _STP_STACK_USER) { /* use task_pt_regs, regs might be kernel regs, or not set. */ - if (c->regs && (c->probe_flags & _STP_PROBE_STATE_USER_MODE)) { - regs = c->regs; + if (c->uregs && (c->probe_flags & _STP_PROBE_STATE_USER_MODE)) { + regs = c->uregs; uregs_valid = 1; } else { regs = task_pt_regs(current); diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx index b576b1de0..7efd73a39 100644 --- a/tapset-itrace.cxx +++ b/tapset-itrace.cxx @@ -191,7 +191,7 @@ itrace_derived_probe_group::emit_module_decls (systemtap_session& s) common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->probe", "_STP_PROBE_HANDLER_ITRACE"); - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->uregs = regs;"; s.op->newline() << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; // call probe function diff --git a/tapset-perfmon.cxx b/tapset-perfmon.cxx index a384189a8..8bd51dbdf 100644 --- a/tapset-perfmon.cxx +++ b/tapset-perfmon.cxx @@ -149,11 +149,14 @@ perf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "struct stap_perf_probe* stp = & stap_perf_probes [i];"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->probe", "_STP_PROBE_HANDLER_PERF"); - s.op->newline() << "c->regs = regs;"; - s.op->newline() << "if (user_mode(regs))"; + s.op->newline() << "if (user_mode(regs)) {"; s.op->newline(1)<< "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; + s.op->newline() << "c->uregs = regs;"; + s.op->newline(-1) << "} else {"; + s.op->newline(1) << "c->kregs = regs;"; + s.op->newline(-1) << "}"; - s.op->newline(-1) << "(*stp->probe->ph) (c);"; + s.op->newline() << "(*stp->probe->ph) (c);"; common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; } diff --git a/tapset-timers.cxx b/tapset-timers.cxx index f0f08ad20..0b91ef0ae 100644 --- a/tapset-timers.cxx +++ b/tapset-timers.cxx @@ -433,10 +433,14 @@ profile_derived_probe_group::emit_module_decls (systemtap_session& s) << common_probe_init (probes[0]) << ";"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "probe", "_STP_PROBE_HANDLER_PROFILE_TIMER"); - s.op->newline() << "c->regs = regs;"; // Timer interrupts save all registers, so if the interrupt happened // in user space we can rely on it being the full user pt_regs. - s.op->newline() << "if (user_mode(regs)) c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; + s.op->newline() << "if (user_mode(regs)) {"; + s.op->newline(1) << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; + s.op->newline() << "c->uregs = regs;"; + s.op->newline(-1) << "} else {"; + s.op->newline(1) << "c->kregs = regs;"; + s.op->newline(-1) << "}"; for (unsigned i=0; iprobe", "_STP_PROBE_HANDLER_UTRACE_SYSCALL"); - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->uregs = regs;"; s.op->newline() << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; // call probe function diff --git a/tapset/arm/registers.stp b/tapset/arm/registers.stp index 42448b8db..db8230431 100644 --- a/tapset/arm/registers.stp +++ b/tapset/arm/registers.stp @@ -29,7 +29,13 @@ function _stp_register_regs() { function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; - if (!CONTEXT->regs) { + struct pt_regs *regs; + if (c->probe_flags & _STP_PROBE_STATE_USER_MODE) { + regs = CONTEXT->kregs; + } else { + regs = CONTEXT->uregs; + } + if (!regs) { CONTEXT->last_error = "No registers available in this context"; return; } @@ -39,7 +45,7 @@ function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ CONTEXT->last_error = CONTEXT->error_buffer; return; } - memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + memcpy(&value, ((char *)regs) + THIS->offset, sizeof(value)); THIS->__retvalue = value; %} diff --git a/tapset/context-symbols.stp b/tapset/context-symbols.stp index 9b2869059..fb85bfcf0 100644 --- a/tapset/context-symbols.stp +++ b/tapset/context-symbols.stp @@ -85,6 +85,7 @@ function sprint_stack:string(stk:string) %{ /* pure */ /* pragma:symbols */ function probefunc:string () %{ /* pure */ /* pragma:symbols */ char *ptr, *start; + THIS->__retvalue[0] = '\0'; start = strstr(CONTEXT->probe_point, "function(\""); ptr = start + 10; if (!start) { @@ -99,16 +100,19 @@ function probefunc:string () %{ /* pure */ /* pragma:symbols */ *dst++ = *ptr++; *dst = 0; - } else if (CONTEXT->regs) { - _stp_snprint_addr(THIS->__retvalue, MAXSTRINGLEN, - REG_IP(CONTEXT->regs), - _STP_SYM_SYMBOL, - (CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE - ? current : NULL)); - if (THIS->__retvalue[0] == '.') /* powerpc symbol has a dot*/ - strlcpy(THIS->__retvalue,THIS->__retvalue + 1,MAXSTRINGLEN); } else { - THIS->__retvalue[0] = '\0'; + struct pt_regs *regs; + int user_mode; + user_mode = c->probe_flags & _STP_PROBE_STATE_USER_MODE; + regs = user_mode ? CONTEXT->uregs : CONTEXT->kregs; + if (regs) { + _stp_snprint_addr(THIS->__retvalue, MAXSTRINGLEN, + REG_IP(regs), _STP_SYM_SYMBOL, + (user_mode ? current : NULL)); + if (THIS->__retvalue[0] == '.') /* powerpc symbol has a dot*/ + strlcpy(THIS->__retvalue, THIS->__retvalue + 1, + MAXSTRINGLEN); + } } %} @@ -130,10 +134,10 @@ function probemod:string () %{ /* pure */ while (*ptr != '"' && --len && *ptr) *dst++ = *ptr++; *dst = 0; - } else if (CONTEXT->regs + } else if (CONTEXT->kregs && ! (CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE)) { struct _stp_module *m; - m = _stp_kmod_sec_lookup (REG_IP(CONTEXT->regs), NULL); + m = _stp_kmod_sec_lookup (REG_IP(CONTEXT->kregs), NULL); if (m && m->name) strlcpy (THIS->__retvalue, m->name, MAXSTRINGLEN); else diff --git a/tapset/context.stp b/tapset/context.stp index 2b7611ae6..c07671b72 100644 --- a/tapset/context.stp +++ b/tapset/context.stp @@ -15,12 +15,14 @@ /** * sfunction print_regs - Print a register dump * - * Description: This function prints a register dump. + * Description: This function prints a register dump. Does nothing if no registers are available for the probe point. */ function print_regs () %{ - if (CONTEXT->regs) { - _stp_print_regs (CONTEXT->regs); + if ((c->probe_flags & _STP_PROBE_STATE_USER_MODE) && CONTEXT->uregs) { + _stp_print_regs (CONTEXT->uregs); + } else if (CONTEXT->kregs) { + _stp_print_regs (CONTEXT->kregs); } %} @@ -232,7 +234,9 @@ function pp:string () */ function registers_valid:long () %{ /* pure */ /* unprivileged */ - THIS->__retvalue = (CONTEXT->regs != NULL); + THIS->__retvalue = ((c->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? (CONTEXT->uregs != NULL) + : (CONTEXT->kregs != NULL)); %} /** @@ -349,7 +353,11 @@ function stack_unused:long () */ function addr:long () %{ /* pure */ - THIS->__retvalue = (intptr_t)(CONTEXT->regs ? REG_IP(CONTEXT->regs) : 0); + if (CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) { + THIS->__retvalue = (intptr_t)(CONTEXT->uregs ? REG_IP(CONTEXT->uregs) : 0); + } else { + THIS->__retvalue = (intptr_t)(CONTEXT->kregs ? REG_IP(CONTEXT->kregs) : 0); + } %} /** diff --git a/tapset/errno.stp b/tapset/errno.stp index bd25dbfa8..58689a51d 100644 --- a/tapset/errno.stp +++ b/tapset/errno.stp @@ -399,8 +399,19 @@ static long _stp_returnval(struct pt_regs *regs) { } %} +/** + * sfunction returnval - Possible return value of probed function + * + * Description: Return the value of the register in which function values + * are typically returned. Can be used in probes where $return isn't + * available. This is only a guess of the actual return value and can be + * totally wrong. Normally only used in dwarfless probes. + */ function returnval:long () %{ /* pure */ - THIS->__retvalue = _stp_returnval(CONTEXT->regs); + struct pt_regs *regs; + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); + THIS->__retvalue = _stp_returnval(regs); %} /** @@ -417,8 +428,11 @@ function returnval:long () %{ /* pure */ * return_str(). */ function returnstr:string (format:long) %{ /* pure */ - if (CONTEXT->regs) { - long ret = _stp_returnval(CONTEXT->regs); + struct pt_regs *regs; + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); + if (regs) { + long ret = _stp_returnval(regs); if (ret < 0 && ret > -Maxerrno && errlist[-ret]) snprintf (THIS->__retvalue, MAXSTRINGLEN, "%ld (%s)", ret, errlist[-ret]); else if (THIS->format == 2) diff --git a/tapset/i386/registers.stp b/tapset/i386/registers.stp index 730f078cd..2703e9c43 100644 --- a/tapset/i386/registers.stp +++ b/tapset/i386/registers.stp @@ -47,7 +47,11 @@ if (test_x86_gs()) { function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; - if (!CONTEXT->regs) { + struct pt_regs *regs; + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); + + if (!regs) { CONTEXT->last_error = "No registers available in this context"; return; } @@ -57,7 +61,7 @@ function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ CONTEXT->last_error = CONTEXT->error_buffer; return; } - memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + memcpy(&value, ((char *)regs) + THIS->offset, sizeof(value)); THIS->__retvalue = value; %} @@ -70,7 +74,7 @@ function _stp_probing_kernel:long () { * the pre-trap stack pointer is ®s->sp. */ function _stp_kernel_sp:long (sp_offset:long) %{ /* pure */ - THIS->__retvalue = ((long) CONTEXT->regs) + THIS->sp_offset; + THIS->__retvalue = ((long) CONTEXT->kregs) + THIS->sp_offset; %} /* Assume ss register hasn't changed since we took the trap. */ @@ -114,9 +118,11 @@ function u_register:long (name:string) { function _stp_arg:long (argnum:long) %{ /* pure */ long val; int n, nr_regargs, result; - + struct pt_regs *regs; + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); THIS->__retvalue = 0; - if (!CONTEXT->regs) { + if (!regs) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access function args in this context"); CONTEXT->last_error = CONTEXT->error_buffer; @@ -125,8 +131,8 @@ function _stp_arg:long (argnum:long) %{ /* pure */ if (THIS->argnum < 1) goto bad_argnum; n = (int) THIS->argnum; - nr_regargs = _stp_get_regparm(CONTEXT->regparm, CONTEXT->regs); - result = _stp_get_arg32_by_number(n, nr_regargs, CONTEXT->regs, &val); + nr_regargs = _stp_get_regparm(CONTEXT->regparm, regs); + result = _stp_get_arg32_by_number(n, nr_regargs, regs, &val); switch (result) { case 0: /* Arg is in register. */ diff --git a/tapset/powerpc/registers.stp b/tapset/powerpc/registers.stp index 8fbfbd500..555c71dba 100644 --- a/tapset/powerpc/registers.stp +++ b/tapset/powerpc/registers.stp @@ -59,12 +59,16 @@ function _stp_register_regs() { } function probing_32bit_app() %{ /* pure */ - THIS->__retvalue = _stp_probing_32bit_app(CONTEXT->regs); + THIS->__retvalue = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + && _stp_probing_32bit_app(CONTEXT->uregs)); %} function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; - if (!CONTEXT->regs) { + struct pt_regs *regs; + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); + if (!regs) { CONTEXT->last_error = "No registers available in this context"; return; } @@ -75,7 +79,7 @@ function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ CONTEXT->last_error = CONTEXT->error_buffer; return; } - memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + memcpy(&value, ((char *)regs) + THIS->offset, sizeof(value)); THIS->__retvalue = value; %} diff --git a/tapset/s390/registers.stp b/tapset/s390/registers.stp index d608cf81d..695b64a4e 100644 --- a/tapset/s390/registers.stp +++ b/tapset/s390/registers.stp @@ -43,8 +43,9 @@ function _stp_register_regs() { * says "32bit process" */ function probing_32bit_app() %{ /* pure */ - if (CONTEXT->regs) - THIS->__retvalue = (user_mode(CONTEXT->regs) && + if ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + && CONTEXT->uregs) + THIS->__retvalue = (user_mode(CONTEXT->uregs) && test_tsk_thread_flag(current, TIF_31BIT)); else THIS->__retvalue = 0; @@ -56,7 +57,10 @@ function _stp_probing_kernel: long () { function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; - if (!CONTEXT->regs) { + struct pt_regs *regs; + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); + if (!regs) { CONTEXT->last_error = "No registers available in this context"; return; } @@ -69,12 +73,12 @@ function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ } if (THIS->offset < sizeof(struct pt_regs) - 2 * sizeof(unsigned short)) - memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, + memcpy(&value, ((char *)regs) + THIS->offset, sizeof(value)); else { /* ilc or trap */ unsigned short us_value; - memcpy(&us_value, ((char *)CONTEXT->regs) + THIS->offset, + memcpy(&us_value, ((char *)regs) + THIS->offset, sizeof(us_value)); value = us_value; // not sign-extended } diff --git a/tapset/syscalls2.stp b/tapset/syscalls2.stp index aad4dea8a..09503493b 100644 --- a/tapset/syscalls2.stp +++ b/tapset/syscalls2.stp @@ -282,7 +282,7 @@ probe syscall.personality.return = kernel.function("sys_personality").return # ia64 returns the results from the pipe call through (user) registers. %( arch == "ia64" %? function _ia64_pipe0:long() %{ - THIS->__retvalue = CONTEXT->regs ? CONTEXT->regs->r8 : 0; + THIS->__retvalue = CONTEXT->kregs ? CONTEXT->kregs->r8 : 0; %} function _ia64_pipe1:long() %{ THIS->__retvalue = task_pt_regs(current)->r9; diff --git a/tapset/utrace.stp b/tapset/utrace.stp index 6c6d91cff..b473eb73c 100644 --- a/tapset/utrace.stp +++ b/tapset/utrace.stp @@ -5,21 +5,21 @@ %} function _utrace_syscall_nr:long () %{ /* pure */ /* myproc-unprivileged */ - if (! CONTEXT->regs + if (! CONTEXT->uregs || ! (CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE)) { CONTEXT->last_error = "invalid call without context registers"; } else { - THIS->__retvalue = syscall_get_nr(current, CONTEXT->regs); + THIS->__retvalue = syscall_get_nr(current, CONTEXT->uregs); } %} function _utrace_syscall_arg:long (n:long) %{ /* pure */ /* myproc-unprivileged */ unsigned long arg = 0; - if (! CONTEXT->regs + if (! CONTEXT->uregs || ! (CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE)) { CONTEXT->last_error = "invalid call without context registers"; } else { - syscall_get_arguments(current, CONTEXT->regs, (int)THIS->n, 1, &arg); + syscall_get_arguments(current, CONTEXT->uregs, (int)THIS->n, 1, &arg); } THIS->__retvalue = arg; %} @@ -31,11 +31,11 @@ function _utrace_syscall_return:long () %{ /* pure */ /* myproc-unprivileged */ * getting sign extended. This caused return values to not match * up with the same values passes as arguments. */ - if (! CONTEXT->regs + if (! CONTEXT->uregs || ! (CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE)) { CONTEXT->last_error = "invalid call without context registers"; } else { THIS->__retvalue = (unsigned long)syscall_get_return_value(current, - CONTEXT->regs); + CONTEXT->uregs); } %} diff --git a/tapset/x86_64/registers.stp b/tapset/x86_64/registers.stp index 9876c08a7..7ebaa48b2 100644 --- a/tapset/x86_64/registers.stp +++ b/tapset/x86_64/registers.stp @@ -47,7 +47,10 @@ function _stp_register_regs() { function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; - if (!CONTEXT->regs) { + struct pt_regs *regs; + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); + if (!regs) { CONTEXT->last_error = "No registers available in this context"; return; } @@ -57,7 +60,7 @@ function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ CONTEXT->last_error = CONTEXT->error_buffer; return; } - memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + memcpy(&value, ((char *)regs) + THIS->offset, sizeof(value)); THIS->__retvalue = value; %} @@ -117,11 +120,14 @@ function u_register:long (name:string) { */ function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{ /* pure */ long val; + struct pt_regs *regs; int result, n, nr_regargs; size_t argsz = sizeof(long); + regs = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + ? CONTEXT->uregs : CONTEXT->kregs); THIS->__retvalue = 0; - if (!CONTEXT->regs) { + if (!regs) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access function args in this context"); CONTEXT->last_error = CONTEXT->error_buffer; @@ -130,14 +136,12 @@ function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{ /* pure 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)) { + nr_regargs = _stp_get_regparm(CONTEXT->regparm, regs); + if (_stp_probing_32bit_app(regs)) { argsz = sizeof(int); - result = _stp_get_arg32_by_number(n, nr_regargs, CONTEXT->regs, - &val); + result = _stp_get_arg32_by_number(n, nr_regargs, regs, &val); } else - result = _stp_get_arg64_by_number(n, nr_regargs, CONTEXT->regs, - &val); + result = _stp_get_arg64_by_number(n, nr_regargs, regs, &val); switch (result) { case 0: /* Arg is in register. */ @@ -188,7 +192,8 @@ deref_fault: /* branched to from kread() */ %} function probing_32bit_app() %{ /* pure */ - THIS->__retvalue = _stp_probing_32bit_app(CONTEXT->regs); + THIS->__retvalue = ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + && _stp_probing_32bit_app(CONTEXT->uregs)); %} /* Return the value of function arg #argnum (1=first arg) as a signed int. */ @@ -247,7 +252,8 @@ function asmlinkage() %{ /* pure */ %} function fastcall() %{ /* pure */ %} function regparm(n:long) %{ - if (_stp_probing_32bit_app(CONTEXT->regs) && + if ((CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) + && _stp_probing_32bit_app(CONTEXT->uregs) && (THIS->n < 0 || THIS->n > 3)) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "For -m32 programs, " diff --git a/tapsets.cxx b/tapsets.cxx index 18329c010..f948f7e96 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -149,7 +149,8 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "c->last_stmt = 0;"; o->newline() << "c->last_error = 0;"; o->newline() << "c->nesting = -1;"; // NB: PR10516 packs locals[] tighter - o->newline() << "c->regs = 0;"; + o->newline() << "c->uregs = 0;"; + o->newline() << "c->kregs = 0;"; o->newline() << "#if defined __ia64__"; o->newline() << "c->unwaddr = 0;"; o->newline() << "#endif"; @@ -4263,7 +4264,7 @@ dwarf_derived_probe::emit_probe_local_init(translator_output * o) { // if accessing $variables, emit bsp cache setup for speeding up o->newline() << "#if defined __ia64__"; - o->newline() << "bspcache(c->unwaddr, c->regs);"; + o->newline() << "bspcache(c->unwaddr, c->kregs);"; o->newline() << "#endif"; } } @@ -4455,14 +4456,14 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << "];"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->probe", "_STP_PROBE_HANDLER_KPROBE"); - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->kregs = regs;"; // Make it look like the IP is set as it wouldn't have been replaced // by a breakpoint instruction when calling real probe handler. Reset // IP regs on return, so we don't confuse kprobes. PR10458 s.op->newline() << "{"; s.op->indent(1); - s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->kregs);"; s.op->newline() << "SET_REG_IP(regs, (unsigned long) inst->addr);"; s.op->newline() << "(*sdp->probe->ph) (c);"; s.op->newline() << "SET_REG_IP(regs, kprobes_ip);"; @@ -4492,7 +4493,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->indent(1); common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sp", "_STP_PROBE_HANDLER_KRETPROBE"); - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->kregs = regs;"; // for assisting runtime's backtrace logic and accessing kretprobe data packets s.op->newline() << "c->ips.krp.pi = inst;"; @@ -4502,7 +4503,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) // by a breakpoint instruction when calling real probe handler. Reset // IP regs on return, so we don't confuse kprobes. PR10458 s.op->newline() << "{"; - s.op->newline(1) << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline(1) << "unsigned long kprobes_ip = REG_IP(c->kregs);"; s.op->newline() << "if (entry)"; s.op->newline(1) << "SET_REG_IP(regs, (unsigned long) inst->rp->kp.addr);"; s.op->newline(-1) << "else"; @@ -7013,7 +7014,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "atomic_dec (&c->busy);"; s.op->newline() << "goto probe_epilogue;"; s.op->newline(-1) << "}"; - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->uregs = regs;"; s.op->newline() << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; // Make it look like the IP is set as it would in the actual user @@ -7021,7 +7022,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // we don't confuse uprobes. PR10458 s.op->newline() << "{"; s.op->indent(1); - s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->uregs);"; s.op->newline() << "SET_REG_IP(regs, inst->vaddr);"; s.op->newline() << "(*sups->probe->ph) (c);"; s.op->newline() << "SET_REG_IP(regs, uprobes_ip);"; @@ -7044,7 +7045,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "goto probe_epilogue;"; s.op->newline(-1) << "}"; - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->uregs = regs;"; s.op->newline() << "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; // Make it look like the IP is set as it would in the actual user @@ -7052,7 +7053,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // we don't confuse uprobes. PR10458 s.op->newline() << "{"; s.op->indent(1); - s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->uregs);"; s.op->newline() << "SET_REG_IP(regs, inst->ret_addr);"; s.op->newline() << "(*sups->probe->ph) (c);"; s.op->newline() << "SET_REG_IP(regs, uprobes_ip);"; @@ -7421,14 +7422,14 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << "];"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->probe", "_STP_PROBE_HANDLER_KPROBE"); - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->kregs = regs;"; // Make it look like the IP is set as it wouldn't have been replaced // by a breakpoint instruction when calling real probe handler. Reset // IP regs on return, so we don't confuse kprobes. PR10458 s.op->newline() << "{"; s.op->indent(1); - s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->kregs);"; s.op->newline() << "SET_REG_IP(regs, (unsigned long) inst->addr);"; s.op->newline() << "(*sdp->probe->ph) (c);"; s.op->newline() << "SET_REG_IP(regs, kprobes_ip);"; @@ -7455,7 +7456,7 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->probe", "_STP_PROBE_HANDLER_KRETPROBE"); - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->kregs = regs;"; s.op->newline() << "c->ips.krp.pi = inst;"; // for assisting runtime's backtrace logic // Make it look like the IP is set as it wouldn't have been replaced @@ -7463,7 +7464,7 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // IP regs on return, so we don't confuse kprobes. PR10458 s.op->newline() << "{"; s.op->indent(1); - s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->kregs);"; s.op->newline() << "SET_REG_IP(regs, (unsigned long) inst->rp->kp.addr);"; s.op->newline() << "(*sdp->probe->ph) (c);"; s.op->newline() << "SET_REG_IP(regs, kprobes_ip);"; @@ -7933,7 +7934,12 @@ hwbkpt_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "struct stap_hwbkpt_probe *sdp = &stap_hwbkpt_probes[i];"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->probe", "_STP_PROBE_HANDLER_HWBKPT"); - s.op->newline() << "c->regs = regs;"; + s.op->newline() << "if (user_mode(regs)) {"; + s.op->newline(1)<< "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;"; + s.op->newline() << "c->uregs = regs;"; + s.op->newline(-1) << "} else {"; + s.op->newline(1) << "c->kregs = regs;"; + s.op->newline(-1) << "}"; s.op->newline() << "(*sdp->probe->ph) (c);"; common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; -- 2.43.5