]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb/
authorDaniel Jacobowitz <drow@false.org>
Wed, 22 Nov 2006 18:51:58 +0000 (18:51 +0000)
committerDaniel Jacobowitz <drow@false.org>
Wed, 22 Nov 2006 18:51:58 +0000 (18:51 +0000)
* Makefile.in (arm-tdep.o): Update dependencies.
* arm-tdep.c (thumb_skip_prologue): Remove.
(thumb_analyze_prologue): New function.
(arm_skip_prologue): Use thumb_analyze_prologue.
(thumb_scan_prologue): Ditto.
gdb/testsuite/
* gdb.arch/thumb-prologue.c, gdb.arch/thumb-prologue.exp: New files.

gdb/ChangeLog
gdb/Makefile.in
gdb/arm-tdep.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.arch/thumb-prologue.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/thumb-prologue.exp [new file with mode: 0644]

index d818a292e57bce2a455f62958f614d9bb53e37ab..84a5a54a6183ee2719ac3f9057854ea2f410cfb7 100644 (file)
@@ -1,3 +1,11 @@
+2006-11-22  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * Makefile.in (arm-tdep.o): Update dependencies.
+       * arm-tdep.c (thumb_skip_prologue): Remove.
+       (thumb_analyze_prologue): New function.
+       (arm_skip_prologue): Use thumb_analyze_prologue.
+       (thumb_scan_prologue): Ditto.
+
 2006-11-22  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * configure.tgt: Enable gdbserver for SPU target.
index 25a04a21e928790e9918c93c25b808ddc3c87ac0..6ec2d2e82c97828d7b3f1434ddd1492c7d9e9ada 100644 (file)
@@ -1807,7 +1807,7 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \
        $(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(arm_tdep_h) \
        $(gdb_sim_arm_h) $(elf_bfd_h) $(coff_internal_h) $(elf_arm_h) \
        $(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \
-       $(dwarf2_frame_h) $(gdbtypes_h)
+       $(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h)
 auxv.o: auxv.c $(defs_h) $(target_h) $(gdbtypes_h) $(command_h) \
        $(inferior_h) $(valprint_h) $(gdb_assert_h) $(auxv_h) \
        $(elf_common_h)
index eaa089fb3763a9c6c45debebf2f97e79114badcc..f4a6a37f2ddf24594a42b2ea1e3242b774a9a4f4 100644 (file)
@@ -41,6 +41,7 @@
 #include "objfiles.h"
 #include "dwarf2-frame.h"
 #include "gdbtypes.h"
+#include "prologue-value.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
@@ -212,84 +213,156 @@ arm_smash_text_address (CORE_ADDR val)
   return val & ~1;
 }
 
-/* A typical Thumb prologue looks like this:
-   push    {r7, lr}
-   add     sp, sp, #-28
-   add     r7, sp, #12
-   Sometimes the latter instruction may be replaced by:
-   mov     r7, sp
-   
-   or like this:
-   push    {r7, lr}
-   mov     r7, sp
-   sub    sp, #12
-   
-   or, on tpcs, like this:
-   sub     sp,#16
-   push    {r7, lr}
-   (many instructions)
-   mov     r7, sp
-   sub    sp, #12
-
-   There is always one instruction of three classes:
-   1 - push
-   2 - setting of r7
-   3 - adjusting of sp
-   
-   When we have found at least one of each class we are done with the prolog.
-   Note that the "sub sp, #NN" before the push does not count.
-   */
+/* Analyze a Thumb prologue, looking for a recognizable stack frame
+   and frame pointer.  Scan until we encounter a store that could
+   clobber the stack frame unexpectedly, or an unknown instruction.  */
 
 static CORE_ADDR
-thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
+thumb_analyze_prologue (struct gdbarch *gdbarch,
+                       CORE_ADDR start, CORE_ADDR limit,
+                       struct arm_prologue_cache *cache)
 {
-  CORE_ADDR current_pc;
-  /* findmask:
-     bit 0 - push { rlist }
-     bit 1 - mov r7, sp  OR  add r7, sp, #imm  (setting of r7)
-     bit 2 - sub sp, #simm  OR  add sp, #simm  (adjusting of sp)
-  */
-  int findmask = 0;
+  int i;
+  pv_t regs[16];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR offset;
 
-  for (current_pc = pc;
-       current_pc + 2 < func_end && current_pc < pc + 40;
-       current_pc += 2)
+  for (i = 0; i < 16; i++)
+    regs[i] = pv_register (i, 0);
+  stack = make_pv_area (ARM_SP_REGNUM);
+  back_to = make_cleanup_free_pv_area (stack);
+
+  /* The call instruction saved PC in LR, and the current PC is not
+     interesting.  Due to this file's conventions, we want the value
+     of LR at this function's entry, not at the call site, so we do
+     not record the save of the PC - when the ARM prologue analyzer
+     has also been converted to the pv mechanism, we could record the
+     save here and remove the hack in prev_register.  */
+  regs[ARM_PC_REGNUM] = pv_unknown ();
+
+  while (start < limit)
     {
-      unsigned short insn = read_memory_unsigned_integer (current_pc, 2);
+      unsigned short insn;
+
+      insn = read_memory_unsigned_integer (start, 2);
 
       if ((insn & 0xfe00) == 0xb400)           /* push { rlist } */
        {
-         findmask |= 1;                        /* push found */
+         int regno;
+         int mask;
+         int stop = 0;
+
+         /* Bits 0-7 contain a mask for registers R0-R7.  Bit 8 says
+            whether to save LR (R14).  */
+         mask = (insn & 0xff) | ((insn & 0x100) << 6);
+
+         /* Calculate offsets of saved R0-R7 and LR.  */
+         for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
+           if (mask & (1 << regno))
+             {
+               if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+                 {
+                   stop = 1;
+                   break;
+                 }
+
+               regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                      -4);
+               pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
+             }
+
+         if (stop)
+           break;
        }
       else if ((insn & 0xff00) == 0xb000)      /* add sp, #simm  OR  
                                                   sub sp, #simm */
        {
-         if ((findmask & 1) == 0)              /* before push ? */
-           continue;
+         offset = (insn & 0x7f) << 2;          /* get scaled offset */
+         if (insn & 0x80)                      /* Check for SUB.  */
+           regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                  -offset);
          else
-           findmask |= 4;                      /* add/sub sp found */
+           regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                  offset);
        }
       else if ((insn & 0xff00) == 0xaf00)      /* add r7, sp, #imm */
+       regs[THUMB_FP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                (insn & 0xff) << 2);
+      else if ((insn & 0xff00) == 0x4600)      /* mov hi, lo or mov lo, hi */
        {
-         findmask |= 2;                        /* setting of r7 found */
+         int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
+         int src_reg = (insn & 0x78) >> 3;
+         regs[dst_reg] = regs[src_reg];
        }
-      else if (insn == 0x466f)                 /* mov r7, sp */
+      else if ((insn & 0xf800) == 0x9000)      /* str rd, [sp, #off] */
        {
-         findmask |= 2;                        /* setting of r7 found */
+         /* Handle stores to the stack.  Normally pushes are used,
+            but with GCC -mtpcs-frame, there may be other stores
+            in the prologue to create the frame.  */
+         int regno = (insn >> 8) & 0x7;
+         pv_t addr;
+
+         offset = (insn & 0xff) << 2;
+         addr = pv_add_constant (regs[ARM_SP_REGNUM], offset);
+
+         if (pv_area_store_would_trash (stack, addr))
+           break;
+
+         pv_area_store (stack, addr, 4, regs[regno]);
        }
-      else if (findmask == (4+2+1))
+      else
        {
-         /* We have found one of each type of prologue instruction */
+         /* We don't know what this instruction is.  We're finished
+            scanning.  NOTE: Recognizing more safe-to-ignore
+            instructions here will improve support for optimized
+            code.  */
          break;
        }
-      else
-       /* Something in the prolog that we don't care about or some
-          instruction from outside the prolog scheduled here for
-          optimization.  */
-       continue;
+
+      start += 2;
     }
 
-  return current_pc;
+  if (cache == NULL)
+    {
+      do_cleanups (back_to);
+      return start;
+    }
+
+  /* frameoffset is unused for this unwinder.  */
+  cache->frameoffset = 0;
+
+  if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
+    {
+      /* Frame pointer is fp.  Frame size is constant.  */
+      cache->framereg = ARM_FP_REGNUM;
+      cache->framesize = -regs[ARM_FP_REGNUM].k;
+    }
+  else if (pv_is_register (regs[THUMB_FP_REGNUM], ARM_SP_REGNUM))
+    {
+      /* Frame pointer is r7.  Frame size is constant.  */
+      cache->framereg = THUMB_FP_REGNUM;
+      cache->framesize = -regs[THUMB_FP_REGNUM].k;
+    }
+  else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
+    {
+      /* Try the stack pointer... this is a bit desperate.  */
+      cache->framereg = ARM_SP_REGNUM;
+      cache->framesize = -regs[ARM_SP_REGNUM].k;
+    }
+  else
+    {
+      /* We're just out of luck.  We don't know where the frame is.  */
+      cache->framereg = -1;
+      cache->framesize = 0;
+    }
+
+  for (i = 0; i < 16; i++)
+    if (pv_area_find_reg (stack, gdbarch, i, &offset))
+      cache->saved_regs[i].addr = offset;
+
+  do_cleanups (back_to);
+  return start;
 }
 
 /* Advance the PC across any function entry prologue instructions to
@@ -337,10 +410,6 @@ arm_skip_prologue (CORE_ADDR pc)
         }
     }
 
-  /* Check if this is Thumb code.  */
-  if (arm_pc_is_thumb (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.  */
 
@@ -348,6 +417,10 @@ arm_skip_prologue (CORE_ADDR pc)
   if (func_end == 0 || func_end > pc + 64)
     func_end = pc + 64;
 
+  /* Check if this is Thumb code.  */
+  if (arm_pc_is_thumb (pc))
+    return thumb_analyze_prologue (current_gdbarch, pc, func_end, NULL);
+
   for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
     {
       inst = read_memory_unsigned_integer (skip_pc, 4);
@@ -462,86 +535,8 @@ thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
 
   prologue_end = min (prologue_end, prev_pc);
 
-  /* Initialize the saved register map.  When register H is copied to
-     register L, we will put H in saved_reg[L].  */
-  for (i = 0; i < 16; i++)
-    saved_reg[i] = i;
-
-  /* Search the prologue looking for instructions that set up the
-     frame pointer, adjust the stack pointer, and save registers.
-     Do this until all basic prolog instructions are found.  */
-
-  cache->framesize = 0;
-  for (current_pc = prologue_start;
-       (current_pc < prologue_end) && ((findmask & 7) != 7);
-       current_pc += 2)
-    {
-      unsigned short insn;
-      int regno;
-      int offset;
-
-      insn = read_memory_unsigned_integer (current_pc, 2);
-
-      if ((insn & 0xfe00) == 0xb400)   /* push { rlist } */
-       {
-         int mask;
-         findmask |= 1;                /* push found */
-         /* Bits 0-7 contain a mask for registers R0-R7.  Bit 8 says
-            whether to save LR (R14).  */
-         mask = (insn & 0xff) | ((insn & 0x100) << 6);
-
-         /* Calculate offsets of saved R0-R7 and LR.  */
-         for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
-           if (mask & (1 << regno))
-             {
-               cache->framesize += 4;
-               cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
-               /* Reset saved register map.  */
-               saved_reg[regno] = regno;
-             }
-       }
-      else if ((insn & 0xff00) == 0xb000)      /* add sp, #simm  OR  
-                                                  sub sp, #simm */
-       {
-         if ((findmask & 1) == 0)              /* before push?  */
-           continue;
-         else
-           findmask |= 4;                      /* add/sub sp found */
-         
-         offset = (insn & 0x7f) << 2;          /* get scaled offset */
-         if (insn & 0x80)              /* is it signed? (==subtracting) */
-           {
-             cache->frameoffset += offset;
-             offset = -offset;
-           }
-         cache->framesize -= offset;
-       }
-      else if ((insn & 0xff00) == 0xaf00)      /* add r7, sp, #imm */
-       {
-         findmask |= 2;                        /* setting of r7 found */
-         cache->framereg = THUMB_FP_REGNUM;
-         /* get scaled offset */
-         cache->frameoffset = (insn & 0xff) << 2;
-       }
-      else if (insn == 0x466f)                 /* mov r7, sp */
-       {
-         findmask |= 2;                        /* setting of r7 found */
-         cache->framereg = THUMB_FP_REGNUM;
-         cache->frameoffset = 0;
-         saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM;
-       }
-      else if ((insn & 0xffc0) == 0x4640)      /* mov r0-r7, r8-r15 */
-       {
-         int lo_reg = insn & 7;                /* dest.  register (r0-r7) */
-         int hi_reg = ((insn >> 3) & 7) + 8;   /* source register (r8-15) */
-         saved_reg[lo_reg] = hi_reg;           /* remember hi reg was saved */
-       }
-      else
-       /* Something in the prolog that we don't care about or some
-          instruction from outside the prolog scheduled here for
-          optimization.  */ 
-       continue;
-    }
+  thumb_analyze_prologue (current_gdbarch, prologue_start, prologue_end,
+                         cache);
 }
 
 /* This function decodes an ARM function prologue to determine:
index 68b7c95febd9a7f1a9a62f12909e45b711af5b2e..c3836c75e9c7e28a74d5c905b944cf79459fa6d1 100644 (file)
@@ -1,3 +1,7 @@
+2006-11-22  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.arch/thumb-prologue.c, gdb.arch/thumb-prologue.exp: New files.
+
 2006-11-22  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
 
        * gdb.asm/asm-source.exp: Add "spu*-*-*" target.
diff --git a/gdb/testsuite/gdb.arch/thumb-prologue.c b/gdb/testsuite/gdb.arch/thumb-prologue.c
new file mode 100644 (file)
index 0000000..f618963
--- /dev/null
@@ -0,0 +1,96 @@
+/* Unwinder test program.
+
+   Copyright 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+void tpcs_frame (void);
+
+int
+main (void)
+{
+  tpcs_frame ();
+  return 0;
+}
+
+/* Normally Thumb functions use r7 as the frame pointer.  However,
+   with the GCC option -mtpcs-frame, they may use fp instead.  */
+
+asm(".text\n"
+    "  .align 2\n"
+    "  .thumb_func\n"
+    "  .code 16\n"
+    "tpcs_frame_1:\n"
+    "  sub     sp, #16\n"
+    "  push    {r7}\n"
+    "  add     r7, sp, #20\n"
+    "  str     r7, [sp, #8]\n"
+    "  mov     r7, pc\n"
+    "  str     r7, [sp, #16]\n"
+    "  mov     r7, fp\n"
+    "  str     r7, [sp, #4]\n"
+    "  mov     r7, lr\n"
+    "  str     r7, [sp, #12]\n"
+    "  add     r7, sp, #16\n"
+    "  mov     fp, r7\n"
+    "  mov     r7, sl\n"
+    "  push    {r7}\n"
+
+    /* Trap.  */
+    "  .short  0xdffe\n"
+
+    "  pop     {r2}\n"
+    "  mov     sl, r2\n"
+    "  pop     {r7}\n"
+    "  pop     {r1, r2}\n"
+    "  mov     fp, r1\n"
+    "  mov     sp, r2\n"
+    "  bx      lr\n"
+
+    "  .align 2\n"
+    "  .thumb_func\n"
+    "  .code 16\n"
+    "tpcs_frame:\n"
+    "  sub     sp, #16\n"
+    "  push    {r7}\n"
+    "  add     r7, sp, #20\n"
+    "  str     r7, [sp, #8]\n"
+    "  mov     r7, pc\n"
+    "  str     r7, [sp, #16]\n"
+    "  mov     r7, fp\n"
+    "  str     r7, [sp, #4]\n"
+    "  mov     r7, lr\n"
+    "  str     r7, [sp, #12]\n"
+    "  add     r7, sp, #16\n"
+    "  mov     fp, r7\n"
+    "  mov     r7, sl\n"
+    "  push    {r7}\n"
+
+    /* Clobber saved regs.  */
+    "  mov     r7, #0\n"
+    "  mov     lr, r7\n"
+    "  bl      tpcs_frame_1\n"
+
+    "  pop     {r2}\n"
+    "  mov     sl, r2\n"
+    "  pop     {r7}\n"
+    "  pop     {r1, r2}\n"
+    "  mov     fp, r1\n"
+    "  mov     sp, r2\n"
+    "  bx      lr\n"
+);
diff --git a/gdb/testsuite/gdb.arch/thumb-prologue.exp b/gdb/testsuite/gdb.arch/thumb-prologue.exp
new file mode 100644 (file)
index 0000000..1353768
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright 2006 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Test ARM/Thumb prologue analyzer.
+
+if {![istarget arm*-*]} then {
+    verbose "Skipping ARM prologue tests."
+    return
+}
+
+set testfile "thumb-prologue"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+# Don't use "debug", so that we don't have line information for the assembly
+# fragments.
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {"additional_flags=-mthumb"}] != "" } {
+    untested "ARM prologue tests"
+    return -1
+}
+
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+#
+# Run to `main' where we begin our tests.
+#
+
+if ![runto_main] then {
+    untested "ARM prologue tests"
+    return -1
+}
+
+# Testcase for TPCS prologue.
+
+gdb_test "continue" "Program received signal SIG.*" "continue to TPCS"
+
+gdb_test "backtrace 10" \
+       "#0\[ \t\]*$hex in tpcs_frame_1 .*\r\n#1\[ \t\]*$hex in tpcs_frame .*\r\n#2\[ \t\]*$hex in main.*" \
+       "backtrace in TPCS"
+
+gdb_test "info frame" \
+       ".*Saved registers:.*r7 at.*r10 at.*r11 at.*lr at.*pc at .*" \
+       "saved registers in TPCS"