1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-17 13:47:37 +01:00

Preliminary version of freebsd syscall unwinder

This commit is contained in:
Konstantin Belousov 2010-03-08 19:45:54 +02:00
parent c1b1c10cfc
commit 752ce15c4f
4 changed files with 45 additions and 12 deletions

View file

@ -63,7 +63,8 @@ struct cursor
{ {
X86_64_SCF_NONE, /* no signal frame encountered */ X86_64_SCF_NONE, /* no signal frame encountered */
X86_64_SCF_LINUX_RT_SIGFRAME, /* Linux ucontext_t */ 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; sigcontext_format;
unw_word_t sigcontext_addr; unw_word_t sigcontext_addr;

View file

@ -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 (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
{ {
#if 1
abort (); abort ();
#if 0 #else
/* If there is no search table or it has an unsupported /* If there is no search table or it has an unsupported
encoding, fall back on linear search. */ encoding, fall back on linear search. */
if (hdr->table_enc == DW_EH_PE_omit) if (hdr->table_enc == DW_EH_PE_omit)

View file

@ -54,7 +54,8 @@ unw_is_signal_frame (unw_cursor_t *cursor)
|| (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0) || (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0)
return 0; return 0;
w1 &= 0xff; 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__) #elif defined(__FreeBSD__)
@ -63,7 +64,7 @@ unw_is_signal_frame (unw_cursor_t *cursor)
{ {
/* XXXKIB */ /* XXXKIB */
struct cursor *c = (struct cursor *) cursor; 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_addr_space_t as;
unw_accessors_t *a; unw_accessors_t *a;
void *arg; void *arg;
@ -88,10 +89,20 @@ eb fd jmp 0b
|| (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0) || (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0)
return 0; return 0;
w2 &= 0xffffff; w2 &= 0xffffff;
ret = w0 == 0x48006a10247c8d48 && if (w0 == 0x48006a10247c8d48 &&
w1 == 0x050f000001a1c0c7 && w1 == 0x050f000001a1c0c7 &&
w2 == 0x0000000000fdebf4; w2 == 0x0000000000fdebf4)
return ret; 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__ */ #else /* !__linux__ && !__FreeBSD__ */

View file

@ -83,7 +83,24 @@ unw_step (unw_cursor_t *cursor)
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); 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; unw_word_t ucontext;
@ -91,10 +108,13 @@ unw_step (unw_cursor_t *cursor)
#if defined __linux__ #if defined __linux__
ucontext = c->dwarf.cfa; 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__ #elif defined __FreeBSD__
if (c->sigcontext_format == X86_64_SCF_FREEBSD_SIGFRAME)
ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc); ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc);
c->sigcontext_format = X86_64_SCF_FREEBSD_SIGFRAME; else
return -UNW_EBADFRAME;
#endif #endif
c->sigcontext_addr = c->dwarf.cfa; c->sigcontext_addr = c->dwarf.cfa;