summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog28
-rw-r--r--NEWS4
-rw-r--r--dwarf_wrappers.cxx2
-rw-r--r--elaborate.cxx43
-rw-r--r--runtime/ChangeLog19
-rw-r--r--runtime/task_finder.c104
-rw-r--r--runtime/utrace_compatibility.h33
-rw-r--r--tapset/ChangeLog9
-rw-r--r--tapset/socket.stp34
-rw-r--r--tapsets.cxx145
-rw-r--r--testsuite/ChangeLog5
-rwxr-xr-xtestsuite/semok/thirtythree.stp5
-rw-r--r--testsuite/systemtap.base/alternatives.exp9
13 files changed, 368 insertions, 72 deletions
diff --git a/ChangeLog b/ChangeLog
index 0ee737c9..d62f154f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2008-09-26 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6916
+ * elaborate.cxx (systemtap_session::print_error): Fix
+ duplicate elimination in face of token compression.
+ * tapsets.cxx (literal_stmt_for_local, literal_stmt_for_return):
+ Change error message to fit old pattern.
+
+2008-09-26 Frank Ch. Eigler <fche@elastic.org>
+
+ BZ 6829: avoid calling unregister_uprobe() when responding
+ to a task-finder exec/exit callback, as uprobes likes to
+ clean such things up by itself.
+
+2008-09-12 Prerna Saxena <prerna@linux.vnet.ibm.com>
+
+ BZ 3016 : Handling members of anonymous structs/unions
+ * tapsets.cxx (translate_components, print_members) : enable
+ translator to identify members of anonymous structs / unions.
+ * testsuite/semok/thirtythree.stp : New test-case.
+ * NEWS : Modify translator code to identify members of anonymous
+ structs/unions.
+
+2008-09-24 Mark Wielaard <mjw@redhat.com>
+
+ * dwarf_wrappers.cxx (dwfl_assert(string,bool)): Call
+ dwfl_assert(string,int), not dwarf_assert().
+
2008-09-12 Dave Brolley <brolley@redhat.com>
* stap-client (staprun_PATH): Ensure that $first_stap is not empty.
diff --git a/NEWS b/NEWS
index 824f3ded..7e737d47 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,9 @@
* What's new
+- The translator can resolve members of anonymous structs / unions:
+ given struct { int foo; struct { int bar; }; } *p;
+ this now works: $p->bar
+
- The stap "-F" flag activates "flight recorder" mode, which consists of
translating the given script as usual, but implicitly launching it into
the background with staprun's existing "-L" (launch) option. A user
diff --git a/dwarf_wrappers.cxx b/dwarf_wrappers.cxx
index 93cb36a2..4fd074ed 100644
--- a/dwarf_wrappers.cxx
+++ b/dwarf_wrappers.cxx
@@ -42,5 +42,5 @@ void dwarf_assert(const string& desc, int rc)
void dwfl_assert(const std::string& desc, bool condition)
{
if (!condition)
- dwarf_assert(desc, -1);
+ dwfl_assert(desc, -1);
}
diff --git a/elaborate.cxx b/elaborate.cxx
index b476948b..94bfd1c5 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -1424,26 +1424,43 @@ systemtap_session::print_token (ostream& o, const token* tok)
void
systemtap_session::print_error (const semantic_error& e)
{
- string message_str;
- stringstream message;
+ string message_str[2];
// NB: we don't print error messages during listing mode.
if (listing_mode) return;
- message << "semantic error: " << e.what ();
- if (e.tok1 || e.tok2)
- message << ": ";
- if (e.tok1) print_token (message, e.tok1);
- message << e.msg2;
- if (e.tok2) print_token (message, e.tok2);
- message << endl;
- message_str = message.str();
+ // We generate two messages. The second one ([1]) is printed
+ // without token compression, for purposes of duplicate elimination.
+ // This way, the same message that may be generated once with a
+ // compressed and once with an uncompressed token still only gets
+ // printed once.
+ for (int i=0; i<2; i++)
+ {
+ stringstream message;
+
+ message << "semantic error: " << e.what ();
+ if (e.tok1 || e.tok2)
+ message << ": ";
+ if (e.tok1)
+ {
+ if (i == 0) print_token (message, e.tok1);
+ else message << *e.tok1;
+ }
+ message << e.msg2;
+ if (e.tok2)
+ {
+ if (i == 0) print_token (message, e.tok2);
+ else message << *e.tok2;
+ }
+ message << endl;
+ message_str[i] = message.str();
+ }
// Duplicate elimination
- if (seen_errors.find (message_str) == seen_errors.end())
+ if (seen_errors.find (message_str[1]) == seen_errors.end())
{
- seen_errors.insert (message_str);
- cerr << message_str;
+ seen_errors.insert (message_str[1]);
+ cerr << message_str[0];
}
if (e.chain)
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index e5594783..6672dbb5 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,22 @@
+2008-09-26 David Smith <dsmith@redhat.com>
+
+ * task_finder.c (__STP_ATTACHED_TASK_EVENTS): Removed UTRACE_STOP,
+ which isn't needed anymore.
+
+2008-09-25 David Smith <dsmith@redhat.com>
+
+ * task_finder.c (__stp_utrace_attach): Added action flag to know
+ to request the thread to be stopped or not.
+ (stap_utrace_attach): Now just calls __stp_utrace_attach().
+ (__stp_utrace_task_finder_target_quiesce): Handles
+ utrace_set_events() errors properly.
+
+ * utrace_compatibility.h (enum utrace_resume_action): Added
+ utrace_resume_action enum.
+ (utrace_control): Added UTRACE_STOP support.
+ (utrace_engine_put): New.
+ (utrace_barrier): New.
+
2008-09-17 Frank Ch. Eigler <fche@elastic.org>
PR 6487, 6504.
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 493ca6f7..db7a8f38 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -89,7 +89,7 @@ struct stap_task_finder_target {
size_t pathlen;
/* public: */
- const char *pathname;
+ const char *pathname;
pid_t pid;
stap_task_finder_callback callback;
stap_task_finder_vm_callback vm_callback;
@@ -148,8 +148,8 @@ static int
stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
{
// Since this __stp_task_finder_list is (currently) only
- // written to in one big setup operation before the task
- // finder process is started, we don't need to lock it.
+ // written to in one big setup operation before the task
+ // finder process is started, we don't need to lock it.
struct list_head *node;
struct stap_task_finder_target *tgt = NULL;
int found_node = 0;
@@ -258,6 +258,7 @@ stap_utrace_detach(struct task_struct *tsk,
rc, tsk->pid);
break;
}
+ utrace_engine_put(engine);
}
return rc;
}
@@ -386,7 +387,6 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
* events.
*/
#define __STP_ATTACHED_TASK_EVENTS (__STP_TASK_BASE_EVENTS \
- | UTRACE_STOP \
| UTRACE_EVENT(QUIESCE))
#define __STP_ATTACHED_TASK_BASE_EVENTS(tgt) \
@@ -394,9 +394,10 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
: __STP_TASK_VM_BASE_EVENTS)
static int
-stap_utrace_attach(struct task_struct *tsk,
- const struct utrace_engine_ops *ops, void *data,
- unsigned long event_flags)
+__stp_utrace_attach(struct task_struct *tsk,
+ const struct utrace_engine_ops *ops, void *data,
+ unsigned long event_flags,
+ enum utrace_resume_action action)
{
struct utrace_attached_engine *engine;
struct mm_struct *mm;
@@ -428,15 +429,51 @@ stap_utrace_attach(struct task_struct *tsk,
}
else {
rc = utrace_set_events(tsk, engine, event_flags);
- if (rc == 0)
+ if (rc == -EINPROGRESS) {
+ /*
+ * It's running our callback, so we have to
+ * synchronize. We can't keep rcu_read_lock,
+ * so the task pointer might die. But it's
+ * safe to call utrace_barrier() even with a
+ * stale task pointer, if we have an engine
+ * ref.
+ */
+ rc = utrace_barrier(tsk, engine);
+ if (rc != 0)
+ _stp_error("utrace_barrier returned error %d on pid %d",
+ rc, (int)tsk->pid);
+ }
+ if (rc == 0) {
debug_task_finder_attach();
+
+ if (action != UTRACE_RESUME) {
+ rc = utrace_control(tsk, engine, UTRACE_STOP);
+ /* EINPROGRESS means we must wait for
+ * a callback, which is what we want. */
+ if (rc != 0 && rc != -EINPROGRESS)
+ _stp_error("utrace_control returned error %d on pid %d",
+ rc, (int)tsk->pid);
+ else
+ rc = 0;
+ }
+
+ }
else
- _stp_error("utrace_set_events returned error %d on pid %d",
+ _stp_error("utrace_set_events2 returned error %d on pid %d",
rc, (int)tsk->pid);
+ utrace_engine_put(engine);
}
return rc;
}
+static int
+stap_utrace_attach(struct task_struct *tsk,
+ const struct utrace_engine_ops *ops, void *data,
+ unsigned long event_flags)
+{
+ return __stp_utrace_attach(tsk, ops, data, event_flags, UTRACE_RESUME);
+}
+
static inline void
__stp_utrace_attach_match_filename(struct task_struct *tsk,
const char * const filename,
@@ -485,9 +522,10 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk,
// isn't set, we can go ahead and call the
// callback.
if (register_p) {
- rc = stap_utrace_attach(tsk, &cb_tgt->ops,
- cb_tgt,
- __STP_ATTACHED_TASK_EVENTS);
+ rc = __stp_utrace_attach(tsk, &cb_tgt->ops,
+ cb_tgt,
+ __STP_ATTACHED_TASK_EVENTS,
+ UTRACE_STOP);
if (rc != 0 && rc != EPERM)
break;
cb_tgt->engine_attached = 1;
@@ -601,8 +639,8 @@ __stp_utrace_task_finder_report_clone(enum utrace_resume_action action,
__stp_tf_handler_start();
// On clone, attach to the child.
- rc = stap_utrace_attach(child, engine->ops, 0,
- __STP_TASK_FINDER_EVENTS);
+ rc = __stp_utrace_attach(child, engine->ops, 0,
+ __STP_TASK_FINDER_EVENTS, UTRACE_RESUME);
if (rc != 0 && rc != EPERM) {
__stp_tf_handler_end();
return UTRACE_RESUME;
@@ -757,6 +795,22 @@ __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action,
// Turn off quiesce handling
rc = utrace_set_events(tsk, engine,
__STP_ATTACHED_TASK_BASE_EVENTS(tgt));
+
+ if (rc == -EINPROGRESS) {
+ /*
+ * It's running our callback, so we have to
+ * synchronize. We can't keep rcu_read_lock,
+ * so the task pointer might die. But it's
+ * safe to call utrace_barrier() even with
+ * a stale task pointer, if we have an engine ref.
+ */
+ rc = utrace_barrier(tsk, engine);
+ if (rc != 0)
+ _stp_error("utrace_barrier returned error %d on pid %d",
+ rc, (int)tsk->pid);
+ rc = utrace_set_events(tsk, engine,
+ __STP_ATTACHED_TASK_BASE_EVENTS(tgt));
+ }
if (rc != 0)
_stp_error("utrace_set_events returned error %d on pid %d",
rc, (int)tsk->pid);
@@ -1173,13 +1227,14 @@ stap_start_task_finder(void)
size_t mmpathlen;
struct list_head *tgt_node;
- /* Skip over processes other than that specified with
- stap -c or -x. */
- if (_stp_target && tsk->tgid != _stp_target)
- continue;
+ /* Skip over processes other than that specified with
+ * stap -c or -x. */
+ if (_stp_target && tsk->tgid != _stp_target)
+ continue;
- rc = stap_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0,
- __STP_TASK_FINDER_EVENTS);
+ rc = __stp_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0,
+ __STP_TASK_FINDER_EVENTS,
+ UTRACE_RESUME);
if (rc == EPERM) {
/* Ignore EPERM errors, which mean this wasn't
* a thread we can attach to. */
@@ -1242,16 +1297,17 @@ stap_start_task_finder(void)
continue;
// Set up events we need for attached tasks.
- rc = stap_utrace_attach(tsk, &cb_tgt->ops,
- cb_tgt,
- __STP_ATTACHED_TASK_EVENTS);
+ rc = __stp_utrace_attach(tsk, &cb_tgt->ops,
+ cb_tgt,
+ __STP_ATTACHED_TASK_EVENTS,
+ UTRACE_STOP);
if (rc != 0 && rc != EPERM)
goto stf_err;
cb_tgt->engine_attached = 1;
}
}
} while_each_thread(grp, tsk);
- stf_err:
+stf_err:
rcu_read_unlock();
_stp_kfree(mmpath_buf);
diff --git a/runtime/utrace_compatibility.h b/runtime/utrace_compatibility.h
index 80037015..27fca250 100644
--- a/runtime/utrace_compatibility.h
+++ b/runtime/utrace_compatibility.h
@@ -24,9 +24,11 @@
#define UTRACE_ORIG_VERSION
-#define UTRACE_RESUME UTRACE_ACTION_RESUME
-#define UTRACE_DETACH UTRACE_ACTION_DETACH
-#define UTRACE_STOP UTRACE_ACTION_QUIESCE
+enum utrace_resume_action {
+ UTRACE_STOP = UTRACE_ACTION_QUIESCE,
+ UTRACE_RESUME = UTRACE_ACTION_RESUME,
+ UTRACE_DETACH = UTRACE_ACTION_DETACH,
+};
static inline struct utrace_attached_engine *
utrace_attach_task(struct task_struct *target, int flags,
@@ -38,11 +40,17 @@ utrace_attach_task(struct task_struct *target, int flags,
static inline int __must_check
utrace_control(struct task_struct *target,
struct utrace_attached_engine *engine,
- unsigned long action)
+ enum utrace_resume_action action)
{
- if (action == UTRACE_DETACH)
+ switch (action) {
+ case UTRACE_DETACH:
return utrace_detach(target, engine);
- return -EINVAL;
+ case UTRACE_STOP:
+ return utrace_set_flags(target, engine,
+ (engine->flags | UTRACE_ACTION_QUIESCE));
+ default:
+ return -EINVAL;
+ }
}
static inline int __must_check
@@ -52,6 +60,19 @@ utrace_set_events(struct task_struct *target,
{
return utrace_set_flags(target, engine, eventmask);
}
+
+static inline void
+utrace_engine_put(struct utrace_attached_engine *engine)
+{
+ return;
+}
+
+static inline int __must_check
+utrace_barrier(struct task_struct *target,
+ struct utrace_attached_engine *engine)
+{
+ return 0;
+}
#endif
#endif /* _UTRACE_COMPATIBILITY_H_ */
diff --git a/tapset/ChangeLog b/tapset/ChangeLog
index 94531989..b3f09767 100644
--- a/tapset/ChangeLog
+++ b/tapset/ChangeLog
@@ -1,3 +1,12 @@
+2008-09-23 Zhaolei <zhaolei@cn.fujitsu.com>
+
+ * socket.stp (socket.aio_read/write): Fix version-checking method.
+
+2008-09-22 Zhaolei <zhaolei@cn.fujitsu.com>
+
+ * socket.stp (socket.aio_read/write): Fix the semantic error
+ caused by the difference of kernel versions.
+
2008-09-18 Mark Wielaard <mjw@redhat.com>
* aux_syscalls.stp (_reboot_magic_str): Moved reboot.h include out.
diff --git a/tapset/socket.stp b/tapset/socket.stp
index 3197a0e2..5c521a33 100644
--- a/tapset/socket.stp
+++ b/tapset/socket.stp
@@ -214,15 +214,26 @@ probe socket.recvmsg.return = kernel.function ("sock_recvmsg").return
* state Socket state value
* flags Socket flags value
* type Socket type value
+ *
+ * 2.6.9~2.6.15:
+ * static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t size, loff_t pos);
+ * 2.6.16~2.6.18:
+ * static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t count, loff_t pos);
+ * 2.6.19~2.6.26:
+ * static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos);
*/
probe socket.aio_write = kernel.function ("sock_aio_write")
{
name = "socket.aio_write"
_sock = _get_sock_addr ($iocb->ki_filp)
-%( kernel_v < "2.6.19" %?
- size = $count
+%( kernel_v < "2.6.16" %?
+ size = $size
%:
- size = _get_sock_size ($iov, $nr_segs)
+ %( kernel_v < "2.6.19" %?
+ size = $count
+ %:
+ size = _get_sock_size ($iov, $nr_segs)
+ %)
%)
protocol = _sock_prot_num (_sock)
family = _sock_fam_num (_sock)
@@ -281,15 +292,26 @@ probe socket.aio_write.return = kernel.function ("sock_aio_write").return
* state Socket state value
* flags Socket flags value
* type Socket type value
+ *
+ * 2.6.9~2.6.15:
+ * static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, size_t size, loff_t pos);
+ * 2.6.16~2.6.18:
+ * static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, size_t count, loff_t pos);
+ * 2.6.19~2.6.26:
+ * static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos);
*/
probe socket.aio_read = kernel.function ("sock_aio_read")
{
name = "socket.aio_read"
_sock = _get_sock_addr ($iocb->ki_filp)
-%( kernel_v < "2.6.19" %?
- size = $count
+%( kernel_v < "2.6.16" %?
+ size = $size
%:
- size = _get_sock_size ($iov, $nr_segs)
+ %( kernel_v < "2.6.19" %?
+ size = $count
+ %:
+ size = _get_sock_size ($iov, $nr_segs)
+ %)
%)
protocol = _sock_prot_num (_sock)
family = _sock_fam_num (_sock)
diff --git a/tapsets.cxx b/tapsets.cxx
index 85505084..b1475997 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -1776,9 +1776,33 @@ struct dwflpp
// Output each sibling's name to 'o'.
while (dwarf_tag (die) == DW_TAG_member)
{
- const char *member = (dwarf_diename_integrate (die) ?: "<anonymous>");
+ const char *member = dwarf_diename_integrate (die) ;
+
+ if ( member != NULL )
- o << " " << member;
+ o << " " << member;
+
+ else
+ {
+ Dwarf_Die temp_die = *die;
+ Dwarf_Attribute temp_attr ;
+
+ if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
+ {
+ clog<<"\n Error in obtaining type attribute for "
+ <<(dwarf_diename(&temp_die)?:"<anonymous>");
+ return ;
+ }
+
+ if ( ! dwarf_formref_die (&temp_attr,&temp_die))
+ {
+ clog<<"\n Error in decoding type attribute for "
+ <<(dwarf_diename(&temp_die)?:"<anonymous>");
+ return ;
+ }
+ print_members(&temp_die,o);
+
+ }
if (dwarf_siblingof (die, &die_mem) != 0)
break;
@@ -1797,7 +1821,15 @@ struct dwflpp
{
Dwarf_Die *die = vardie;
Dwarf_Die struct_die;
+ Dwarf_Attribute temp_attr;
+
unsigned i = 0;
+
+ static unsigned int func_call_level ;
+ static unsigned int dwarf_error_flag ; // indicates current error is dwarf error
+ static unsigned int dwarf_error_count ; // keeps track of no of dwarf errors
+ static semantic_error saved_dwarf_error("");
+
while (i < components.size())
{
/* XXX: This would be desirable, but we don't get the target_symbol token,
@@ -1855,9 +1887,7 @@ struct dwflpp
switch (dwarf_child (die, die_mem))
{
case 1: /* No children. */
- throw semantic_error ("empty struct "
- + string (dwarf_diename_integrate (die) ?: "<anonymous>"));
- break;
+ return NULL;
case -1: /* Error. */
default: /* Shouldn't happen */
throw semantic_error (string (typetag == DW_TAG_union_type ? "union" : "struct")
@@ -1872,14 +1902,60 @@ struct dwflpp
while (dwarf_tag (die) != DW_TAG_member
|| ({ const char *member = dwarf_diename_integrate (die);
member == NULL || string(member) != components[i].second; }))
+ {
+ if ( dwarf_diename (die) == NULL ) // handling Anonymous structs/unions
+ {
+ Dwarf_Die temp_die = *die;
+ Dwarf_Die temp_die_2;
+
+ try
+ {
+ if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
+ {
+ dwarf_error_flag ++ ;
+ dwarf_error_count ++;
+ throw semantic_error(" Error in obtaining type attribute for "+ string(dwarf_diename(&temp_die)?:"<anonymous>"));
+ }
+
+ if ( !dwarf_formref_die (&temp_attr, &temp_die))
+ {
+ dwarf_error_flag ++ ;
+ dwarf_error_count ++;
+ throw semantic_error(" Error in decoding DW_AT_type attribute for " + string(dwarf_diename(&temp_die)?:"<anonymous>"));
+ }
+
+ func_call_level ++ ;
+
+ Dwarf_Die *result_die = translate_components(pool, tail, pc, components, &temp_die, &temp_die_2, &temp_attr );
+
+ func_call_level -- ;
+
+ if (result_die != NULL)
+ {
+ memcpy(die_mem, &temp_die_2, sizeof(Dwarf_Die));
+ memcpy(attr_mem, &temp_attr, sizeof(Dwarf_Attribute));
+ return die_mem;
+ }
+ }
+ catch (const semantic_error& e)
+ {
+ if ( !dwarf_error_flag ) //not a dwarf error
+ throw;
+ else
+ {
+ dwarf_error_flag = 0 ;
+ saved_dwarf_error = e ;
+ }
+ }
+ }
if (dwarf_siblingof (die, die_mem) != 0)
- {
- stringstream alternatives;
- print_members (&struct_die, alternatives);
- throw semantic_error ("field '" + components[i].second
- + "' not found (alternatives:"
- + alternatives.str () + ")");
- }
+ {
+ if ( func_call_level == 0 && dwarf_error_count ) // this is parent call & a dwarf error has been reported in a branch somewhere
+ throw semantic_error( saved_dwarf_error );
+ else
+ return NULL;
+ }
+ }
if (dwarf_attr_integrate (die, DW_AT_data_member_location,
attr_mem) == NULL)
@@ -2161,6 +2237,15 @@ struct dwflpp
Dwarf_Die die_mem, *die = NULL;
die = translate_components (&pool, &tail, pc, components,
&vardie, &die_mem, &attr_mem);
+ if(!die)
+ {
+ die = dwarf_formref_die (&attr_mem, &vardie);
+ stringstream alternatives;
+ print_members(die,alternatives);
+ throw semantic_error("unable to find local '" + local + "'"
+ + " near pc " + lex_cast_hex<string>(pc)
+ + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")));
+ }
/* Translate the assignment part, either
x = $foo->bar->baz[NN]
@@ -2228,6 +2313,16 @@ struct dwflpp
Dwarf_Die die_mem, *die = NULL;
die = translate_components (&pool, &tail, pc, components,
vardie, &die_mem, &attr_mem);
+ if(!die)
+ {
+ die = dwarf_formref_die (&attr_mem, vardie);
+ stringstream alternatives;
+ print_members(die,alternatives);
+ throw semantic_error("unable to find return value"
+ " near pc " + lex_cast_hex<string>(pc)
+ + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")));
+ }
+
/* Translate the assignment part, either
x = $return->bar->baz[NN]
@@ -6841,7 +6936,11 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
// register new uprobe
s.op->newline() << "if (register_p && sup->spec_index < 0) {";
- s.op->newline(1) << "sup->spec_index = spec_index;";
+ // PR6829: we need to check that the sup we're about to reuse is really completely free.
+ // See PR6829 notes below.
+ s.op->newline(1) << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;";
+ s.op->newline() << "else if (sup->spec_index == -2 && sup->urp.u.kdata != NULL) continue;";
+ s.op->newline() << "sup->spec_index = spec_index;";
s.op->newline() << "if (sups->return_p) {";
s.op->newline(1) << "sup->urp.u.pid = tsk->tgid;";
s.op->newline() << "sup->urp.u.vaddr = relocation + sups->address;";
@@ -6877,15 +6976,22 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(1) << "#ifdef DEBUG_UPROBES";
s.op->newline() << "printk (KERN_WARNING \"uretprobe unregister pid %d addr %p\\n\", sup->up.pid, (void*) sup->up.vaddr);";
s.op->newline() << "#endif";
- s.op->newline() << "unregister_uretprobe (& sup->urp);";
+ // NB: We must not actually uregister uprobes when a target process execs or exits;
+ // uprobes does that by itself asynchronously. We can reuse the up/urp struct after
+ // uprobes clears the sup->urp->kdata pointer. PR6829
+ // s.op->newline() << "unregister_uretprobe (& sup->urp);";
+ s.op->newline() << "sup->spec_index = -2;";
s.op->newline(-1) << "} else {";
s.op->newline(1) << "#ifdef DEBUG_UPROBES";
s.op->newline() << "printk (KERN_WARNING \"uprobe unregister pid %d addr %p\\n\", sup->urp.u.pid, (void*) sup->urp.u.vaddr);";
s.op->newline() << "#endif";
- s.op->newline() << "unregister_uprobe (& sup->up);";
+ // NB: We must not actually unregister uprobes ... same as above, except that
+ // here it's the sup->up->kdata field that will get cleared. To tell the two
+ // cases apart, we use spec_index -2 vs -1.
+ // s.op->newline() << "unregister_uprobe (& sup->up);";
+ s.op->newline() << "sup->spec_index = -1;";
s.op->newline(-1) << "}";
- s.op->newline(1) << "sup->spec_index = -1;";
- s.op->newline() << "handled_p = 1;";
+ s.op->newline(1) << "handled_p = 1;";
s.op->newline() << "break;"; // exit to-free slot search
s.op->newline(-1) << "}"; // if/else
@@ -6946,6 +7052,9 @@ uprobe_derived_probe_group::emit_module_init (systemtap_session& s)
s.op->newline() << "for (j=0; j<NUMUPROBES; j++) {";
s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];";
s.op->newline() << "sup->spec_index = -1;"; // free slot
+ // NB: we assume the rest of the struct (specificaly, sup->up) is
+ // initialized to zero. This is so that we can use
+ // sup->up->kdata = NULL for "really free!" PR 6829.
s.op->newline(-1) << "}";
s.op->newline() << "mutex_init (& stap_uprobes_lock);";
@@ -6986,6 +7095,8 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
s.op->newline(1) << "#ifdef DEBUG_UPROBES";
s.op->newline() << "printk (KERN_WARNING \"uretprobe unregister2 index %d pid %d addr %p\\n\", sup->spec_index, sup->up.pid, (void*) sup->up.vaddr);";
s.op->newline() << "#endif";
+ // NB: PR6829 does not change that we still need to unregister at
+ // *this* time -- when the script as a whole exits.
s.op->newline() << "unregister_uretprobe (& sup->urp);";
s.op->newline(-1) << "} else {";
s.op->newline(1) << "#ifdef DEBUG_UPROBES";
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index 234ff66d..f3fad077 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-09-26 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6916.
+ * systemtap.base/alternatives.exp: Assert error counts.
+
2008-09-15 Mark Wielaard <mjw@redhat.com>
* buildok/seventeen.stp: Fix 2.6.27 detection.
diff --git a/testsuite/semok/thirtythree.stp b/testsuite/semok/thirtythree.stp
new file mode 100755
index 00000000..d5171f66
--- /dev/null
+++ b/testsuite/semok/thirtythree.stp
@@ -0,0 +1,5 @@
+#! stap -p2
+# Per bz3016, this should get through the semantic pass without warnings.
+probe kernel.function("do_mpage_readpage") {
+ printf("\n page ->inuse %u",$page->inuse)
+}
diff --git a/testsuite/systemtap.base/alternatives.exp b/testsuite/systemtap.base/alternatives.exp
index 673f3426..deaf3bf8 100644
--- a/testsuite/systemtap.base/alternatives.exp
+++ b/testsuite/systemtap.base/alternatives.exp
@@ -26,11 +26,10 @@ proc stap_run_alternatives {args} {
verbose -log "starting $args"
eval spawn $args
expect {
- -re {semantic error: .+ \(alternatives: [a-zA-Z_]}
- { set alternatives_found 1 }
+ -re {semantic error: .+ \(alternatives: [a-zA-Z_]} {incr alternatives_found; exp_continue}
-re {[^\r]*\r} { verbose -log $expect_out(0,string); exp_continue }
eof { }
- timeout { exp_continue }
+ timeout { }
}
set results [wait]
verbose -log "wait results: $results"
@@ -39,8 +38,8 @@ proc stap_run_alternatives {args} {
set test "LOCAL1"
set rc [stap_run_alternatives stap -vu -p2 -e $local1_script]
-if {$rc == 1} { pass $test } else { fail $test }
+if {$rc == 1} { pass $test } else { fail "$test ($rc)" }
set test "STRUCT1"
set rc [stap_run_alternatives stap -vu -p2 -e $struct1_script]
-if {$rc == 1} { pass $test } else { fail $test }
+if {$rc == 1} { pass $test } else { fail "$test ($rc)" }