Move the ``set mask-address'' command to remote-mips.c. Disable
[deliverable/binutils-gdb.git] / gdb / ia64-tdep.c
index be3a9009a4d2f2c86dc3d4759c4dff7f3680a608..e220e27b5035660429fcb9050f34540a62a975a9 100644 (file)
 #include "inferior.h"
 #include "symfile.h"           /* for entry_point_address */
 #include "gdbcore.h"
+#include "arch-utils.h"
 #include "floatformat.h"
 
 #include "objfiles.h"
 #include "elf/common.h"                /* for DT_PLTGOT value */
+#include "elf-bfd.h"
 
 typedef enum instruction_type
 {
@@ -63,6 +65,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;
@@ -87,8 +91,8 @@ static gdbarch_push_arguments_ftype ia64_push_arguments;
 static gdbarch_push_return_address_ftype ia64_push_return_address;
 static gdbarch_pop_frame_ftype ia64_pop_frame;
 static gdbarch_saved_pc_after_call_ftype ia64_saved_pc_after_call;
-
 static void ia64_pop_frame_regular (struct frame_info *frame);
+static struct type *is_float_or_hfa_type (struct type *t);
 
 static int ia64_num_regs = 590;
 
@@ -188,23 +192,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 +298,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 +362,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 +412,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,13 +420,13 @@ 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);
 }
 
-static template_encoding_table[32][3] =
+static enum instruction_type template_encoding_table[32][3] =
 {
   { M, I, I },                         /* 00 */
   { M, I, I },                         /* 01 */
@@ -445,7 +487,7 @@ fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr)
   template = extract_bit_field (bundle, 0, 5);
   *it = template_encoding_table[(int)template][slotnum];
 
-  if (slotnum == 2 || slotnum == 1 && *it == L)
+  if (slotnum == 2 || (slotnum == 1 && *it == L))
     addr += 16;
   else
     addr += (slotnum + 1) * SLOT_MULTIPLIER;
@@ -607,23 +649,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 \
@@ -639,7 +696,6 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
 {
   CORE_ADDR next_pc;
   CORE_ADDR last_prologue_pc = pc;
-  int done = 0;
   instruction_type it;
   long long instr;
   int do_fsr_stuff = 0;
@@ -652,6 +708,11 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
   int mem_stack_frame_size = 0;
   int spill_reg   = 0;
   CORE_ADDR spill_addr = 0;
+  char instores[8];
+  char infpstores[8];
+
+  memset (instores, 0, sizeof instores);
+  memset (infpstores, 0, sizeof infpstores);
 
   if (frame && !frame->saved_regs)
     {
@@ -694,7 +755,13 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
       if (next_pc == 0)
        break;
 
-      if (it == I && ((instr & 0x1eff8000000LL) == 0x00188000000LL))
+      if (it == B || ((instr & 0x3fLL) != 0LL))
+       {
+         /* Exit loop upon hitting a branch instruction or a predicated
+            instruction. */
+         break;
+       }
+      else if (it == I && ((instr & 0x1eff8000000LL) == 0x00188000000LL))
         {
          /* Move from BR */
          int b2 = (int) ((instr & 0x0000000e000LL) >> 13);
@@ -844,6 +911,48 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
                spill_addr = 0;         /* must be done spilling */
              last_prologue_pc = next_pc;
            }
+         else if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
+           {
+             /* Allow up to one store of each input register. */
+             instores[rM-32] = 1;
+             last_prologue_pc = next_pc;
+           }
+       }
+      else if (it == M && ((instr & 0x1ff08000000LL) == 0x08c00000000LL))
+       {
+         /* One of
+              st1 [rN] = rM
+              st2 [rN] = rM
+              st4 [rN] = rM
+              st8 [rN] = rM
+            Note that the st8 case is handled in the clause above.
+            
+            Advance over stores of input registers. One store per input
+            register is permitted. */
+         int rM = (int) ((instr & 0x000000fe000LL) >> 13);
+         int qp = (int) (instr & 0x0000000003fLL);
+         if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
+           {
+             instores[rM-32] = 1;
+             last_prologue_pc = next_pc;
+           }
+       }
+      else if (it == M && ((instr & 0x1ff88000000LL) == 0x0cc80000000LL))
+        {
+         /* Either
+              stfs [rN] = fM
+            or
+              stfd [rN] = fM
+
+            Advance over stores of floating point input registers.  Again
+            one store per register is permitted */
+         int fM = (int) ((instr & 0x000000fe000LL) >> 13);
+         int qp = (int) (instr & 0x0000000003fLL);
+         if (qp == 0 && 8 <= fM && fM < 16 && !infpstores[fM - 8])
+           {
+             infpstores[fM-8] = 1;
+             last_prologue_pc = next_pc;
+           }
        }
       else if (it == M
             && (   ((instr & 0x1ffc8000000LL) == 0x08ec0000000LL)
@@ -870,8 +979,6 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
              last_prologue_pc = next_pc;
            }
        }
-      else if (it == B || ((instr & 0x3fLL) != 0LL))
-       break;
 
       pc = next_pc;
     }
@@ -917,50 +1024,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
@@ -971,76 +1083,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);
     }
@@ -1051,9 +1116,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)
@@ -1068,9 +1130,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)
     {
@@ -1085,18 +1144,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 */
@@ -1115,20 +1176,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
@@ -1137,20 +1228,45 @@ ia64_get_saved_register (char *raw_buffer,
 int
 ia64_use_struct_convention (int gcc_p, struct type *type)
 {
-  /* FIXME: Need to check for HFAs; structures containing (only) up to 8
-     floating point values of the same size are returned in floating point
-     registers. */
+  struct type *float_elt_type;
+
+  /* HFAs are structures (or arrays) consisting entirely of floating
+     point values of the same length.  Up to 8 of these are returned
+     in registers.  Don't use the struct convention when this is the
+     case. */
+  float_elt_type = is_float_or_hfa_type (type);
+  if (float_elt_type != NULL
+      && TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type) <= 8)
+    return 0;
+
+  /* Other structs of length 32 or less are returned in r8-r11.
+     Don't use the struct convention for those either. */
   return TYPE_LENGTH (type) > 32;
 }
 
 void
 ia64_extract_return_value (struct type *type, char *regbuf, char *valbuf)
 {
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    ia64_register_convert_to_virtual (IA64_FR8_REGNUM, type,
-      &regbuf[REGISTER_BYTE (IA64_FR8_REGNUM)], valbuf);
+  struct type *float_elt_type;
+
+  float_elt_type = is_float_or_hfa_type (type);
+  if (float_elt_type != NULL)
+    {
+      int offset = 0;
+      int regnum = IA64_FR8_REGNUM;
+      int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type);
+
+      while (n-- > 0)
+       {
+         ia64_register_convert_to_virtual (regnum, float_elt_type,
+           &regbuf[REGISTER_BYTE (regnum)], valbuf + offset);
+         offset += TYPE_LENGTH (float_elt_type);
+         regnum++;
+       }
+    }
   else
-    memcpy (valbuf, &regbuf[REGISTER_BYTE (IA64_GR8_REGNUM)], TYPE_LENGTH (type));
+    memcpy (valbuf, &regbuf[REGISTER_BYTE (IA64_GR8_REGNUM)],
+           TYPE_LENGTH (type));
 }
 
 /* FIXME: Turn this into a stack of some sort.  Unfortunately, something
@@ -1206,6 +1322,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));
@@ -1216,24 +1335,44 @@ 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;
-      CORE_ADDR cfm_addr;
 
       FRAME_INIT_SAVED_REGS (frn);
 
       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_CFM_REGNUM);
+       cfm = read_register (IA64_PFS_REGNUM);
 
       bsp = frn->extra_info->bsp;
     }
   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);
@@ -1243,7 +1382,197 @@ ia64_init_extra_frame_info (int fromleaf, struct frame_info *frame)
   frame->extra_info->fp_reg = 0;
 }
 
-#define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
+static int
+is_float_or_hfa_type_recurse (struct type *t, struct type **etp)
+{
+  switch (TYPE_CODE (t))
+    {
+    case TYPE_CODE_FLT:
+      if (*etp)
+       return TYPE_LENGTH (*etp) == TYPE_LENGTH (t);
+      else
+       {
+         *etp = t;
+         return 1;
+       }
+      break;
+    case TYPE_CODE_ARRAY:
+      return is_float_or_hfa_type_recurse (TYPE_TARGET_TYPE (t), etp);
+      break;
+    case TYPE_CODE_STRUCT:
+      {
+       int i;
+
+       for (i = 0; i < TYPE_NFIELDS (t); i++)
+         if (!is_float_or_hfa_type_recurse (TYPE_FIELD_TYPE (t, i), etp))
+           return 0;
+       return 1;
+      }
+      break;
+    default:
+      return 0;
+      break;
+    }
+}
+
+/* Determine if the given type is one of the floating point types or
+   and HFA (which is a struct, array, or combination thereof whose
+   bottom-most elements are all of the same floating point type.) */
+
+static struct type *
+is_float_or_hfa_type (struct type *t)
+{
+  struct type *et = 0;
+
+  return is_float_or_hfa_type_recurse (t, &et) ? et : 0;
+}
+
+
+/* Attempt to find (and return) the global pointer for the given
+   function.
+
+   This is a rather nasty bit of code searchs for the .dynamic section
+   in the objfile corresponding to the pc of the function we're trying
+   to call.  Once it finds the addresses at which the .dynamic section
+   lives in the child process, it scans the Elf64_Dyn entries for a
+   DT_PLTGOT tag.  If it finds one of these, the corresponding
+   d_un.d_ptr value is the global pointer.  */
+
+static CORE_ADDR
+find_global_pointer (CORE_ADDR faddr)
+{
+  struct obj_section *faddr_sect;
+     
+  faddr_sect = find_pc_section (faddr);
+  if (faddr_sect != NULL)
+    {
+      struct obj_section *osect;
+
+      ALL_OBJFILE_OSECTIONS (faddr_sect->objfile, osect)
+       {
+         if (strcmp (osect->the_bfd_section->name, ".dynamic") == 0)
+           break;
+       }
+
+      if (osect < faddr_sect->objfile->sections_end)
+       {
+         CORE_ADDR addr;
+
+         addr = osect->addr;
+         while (addr < osect->endaddr)
+           {
+             int status;
+             LONGEST tag;
+             char buf[8];
+
+             status = target_read_memory (addr, buf, sizeof (buf));
+             if (status != 0)
+               break;
+             tag = extract_signed_integer (buf, sizeof (buf));
+
+             if (tag == DT_PLTGOT)
+               {
+                 CORE_ADDR global_pointer;
+
+                 status = target_read_memory (addr + 8, buf, sizeof (buf));
+                 if (status != 0)
+                   break;
+                 global_pointer = extract_address (buf, sizeof (buf));
+
+                 /* The payoff... */
+                 return global_pointer;
+               }
+
+             if (tag == DT_NULL)
+               break;
+
+             addr += 16;
+           }
+       }
+    }
+  return 0;
+}
+
+/* Given a function's address, attempt to find (and return) the
+   corresponding (canonical) function descriptor.  Return 0 if
+   not found. */
+static CORE_ADDR
+find_extant_func_descr (CORE_ADDR faddr)
+{
+  struct obj_section *faddr_sect;
+
+  /* Return early if faddr is already a function descriptor */
+  faddr_sect = find_pc_section (faddr);
+  if (faddr_sect && strcmp (faddr_sect->the_bfd_section->name, ".opd") == 0)
+    return faddr;
+
+  if (faddr_sect != NULL)
+    {
+      struct obj_section *osect;
+      ALL_OBJFILE_OSECTIONS (faddr_sect->objfile, osect)
+       {
+         if (strcmp (osect->the_bfd_section->name, ".opd") == 0)
+           break;
+       }
+
+      if (osect < faddr_sect->objfile->sections_end)
+       {
+         CORE_ADDR addr;
+
+         addr = osect->addr;
+         while (addr < osect->endaddr)
+           {
+             int status;
+             LONGEST faddr2;
+             char buf[8];
+
+             status = target_read_memory (addr, buf, sizeof (buf));
+             if (status != 0)
+               break;
+             faddr2 = extract_signed_integer (buf, sizeof (buf));
+
+             if (faddr == faddr2)
+               return addr;
+
+             addr += 16;
+           }
+       }
+    }
+  return 0;
+}
+
+/* Attempt to find a function descriptor corresponding to the
+   given address.  If none is found, construct one on the
+   stack using the address at fdaptr */
+
+static CORE_ADDR
+find_func_descr (CORE_ADDR faddr, CORE_ADDR *fdaptr)
+{
+  CORE_ADDR fdesc;
+
+  fdesc = find_extant_func_descr (faddr);
+
+  if (fdesc == 0)
+    {
+      CORE_ADDR global_pointer;
+      char buf[16];
+
+      fdesc = *fdaptr;
+      *fdaptr += 16;
+
+      global_pointer = find_global_pointer (faddr);
+
+      if (global_pointer == 0)
+       global_pointer = read_register (IA64_GR1_REGNUM);
+
+      store_address (buf, 8, faddr);
+      store_address (buf + 8, 8, global_pointer);
+
+      write_memory (fdesc, buf, 16);
+    }
+
+  return fdesc; 
+}
 
 CORE_ADDR
 ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
@@ -1253,11 +1582,12 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
   value_ptr arg;
   struct type *type;
   int len, argoffset;
-  int nslots, rseslots, memslots, slotnum;
+  int nslots, rseslots, memslots, slotnum, nfuncargs;
   int floatreg;
-  CORE_ADDR bsp, cfm, pfs, new_bsp;
+  CORE_ADDR bsp, cfm, pfs, new_bsp, funcdescaddr;
 
   nslots = 0;
+  nfuncargs = 0;
   /* Count the number of slots needed for the arguments */
   for (argno = 0; argno < nargs; argno++)
     {
@@ -1270,12 +1600,17 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
       if (len > 8 && (nslots & 1))
        nslots++;
 
+      if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+       nfuncargs++;
+
       nslots += (len + 7) / 8;
     }
 
+  /* Divvy up the slots between the RSE and the memory stack */
   rseslots = (nslots > 8) ? 8 : nslots;
   memslots = nslots - rseslots;
 
+  /* Allocate a new RSE frame */
   cfm = read_register (IA64_CFM_REGNUM);
 
   bsp = read_register (IA64_BSP_REGNUM);
@@ -1292,18 +1627,51 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
   cfm |= rseslots;
   write_register (IA64_CFM_REGNUM, cfm);
   
-
-  
-  sp = sp - 16 - memslots * 8;
+  /* We will attempt to find function descriptors in the .opd segment,
+     but if we can't we'll construct them ourselves.  That being the
+     case, we'll need to reserve space on the stack for them. */
+  funcdescaddr = sp - nfuncargs * 16;
+  funcdescaddr &= ~0xfLL;
+
+  /* Adjust the stack pointer to it's new value.  The calling conventions
+     require us to have 16 bytes of scratch, plus whatever space is
+     necessary for the memory slots and our function descriptors */
+  sp = sp - 16 - (memslots + nfuncargs) * 8;
   sp &= ~0xfLL;                                /* Maintain 16 byte alignment */
 
+  /* Place the arguments where they belong.  The arguments will be
+     either placed in the RSE backing store or on the memory stack.
+     In addition, floating point arguments or HFAs are placed in
+     floating point registers. */
   slotnum = 0;
   floatreg = IA64_FR8_REGNUM;
   for (argno = 0; argno < nargs; argno++)
     {
+      struct type *float_elt_type;
+
       arg = args[argno];
       type = check_typedef (VALUE_TYPE (arg));
       len = TYPE_LENGTH (type);
+
+      /* Special handling for function parameters */
+      if (len == 8 
+          && TYPE_CODE (type) == TYPE_CODE_PTR 
+         && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
+       {
+         char val_buf[8];
+
+         store_address (val_buf, 8,
+           find_func_descr (extract_address (VALUE_CONTENTS (arg), 8),
+                            &funcdescaddr));
+         if (slotnum < rseslots)
+           write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+         else
+           write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
+         slotnum++;
+         continue;
+       }
+
+      /* Normal slots */
       if (len > 8 && (slotnum & 1))
        slotnum++;
       argoffset = 0;
@@ -1323,14 +1691,28 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
          len -= 8;
          slotnum++;
        }
-      if (TYPE_CODE (type) == TYPE_CODE_FLT && floatreg < IA64_FR16_REGNUM)
-        {
-         ia64_register_convert_to_raw (type, floatreg, VALUE_CONTENTS (arg),
-           &registers[REGISTER_BYTE (floatreg)]);
-         floatreg++;
+
+      /* Handle floating point types (including HFAs) */
+      float_elt_type = is_float_or_hfa_type (type);
+      if (float_elt_type != NULL)
+       {
+         argoffset = 0;
+         len = TYPE_LENGTH (type);
+         while (len > 0 && floatreg < IA64_FR16_REGNUM)
+           {
+             ia64_register_convert_to_raw (
+               float_elt_type,
+               floatreg,
+               VALUE_CONTENTS (arg) + argoffset,
+               &registers[REGISTER_BYTE (floatreg)]);
+             floatreg++;
+             argoffset += TYPE_LENGTH (float_elt_type);
+             len -= TYPE_LENGTH (float_elt_type);
+           }
        }
     }
 
+  /* Store the struct return value in r8 if necessary. */
   if (struct_return)
     {
       store_address (&registers[REGISTER_BYTE (IA64_GR8_REGNUM)],
@@ -1338,7 +1720,7 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
                     struct_addr);
     }
 
-
+  /* Sync gdb's idea of what the registers are with the target. */
   target_store_registers (-1);
 
   /* FIXME: This doesn't belong here!  Instead, SAVE_DUMMY_FRAME_TOS needs
@@ -1359,64 +1741,10 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
 CORE_ADDR
 ia64_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
 {
-  struct partial_symtab *pst;
-
-  /* Attempt to determine and set global pointer (r1) for this pc.
-     
-     This rather nasty bit of code searchs for the .dynamic section
-     in the objfile corresponding to the pc of the function we're
-     trying to call.  Once it finds the addresses at which the .dynamic
-     section lives in the child process, it scans the Elf64_Dyn entries
-     for a DT_PLTGOT tag.  If it finds one of these, the corresponding
-     d_un.d_ptr value is the global pointer. */
-  pst = find_pc_psymtab (pc);
-  if (pst != NULL)
-    {
-      struct obj_section *osect;
-
-      ALL_OBJFILE_OSECTIONS (pst->objfile, osect)
-       {
-         if (strcmp (osect->the_bfd_section->name, ".dynamic") == 0)
-           break;
-       }
-
-      if (osect < pst->objfile->sections_end)
-       {
-         CORE_ADDR addr;
-
-         addr = osect->addr;
-         while (addr < osect->endaddr)
-           {
-             int status;
-             LONGEST tag;
-             char buf[8];
-
-             status = target_read_memory (addr, buf, sizeof (buf));
-             if (status != 0)
-               break;
-             tag = extract_signed_integer (buf, sizeof (buf));
-
-             if (tag == DT_PLTGOT)
-               {
-                 CORE_ADDR global_pointer;
-
-                 status = target_read_memory (addr + 8, buf, sizeof (buf));
-                 if (status != 0)
-                   break;
-                 global_pointer = extract_address (buf, sizeof (buf));
-
-                 /* The payoff... */
-                 write_register (IA64_GR1_REGNUM, global_pointer);
-                 break;
-               }
-
-             if (tag == DT_NULL)
-               break;
+  CORE_ADDR global_pointer = find_global_pointer (pc);
 
-             addr += 16;
-           }
-       }
-    }
+  if (global_pointer != 0)
+    write_register (IA64_GR1_REGNUM, global_pointer);
 
   write_register (IA64_BR0_REGNUM, CALL_DUMMY_ADDRESS ());
   return sp;
@@ -1507,16 +1835,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;
 
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      os_ident = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
 
-  gdbarch = gdbarch_alloc (&info, NULL);
+      /* If os_ident is 0, it is not necessarily the case that we're on a
+         SYSV system.  (ELFOSABI_NONE 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;
+    }
+
+  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);
@@ -1550,7 +1960,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);
This page took 0.036942 seconds and 4 git commands to generate.