This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] DWARF2 unwinder on SPARC


I'm working on enabling the DWARF2 unwinder on 32-bit and 64-bit
SPARC.  It's basically working for me on FreeBSD/sparc64, but there
are two issues that I'd like some opinions about.

1. I'll need to handle DW_CFA_GNU_window_save.  I suppose its
   interpretation will be really machine specific, but it really only
   makes sense for register window architectures.  And I can only
   think of a single example of such an architecture that's still
   around.  Now the problem I'm facing is the choice between two
   evils:

   a. Contaminate dwarf2-frame.c with a bit of target-specific code.

   b. Contaminate dwarf2-frame.c with another architecture-specific
      operation that will only be used for SPARC.

   Can someone make a choice for me ;-)

2. We need a mechanism for return addresses that are not quite the
   contents of a register or memory slot.  On SPARC, the address of
   the call instruction is stored in a register instead of the address
   where we should return to.  So the proper way to unwind the pc is
   to take this register and add 8 to it.  There's also npc, which
   should be calculated in a similar way by adding 12.  We'll need
   something similar for PA-RISC and m88k will need it too if it ever
   gains a dwarf2 unwinder.  There might be more architectures out
   there that need this.

   My proposal is to change the definition of DWARF2_FRAME_REG_RA such
   that the offset member of `struct dwarf2_frame_state_reg' can be
   used to specify the amount to add to the value yielded by the
   return address column.  This is compatible with the existing use
   since currently that offset member is initialized to zero.  As an
   alternative, we can add a new constant DWARF2_FRAME_REG_RA_OFFSET
   for this usage.

Attached is my preliminary patch that implements this stuff.

Mark


Index: dwarf2-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2-frame.c,v
retrieving revision 1.48
diff -u -p -r1.48 dwarf2-frame.c
--- dwarf2-frame.c 11 Feb 2005 18:13:49 -0000 1.48
+++ dwarf2-frame.c 7 Mar 2005 21:03:14 -0000
@@ -445,6 +445,20 @@ bad CFI data; mismatched DW_CFA_restore_
 	      /* cfa_how deliberately not set.  */
 	      break;
 
+	    case DW_CFA_GNU_window_save:
+	      dwarf2_frame_state_alloc_regs (&fs->regs, 32);
+	      for (reg = 8; reg < 16; reg++)
+		{
+		  fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
+		  fs->regs.reg[reg].loc.reg = reg + 16;
+		}
+	      for (reg = 16; reg < 32; reg++)
+		{
+		  fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
+		  fs->regs.reg[reg].loc.offset = (reg - 16) * 8;
+		}
+	      break;
+
 	    case DW_CFA_GNU_args_size:
 	      /* Ignored.  */
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
@@ -588,6 +602,9 @@ struct dwarf2_frame_cache
   /* Saved registers, indexed by GDB register number, not by DWARF
      register number.  */
   struct dwarf2_frame_state_reg *reg;
+
+  /* Return address register.  */
+  struct dwarf2_frame_state_reg retaddr_reg;
 };
 
 static struct dwarf2_frame_cache *
@@ -733,16 +750,29 @@ incomplete CFI data; unspecified registe
                what GCC does on some targets.  It turns out that GCC
                assumes that the return address can be found in the
                register corresponding to the return address column.
-               Incidentally, that's how should treat a return address
-               column specifying "same value" too.  */
+               Incidentally, that's how we should treat a return
+               address column specifying "same value" too.  */
 	    if (fs->retaddr_column < fs->regs.num_regs
 		&& retaddr_reg->how != DWARF2_FRAME_REG_UNSPECIFIED
 		&& retaddr_reg->how != DWARF2_FRAME_REG_SAME_VALUE)
-	      cache->reg[regnum] = *retaddr_reg;
+	      {
+		if (cache->reg[regnum].loc.offset == 0)
+		  cache->reg[regnum] = *retaddr_reg;
+		else
+		  cache->retaddr_reg = *retaddr_reg;
+	      }
 	    else
 	      {
-		cache->reg[regnum].loc.reg = fs->retaddr_column;
-		cache->reg[regnum].how = DWARF2_FRAME_REG_SAVED_REG;
+		if (cache->reg[regnum].loc.offset == 0)
+		  {
+		    cache->reg[regnum].loc.reg = fs->retaddr_column;
+		    cache->reg[regnum].how = DWARF2_FRAME_REG_SAVED_REG;
+		  }
+		else
+		  {
+		    cache->retaddr_reg.loc.reg = fs->retaddr_column;
+		    cache->retaddr_reg.how = DWARF2_FRAME_REG_SAVED_REG;
+		  }
 	      }
 	  }
       }
@@ -864,6 +894,21 @@ dwarf2_frame_prev_register (struct frame
 	}
       break;
 
+    case DWARF2_FRAME_REG_RA:
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      if (valuep)
+	{
+	  CORE_ADDR pc = cache->reg[regnum].loc.offset;
+
+	  regnum = DWARF2_REG_TO_REGNUM (cache->retaddr_reg.loc.reg);
+	  pc += frame_unwind_register_unsigned (next_frame, regnum);
+	  store_typed_address (valuep, builtin_type_void_func_ptr, pc);
+	}
+      break;
+
     default:
       internal_error (__FILE__, __LINE__, _("Unknown register rule."));
     }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]