mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-06 16:56:41 +08:00
various bug fixes
This commit is contained in:
parent
0155d789b4
commit
e1e243e25a
@ -83,7 +83,7 @@ static void enable_sw_breakpoint(struct task *task, struct breakpoint *bp)
|
||||
bp->sw = 1;
|
||||
bp->enabled = 1;
|
||||
|
||||
if (bp->break_insn)
|
||||
if (unlikely(options.verbose && bp->break_insn))
|
||||
fprintf(stderr, "!!!break insn pid=%d, addr=%#lx\n", task->pid, bp->addr);
|
||||
}
|
||||
|
||||
@ -529,13 +529,11 @@ void breakpoint_delete(struct task *task, struct breakpoint *bp)
|
||||
|
||||
if (unlikely(options.verbose > 1 && bp->libsym)) {
|
||||
fprintf(stderr,
|
||||
"delete %s breakpoint %s:%s [%#lx] count=%u was_hw=%u\n",
|
||||
"delete %s breakpoint %s:%s [%#lx]\n",
|
||||
bp->type == BP_SW ? "sw" : "hw",
|
||||
bp->libsym->libref->filename,
|
||||
bp->libsym->func->demangled_name,
|
||||
bp->addr,
|
||||
bp->count,
|
||||
bp->was_hw);
|
||||
bp->addr);
|
||||
}
|
||||
|
||||
bp->deleted = 1;
|
||||
|
||||
@ -353,9 +353,8 @@ static void readline_handler(char *line)
|
||||
char *linedup;
|
||||
char *s;
|
||||
|
||||
linedup = strdup(line);
|
||||
if (!linedup)
|
||||
goto finish;
|
||||
linedup = alloca(strlen(line) + 1);
|
||||
strcpy(linedup, line);
|
||||
|
||||
argv = malloc(argv_size * sizeof(*argv));
|
||||
if (!argv)
|
||||
@ -407,7 +406,7 @@ static void readline_handler(char *line)
|
||||
s += n + 1;
|
||||
}
|
||||
if (!i)
|
||||
return;
|
||||
goto finish;
|
||||
|
||||
argc = i;
|
||||
argv[i++] = NULL;
|
||||
@ -445,7 +444,6 @@ static void readline_handler(char *line)
|
||||
printf("unknown command '%s'\n", argv[0]);
|
||||
finish:
|
||||
free(argv);
|
||||
free(linedup);
|
||||
|
||||
if (quit)
|
||||
rl_callback_handler_remove();
|
||||
@ -919,5 +917,6 @@ void readline_exit(void)
|
||||
{
|
||||
if (!quit)
|
||||
rl_callback_handler_remove();
|
||||
rl_clear_history();
|
||||
}
|
||||
|
||||
|
||||
41
event.c
41
event.c
@ -114,27 +114,27 @@ static int do_clone(struct task *task, struct task *newtask)
|
||||
debug(DEBUG_EVENT, "+++ process %s pid=%d, newpid=%d", get_clone_type(task->event.type), task->pid, newtask->pid);
|
||||
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "+++ process %s(%d) pid=%d, newpid=%d\n", get_clone_type(task->event.type), task->event.type, task->pid, newtask->pid);
|
||||
fprintf(stderr, "+++ process %s pid=%d, newpid=%d\n", get_clone_type(task->event.type), task->pid, newtask->pid);
|
||||
|
||||
assert(task->stopped);
|
||||
assert(newtask->stopped);
|
||||
assert(newtask->is_new);
|
||||
|
||||
if (newtask->event.type != EVENT_NEW)
|
||||
if (unlikely(options.verbose && newtask->event.type != EVENT_NEW))
|
||||
fprintf(stderr, "!!!task new unexpected event for pid=%d: %d\n", newtask->pid, newtask->event.type);
|
||||
else
|
||||
if (newtask->event.e_un.signum)
|
||||
if (unlikely(options.verbose && newtask->event.e_un.signum))
|
||||
fprintf(stderr, "!!!task new unexpected signal for pid=%d: %d\n", newtask->pid, newtask->event.e_un.signum);
|
||||
|
||||
if (newtask->leader == newtask) {
|
||||
if (!options.follow) {
|
||||
untrace_proc(newtask);
|
||||
return RET_DELETED;
|
||||
}
|
||||
|
||||
if (task_fork(task, newtask) < 0)
|
||||
goto fail;
|
||||
|
||||
if (!options.follow) {
|
||||
remove_proc(newtask);
|
||||
return RET_DELETED;
|
||||
}
|
||||
|
||||
report_fork(newtask, task);
|
||||
}
|
||||
else {
|
||||
@ -207,7 +207,7 @@ static int handle_new(struct task *task)
|
||||
|
||||
assert(task->is_new);
|
||||
|
||||
if (task->event.e_un.signum)
|
||||
if (unlikely(options.verbose && task->event.e_un.signum))
|
||||
fprintf(stderr, "!!!task unexpected signal for pid=%d: %d\n", task->pid, task->event.e_un.signum);
|
||||
task->is_new = 0;
|
||||
|
||||
@ -338,7 +338,8 @@ static int handle_breakpoint(struct task *task)
|
||||
goto end;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s:%d\n", __func__, __LINE__);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!unhandled skip breakpoint for pid=%d\n", task->pid);
|
||||
}
|
||||
|
||||
if (unlikely(bp->deleted)) {
|
||||
@ -396,7 +397,10 @@ static int handle_breakpoint(struct task *task)
|
||||
}
|
||||
}
|
||||
|
||||
skip_breakpoint(task, bp);
|
||||
if (task->bp_skipped)
|
||||
task->bp_skipped = 0;
|
||||
else
|
||||
skip_breakpoint(task, bp);
|
||||
end:
|
||||
breakpoint_put(bp);
|
||||
return 0;
|
||||
@ -416,10 +420,12 @@ int handle_event(struct task *task)
|
||||
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;
|
||||
|
||||
return ret;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
struct event *event = &task->event;
|
||||
@ -434,7 +440,7 @@ int handle_event(struct task *task)
|
||||
break;
|
||||
case EVENT_ABOUT_EXIT:
|
||||
ret = handle_about_exit(task);
|
||||
goto out;
|
||||
goto out1;
|
||||
case EVENT_EXIT:
|
||||
ret = handle_exit(task);
|
||||
break;
|
||||
@ -451,12 +457,12 @@ int handle_event(struct task *task)
|
||||
break;
|
||||
case EVENT_BREAKPOINT:
|
||||
ret = handle_breakpoint(task);
|
||||
goto out;
|
||||
goto out1;
|
||||
case EVENT_NEW:
|
||||
ret = handle_new(task);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "!!!pid=%d, unknown event %d\n", task->pid, type);
|
||||
fprintf(stderr, "fatal error, unknown event %d\n", type);
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -467,8 +473,9 @@ int handle_event(struct task *task)
|
||||
assert(task->event.type == EVENT_NONE);
|
||||
assert(task->stopped == 0);
|
||||
}
|
||||
out2:
|
||||
assert(task->is_new == 0);
|
||||
out:
|
||||
out1:
|
||||
return (ret < 0) ? ret : 0;
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#define IS64BIT 0
|
||||
#endif
|
||||
|
||||
#define MEMTRACE_SI_VERSION 8
|
||||
#define MEMTRACE_SI_VERSION 9
|
||||
|
||||
#define MEMTRACE_SI_FORK 1
|
||||
#define MEMTRACE_SI_EXEC 2
|
||||
@ -100,6 +100,7 @@ struct __attribute__((packed)) mt_pid_payload {
|
||||
|
||||
struct __attribute__((packed)) mt_scan_payload {
|
||||
uint32_t ptr_size;
|
||||
uint32_t pad; // for 64 bit alignment
|
||||
uint64_t mask;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
3
report.c
3
report.c
@ -106,6 +106,9 @@ static void report_alloc32(struct task *task, enum mt_operation op, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
task->bp_skipped = 1;
|
||||
skip_breakpoint(task, task->event.e_un.breakpoint);
|
||||
|
||||
server_send_msg(op, task->leader->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
|
||||
@ -256,6 +256,9 @@ void *mem_scan(struct task *task, struct mt_msg *cmd, void *payload, unsigned lo
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "+++ scan for memory leaks...\n");
|
||||
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ static inline int wait_task(struct task *task, int *status)
|
||||
|
||||
ret = TEMP_FAILURE_RETRY(waitpid(task ? task->pid : -1, status, __WALL));
|
||||
if (ret == -1) {
|
||||
if (task)
|
||||
if (unlikely(options.verbose && task))
|
||||
fprintf(stderr, "!!!%s: waitpid pid=%d %s\n", __func__, task->pid, strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
@ -75,23 +75,25 @@ static int trace_setup(struct task *task, int status, int signum)
|
||||
{
|
||||
int sig;
|
||||
|
||||
if (!WIFSTOPPED(status)) {
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!pid=%d not stopped\n", task->pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
task->attached = 1;
|
||||
task->stopped = 1;
|
||||
task->leader->threads_stopped++;
|
||||
task->event.type = EVENT_NEW;
|
||||
task->event.e_un.signum = 0;
|
||||
|
||||
if (!WIFSTOPPED(status)) {
|
||||
fprintf(stderr, "!!!pid=%d not stopped\n", task->pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sig = WSTOPSIG(status);
|
||||
|
||||
if (sig != signum) {
|
||||
task->event.e_un.signum = sig;
|
||||
|
||||
fprintf(stderr, "!!!pid=%d unexpected trace signal (got:%d expected:%d)\n", task->pid, sig, signum);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!pid=%d unexpected trace signal (got:%d expected:%d)\n", task->pid, sig, signum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -123,17 +125,18 @@ int trace_wait(struct task *task)
|
||||
|
||||
static int child_event(struct task *task, enum event_type ev)
|
||||
{
|
||||
unsigned long data;
|
||||
unsigned long data = 0;
|
||||
|
||||
debug(DEBUG_EVENT, "child event %d pid=%d, newpid=%d", ev, task->pid, task->event.e_un.newpid);
|
||||
|
||||
if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) {
|
||||
if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1))
|
||||
debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pid = data;
|
||||
|
||||
if (!pid)
|
||||
return -1;
|
||||
|
||||
if (!pid2task(pid)) {
|
||||
struct task *child = task_new(pid);
|
||||
|
||||
@ -174,7 +177,8 @@ static int _process_event(struct task *task, int status)
|
||||
}
|
||||
|
||||
if (!WIFSTOPPED(status)) {
|
||||
fprintf(stderr, "!!!not WIFSTOPPED pid=%d\n", task->pid);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!not WIFSTOPPED pid=%d\n", task->pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -187,7 +191,8 @@ static int _process_event(struct task *task, int status)
|
||||
}
|
||||
|
||||
if (!task->bad) {
|
||||
fprintf(stderr, "!!!unexpected state for pid=%d, expected signal SIGSTOP (%d %d)\n", task->pid, sig, status >> 16);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!unexpected state for pid=%d, expected signal SIGSTOP (%d %d)\n", task->pid, sig, status >> 16);
|
||||
task->bad = 1;
|
||||
}
|
||||
}
|
||||
@ -210,24 +215,24 @@ static int _process_event(struct task *task, int status)
|
||||
return 0;
|
||||
case PTRACE_EVENT_EXIT:
|
||||
{
|
||||
unsigned long data;
|
||||
unsigned long data = 0;
|
||||
|
||||
debug(DEBUG_EVENT, "ABOUT_EXIT: pid=%d", task->pid);
|
||||
|
||||
if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) {
|
||||
if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1))
|
||||
debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
task->event.e_un.ret_val = WEXITSTATUS(data);
|
||||
task->event.type = EVENT_ABOUT_EXIT;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "!!!PTRACE_EVENT_????? pid=%d %d\n", task->pid, status >> 16);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!PTRACE_EVENT_????? pid=%d %d\n", task->pid, status >> 16);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sig)
|
||||
if (unlikely(options.verbose && !sig))
|
||||
fprintf(stderr, "!!!%s: sig == 0 pid=%d\n", __func__, task->pid);
|
||||
|
||||
if (sig == SIGSTOP) {
|
||||
@ -238,8 +243,10 @@ static int _process_event(struct task *task, int status)
|
||||
else {
|
||||
if (likely(siginfo.si_pid == mtrace_pid))
|
||||
sig = 0;
|
||||
else
|
||||
fprintf(stderr, "!!!%s: SIGSTOP pid=%d %d %d %d %d\n", __func__, task->pid, siginfo.si_signo, siginfo.si_errno, siginfo.si_code, siginfo.si_pid);
|
||||
else {
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: SIGSTOP pid=%d %d %d %d %d\n", __func__, task->pid, siginfo.si_signo, siginfo.si_errno, siginfo.si_code, siginfo.si_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,7 +314,8 @@ static struct task * process_event(struct task *task, int status)
|
||||
{
|
||||
bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK);
|
||||
if (unlikely(!bp)) {
|
||||
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
|
||||
return task;
|
||||
}
|
||||
#if HW_BREAKPOINTS > 0
|
||||
@ -345,20 +353,18 @@ void trace_me(void)
|
||||
|
||||
static inline int chk_signal(struct task *task, int signum)
|
||||
{
|
||||
#if 1
|
||||
if (signum == SIGSTOP)
|
||||
fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid);
|
||||
|
||||
if (signum == SIGTRAP)
|
||||
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
|
||||
#endif
|
||||
if (unlikely(options.verbose)) {
|
||||
if (signum == SIGSTOP)
|
||||
fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid);
|
||||
|
||||
if (signum == SIGTRAP)
|
||||
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
|
||||
}
|
||||
return signum;
|
||||
}
|
||||
|
||||
int untrace_task(struct task *task)
|
||||
{
|
||||
int ret;
|
||||
int sig = 0;
|
||||
|
||||
assert(task->stopped);
|
||||
@ -366,8 +372,7 @@ int untrace_task(struct task *task)
|
||||
if (unlikely(ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1)) {
|
||||
if (errno != ESRCH)
|
||||
fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno));
|
||||
ret = -1;
|
||||
goto skip;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (task->event.type == EVENT_SIGNAL || task->event.type == EVENT_NONE)
|
||||
@ -376,16 +381,11 @@ int untrace_task(struct task *task)
|
||||
if (unlikely(ptrace(PTRACE_DETACH, task->pid, 0, sig) == -1)) {
|
||||
if (errno != ESRCH)
|
||||
fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno));
|
||||
ret = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
task_kill(task, SIGCONT);
|
||||
skip:
|
||||
task->leader->threads_stopped--;
|
||||
task->stopped = 0;
|
||||
task->attached = 0;
|
||||
|
||||
return ret;
|
||||
// task_kill(task, SIGCONT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stop_task(struct task *task)
|
||||
@ -397,6 +397,7 @@ void stop_task(struct task *task)
|
||||
int status;
|
||||
|
||||
task_kill(task, SIGSTOP);
|
||||
|
||||
if (wait_task(task, &status) != -1)
|
||||
_process_event(task, status);
|
||||
}
|
||||
@ -441,14 +442,14 @@ int continue_task(struct task *task, int signum)
|
||||
assert(task->leader != NULL);
|
||||
assert(task->stopped);
|
||||
|
||||
if (signum >= 0x80)
|
||||
if (unlikely(options.verbose && signum >= 0x80))
|
||||
fprintf(stderr, "!!!signum >= 0x80 pid=%d: %d\n", task->pid, signum);
|
||||
|
||||
task->leader->threads_stopped--;
|
||||
task->stopped = 0;
|
||||
task->event.type = EVENT_NONE;
|
||||
|
||||
if (signum == SIGTRAP)
|
||||
if (unlikely(options.verbose && signum == SIGTRAP))
|
||||
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
|
||||
|
||||
if (unlikely(ptrace(PTRACE_CONT, task->pid, 0, chk_signal(task, signum)) == -1)) {
|
||||
@ -487,9 +488,10 @@ void stop_threads(struct task *task)
|
||||
|
||||
each_task(leader, &do_stop_cb, NULL);
|
||||
|
||||
while (leader->threads != leader->threads_stopped) {
|
||||
task = wait_event();
|
||||
while(leader->threads != leader->threads_stopped) {
|
||||
assert(leader->threads > leader->threads_stopped);
|
||||
|
||||
task = wait_event();
|
||||
if (task)
|
||||
queue_event(task);
|
||||
}
|
||||
@ -511,7 +513,8 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
|
||||
task->event.type = EVENT_NONE;
|
||||
|
||||
if (unlikely(singlestep(task) == -1)) {
|
||||
fprintf(stderr, "!!!%s: single step failed pid=%d\n", __func__, task->pid);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: single step failed pid=%d\n", __func__, task->pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -521,7 +524,8 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
|
||||
sig = _process_event(task, status);
|
||||
|
||||
if (sig == -1) {
|
||||
fprintf(stderr, "!!!%s: failed _process_event pid=%d\n", __func__, task->pid);
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: failed _process_event pid=%d\n", __func__, task->pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -535,7 +539,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
|
||||
}
|
||||
|
||||
if (sig != SIGTRAP) {
|
||||
if (sig == SIGSTOP)
|
||||
if (unlikely(options.verbose && sig == SIGSTOP))
|
||||
fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid);
|
||||
queue_event(task);
|
||||
return 1;
|
||||
@ -555,7 +559,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
|
||||
static int ptrace_singlestep(struct task *task)
|
||||
{
|
||||
if (unlikely(ptrace(PTRACE_SINGLESTEP, task->pid, 0, 0) == -1)) {
|
||||
if (errno != ESRCH)
|
||||
if (unlikely(options.verbose && errno != ESRCH))
|
||||
fprintf(stderr, "!!!%s: PTRACE_SINGLESTEP pid=%d %s\n", __func__, task->pid, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
@ -600,7 +604,43 @@ struct task *wait_event(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(!task->stopped);
|
||||
if (unlikely(task->stopped)) {
|
||||
fprintf(stderr, "!!!%s: pid=%d already stopped (%u)\n", __func__, task->pid, task->event.type);
|
||||
|
||||
if (WIFSIGNALED(status)) {
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: exit signal for stopped pid=%d\n", __func__, task->pid);
|
||||
|
||||
task->event.type = EVENT_EXIT_SIGNAL;
|
||||
task->event.e_un.signum = WTERMSIG(status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: exited process for stopped pid=%d\n", __func__, task->pid);
|
||||
|
||||
task->event.type = EVENT_EXIT;
|
||||
task->event.e_un.ret_val = WEXITSTATUS(status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((status >> 16) == PTRACE_EVENT_EXIT) {
|
||||
unsigned long data = 0;
|
||||
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: exit event for stopped pid=%d\n", __func__, task->pid);
|
||||
|
||||
debug(DEBUG_EVENT, "ABOUT_EXIT: pid=%d", task->pid);
|
||||
|
||||
if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1))
|
||||
debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno));
|
||||
|
||||
task->event.e_un.ret_val = WEXITSTATUS(data);
|
||||
task->event.type = EVENT_ABOUT_EXIT;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
task = process_event(task, status);
|
||||
if (task)
|
||||
@ -659,7 +699,8 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le
|
||||
|
||||
if (errno != EFAULT) {
|
||||
if (errno != ENOSYS) {
|
||||
fprintf(stderr, "!!!%s: pid=%d process_vm_readv: %s\n", __func__, task->pid, strerror(errno));
|
||||
if (unlikely(options.verbose))
|
||||
fprintf(stderr, "!!!%s: pid=%d process_vm_readv: %s\n", __func__, task->pid, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
97
task.c
97
task.c
@ -21,6 +21,8 @@
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -153,6 +155,15 @@ struct task *pid2task(pid_t pid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void delete_task(struct task *task)
|
||||
{
|
||||
arch_task_destroy(task);
|
||||
os_task_destroy(task);
|
||||
delete_pid(task);
|
||||
breakpoint_clear_all(task);
|
||||
free(task);
|
||||
}
|
||||
|
||||
static int leader_setup(struct task *leader, int was_attached)
|
||||
{
|
||||
if (!elf_read_main_binary(leader, was_attached))
|
||||
@ -212,29 +223,13 @@ static int task_init(struct task *task)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leader_cleanup(struct task *leader)
|
||||
static void leader_cleanup(struct task *leader)
|
||||
{
|
||||
if (!leader)
|
||||
return 0;
|
||||
|
||||
if (--leader->threads)
|
||||
return 0;
|
||||
|
||||
library_clear_all(leader);
|
||||
breakpoint_clear_all(leader);
|
||||
backtrace_destroy(leader);
|
||||
|
||||
list_del(&leader->leader_list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void leader_release(struct task *leader)
|
||||
{
|
||||
if (!leader_cleanup(leader))
|
||||
return;
|
||||
|
||||
free(leader);
|
||||
}
|
||||
|
||||
static void task_destroy(struct task *task)
|
||||
@ -248,23 +243,32 @@ static void task_destroy(struct task *task)
|
||||
|
||||
stop_task(task);
|
||||
|
||||
if (leader != task)
|
||||
list_del(&task->task_list);
|
||||
|
||||
leader->threads--;
|
||||
leader->threads_stopped--;
|
||||
|
||||
if (task->event.type == EVENT_BREAKPOINT)
|
||||
breakpoint_put(task->event.e_un.breakpoint);
|
||||
|
||||
arch_task_destroy(task);
|
||||
os_task_destroy(task);
|
||||
task_reset_bp(task);
|
||||
remove_event(task);
|
||||
breakpoint_hw_destroy(task);
|
||||
delete_pid(task);
|
||||
|
||||
if (!leader->threads)
|
||||
leader_cleanup(leader);
|
||||
|
||||
untrace_task(task);
|
||||
remove_event(task);
|
||||
|
||||
if (leader != task) {
|
||||
list_del(&task->task_list);
|
||||
if (leader != task)
|
||||
free(task);
|
||||
}
|
||||
|
||||
leader_release(leader);
|
||||
if (!leader->threads)
|
||||
free(leader);
|
||||
}
|
||||
|
||||
struct task *task_new(pid_t pid)
|
||||
@ -279,6 +283,7 @@ struct task *task_new(pid_t pid)
|
||||
task->pid = pid;
|
||||
task->attached = 0;
|
||||
task->stopped = 0;
|
||||
task->bp_skipped = 0;
|
||||
task->is_new = 1;
|
||||
task->defer_func = NULL;
|
||||
task->defer_data = NULL;
|
||||
@ -288,7 +293,6 @@ struct task *task_new(pid_t pid)
|
||||
#if HW_BREAKPOINTS > 1
|
||||
INIT_LIST_HEAD(&task->hw_bp_list);
|
||||
#endif
|
||||
|
||||
library_setup(task);
|
||||
|
||||
init_event(task);
|
||||
@ -322,16 +326,17 @@ int process_exec(struct task *task)
|
||||
|
||||
each_task(leader, &remove_task_cb, leader);
|
||||
|
||||
assert(leader->threads == 1);
|
||||
|
||||
os_task_destroy(leader);
|
||||
arch_task_destroy(leader);
|
||||
leader_cleanup(leader);
|
||||
|
||||
assert(leader->threads == 0);
|
||||
|
||||
if (task_init(leader) < 0)
|
||||
goto fail;
|
||||
|
||||
assert(leader->leader == leader);
|
||||
assert(leader->threads == 1);
|
||||
assert(leader->threads_stopped == 1);
|
||||
|
||||
if (leader_setup(leader, 0) < 0)
|
||||
@ -347,9 +352,10 @@ struct task *task_create(char **argv)
|
||||
{
|
||||
struct task *task;
|
||||
pid_t pid;
|
||||
int ret;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
return NULL;
|
||||
}
|
||||
@ -365,27 +371,34 @@ struct task *task_create(char **argv)
|
||||
|
||||
task = task_new(pid);
|
||||
if (!task)
|
||||
goto fail2;
|
||||
goto fail1;
|
||||
|
||||
if (trace_wait(task))
|
||||
goto fail1;
|
||||
|
||||
if (trace_set_options(task) < 0)
|
||||
goto fail2;
|
||||
goto fail1;
|
||||
|
||||
if (leader_setup(task, 0) < 0)
|
||||
goto fail1;
|
||||
goto fail2;
|
||||
|
||||
if (handle_event(task))
|
||||
goto fail1;
|
||||
ret = handle_event(task);
|
||||
if (ret < 0)
|
||||
goto fail2;
|
||||
|
||||
if (ret > 0)
|
||||
return NULL;
|
||||
|
||||
return task;
|
||||
fail2:
|
||||
fprintf(stderr, "failed to initialize process %d\n", pid);
|
||||
fail1:
|
||||
if (task)
|
||||
remove_proc(task);
|
||||
kill(pid, SIGKILL);
|
||||
fprintf(stderr, "failed to initialize process %d\n", pid);
|
||||
if (task) {
|
||||
delete_task(task);
|
||||
kill(pid, SIGKILL);
|
||||
}
|
||||
return NULL;
|
||||
fail2:
|
||||
remove_proc(task);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -475,9 +488,12 @@ static struct task *open_one_pid(pid_t pid)
|
||||
if (trace_set_options(task) < 0)
|
||||
goto fail2;
|
||||
|
||||
queue_event(task);
|
||||
|
||||
return task;
|
||||
fail2:
|
||||
task_destroy(task);
|
||||
delete_task(task);
|
||||
kill(pid, SIGCONT);
|
||||
fail1:
|
||||
return NULL;
|
||||
}
|
||||
@ -571,7 +587,9 @@ void each_process(void (*cb)(struct task *task))
|
||||
{
|
||||
struct list_head *it, *next;
|
||||
|
||||
list_for_each_safe(it, next, &list_of_leaders) {
|
||||
for(it = list_of_leaders.prev; it != &list_of_leaders; it = next) {
|
||||
next = it->prev;
|
||||
|
||||
struct task *task = container_of(it, struct task, leader_list);
|
||||
|
||||
(*cb)(task);
|
||||
@ -603,7 +621,10 @@ void remove_proc(struct task *leader)
|
||||
|
||||
assert(leader->leader == leader);
|
||||
|
||||
stop_threads(leader);
|
||||
breakpoint_disable_all(leader);
|
||||
each_task(leader, &remove_task_cb, leader);
|
||||
assert(leader->threads == 1);
|
||||
task_destroy(leader);
|
||||
}
|
||||
|
||||
|
||||
1
task.h
1
task.h
@ -49,6 +49,7 @@ struct task {
|
||||
unsigned int stopped:1;
|
||||
unsigned int is_new:1;
|
||||
unsigned int bad:1;
|
||||
unsigned int bp_skipped:1;
|
||||
|
||||
struct breakpoint *breakpoint;
|
||||
struct library_symbol *libsym;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user