2004-07-17 Andrew Cagney <cagney@gnu.org>
[deliverable/binutils-gdb.git] / gdb / sparc-tdep.c
index fcaf0f437bf23afb453aeb443d56bcf9b3d39bf2..7fbd9de62b02e26881d131e6390f269685d926a4 100644 (file)
 
 struct regset;
 
-/* This file implements the The SPARC 32-bit ABI as defined by the
-   section "Low-Level System Information" of the SPARC Compliance
-   Definition (SCD) 2.4.1, which is the 32-bit System V psABI for
-   SPARC.  The SCD lists changes with respect to the origional 32-bit
-   psABI as defined in the "System V ABI, SPARC Processor
-   Supplement".
+/* This file implements the SPARC 32-bit ABI as defined by the section
+   "Low-Level System Information" of the SPARC Compliance Definition
+   (SCD) 2.4.1, which is the 32-bit System V psABI for SPARC.  The SCD
+   lists changes with respect to the original 32-bit psABI as defined
+   in the "System V ABI, SPARC Processor Supplement".
 
    Note that if we talk about SunOS, we mean SunOS 4.x, which was
    BSD-based, which is sometimes (retroactively?) referred to as
@@ -106,6 +105,56 @@ sparc_fetch_instruction (CORE_ADDR pc)
   return insn;
 }
 \f
+
+/* OpenBSD/sparc includes StackGhost, which according to the author's
+   website http://stackghost.cerias.purdue.edu "... transparently and
+   automatically protects applications' stack frames; more
+   specifically, it guards the return pointers.  The protection
+   mechanisms require no application source or binary modification and
+   imposes only a negligible performance penalty."
+
+   The same website provides the following description of how
+   StackGhost works:
+
+   "StackGhost interfaces with the kernel trap handler that would
+   normally write out registers to the stack and the handler that
+   would read them back in.  By XORing a cookie into the
+   return-address saved in the user stack when it is actually written
+   to the stack, and then XOR it out when the return-address is pulled
+   from the stack, StackGhost can cause attacker corrupted return
+   pointers to behave in a manner the attacker cannot predict.
+   StackGhost can also use several unused bits in the return pointer
+   to detect a smashed return pointer and abort the process."
+
+   For GDB this means that whenever we're reading %i7 from a stack
+   frame's window save area, we'll have to XOR the cookie.
+
+   More information on StackGuard can be found on in:
+
+   Mike Frantzen and Mike Shuey. "StackGhost: Hardware Facilitated
+   Stack Protection."  2001.  Published in USENIX Security Symposium
+   '01.  */
+
+/* Fetch StackGhost Per-Process XOR cookie.  */
+
+ULONGEST
+sparc_fetch_wcookie (void)
+{
+  struct target_ops *ops = &current_target;
+  char buf[8];
+  int len;
+
+  len = target_read_partial (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
+  if (len == -1)
+    return 0;
+
+  /* We should have either an 32-bit or an 64-bit cookie.  */
+  gdb_assert (len == 4 || len == 8);
+
+  return extract_unsigned_integer (buf, len);
+}
+\f
+
 /* Return the contents if register REGNUM as an address.  */
 
 static CORE_ADDR
@@ -136,7 +185,7 @@ sparc_integral_or_pointer_p (const struct type *type)
       {
        /* We have byte, half-word, word and extended-word/doubleword
            integral types.  The doubleword is an extension to the
-           origional 32-bit ABI by the SCD 2.4.x.  */
+           original 32-bit ABI by the SCD 2.4.x.  */
        int len = TYPE_LENGTH (type);
        return (len == 1 || len == 2 || len == 4 || len == 8);
       }
@@ -401,7 +450,7 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
 }
 
 static CORE_ADDR
-sparc32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+sparc32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                         struct regcache *regcache, CORE_ADDR bp_addr,
                         int nargs, struct value **args, CORE_ADDR sp,
                         int struct_return, CORE_ADDR struct_addr)
@@ -565,14 +614,6 @@ sparc_frame_cache (struct frame_info *next_frame, void **this_cache)
   cache = sparc_alloc_frame_cache ();
   *this_cache = cache;
 
-  /* In priciple, for normal frames, %fp (%i6) holds the frame
-     pointer, which holds the base address for the current stack
-     frame.  */
-
-  cache->base = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
-  if (cache->base == 0)
-    return cache;
-
   cache->pc = frame_func_unwind (next_frame);
   if (cache->pc != 0)
     {
@@ -582,10 +623,18 @@ sparc_frame_cache (struct frame_info *next_frame, void **this_cache)
 
   if (cache->frameless_p)
     {
-      /* We didn't find a valid frame, which means that CACHE->base
-        currently holds the frame pointer for our calling frame.  */
-      cache->base = frame_unwind_register_unsigned (next_frame,
-                                                   SPARC_SP_REGNUM);
+      /* This function is frameless, so %fp (%i6) holds the frame
+         pointer for our calling frame.  Use %sp (%o6) as this frame's
+         base address.  */
+      cache->base =
+       frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
+    }
+  else
+    {
+      /* For normal frames, %fp (%i6) holds the frame pointer, the
+         base address for the current stack frame.  */
+      cache->base =
+       frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
     }
 
   return cache;
@@ -666,6 +715,29 @@ sparc32_frame_prev_register (struct frame_info *next_frame, void **this_cache,
       return;
     }
 
+  /* Handle StackGhost.  */
+  {
+    ULONGEST wcookie = sparc_fetch_wcookie ();
+
+    if (wcookie != 0 && !cache->frameless_p && regnum == SPARC_I7_REGNUM)
+      {
+       *optimizedp = 0;
+       *lvalp = not_lval;
+       *addrp = 0;
+       *realnump = -1;
+       if (valuep)
+         {
+           CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
+           ULONGEST i7;
+
+           /* Read the value in from memory.  */
+           i7 = get_frame_memory_unsigned (next_frame, addr, 4);
+           store_unsigned_integer (valuep, 4, i7 ^ wcookie);
+         }
+       return;
+      }
+  }
+
   /* The previous frame's `local' and `in' registers have been saved
      in the register save area.  */
   if (!cache->frameless_p
@@ -839,8 +911,8 @@ sparc32_return_value (struct gdbarch *gdbarch, struct type *type,
 #if 0
 /* NOTE: cagney/2004-01-17: For the moment disable this method.  The
    architecture and CORE-gdb will need new code (and a replacement for
-   EXTRACT_STRUCT_VALUE_ADDRESS) before this can be made to work
-   robustly.  Here is a possible function signature: */
+   DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS) before this can be made to
+   work robustly.  Here is a possible function signature: */
 /* NOTE: cagney/2004-01-17: So far only the 32-bit SPARC ABI has been
    identifed as having a way to robustly recover the address of a
    struct-convention return-value (after the function has returned).
@@ -1030,10 +1102,10 @@ sparc_regset_from_core_section (struct gdbarch *gdbarch,
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (strcmp (sect_name, ".reg") == 0 && sect_size == tdep->sizeof_gregset)
+  if (strcmp (sect_name, ".reg") == 0 && sect_size >= tdep->sizeof_gregset)
     return tdep->gregset;
 
-  if (strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
+  if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset)
     return tdep->fpregset;
 
   return NULL;
@@ -1058,9 +1130,9 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->pc_regnum = SPARC32_PC_REGNUM;
   tdep->npc_regnum = SPARC32_NPC_REGNUM;
   tdep->gregset = NULL;
-  tdep->sizeof_gregset = 20 * 4;
+  tdep->sizeof_gregset = 0;
   tdep->fpregset = NULL;
-  tdep->sizeof_fpregset = 33 * 4;
+  tdep->sizeof_fpregset = 0;
   tdep->plt_entry_size = 0;
 
   set_gdbarch_long_double_bit (gdbarch, 128);
@@ -1113,7 +1185,7 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   frame_unwind_append_sniffer (gdbarch, sparc32_frame_sniffer);
 
   /* If we have register sets, enable the generic core file support.  */
-  if (tdep->gregset && tdep->fpregset)
+  if (tdep->gregset)
     set_gdbarch_regset_from_core_section (gdbarch,
                                          sparc_regset_from_core_section);
 
@@ -1163,6 +1235,16 @@ sparc_supply_rwindow (struct regcache *regcache, CORE_ADDR sp, int regnum)
            {
              target_read_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
                                  buf + offset, 4);
+
+             /* Handle StackGhost.  */
+             if (i == SPARC_I7_REGNUM)
+               {
+                 ULONGEST wcookie = sparc_fetch_wcookie ();
+                 ULONGEST i7 = extract_unsigned_integer (buf + offset, 4);
+
+                 store_unsigned_integer (buf + offset, 4, i7 ^ wcookie);
+               }
+
              regcache_raw_supply (regcache, i, buf);
            }
        }
@@ -1206,6 +1288,16 @@ sparc_collect_rwindow (const struct regcache *regcache,
          if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i)
            {
              regcache_raw_collect (regcache, i, buf);
+
+             /* Handle StackGhost.  */
+             if (i == SPARC_I7_REGNUM)
+               {
+                 ULONGEST wcookie = sparc_fetch_wcookie ();
+                 ULONGEST i7 = extract_unsigned_integer (buf + offset, 4);
+
+                 store_unsigned_integer (buf + offset, 4, i7 ^ wcookie);
+               }
+
              target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
                                   buf + offset, 4);
            }
This page took 0.054322 seconds and 4 git commands to generate.