diff options
Diffstat (limited to 'lib/libdtrace/common/dt_link.c')
-rw-r--r-- | lib/libdtrace/common/dt_link.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/lib/libdtrace/common/dt_link.c b/lib/libdtrace/common/dt_link.c index e317fe7f1162..e910ac3ff1bc 100644 --- a/lib/libdtrace/common/dt_link.c +++ b/lib/libdtrace/common/dt_link.c @@ -776,15 +776,19 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, /* * We may have already processed this object file in an earlier linker * invocation. Check to see if the present instruction sequence matches - * the one we would install. + * the one we would install below. */ if (isenabled) { - if (ip[0] == DT_OP_CLR_O0) + if (ip[0] == DT_OP_NOP) { + (*off) += sizeof (ip[0]); return (0); + } } else { if (DT_IS_RESTORE(ip[1])) { - if (ip[0] == DT_OP_RET) + if (ip[0] == DT_OP_RET) { + (*off) += sizeof (ip[0]); return (0); + } } else if (DT_IS_MOV_O7(ip[1])) { if (DT_IS_RETL(ip[0])) return (0); @@ -818,7 +822,17 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, return (-1); } - ip[0] = DT_OP_CLR_O0; + + /* + * On SPARC, we take advantage of the fact that the first + * argument shares the same register as for the return value. + * The macro handles the work of zeroing that register so we + * don't need to do anything special here. We instrument the + * instruction in the delay slot as we'll need to modify the + * return register after that instruction has been emulated. + */ + ip[0] = DT_OP_NOP; + (*off) += sizeof (ip[0]); } else { /* * If the call is followed by a restore, it's a tail call so @@ -827,11 +841,16 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, * so change the call to a retl-like instruction that returns * to that register value + 8 (rather than the typical %o7 + * 8); the delay slot instruction is left, but should have no - * effect. Otherwise we change the call to be a nop. In the - * first and the last case we adjust the offset to land on what - * was once the delay slot of the call so we correctly get all - * the arguments as they would have been passed in a normal - * function call. + * effect. Otherwise we change the call to be a nop. We + * identify the subsequent instruction as the probe point in + * all but the leaf tail-call case to ensure that arguments to + * the probe are complete and consistent. An astute, though + * largely hypothetical, observer would note that there is the + * possibility of a false-positive probe firing if the function + * contained a branch to the instruction in the delay slot of + * the call. Fixing this would require significant in-kernel + * modifications, and isn't worth doing until we see it in the + * wild. */ if (DT_IS_RESTORE(ip[1])) { ip[0] = DT_OP_RET; |