Handle signal handler frames and call dummy frames.
authorKevin Buettner <kevinb@redhat.com>
Tue, 25 Apr 2000 06:36:52 +0000 (06:36 +0000)
committerKevin Buettner <kevinb@redhat.com>
Tue, 25 Apr 2000 06:36:52 +0000 (06:36 +0000)
gdb/ChangeLog
gdb/config/ia64/linux.mt
gdb/config/ia64/tm-linux.h
gdb/ia64-linux-tdep.c [new file with mode: 0644]
gdb/ia64-tdep.c

index 6275eb3..912c19c 100644 (file)
@@ -1,3 +1,29 @@
+2000-04-24  Kevin Buettner  <kevinb@redhat.com>
+
+       * 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.
+
 2000-04-23  Eli Zaretskii  <eliz@is.elta.co.il>
 
        * TODO, NEWS: Update due to inclusion of gdbmi.texinfo in the GDB
index e688b46..8e5b910 100644 (file)
@@ -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 6bae759..79a664f 100644 (file)
@@ -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 */
diff --git a/gdb/ia64-linux-tdep.c b/gdb/ia64-linux-tdep.c
new file mode 100644 (file)
index 0000000..d69dd2a
--- /dev/null
@@ -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 ae35b73..b81f6a0 100644 (file)
@@ -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 from, int len)
 
 /* 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 long val, int from, int len)
 /* 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, int slotnum)
 
 /* 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 nslots)
 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);
-}
+  if (frame->signal_handler_caller && SIGCONTEXT_REGISTER_ADDRESS)
+    {
+      int regno;
 
-static CORE_ADDR
-ia64_find_saved_register (frame, regnum)
-     struct frame_info *frame;
-     int regnum;
-{
-  register CORE_ADDR addr = 0;
+      frame_saved_regs_zalloc (frame);
 
-  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)
-    {
-      FRAME_INIT_SAVED_REGS (frame->next);
-      return frame->next->saved_regs[IA64_VRAP_REGNUM];
+      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_buffer,
                         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_buffer,
         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_buffer,
       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_buffer,
                                    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_buffer,
          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, struct frame_info *frame)
       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, struct frame_info *frame)
 
       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, struct frame_info *frame)
   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_ADDR memaddr, int nr_bytes,
   *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];
+
+      /* 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;
 
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
+  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 info, struct gdbarch_list *arches)
   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);