void handle_event(Event *event) { if (exiting == 1) { exiting = 2; debug(1, "ltrace about to exit"); ltrace_exiting(); } debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type); /* If the thread group or an individual task define an overriding event handler, give them a chance to kick in. We will end up calling both handlers, if the first one doesn't sink the event. */ if (event->proc != NULL) { event = call_handler(event->proc, event); if (event == NULL) /* It was handled. */ return; /* Note: the previous handler has a chance to alter * the event. */ if (event->proc != NULL && event->proc->leader != NULL && event->proc != event->proc->leader) { event = call_handler(event->proc->leader, event); if (event == NULL) return; } } switch (event->type) { case EVENT_NONE: debug(1, "event: none"); return; case EVENT_SIGNAL: debug(1, "event: signal (%s [%d])", shortsignal(event->proc, event->e_un.signum), event->e_un.signum); handle_signal(event); return; case EVENT_EXIT: debug(1, "event: exit (%d)", event->e_un.ret_val); handle_exit(event); return; case EVENT_EXIT_SIGNAL: debug(1, "event: exit signal (%s [%d])", shortsignal(event->proc, event->e_un.signum), event->e_un.signum); handle_exit_signal(event); return; case EVENT_SYSCALL: debug(1, "event: syscall (%s [%d])", sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_syscall(event); return; case EVENT_SYSRET: debug(1, "event: sysret (%s [%d])", sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_sysret(event); return; case EVENT_ARCH_SYSCALL: debug(1, "event: arch_syscall (%s [%d])", arch_sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_arch_syscall(event); return; case EVENT_ARCH_SYSRET: debug(1, "event: arch_sysret (%s [%d])", arch_sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_arch_sysret(event); return; case EVENT_CLONE: case EVENT_VFORK: debug(1, "event: clone (%u)", event->e_un.newpid); handle_clone(event); return; case EVENT_EXEC: debug(1, "event: exec()"); handle_exec(event); return; case EVENT_BREAKPOINT: debug(1, "event: breakpoint"); handle_breakpoint(event); return; case EVENT_NEW: debug(1, "event: new process"); handle_new(event); return; default: fprintf(stderr, "Error! unknown event?\n"); exit(1); } }
int handle_event(struct task *task) { int ret; if (!task) return 0; debug(DEBUG_EVENT, "+++ process pid=%d event: %d", task->pid, task->event.type); assert(task->stopped); if (task->defer_func) { ret = task->defer_func(task, task->defer_data); if (ret == RET_DELETED) return 1; task->defer_func = NULL; task->defer_data = NULL; goto out2; } struct event *event = &task->event; enum event_type type = event->type; switch (type) { case EVENT_NONE: ret = continue_task(task, task->event.e_un.signum); break; case EVENT_SIGNAL: ret = handle_signal(task); break; case EVENT_ABOUT_EXIT: ret = handle_about_exit(task); goto out1; case EVENT_EXIT: ret = handle_exit(task); break; case EVENT_EXIT_SIGNAL: ret = handle_exit_signal(task); break; case EVENT_FORK: case EVENT_VFORK: case EVENT_CLONE: ret = handle_child(task); break; case EVENT_EXEC: ret = handle_exec(task); break; case EVENT_BREAKPOINT: ret = handle_breakpoint(task); goto out2; case EVENT_NEW: ret = handle_new(task); break; default: fprintf(stderr, "fatal error, unknown event %d\n", type); abort(); } if (ret == RET_DELETED) return 1; if (ret != RET_DEFERED) { assert(task->event.type == EVENT_NONE); assert(task->stopped == 0); } out2: assert(task->is_new == 0); out1: return (ret < 0) ? ret : 0; }