libunwind-devel
[Top][All Lists]
Advanced

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

[Libunwind-devel] add methods to access full xmm registers on i386


From: Andrew Cagney
Subject: [Libunwind-devel] add methods to access full xmm registers on i386
Date: Tue, 11 Dec 2007 10:14:49 -0500
User-agent: Thunderbird 1.5.0.12 (X11/20070530)

Hi,

I noticed two possible limitations with the i386 interface:

- unw_fpreg_t is defined as "long double"

When remote unwinding, "long double" may not be what you think. Since the type is used as a container, and not actually interpreted. I've changed the type to a union vis:
+typedef union {
+  struct { uint8_t b[4]; } val32;
+  struct { uint8_t b[10]; } val80;
+  struct { uint8_t b[16]; } val128;
+} unw_tdep_fpreg_t;
from memory this was suggested a while back when the PPC was being discussed.

- fetching the 128-bit xmm registers is a pain

The interface, as defined, requires that they be fetched as lo/hi 64-bit halves. With unw_fpreg_t enlarged to hold full 128-bit values, I can add full XMM registers to the enum list vis:
+    UNW_X86_XMM0,      /* scratch */
+    UNW_X86_XMM1,      /* scratch */
...
(and hopefully tweaked every where where needed). One thing to notice is that I've placed them after UNW_X86_CFA (so its value doesn't change), I suspect that, in future, these virtual registers should be given -ve values so that they can't get in the way of this register growth.



I've appended true XMM enum definitions that, using the above, fetch the full registers.

Andrew

2007-12-10  Andrew Cagney  <address@hidden>

        * src/x86/Gregs.c (linux_scratch_loc): Add XMM registers.
        (tdep_access_fpreg): Ditto.
        * src/x86/regname.c: Add XMM registers.
        * src/x86/is_fpreg.c: Include XMM0 .. XMM7 in floating point
        registers.
        * include/libunwind-x86.h (x86_regnum_t): Add UNW_X86_XMM0,
        UNW_X86_XMM1, UNW_X86_XMM2, UNW_X86_XMM3, UNW_X86_XMM4,
        UNW_X86_XMM5, UNW_X86_XMM7, UNW_X86_XMM7.
        (unw_tdep_fpreg_t): Change to a union of possible values.

diff --git a/frysk-imports/libunwind/include/libunwind-x86.h 
b/frysk-imports/libunwind/include/libunwind-x86.h
index 38664f9..1e321db 100644
--- a/frysk-imports/libunwind/include/libunwind-x86.h
+++ b/frysk-imports/libunwind/include/libunwind-x86.h
@@ -48,7 +48,11 @@ extern "C" {
 typedef uint32_t unw_word_t;
 typedef int32_t unw_sword_t;
 
-typedef long double unw_tdep_fpreg_t;
+typedef union {
+  struct { uint8_t b[4]; } val32;
+  struct { uint8_t b[10]; } val80;
+  struct { uint8_t b[16]; } val128;
+} unw_tdep_fpreg_t;
 
 typedef enum
   {
@@ -131,7 +135,16 @@ typedef enum
     /* frame info (read-only) */
     UNW_X86_CFA,
 
-    UNW_TDEP_LAST_REG = UNW_X86_LDT,
+    UNW_X86_XMM0,      /* scratch */
+    UNW_X86_XMM1,      /* scratch */
+    UNW_X86_XMM2,      /* scratch */
+    UNW_X86_XMM3,      /* scratch */
+    UNW_X86_XMM4,      /* scratch */
+    UNW_X86_XMM5,      /* scratch */
+    UNW_X86_XMM6,      /* scratch */
+    UNW_X86_XMM7,      /* scratch */
+
+    UNW_TDEP_LAST_REG = UNW_X86_XMM7,
 
     UNW_TDEP_IP = UNW_X86_EIP,
     UNW_TDEP_SP = UNW_X86_CFA,
diff --git a/frysk-imports/libunwind/src/x86/Gregs.c 
b/frysk-imports/libunwind/src/x86/Gregs.c
index 68afd37..78cfabc 100644
--- a/frysk-imports/libunwind/src/x86/Gregs.c
+++ b/frysk-imports/libunwind/src/x86/Gregs.c
@@ -97,6 +97,17 @@ linux_scratch_loc (struct cursor *c, unw_regnum_t reg)
       is_fpstate = 1;
       off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
       break;
+    case UNW_X86_XMM0:
+    case UNW_X86_XMM1:
+    case UNW_X86_XMM2:
+    case UNW_X86_XMM3:
+    case UNW_X86_XMM4:
+    case UNW_X86_XMM5:
+    case UNW_X86_XMM6:
+    case UNW_X86_XMM7:
+      is_fpstate = 1;
+      off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
+      break;
 
     case UNW_X86_FOP:
     case UNW_X86_TSS:
@@ -235,6 +246,14 @@ tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, 
unw_fpreg_t *valp,
     case UNW_X86_ST6:
     case UNW_X86_ST7:
       /* SSE fp registers */
+    case UNW_X86_XMM0:
+    case UNW_X86_XMM1:
+    case UNW_X86_XMM2:
+    case UNW_X86_XMM3:
+    case UNW_X86_XMM4:
+    case UNW_X86_XMM5:
+    case UNW_X86_XMM6:
+    case UNW_X86_XMM7:
     case UNW_X86_XMM0_lo:
     case UNW_X86_XMM0_hi:
     case UNW_X86_XMM1_lo:
diff --git a/frysk-imports/libunwind/src/x86/is_fpreg.c 
b/frysk-imports/libunwind/src/x86/is_fpreg.c
index 6dc5640..8f1536d 100644
--- a/frysk-imports/libunwind/src/x86/is_fpreg.c
+++ b/frysk-imports/libunwind/src/x86/is_fpreg.c
@@ -29,5 +29,6 @@ PROTECTED int
 unw_is_fpreg (int regnum)
 {
   return ((regnum >= UNW_X86_ST0 && regnum <= UNW_X86_ST7)
-         || (regnum >= UNW_X86_XMM0_lo && regnum <= UNW_X86_XMM7_hi));
+         || (regnum >= UNW_X86_XMM0_lo && regnum <= UNW_X86_XMM7_hi)
+         || (regnum >= UNW_X86_XMM0 && regnum <= UNW_X86_XMM7));
 }
diff --git a/frysk-imports/libunwind/src/x86/regname.c 
b/frysk-imports/libunwind/src/x86/regname.c
index 824e213..2228510 100644
--- a/frysk-imports/libunwind/src/x86/regname.c
+++ b/frysk-imports/libunwind/src/x86/regname.c
@@ -12,7 +12,9 @@ static const char *regname[] =
     "xmm6_lo", "xmm6_hi", "xmm7_lo", "xmm7_hi",
     "mxcsr",
     "gs", "fs", "es", "ds", "ss", "cs",
-    "tss", "ldt"
+    "tss", "ldt",
+    "cfi",
+    "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
   };
 
 PROTECTED const char *
diff --git a/frysk-sys/lib/unwind/cni/UnwindH.hxx 
b/frysk-sys/lib/unwind/cni/UnwindH.hxx
index 1d13156..04bb212 100644
--- a/frysk-sys/lib/unwind/cni/UnwindH.hxx
+++ b/frysk-sys/lib/unwind/cni/UnwindH.hxx
@@ -286,20 +286,21 @@ 
lib::unwind::TARGET::getRegister(gnu::gcj::RawDataManaged* cursor,
     unw_word_t w;
     unw_fpreg_t fp;
   } word;
+  int size;
   if (unw_is_fpreg(regNum))
-    {
-      verifyBounds(offset, length, bytes, start, sizeof(word.fp));
-      status = unw_get_fpreg((::unw_cursor_t *) cursor,
-                            (::unw_regnum_t) regNum,
-                            &word.fp);
-    }
+    size = sizeof(word.fp);
   else
-    {
-      verifyBounds(offset, length, bytes, start, sizeof(word.w));
-      status = unw_get_reg((::unw_cursor_t *) cursor,
+    size = sizeof(word.w);
+  verifyBounds(offset, length, bytes, start, size);
+  if (unw_is_fpreg(regNum))
+    status = unw_get_fpreg((::unw_cursor_t *) cursor,
                           (::unw_regnum_t) regNum,
-                          &word.w);
-    }
+                          &word.fp);
+  else
+    status = unw_get_reg((::unw_cursor_t *) cursor,
+                        (::unw_regnum_t) regNum,
+                        &word.w);
+  printf("status=%d\n", status);
   if (status != 0)
     throwRuntimeException("get register failed");
   memcpy(elements(bytes) + start, (uint8_t*)&word + offset, length);
@@ -317,20 +318,20 @@ 
lib::unwind::TARGET::setRegister(gnu::gcj::RawDataManaged* cursor,
     unw_word_t w;
     unw_fpreg_t fp;
   } word;
+  int size;
   if (unw_is_fpreg(regNum))
-    {
-      verifyBounds(offset, length, bytes, start, sizeof(word.fp));
-      status = unw_get_fpreg((::unw_cursor_t *) cursor,
-                            (::unw_regnum_t) regNum,
-                            &word.fp);
-    }
+    size = sizeof(word.fp);
   else
-    {
-      verifyBounds(offset, length, bytes, start, sizeof(word.w));
-      status = unw_get_reg((::unw_cursor_t *) cursor,
+    size = sizeof(word.w);
+  verifyBounds(offset, length, bytes, start, size);
+  if (unw_is_fpreg(regNum))
+    status = unw_get_fpreg((::unw_cursor_t *) cursor,
                           (::unw_regnum_t) regNum,
-                          &word.w);
-    }
+                          &word.fp);
+  else
+    status = unw_get_reg((::unw_cursor_t *) cursor,
+                        (::unw_regnum_t) regNum,
+                        &word.w);
   if (status != 0)
     throwRuntimeException("set register failed");
   memcpy((uint8_t*)&word + offset, elements(bytes) + start, length);

reply via email to

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