libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] [PATCH 33/57] MIPS coredump support


From: Tommi Rantala
Subject: [Libunwind-devel] [PATCH 33/57] MIPS coredump support
Date: Fri, 21 Sep 2012 14:11:34 +0300

Add MIPS support to the coredump library. Explicit support for the MIPS
program counter register is added so that we can start backtracing from
the program counter value we read from a core dump. The PC register
support was not strictly required for local backtracing, and we will in
fact just plug the return address to the PC register in getcontext().

I have only tested the 32bit "OABI" paths.
---
 configure.ac                         |    2 +-
 include/libunwind-mips.h             |    2 ++
 src/coredump/_UCD_access_reg_linux.c |   37 +++++++++++++++++++++++++++++++++-
 src/mips/Gget_save_loc.c             |    1 +
 src/mips/Ginit.c                     |    2 ++
 src/mips/Gregs.c                     |    4 ++++
 src/mips/getcontext.S                |    8 ++++++++
 src/mips/init.h                      |    4 +++-
 src/mips/offsets.h                   |    3 +++
 src/mips/regname.c                   |    2 ++
 10 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0312b24..aed7eab 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 91f7001..cf22fc9 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 c48f5c9..9fd7f7d 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 262e23e..0f90847 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 6ffeabf..31000b3 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 9f37299..0dfc4a9 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 ad9e1f0..d1dbd57 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 <address@hidden>
 
 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 3a4bb00..95322c6 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 8040f6a..49af970 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 94000d4..a4a6334 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 "???";
 }
-- 
1.7.9.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]