static void waitpid_listener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { if (exited) { Context * stopped_ctx = context_find_from_pid(pid, 1); if (stopped_ctx != NULL) { /* TODO: need call back for vxdbgCont() * assert(!stopped_ctx->stopped) can fail if a task is resumed outside TCF agent. */ assert(!stopped_ctx->stopped); assert(!stopped_ctx->exited); trace(LOG_CONTEXT, "context: exited ctx %#lx, id %#x", stopped_ctx, EXT(stopped_ctx)->pid); release_error_report(EXT(stopped_ctx)->regs_error); loc_free(EXT(stopped_ctx)->regs); EXT(stopped_ctx)->regs_error = NULL; EXT(stopped_ctx)->regs = NULL; send_context_exited_event(stopped_ctx); } } }
static int kill_context(Context * ctx) { ContextExtensionVxWorks * ext = EXT(ctx); assert(ctx->stopped); assert(ctx->parent != NULL); if (taskDelete(ext->pid) != OK) { int error = errno; trace(LOG_ALWAYS, "context: can't kill ctx %#lx, id %#x: %s", ctx, ext->pid, errno_to_str(error)); return -1; } send_context_started_event(ctx); trace(LOG_CONTEXT, "context: killed ctx %#lx, id %#x", ctx, ext->pid); release_error_report(ext->regs_error); loc_free(ext->regs); ext->regs_error = NULL; ext->regs = NULL; send_context_exited_event(ctx); return 0; }
static void event_pid_exited(pid_t pid, int status, int signal) { Context * ctx; ctx = context_find_from_pid(pid, 1); if (ctx == NULL) { ctx = find_pending(pid); if (ctx == NULL) { trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d, term signal %d", pid, status, signal); } else { assert(ctx->ref_count == 0); ctx->ref_count = 1; if (EXT(ctx)->attach_callback != NULL) { if (status == 0) status = EINVAL; EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); } assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); ctx->exited = 1; context_unlock(ctx); } } else { /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing * between PTRACE_CONT (or PTRACE_SYSCALL) and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0. */ if (EXT(ctx->parent)->pid == pid) ctx = ctx->parent; assert(EXT(ctx)->attach_callback == NULL); if (ctx->exited) { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, exited %d", ctx, pid, status, ctx->stopped, ctx->exited); } else { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d, term signal %d", ctx, pid, status, signal); ctx->exiting = 1; if (ctx->stopped) send_context_started_event(ctx); if (!list_is_empty(&ctx->children)) { LINK * l = ctx->children.next; while (l != &ctx->children) { Context * c = cldl2ctxp(l); l = l->next; assert(c->parent == ctx); if (!c->exited) { c->exiting = 1; if (c->stopped) send_context_started_event(c); release_error_report(EXT(c)->regs_error); loc_free(EXT(c)->regs); EXT(c)->regs_error = NULL; EXT(c)->regs = NULL; send_context_exited_event(c); } } } release_error_report(EXT(ctx)->regs_error); loc_free(EXT(ctx)->regs); EXT(ctx)->regs_error = NULL; EXT(ctx)->regs = NULL; send_context_exited_event(ctx); } } }