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->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;
|
||||||
|
|||||||
@ -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
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);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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];
|
||||||
};
|
};
|
||||||
|
|||||||
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));
|
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 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;
|
||||||
|
|
||||||
|
|||||||
@ -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
97
task.c
@ -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
1
task.h
@ -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;
|
||||||
|
|||||||
2
trace.c
2
trace.c
@ -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;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user