2011-09-02 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / ia64-tdep.c
index 05ca3a127ea5373ba53a6bc45f6eb5f2e15b046b..68e50217028351c3560710923fadaea629a33f2e 100644 (file)
@@ -933,11 +933,12 @@ rse_address_add(CORE_ADDR addr, int nslots)
   return new_addr;
 }
 
-static void
+static enum register_status
 ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
                            int regnum, gdb_byte *buf)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum register_status status;
 
   if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
     {
@@ -952,12 +953,21 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
             found sequentially in memory starting at $bof.  This
             isn't always true, but without libunwind, this is the
             best we can do.  */
+         enum register_status status;
          ULONGEST cfm;
          ULONGEST bsp;
          CORE_ADDR reg;
-         regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
-         regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
-         
+
+         status = regcache_cooked_read_unsigned (regcache,
+                                                 IA64_BSP_REGNUM, &bsp);
+         if (status != REG_VALID)
+           return status;
+
+         status = regcache_cooked_read_unsigned (regcache,
+                                                 IA64_CFM_REGNUM, &cfm);
+         if (status != REG_VALID)
+           return status;
+
          /* The bsp points at the end of the register frame so we
             subtract the size of frame from it to get start of
             register frame.  */
@@ -979,7 +989,9 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
     {
       ULONGEST unatN_val;
       ULONGEST unat;
-      regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
+      status = regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
+      if (status != REG_VALID)
+       return status;
       unatN_val = (unat & (1LL << (regnum - IA64_NAT0_REGNUM))) != 0;
       store_unsigned_integer (buf, register_size (gdbarch, regnum),
                              byte_order, unatN_val);
@@ -990,8 +1002,12 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       ULONGEST bsp;
       ULONGEST cfm;
       CORE_ADDR gr_addr = 0;
-      regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
-      regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+      status = regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+      if (status != REG_VALID)
+       return status;
+      status = regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+      if (status != REG_VALID)
+       return status;
 
       /* The bsp points at the end of the register frame so we
         subtract the size of frame from it to get start of register frame.  */
@@ -1028,8 +1044,12 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       ULONGEST bsp, vbsp;
       ULONGEST cfm;
       CORE_ADDR reg;
-      regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
-      regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+      status = regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+      if (status != REG_VALID)
+       return status;
+      status = regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+      if (status != REG_VALID)
+       return status;
 
       /* The bsp points at the end of the register frame so we
         subtract the size of frame from it to get beginning of frame.  */
@@ -1043,8 +1063,12 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       ULONGEST cfm;
       ULONGEST prN_val;
       CORE_ADDR reg;
-      regcache_cooked_read_unsigned (regcache, IA64_PR_REGNUM, &pr);
-      regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+      status = regcache_cooked_read_unsigned (regcache, IA64_PR_REGNUM, &pr);
+      if (status != REG_VALID)
+       return status;
+      status = regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+      if (status != REG_VALID)
+       return status;
 
       if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
        {
@@ -1062,6 +1086,8 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
     }
   else
     memset (buf, 0, register_size (gdbarch, regnum));
+
+  return REG_VALID;
 }
 
 static void
@@ -1132,7 +1158,8 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
             collection from the computed address.  */
          if (nat_addr >= bsp)
            {
-             regcache_cooked_read_unsigned (regcache, IA64_RNAT_REGNUM,
+             regcache_cooked_read_unsigned (regcache,
+                                            IA64_RNAT_REGNUM,
                                             &nat_collection);
              if (natN_val)
                nat_collection |= natN_mask;
@@ -1196,14 +1223,23 @@ ia64_convert_register_p (struct gdbarch *gdbarch, int regno, struct type *type)
          && type != ia64_ext_type (gdbarch));
 }
 
-static void
+static int
 ia64_register_to_value (struct frame_info *frame, int regnum,
-                         struct type *valtype, gdb_byte *out)
+                       struct type *valtype, gdb_byte *out,
+                       int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   char in[MAX_REGISTER_SIZE];
-  frame_register_read (frame, regnum, in);
+
+  /* Convert to TYPE.  */
+  if (!get_frame_register_bytes (frame, regnum, 0,
+                                register_size (gdbarch, regnum),
+                                in, optimizedp, unavailablep))
+    return 0;
+
   convert_typed_floating (in, ia64_ext_type (gdbarch), out, valtype);
+  *optimizedp = *unavailablep = 0;
+  return 1;
 }
 
 static void
@@ -2139,6 +2175,7 @@ ia64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
 static const struct frame_unwind ia64_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   &ia64_frame_this_id,
   &ia64_frame_prev_register,
   NULL,
@@ -2330,6 +2367,7 @@ ia64_sigtramp_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind ia64_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   ia64_sigtramp_frame_this_id,
   ia64_sigtramp_frame_prev_register,
   NULL,
@@ -2452,7 +2490,7 @@ ia64_is_fpreg (int uw_regnum)
 {
   return unw_is_fpreg (uw_regnum);
 }
-  
+
 /* Libunwind callback accessor function for general registers.  */
 static int
 ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val, 
@@ -2490,7 +2528,7 @@ ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
        bsp = extract_unsigned_integer (buf, 8, byte_order);
        get_frame_register (this_frame, IA64_CFM_REGNUM, buf);
        cfm = extract_unsigned_integer (buf, 8, byte_order);
-       sof = (cfm & 0x7f);
+       sof = gdbarch_tdep (gdbarch)->size_of_register_frame (this_frame, cfm);
        *val = ia64_rse_skip_regs (bsp, -sof);
        break;
 
@@ -3015,6 +3053,7 @@ ia64_libunwind_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind ia64_libunwind_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   ia64_libunwind_frame_this_id,
   ia64_libunwind_frame_prev_register,
   NULL,
@@ -3103,6 +3142,7 @@ ia64_libunwind_sigtramp_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   ia64_libunwind_sigtramp_frame_this_id,
   ia64_libunwind_sigtramp_frame_prev_register,
   NULL,
@@ -3420,7 +3460,8 @@ slot_alignment_is_next_even (struct type *t)
    d_un.d_ptr value is the global pointer.  */
 
 static CORE_ADDR
-ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+ia64_find_global_pointer_from_dynamic_section (struct gdbarch *gdbarch,
+                                              CORE_ADDR faddr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   struct obj_section *faddr_sect;
@@ -3478,6 +3519,24 @@ ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
   return 0;
 }
 
+/* Attempt to find (and return) the global pointer for the given
+   function.  We first try the find_global_pointer_from_solib routine
+   from the gdbarch tdep vector, if provided.  And if that does not
+   work, then we try ia64_find_global_pointer_from_dynamic_section.  */
+
+static CORE_ADDR
+ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  CORE_ADDR addr = 0;
+
+  if (tdep->find_global_pointer_from_solib)
+    addr = tdep->find_global_pointer_from_solib (gdbarch, faddr);
+  if (addr == 0)
+    addr = ia64_find_global_pointer_from_dynamic_section (gdbarch, faddr);
+  return addr;
+}
+
 /* Given a function's address, attempt to find (and return) the
    corresponding (canonical) function descriptor.  Return 0 if
    not found.  */
@@ -3617,12 +3676,53 @@ ia64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
   return sp & ~0xfLL;
 }
 
+/* The default "allocate_new_rse_frame" ia64_infcall_ops routine for ia64.  */
+
+static void
+ia64_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp, int sof)
+{
+  ULONGEST cfm, pfs, new_bsp;
+
+  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+  new_bsp = rse_address_add (bsp, sof);
+  regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
+
+  regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
+  pfs &= 0xc000000000000000LL;
+  pfs |= (cfm & 0xffffffffffffLL);
+  regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
+
+  cfm &= 0xc000000000000000LL;
+  cfm |= sof;
+  regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+}
+
+/* The default "store_argument_in_slot" ia64_infcall_ops routine for
+   ia64.  */
+
+static void
+ia64_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
+                            int slotnum, gdb_byte *buf)
+{
+  write_memory (rse_address_add (bsp, slotnum), buf, 8);
+}
+
+/* The default "set_function_addr" ia64_infcall_ops routine for ia64.  */
+
+static void
+ia64_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
+{
+  /* Nothing needed.  */
+}
+
 static CORE_ADDR
 ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr,
                      int nargs, struct value **args, CORE_ADDR sp,
                      int struct_return, CORE_ADDR struct_addr)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argno;
   struct value *arg;
@@ -3630,7 +3730,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   int len, argoffset;
   int nslots, rseslots, memslots, slotnum, nfuncargs;
   int floatreg;
-  ULONGEST bsp, cfm, pfs, new_bsp;
+  ULONGEST bsp;
   CORE_ADDR funcdescaddr, pc, global_pointer;
   CORE_ADDR func_addr = find_function_addr (function, NULL);
 
@@ -3657,20 +3757,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   memslots = nslots - rseslots;
 
   /* Allocate a new RSE frame.  */
-  regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
-
   regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
-  new_bsp = rse_address_add (bsp, rseslots);
-  regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
-
-  regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
-  pfs &= 0xc000000000000000LL;
-  pfs |= (cfm & 0xffffffffffffLL);
-  regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
-
-  cfm &= 0xc000000000000000LL;
-  cfm |= rseslots;
-  regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+  tdep->infcall_ops.allocate_new_rse_frame (regcache, bsp, rseslots);
   
   /* We will attempt to find function descriptors in the .opd segment,
      but if we can't we'll construct them ourselves.  That being the
@@ -3710,7 +3798,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                                  find_func_descr (regcache, faddr,
                                                   &funcdescaddr));
          if (slotnum < rseslots)
-           write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+           tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+                                                     slotnum, val_buf);
          else
            write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
          slotnum++;
@@ -3755,7 +3844,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
             }
 
          if (slotnum < rseslots)
-           write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+           tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+                                                     slotnum, val_buf);
          else
            write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
 
@@ -3796,13 +3886,27 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   if (global_pointer != 0)
     regcache_cooked_write_unsigned (regcache, IA64_GR1_REGNUM, global_pointer);
 
+  /* The following is not necessary on HP-UX, because we're using
+     a dummy code sequence pushed on the stack to make the call, and
+     this sequence doesn't need b0 to be set in order for our dummy
+     breakpoint to be hit.  Nonetheless, this doesn't interfere, and
+     it's needed for other OSes, so we do this unconditionaly.  */
   regcache_cooked_write_unsigned (regcache, IA64_BR0_REGNUM, bp_addr);
 
   regcache_cooked_write_unsigned (regcache, sp_regnum, sp);
 
+  tdep->infcall_ops.set_function_addr (regcache, func_addr);
+
   return sp;
 }
 
+static const struct ia64_infcall_ops ia64_infcall_ops =
+{
+  ia64_allocate_new_rse_frame,
+  ia64_store_argument_in_slot,
+  ia64_set_function_addr
+};
+
 static struct frame_id
 ia64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
@@ -3848,6 +3952,14 @@ ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info)
   return print_insn_ia64 (memaddr, info);
 }
 
+/* The default "size_of_register_frame" gdbarch_tdep routine for ia64.  */
+
+static int
+ia64_size_of_register_frame (struct frame_info *this_frame, ULONGEST cfm)
+{
+  return (cfm & 0x7f);
+}
+
 static struct gdbarch *
 ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
@@ -3862,6 +3974,8 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep = xzalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
 
+  tdep->size_of_register_frame = ia64_size_of_register_frame;
+
   /* According to the ia64 specs, instructions that store long double
      floats in memory use a long-double format different than that
      used in the floating registers.  The memory format matches the
@@ -3912,6 +4026,7 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Settings for calling functions in the inferior.  */
   set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call);
+  tdep->infcall_ops = ia64_infcall_ops;
   set_gdbarch_frame_align (gdbarch, ia64_frame_align);
   set_gdbarch_dummy_id (gdbarch, ia64_dummy_id);
 
This page took 0.026987 seconds and 4 git commands to generate.