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->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;

View File

@ -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();
}

39
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);
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,6 +397,9 @@ static int handle_breakpoint(struct task *task)
}
}
if (task->bp_skipped)
task->bp_skipped = 0;
else
skip_breakpoint(task, bp);
end:
breakpoint_put(bp);
@ -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;
}

View File

@ -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];
};

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));
}

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 end;
if (unlikely(options.verbose))
fprintf(stderr, "+++ scan for memory leaks...\n");
if (!n)
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));
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,22 +75,24 @@ 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;
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,6 +177,7 @@ static int _process_event(struct task *task, int status)
}
if (!WIFSTOPPED(status)) {
if (unlikely(options.verbose))
fprintf(stderr, "!!!not WIFSTOPPED pid=%d\n", task->pid);
return -1;
}
@ -187,6 +191,7 @@ static int _process_event(struct task *task, int status)
}
if (!task->bad) {
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:
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,10 +243,12 @@ static int _process_event(struct task *task, int status)
else {
if (likely(siginfo.si_pid == mtrace_pid))
sig = 0;
else
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);
}
}
}
task->event.type = EVENT_SIGNAL;
task->event.e_un.signum = sig;
@ -307,6 +314,7 @@ static struct task * process_event(struct task *task, int status)
{
bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK);
if (unlikely(!bp)) {
if (unlikely(options.verbose))
fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid);
return task;
}
@ -345,20 +353,18 @@ void trace_me(void)
static inline int chk_signal(struct task *task, int signum)
{
#if 1
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);
#endif
}
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)) {
@ -488,8 +489,9 @@ void stop_threads(struct task *task)
each_task(leader, &do_stop_cb, NULL);
while(leader->threads != leader->threads_stopped) {
task = wait_event();
assert(leader->threads > leader->threads_stopped);
task = wait_event();
if (task)
queue_event(task);
}
@ -511,6 +513,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
task->event.type = EVENT_NONE;
if (unlikely(singlestep(task) == -1)) {
if (unlikely(options.verbose))
fprintf(stderr, "!!!%s: single step failed pid=%d\n", __func__, task->pid);
return -1;
}
@ -521,6 +524,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s
sig = _process_event(task, status);
if (sig == -1) {
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,6 +699,7 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le
if (errno != EFAULT) {
if (errno != ENOSYS) {
if (unlikely(options.verbose))
fprintf(stderr, "!!!%s: pid=%d process_vm_readv: %s\n", __func__, task->pid, strerror(errno));
return -1;
}

95
task.c
View File

@ -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);
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
View File

@ -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;

View File

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