2010-08-30 Yao Qi <yao@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / avr-tdep.c
index 56c3f6356167acf5685cca9555e8633602f5301a..1b9e41139ab91448cdeb3fa2ef9f2ffd5575dc5b 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-dependent code for Atmel AVR, for GDB.
 
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -89,6 +89,10 @@ enum
   AVR_NUM_REGS = 32 + 1 /*SREG*/ + 1 /*SP*/ + 1 /*PC*/,
   AVR_NUM_REG_BYTES = 32 + 1 /*SREG*/ + 2 /*SP*/ + 4 /*PC*/,
 
+  /* Pseudo registers.  */
+  AVR_PSEUDO_PC_REGNUM = 35,
+  AVR_NUM_PSEUDO_REGS = 1,
+
   AVR_PC_REG_INDEX = 35,       /* index into array of registers */
 
   AVR_MAX_PROLOGUE_SIZE = 64,  /* bytes */
@@ -181,6 +185,13 @@ struct gdbarch_tdep
   /* Number of bytes stored to the stack by call instructions.
      2 bytes for avr1-5, 3 bytes for avr6.  */
   int call_length;
+
+  /* Type for void.  */
+  struct type *void_type;
+  /* Type for a function returning void.  */
+  struct type *func_void_type;
+  /* Type for a pointer to a function.  Used for the type of PC.  */
+  struct type *pc_type;
 };
 
 /* Lookup the name of a register given it's number. */
@@ -193,7 +204,8 @@ avr_register_name (struct gdbarch *gdbarch, int regnum)
     "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
-    "SREG", "SP", "PC"
+    "SREG", "SP", "PC2",
+    "pc"
   };
   if (regnum < 0)
     return NULL;
@@ -210,10 +222,11 @@ avr_register_type (struct gdbarch *gdbarch, int reg_nr)
 {
   if (reg_nr == AVR_PC_REGNUM)
     return builtin_type (gdbarch)->builtin_uint32;
+  if (reg_nr == AVR_PSEUDO_PC_REGNUM)
+    return gdbarch_tdep (gdbarch)->pc_type;
   if (reg_nr == AVR_SP_REGNUM)
     return builtin_type (gdbarch)->builtin_data_ptr;
-  else
-    return builtin_type (gdbarch)->builtin_uint8;
+  return builtin_type (gdbarch)->builtin_uint8;
 }
 
 /* Instruction address checks and convertions. */
@@ -317,6 +330,15 @@ avr_pointer_to_address (struct gdbarch *gdbarch,
     return avr_make_saddr (addr);
 }
 
+static CORE_ADDR
+avr_integer_to_address (struct gdbarch *gdbarch,
+                       struct type *type, const gdb_byte *buf)
+{
+  ULONGEST addr = unpack_long (type, buf);
+
+  return avr_make_saddr (addr);
+}
+
 static CORE_ADDR
 avr_read_pc (struct regcache *regcache)
 {
@@ -329,7 +351,43 @@ static void
 avr_write_pc (struct regcache *regcache, CORE_ADDR val)
 {
   regcache_cooked_write_unsigned (regcache, AVR_PC_REGNUM,
-                                 avr_convert_iaddr_to_raw (val));
+                                  avr_convert_iaddr_to_raw (val));
+}
+
+static void
+avr_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+                          int regnum, gdb_byte *buf)
+{
+  ULONGEST val;
+
+  switch (regnum)
+    {
+    case AVR_PSEUDO_PC_REGNUM:
+      regcache_raw_read_unsigned (regcache, AVR_PC_REGNUM, &val);
+      val >>= 1;
+      store_unsigned_integer (buf, 4, gdbarch_byte_order (gdbarch), val);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("invalid regnum"));
+    }
+}
+
+static void
+avr_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
+                           int regnum, const gdb_byte *buf)
+{
+  ULONGEST val;
+
+  switch (regnum)
+    {
+    case AVR_PSEUDO_PC_REGNUM:
+      val = extract_unsigned_integer (buf, 4, gdbarch_byte_order (gdbarch));
+      val <<= 1;
+      regcache_raw_write_unsigned (regcache, AVR_PC_REGNUM, val);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("invalid regnum"));
+    }
 }
 
 /* Function: avr_scan_prologue
@@ -628,7 +686,7 @@ avr_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR pc_beg, CORE_ADDR pc_end,
           info->saved_regs[AVR_SREG_REGNUM].addr = 3;
           info->saved_regs[0].addr = 2;
           info->saved_regs[1].addr = 1;
-          info->size += 3;
+          info->size += 2;
        }
     }
 
@@ -650,9 +708,7 @@ avr_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR pc_beg, CORE_ADDR pc_end,
        break;
     }
 
-  if (vpc >= AVR_MAX_PROLOGUE_SIZE)
-     fprintf_unfiltered (gdb_stderr,
-                         _("Hit end of prologue while scanning pushes\n"));
+  gdb_assert (vpc < AVR_MAX_PROLOGUE_SIZE);
 
   /* Handle static small stack allocation using rcall or push.  */
 
@@ -789,40 +845,39 @@ static CORE_ADDR
 avr_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   CORE_ADDR func_addr, func_end;
-  CORE_ADDR prologue_end = pc;
+  CORE_ADDR post_prologue_pc;
 
   /* See what the symbol table says */
 
-  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
-    {
-      struct symtab_and_line sal;
-      struct avr_unwind_cache info = {0};
-      struct trad_frame_saved_reg saved_regs[AVR_NUM_REGS];
-
-      info.saved_regs = saved_regs;
-
-      /* Need to run the prologue scanner to figure out if the function has a
-         prologue and possibly skip over moving arguments passed via registers
-         to other registers.  */
+  if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    return pc;
 
-      prologue_end = avr_scan_prologue (gdbarch, func_addr, func_end, &info);
+  post_prologue_pc = skip_prologue_using_sal (gdbarch, func_addr);
+  if (post_prologue_pc != 0)
+    return max (pc, post_prologue_pc);
 
-      if (info.prologue_type == AVR_PROLOGUE_NONE)
-        return pc;
-      else
-        {
-          sal = find_pc_line (func_addr, 0);
+  {
+    CORE_ADDR prologue_end = pc;
+    struct avr_unwind_cache info = {0};
+    struct trad_frame_saved_reg saved_regs[AVR_NUM_REGS];
 
-          if (sal.line != 0 && sal.end < func_end)
-            return sal.end;
-        }
-    }
+    info.saved_regs = saved_regs;
+    
+    /* Need to run the prologue scanner to figure out if the function has a
+       prologue and possibly skip over moving arguments passed via registers
+       to other registers.  */
+    
+    prologue_end = avr_scan_prologue (gdbarch, func_addr, func_end, &info);
+    
+    if (info.prologue_type != AVR_PROLOGUE_NONE)
+      return prologue_end;
+  }
 
   /* Either we didn't find the start of this function (nothing we can do),
      or there's no line info, or the line after the prologue is after
      the end of the function (there probably isn't a prologue). */
 
-  return prologue_end;
+  return pc;
 }
 
 /* Not all avr devices support the BREAK insn. Those that don't should treat
@@ -867,7 +922,7 @@ avr_return_value (struct gdbarch *gdbarch, struct type *func_type,
   else if (TYPE_LENGTH (valtype) <= 8)
     lsb_reg = 18;
   else
-    gdb_assert (0);
+    gdb_assert_not_reached ("unexpected type length");
 
   if (writebuf != NULL)
     {
@@ -1028,9 +1083,9 @@ avr_frame_prev_register (struct frame_info *this_frame,
   struct avr_unwind_cache *info
     = avr_frame_unwind_cache (this_frame, this_prologue_cache);
 
-  if (regnum == AVR_PC_REGNUM)
+  if (regnum == AVR_PC_REGNUM || regnum == AVR_PSEUDO_PC_REGNUM)
     {
-      if (trad_frame_addr_p (info->saved_regs, regnum))
+      if (trad_frame_addr_p (info->saved_regs, AVR_PC_REGNUM))
         {
          /* Reading the return PC from the PC register is slightly
             abnormal.  register_size(AVR_PC_REGNUM) says it is 4 bytes,
@@ -1050,14 +1105,18 @@ avr_frame_prev_register (struct frame_info *this_frame,
          struct gdbarch *gdbarch = get_frame_arch (this_frame);
          struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-         read_memory (info->saved_regs[regnum].addr, buf, tdep->call_length);
+         read_memory (info->saved_regs[AVR_PC_REGNUM].addr,
+                       buf, tdep->call_length);
 
          /* Extract the PC read from memory as a big-endian.  */
          pc = 0;
          for (i = 0; i < tdep->call_length; i++)
            pc = (pc << 8) | buf[i];
 
-         return frame_unwind_got_constant (this_frame, regnum, pc << 1);
+          if (regnum == AVR_PC_REGNUM)
+            pc <<= 1;
+
+         return frame_unwind_got_constant (this_frame, regnum, pc);
         }
 
       return frame_unwind_got_optimized (this_frame, regnum);
@@ -1191,10 +1250,14 @@ avr_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   if (struct_return)
     {
-      regcache_cooked_write_unsigned (regcache, regnum--,
-                                      struct_addr & 0xff);
-      regcache_cooked_write_unsigned (regcache, regnum--,
-                                      (struct_addr >> 8) & 0xff);
+      regcache_cooked_write_unsigned
+        (regcache, regnum--, (struct_addr >> 8) & 0xff);
+      regcache_cooked_write_unsigned
+        (regcache, regnum--, struct_addr & 0xff);
+      /* SP being post decremented, we need to reserve one byte so that the
+         return address won't overwrite the result (or vice-versa).  */
+      if (sp == struct_addr)
+        sp--;
     }
 
   for (i = 0; i < nargs; i++)
@@ -1319,6 +1382,14 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   
   tdep->call_length = call_length;
 
+  /* Create a type for PC.  We can't use builtin types here, as they may not
+     be defined.  */
+  tdep->void_type = arch_type (gdbarch, TYPE_CODE_VOID, 1, "void");
+  tdep->func_void_type = make_function_type (tdep->void_type, NULL);
+  tdep->pc_type = arch_type (gdbarch, TYPE_CODE_PTR, 4, NULL);
+  TYPE_TARGET_TYPE (tdep->pc_type) = tdep->func_void_type;
+  TYPE_UNSIGNED (tdep->pc_type) = 1;
+
   set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
   set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT);
   set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
@@ -1345,6 +1416,10 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_register_name (gdbarch, avr_register_name);
   set_gdbarch_register_type (gdbarch, avr_register_type);
 
+  set_gdbarch_num_pseudo_regs (gdbarch, AVR_NUM_PSEUDO_REGS);
+  set_gdbarch_pseudo_register_read (gdbarch, avr_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, avr_pseudo_register_write);
+
   set_gdbarch_return_value (gdbarch, avr_return_value);
   set_gdbarch_print_insn (gdbarch, print_insn_avr);
 
@@ -1354,6 +1429,7 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_address_to_pointer (gdbarch, avr_address_to_pointer);
   set_gdbarch_pointer_to_address (gdbarch, avr_pointer_to_address);
+  set_gdbarch_integer_to_address (gdbarch, avr_integer_to_address);
 
   set_gdbarch_skip_prologue (gdbarch, avr_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
This page took 0.027025 seconds and 4 git commands to generate.