mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-13 23:19:54 +08:00
fixes
This commit is contained in:
parent
0a26d61e70
commit
92e40e9ec5
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
.*
|
||||
*.o
|
||||
*.o.*
|
||||
*.a
|
||||
*.s
|
||||
*.so
|
||||
*.lo
|
||||
*.la
|
||||
*.log
|
||||
*.lst
|
||||
*.symtypes
|
||||
*.elf
|
||||
*.bin
|
||||
*.gz
|
||||
*.bz2
|
||||
*.lzma
|
||||
*.xz
|
||||
*.lz4
|
||||
*.lzo
|
||||
*.patch
|
||||
*.gcno
|
||||
*.orig
|
||||
*.save
|
||||
*~
|
||||
Makefile
|
||||
config.h
|
||||
config.status
|
||||
stamp-h1
|
||||
libtool
|
||||
docross
|
||||
doremote
|
||||
mtrace
|
||||
@ -82,10 +82,10 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task));
|
||||
arch_addr_t get_return_addr(struct task *task);
|
||||
|
||||
/* set instruction hw breakpoint */
|
||||
int set_hw_bp(struct task *task, unsigned int slot, arch_addr_t addr);
|
||||
int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr);
|
||||
|
||||
/* remove instruction hw breakpoint */
|
||||
int reset_hw_bp(struct task *task, unsigned int slot, arch_addr_t addr);
|
||||
int reset_hw_bp(struct task *task, unsigned int n);
|
||||
|
||||
/* save the process context (state, registers, stack pointer) */
|
||||
int fetch_context(struct task *task);
|
||||
|
||||
10
breakpoint.c
10
breakpoint.c
@ -153,7 +153,7 @@ static void disable_hw_bp(struct task *task, struct breakpoint *bp)
|
||||
|
||||
task->hw_bp[slot] = NULL;
|
||||
|
||||
if (reset_hw_bp(task, slot, bp->addr) == -1)
|
||||
if (reset_hw_bp(task, slot) == -1)
|
||||
fatal("reset_hw_bp");
|
||||
}
|
||||
|
||||
@ -272,6 +272,7 @@ void breakpoint_enable(struct task *task, struct breakpoint *bp)
|
||||
debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr);
|
||||
|
||||
if (!bp->enabled) {
|
||||
stop_threads(task);
|
||||
#if HW_BREAKPOINTS > 0
|
||||
if (bp->type != SW_BP) {
|
||||
if (bp->type == HW_BP)
|
||||
@ -280,7 +281,6 @@ void breakpoint_enable(struct task *task, struct breakpoint *bp)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
stop_threads(task);
|
||||
enable_sw_breakpoint(task, bp);
|
||||
}
|
||||
bp->enabled = 1;
|
||||
@ -292,6 +292,7 @@ void breakpoint_disable(struct task *task, struct breakpoint *bp)
|
||||
debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr);
|
||||
|
||||
if (bp->enabled) {
|
||||
stop_threads(task);
|
||||
#if HW_BREAKPOINTS > 0
|
||||
if (bp->type != SW_BP) {
|
||||
if (bp->type == HW_BP)
|
||||
@ -302,7 +303,6 @@ void breakpoint_disable(struct task *task, struct breakpoint *bp)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
stop_threads(task);
|
||||
disable_sw_breakpoint(task, bp);
|
||||
}
|
||||
bp->enabled = 0;
|
||||
@ -453,6 +453,8 @@ void breakpoint_clear_all(struct task *leader)
|
||||
|
||||
void breakpoint_setup(struct task *leader)
|
||||
{
|
||||
assert(leader->breakpoints == NULL);
|
||||
|
||||
leader->breakpoints = dict_init(12401, target_address_hash, target_address_cmp);
|
||||
}
|
||||
|
||||
@ -475,7 +477,7 @@ static int clone_single_cb(unsigned long key, const void *value, void *data)
|
||||
new_bp->type = bp->type;
|
||||
new_bp->ext = ext;
|
||||
|
||||
#if HW_BREAKPOINT > 0
|
||||
#if HW_BREAKPOINTS > 0
|
||||
if (new_bp->type != SW_BP) {
|
||||
new_bp->hw_bp_slot = bp->hw_bp_slot;
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ static void swap_msg(struct mt_msg *mt_msg)
|
||||
mt_msg->tid = bswap_32(mt_msg->tid);
|
||||
}
|
||||
|
||||
static int socket_read_msg(struct mt_msg *mt_msg, void **payload, int *swap_endian)
|
||||
static int socket_read_msg(struct mt_msg *mt_msg, void **payload, unsigned int *swap_endian)
|
||||
{
|
||||
if (TEMP_FAILURE_RETRY(safe_read(client_fd, mt_msg, sizeof(*mt_msg))) <= 0)
|
||||
return FALSE;
|
||||
@ -156,6 +156,13 @@ static pid_t pid_payload(struct process *process, void *payload)
|
||||
return process->val32(mt_pid->pid);
|
||||
}
|
||||
|
||||
static unsigned int attached_payload(void *payload)
|
||||
{
|
||||
struct mt_attached_payload *mt_attached = payload;
|
||||
|
||||
return mt_attached->attached;
|
||||
}
|
||||
|
||||
void client_close(void)
|
||||
{
|
||||
if (client_fd != -1) {
|
||||
@ -179,7 +186,7 @@ static int client_func(void)
|
||||
struct mt_msg mt_msg;
|
||||
struct process *process;
|
||||
void *payload = NULL;
|
||||
int swap_endian;
|
||||
unsigned int swap_endian;
|
||||
|
||||
if (socket_read_msg(&mt_msg, &payload, &swap_endian) == FALSE) {
|
||||
client_broken();
|
||||
@ -204,7 +211,7 @@ static int client_func(void)
|
||||
else {
|
||||
process = client_find_process(mt_msg.pid);
|
||||
if (!process) {
|
||||
process = process_new(mt_msg.pid, swap_endian, 0, mt_info.do_trace);
|
||||
process = process_new(mt_msg.pid, swap_endian, mt_info.do_trace);
|
||||
|
||||
client_add_process(process);
|
||||
}
|
||||
@ -242,7 +249,7 @@ static int client_func(void)
|
||||
process_duplicate(process, client_find_process(pid_payload(process, payload)));
|
||||
break;
|
||||
case MT_ATTACH:
|
||||
process_reinit(process, swap_endian, 0);
|
||||
process_reinit(process, swap_endian, 0, attached_payload(payload));
|
||||
break;
|
||||
case MT_ATTACH64:
|
||||
if (!IS64BIT) {
|
||||
@ -250,7 +257,7 @@ static int client_func(void)
|
||||
process_set_status(process, MT_PROCESS_IGNORE);
|
||||
break;
|
||||
}
|
||||
process_reinit(process, swap_endian, 1);
|
||||
process_reinit(process, swap_endian, 1, attached_payload(payload));
|
||||
break;
|
||||
case MT_ABOUT_EXIT:
|
||||
process_about_exit(process);
|
||||
|
||||
@ -80,6 +80,41 @@ struct map {
|
||||
int ignore;
|
||||
};
|
||||
|
||||
static const char *str_operation(enum mt_operation operation)
|
||||
{
|
||||
switch(operation) {
|
||||
case MT_MALLOC:
|
||||
return "malloc";
|
||||
case MT_REALLOC_ENTER:
|
||||
return "realloc enter";
|
||||
case MT_REALLOC:
|
||||
return "realloc";
|
||||
case MT_REALLOC_FAILED:
|
||||
return "realloc failed";
|
||||
case MT_MEMALIGN:
|
||||
return "memalign";
|
||||
case MT_POSIX_MEMALIGN:
|
||||
return "posix_memalign";
|
||||
case MT_ALIGNED_ALLOC:
|
||||
return "aligned_alloc";
|
||||
case MT_VALLOC:
|
||||
return "valloc";
|
||||
case MT_PVALLOC:
|
||||
return "pvalloc";
|
||||
case MT_MMAP:
|
||||
return "mmap";
|
||||
case MT_MMAP64:
|
||||
return "mmap64";
|
||||
case MT_FREE:
|
||||
return "free";
|
||||
case MT_MUNMAP:
|
||||
return "munmap";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "unknow operation";
|
||||
}
|
||||
|
||||
static unsigned long get_uint64(void *p)
|
||||
{
|
||||
uint64_t v;
|
||||
@ -624,7 +659,7 @@ void process_del_map(struct process *process, void *payload, uint32_t payload_le
|
||||
fatal("process_del_map");
|
||||
}
|
||||
|
||||
static void process_init(struct process *process, int swap_endian, int is_64bit)
|
||||
static void process_init(struct process *process, unsigned int swap_endian, unsigned int is_64bit, unsigned int attached)
|
||||
{
|
||||
if (is_64bit) {
|
||||
process->ptr_size = sizeof(uint64_t);
|
||||
@ -642,6 +677,7 @@ static void process_init(struct process *process, int swap_endian, int is_64bit)
|
||||
process->val64 = swap_endian ? val64_swap : val64;
|
||||
|
||||
process->is_64bit = is_64bit;
|
||||
process->attached = attached;
|
||||
process->swap_endian = swap_endian;
|
||||
process->status = MT_PROCESS_RUNNING;
|
||||
process->filename = NULL;
|
||||
@ -708,7 +744,7 @@ void process_duplicate(struct process *process, struct process *copy)
|
||||
struct list_head *it;
|
||||
|
||||
process_reset(process);
|
||||
process_init(process, copy->swap_endian, copy->is_64bit);
|
||||
process_init(process, copy->swap_endian, copy->is_64bit, copy->attached);
|
||||
|
||||
if (!copy)
|
||||
return;
|
||||
@ -800,41 +836,6 @@ static int sort_total(const struct rb_stack **p, const struct rb_stack **q)
|
||||
return sort_allocations(p, q);
|
||||
}
|
||||
|
||||
static const char *str_operation(enum mt_operation operation)
|
||||
{
|
||||
switch(operation) {
|
||||
case MT_MALLOC:
|
||||
return "malloc";
|
||||
case MT_REALLOC_ENTER:
|
||||
return "realloc enter";
|
||||
case MT_REALLOC:
|
||||
return "realloc";
|
||||
case MT_REALLOC_FAILED:
|
||||
return "realloc failed";
|
||||
case MT_MEMALIGN:
|
||||
return "memalign";
|
||||
case MT_POSIX_MEMALIGN:
|
||||
return "posix_memalign";
|
||||
case MT_ALIGNED_ALLOC:
|
||||
return "aligned_alloc";
|
||||
case MT_VALLOC:
|
||||
return "valloc";
|
||||
case MT_PVALLOC:
|
||||
return "pvalloc";
|
||||
case MT_MMAP:
|
||||
return "mmap";
|
||||
case MT_MMAP64:
|
||||
return "mmap64";
|
||||
case MT_FREE:
|
||||
return "free";
|
||||
case MT_MUNMAP:
|
||||
return "munmap";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "unknow operation";
|
||||
}
|
||||
|
||||
static void _process_dump(struct process *process, int (*sortby)(const struct rb_stack **, const struct rb_stack **), int (*skipfunc)(struct rb_stack *), FILE *file)
|
||||
{
|
||||
struct rb_stack **arr;
|
||||
@ -1146,7 +1147,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
|
||||
process_rb_delete_block(process, block);
|
||||
}
|
||||
else {
|
||||
if (!options.client || options.wait) {
|
||||
if (!process->attached) {
|
||||
fprintf(stderr, ">>> block %#lx not found (pid=%d, tid=%d)\n", ptr, process->pid, mt_msg->tid);
|
||||
abort();
|
||||
}
|
||||
@ -1209,13 +1210,13 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload
|
||||
stack->tsc = process->tsc++;
|
||||
}
|
||||
|
||||
void process_reinit(struct process *process, int swap_endian, int is_64bit)
|
||||
void process_reinit(struct process *process, unsigned int swap_endian, unsigned int is_64bit, unsigned int attached)
|
||||
{
|
||||
process_reset(process);
|
||||
process_init(process, swap_endian, is_64bit);
|
||||
process_init(process, swap_endian, is_64bit, attached);
|
||||
}
|
||||
|
||||
struct process *process_new(pid_t pid, int swap_endian, int is_64bit, int tracing)
|
||||
struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing)
|
||||
{
|
||||
struct process *process = malloc(sizeof(*process));
|
||||
|
||||
@ -1227,7 +1228,7 @@ struct process *process_new(pid_t pid, int swap_endian, int is_64bit, int tracin
|
||||
process->stack_table = RB_ROOT;
|
||||
INIT_LIST_HEAD(&process->map_list);
|
||||
|
||||
process_init(process, swap_endian, is_64bit);
|
||||
process_init(process, swap_endian, 0, 0);
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
@ -50,7 +50,6 @@ struct lib {
|
||||
struct process {
|
||||
enum process_status status;
|
||||
pid_t pid;
|
||||
int tracing;
|
||||
char *filename;
|
||||
unsigned long bytes_used;
|
||||
unsigned long n_allocations;
|
||||
@ -62,8 +61,10 @@ struct process {
|
||||
struct rb_root stack_table;
|
||||
struct list_head map_list;
|
||||
unsigned long long tsc;
|
||||
int swap_endian;
|
||||
int is_64bit;
|
||||
unsigned int tracing:1;
|
||||
unsigned int swap_endian:1;
|
||||
unsigned int is_64bit:1;
|
||||
unsigned int attached:1;
|
||||
unsigned long (*get_ulong)(void *);
|
||||
void (*put_ulong)(void *, unsigned long);
|
||||
uint16_t (*val16)(uint16_t val);
|
||||
@ -72,9 +73,9 @@ struct process {
|
||||
uint8_t ptr_size;
|
||||
};
|
||||
|
||||
struct process *process_new(pid_t pid, int swap_endian, int is_64bit, int tracing);
|
||||
struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing);
|
||||
void process_reset_allocations(struct process *process);
|
||||
void process_reinit(struct process *process, int swap_endian, int is_64bit);
|
||||
void process_reinit(struct process *process, unsigned int swap_endian, unsigned int is_64bit, unsigned int attached);
|
||||
void process_set_clone(struct process *process, struct process *clone);
|
||||
struct process *process_clone_of(struct process *process);
|
||||
void process_delete(struct process *process);
|
||||
|
||||
@ -781,6 +781,7 @@ static int do_start(struct cmd_opt *cmd, int argc, const char *argv[])
|
||||
process_reset_allocations(process);
|
||||
|
||||
process->tracing = 1;
|
||||
process->attached = 1;
|
||||
|
||||
client_send_msg(process, MT_START, NULL, 0);
|
||||
|
||||
|
||||
24
dwarf.c
24
dwarf.c
@ -403,14 +403,16 @@ static inline int dwarf_readw(struct dwarf_addr_space *as, arch_addr_t *addr, ar
|
||||
|
||||
ret = dwarf_read64(as, addr, &u64);
|
||||
|
||||
*valp = u64;
|
||||
if (valp)
|
||||
*valp = u64;
|
||||
}
|
||||
else {
|
||||
uint32_t u32;
|
||||
|
||||
ret = dwarf_read32(as, addr, &u32);
|
||||
|
||||
*valp = u32;
|
||||
if (valp)
|
||||
*valp = u32;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -430,7 +432,8 @@ static int dwarf_read_uleb128(struct dwarf_addr_space *as, arch_addr_t *addr, ar
|
||||
}
|
||||
while (byte & 0x80);
|
||||
|
||||
*valp = val;
|
||||
if (valp)
|
||||
*valp = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -453,7 +456,8 @@ static int dwarf_read_sleb128(struct dwarf_addr_space *as, arch_addr_t *addr, ar
|
||||
/* sign-extend negative value */
|
||||
val |= ((arch_addr_t) -1) << shift;
|
||||
|
||||
*valp = val;
|
||||
if (valp)
|
||||
*valp = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -476,6 +480,16 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local,
|
||||
arch_addr_t addr;
|
||||
} tmp;
|
||||
|
||||
#ifdef DEBUG
|
||||
struct dwarf_cursor *c = &as->cursor;
|
||||
struct library *lib = c->lib;
|
||||
|
||||
if (*addr < ARCH_ADDR_T(lib->image_addr))
|
||||
fatal("invalid access mem: addr %#lx < %p", *addr, lib->image_addr);
|
||||
if (*addr >= ARCH_ADDR_T(lib->image_addr + lib->load_size))
|
||||
fatal("invalid access mem: addr %#lx >= %p", *addr, lib->image_addr + lib->load_size);
|
||||
#endif
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
if (valp)
|
||||
@ -1522,7 +1536,7 @@ do { \
|
||||
return ret;
|
||||
tmp2 = u32;
|
||||
if (operand1 == 3) {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#if __BYTE_ORDER == __ORDER_LITTLE_ENDIAN
|
||||
tmp2 &= 0xffffff;
|
||||
#else
|
||||
tmp2 >>= 8;
|
||||
|
||||
24
event.c
24
event.c
@ -115,7 +115,7 @@ static void show_clone(struct task *task, enum event_type type)
|
||||
|
||||
static struct task *handle_clone(struct task *task, enum event_type type)
|
||||
{
|
||||
struct task *newproc;
|
||||
struct task *newtask;
|
||||
int newpid = task->event.e_un.newpid;
|
||||
|
||||
debug(DEBUG_FUNCTION, "pid=%d, newpid=%d", task->pid, newpid);
|
||||
@ -125,19 +125,27 @@ static struct task *handle_clone(struct task *task, enum event_type type)
|
||||
|
||||
continue_task(task, 0);
|
||||
|
||||
newproc = task_clone(task, newpid);
|
||||
if (!newproc)
|
||||
newtask = pid2task(newpid);
|
||||
if (!newtask)
|
||||
goto fail;
|
||||
|
||||
if (newproc->leader == newproc) {
|
||||
if (newtask->leader == newtask) {
|
||||
if (task_fork(task, newtask) < 0)
|
||||
goto fail;
|
||||
|
||||
if (!options.follow) {
|
||||
remove_proc(newproc);
|
||||
remove_proc(newtask);
|
||||
return task;
|
||||
}
|
||||
report_fork(newproc, task->pid);
|
||||
|
||||
report_fork(newtask, task);
|
||||
}
|
||||
else {
|
||||
if (task_clone(task, newtask) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
continue_task(newproc, newproc->event.e_un.signum);
|
||||
continue_task(newtask, newtask->event.e_un.signum);
|
||||
|
||||
return task;
|
||||
fail:
|
||||
@ -272,8 +280,8 @@ static struct task *handle_breakpoint(struct task *task)
|
||||
if (task->breakpoint) {
|
||||
task->libsym = libsym;
|
||||
task->breakpoint->on_hit = handle_call_after;
|
||||
enable_scratch_hw_bp(task, task->breakpoint);
|
||||
}
|
||||
enable_scratch_hw_bp(task, task->breakpoint);
|
||||
}
|
||||
|
||||
if (libsym->func->report_in)
|
||||
|
||||
3
event.h
3
event.h
@ -36,8 +36,7 @@ enum event_type {
|
||||
EVENT_CLONE,
|
||||
EVENT_VFORK,
|
||||
EVENT_EXEC,
|
||||
EVENT_BREAKPOINT,
|
||||
EVENT_MAX
|
||||
EVENT_BREAKPOINT
|
||||
};
|
||||
|
||||
struct event {
|
||||
|
||||
@ -52,6 +52,10 @@ struct mt_msg {
|
||||
uint32_t payload_len;
|
||||
};
|
||||
|
||||
struct mt_attached_payload {
|
||||
uint8_t attached;
|
||||
};
|
||||
|
||||
struct mt_alloc_payload_64 {
|
||||
uint64_t ptr;
|
||||
uint64_t size;
|
||||
|
||||
6
mtelf.c
6
mtelf.c
@ -58,7 +58,11 @@ static int open_elf(struct mt_elf *mte, const char *filename)
|
||||
{
|
||||
mte->filename = filename;
|
||||
|
||||
mte->fd = open(filename, O_RDONLY);
|
||||
if (options.cwd != -1)
|
||||
mte->fd = openat(options.cwd, filename, O_RDONLY);
|
||||
else
|
||||
mte->fd = open(filename, O_RDONLY);
|
||||
|
||||
if (mte->fd == -1)
|
||||
return 1;
|
||||
|
||||
|
||||
13
options.c
13
options.c
@ -74,6 +74,7 @@ static void usage(void)
|
||||
" -a, --autoscan scan memory on exit of a traced program\n"
|
||||
" -b, --binpath=path binary search path (may be repeated)\n"
|
||||
" -c, --client connect to socket (path or address)\n"
|
||||
" -C, --cwd set current working directory\n"
|
||||
#ifdef DEBUG
|
||||
" -D, --debug=MASK enable debugging (see -Dh or --debug=help)\n"
|
||||
" -Dh, --debug=help show help on debugging\n"
|
||||
@ -184,6 +185,7 @@ char **process_options(int argc, char **argv)
|
||||
options.listen = NULL;
|
||||
options.user = NULL;
|
||||
options.command = NULL;
|
||||
options.cwd = -1;
|
||||
options.opt_p = NULL;
|
||||
options.opt_F = NULL;
|
||||
options.opt_b = NULL;
|
||||
@ -198,6 +200,7 @@ char **process_options(int argc, char **argv)
|
||||
{ "binpath", 1, 0, 'b' },
|
||||
{ "client", 1, 0, 'c' },
|
||||
{ "config", 1, 0, 'F' },
|
||||
{ "cwd", 1, 0, 'C' },
|
||||
{ "debug", 1, 0, 'D' },
|
||||
{ "depth", 1, 0, 'd' },
|
||||
{ "help", 0, 0, 'h' },
|
||||
@ -218,7 +221,7 @@ char **process_options(int argc, char **argv)
|
||||
};
|
||||
c = getopt_long(argc, argv,
|
||||
"+aefhisVvw"
|
||||
"b:c:D:F:l:o:p:P:u:d:S:",
|
||||
"b:c:C:D:F:l:o:p:P:u:d:S:",
|
||||
long_options,
|
||||
&option_index);
|
||||
|
||||
@ -251,6 +254,14 @@ char **process_options(int argc, char **argv)
|
||||
case 'c':
|
||||
options.client = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
options.cwd = open(optarg, O_RDONLY|O_DIRECTORY);
|
||||
|
||||
if (options.cwd == -1) {
|
||||
fprintf(stderr, "%s: `%s' %s\n", progname, optarg, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
{
|
||||
#ifdef DEBUG
|
||||
|
||||
@ -72,6 +72,7 @@ struct options_t {
|
||||
int wait; /* wait for client connection */
|
||||
char *port; /* socket port */
|
||||
char *command; /* command string */
|
||||
int cwd; /* current working directory handle */
|
||||
struct opt_p_t *opt_p; /* attach to process with a given pid */
|
||||
struct opt_F_t *opt_F; /* alternate configuration file(s) */
|
||||
struct opt_b_t *opt_b; /* binary search path(s) */
|
||||
|
||||
27
report.c
27
report.c
@ -307,20 +307,6 @@ static int _report_pvalloc(struct task *task, struct library_symbol *libsym)
|
||||
return report_alloc(task, MT_PVALLOC, ret, len, options.bt_depth);
|
||||
}
|
||||
|
||||
#if 1
|
||||
static int mt_test(struct task *task, struct library_symbol *libsym)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0; i < 13; ++i) {
|
||||
unsigned long val = fetch_param(task, i);
|
||||
|
||||
fprintf(stderr, "%s:%d %d\n", __FUNCTION__, __LINE__, (int32_t)val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct function flist[] = {
|
||||
{ "malloc", 2, NULL, _report_malloc },
|
||||
{ "free", 3, report_free, NULL },
|
||||
@ -337,16 +323,13 @@ static const struct function flist[] = {
|
||||
#if 0
|
||||
{ "cfree", 14, report_free, NULL },
|
||||
#endif
|
||||
#if 1
|
||||
{ "mt_test", 15, mt_test, NULL },
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct function *flist_matches_symbol(const char *sym_name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(flist); ++i) {
|
||||
for(i = 0; i < ARRAY_SIZE(flist); ++i) {
|
||||
if (!strcmp(sym_name, flist[i].name))
|
||||
return &flist[i];
|
||||
}
|
||||
@ -417,15 +400,17 @@ int report_scan(pid_t pid, const void *data, unsigned int data_len)
|
||||
|
||||
int report_attach(struct task *task)
|
||||
{
|
||||
struct mt_attached_payload state = { .attached = task->attached };
|
||||
|
||||
if (!server_connected())
|
||||
return -1;
|
||||
|
||||
return server_send_msg(task->is_64bit ? MT_ATTACH64 : MT_ATTACH, task->pid, 0, NULL, 0);
|
||||
return server_send_msg(task->is_64bit ? MT_ATTACH64 : MT_ATTACH, task->pid, 0, &state, sizeof(state));
|
||||
}
|
||||
|
||||
int report_fork(struct task *task, pid_t ppid)
|
||||
int report_fork(struct task *task, struct task *ptask)
|
||||
{
|
||||
struct mt_pid_payload fork_pid = { .pid = ppid };
|
||||
struct mt_pid_payload fork_pid = { .pid = ptask->leader->pid };
|
||||
|
||||
if (!server_connected())
|
||||
return -1;
|
||||
|
||||
2
report.h
2
report.h
@ -40,7 +40,7 @@ int report_del_map(struct task *task, struct library *lib);
|
||||
int report_info(int do_trace);
|
||||
int report_scan(pid_t pid, const void *data, unsigned int data_len);
|
||||
int report_attach(struct task *task);
|
||||
int report_fork(struct task *task, pid_t pid);
|
||||
int report_fork(struct task *task, struct task *ptask);
|
||||
int report_exit(struct task *task);
|
||||
int report_about_exit(struct task *task);
|
||||
int report_nofollow(struct task *task);
|
||||
|
||||
@ -51,6 +51,9 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr)
|
||||
{
|
||||
unsigned long val = (unsigned long)addr;
|
||||
|
||||
if (task->context.regs.ARM_pc == (long)val)
|
||||
return;
|
||||
|
||||
task->context.regs.ARM_pc = val;
|
||||
|
||||
if (ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct pt_regs, ARM_pc), val) == -1)
|
||||
|
||||
@ -22,10 +22,13 @@
|
||||
#include "dwarf.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int backtrace_init(struct task *task)
|
||||
{
|
||||
assert(task->backtrace == NULL);
|
||||
|
||||
task->backtrace = dwarf_init(task);
|
||||
|
||||
return task->backtrace != NULL;
|
||||
@ -33,28 +36,31 @@ int backtrace_init(struct task *task)
|
||||
|
||||
void backtrace_destroy(struct task *task)
|
||||
{
|
||||
if (task->backtrace)
|
||||
if (task->backtrace) {
|
||||
dwarf_destroy(task->backtrace);
|
||||
|
||||
task->backtrace = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int backtrace_init_unwind(struct task *task)
|
||||
{
|
||||
if (task->backtrace)
|
||||
return dwarf_init_unwind(task->backtrace);
|
||||
return -1;
|
||||
assert(task->backtrace);
|
||||
|
||||
return dwarf_init_unwind(task->backtrace);
|
||||
}
|
||||
|
||||
unsigned long backtrace_get_ip(struct task *task)
|
||||
{
|
||||
if (task->backtrace)
|
||||
return dwarf_get_ip(task->backtrace);
|
||||
return 0;
|
||||
assert(task->backtrace);
|
||||
|
||||
return dwarf_get_ip(task->backtrace);
|
||||
}
|
||||
|
||||
int backtrace_step(struct task *task)
|
||||
{
|
||||
if (task->backtrace)
|
||||
return dwarf_step(task->backtrace);
|
||||
return -1;
|
||||
assert(task->backtrace);
|
||||
|
||||
return dwarf_step(task->backtrace);
|
||||
}
|
||||
|
||||
|
||||
@ -65,6 +65,9 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr)
|
||||
#ifdef __powerpc64__
|
||||
val = fix_machine(task, val);
|
||||
#endif
|
||||
if (task->context.regs.nip == val)
|
||||
return;
|
||||
|
||||
task->context.regs.nip = val;
|
||||
|
||||
if (ptrace(PTRACE_POKEUSER, task->pid, (sizeof(unsigned long) * PT_NIP), val) == -1)
|
||||
|
||||
@ -67,6 +67,12 @@ static int trace_setup(struct task *task, int status, int signum)
|
||||
{
|
||||
int stop_signal;
|
||||
|
||||
task->traced = 1;
|
||||
task->stopped = 1;
|
||||
task->leader->threads_stopped++;
|
||||
task->event.type = EVENT_SIGNAL;
|
||||
task->event.e_un.signum = 0;
|
||||
|
||||
if (!WIFSTOPPED(status)) {
|
||||
fprintf(stderr, "%s pid=%d not stopped\n", __FUNCTION__, task->pid);
|
||||
return -1;
|
||||
@ -74,20 +80,12 @@ static int trace_setup(struct task *task, int status, int signum)
|
||||
|
||||
stop_signal = WSTOPSIG(status);
|
||||
|
||||
if (stop_signal == SIGSTOP)
|
||||
task->was_stopped = 1;
|
||||
else
|
||||
if (stop_signal == signum)
|
||||
stop_signal = 0;
|
||||
if (stop_signal != signum) {
|
||||
task->event.e_un.signum = stop_signal;
|
||||
|
||||
task->event.type = EVENT_SIGNAL;
|
||||
task->event.e_un.signum = stop_signal;
|
||||
|
||||
task->traced = 1;
|
||||
task->stopped = 1;
|
||||
|
||||
if (task->leader)
|
||||
task->leader->threads_stopped++;
|
||||
fprintf(stderr, "%s pid=%d unexpected trace signal (got:%d expected:%d)\n", __FUNCTION__, task->pid, stop_signal, signum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -109,7 +107,12 @@ static int _trace_wait(struct task *task, int signum)
|
||||
|
||||
int trace_wait(struct task *task)
|
||||
{
|
||||
return _trace_wait(task, SIGTRAP);
|
||||
if (_trace_wait(task, SIGTRAP))
|
||||
return -1;
|
||||
|
||||
queue_event(task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int child_event(struct task *task, enum event_type ev)
|
||||
@ -126,12 +129,18 @@ static int child_event(struct task *task, enum event_type ev)
|
||||
if (!pid2task(pid)) {
|
||||
struct task *child = task_new(pid, 0);
|
||||
|
||||
if (!child || _trace_wait(child, SIGTRAP))
|
||||
if (!child)
|
||||
return -1;
|
||||
|
||||
if (_trace_wait(child, SIGSTOP)) {
|
||||
remove_task(child);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
task->event.e_un.newpid = pid;
|
||||
task->event.type = ev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -213,10 +222,11 @@ static void process_event(struct task *task, int status)
|
||||
int i;
|
||||
arch_addr_t ip;
|
||||
|
||||
assert(leader != NULL);
|
||||
|
||||
task->stopped = 1;
|
||||
|
||||
if (leader)
|
||||
leader->threads_stopped++;
|
||||
leader->threads_stopped++;
|
||||
|
||||
stop_signal = _process_event(task, status);
|
||||
|
||||
@ -267,7 +277,7 @@ static void process_event(struct task *task, int status)
|
||||
#if 1
|
||||
assert(bp->enabled);
|
||||
#else
|
||||
if (bp->enabled)
|
||||
if (!bp->enabled)
|
||||
return;
|
||||
#endif
|
||||
|
||||
@ -318,31 +328,49 @@ static inline int fix_signal(struct task *task, int signum)
|
||||
|
||||
int untrace_task(struct task *task, int signum)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
assert(task->leader != NULL);
|
||||
|
||||
debug(DEBUG_PROCESS, "pid=%d", task->pid);
|
||||
|
||||
if (!task->traced)
|
||||
if (!task->stopped)
|
||||
return 0;
|
||||
|
||||
task->traced = 0;
|
||||
task->stopped = 0;
|
||||
|
||||
if (task->leader)
|
||||
task->leader->threads_stopped--;
|
||||
|
||||
if (ptrace(PTRACE_DETACH, task->pid, 0, fix_signal(task, signum)) == -1) {
|
||||
if (ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1) {
|
||||
if (errno != ESRCH)
|
||||
fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno));
|
||||
return -1;
|
||||
fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno));
|
||||
ret = -1;
|
||||
goto skip;
|
||||
|
||||
}
|
||||
return 0;
|
||||
|
||||
signum = fix_signal(task, signum);
|
||||
|
||||
if (ptrace(PTRACE_DETACH, task->pid, 0, signum) == -1) {
|
||||
if (task->traced) {
|
||||
if (errno != ESRCH)
|
||||
fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno));
|
||||
ret = -1;
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
|
||||
task_kill(task, SIGCONT);
|
||||
skip:
|
||||
task->leader->threads_stopped--;
|
||||
task->stopped = 0;
|
||||
task->was_stopped = 0;
|
||||
task->traced = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int trace_attach(struct task *task)
|
||||
{
|
||||
debug(DEBUG_PROCESS, "pid=%d", task->pid);
|
||||
|
||||
if (task->traced)
|
||||
return 0;
|
||||
assert(task->traced == 0);
|
||||
|
||||
if (ptrace(PTRACE_ATTACH, task->pid, 0, 0) == -1) {
|
||||
fprintf(stderr, "PTRACE_ATTACH pid=%d %s\n", task->pid, strerror(errno));
|
||||
@ -353,6 +381,8 @@ int trace_attach(struct task *task)
|
||||
if (_trace_wait(task, SIGSTOP))
|
||||
return -1;
|
||||
|
||||
queue_event(task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -373,8 +403,10 @@ int continue_task(struct task *task, int signum)
|
||||
{
|
||||
debug(DEBUG_PROCESS, "pid=%d", task->pid);
|
||||
|
||||
if (task->leader)
|
||||
task->leader->threads_stopped--;
|
||||
assert(task->leader != NULL);
|
||||
assert(task->stopped);
|
||||
|
||||
task->leader->threads_stopped--;
|
||||
task->stopped = 0;
|
||||
|
||||
if (ptrace(PTRACE_CONT, task->pid, 0, fix_signal(task, signum)) == -1) {
|
||||
@ -388,16 +420,7 @@ static void do_stop_cb(struct task *task, void *data)
|
||||
{
|
||||
if (task->stopped)
|
||||
return;
|
||||
#if 0
|
||||
int status;
|
||||
int pid = TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL | WNOHANG));
|
||||
|
||||
if (pid == task->pid) {
|
||||
process_event(task, status);
|
||||
queue_event(task);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
task->was_stopped = 1;
|
||||
|
||||
task_kill(task, SIGSTOP);
|
||||
@ -407,8 +430,7 @@ void stop_threads(struct task *task)
|
||||
{
|
||||
struct task *leader = task->leader;
|
||||
|
||||
if (!leader)
|
||||
return;
|
||||
assert(task->leader != NULL);
|
||||
|
||||
if (leader->threads != leader->threads_stopped) {
|
||||
each_task(leader, &do_stop_cb, NULL);
|
||||
@ -440,13 +462,11 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task))
|
||||
if (stop_signal == SIGTRAP)
|
||||
return 0; /* check if was a real breakpoint code there */
|
||||
|
||||
|
||||
if (!stop_signal) {
|
||||
queue_event(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (fix_signal(task, stop_signal) > 0) {
|
||||
queue_event(task);
|
||||
return 1;
|
||||
@ -503,7 +523,8 @@ struct task *wait_event(void)
|
||||
task = task_new(pid, 0);
|
||||
|
||||
if (task)
|
||||
trace_setup(task, status, SIGTRAP);
|
||||
trace_setup(task, status, SIGSTOP);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <backend.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -40,6 +41,11 @@ static int set_breakpoint_addr(struct task *task, arch_addr_t addr, int n)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef __x86_64__
|
||||
if (!task->is_64bit)
|
||||
addr &= 0xffffffff;
|
||||
#endif
|
||||
|
||||
ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[n]), addr);
|
||||
if (ret) {
|
||||
if (errno != ESRCH) {
|
||||
@ -50,56 +56,63 @@ static int set_breakpoint_addr(struct task *task, arch_addr_t addr, int n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int toggle_breakpoint(struct task *task, int n, int type, int len, int local, int global, int set)
|
||||
static int set_breakpoint_mode(struct task *task, int n, int type, int len, int local, int global)
|
||||
{
|
||||
long ret;
|
||||
int xtype, xlen;
|
||||
unsigned long dr7, vdr7;
|
||||
uint32_t mode;
|
||||
uint32_t dr7, mask;
|
||||
|
||||
switch (type) {
|
||||
mask = (0b1111 << (16 + 4 * n)) | (0b11 << (2 * n));
|
||||
|
||||
switch(type) {
|
||||
case BP_X:
|
||||
xtype = 0;
|
||||
mode = 0b0000;
|
||||
break;
|
||||
case BP_W:
|
||||
xtype = 1;
|
||||
mode = 0b0001;
|
||||
break;
|
||||
case BP_RW:
|
||||
xtype = 3;
|
||||
mode = 0b0011;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid hw breakpoint type\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (len) {
|
||||
switch(len) {
|
||||
case 1:
|
||||
xlen = 0;
|
||||
mode |= 0b0000;
|
||||
break;
|
||||
case 2:
|
||||
xlen = 4;
|
||||
mode |= 0b0100;
|
||||
break;
|
||||
case 4:
|
||||
xlen = 0xc;
|
||||
mode |= 0b1100;
|
||||
break;
|
||||
case 8:
|
||||
xlen = 8;
|
||||
mode |= 0b1000;
|
||||
break;
|
||||
}
|
||||
|
||||
vdr7 = (xlen | xtype) << 16;
|
||||
vdr7 <<= 4 * n;
|
||||
dr7 = task->arch.dr7 & ~mask;
|
||||
|
||||
dr7 |= mode << (16 + 4 * n);
|
||||
|
||||
if (local) {
|
||||
vdr7 |= 1 << (2 * n);
|
||||
vdr7 |= 1 << 8;
|
||||
dr7 |= 0b01 << (2 * n);
|
||||
dr7 |= 1 << 8;
|
||||
}
|
||||
if (global) {
|
||||
vdr7 |= 2 << (2 * n);
|
||||
vdr7 |= 1 << 9;
|
||||
}
|
||||
|
||||
dr7 = task->arch.dr7;
|
||||
if (set)
|
||||
dr7 |= vdr7;
|
||||
else
|
||||
dr7 &= ~vdr7;
|
||||
if (!(dr7 & 0b01010101))
|
||||
dr7 &= ~(1 << 8);
|
||||
|
||||
if (global) {
|
||||
dr7 |= 0b10 << (2 * n);
|
||||
dr7 |= 1 << 9;
|
||||
}
|
||||
else
|
||||
if (!(dr7 & 0b10101010))
|
||||
dr7 &= ~(1 << 9);
|
||||
|
||||
if (dr7 != task->arch.dr7) {
|
||||
task->arch.dr7 = dr7;
|
||||
@ -115,31 +128,50 @@ static int toggle_breakpoint(struct task *task, int n, int type, int len, int lo
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_hw_bp(struct task *task, unsigned int slot, arch_addr_t addr)
|
||||
int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr)
|
||||
{
|
||||
if (set_breakpoint_addr(task, addr, slot) == -1)
|
||||
if (reset_hw_bp(task, n) == -1)
|
||||
return -1;
|
||||
|
||||
return toggle_breakpoint(task,
|
||||
slot, /* n */
|
||||
if (set_breakpoint_addr(task, addr, n) == -1)
|
||||
return -1;
|
||||
|
||||
return set_breakpoint_mode(task,
|
||||
n, /* n */
|
||||
BP_X, /* type */
|
||||
1, /* len */
|
||||
1, /* local */
|
||||
0, /* global */
|
||||
1 /* set */
|
||||
0 /* global */
|
||||
);
|
||||
}
|
||||
|
||||
int reset_hw_bp(struct task *task, unsigned int slot, arch_addr_t addr)
|
||||
int reset_hw_bp(struct task *task, unsigned int n)
|
||||
{
|
||||
return toggle_breakpoint(task,
|
||||
slot, /* n */
|
||||
BP_X, /* type */
|
||||
1, /* len */
|
||||
1, /* local */
|
||||
0, /* global */
|
||||
0 /* set */
|
||||
);
|
||||
long ret;
|
||||
uint32_t dr7, mask;
|
||||
|
||||
mask = (0b1111 << (16 + 4 * n)) | (0b11 << (2 * n));
|
||||
|
||||
dr7 = task->arch.dr7 & ~mask;
|
||||
|
||||
if (!(dr7 & 0b01010101))
|
||||
dr7 &= ~(1 << 8);
|
||||
|
||||
if (!(dr7 & 0b10101010))
|
||||
dr7 &= ~(1 << 9);
|
||||
|
||||
if (dr7 != task->arch.dr7) {
|
||||
task->arch.dr7 = dr7;
|
||||
|
||||
ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7);
|
||||
if (ret) {
|
||||
if (errno != ESRCH) {
|
||||
fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_64bit(struct mt_elf *mte)
|
||||
@ -150,6 +182,7 @@ int is_64bit(struct mt_elf *mte)
|
||||
int arch_task_init(struct task *task)
|
||||
{
|
||||
long ret;
|
||||
int i;
|
||||
|
||||
ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[7]), 0);
|
||||
if (ret == -1 && errno) {
|
||||
@ -162,6 +195,9 @@ int arch_task_init(struct task *task)
|
||||
|
||||
task->arch.dr7 = ret;
|
||||
|
||||
for(i = 0; i < HW_BREAKPOINTS; ++i)
|
||||
reset_hw_bp(task, i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ static const uint8_t dwarf_to_regnum_map32[] = {
|
||||
[DWARF_X86_ECX] = ECX,
|
||||
[DWARF_X86_EDX] = EDX,
|
||||
[DWARF_X86_EBX] = EBX,
|
||||
[DWARF_X86_ESP] = ESP,
|
||||
[DWARF_X86_ESP] = UESP,
|
||||
[DWARF_X86_EBP] = EBP,
|
||||
[DWARF_X86_ESI] = ESI,
|
||||
[DWARF_X86_EDI] = EDI,
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
/*
|
||||
* This file is part of mtrace.
|
||||
* Copyright (C) 2015 Stefani Seibold <stefani@seibold.net>
|
||||
* This file is based on the ltrace source
|
||||
* Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
||||
* Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes
|
||||
* Copyright (C) 2006 Ian Wienand
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@ -75,10 +71,16 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr)
|
||||
#ifdef __x86_64__
|
||||
val = fix_machine(task, val);
|
||||
|
||||
if (task->context.iregs.rip == val)
|
||||
return;
|
||||
|
||||
task->context.iregs.rip = val;
|
||||
if (ptrace(PTRACE_POKEUSER, task->pid, (sizeof(unsigned long) * RIP), val) != -1)
|
||||
return;
|
||||
#else
|
||||
if (task->context.iregs.eip == (long)val)
|
||||
return;
|
||||
|
||||
task->context.iregs.eip = val;
|
||||
if (ptrace(PTRACE_POKEUSER, task->pid, (sizeof(unsigned long) * EIP), val) != -1)
|
||||
return;
|
||||
@ -271,52 +273,52 @@ unsigned long fetch_reg(struct task *task, unsigned int reg)
|
||||
#else
|
||||
switch(reg) {
|
||||
case EBX:
|
||||
val = task->context.iregs.bx;
|
||||
val = task->context.iregs.ebx;
|
||||
break;
|
||||
case ECX:
|
||||
val = task->context.iregs.cx;
|
||||
val = task->context.iregs.ecx;
|
||||
break;
|
||||
case ESI:
|
||||
val = task->context.iregs.si;
|
||||
val = task->context.iregs.esi;
|
||||
break;
|
||||
case EDI:
|
||||
val = task->context.iregs.di;
|
||||
val = task->context.iregs.edi;
|
||||
break;
|
||||
case EBP:
|
||||
val = task->context.iregs.bp;
|
||||
val = task->context.iregs.ebp;
|
||||
break;
|
||||
case EAX:
|
||||
val = task->context.iregs.cx;
|
||||
val = task->context.iregs.ecx;
|
||||
break;
|
||||
case DS:
|
||||
val = task->context.iregs.ds;
|
||||
val = task->context.iregs.xds;
|
||||
break;
|
||||
case ES:
|
||||
val = task->context.iregs.es;
|
||||
val = task->context.iregs.xes;
|
||||
break;
|
||||
case FS:
|
||||
val = task->context.iregs.fs;
|
||||
val = task->context.iregs.xfs;
|
||||
break;
|
||||
case GS:
|
||||
val = task->context.iregs.gs;
|
||||
val = task->context.iregs.xgs;
|
||||
break;
|
||||
case ORIG_EAX:
|
||||
val = task->context.iregs.orig_ax;
|
||||
val = task->context.iregs.orig_eax;
|
||||
break;
|
||||
case EIP:
|
||||
val = task->context.iregs.ip;
|
||||
val = task->context.iregs.eip;
|
||||
break;
|
||||
case CS:
|
||||
val = task->context.iregs.cs;
|
||||
val = task->context.iregs.xcs;
|
||||
break;
|
||||
case EFL:
|
||||
val = task->context.iregs.flags;
|
||||
val = task->context.iregs.eflags;
|
||||
break;
|
||||
case UESP:
|
||||
val = task->context.iregs.sp;
|
||||
val = task->context.iregs.esp;
|
||||
break;
|
||||
case SS:
|
||||
val = task->context.iregs.ss;
|
||||
val = task->context.iregs.xss;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
|
||||
141
task.c
141
task.c
@ -132,14 +132,16 @@ static int leader_setup(struct task *leader)
|
||||
}
|
||||
|
||||
|
||||
static int task_bare_init(struct task *task)
|
||||
static int task_init(struct task *task, int attached)
|
||||
{
|
||||
pid_t tgid;
|
||||
|
||||
/* Add process so that we know who the leader is. */
|
||||
tgid = process_leader(task->pid);
|
||||
if (!tgid)
|
||||
if (!tgid){
|
||||
fprintf(stderr, "%s no tgid for pid=%d\n", __FUNCTION__, task->pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tgid == task->pid) {
|
||||
task->leader = task;
|
||||
@ -152,8 +154,10 @@ static int task_bare_init(struct task *task)
|
||||
else {
|
||||
task->leader = pid2task(tgid);
|
||||
|
||||
if (!task->leader)
|
||||
if (!task->leader) {
|
||||
fprintf(stderr, "%s no leader for tgpid=%d\n", __FUNCTION__, tgid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
task->leader->threads++;
|
||||
task->breakpoints = NULL;
|
||||
@ -162,13 +166,20 @@ static int task_bare_init(struct task *task)
|
||||
list_add_tail(&task->task_list, &task->leader->task_list);
|
||||
}
|
||||
|
||||
task->attached = attached;
|
||||
|
||||
if (arch_task_init(task) < 0)
|
||||
return -1;
|
||||
|
||||
if (os_task_init(task) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void leader_cleanup(struct task *task)
|
||||
{
|
||||
if (!task->leader)
|
||||
return;
|
||||
assert(task->leader);
|
||||
|
||||
task->leader->threads--;
|
||||
|
||||
@ -188,9 +199,11 @@ static void leader_cleanup(struct task *task)
|
||||
static void task_destroy(struct task *task)
|
||||
{
|
||||
breakpoint_hw_destroy(task);
|
||||
detach_task(task);
|
||||
leader_cleanup(task);
|
||||
backtrace_destroy(task);
|
||||
arch_task_destroy(task);
|
||||
os_task_destroy(task);
|
||||
leader_cleanup(task);
|
||||
detach_task(task);
|
||||
list_del(&task->task_list);
|
||||
rb_erase(&task->pid_node, &pid_tree);
|
||||
free(task);
|
||||
@ -215,22 +228,16 @@ struct task *task_new(pid_t pid, int traced)
|
||||
|
||||
library_setup(task);
|
||||
|
||||
if (arch_task_init(task) < 0)
|
||||
if (task_init(task, 1) < 0)
|
||||
goto fail1;
|
||||
|
||||
if (os_task_init(task) < 0)
|
||||
goto fail2;
|
||||
|
||||
init_event(task);
|
||||
|
||||
insert_pid(task);
|
||||
|
||||
return task;
|
||||
fail2:
|
||||
arch_task_destroy(task);
|
||||
fail1:
|
||||
task_destroy(task);
|
||||
free(task);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -240,11 +247,13 @@ int process_exec(struct task *task)
|
||||
|
||||
task->threads_stopped--;
|
||||
|
||||
breakpoint_hw_destroy(task);
|
||||
backtrace_destroy(task);
|
||||
os_task_destroy(task);
|
||||
arch_task_destroy(task);
|
||||
leader_cleanup(task);
|
||||
|
||||
backtrace_destroy(task);
|
||||
|
||||
if (task_bare_init(task) < 0)
|
||||
if (task_init(task, 0) < 0)
|
||||
return -1;
|
||||
|
||||
assert(task->leader == task);
|
||||
@ -282,9 +291,6 @@ struct task *task_create(const char *command, char **argv)
|
||||
if (!task)
|
||||
goto fail2;
|
||||
|
||||
if (task_bare_init(task) < 0)
|
||||
goto fail2;
|
||||
|
||||
if (trace_wait(task))
|
||||
goto fail1;
|
||||
|
||||
@ -294,8 +300,6 @@ struct task *task_create(const char *command, char **argv)
|
||||
if (leader_setup(task) < 0)
|
||||
goto fail1;
|
||||
|
||||
queue_event(task);
|
||||
|
||||
return task;
|
||||
fail2:
|
||||
fprintf(stderr, "failed to initialize process %d\n", pid);
|
||||
@ -306,63 +310,67 @@ fail1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct task *task_clone(struct task *task, pid_t pid)
|
||||
int task_clone(struct task *task, struct task *newtask)
|
||||
{
|
||||
struct task *retp;
|
||||
assert(newtask->leader != newtask);
|
||||
assert(newtask->event.type == EVENT_SIGNAL);
|
||||
assert(newtask->event.e_un.signum == 0);
|
||||
assert(newtask->traced);
|
||||
assert(newtask->stopped);
|
||||
assert(newtask->backtrace == NULL);
|
||||
|
||||
assert(task == task->leader);
|
||||
if (backtrace_init(newtask) < 0)
|
||||
goto fail;
|
||||
|
||||
retp = pid2task(pid);
|
||||
if (!retp)
|
||||
goto fail1;
|
||||
breakpoint_hw_clone(newtask);
|
||||
|
||||
assert(!retp->leader);
|
||||
return 0;
|
||||
fail:
|
||||
fprintf(stderr, "failed to clone process %d->%d : %s\n", task->pid, newtask->pid, strerror(errno));
|
||||
task_destroy(newtask);
|
||||
|
||||
if (task_bare_init(retp) < 0)
|
||||
goto fail2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
retp->leader->threads_stopped++;
|
||||
int task_fork(struct task *task, struct task *newtask)
|
||||
{
|
||||
struct task *leader = task->leader;
|
||||
|
||||
if (backtrace_init(retp) < 0)
|
||||
goto fail2;
|
||||
assert(newtask->leader == newtask);
|
||||
assert(newtask->event.type == EVENT_SIGNAL);
|
||||
assert(newtask->event.e_un.signum == 0);
|
||||
assert(newtask->traced);
|
||||
assert(newtask->stopped);
|
||||
assert(newtask->backtrace == NULL);
|
||||
|
||||
/* For non-leader tasks, that's all we need to do. */
|
||||
if (retp->leader != retp) {
|
||||
breakpoint_hw_clone(retp);
|
||||
if (backtrace_init(newtask) < 0)
|
||||
goto fail;
|
||||
|
||||
return retp;
|
||||
}
|
||||
if (library_clone_all(newtask, leader))
|
||||
goto fail;
|
||||
|
||||
if (library_clone_all(retp, task))
|
||||
goto fail2;
|
||||
if (breakpoint_clone_all(newtask, leader))
|
||||
goto fail;
|
||||
|
||||
if (breakpoint_clone_all(retp, task))
|
||||
goto fail2;
|
||||
|
||||
retp->libsym = task->libsym;
|
||||
retp->context = task->context;
|
||||
retp->breakpoint = task->breakpoint;
|
||||
newtask->libsym = task->libsym;
|
||||
newtask->context = task->context;
|
||||
newtask->breakpoint = task->breakpoint;
|
||||
|
||||
if (task->breakpoint)
|
||||
retp->breakpoint = breakpoint_find(retp, retp->breakpoint->addr);
|
||||
newtask->breakpoint = breakpoint_find(newtask, newtask->breakpoint->addr);
|
||||
|
||||
if (arch_task_clone(retp, task) < 0)
|
||||
goto fail2;
|
||||
if (arch_task_clone(newtask, task) < 0)
|
||||
goto fail;
|
||||
|
||||
/* At this point, retp is fully initialized, except for OS and
|
||||
* arch parts, and we can call task_destroy. */
|
||||
if (os_task_clone(retp, task) < 0)
|
||||
goto fail3;
|
||||
if (os_task_clone(newtask, task) < 0)
|
||||
goto fail;
|
||||
|
||||
return retp;
|
||||
fail3:
|
||||
arch_task_destroy(retp);
|
||||
fail2:
|
||||
task_destroy(retp);
|
||||
fail1:
|
||||
fprintf(stderr, "failed to clone process %d->%d : %s\n", task->pid, pid, strerror(errno));
|
||||
return 0;
|
||||
fail:
|
||||
fprintf(stderr, "failed to fork process %d->%d : %s\n", task->pid, newtask->pid, strerror(errno));
|
||||
task_destroy(newtask);
|
||||
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct task *open_one_pid(pid_t pid)
|
||||
@ -375,17 +383,12 @@ static struct task *open_one_pid(pid_t pid)
|
||||
if (task == NULL)
|
||||
goto fail1;
|
||||
|
||||
if (task_bare_init(task) < 0)
|
||||
goto fail2;
|
||||
|
||||
if (trace_attach(task) < 0)
|
||||
goto fail2;
|
||||
|
||||
if (trace_set_options(task) < 0)
|
||||
goto fail2;
|
||||
|
||||
queue_event(task);
|
||||
|
||||
return task;
|
||||
fail2:
|
||||
remove_task(task);
|
||||
@ -445,7 +448,7 @@ void open_pid(pid_t pid)
|
||||
struct task *child = open_one_pid(tasks[i]);
|
||||
|
||||
if (child) {
|
||||
if (backtrace_init(child) < 0)
|
||||
if (task_clone(child->leader, child) < 0)
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
@ -506,8 +509,6 @@ void remove_task(struct task *task)
|
||||
{
|
||||
debug(DEBUG_FUNCTION, "pid=%d", task->pid);
|
||||
|
||||
arch_task_destroy(task);
|
||||
os_task_destroy(task);
|
||||
task_destroy(task);
|
||||
}
|
||||
|
||||
|
||||
9
task.h
9
task.h
@ -48,6 +48,7 @@ struct task {
|
||||
unsigned int traced:1;
|
||||
unsigned int was_stopped:1;
|
||||
unsigned int is_64bit:1;
|
||||
unsigned int attached:1;
|
||||
|
||||
/* Dictionary of breakpoints */
|
||||
struct dict *breakpoints;
|
||||
@ -110,9 +111,11 @@ void open_pid(pid_t pid);
|
||||
|
||||
struct task *pid2task(pid_t pid);
|
||||
|
||||
/* Clone the contents of PROC
|
||||
* Returns the new task pointer on succes or NULL on failure. */
|
||||
struct task *task_clone(struct task *task, pid_t pid);
|
||||
/* Clone the contents of a task */
|
||||
int task_clone(struct task *task, struct task *newtask);
|
||||
|
||||
/* Fork the contents of a task */
|
||||
int task_fork(struct task *task, struct task *newtask);
|
||||
|
||||
/* get first process of leader list */
|
||||
struct task *get_first_process(void);
|
||||
|
||||
3
trace.c
3
trace.c
@ -58,9 +58,9 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp)
|
||||
ret = do_singlestep(task);
|
||||
breakpoint_enable(task, bp);
|
||||
if (ret) {
|
||||
//fprintf(stderr, "%s:%d %d\n", __FUNCTION__, __LINE__, ret);
|
||||
if (ret == 1)
|
||||
task->skip_bp = bp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -76,6 +76,7 @@ void detach_task(struct task *task)
|
||||
sig = task->event.e_un.signum;
|
||||
|
||||
remove_event(task);
|
||||
breakpoint_hw_destroy(task);
|
||||
untrace_task(task, sig);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user