This is the mail archive of the gdb-patches@sourceware.cygnus.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]

[PATCH] Handle IA-64 signal handler frames, call dummy frames


I've just committed the patch below.  It consists (mostly) of changes
for handling signal handler frames, but also contains changes for
handling call dummy frames.  (Prior to this patch, you couldn't
backtrace through either; it's odd that signals.exp caught the fact
that backtracing through dummy frames was broken on IA-64.)

Target architecture maintainers who are involved in multi-arching
their target may want to look at my changes to ia64_gdbarch_init(). 
I've added some machinery for determining the OS/ABI associated with
the target in order to set up target specific code for looking up
registers from the OS's sigcontext struct.

Note that IN_SIGTRAMP really needs to be brought under multiarch
control.  But once this is done, I have the mechanisms in place to
properly set it.

	* ia64-linux-tdep.c: New file.
	* ia64-tdep.c (elf-bfd.h): Include.
	(ia64_linux_sigcontext_register_address): New extern declaration.
	(struct gdbarch_tdep): New struct.
	(SIGCONTEXT_REGISTER_ADDRESS): New define.
	(read_sigcontext_register): New static function.
	(extract_bit_field, replace_bit_field, slotN_contents,
	replace_slotN_contents): Made static.
	(ia64_frame_chain, ia64_frame_saved_pc, ia64_init_extra_frame_info):
	Added new code for signal handler frames and call dummy frames.
	(ia64_frame_init_saved_regs): Handle signal handler frames.
	(ia64_find_saved_register): Removed.
	(ia64_get_saved_register): Handle call dummy frames; reorganized
	to call generic_get_saved_register() to find registers saved
	in previous frames.
	(process_note_abi_tag_sections): New static function.
	(ia64_gdbarch_init): Attempt to determine the ABI/OS of the
	executable.  Based upon this information, set target dependent
	field sigcontext_register_address appropriately.  Also set
	FRAME_CHAIN_VALID to be generic_func_frame_chain_valid.
	* config/ia64/linux.mt (TDEPFILES): Add ia64-linux-tdep.o.
	* config/ia64/tm-linux.h (IN_SIGTRAMP): Define.
	(ia64_linux_in_sigtramp): New declaration.

Index: ia64-linux-tdep.c
===================================================================
RCS file: ia64-linux-tdep.c
diff -N ia64-linux-tdep.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ ia64-linux-tdep.c	Mon Apr 24 23:07:42 2000
@@ -0,0 +1,86 @@
+/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
+   Copyright 2000
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+
+/* The sigtramp code is in a non-readable (executable-only) region
+   of memory called the ``gate page''.  The addresses in question
+   were determined by examining the system headers.  They are
+   overly generous to allow for different pages sizes. */
+
+#define GATE_AREA_START 0xa000000000000100LL
+#define GATE_AREA_END   0xa000000000010000LL
+
+/* Offset to sigcontext structure from frame of handler */
+#define IA64_LINUX_SIGCONTEXT_OFFSET 160
+
+int
+ia64_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+  return (pc >= (CORE_ADDR) GATE_AREA_START && pc < (CORE_ADDR) GATE_AREA_END);
+}
+
+/* IA-64 GNU/Linux specific function which, given a frame address and
+   a register number, returns the address at which that register may be
+   found.  0 is returned for registers which aren't stored in the the
+   sigcontext structure. */
+
+CORE_ADDR
+ia64_linux_sigcontext_register_address (CORE_ADDR sp, int regno)
+{
+  if (IA64_GR0_REGNUM <= regno && regno <= IA64_GR31_REGNUM)
+    return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 200 + 8 * (regno - IA64_GR0_REGNUM);
+  else if (IA64_BR0_REGNUM <= regno && regno <= IA64_BR7_REGNUM)
+    return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 136 + 8 * (regno - IA64_BR0_REGNUM);
+  else if (IA64_FR0_REGNUM <= regno && regno <= IA64_FR127_REGNUM)
+    return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 464 + 16 * (regno - IA64_FR0_REGNUM);
+  else
+    switch (regno)
+      {
+      case IA64_IP_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 40;
+      case IA64_CFM_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 48;
+      case IA64_PSR_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 56;		/* user mask only */
+      /* sc_ar_rsc is provided, from which we could compute bspstore, but
+	 I don't think it's worth it.  Anyway, if we want it, it's at offset
+	 64 */
+      case IA64_BSP_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 72;
+      case IA64_RNAT_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 80;
+      case IA64_CCV_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 88;
+      case IA64_UNAT_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 96;
+      case IA64_FPSR_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 104;
+      case IA64_PFS_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 112;
+      case IA64_LC_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 120;
+      case IA64_PR_REGNUM :
+	return sp + IA64_LINUX_SIGCONTEXT_OFFSET + 128;
+      default :
+	return 0;
+      }
+}
Index: ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.3
diff -u -p -r1.3 ia64-tdep.c
--- ia64-tdep.c	2000/04/03 18:58:48	1.3
+++ ia64-tdep.c	2000/04/25 06:07:44
@@ -27,6 +27,7 @@
 
 #include "objfiles.h"
 #include "elf/common.h"		/* for DT_PLTGOT value */
+#include "elf-bfd.h"
 
 typedef enum instruction_type
 {
@@ -63,6 +64,8 @@ typedef enum instruction_type
 
 extern void _initialize_ia64_tdep (void);
 
+extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int);
+
 static gdbarch_init_ftype ia64_gdbarch_init;
 
 static gdbarch_register_name_ftype ia64_register_name;
@@ -188,23 +191,36 @@ static char *ia64_register_names[] = 
 };
 
 struct frame_extra_info
-{
-  CORE_ADDR bsp;	/* points at r32 for the current frame */
-  CORE_ADDR cfm;	/* cfm value for current frame */
-  int       sof;	/* Size of frame  (decoded from cfm value) */
-  int	    sol;	/* Size of locals (decoded from cfm value) */
-  CORE_ADDR after_prologue;
-  			/* Address of first instruction after the last
+  {
+    CORE_ADDR bsp;	/* points at r32 for the current frame */
+    CORE_ADDR cfm;	/* cfm value for current frame */
+    int sof;		/* Size of frame  (decoded from cfm value) */
+    int	sol;		/* Size of locals (decoded from cfm value) */
+    CORE_ADDR after_prologue;
+			/* Address of first instruction after the last
 			   prologue instruction;  Note that there may
 			   be instructions from the function's body
 			   intermingled with the prologue. */
-  int       mem_stack_frame_size;
-  			/* Size of the memory stack frame (may be zero),
+    int mem_stack_frame_size;
+			/* Size of the memory stack frame (may be zero),
 			   or -1 if it has not been determined yet. */
-  int	    fp_reg;	/* Register number (if any) used a frame pointer
-                           for this frame.  0 if no register is being used
+    int	fp_reg;		/* Register number (if any) used a frame pointer
+			   for this frame.  0 if no register is being used
 			   as the frame pointer. */
-};
+  };
+
+struct gdbarch_tdep
+  {
+    int os_ident;	/* From the ELF header, one of the ELFOSABI_
+                           constants: ELFOSABI_LINUX, ELFOSABI_MONTEREY,
+			   etc. */
+    CORE_ADDR (*sigcontext_register_address) (CORE_ADDR, int);
+    			/* OS specific function which, given a frame address
+			   and register number, returns the offset to the
+			   given register from the start of the frame. */
+  };
+
+#define SIGCONTEXT_REGISTER_ADDRESS (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
 
 static char *
 ia64_register_name (int reg)
@@ -281,10 +297,35 @@ ia64_register_byte (int reg)
    (reg <= IA64_FR0_REGNUM ? 0 : 8 * ((reg > IA64_FR127_REGNUM) ? 128 : reg - IA64_FR0_REGNUM));
 }
 
+/* Read the given register from a sigcontext structure in the
+   specified frame.  */
+
+static CORE_ADDR
+read_sigcontext_register (struct frame_info *frame, int regnum)
+{
+  CORE_ADDR regaddr;
+
+  if (frame == NULL)
+    internal_error ("read_sigcontext_register: NULL frame");
+  if (!frame->signal_handler_caller)
+    internal_error (
+      "read_sigcontext_register: frame not a signal_handler_caller");
+  if (SIGCONTEXT_REGISTER_ADDRESS == 0)
+    internal_error (
+      "read_sigcontext_register: SIGCONTEXT_REGISTER_ADDRESS is 0");
+
+  regaddr = SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regnum);
+  if (regaddr)
+    return read_memory_integer (regaddr, REGISTER_RAW_SIZE (regnum));
+  else
+    internal_error (
+      "read_sigcontext_register: Register %d not in struct sigcontext", regnum);
+}
+
 /* Extract ``len'' bits from an instruction bundle starting at
    bit ``from''.  */
 
-long long
+static long long
 extract_bit_field (char *bundle, int from, int len)
 {
   long long result = 0LL;
@@ -320,7 +361,7 @@ extract_bit_field (char *bundle, int fro
 
 /* Replace the specified bits in an instruction bundle */
 
-void
+static void
 replace_bit_field (char *bundle, long long val, int from, int len)
 {
   int to = from + len;
@@ -370,7 +411,7 @@ replace_bit_field (char *bundle, long lo
 /* Return the contents of slot N (for N = 0, 1, or 2) in
    and instruction bundle */
 
-long long
+static long long
 slotN_contents (unsigned char *bundle, int slotnum)
 {
   return extract_bit_field (bundle, 5+41*slotnum, 41);
@@ -378,7 +419,7 @@ slotN_contents (unsigned char *bundle, i
 
 /* Store an instruction in an instruction bundle */
 
-void
+static void
 replace_slotN_contents (unsigned char *bundle, long long instr, int slotnum)
 {
   replace_bit_field (bundle, instr, 5+41*slotnum, 41);
@@ -607,23 +648,38 @@ rse_address_add(CORE_ADDR addr, int nslo
 CORE_ADDR
 ia64_frame_chain (struct frame_info *frame)
 {
-  FRAME_INIT_SAVED_REGS (frame);
-
-  if (frame->saved_regs[IA64_VFP_REGNUM])
-    return read_memory_integer (frame->saved_regs[IA64_VFP_REGNUM], 8);
+  if (frame->signal_handler_caller)
+    return read_sigcontext_register (frame, sp_regnum);
+  else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+    return frame->frame;
   else
-    return frame->frame + frame->extra_info->mem_stack_frame_size;
+    {
+      FRAME_INIT_SAVED_REGS (frame);
+      if (frame->saved_regs[IA64_VFP_REGNUM])
+	return read_memory_integer (frame->saved_regs[IA64_VFP_REGNUM], 8);
+      else
+	return frame->frame + frame->extra_info->mem_stack_frame_size;
+    }
 }
 
 CORE_ADDR
 ia64_frame_saved_pc (struct frame_info *frame)
 {
-  FRAME_INIT_SAVED_REGS (frame);
+  if (frame->signal_handler_caller)
+    return read_sigcontext_register (frame, pc_regnum);
+  else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+    return generic_read_register_dummy (frame->pc, frame->frame, pc_regnum);
+  else
+    {
+      FRAME_INIT_SAVED_REGS (frame);
 
-  if (frame->saved_regs[IA64_VRAP_REGNUM])
-    return read_memory_integer (frame->saved_regs[IA64_VRAP_REGNUM], 8);
-  else	/* either frameless, or not far enough along in the prologue... */
-    return ia64_saved_pc_after_call (frame);
+      if (frame->saved_regs[IA64_VRAP_REGNUM])
+	return read_memory_integer (frame->saved_regs[IA64_VRAP_REGNUM], 8);
+      else if (frame->next && frame->next->signal_handler_caller)
+	return read_sigcontext_register (frame->next, IA64_BR0_REGNUM);
+      else	/* either frameless, or not far enough along in the prologue... */
+	return ia64_saved_pc_after_call (frame);
+    }
 }
 
 #define isScratch(_regnum_) ((_regnum_) == 2 || (_regnum_) == 3 \
@@ -916,50 +972,55 @@ ia64_skip_prologue (CORE_ADDR pc)
 void
 ia64_frame_init_saved_regs (struct frame_info *frame)
 {
-  CORE_ADDR func_start;
-
   if (frame->saved_regs)
     return;
-
-  func_start = get_pc_function_start (frame->pc);
-  examine_prologue (func_start, frame->pc, frame);
-}
 
-static CORE_ADDR
-ia64_find_saved_register (frame, regnum)
-     struct frame_info *frame;
-     int regnum;
-{
-  register CORE_ADDR addr = 0;
-
-  if ((IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
-      || regnum == IA64_VFP_REGNUM
-      || regnum == IA64_VRAP_REGNUM)
-    {
-      FRAME_INIT_SAVED_REGS (frame);
-      return frame->saved_regs[regnum];
-    }
-  else if (regnum == IA64_IP_REGNUM && frame->next)
+  if (frame->signal_handler_caller && SIGCONTEXT_REGISTER_ADDRESS)
     {
-      FRAME_INIT_SAVED_REGS (frame->next);
-      return frame->next->saved_regs[IA64_VRAP_REGNUM];
+      int regno;
+
+      frame_saved_regs_zalloc (frame);
+
+      frame->saved_regs[IA64_VRAP_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_IP_REGNUM);
+      frame->saved_regs[IA64_CFM_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CFM_REGNUM);
+      frame->saved_regs[IA64_PSR_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PSR_REGNUM);
+#if 0
+      frame->saved_regs[IA64_BSP_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_BSP_REGNUM);
+#endif
+      frame->saved_regs[IA64_RNAT_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_RNAT_REGNUM);
+      frame->saved_regs[IA64_CCV_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CCV_REGNUM);
+      frame->saved_regs[IA64_UNAT_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_UNAT_REGNUM);
+      frame->saved_regs[IA64_FPSR_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_FPSR_REGNUM);
+      frame->saved_regs[IA64_PFS_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PFS_REGNUM);
+      frame->saved_regs[IA64_LC_REGNUM] = 
+	SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_LC_REGNUM);
+      for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++)
+	if (regno != sp_regnum)
+	  frame->saved_regs[regno] =
+	    SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
+      for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
+	frame->saved_regs[regno] =
+	  SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
+      for (regno = IA64_FR2_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
+	frame->saved_regs[regno] =
+	  SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
     }
   else
     {
-      struct frame_info *frame1 = NULL;
-      while (1)
-	{
-	  QUIT;
-	  frame1 = get_prev_frame (frame1);
-	  if (frame1 == 0 || frame1 == frame)
-	    break;
-	  FRAME_INIT_SAVED_REGS (frame1);
-	  if (frame1->saved_regs[regnum])
-	    addr = frame1->saved_regs[regnum];
-	}
-    }
+      CORE_ADDR func_start;
 
-  return addr;
+      func_start = get_pc_function_start (frame->pc);
+      examine_prologue (func_start, frame->pc, frame);
+    }
 }
 
 void
@@ -970,76 +1031,29 @@ ia64_get_saved_register (char *raw_buffe
 			 int regnum,
 			 enum lval_type *lval)
 {
-  CORE_ADDR addr;
+  int is_dummy_frame;
 
   if (!target_has_registers)
     error ("No registers.");
 
   if (optimized != NULL)
     *optimized = 0;
-  addr = ia64_find_saved_register (frame, regnum);
-  if (addr != 0)
-    {
-      if (lval != NULL)
-	*lval = lval_memory;
-      if (regnum == SP_REGNUM)
-	{
-	  if (raw_buffer != NULL)
-	    {
-	      /* Put it back in target format.  */
-	      store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), (LONGEST) addr);
-	    }
-	  if (addrp != NULL)
-	    *addrp = 0;
-	  return;
-	}
-      if (raw_buffer != NULL)
-	read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
-    }
-  else if (IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
-    {
-      /* r32 - r127 must be fetchable via memory.  If they aren't,
-         then the register is unavailable */
-      addr = 0;
-      if (lval != NULL)
-	*lval = not_lval;
-      memset (raw_buffer, 0, REGISTER_RAW_SIZE (regnum));
-    }
-  else if (regnum == IA64_IP_REGNUM)
-    {
-      CORE_ADDR pc;
-      if (frame->next)
-        {
-	  /* This case will normally be handled above, except when it's
-	     frameless or we haven't advanced far enough into the prologue
-	     of the top frame to save the register. */
-	  addr = REGISTER_BYTE (regnum);
-	  if (lval != NULL)
-	    *lval = lval_register;
-	  pc = ia64_saved_pc_after_call (frame);
-        }
-      else
-        {
-	  addr = 0;
-	  if (lval != NULL)
-	    *lval = not_lval;
-	  pc = read_pc ();
-	}
-      store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_IP_REGNUM), pc);
-    }
-  else if (regnum == SP_REGNUM && frame->next)
+
+  if (addrp != NULL)
+    *addrp = 0;
+
+  if (lval != NULL)
+    *lval = not_lval;
+
+  is_dummy_frame = PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame);
+
+  if (regnum == SP_REGNUM && frame->next)
     {
       /* Handle SP values for all frames but the topmost. */
-      addr = 0;
-      if (lval != NULL)
-        *lval = not_lval;
       store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->frame);
     }
   else if (regnum == IA64_BSP_REGNUM)
     {
-      addr = 0;
-      if (lval != NULL)
-        *lval = not_lval;
       store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), 
                      frame->extra_info->bsp);
     }
@@ -1050,9 +1064,6 @@ ia64_get_saved_register (char *raw_buffe
 	 above.  If the function lacks one of these frame pointers, we can
 	 still provide a value since we know the size of the frame */
       CORE_ADDR vfp = frame->frame + frame->extra_info->mem_stack_frame_size;
-      addr = 0;
-      if (lval != NULL)
-	*lval = not_lval;
       store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_VFP_REGNUM), vfp);
     }
   else if (IA64_PR0_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
@@ -1067,9 +1078,6 @@ ia64_get_saved_register (char *raw_buffe
       prN_val = extract_bit_field ((unsigned char *) pr_raw_buffer,
                                    regnum - IA64_PR0_REGNUM, 1);
       store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), prN_val);
-      addr = 0;
-      if (lval != NULL)
-	*lval = not_lval;
     }
   else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
     {
@@ -1084,18 +1092,20 @@ ia64_get_saved_register (char *raw_buffe
                                    regnum - IA64_NAT0_REGNUM, 1);
       store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), 
                               unatN_val);
-      addr = 0;
-      if (lval != NULL)
-	*lval = not_lval;
     }
   else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
     {
       int natval = 0;
       /* Find address of general register corresponding to nat bit we're
          interested in. */
-      CORE_ADDR gr_addr = 
-	ia64_find_saved_register (frame, 
-	                          regnum - IA64_NAT0_REGNUM + IA64_GR0_REGNUM);
+      CORE_ADDR gr_addr = 0;
+
+      if (!is_dummy_frame)
+	{
+	  FRAME_INIT_SAVED_REGS (frame);
+	  gr_addr = frame->saved_regs[ regnum - IA64_NAT0_REGNUM 
+	                                      + IA64_GR0_REGNUM];
+	}
       if (gr_addr)
 	{
 	  /* Compute address of nat collection bits */
@@ -1114,20 +1124,50 @@ ia64_get_saved_register (char *raw_buffe
 	  natval = (nat_collection >> nat_bit) & 1;
 	}
       store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), natval);
-      addr = 0;
-      if (lval != NULL)
-	*lval = not_lval;
     }
+  else if (regnum == IA64_IP_REGNUM)
+    {
+      CORE_ADDR pc;
+      if (frame->next)
+        {
+	  /* FIXME: Set *addrp, *lval when possible. */
+	  pc = ia64_frame_saved_pc (frame->next);
+        }
+      else
+        {
+	  pc = read_pc ();
+	}
+      store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_IP_REGNUM), pc);
+    }
+  else if (IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
+    {
+      CORE_ADDR addr = 0;
+      if (!is_dummy_frame)
+	{
+	  FRAME_INIT_SAVED_REGS (frame);
+	  addr = frame->saved_regs[regnum];
+	}
+
+      if (addr != 0)
+	{
+	  if (lval != NULL)
+	    *lval = lval_memory;
+	  if (addrp != NULL)
+	    *addrp = addr;
+	  read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+	}
+      else
+        {
+	  /* r32 - r127 must be fetchable via memory.  If they aren't,
+	     then the register is unavailable */
+	  memset (raw_buffer, 0, REGISTER_RAW_SIZE (regnum));
+        }
+    }
   else
     {
-      if (lval != NULL)
-	*lval = lval_register;
-      addr = REGISTER_BYTE (regnum);
-      if (raw_buffer != NULL)
-	read_register_gen (regnum, raw_buffer);
+      generic_get_saved_register (raw_buffer, optimized, addrp, frame,
+                                  regnum, lval);
     }
-  if (addrp != NULL)
-    *addrp = addr;
 }
 
 /* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
@@ -1230,6 +1270,9 @@ void
 ia64_init_extra_frame_info (int fromleaf, struct frame_info *frame)
 {
   CORE_ADDR bsp, cfm;
+  int next_frame_is_call_dummy = ((frame->next != NULL)
+    && PC_IN_CALL_DUMMY (frame->next->pc, frame->next->frame,
+                                          frame->next->frame));
 
   frame->extra_info = (struct frame_extra_info *)
     frame_obstack_alloc (sizeof (struct frame_extra_info));
@@ -1240,6 +1283,18 @@ ia64_init_extra_frame_info (int fromleaf
       cfm = read_register (IA64_CFM_REGNUM);
 
     }
+  else if (frame->next->signal_handler_caller)
+    {
+      bsp = read_sigcontext_register (frame->next, IA64_BSP_REGNUM);
+      cfm = read_sigcontext_register (frame->next, IA64_CFM_REGNUM);
+    }
+  else if (next_frame_is_call_dummy)
+    {
+      bsp = generic_read_register_dummy (frame->next->pc, frame->next->frame,
+                                         IA64_BSP_REGNUM);
+      cfm = generic_read_register_dummy (frame->next->pc, frame->next->frame,
+                                         IA64_CFM_REGNUM);
+    }
   else
     {
       struct frame_info *frn = frame->next;
@@ -1248,6 +1303,13 @@ ia64_init_extra_frame_info (int fromleaf
 
       if (frn->saved_regs[IA64_CFM_REGNUM] != 0)
 	cfm = read_memory_integer (frn->saved_regs[IA64_CFM_REGNUM], 8);
+      else if (frn->next && frn->next->signal_handler_caller)
+	cfm = read_sigcontext_register (frn->next, IA64_PFS_REGNUM);
+      else if (frn->next
+               && PC_IN_CALL_DUMMY (frn->next->pc, frn->next->frame,
+	                                           frn->next->frame))
+	cfm = generic_read_register_dummy (frn->next->pc, frn->next->frame,
+	                                   IA64_PFS_REGNUM);
       else
 	cfm = read_register (IA64_PFS_REGNUM);
 
@@ -1256,7 +1318,9 @@ ia64_init_extra_frame_info (int fromleaf
   frame->extra_info->cfm = cfm;
   frame->extra_info->sof = cfm & 0x7f;
   frame->extra_info->sol = (cfm >> 7) & 0x7f;
-  if (frame->next == 0)
+  if (frame->next == 0 
+      || frame->next->signal_handler_caller 
+      || next_frame_is_call_dummy)
     frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sof);
   else
     frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sol);
@@ -1719,16 +1783,98 @@ ia64_remote_translate_xfer_address (CORE
   *targ_len  = nr_bytes;
 }
 
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+  int *os_ident_ptr = obj;
+  const char *name;
+  unsigned int sectsize;
+
+  name = bfd_get_section_name (abfd, sect);
+  sectsize = bfd_section_size (abfd, sect);
+  if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+    {
+      unsigned int name_length, data_length, note_type;
+      char *note = alloca (sectsize);
+
+      bfd_get_section_contents (abfd, sect, note,
+                                (file_ptr) 0, (bfd_size_type) sectsize);
+
+      name_length = bfd_h_get_32 (abfd, note);
+      data_length = bfd_h_get_32 (abfd, note + 4);
+      note_type   = bfd_h_get_32 (abfd, note + 8);
+
+      if (name_length == 4 && data_length == 16 && note_type == 1
+          && strcmp (note + 12, "GNU") == 0)
+	{
+	  int os_number = bfd_h_get_32 (abfd, note + 16);
+
+	  /* The case numbers are from abi-tags in glibc */
+	  switch (os_number)
+	    {
+	    case 0 :
+	      *os_ident_ptr = ELFOSABI_LINUX;
+	      break;
+#if 0	/* FIXME: Enable after internal repository is synced with sourceware */
+	    case 1 :
+	      *os_ident_ptr = ELFOSABI_HURD;
+	      break;
+	    case 2 :
+	      *os_ident_ptr = ELFOSABI_SOLARIS;
+	      break;
+#endif
+	    default :
+	      internal_error (
+		"process_note_abi_sections: unknown OS number %d", os_number);
+	      break;
+	    }
+	}
+    }
+}
+
 static struct gdbarch *
 ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int os_ident;
+
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      os_ident = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
 
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
+      /* If os_ident is 0, it is not necessarily the case that we're on a
+         SYSV system.  (ELFOSABI_SYSV is defined to be 0.) GNU/Linux uses
+	 a note section to record OS/ABI info, but leaves e_ident[EI_OSABI]
+	 zero.  So we have to check for note sections too. */
+      if (os_ident == 0)
+	{
+	  bfd_map_over_sections (info.abfd,
+	                         process_note_abi_tag_sections,
+				 &os_ident);
+	}
+    }
+  else
+    os_ident = -1;
+
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (current_gdbarch)->os_ident != os_ident)
+	continue;
+      return arches->gdbarch;
+    }
 
-  gdbarch = gdbarch_alloc (&info, NULL);
+  tdep = xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+  tdep->os_ident = os_ident;
+
+  if (os_ident == ELFOSABI_LINUX)
+    tdep->sigcontext_register_address = ia64_linux_sigcontext_register_address;
+  else
+    tdep->sigcontext_register_address = 0;
 
   set_gdbarch_short_bit (gdbarch, 16);
   set_gdbarch_int_bit (gdbarch, 32);
@@ -1762,7 +1908,7 @@ ia64_gdbarch_init (struct gdbarch_info i
   set_gdbarch_saved_pc_after_call (gdbarch, ia64_saved_pc_after_call);
 
   set_gdbarch_frame_chain (gdbarch, ia64_frame_chain);
-  set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+  set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid);
   set_gdbarch_frame_saved_pc (gdbarch, ia64_frame_saved_pc);
 
   set_gdbarch_frame_init_saved_regs (gdbarch, ia64_frame_init_saved_regs);
Index: config/ia64/linux.mt
===================================================================
RCS file: /cvs/src/src/gdb/config/ia64/linux.mt,v
retrieving revision 1.1
diff -u -p -r1.1 linux.mt
--- linux.mt	2000/03/21 00:11:10	1.1
+++ linux.mt	2000/04/25 06:07:46
@@ -1,5 +1,5 @@
 # Target: Intel IA-64 running GNU/Linux
-TDEPFILES= ia64-tdep.o
+TDEPFILES= ia64-tdep.o ia64-linux-tdep.o
 TM_FILE= tm-linux.h
 
 GDBSERVER_DEPFILES= low-linux.o
Index: config/ia64/tm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/ia64/tm-linux.h,v
retrieving revision 1.1
diff -u -p -r1.1 tm-linux.h
--- tm-linux.h	2000/03/21 00:11:10	1.1
+++ tm-linux.h	2000/04/25 06:07:46
@@ -28,4 +28,7 @@
 
 #define TARGET_ELF64
 
+extern int ia64_linux_in_sigtramp (CORE_ADDR pc, char *func_name);
+#define IN_SIGTRAMP(pc,func_name) ia64_linux_in_sigtramp (pc, func_name)
+
 #endif /* #ifndef TM_LINUX_H */


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