From 752ce15c4fbe0e08c2d19df18caa86887732b3c8 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 8 Mar 2010 19:45:54 +0200 Subject: [PATCH] Preliminary version of freebsd syscall unwinder --- include/tdep-x86_64/libunwind_i.h | 3 ++- src/ptrace/_UPT_find_proc_info.c | 3 ++- src/x86_64/Gis_signal_frame.c | 23 +++++++++++++++++------ src/x86_64/Gstep.c | 28 ++++++++++++++++++++++++---- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/include/tdep-x86_64/libunwind_i.h b/include/tdep-x86_64/libunwind_i.h index 974d610e..f6a02897 100644 --- a/include/tdep-x86_64/libunwind_i.h +++ b/include/tdep-x86_64/libunwind_i.h @@ -63,7 +63,8 @@ struct cursor { X86_64_SCF_NONE, /* no signal frame encountered */ X86_64_SCF_LINUX_RT_SIGFRAME, /* Linux ucontext_t */ - X86_64_SCF_FREEBSD_SIGFRAME, /* FreeBSD ucontext_t */ + X86_64_SCF_FREEBSD_SIGFRAME, /* FreeBSD signal frame */ + X86_64_SCF_FREEBSD_SYSCALL, /* FreeBSD syscall */ } sigcontext_format; unw_word_t sigcontext_addr; diff --git a/src/ptrace/_UPT_find_proc_info.c b/src/ptrace/_UPT_find_proc_info.c index 2b81e59a..d06c84ca 100644 --- a/src/ptrace/_UPT_find_proc_info.c +++ b/src/ptrace/_UPT_find_proc_info.c @@ -262,8 +262,9 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as, if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { +#if 1 abort (); -#if 0 +#else /* If there is no search table or it has an unsupported encoding, fall back on linear search. */ if (hdr->table_enc == DW_EH_PE_omit) diff --git a/src/x86_64/Gis_signal_frame.c b/src/x86_64/Gis_signal_frame.c index fd6599c1..4e516663 100644 --- a/src/x86_64/Gis_signal_frame.c +++ b/src/x86_64/Gis_signal_frame.c @@ -54,7 +54,8 @@ unw_is_signal_frame (unw_cursor_t *cursor) || (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0) return 0; w1 &= 0xff; - return (w0 == 0x0f0000000fc0c748 && w1 == 0x05); + return (w0 == 0x0f0000000fc0c748 && w1 == 0x05) ? + X86_64_SCF_LINUX_RT_SIGFRAME : X86_64_SCF_NONE; } #elif defined(__FreeBSD__) @@ -63,7 +64,7 @@ unw_is_signal_frame (unw_cursor_t *cursor) { /* XXXKIB */ struct cursor *c = (struct cursor *) cursor; - unw_word_t w0, w1, w2, w3, w4, ip; + unw_word_t w0, w1, w2, b0, ip; unw_addr_space_t as; unw_accessors_t *a; void *arg; @@ -88,10 +89,20 @@ eb fd jmp 0b || (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0) return 0; w2 &= 0xffffff; - ret = w0 == 0x48006a10247c8d48 && - w1 == 0x050f000001a1c0c7 && - w2 == 0x0000000000fdebf4; - return ret; + if (w0 == 0x48006a10247c8d48 && + w1 == 0x050f000001a1c0c7 && + w2 == 0x0000000000fdebf4) + return X86_64_SCF_FREEBSD_SIGFRAME; + /* Check if RIP points at standard syscall sequence. +49 89 ca mov %rcx,%r10 +0f 05 syscall + */ + if ((ret = (*a->access_mem) (as, ip - 5, &b0, 0, arg)) < 0) + return (0); + b0 &= 0xffffffffff; + if (b0 == 0x000000050fca8949) + return X86_64_SCF_FREEBSD_SYSCALL; + return X86_64_SCF_NONE; } #else /* !__linux__ && !__FreeBSD__ */ diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index 5a1654e1..96f1c902 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -83,7 +83,24 @@ unw_step (unw_cursor_t *cursor) Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); - if (unw_is_signal_frame (cursor)) + c->sigcontext_format = unw_is_signal_frame (cursor); + if (c->sigcontext_format == X86_64_SCF_FREEBSD_SYSCALL) { + c->dwarf.loc[RCX] = c->dwarf.loc[R10]; +// rsp_loc = DWARF_LOC(c->dwarf.cfa - 8, 0); +// rbp_loc = c->dwarf.loc[RBP]; + c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); + ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); + Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", + (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]), + (unsigned long long) c->dwarf.ip); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + c->dwarf.cfa += 8; + return 1; + } else if (c->sigcontext_format != X86_64_SCF_NONE) { unw_word_t ucontext; @@ -91,10 +108,13 @@ unw_step (unw_cursor_t *cursor) #if defined __linux__ ucontext = c->dwarf.cfa; - c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME; + if (c->sigcontext_format != X86_64_SCF_LINUX_RT_SIGFRAME) + return -UNW_EBADFRAME; #elif defined __FreeBSD__ - ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc); - c->sigcontext_format = X86_64_SCF_FREEBSD_SIGFRAME; + if (c->sigcontext_format == X86_64_SCF_FREEBSD_SIGFRAME) + ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc); + else + return -UNW_EBADFRAME; #endif c->sigcontext_addr = c->dwarf.cfa;