Fix -Werror -Wuninitialized warnings.
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index f10f66121ee77cd813757f078f9cdfd4de79bcd5..a4d16329402a3e4da6f78bab309cdbc8aa36f6d6 100644 (file)
@@ -1,6 +1,6 @@
 /* Common target dependent code for GDB on ARM systems.
-   Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000
-   Free Software Foundation, Inc.
+   Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
+   2001 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "symfile.h"
 #include "gdb_string.h"
 #include "coff/internal.h"     /* Internal format of COFF symbols in BFD */
+#include "dis-asm.h"           /* For register flavors. */
+#include <ctype.h>             /* for isupper () */
+#include "regcache.h"
+
+/* Each OS has a different mechanism for accessing the various
+   registers stored in the sigcontext structure.
+
+   SIGCONTEXT_REGISTER_ADDRESS should be defined to the name (or
+   function pointer) which may be used to determine the addresses
+   of the various saved registers in the sigcontext structure.
+
+   For the ARM target, there are three parameters to this function. 
+   The first is the pc value of the frame under consideration, the
+   second the stack pointer of this frame, and the last is the
+   register number to fetch.  
+
+   If the tm.h file does not define this macro, then it's assumed that
+   no mechanism is needed and we define SIGCONTEXT_REGISTER_ADDRESS to
+   be 0. 
+   
+   When it comes time to multi-arching this code, see the identically
+   named machinery in ia64-tdep.c for an example of how it could be
+   done.  It should not be necessary to modify the code below where
+   this macro is used.  */
+
+#ifdef SIGCONTEXT_REGISTER_ADDRESS
+#ifndef SIGCONTEXT_REGISTER_ADDRESS_P
+#define SIGCONTEXT_REGISTER_ADDRESS_P() 1
+#endif
+#else
+#define SIGCONTEXT_REGISTER_ADDRESS(SP,PC,REG) 0
+#define SIGCONTEXT_REGISTER_ADDRESS_P() 0
+#endif
 
 extern void _initialize_arm_tdep (void);
 
-/*
-   The following macros are actually wrong.  Neither arm nor thumb can
-   or should set the lsb on addr.
-   The thumb addresses are mod 2, so (addr & 2) would be a good heuristic
-   to use when checking for thumb (see arm_pc_is_thumb() below).
-   Unfortunately, something else depends on these (incorrect) macros, so
-   fixing them actually breaks gdb.  I didn't have time to investigate. Z.R.
- */
-/* Thumb function addresses are odd (bit 0 is set).  Here are some
-   macros to test, set, or clear bit 0 of addresses.  */
-#define IS_THUMB_ADDR(addr)    ((addr) & 1)
-#define MAKE_THUMB_ADDR(addr)  ((addr) | 1)
-#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
+/* Number of different reg name sets (options). */
+static int num_flavor_options;
+
+/* We have more registers than the disassembler as gdb can print the value
+   of special registers as well.
+   The general register names are overwritten by whatever is being used by
+   the disassembler at the moment. We also adjust the case of cpsr and fps. */
 
-/* Default register names as specified by APCS.  */
-static char * atpcs_register_names[] =
-{"a1", "a2", "a3", "a4",       /*  0  1  2  3 */
- "v1", "v2", "v3", "v4",       /*  4  5  6  7 */
- "v5", "v6", "v7", "v8",       /*  8  9 10 11 */
- "IP", "SP", "LR", "PC",       /* 12 13 14 15 */
- "f0", "f1", "f2", "f3",       /* 16 17 18 19 */
- "f4", "f5", "f6", "f7",       /* 20 21 22 23 */
- "FPS", "PS" };                /* 24 25       */
-
-/* Alternate set of registers names used by GCC.  */
-static char * additional_register_names[] =
+/* Initial value: Register names used in ARM's ISA documentation. */
+static char * arm_register_name_strings[] =
 {"r0",  "r1",  "r2",  "r3",    /*  0  1  2  3 */
  "r4",  "r5",  "r6",  "r7",    /*  4  5  6  7 */
  "r8",  "r9",  "r10", "r11",   /*  8  9 10 11 */
  "r12", "sp",  "lr",  "pc",    /* 12 13 14 15 */
  "f0",  "f1",  "f2",  "f3",    /* 16 17 18 19 */
  "f4",  "f5",  "f6",  "f7",    /* 20 21 22 23 */
- "fps", "ps" };                /* 24 25       */
+ "fps", "cpsr" };              /* 24 25       */
+char **arm_register_names = arm_register_name_strings;
 
-/* This is the variable that is set with "set disassembly-flavor".
-   By default use the APCS registers names.  */
-char ** arm_register_names = atpcs_register_names;
+/* Valid register name flavors.  */
+static const char **valid_flavors;
 
-/* Valid register name flavours.  */
-static char apcs_flavor[] = "apcs";
-static char r_prefix_flavor[] = "r-prefix";
-static char * valid_flavors[] =
-{
-  apcs_flavor,
-  r_prefix_flavor,
-  NULL
-};
-
-/* Disassembly flavor to use.  */
-static char *disassembly_flavor = apcs_flavor;
+/* Disassembly flavor to use. Default to "std" register names. */
+static const char *disassembly_flavor;
+static int current_option;     /* Index to that option in the opcodes table. */
 
 /* This is used to keep the bfd arch_info in sync with the disassembly
    flavor.  */
@@ -103,6 +111,30 @@ struct frame_extra_info
     int framereg;
   };
 
+/* Addresses for calling Thumb functions have the bit 0 set.
+   Here are some macros to test, set, or clear bit 0 of addresses.  */
+#define IS_THUMB_ADDR(addr)    ((addr) & 1)
+#define MAKE_THUMB_ADDR(addr)  ((addr) | 1)
+#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
+
+#define SWAP_TARGET_AND_HOST(buffer,len)                               \
+  do                                                                   \
+    {                                                                  \
+      if (TARGET_BYTE_ORDER != HOST_BYTE_ORDER)                                \
+       {                                                               \
+         char tmp;                                                     \
+         char *p = (char *)(buffer);                                   \
+         char *q = ((char *)(buffer)) + len - 1;                       \
+         for (; p < q; p++, q--)                                       \
+           {                                                           \
+             tmp = *q;                                                 \
+             *q = *p;                                                  \
+             *p = tmp;                                                 \
+           }                                                           \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
 /* Will a function return an aggregate type in memory or in a
    register?  Return 0 if an aggregate type can be returned in a
    register, 1 if it must be returned in memory.  */
@@ -225,7 +257,7 @@ static int caller_is_thumb;
    function.  */
 
 int
-arm_pc_is_thumb (bfd_vma memaddr)
+arm_pc_is_thumb (CORE_ADDR memaddr)
 {
   struct minimal_symbol *sym;
 
@@ -249,11 +281,18 @@ arm_pc_is_thumb (bfd_vma memaddr)
    dummy being called from a Thumb function.  */
 
 int
-arm_pc_is_thumb_dummy (bfd_vma memaddr)
+arm_pc_is_thumb_dummy (CORE_ADDR memaddr)
 {
   CORE_ADDR sp = read_sp ();
 
-  if (PC_IN_CALL_DUMMY (memaddr, sp, sp + 64))
+  /* FIXME: Until we switch for the new call dummy macros, this heuristic
+     is the best we can do.  We are trying to determine if the pc is on
+     the stack, which (hopefully) will only happen in a call dummy.
+     We hope the current stack pointer is not so far alway from the dummy
+     frame location (true if we have not pushed large data structures or
+     gone too many levels deep) and that our 1024 is not enough to consider
+     code regions as part of the stack (true for most practical purposes) */
+  if (PC_IN_CALL_DUMMY (memaddr, sp, sp + 1024))
     return caller_is_thumb;
   else
     return 0;
@@ -320,7 +359,7 @@ arm_frameless_function_invocation (struct frame_info *fi)
    */
 
 static CORE_ADDR
-thumb_skip_prologue (CORE_ADDR pc)
+thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
 {
   CORE_ADDR current_pc;
   int findmask = 0;    /* findmask:
@@ -329,7 +368,7 @@ thumb_skip_prologue (CORE_ADDR pc)
                           bit 2 - sub sp, #simm  OR  add sp, #simm  (adjusting of sp)
                        */
 
-  for (current_pc = pc; current_pc < pc + 40; current_pc += 2)
+  for (current_pc = pc; current_pc + 2 < func_end && current_pc < pc + 40; current_pc += 2)
     {
       unsigned short insn = read_memory_unsigned_integer (current_pc, 2);
 
@@ -391,7 +430,7 @@ arm_skip_prologue (CORE_ADDR pc)
 
   /* Check if this is Thumb code.  */
   if (arm_pc_is_thumb (pc))
-    return thumb_skip_prologue (pc);
+    return thumb_skip_prologue (pc, func_end);
 
   /* Can't find the prologue end in the symbol table, try it the hard way
      by disassembling the instructions. */
@@ -597,7 +636,7 @@ check_prologue_cache (struct frame_info *fi)
       fi->framereg = prologue_cache.framereg;
       fi->framesize = prologue_cache.framesize;
       fi->frameoffset = prologue_cache.frameoffset;
-      for (i = 0; i <= NUM_REGS; i++)
+      for (i = 0; i < NUM_REGS; i++)
        fi->fsr.regs[i] = prologue_cache.fsr.regs[i];
       return 1;
     }
@@ -618,7 +657,7 @@ save_prologue_cache (struct frame_info *fi)
   prologue_cache.framesize = fi->framesize;
   prologue_cache.frameoffset = fi->frameoffset;
 
-  for (i = 0; i <= NUM_REGS; i++)
+  for (i = 0; i < NUM_REGS; i++)
     prologue_cache.fsr.regs[i] = fi->fsr.regs[i];
 }
 
@@ -717,14 +756,42 @@ arm_scan_prologue (struct frame_info *fi)
      the symbol table, peek in the stack frame to find the PC.  */
   if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end))
     {
-      /* Assume the prologue is everything between the first instruction
-         in the function and the first source line.  */
-      struct symtab_and_line sal = find_pc_line (prologue_start, 0);
-
-      if (sal.line == 0)       /* no line info, use current PC */
-       prologue_end = fi->pc;
-      else if (sal.end < prologue_end) /* next line begins after fn end */
-       prologue_end = sal.end; /* (probably means no prologue)  */
+      /* One way to find the end of the prologue (which works well
+         for unoptimized code) is to do the following:
+
+           struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+
+           if (sal.line == 0)
+             prologue_end = fi->pc;
+           else if (sal.end < prologue_end)
+             prologue_end = sal.end;
+
+        This mechanism is very accurate so long as the optimizer
+        doesn't move any instructions from the function body into the
+        prologue.  If this happens, sal.end will be the last
+        instruction in the first hunk of prologue code just before
+        the first instruction that the scheduler has moved from
+        the body to the prologue.
+
+        In order to make sure that we scan all of the prologue
+        instructions, we use a slightly less accurate mechanism which
+        may scan more than necessary.  To help compensate for this
+        lack of accuracy, the prologue scanning loop below contains
+        several clauses which'll cause the loop to terminate early if
+        an implausible prologue instruction is encountered.  
+        
+        The expression
+        
+             prologue_start + 64
+           
+        is a suitable endpoint since it accounts for the largest
+        possible prologue plus up to five instructions inserted by
+        the scheduler. */
+         
+      if (prologue_end > prologue_start + 64)
+       {
+         prologue_end = prologue_start + 64;   /* See above. */
+       }
     }
   else
     {
@@ -732,10 +799,7 @@ arm_scan_prologue (struct frame_info *fi)
          PC is the address of the stmfd + 8.  */
       prologue_start = ADDR_BITS_REMOVE (read_memory_integer (fi->frame, 4))
        - 8;
-      prologue_end = prologue_start + 64;      /* This is all the insn's
-                                                  that could be in the prologue,
-                                                  plus room for 5 insn's inserted
-                                                  by the scheduler.  */
+      prologue_end = prologue_start + 64;      /* See above. */
     }
 
   /* Now search the prologue looking for instructions that set up the
@@ -825,6 +889,10 @@ arm_scan_prologue (struct frame_info *fi)
                  fi->fsr.regs[fp_start_reg++] = sp_offset;
                }
            }
+         else if ((insn & 0xf0000000) != 0xe0000000)
+           break;      /* Condition not true, exit early */
+         else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */
+           break;      /* Don't scan past a block load */
          else
            /* The optimizer might shove anything into the prologue,
               so we just skip what we don't recognize. */
@@ -965,6 +1033,40 @@ arm_init_extra_frame_info (int fromleaf, struct frame_info *fi)
     }
   else
 #endif
+
+  /* Determine whether or not we're in a sigtramp frame. 
+     Unfortunately, it isn't sufficient to test
+     fi->signal_handler_caller because this value is sometimes set
+     after invoking INIT_EXTRA_FRAME_INFO.  So we test *both*
+     fi->signal_handler_caller and IN_SIGTRAMP to determine if we need
+     to use the sigcontext addresses for the saved registers.
+
+     Note: If an ARM IN_SIGTRAMP method ever needs to compare against
+     the name of the function, the code below will have to be changed
+     to first fetch the name of the function and then pass this name
+     to IN_SIGTRAMP. */
+
+  if (SIGCONTEXT_REGISTER_ADDRESS_P () 
+      && (fi->signal_handler_caller || IN_SIGTRAMP (fi->pc, 0)))
+    {
+      CORE_ADDR sp;
+
+      if (!fi->next)
+       sp = read_sp();
+      else
+       sp = fi->next->frame - fi->next->frameoffset + fi->next->framesize;
+
+      for (reg = 0; reg < NUM_REGS; reg++)
+       fi->fsr.regs[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, fi->pc, reg);
+
+      /* FIXME: What about thumb mode? */
+      fi->framereg = SP_REGNUM;
+      fi->frame = read_memory_integer (fi->fsr.regs[fi->framereg], 4);
+      fi->framesize = 0;
+      fi->frameoffset = 0;
+
+    }
+  else
     {
       arm_scan_prologue (fi);
 
@@ -1227,10 +1329,22 @@ arm_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp,
          calling the function.  */
       if (TYPE_CODE_FLT == typecode && REGISTER_SIZE == len)
        {
-         float f = *(float *) val;
-         dbl_arg = f;
-         val = (char *) &dbl_arg;
+         float f;
+         double d;
+         char * bufo = (char *) &d;
+         char * bufd = (char *) &dbl_arg;
+
          len = sizeof (double);
+         f = *(float *) val;
+         SWAP_TARGET_AND_HOST (&f, sizeof (float));  /* adjust endianess */
+         d = f;
+         /* We must revert the longwords so they get loaded into the
+            the right registers. */
+         memcpy (bufd, bufo + len / 2, len / 2);
+         SWAP_TARGET_AND_HOST (bufd, len / 2);  /* adjust endianess */
+         memcpy (bufd + len / 2, bufo, len / 2);
+         SWAP_TARGET_AND_HOST (bufd + len / 2, len / 2); /* adjust endianess */
+         val = (char *) &dbl_arg;
        }
 #if 1
       /* I don't know why this code was disable. The only logical use
@@ -1279,18 +1393,42 @@ arm_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp,
 void
 arm_pop_frame (void)
 {
-  struct frame_info *frame = get_current_frame ();
   int regnum;
-  CORE_ADDR old_SP;
+  struct frame_info *frame = get_current_frame ();
 
-  old_SP = read_register (frame->framereg);
-  for (regnum = 0; regnum < NUM_REGS; regnum++)
-    if (frame->fsr.regs[regnum] != 0)
-      write_register (regnum,
+  if (!PC_IN_CALL_DUMMY(frame->pc, frame->frame, read_fp()))
+    {
+      CORE_ADDR old_SP;
+
+      old_SP = read_register (frame->framereg);
+      for (regnum = 0; regnum < NUM_REGS; regnum++)
+        if (frame->fsr.regs[regnum] != 0)
+          write_register (regnum,
                      read_memory_integer (frame->fsr.regs[regnum], 4));
 
-  write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
-  write_register (SP_REGNUM, old_SP);
+      write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
+      write_register (SP_REGNUM, old_SP);
+    }
+  else
+    {
+      CORE_ADDR sp;
+
+      sp = read_register (FP_REGNUM);
+      sp -= sizeof(CORE_ADDR); /* we don't care about this first word */
+
+      write_register (PC_REGNUM, read_memory_integer (sp, 4));
+      sp -= sizeof(CORE_ADDR);
+      write_register (SP_REGNUM, read_memory_integer (sp, 4));
+      sp -= sizeof(CORE_ADDR);
+      write_register (FP_REGNUM, read_memory_integer (sp, 4));
+      sp -= sizeof(CORE_ADDR);
+
+      for (regnum = 10; regnum >= 0; regnum--)
+        {
+          write_register (regnum, read_memory_integer (sp, 4));
+          sp -= sizeof(CORE_ADDR);
+        }
+    }
 
   flush_cached_frames ();
 }
@@ -1327,52 +1465,6 @@ arm_float_info (void)
   print_fpu_flags (status);
 }
 
-/* If the disassembly mode is APCS, we have to also switch the
-   bfd mach_type.  This function is run in the set disassembly_flavor
-   command, and does that.  */
-
-static void
-set_disassembly_flavor_sfunc (char *args, int from_tty,
-                             struct cmd_list_element *c)
-{
-  set_disassembly_flavor ();
-}
-
-static void
-set_disassembly_flavor (void)
-{
-  if (disassembly_flavor == apcs_flavor)
-    {
-      parse_arm_disassembler_option ("reg-names-atpcs");
-      arm_register_names = atpcs_register_names;
-    }
-  else if (disassembly_flavor == r_prefix_flavor)
-    {
-      parse_arm_disassembler_option ("reg-names-std");
-      arm_register_names = additional_register_names;
-    }
-}
-
-/* arm_othernames implements the "othernames" command.  This is kind
-   of hacky, and I prefer the set-show disassembly-flavor which is
-   also used for the x86 gdb.  I will keep this around, however, in
-   case anyone is actually using it. */
-
-static void
-arm_othernames (char *names, int n)
-{
-  if (disassembly_flavor == r_prefix_flavor)
-    {
-      disassembly_flavor = apcs_flavor;
-      set_disassembly_flavor ();
-    }
-  else
-    {
-      disassembly_flavor = r_prefix_flavor;
-      set_disassembly_flavor ();
-    }
-}
-
 #if 0
 /* FIXME:  The generated assembler works but sucks.  Instead of using
    r0, r1 it pushes them on the stack, then loads them into r3, r4 and
@@ -1972,29 +2064,123 @@ arm_skip_stub (CORE_ADDR pc)
   return 0;                    /* not a stub */
 }
 
+/* If the user changes the register disassembly flavor used for info register
+   and other commands, we have to also switch the flavor used in opcodes
+   for disassembly output.
+   This function is run in the set disassembly_flavor command, and does that. */
+
+static void
+set_disassembly_flavor_sfunc (char *args, int from_tty,
+                             struct cmd_list_element *c)
+{
+  set_disassembly_flavor ();
+}
+\f
+static void
+set_disassembly_flavor (void)
+{
+  const char *setname, *setdesc, **regnames;
+  int numregs, j;
+
+  /* Find the flavor that the user wants in the opcodes table. */
+  int current = 0;
+  numregs = get_arm_regnames (current, &setname, &setdesc, &regnames);
+  while ((disassembly_flavor != setname)
+        && (current < num_flavor_options))
+    get_arm_regnames (++current, &setname, &setdesc, &regnames);
+  current_option = current;
+
+  /* Fill our copy. */
+  for (j = 0; j < numregs; j++)
+    arm_register_names[j] = (char *) regnames[j];
+
+  /* Adjust case. */
+  if (isupper (*regnames[PC_REGNUM]))
+    {
+      arm_register_names[FPS_REGNUM] = "FPS";
+      arm_register_names[PS_REGNUM] = "CPSR";
+    }
+  else
+    {
+      arm_register_names[FPS_REGNUM] = "fps";
+      arm_register_names[PS_REGNUM] = "cpsr";
+    }
+
+  /* Synchronize the disassembler. */
+  set_arm_regname_option (current);
+}
+
+/* arm_othernames implements the "othernames" command.  This is kind
+   of hacky, and I prefer the set-show disassembly-flavor which is
+   also used for the x86 gdb.  I will keep this around, however, in
+   case anyone is actually using it. */
+
+static void
+arm_othernames (char *names, int n)
+{
+  /* Circle through the various flavors. */
+  current_option = (current_option + 1) % num_flavor_options;
+
+  disassembly_flavor = valid_flavors[current_option];
+  set_disassembly_flavor (); 
+}
+
 void
 _initialize_arm_tdep (void)
 {
+  struct ui_file *stb;
+  long length;
   struct cmd_list_element *new_cmd;
+  const char *setname;
+  const char *setdesc;
+  const char **regnames;
+  int numregs, i, j;
+  static char *helptext;
 
   tm_print_insn = gdb_print_insn_arm;
 
+  /* Get the number of possible sets of register names defined in opcodes. */
+  num_flavor_options = get_arm_regname_num_options ();
+
   /* Sync the opcode insn printer with our register viewer: */
-  parse_arm_disassembler_option ("reg-names-atpcs");
+  parse_arm_disassembler_option ("reg-names-std");
 
-  /* Add the deprecated "othernames" command */
+  /* Begin creating the help text. */
+  stb = mem_fileopen ();
+  fprintf_unfiltered (stb, "Set the disassembly flavor.\n\
+The valid values are:\n");
 
-  add_com ("othernames", class_obscure, arm_othernames,
-          "Switch to the other set of register names.");
+  /* Initialize the array that will be passed to add_set_enum_cmd(). */
+  valid_flavors = xmalloc ((num_flavor_options + 1) * sizeof (char *));
+  for (i = 0; i < num_flavor_options; i++)
+    {
+      numregs = get_arm_regnames (i, &setname, &setdesc, &regnames);
+      valid_flavors[i] = setname;
+      fprintf_unfiltered (stb, "%s - %s\n", setname,
+                         setdesc);
+      /* Copy the default names (if found) and synchronize disassembler. */
+      if (!strcmp (setname, "std"))
+       {
+          disassembly_flavor = setname;
+          current_option = i;
+         for (j = 0; j < numregs; j++)
+            arm_register_names[j] = (char *) regnames[j];
+          set_arm_regname_option (i);
+       }
+    }
+  /* Mark the end of valid options. */
+  valid_flavors[num_flavor_options] = NULL;
 
-  /* Add the disassembly-flavor command */
+  /* Finish the creation of the help text. */
+  fprintf_unfiltered (stb, "The default is \"std\".");
+  helptext = ui_file_xstrdup (stb, &length);
+  ui_file_delete (stb);
 
+  /* Add the disassembly-flavor command */
   new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class,
                              valid_flavors,
-                             (char *) &disassembly_flavor,
-                             "Set the disassembly flavor, \
-the valid values are \"apcs\" and \"r-prefix\", \
-and the default value is \"apcs\".",
+                             &disassembly_flavor,
+                             helptext,
                              &setlist);
   new_cmd->function.sfunc = set_disassembly_flavor_sfunc;
   add_show_from_set (new_cmd, &showlist);
@@ -2005,6 +2191,10 @@ and the default value is \"apcs\".",
                                  "Set usage of ARM 32-bit mode.\n", &setlist),
                     &showlist);
 
+  /* Add the deprecated "othernames" command */
+
+  add_com ("othernames", class_obscure, arm_othernames,
+          "Switch to the next set of register names.");
 }
 
 /* Test whether the coff symbol specific value corresponds to a Thumb
This page took 0.030136 seconds and 4 git commands to generate.