diff options
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | dwarf_wrappers.cxx | 2 | ||||
-rw-r--r-- | elaborate.cxx | 43 | ||||
-rw-r--r-- | runtime/ChangeLog | 19 | ||||
-rw-r--r-- | runtime/task_finder.c | 104 | ||||
-rw-r--r-- | runtime/utrace_compatibility.h | 33 | ||||
-rw-r--r-- | tapset/ChangeLog | 9 | ||||
-rw-r--r-- | tapset/socket.stp | 34 | ||||
-rw-r--r-- | tapsets.cxx | 145 | ||||
-rw-r--r-- | testsuite/ChangeLog | 5 | ||||
-rwxr-xr-x | testsuite/semok/thirtythree.stp | 5 | ||||
-rw-r--r-- | testsuite/systemtap.base/alternatives.exp | 9 |
13 files changed, 368 insertions, 72 deletions
@@ -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. @@ -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)" } |