/* Target-dependent code for Atmel AVR, for GDB.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007 Free Software Foundation, Inc.
+ 2006, 2007, 2008 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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Contributed by Theodore A. Roth, troth@openavr.org */
/* Lookup the name of a register given it's number. */
static const char *
-avr_register_name (int regnum)
+avr_register_name (struct gdbarch *gdbarch, int regnum)
{
static char *register_names[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
}
static CORE_ADDR
-avr_read_pc (ptid_t ptid)
+avr_read_pc (struct regcache *regcache)
{
- ptid_t save_ptid;
ULONGEST pc;
- CORE_ADDR retval;
-
- save_ptid = inferior_ptid;
- inferior_ptid = ptid;
- regcache_cooked_read_unsigned (current_regcache, AVR_PC_REGNUM, &pc);
- inferior_ptid = save_ptid;
- retval = avr_make_iaddr (pc);
- return retval;
+ regcache_cooked_read_unsigned (regcache, AVR_PC_REGNUM, &pc);
+ return avr_make_iaddr (pc);
}
static void
-avr_write_pc (CORE_ADDR val, ptid_t ptid)
+avr_write_pc (struct regcache *regcache, CORE_ADDR val)
{
- ptid_t save_ptid;
-
- save_ptid = inferior_ptid;
- inferior_ptid = ptid;
- write_register (AVR_PC_REGNUM, avr_convert_iaddr_to_raw (val));
- inferior_ptid = save_ptid;
-}
-
-static CORE_ADDR
-avr_read_sp (void)
-{
- ULONGEST sp;
-
- regcache_cooked_read_unsigned (current_regcache, AVR_SP_REGNUM, &sp);
- return (avr_make_saddr (sp));
+ regcache_cooked_write_unsigned (regcache, AVR_PC_REGNUM,
+ avr_convert_iaddr_to_raw (val));
}
static int
}
static CORE_ADDR
-avr_skip_prologue (CORE_ADDR pc)
+avr_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end;
CORE_ADDR prologue_end = pc;
only target, this shouldn't be a problem (I hope). TRoth/2003-05-14 */
static const unsigned char *
-avr_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
+avr_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr, int *lenptr)
{
static unsigned char avr_break_insn [] = { 0x98, 0x95 };
*lenptr = sizeof (avr_break_insn);
}
}
+/* Determine, for architecture GDBARCH, how a return value of TYPE
+ should be returned. If it is supposed to be returned in registers,
+ and READBUF is non-zero, read the appropriate value from REGCACHE,
+ and copy it into READBUF. If WRITEBUF is non-zero, write the value
+ from WRITEBUF into REGCACHE. */
+
+enum return_value_convention
+avr_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *valtype, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ int struct_return = ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (valtype) == TYPE_CODE_UNION
+ || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
+ && !(TYPE_LENGTH (valtype) == 1
+ || TYPE_LENGTH (valtype) == 2
+ || TYPE_LENGTH (valtype) == 4
+ || TYPE_LENGTH (valtype) == 8));
+
+ if (writebuf != NULL)
+ {
+ gdb_assert (!struct_return);
+ error (_("Cannot store return value."));
+ }
+
+ if (readbuf != NULL)
+ {
+ gdb_assert (!struct_return);
+ avr_extract_return_value (valtype, regcache, readbuf);
+ }
+
+ if (struct_return)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
/* Put here the code to store, into fi->saved_regs, the addresses of
the saved registers of frame described by FRAME_INFO. This
includes special registers such as pc and fp saved in special ways
/* The SP was moved to the FP. This indicates that a new frame
was created. Get THIS frame's FP value by unwinding it from
the next frame. */
- frame_unwind_unsigned_register (next_frame, AVR_FP_REGNUM, &this_base);
- frame_unwind_unsigned_register (next_frame, AVR_FP_REGNUM+1, &high_base);
+ this_base = frame_unwind_register_unsigned (next_frame, AVR_FP_REGNUM);
+ high_base = frame_unwind_register_unsigned (next_frame, AVR_FP_REGNUM+1);
this_base += (high_base << 8);
/* The FP points at the last saved register. Adjust the FP back
{
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
- frame_unwind_unsigned_register (next_frame, AVR_SP_REGNUM, &this_base);
+ this_base = frame_unwind_register_unsigned (next_frame, AVR_SP_REGNUM);
prev_sp = this_base + info->size;
}
/* Adjust all the saved registers so that they contain addresses and not
offsets. */
- for (i = 0; i < NUM_REGS - 1; i++)
+ for (i = 0; i < gdbarch_num_regs (get_frame_arch (next_frame)) - 1; i++)
if (info->saved_regs[i].addr)
{
info->saved_regs[i].addr = (info->prev_sp - info->saved_regs[i].addr);
{
ULONGEST pc;
- frame_unwind_unsigned_register (next_frame, AVR_PC_REGNUM, &pc);
+ pc = frame_unwind_register_unsigned (next_frame, AVR_PC_REGNUM);
return avr_make_iaddr (pc);
}
+static CORE_ADDR
+avr_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ ULONGEST sp;
+
+ sp = frame_unwind_register_unsigned (next_frame, AVR_SP_REGNUM);
+
+ return avr_make_saddr (sp);
+}
+
/* Given a GDB frame, determine the address of the calling function's
frame. This will be used to create a new GDB frame struct. */
buf[1] = tmp;
pc = (extract_unsigned_integer (buf, 2) * 2);
- store_unsigned_integer (bufferp,
- register_size (current_gdbarch, regnum),
- pc);
+ store_unsigned_integer
+ (bufferp, register_size (get_frame_arch (next_frame), regnum),
+ pc);
}
}
}
{
ULONGEST base;
- frame_unwind_unsigned_register (next_frame, AVR_SP_REGNUM, &base);
+ base = frame_unwind_register_unsigned (next_frame, AVR_SP_REGNUM);
return frame_id_build (avr_make_saddr (base), frame_pc_unwind (next_frame));
}
if (struct_return)
{
fprintf_unfiltered (gdb_stderr, "struct_return: 0x%lx\n", struct_addr);
- write_register (argreg--, struct_addr & 0xff);
- write_register (argreg--, (struct_addr >>8) & 0xff);
+ regcache_cooked_write_unsigned (regcache, argreg--, struct_addr & 0xff);
+ regcache_cooked_write_unsigned (regcache, argreg--, (struct_addr >>8) & 0xff);
}
#endif
set_gdbarch_read_pc (gdbarch, avr_read_pc);
set_gdbarch_write_pc (gdbarch, avr_write_pc);
- set_gdbarch_read_sp (gdbarch, avr_read_sp);
set_gdbarch_num_regs (gdbarch, AVR_NUM_REGS);
set_gdbarch_register_name (gdbarch, avr_register_name);
set_gdbarch_register_type (gdbarch, avr_register_type);
- set_gdbarch_extract_return_value (gdbarch, avr_extract_return_value);
+ set_gdbarch_return_value (gdbarch, avr_return_value);
set_gdbarch_print_insn (gdbarch, print_insn_avr);
set_gdbarch_push_dummy_call (gdbarch, avr_push_dummy_call);
set_gdbarch_unwind_dummy_id (gdbarch, avr_unwind_dummy_id);
set_gdbarch_unwind_pc (gdbarch, avr_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, avr_unwind_sp);
return gdbarch;
}