various bug fixes

This commit is contained in:
Stefani Seibold 2018-04-12 11:00:20 +02:00
parent 0155d789b4
commit e1e243e25a
10 changed files with 191 additions and 117 deletions

View File

@ -83,7 +83,7 @@ static void enable_sw_breakpoint(struct task *task, struct breakpoint *bp)
bp->sw = 1; bp->sw = 1;
bp->enabled = 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); 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)) { if (unlikely(options.verbose > 1 && bp->libsym)) {
fprintf(stderr, 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->type == BP_SW ? "sw" : "hw",
bp->libsym->libref->filename, bp->libsym->libref->filename,
bp->libsym->func->demangled_name, bp->libsym->func->demangled_name,
bp->addr, bp->addr);
bp->count,
bp->was_hw);
} }
bp->deleted = 1; bp->deleted = 1;

View File

@ -353,9 +353,8 @@ static void readline_handler(char *line)
char *linedup; char *linedup;
char *s; char *s;
linedup = strdup(line); linedup = alloca(strlen(line) + 1);
if (!linedup) strcpy(linedup, line);
goto finish;
argv = malloc(argv_size * sizeof(*argv)); argv = malloc(argv_size * sizeof(*argv));
if (!argv) if (!argv)
@ -407,7 +406,7 @@ static void readline_handler(char *line)
s += n + 1; s += n + 1;
} }
if (!i) if (!i)
return; goto finish;
argc = i; argc = i;
argv[i++] = NULL; argv[i++] = NULL;
@ -445,7 +444,6 @@ static void readline_handler(char *line)
printf("unknown command '%s'\n", argv[0]); printf("unknown command '%s'\n", argv[0]);
finish: finish:
free(argv); free(argv);
free(linedup);
if (quit) if (quit)
rl_callback_handler_remove(); rl_callback_handler_remove();
@ -919,5 +917,6 @@ void readline_exit(void)
{ {
if (!quit) if (!quit)
rl_callback_handler_remove(); rl_callback_handler_remove();
rl_clear_history();
} }

41
event.c
View File

@ -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); debug(DEBUG_EVENT, "+++ process %s pid=%d, newpid=%d", get_clone_type(task->event.type), task->pid, newtask->pid);
if (unlikely(options.verbose)) 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(task->stopped);
assert(newtask->stopped); assert(newtask->stopped);
assert(newtask->is_new); 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); fprintf(stderr, "!!!task new unexpected event for pid=%d: %d\n", newtask->pid, newtask->event.type);
else 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); fprintf(stderr, "!!!task new unexpected signal for pid=%d: %d\n", newtask->pid, newtask->event.e_un.signum);
if (newtask->leader == newtask) { if (newtask->leader == newtask) {
if (!options.follow) {
untrace_proc(newtask);
return RET_DELETED;
}
if (task_fork(task, newtask) < 0) if (task_fork(task, newtask) < 0)
goto fail; goto fail;
if (!options.follow) {
remove_proc(newtask);
return RET_DELETED;
}
report_fork(newtask, task); report_fork(newtask, task);
} }
else { else {
@ -207,7 +207,7 @@ static int handle_new(struct task *task)
assert(task->is_new); 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); fprintf(stderr, "!!!task unexpected signal for pid=%d: %d\n", task->pid, task->event.e_un.signum);
task->is_new = 0; task->is_new = 0;
@ -338,7 +338,8 @@ static int handle_breakpoint(struct task *task)
goto end; 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)) { 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: end:
breakpoint_put(bp); breakpoint_put(bp);
return 0; return 0;
@ -416,10 +420,12 @@ int handle_event(struct task *task)
if (task->defer_func) { if (task->defer_func) {
ret = task->defer_func(task, task->defer_data); ret = task->defer_func(task, task->defer_data);
if (ret == RET_DELETED)
return 1;
task->defer_func = NULL; task->defer_func = NULL;
task->defer_data = NULL; task->defer_data = NULL;
goto out2;
return ret;
} }
struct event *event = &task->event; struct event *event = &task->event;
@ -434,7 +440,7 @@ int handle_event(struct task *task)
break; break;
case EVENT_ABOUT_EXIT: case EVENT_ABOUT_EXIT:
ret = handle_about_exit(task); ret = handle_about_exit(task);
goto out; goto out1;
case EVENT_EXIT: case EVENT_EXIT:
ret = handle_exit(task); ret = handle_exit(task);
break; break;
@ -451,12 +457,12 @@ int handle_event(struct task *task)
break; break;
case EVENT_BREAKPOINT: case EVENT_BREAKPOINT:
ret = handle_breakpoint(task); ret = handle_breakpoint(task);
goto out; goto out1;
case EVENT_NEW: case EVENT_NEW:
ret = handle_new(task); ret = handle_new(task);
break; break;
default: default:
fprintf(stderr, "!!!pid=%d, unknown event %d\n", task->pid, type); fprintf(stderr, "fatal error, unknown event %d\n", type);
abort(); abort();
} }
@ -467,8 +473,9 @@ int handle_event(struct task *task)
assert(task->event.type == EVENT_NONE); assert(task->event.type == EVENT_NONE);
assert(task->stopped == 0); assert(task->stopped == 0);
} }
out2:
assert(task->is_new == 0); assert(task->is_new == 0);
out: out1:
return (ret < 0) ? ret : 0; return (ret < 0) ? ret : 0;
} }

View File

@ -31,7 +31,7 @@
#define IS64BIT 0 #define IS64BIT 0
#endif #endif
#define MEMTRACE_SI_VERSION 8 #define MEMTRACE_SI_VERSION 9
#define MEMTRACE_SI_FORK 1 #define MEMTRACE_SI_FORK 1
#define MEMTRACE_SI_EXEC 2 #define MEMTRACE_SI_EXEC 2
@ -100,6 +100,7 @@ struct __attribute__((packed)) mt_pid_payload {
struct __attribute__((packed)) mt_scan_payload { struct __attribute__((packed)) mt_scan_payload {
uint32_t ptr_size; uint32_t ptr_size;
uint32_t pad; // for 64 bit alignment
uint64_t mask; uint64_t mask;
char data[0]; char data[0];
}; };

View File

@ -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)); server_send_msg(op, task->leader->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t));
} }

View File

@ -256,6 +256,9 @@ void *mem_scan(struct task *task, struct mt_msg *cmd, void *payload, unsigned lo
unsigned long start; unsigned long start;
unsigned long end; unsigned long end;
if (unlikely(options.verbose))
fprintf(stderr, "+++ scan for memory leaks...\n");
if (!n) if (!n)
return NULL; return NULL;

View File

@ -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)); ret = TEMP_FAILURE_RETRY(waitpid(task ? task->pid : -1, status, __WALL));
if (ret == -1) { if (ret == -1) {
if (task) if (unlikely(options.verbose && task))
fprintf(stderr, "!!!%s: waitpid pid=%d %s\n", __func__, task->pid, strerror(errno)); fprintf(stderr, "!!!%s: waitpid pid=%d %s\n", __func__, task->pid, strerror(errno));
} }
return ret; return ret;
@ -75,23 +75,25 @@ static int trace_setup(struct task *task, int status, int signum)
{ {
int sig; int sig;
if (!WIFSTOPPED(status)) {
if (unlikely(options.verbose))
fprintf(stderr, "!!!pid=%d not stopped\n", task->pid);
return -1;
}
task->attached = 1; task->attached = 1;
task->stopped = 1; task->stopped = 1;
task->leader->threads_stopped++; task->leader->threads_stopped++;
task->event.type = EVENT_NEW; task->event.type = EVENT_NEW;
task->event.e_un.signum = 0; task->event.e_un.signum = 0;
if (!WIFSTOPPED(status)) {
fprintf(stderr, "!!!pid=%d not stopped\n", task->pid);
return -1;
}
sig = WSTOPSIG(status); sig = WSTOPSIG(status);
if (sig != signum) { if (sig != signum) {
task->event.e_un.signum = sig; 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; return -1;
} }
@ -123,17 +125,18 @@ int trace_wait(struct task *task)
static int child_event(struct task *task, enum event_type ev) 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); 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)); debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno));
return -1;
}
int pid = data; int pid = data;
if (!pid)
return -1;
if (!pid2task(pid)) { if (!pid2task(pid)) {
struct task *child = task_new(pid); struct task *child = task_new(pid);
@ -174,7 +177,8 @@ static int _process_event(struct task *task, int status)
} }
if (!WIFSTOPPED(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; return -1;
} }
@ -187,7 +191,8 @@ static int _process_event(struct task *task, int status)
} }
if (!task->bad) { 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; task->bad = 1;
} }
} }
@ -210,24 +215,24 @@ static int _process_event(struct task *task, int status)
return 0; return 0;
case PTRACE_EVENT_EXIT: case PTRACE_EVENT_EXIT:
{ {
unsigned long data; unsigned long data = 0;
debug(DEBUG_EVENT, "ABOUT_EXIT: pid=%d", task->pid); 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)); debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno));
return -1;
}
task->event.e_un.ret_val = WEXITSTATUS(data); task->event.e_un.ret_val = WEXITSTATUS(data);
task->event.type = EVENT_ABOUT_EXIT; task->event.type = EVENT_ABOUT_EXIT;
return 0; return 0;
} }
default: 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; break;
} }
if (!sig) if (unlikely(options.verbose && !sig))
fprintf(stderr, "!!!%s: sig == 0 pid=%d\n", __func__, task->pid); fprintf(stderr, "!!!%s: sig == 0 pid=%d\n", __func__, task->pid);
if (sig == SIGSTOP) { if (sig == SIGSTOP) {
@ -238,8 +243,10 @@ static int _process_event(struct task *task, int status)
else { else {
if (likely(siginfo.si_pid == mtrace_pid)) if (likely(siginfo.si_pid == mtrace_pid))
sig = 0; sig = 0;
else 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); 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); bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK);
if (unlikely(!bp)) { 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; return task;
} }
#if HW_BREAKPOINTS > 0 #if HW_BREAKPOINTS > 0
@ -345,20 +353,18 @@ void trace_me(void)
static inline int chk_signal(struct task *task, int signum) static inline int chk_signal(struct task *task, int signum)
{ {
#if 1 if (unlikely(options.verbose)) {
if (signum == SIGSTOP) if (signum == SIGSTOP)
fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid); 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 (signum == SIGTRAP)
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
}
return signum; return signum;
} }
int untrace_task(struct task *task) int untrace_task(struct task *task)
{ {
int ret;
int sig = 0; int sig = 0;
assert(task->stopped); 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 (unlikely(ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno));
ret = -1; return -1;
goto skip;
} }
if (task->event.type == EVENT_SIGNAL || task->event.type == EVENT_NONE) 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 (unlikely(ptrace(PTRACE_DETACH, task->pid, 0, sig) == -1)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno));
ret = -1; return -1;
} }
task_kill(task, SIGCONT); // task_kill(task, SIGCONT);
skip: return 0;
task->leader->threads_stopped--;
task->stopped = 0;
task->attached = 0;
return ret;
} }
void stop_task(struct task *task) void stop_task(struct task *task)
@ -397,6 +397,7 @@ void stop_task(struct task *task)
int status; int status;
task_kill(task, SIGSTOP); task_kill(task, SIGSTOP);
if (wait_task(task, &status) != -1) if (wait_task(task, &status) != -1)
_process_event(task, status); _process_event(task, status);
} }
@ -441,14 +442,14 @@ int continue_task(struct task *task, int signum)
assert(task->leader != NULL); assert(task->leader != NULL);
assert(task->stopped); assert(task->stopped);
if (signum >= 0x80) if (unlikely(options.verbose && signum >= 0x80))
fprintf(stderr, "!!!signum >= 0x80 pid=%d: %d\n", task->pid, signum); fprintf(stderr, "!!!signum >= 0x80 pid=%d: %d\n", task->pid, signum);
task->leader->threads_stopped--; task->leader->threads_stopped--;
task->stopped = 0; task->stopped = 0;
task->event.type = EVENT_NONE; task->event.type = EVENT_NONE;
if (signum == SIGTRAP) if (unlikely(options.verbose && signum == SIGTRAP))
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid); fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
if (unlikely(ptrace(PTRACE_CONT, task->pid, 0, chk_signal(task, signum)) == -1)) { 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); each_task(leader, &do_stop_cb, NULL);
while (leader->threads != leader->threads_stopped) { while(leader->threads != leader->threads_stopped) {
task = wait_event(); assert(leader->threads > leader->threads_stopped);
task = wait_event();
if (task) if (task)
queue_event(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; task->event.type = EVENT_NONE;
if (unlikely(singlestep(task) == -1)) { 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; return -1;
} }
@ -521,7 +524,8 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
sig = _process_event(task, status); sig = _process_event(task, status);
if (sig == -1) { 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; return 0;
} }
@ -535,7 +539,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
} }
if (sig != SIGTRAP) { if (sig != SIGTRAP) {
if (sig == SIGSTOP) if (unlikely(options.verbose && sig == SIGSTOP))
fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid); fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid);
queue_event(task); queue_event(task);
return 1; 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) static int ptrace_singlestep(struct task *task)
{ {
if (unlikely(ptrace(PTRACE_SINGLESTEP, task->pid, 0, 0) == -1)) { 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)); fprintf(stderr, "!!!%s: PTRACE_SINGLESTEP pid=%d %s\n", __func__, task->pid, strerror(errno));
return -1; return -1;
} }
@ -600,7 +604,43 @@ struct task *wait_event(void)
return NULL; 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); task = process_event(task, status);
if (task) 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 != EFAULT) {
if (errno != ENOSYS) { 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; return -1;
} }

97
task.c
View File

@ -21,6 +21,8 @@
* 02110-1301 USA * 02110-1301 USA
*/ */
#define _GNU_SOURCE
#include "config.h" #include "config.h"
#include <sys/types.h> #include <sys/types.h>
@ -153,6 +155,15 @@ struct task *pid2task(pid_t pid)
return NULL; 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) static int leader_setup(struct task *leader, int was_attached)
{ {
if (!elf_read_main_binary(leader, was_attached)) if (!elf_read_main_binary(leader, was_attached))
@ -212,29 +223,13 @@ static int task_init(struct task *task)
return 0; 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); library_clear_all(leader);
breakpoint_clear_all(leader); breakpoint_clear_all(leader);
backtrace_destroy(leader); backtrace_destroy(leader);
list_del(&leader->leader_list); 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) static void task_destroy(struct task *task)
@ -248,23 +243,32 @@ static void task_destroy(struct task *task)
stop_task(task); stop_task(task);
if (leader != task)
list_del(&task->task_list);
leader->threads--;
leader->threads_stopped--;
if (task->event.type == EVENT_BREAKPOINT) if (task->event.type == EVENT_BREAKPOINT)
breakpoint_put(task->event.e_un.breakpoint); breakpoint_put(task->event.e_un.breakpoint);
arch_task_destroy(task); arch_task_destroy(task);
os_task_destroy(task); os_task_destroy(task);
task_reset_bp(task); task_reset_bp(task);
remove_event(task);
breakpoint_hw_destroy(task); breakpoint_hw_destroy(task);
delete_pid(task); delete_pid(task);
if (!leader->threads)
leader_cleanup(leader);
untrace_task(task); untrace_task(task);
remove_event(task);
if (leader != task) { if (leader != task)
list_del(&task->task_list);
free(task); free(task);
}
leader_release(leader); if (!leader->threads)
free(leader);
} }
struct task *task_new(pid_t pid) struct task *task_new(pid_t pid)
@ -279,6 +283,7 @@ struct task *task_new(pid_t pid)
task->pid = pid; task->pid = pid;
task->attached = 0; task->attached = 0;
task->stopped = 0; task->stopped = 0;
task->bp_skipped = 0;
task->is_new = 1; task->is_new = 1;
task->defer_func = NULL; task->defer_func = NULL;
task->defer_data = NULL; task->defer_data = NULL;
@ -288,7 +293,6 @@ struct task *task_new(pid_t pid)
#if HW_BREAKPOINTS > 1 #if HW_BREAKPOINTS > 1
INIT_LIST_HEAD(&task->hw_bp_list); INIT_LIST_HEAD(&task->hw_bp_list);
#endif #endif
library_setup(task); library_setup(task);
init_event(task); init_event(task);
@ -322,16 +326,17 @@ int process_exec(struct task *task)
each_task(leader, &remove_task_cb, leader); each_task(leader, &remove_task_cb, leader);
assert(leader->threads == 1);
os_task_destroy(leader); os_task_destroy(leader);
arch_task_destroy(leader); arch_task_destroy(leader);
leader_cleanup(leader); leader_cleanup(leader);
assert(leader->threads == 0);
if (task_init(leader) < 0) if (task_init(leader) < 0)
goto fail; goto fail;
assert(leader->leader == leader); assert(leader->leader == leader);
assert(leader->threads == 1);
assert(leader->threads_stopped == 1); assert(leader->threads_stopped == 1);
if (leader_setup(leader, 0) < 0) if (leader_setup(leader, 0) < 0)
@ -347,9 +352,10 @@ struct task *task_create(char **argv)
{ {
struct task *task; struct task *task;
pid_t pid; pid_t pid;
int ret;
pid = fork(); pid = fork();
if (pid < 0) { if (pid == -1) {
perror("fork"); perror("fork");
return NULL; return NULL;
} }
@ -365,27 +371,34 @@ struct task *task_create(char **argv)
task = task_new(pid); task = task_new(pid);
if (!task) if (!task)
goto fail2; goto fail1;
if (trace_wait(task)) if (trace_wait(task))
goto fail1; goto fail1;
if (trace_set_options(task) < 0) if (trace_set_options(task) < 0)
goto fail2; goto fail1;
if (leader_setup(task, 0) < 0) if (leader_setup(task, 0) < 0)
goto fail1; goto fail2;
if (handle_event(task)) ret = handle_event(task);
goto fail1; if (ret < 0)
goto fail2;
if (ret > 0)
return NULL;
return task; return task;
fail2:
fprintf(stderr, "failed to initialize process %d\n", pid);
fail1: fail1:
if (task) fprintf(stderr, "failed to initialize process %d\n", pid);
remove_proc(task); if (task) {
kill(pid, SIGKILL); delete_task(task);
kill(pid, SIGKILL);
}
return NULL;
fail2:
remove_proc(task);
return NULL; return NULL;
} }
@ -475,9 +488,12 @@ static struct task *open_one_pid(pid_t pid)
if (trace_set_options(task) < 0) if (trace_set_options(task) < 0)
goto fail2; goto fail2;
queue_event(task);
return task; return task;
fail2: fail2:
task_destroy(task); delete_task(task);
kill(pid, SIGCONT);
fail1: fail1:
return NULL; return NULL;
} }
@ -571,7 +587,9 @@ void each_process(void (*cb)(struct task *task))
{ {
struct list_head *it, *next; 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); struct task *task = container_of(it, struct task, leader_list);
(*cb)(task); (*cb)(task);
@ -603,7 +621,10 @@ void remove_proc(struct task *leader)
assert(leader->leader == leader); assert(leader->leader == leader);
stop_threads(leader);
breakpoint_disable_all(leader);
each_task(leader, &remove_task_cb, leader); each_task(leader, &remove_task_cb, leader);
assert(leader->threads == 1);
task_destroy(leader); task_destroy(leader);
} }

1
task.h
View File

@ -49,6 +49,7 @@ struct task {
unsigned int stopped:1; unsigned int stopped:1;
unsigned int is_new:1; unsigned int is_new:1;
unsigned int bad:1; unsigned int bad:1;
unsigned int bp_skipped:1;
struct breakpoint *breakpoint; struct breakpoint *breakpoint;
struct library_symbol *libsym; struct library_symbol *libsym;

View File

@ -50,7 +50,7 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp)
assert(task->stopped); assert(task->stopped);
assert(task->skip_bp == NULL); assert(task->skip_bp == NULL);
if (bp->enabled && !bp->hw) { if (bp->sw && bp->enabled) {
int ret = 0; int ret = 0;
struct timespec start; struct timespec start;