* arm-tdep.c (arm_gdbarch_init): Use gdbarch_num_pseudo_regs
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 9577f0a1e56b76548ab824bbf478d02745e78ae5..3474d1fc0788c4ad4c163d7cf531a666d7c811e0 100644 (file)
@@ -1263,6 +1263,25 @@ static LONGEST arm_call_dummy_words[] =
   0xe1a0e00f, 0xe1a0f004, 0xe7ffdefe
 };
 
+/* Adjust the call_dummy_breakpoint_offset for the bp_call_dummy
+   breakpoint to the proper address in the call dummy, so that
+   `finish' after a stop in a call dummy works.
+
+   FIXME rearnsha 2002-02018: Tweeking current_gdbarch is not an
+   optimal solution, but the call to arm_fix_call_dummy is immediately
+   followed by a call to run_stack_dummy, which is the only function
+   where call_dummy_breakpoint_offset is actually used.  */
+
+
+static void
+arm_set_call_dummy_breakpoint_offset (void)
+{
+  if (caller_is_thumb)
+    set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 4);
+  else
+    set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 8);
+}
+
 /* Fix up the call dummy, based on whether the processor is currently
    in Thumb or ARM mode, and whether the target function is Thumb or
    ARM.  There are three different situations requiring three
@@ -1292,6 +1311,7 @@ arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
 
   /* Set flag indicating whether the current PC is in a Thumb function. */
   caller_is_thumb = arm_pc_is_thumb (read_pc ());
+  arm_set_call_dummy_breakpoint_offset ();
 
   /* If the target function is Thumb, set the low bit of the function
      address.  And if the CPU is currently in ARM mode, patch the
@@ -1326,22 +1346,6 @@ arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
   write_register (4, fun);
 }
 
-/* Return the offset in the call dummy of the instruction that needs
-   to have a breakpoint placed on it.  This is the offset of the 'swi
-   24' instruction, which is no longer actually used, but simply acts
-   as a place-holder now.
-
-   This implements the CALL_DUMMY_BREAK_OFFSET macro.  */
-
-int
-arm_call_dummy_breakpoint_offset (void)
-{
-  if (caller_is_thumb)
-    return 4;
-  else
-    return 8;
-}
-
 /* Note: ScottB
 
    This function does not support passing parameters using the FPA
@@ -2044,6 +2048,56 @@ gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
     return print_insn_little_arm (memaddr, info);
 }
 
+/* The following define instruction sequences that will cause ARM
+   cpu's to take an undefined instruction trap.  These are used to
+   signal a breakpoint to GDB.
+   
+   The newer ARMv4T cpu's are capable of operating in ARM or Thumb
+   modes.  A different instruction is required for each mode.  The ARM
+   cpu's can also be big or little endian.  Thus four different
+   instructions are needed to support all cases.
+   
+   Note: ARMv4 defines several new instructions that will take the
+   undefined instruction trap.  ARM7TDMI is nominally ARMv4T, but does
+   not in fact add the new instructions.  The new undefined
+   instructions in ARMv4 are all instructions that had no defined
+   behaviour in earlier chips.  There is no guarantee that they will
+   raise an exception, but may be treated as NOP's.  In practice, it
+   may only safe to rely on instructions matching:
+   
+   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 
+   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+   C C C C 0 1 1 x x x x x x x x x x x x x x x x x x x x 1 x x x x
+   
+   Even this may only true if the condition predicate is true. The
+   following use a condition predicate of ALWAYS so it is always TRUE.
+   
+   There are other ways of forcing a breakpoint.  GNU/Linux, RISC iX,
+   and NetBSD all use a software interrupt rather than an undefined
+   instruction to force a trap.  This can be handled by by the
+   abi-specific code during establishment of the gdbarch vector.  */
+
+
+/* NOTE rearnsha 2002-02-18: for now we allow a non-multi-arch gdb to
+   override these definitions.  */
+#ifndef ARM_LE_BREAKPOINT
+#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
+#endif
+#ifndef ARM_BE_BREAKPOINT
+#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
+#endif
+#ifndef THUMB_LE_BREAKPOINT
+#define THUMB_LE_BREAKPOINT {0xfe,0xdf}
+#endif
+#ifndef THUMB_BE_BREAKPOINT
+#define THUMB_BE_BREAKPOINT {0xdf,0xfe}
+#endif
+
+static const char arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
+static const char arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
+static const char arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
+static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
+
 /* Determine the type and size of breakpoint to insert at PCPTR.  Uses
    the program counter value to determine whether a 16-bit or 32-bit
    breakpoint should be used.  It returns a pointer to a string of
@@ -2060,37 +2114,18 @@ gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
 unsigned char *
 arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
   if (arm_pc_is_thumb (*pcptr) || arm_pc_is_thumb_dummy (*pcptr))
     {
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
-       {
-         static char thumb_breakpoint[] = THUMB_BE_BREAKPOINT;
-         *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
-         *lenptr = sizeof (thumb_breakpoint);
-         return thumb_breakpoint;
-       }
-      else
-       {
-         static char thumb_breakpoint[] = THUMB_LE_BREAKPOINT;
-         *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
-         *lenptr = sizeof (thumb_breakpoint);
-         return thumb_breakpoint;
-       }
+      *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
+      *lenptr = tdep->thumb_breakpoint_size;
+      return tdep->thumb_breakpoint;
     }
   else
     {
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
-       {
-         static char arm_breakpoint[] = ARM_BE_BREAKPOINT;
-         *lenptr = sizeof (arm_breakpoint);
-         return arm_breakpoint;
-       }
-      else
-       {
-         static char arm_breakpoint[] = ARM_LE_BREAKPOINT;
-         *lenptr = sizeof (arm_breakpoint);
-         return arm_breakpoint;
-       }
+      *lenptr = tdep->arm_breakpoint_size;
+      return tdep->arm_breakpoint;
     }
 }
 
@@ -2104,7 +2139,29 @@ arm_extract_return_value (struct type *type,
                          char *valbuf)
 {
   if (TYPE_CODE_FLT == TYPE_CODE (type))
-    convert_from_extended (&regbuf[REGISTER_BYTE (ARM_F0_REGNUM)], valbuf);
+    {
+      struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+      switch (tdep->fp_model)
+       {
+       case ARM_FLOAT_FPA:
+         convert_from_extended (&regbuf[REGISTER_BYTE (ARM_F0_REGNUM)],
+                                valbuf);
+         break;
+
+       case ARM_FLOAT_SOFT:
+       case ARM_FLOAT_SOFT_VFP:
+         memcpy (valbuf, &regbuf[REGISTER_BYTE (ARM_A1_REGNUM)],
+                 TYPE_LENGTH (type));
+         break;
+
+       default:
+         internal_error
+           (__FILE__, __LINE__,
+            "arm_extract_return_value: Floating point model not supported");
+         break;
+       }
+    }
   else
     memcpy (valbuf, &regbuf[REGISTER_BYTE (ARM_A1_REGNUM)],
            TYPE_LENGTH (type));
@@ -2221,15 +2278,32 @@ arm_store_return_value (struct type *type, char *valbuf)
 {
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
     {
+      struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
       char buf[MAX_REGISTER_RAW_SIZE];
 
-      convert_to_extended (valbuf, buf);
-      /* XXX Is this correct for soft-float?  */
-      write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf,
-                           MAX_REGISTER_RAW_SIZE);
+      switch (tdep->fp_model)
+       {
+       case ARM_FLOAT_FPA:
+
+         convert_to_extended (valbuf, buf);
+         write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf,
+                               MAX_REGISTER_RAW_SIZE);
+         break;
+
+       case ARM_FLOAT_SOFT:
+       case ARM_FLOAT_SOFT_VFP:
+         write_register_bytes (ARM_A1_REGNUM, valbuf, TYPE_LENGTH (type));
+         break;
+
+       default:
+         internal_error
+           (__FILE__, __LINE__,
+            "arm_store_return_value: Floating point model not supported");
+         break;
+       }
     }
   else
-    write_register_bytes (0, valbuf, TYPE_LENGTH (type));
+    write_register_bytes (ARM_A1_REGNUM, valbuf, TYPE_LENGTH (type));
 }
 
 /* Store the address of the place in which to copy the structure the
@@ -2241,6 +2315,23 @@ arm_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
   write_register (ARM_A1_REGNUM, addr);
 }
 
+static int
+arm_get_longjmp_target (CORE_ADDR *pc)
+{
+  CORE_ADDR jb_addr;
+  char buf[INT_REGISTER_RAW_SIZE];
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  
+  jb_addr = read_register (ARM_A1_REGNUM);
+
+  if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
+                         INT_REGISTER_RAW_SIZE))
+    return 0;
+
+  *pc = extract_address (buf, INT_REGISTER_RAW_SIZE);
+  return 1;
+}
+
 /* Return non-zero if the PC is inside a thumb call thunk.  */
 
 int
@@ -2473,7 +2564,7 @@ process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
        {
          int os_number = bfd_h_get_32 (abfd, note + 16);
 
-         /* The case numbers are from abi-tags in glibc */
+         /* The case numbers are from abi-tags in glibc */
          switch (os_number)
            {
            case 0 :
@@ -2531,7 +2622,7 @@ process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
 
 /* Return one of the ELFOSABI_ constants for BFDs representing ELF
    executables.  If it's not an ELF executable or if the OS/ABI couldn't
-   be determined, simply return -1. */
+   be determined, simply return -1.  */
 
 static int
 get_elfosabi (bfd *abfd)
@@ -2547,7 +2638,7 @@ get_elfosabi (bfd *abfd)
      have to check the note sections too.
 
      GNU/ARM tools set the EI_OSABI field to ELFOSABI_ARM, so handle that
-     as well.*/
+     as well.  */
   if (elfosabi == 0 || elfosabi == ELFOSABI_ARM)
     {
       bfd_map_over_sections (abfd,
@@ -2646,7 +2737,7 @@ arm_gdbarch_register_os_abi (enum arm_abi abi,
    during this debugging session.
 
    Called e.g. at program startup, when reading a core file, and when reading
-   a binary file. */
+   a binary file.  */
 
 static struct gdbarch *
 arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
@@ -2686,7 +2777,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        }
     }
 
-  /* Find a candidate among extant architectures. */
+  /* Find a candidate among extant architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
        arches != NULL;
        arches = gdbarch_list_lookup_by_info (arches->next, &info))
@@ -2710,21 +2801,26 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       tdep->abi_name = "<invalid>";
     }
 
-  /* Floating point sizes and format.  */
+  /* This is the way it has always defaulted.  */
+  tdep->fp_model = ARM_FLOAT_FPA;
+
+  /* Breakpoints.  */
   switch (info.byte_order)
     {
     case BFD_ENDIAN_BIG:
-      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
-      set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
-      set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
+      tdep->arm_breakpoint = arm_default_arm_be_breakpoint;
+      tdep->arm_breakpoint_size = sizeof (arm_default_arm_be_breakpoint);
+      tdep->thumb_breakpoint = arm_default_thumb_be_breakpoint;
+      tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_be_breakpoint);
+
       break;
 
     case BFD_ENDIAN_LITTLE:
-      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
-      set_gdbarch_double_format (gdbarch,
-                                &floatformat_ieee_double_littlebyte_bigword);
-      set_gdbarch_long_double_format (gdbarch,
-                                &floatformat_ieee_double_littlebyte_bigword);
+      tdep->arm_breakpoint = arm_default_arm_le_breakpoint;
+      tdep->arm_breakpoint_size = sizeof (arm_default_arm_le_breakpoint);
+      tdep->thumb_breakpoint = arm_default_thumb_le_breakpoint;
+      tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_le_breakpoint);
+
       break;
 
     default:
@@ -2732,19 +2828,28 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                      "arm_gdbarch_init: bad byte order for float format");
     }
 
+  /* On ARM targets char defaults to unsigned.  */
+  set_gdbarch_char_signed (gdbarch, 0);
+
+  /* This should be low enough for everything.  */
   tdep->lowest_pc = 0x20;
+  tdep->jb_pc = -1; /* Longjump support not enabled by default.  */
 
   set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
 
   /* Call dummy code.  */
   set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
   set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+  /* We have to give this a value now, even though we will re-set it 
+     during each call to arm_fix_call_dummy.  */
+  set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 8);
   set_gdbarch_call_dummy_p (gdbarch, 1);
   set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
 
   set_gdbarch_call_dummy_words (gdbarch, arm_call_dummy_words);
   set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (arm_call_dummy_words));
   set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+  set_gdbarch_call_dummy_length (gdbarch, 0);
 
   set_gdbarch_fix_call_dummy (gdbarch, arm_fix_call_dummy);
 
@@ -2752,6 +2857,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
   set_gdbarch_push_arguments (gdbarch, arm_push_arguments);
+  set_gdbarch_coerce_float_to_double (gdbarch,
+                                     standard_coerce_float_to_double);
 
   /* Frame handling.  */
   set_gdbarch_frame_chain_valid (gdbarch, arm_frame_chain_valid);
@@ -2830,9 +2937,12 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Hook in the ABI-specific overrides, if they have been registered.  */
   if (arm_abi == ARM_ABI_UNKNOWN)
     {
-      fprintf_filtered
-       (gdb_stderr, "GDB doesn't recognize the ABI of the inferior.  "
-        "Attempting to continue with the default ARM settings");
+      /* Don't complain about not knowing the ABI variant if we don't 
+        have an inferior.  */
+      if (info.abfd)
+       fprintf_filtered
+         (gdb_stderr, "GDB doesn't recognize the ABI of the inferior.  "
+          "Attempting to continue with the default ARM settings");
     }
   else
     {
@@ -2861,6 +2971,42 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Now we have tuned the configuration, set a few final things,
      based on what the OS ABI has told us.  */
 
+  if (tdep->jb_pc >= 0)
+    set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
+
+  /* Floating point sizes and format.  */
+  switch (info.byte_order)
+    {
+    case BFD_ENDIAN_BIG:
+      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
+      set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
+      set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
+      
+      break;
+
+    case BFD_ENDIAN_LITTLE:
+      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
+      if (tdep->fp_model == ARM_FLOAT_VFP
+         || tdep->fp_model == ARM_FLOAT_SOFT_VFP)
+       {
+         set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
+         set_gdbarch_long_double_format (gdbarch,
+                                         &floatformat_ieee_double_little);
+       }
+      else
+       {
+         set_gdbarch_double_format
+           (gdbarch, &floatformat_ieee_double_littlebyte_bigword);
+         set_gdbarch_long_double_format
+           (gdbarch, &floatformat_ieee_double_littlebyte_bigword);
+       }
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "arm_gdbarch_init: bad byte order for float format");
+    }
+
   /* We can't use SIZEOF_FRAME_SAVED_REGS here, since that still
      references the old architecture vector, not the one we are
      building here.  */
@@ -2869,7 +3015,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   prologue_cache.saved_regs = (CORE_ADDR *)
     xcalloc (1, (sizeof (CORE_ADDR)
-                * (gdbarch_num_regs (gdbarch) + NUM_PSEUDO_REGS)));
+                * (gdbarch_num_regs (gdbarch)
+                   + gdbarch_num_pseudo_regs (gdbarch))));
 
   return gdbarch;
 }
This page took 0.027414 seconds and 4 git commands to generate.