From 31440e9796bb34146372df52ed59c4f68ea5839d Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Thu, 5 Apr 2007 20:40:41 -0600 Subject: [PATCH] Make libunwind pass C++ exceptions correctly When libunwind is linked with a C++ program that throws exceptions, the exception that's thrown is passed in %rax. However, libc's setcontext clears %rax, causing problems. This patch implements a setcontext that doesn't clobber rax. TBD: Add dwarf CFI annotations Signed-off-by: Arun Sharma --- src/x86_64/Gresume.c | 2 +- src/x86_64/gen-offsets.c | 73 +++++++++++++++++++++++++++++++++++++ src/x86_64/setcontext.S | 79 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 src/x86_64/gen-offsets.c diff --git a/src/x86_64/Gresume.c b/src/x86_64/Gresume.c index 2fc51aab..4edc4da6 100644 --- a/src/x86_64/Gresume.c +++ b/src/x86_64/Gresume.c @@ -71,7 +71,7 @@ x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) { Debug (8, "resuming at ip=%llx via setcontext()\n", (unsigned long long) c->dwarf.ip); - setcontext (uc); + _x86_64_setcontext (uc); } #else # warning Implement me! diff --git a/src/x86_64/gen-offsets.c b/src/x86_64/gen-offsets.c new file mode 100644 index 00000000..343716db --- /dev/null +++ b/src/x86_64/gen-offsets.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#define REG_OFFSET(reg) (offsetof(struct ucontext, uc_mcontext.gregs[REG_##reg])) + +# define REG_R8 0 +# define REG_R9 1 +# define REG_R10 2 +# define REG_R11 3 +# define REG_R12 4 +# define REG_R13 5 +# define REG_R14 6 +# define REG_R15 7 +# define REG_RDI 8 +# define REG_RSI 9 +# define REG_RBP 10 +# define REG_RBX 11 +# define REG_RDX 12 +# define REG_RAX 13 +# define REG_RCX 14 +# define REG_RSP 15 +# define REG_RIP 16 + +char *regs[] = { "RAX", + "RBX", + "RCX", + "RDX", + "RDI", + "RSI", + "RSP", + "RBP", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + "RIP", + }; + +main() +{ + printf("#define REG_OFFSET_%s\t%d\n" , regs[0], REG_OFFSET(RAX)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[1], REG_OFFSET(RBX)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[2], REG_OFFSET(RCX)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[3], REG_OFFSET(RDX)); + + printf("#define REG_OFFSET_%s\t%d\n" , regs[4], REG_OFFSET(RDI)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[5], REG_OFFSET(RSI)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[6], REG_OFFSET(RSP)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[7], REG_OFFSET(RBP)); + + printf("#define REG_OFFSET_%s\t%d\n" , regs[8], REG_OFFSET(R8)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[9], REG_OFFSET(R9)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[10], REG_OFFSET(R10)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[11], REG_OFFSET(R11)); + + printf("#define REG_OFFSET_%s\t%d\n" , regs[12], REG_OFFSET(R12)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[13], REG_OFFSET(R13)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[14], REG_OFFSET(R14)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[15], REG_OFFSET(R15)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[15], REG_OFFSET(R15)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[15], REG_OFFSET(R15)); + printf("#define REG_OFFSET_%s\t%d\n" , regs[16], REG_OFFSET(RIP)); + + printf("#define REG_OFFSET_FPREGS_PTR\t%d\n" , offsetof(struct ucontext, uc_mcontext.fpregs)); + printf("#define FPREG_OFFSET_MXCR\t%d\n" , offsetof(struct _libc_fpstate, mxcsr)); +} + + diff --git a/src/x86_64/setcontext.S b/src/x86_64/setcontext.S index d164d8db..d1578e1d 100644 --- a/src/x86_64/setcontext.S +++ b/src/x86_64/setcontext.S @@ -1,4 +1,79 @@ - .global _UI_setcontext +/* libunwind - a platform-independent unwind library + Copyright (C) 2007 Google, Inc + Contributed by Arun Sharma -_UI_setcontext: +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define REG_OFFSET_RAX 144 +#define REG_OFFSET_RBX 128 +#define REG_OFFSET_RCX 152 +#define REG_OFFSET_RDX 136 +#define REG_OFFSET_RDI 104 +#define REG_OFFSET_RSI 112 +#define REG_OFFSET_RSP 160 +#define REG_OFFSET_RBP 120 +#define REG_OFFSET_R8 40 +#define REG_OFFSET_R9 48 +#define REG_OFFSET_R10 56 +#define REG_OFFSET_R11 64 +#define REG_OFFSET_R12 72 +#define REG_OFFSET_R13 80 +#define REG_OFFSET_R14 88 +#define REG_OFFSET_R15 96 +#define REG_OFFSET_R15 96 +#define REG_OFFSET_R15 96 +#define REG_OFFSET_RIP 168 +#define REG_OFFSET_FPREGS_PTR 224 +#define FPREG_OFFSET_MXCR 24 + + .global _x86_64_setcontext + +_x86_64_setcontext: + + /* restore fp state */ + mov REG_OFFSET_FPREGS_PTR(%rdi),%r8 + fldenv (%r8) + ldmxcsr FPREG_OFFSET_MXCR(%r8) + + /* restore the rest of the state */ + mov REG_OFFSET_R8(%rdi),%r8 + mov REG_OFFSET_R9(%rdi),%r9 + mov REG_OFFSET_RBX(%rdi),%rbx + mov REG_OFFSET_RBP(%rdi),%rbp + mov REG_OFFSET_R12(%rdi),%r12 + mov REG_OFFSET_R13(%rdi),%r13 + mov REG_OFFSET_R14(%rdi),%r14 + mov REG_OFFSET_R15(%rdi),%r15 + mov REG_OFFSET_RSI(%rdi),%rsi + mov REG_OFFSET_RDX(%rdi),%rdx + mov REG_OFFSET_RAX(%rdi),%rax + mov REG_OFFSET_RCX(%rdi),%rcx + mov REG_OFFSET_RSP(%rdi),%rsp + + /* push the return address on the stack */ + mov REG_OFFSET_RIP(%rdi),%rcx + push %rcx + + mov REG_OFFSET_RCX(%rdi),%rcx + mov REG_OFFSET_RDI(%rdi),%rdi retq +