From a8021985a74fe86cec06d257e5cf2ee5b43d1ba7 Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 1 Nov 2010 15:32:57 -0500 Subject: [PATCH] Improve handling of vfork'ed processes for uprobes version 1. * runtime/uprobes/uprobes.c (insert_bkpt): Don't log EEXIST errors (since systemtap inserts duplicate probes). (uprobe_report_exec): Only cleanup if this is the last thread. Without this change, vfork'ed processes doing an exec weren't handled correctly. --- runtime/uprobes/uprobes.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c index 3eb8ea902..bfa39031d 100644 --- a/runtime/uprobes/uprobes.c +++ b/runtime/uprobes/uprobes.c @@ -279,7 +279,12 @@ static void insert_bkpt(struct uprobe_probept *ppt, struct task_struct *tsk) } memcpy(&ppt->opcode, ppt->insn, BP_INSN_SIZE); if (ppt->opcode == BREAKPOINT_INSTRUCTION) { - bkpt_insertion_failed(ppt, "bkpt already exists at that addr"); + /* + * To avoid filling up the log file with complaints + * about breakpoints already existing, don't log this + * error. + */ + //bkpt_insertion_failed(ppt, "bkpt already exists at that addr"); result = -EEXIST; goto out; } @@ -2363,14 +2368,27 @@ static u32 uprobe_report_exec(struct utrace_attached_engine *engine, uproc = utask->uproc; uprobe_get_process(uproc); - down_write(&uproc->rwsem); - uprobe_cleanup_process(uproc); /* - * If [un]register_uprobe() is in progress, cancel the quiesce. - * Otherwise, utrace_report_exec() might call uprobe_report_exec() - * while the [un]register_uprobe thread is freeing the uproc. + * Only cleanup if we're the last thread. If we aren't, + * uprobe_report_exit() will handle cleanup. + * + * One instance of this can happen if vfork() was called, + * creating 2 tasks that share the same memory space + * (CLONE_VFORK|CLONE_VM). In this case we don't want to + * remove the probepoints from the child, since that would + * also remove them from the parent. */ - clear_utrace_quiesce(utask); + down_write(&uproc->rwsem); + if (uproc->nthreads == 1) { + uprobe_cleanup_process(uproc); + /* + * If [un]register_uprobe() is in progress, cancel the + * quiesce. Otherwise, utrace_report_exec() might + * call uprobe_report_exec() while the + * [un]register_uprobe thread is freeing the uproc. + */ + clear_utrace_quiesce(utask); + } up_write(&uproc->rwsem); /* If any [un]register_uprobe is pending, it'll clean up. */ -- 2.43.5