diff --git a/configure.ac b/configure.ac index a5e0537d..0597f516 100644 --- a/configure.ac +++ b/configure.ac @@ -103,7 +103,7 @@ SET_ARCH([$target_cpu],[target_arch]) AC_ARG_ENABLE(coredump, AS_HELP_STRING([--enable-coredump],[building libunwind-coredump library]),, - [AS_CASE([$host_arch], [x86*], [enable_coredump=yes], [enable_coredump=no])] + [AS_CASE([$host_arch], [mips*|x86*], [enable_coredump=yes], [enable_coredump=no])] ) AC_MSG_CHECKING([if we should build libunwind-coredump]) diff --git a/include/libunwind-mips.h b/include/libunwind-mips.h index 91f70015..cf22fc90 100644 --- a/include/libunwind-mips.h +++ b/include/libunwind-mips.h @@ -95,6 +95,8 @@ typedef enum UNW_MIPS_R30, UNW_MIPS_R31, + UNW_MIPS_PC = 34, + /* FIXME: Other registers! */ /* For MIPS, the CFA is the value of SP (r29) at the call site in the diff --git a/src/coredump/_UCD_access_reg_linux.c b/src/coredump/_UCD_access_reg_linux.c index c48f5c9b..9fd7f7d4 100644 --- a/src/coredump/_UCD_access_reg_linux.c +++ b/src/coredump/_UCD_access_reg_linux.c @@ -43,7 +43,42 @@ _UCD_access_reg (unw_addr_space_t as, if (regnum < 0 || regnum >= 16) goto badreg; #else -#if defined(UNW_TARGET_X86) +#if defined(UNW_TARGET_MIPS) + static const uint8_t remap_regs[] = + { + [UNW_MIPS_R0] = EF_REG0, + [UNW_MIPS_R1] = EF_REG1, + [UNW_MIPS_R2] = EF_REG2, + [UNW_MIPS_R3] = EF_REG3, + [UNW_MIPS_R4] = EF_REG4, + [UNW_MIPS_R5] = EF_REG5, + [UNW_MIPS_R6] = EF_REG6, + [UNW_MIPS_R7] = EF_REG7, + [UNW_MIPS_R8] = EF_REG8, + [UNW_MIPS_R9] = EF_REG9, + [UNW_MIPS_R10] = EF_REG10, + [UNW_MIPS_R11] = EF_REG11, + [UNW_MIPS_R12] = EF_REG12, + [UNW_MIPS_R13] = EF_REG13, + [UNW_MIPS_R14] = EF_REG14, + [UNW_MIPS_R15] = EF_REG15, + [UNW_MIPS_R16] = EF_REG16, + [UNW_MIPS_R17] = EF_REG17, + [UNW_MIPS_R18] = EF_REG18, + [UNW_MIPS_R19] = EF_REG19, + [UNW_MIPS_R20] = EF_REG20, + [UNW_MIPS_R21] = EF_REG21, + [UNW_MIPS_R22] = EF_REG22, + [UNW_MIPS_R23] = EF_REG23, + [UNW_MIPS_R24] = EF_REG24, + [UNW_MIPS_R25] = EF_REG25, + [UNW_MIPS_R28] = EF_REG28, + [UNW_MIPS_R29] = EF_REG29, + [UNW_MIPS_R30] = EF_REG30, + [UNW_MIPS_R31] = EF_REG31, + [UNW_MIPS_PC] = EF_CP0_EPC, + }; +#elif defined(UNW_TARGET_X86) static const uint8_t remap_regs[] = { /* names from libunwind-x86.h */ diff --git a/src/mips/Gget_save_loc.c b/src/mips/Gget_save_loc.c index 262e23ec..0f90847a 100644 --- a/src/mips/Gget_save_loc.c +++ b/src/mips/Gget_save_loc.c @@ -68,6 +68,7 @@ unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) case UNW_MIPS_R29: case UNW_MIPS_R30: case UNW_MIPS_R31: + case UNW_MIPS_PC: loc = c->dwarf.loc[reg - UNW_MIPS_R0]; break; diff --git a/src/mips/Ginit.c b/src/mips/Ginit.c index 6ffeabfa..31000b3c 100644 --- a/src/mips/Ginit.c +++ b/src/mips/Ginit.c @@ -46,6 +46,8 @@ uc_addr (ucontext_t *uc, int reg) { if (reg >= UNW_MIPS_R0 && reg < UNW_MIPS_R0 + 32) return &uc->uc_mcontext.gregs[reg - UNW_MIPS_R0]; + else if (reg == UNW_MIPS_PC) + return &uc->uc_mcontext.pc; else return NULL; } diff --git a/src/mips/Gregs.c b/src/mips/Gregs.c index 9f37299c..0dfc4a93 100644 --- a/src/mips/Gregs.c +++ b/src/mips/Gregs.c @@ -69,6 +69,10 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, loc = c->dwarf.loc[reg - UNW_MIPS_R0]; break; + case UNW_MIPS_PC: + loc = c->dwarf.loc[reg]; + break; + case UNW_MIPS_CFA: if (write) return -UNW_EREADONLYREG; diff --git a/src/mips/getcontext.S b/src/mips/getcontext.S index ad9e1f00..d1dbd579 100644 --- a/src/mips/getcontext.S +++ b/src/mips/getcontext.S @@ -1,5 +1,6 @@ /* libunwind - a platform-independent unwind library Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala This file is part of libunwind. @@ -37,8 +38,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ sw $X, (LINUX_UC_MCONTEXT_GREGS + 8 * X + OFFSET) ($4); \ sra $1, $X, 31; \ sw $1, (LINUX_UC_MCONTEXT_GREGS + 8 * X + 4 - OFFSET) ($4) +/* Yes, we save the return address to PC. */ +# define SPC \ + sw $31, (LINUX_UC_MCONTEXT_PC + OFFSET) ($4); \ + sra $1, $31, 31; \ + sw $1, (LINUX_UC_MCONTEXT_PC + 4 - OFFSET) ($4) #else # define SREG(X) sd $X, (LINUX_UC_MCONTEXT_GREGS + 8 * X) ($4) +# define SPC sd $31, (LINUX_UC_MCONTEXT_PC) ($4) #endif .global _Umips_getcontext @@ -79,6 +86,7 @@ _Umips_getcontext: SREG (29) SREG (30) SREG (31) + SPC li $2, 0 j $31 diff --git a/src/mips/init.h b/src/mips/init.h index 3a4bb008..95322c6b 100644 --- a/src/mips/init.h +++ b/src/mips/init.h @@ -34,7 +34,9 @@ common_init (struct cursor *c, unsigned use_prev_instr) for (i = 32; i < DWARF_NUM_PRESERVED_REGS; ++i) c->dwarf.loc[i] = DWARF_NULL_LOC; - ret = dwarf_get (&c->dwarf, c->dwarf.loc[31], &c->dwarf.ip); + c->dwarf.loc[UNW_MIPS_PC] = DWARF_REG_LOC (&c->dwarf, UNW_MIPS_PC); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_PC], &c->dwarf.ip); if (ret < 0) return ret; diff --git a/src/mips/offsets.h b/src/mips/offsets.h index 8040f6a5..49af9704 100644 --- a/src/mips/offsets.h +++ b/src/mips/offsets.h @@ -16,6 +16,7 @@ # define LINUX_UC_STACK_OFF 0x8 # define LINUX_UC_MCONTEXT_OFF 0x18 # define LINUX_UC_SIGMASK_OFF 0x268 +# define LINUX_UC_MCONTEXT_PC 0x20 # define LINUX_UC_MCONTEXT_GREGS 0x28 #elif _MIPS_SIM == _ABIN32 @@ -25,6 +26,7 @@ # define LINUX_UC_STACK_OFF 0x8 # define LINUX_UC_MCONTEXT_OFF 0x18 # define LINUX_UC_SIGMASK_OFF 0x270 +# define LINUX_UC_MCONTEXT_PC 0x258 # define LINUX_UC_MCONTEXT_GREGS 0x18 #elif _MIPS_SIM == _ABI64 @@ -34,6 +36,7 @@ # define LINUX_UC_STACK_OFF 0x10 # define LINUX_UC_MCONTEXT_OFF 0x28 # define LINUX_UC_SIGMASK_OFF 0x280 +# define LINUX_UC_MCONTEXT_PC 0x268 # define LINUX_UC_MCONTEXT_GREGS 0x28 #endif diff --git a/src/mips/regname.c b/src/mips/regname.c index 94000d49..a4a63340 100644 --- a/src/mips/regname.c +++ b/src/mips/regname.c @@ -41,6 +41,8 @@ unw_regname (unw_regnum_t reg) { if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) return regname[reg]; + else if (reg == UNW_MIPS_PC) + return "pc"; else return "???"; }