OSDN Git Service

2000-07-10 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
authorElena Zannoni <ezannoni@kwikemart.cygnus.com>
Mon, 10 Jul 2000 14:43:37 +0000 (14:43 +0000)
committerElena Zannoni <ezannoni@kwikemart.cygnus.com>
Mon, 10 Jul 2000 14:43:37 +0000 (14:43 +0000)
* config/sh/tm-sh.h (STORE_RETURN_VALUE): Redefine as
  sh_store_return_value().
* sh-tdep.c (sh_store_return_value): New function. Store the
  value returned by a function into the appropriate register.

2000-07-10  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>

        * sh-tdep.c (sh_skip_prologue): Before looking at the actual
  instructions, try to see if the symbol table can be of help, by
  calling after_prologue(). If this doesn't work, call
  skip_prologue_hard_way().
(skip_prologue_hard_way): Renamed from sh_skip_prologue. Add some
  more instruction pattern matching for pushing of arguments, and
  manipulation of r14.
(after_prologue): New function. Use symbol table info to determine
  the end of the prologue, if possible.

gdb/ChangeLog
gdb/config/sh/tm-sh.h
gdb/sh-tdep.c

index 435cd2d..72584e0 100644 (file)
@@ -1,3 +1,22 @@
+2000-07-10  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * config/sh/tm-sh.h (STORE_RETURN_VALUE): Redefine as
+       sh_store_return_value().
+       * sh-tdep.c (sh_store_return_value): New function. Store the
+       value returned by a function into the appropriate register.
+
+2000-07-10  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+        * sh-tdep.c (sh_skip_prologue): Before looking at the actual
+       instructions, try to see if the symbol table can be of help, by
+       calling after_prologue(). If this doesn't work, call
+       skip_prologue_hard_way().
+       (skip_prologue_hard_way): Renamed from sh_skip_prologue. Add some
+       more instruction pattern matching for pushing of arguments, and
+       manipulation of r14.
+       (after_prologue): New function. Use symbol table info to determine
+       the end of the prologue, if possible.
+
 2000-07-07  Michael Snyder  <msnyder@cleaver.cygnus.com>
 
        * findvar.c (_initialize_findvar, build_findvar, write_fp, read_fp,
index ca6d9e5..bb03f53 100644 (file)
@@ -181,12 +181,11 @@ extern void sh_extract_return_value (struct type *, void *, void *);
        sh_extract_return_value (TYPE, REGBUF, VALBUF)
 
 /* Write into appropriate registers a function return value
-   of type TYPE, given in virtual format.
-
-   Things always get returned in R0/R1 */
+   of type TYPE, given in virtual format. */
 
+extern void sh_store_return_value (struct type *, void *);
 #define STORE_RETURN_VALUE(TYPE,VALBUF) \
-  write_register_bytes (REGISTER_BYTE(0), VALBUF, TYPE_LENGTH (TYPE))
+  sh_store_return_value (TYPE, VALBUF)
 
 /* Extract from an array REGBUF containing the (raw) register state
    the address in which a function should return its structure value,
index 052fb56..19bfa8e 100644 (file)
@@ -161,19 +161,74 @@ sh_processor_type_table[] =
    [sts.l       pr,@-r15]
    [mov.l       r14,@-r15]
    [mov         r15,r14]
+
+   Actually it can be more complicated than this.  For instance, with
+   newer gcc's:
+
+   mov.l   r14,@-r15
+   add     #-12,r15
+   mov     r15,r14
+   mov     r4,r1
+   mov     r5,r2
+   mov.l   r6,@(4,r14)
+   mov.l   r7,@(8,r14)
+   mov.b   r1,@r14
+   mov     r14,r1
+   mov     r14,r1
+   add     #2,r1
+   mov.w   r2,@r1
+
  */
 
+/* STS.L PR,@-r15  0100111100100010
+   r15-4-->r15, PR-->(r15) */
 #define IS_STS(x)              ((x) == 0x4f22)
+
+/* MOV.L Rm,@-r15  00101111mmmm0110
+   r15-4-->r15, Rm-->(R15) */
 #define IS_PUSH(x)             (((x) & 0xff0f) == 0x2f06)
+
 #define GET_PUSHED_REG(x)      (((x) >> 4) & 0xf)
+
+/* MOV r15,r14     0110111011110011
+   r15-->r14  */
 #define IS_MOV_SP_FP(x)        ((x) == 0x6ef3)
+
+/* ADD #imm,r15    01111111iiiiiiii
+   r15+imm-->r15 */
 #define IS_ADD_SP(x)           (((x) & 0xff00) == 0x7f00)
+
 #define IS_MOV_R3(x)           (((x) & 0xff00) == 0x1a00)
 #define IS_SHLL_R3(x)          ((x) == 0x4300)
+
+/* ADD r3,r15      0011111100111100
+   r15+r3-->r15 */
 #define IS_ADD_R3SP(x)         ((x) == 0x3f3c)
+
+/* FMOV.S FRm,@-Rn  Rn-4-->Rn, FRm-->(Rn)     1111nnnnmmmm1011
+   or
+   FMOV DRm,@-Rn    Rn-8-->Rn, DRm-->(Rn)     1111nnnnmmm01011
+   or
+   FMOV XDm,@-Rn    Rn-8-->Rn, XDm-->(Rn)     1111nnnnmmm11011 */
 #define IS_FMOV(x)             (((x) & 0xf00f) == 0xf00b)
-#define FPSCR_SZ               (1 << 20)
 
+/* MOV Rm,Rn            Rm-->Rn          0110nnnnmmmm0011 
+   or
+   MOV.L Rm,@(disp,Rn)  Rm-->(dispx4+Rn) 0001nnnnmmmmdddd
+   or
+   MOV.L Rm,@Rn         Rm-->(Rn)        0010nnnnmmmm0010
+   where Rm is one of r4,r5,r6,r7 which are the argument registers. */
+#define IS_ARG_MOV(x) \
+(((((x) & 0xf00f) == 0x6003) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070)) \
+|| ((((x) & 0xf000) == 0x1000) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070)) \
+|| ((((x) & 0xf00f) == 0x2002) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070)))
+
+/* MOV.L Rm,@(disp,r14)  00011110mmmmdddd
+   Rm-->(dispx4+r14) where Rm is one of r4,r5,r6,r7 */
+#define IS_MOV_R14(x) \
+((((x) & 0xff00) == 0x1e) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070))
+                        
+#define FPSCR_SZ               (1 << 20)
 
 /* Should call_function allocate stack space for a struct return?  */
 int
@@ -184,14 +239,46 @@ sh_use_struct_convention (gcc_p, type)
   return (TYPE_LENGTH (type) > 1);
 }
 
-
 /* Skip any prologue before the guts of a function */
 
-CORE_ADDR
-sh_skip_prologue (start_pc)
+/* Skip the prologue using the debug information. If this fails we'll
+   fall back on the 'guess' method below. */
+static CORE_ADDR
+after_prologue (pc)
+     CORE_ADDR pc;
+{
+  struct symtab_and_line sal;
+  CORE_ADDR func_addr, func_end;
+
+  /* If we can not find the symbol in the partial symbol table, then
+     there is no hope we can determine the function's start address
+     with this code.  */
+  if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    return 0;
+
+  /* Get the line associated with FUNC_ADDR.  */
+  sal = find_pc_line (func_addr, 0);
+
+  /* There are only two cases to consider.  First, the end of the source line
+     is within the function bounds.  In that case we return the end of the
+     source line.  Second is the end of the source line extends beyond the
+     bounds of the current function.  We need to use the slow code to
+     examine instructions in that case.  */
+  if (sal.end < func_end)
+    return sal.end;
+  else
+    return 0;
+}
+
+/* Here we look at each instruction in the function, and try to guess
+   where the prologue ends. Unfortunately this is not always 
+   accurate. */
+static CORE_ADDR
+skip_prologue_hard_way (start_pc)
      CORE_ADDR start_pc;
 {
   CORE_ADDR here, end;
+  int updated_fp = 0;
 
   if (!start_pc)
     return 0;
@@ -201,19 +288,45 @@ sh_skip_prologue (start_pc)
       int w = read_memory_integer (here, 2);
       here += 2;
       if (IS_FMOV (w) || IS_PUSH (w) || IS_STS (w) || IS_MOV_R3 (w)
-         || IS_ADD_R3SP (w) || IS_ADD_SP (w) || IS_SHLL_R3 (w))
-       start_pc = here;
-
-      if (IS_MOV_SP_FP (w))
+         || IS_ADD_R3SP (w) || IS_ADD_SP (w) || IS_SHLL_R3 (w) 
+         || IS_ARG_MOV (w) || IS_MOV_R14 (w))
        {
          start_pc = here;
-         break;
        }
+      else if (IS_MOV_SP_FP (w))
+       {
+         start_pc = here;
+         updated_fp = 1;
+       }
+      else
+       /* Don't bail out yet, if we are before the copy of sp. */
+       if (updated_fp)
+         break;
     }
 
   return start_pc;
 }
 
+CORE_ADDR
+sh_skip_prologue (pc)
+     CORE_ADDR pc;
+{
+  CORE_ADDR post_prologue_pc;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+
+  post_prologue_pc = after_prologue (pc);
+
+  /* If after_prologue returned a useful address, then use it.  Else
+     fall back on the instruction skipping code. */
+  if (post_prologue_pc != 0)
+    return max (pc, post_prologue_pc);
+  else
+    return (skip_prologue_hard_way (pc));
+}
+
 /* Disassemble an instruction.  */
 
 int
@@ -786,6 +899,29 @@ sh_extract_return_value (type, regbuf, valbuf)
     error ("bad size for return value");
 }
 
+/* If the architecture is sh4 or sh3e, store a function's return value
+   in the R0 general register or in the FP0 floating point register,
+   depending on the type of the return value. In all the other cases
+   the result is stored in r0. */
+void
+sh_store_return_value (struct type *type, void *valbuf)
+{
+  int cpu;
+  if (TARGET_ARCHITECTURE->arch == bfd_arch_sh)
+    cpu = TARGET_ARCHITECTURE->mach;
+  else
+    cpu = 0;
+  if (cpu == bfd_mach_sh3e || cpu == bfd_mach_sh4)
+    {
+      if (TYPE_CODE (type) == TYPE_CODE_FLT) 
+       write_register_bytes (REGISTER_BYTE (FP0_REGNUM), valbuf, TYPE_LENGTH (type));
+      else
+       write_register_bytes (REGISTER_BYTE (0), valbuf, TYPE_LENGTH (type));
+    }
+  else
+    write_register_bytes (REGISTER_BYTE (0), valbuf, TYPE_LENGTH (type));
+}
+
 void
 _initialize_sh_tdep ()
 {