/* 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.
/* 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_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
for it IS the sp for the next frame. */
struct avr_unwind_cache *
-avr_frame_unwind_cache (struct frame_info *next_frame,
+avr_frame_unwind_cache (struct frame_info *this_frame,
void **this_prologue_cache)
{
CORE_ADDR pc;
info = FRAME_OBSTACK_ZALLOC (struct avr_unwind_cache);
(*this_prologue_cache) = info;
- info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+ info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
info->size = 0;
info->prologue_type = AVR_PROLOGUE_NONE;
- pc = frame_func_unwind (next_frame, NORMAL_FRAME);
+ pc = get_frame_func (this_frame);
- if ((pc > 0) && (pc < frame_pc_unwind (next_frame)))
+ if ((pc > 0) && (pc < get_frame_pc (this_frame)))
avr_scan_prologue (pc, info);
if ((info->prologue_type != AVR_PROLOGUE_NONE)
/* 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 = get_frame_register_unsigned (this_frame, AVR_FP_REGNUM);
+ high_base = get_frame_register_unsigned (this_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 = get_frame_register_unsigned (this_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 < gdbarch_num_regs (current_gdbarch) - 1; i++)
+ for (i = 0; i < gdbarch_num_regs (get_frame_arch (this_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);
}
{
ULONGEST sp;
- frame_unwind_unsigned_register (next_frame, AVR_SP_REGNUM, &sp);
+ sp = frame_unwind_register_unsigned (next_frame, AVR_SP_REGNUM);
return avr_make_saddr (sp);
}
frame. This will be used to create a new GDB frame struct. */
static void
-avr_frame_this_id (struct frame_info *next_frame,
+avr_frame_this_id (struct frame_info *this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct avr_unwind_cache *info
- = avr_frame_unwind_cache (next_frame, this_prologue_cache);
+ = avr_frame_unwind_cache (this_frame, this_prologue_cache);
CORE_ADDR base;
CORE_ADDR func;
struct frame_id id;
/* The FUNC is easy. */
- func = frame_func_unwind (next_frame, NORMAL_FRAME);
+ func = get_frame_func (this_frame);
/* Hopefully the prologue analysis either correctly determined the
frame's base (which is the SP from the previous frame), or set
(*this_id) = id;
}
-static void
-avr_frame_prev_register (struct frame_info *next_frame,
- void **this_prologue_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, gdb_byte *bufferp)
+static struct value *
+avr_frame_prev_register (struct frame_info *this_frame,
+ void **this_prologue_cache, int regnum)
{
struct avr_unwind_cache *info
- = avr_frame_unwind_cache (next_frame, this_prologue_cache);
+ = avr_frame_unwind_cache (this_frame, this_prologue_cache);
if (regnum == AVR_PC_REGNUM)
{
if (trad_frame_addr_p (info->saved_regs, regnum))
{
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = info->saved_regs[regnum].addr;
- *realnump = -1;
- if (bufferp != NULL)
- {
- /* Reading the return PC from the PC register is slightly
- abnormal. register_size(AVR_PC_REGNUM) says it is 4 bytes,
- but in reality, only two bytes (3 in upcoming mega256) are
- stored on the stack.
-
- Also, note that the value on the stack is an addr to a word
- not a byte, so we will need to multiply it by two at some
- point.
-
- And to confuse matters even more, the return address stored
- on the stack is in big endian byte order, even though most
- everything else about the avr is little endian. Ick! */
-
- /* FIXME: number of bytes read here will need updated for the
- mega256 when it is available. */
-
- ULONGEST pc;
- unsigned char tmp;
- unsigned char buf[2];
-
- read_memory (info->saved_regs[regnum].addr, buf, 2);
-
- /* Convert the PC read from memory as a big-endian to
- little-endian order. */
- tmp = buf[0];
- buf[0] = buf[1];
- buf[1] = tmp;
-
- pc = (extract_unsigned_integer (buf, 2) * 2);
- store_unsigned_integer (bufferp,
- register_size (current_gdbarch, regnum),
- pc);
- }
+ /* Reading the return PC from the PC register is slightly
+ abnormal. register_size(AVR_PC_REGNUM) says it is 4 bytes,
+ but in reality, only two bytes (3 in upcoming mega256) are
+ stored on the stack.
+
+ Also, note that the value on the stack is an addr to a word
+ not a byte, so we will need to multiply it by two at some
+ point.
+
+ And to confuse matters even more, the return address stored
+ on the stack is in big endian byte order, even though most
+ everything else about the avr is little endian. Ick! */
+
+ /* FIXME: number of bytes read here will need updated for the
+ mega256 when it is available. */
+
+ ULONGEST pc;
+ unsigned char tmp;
+ unsigned char buf[2];
+
+ read_memory (info->saved_regs[regnum].addr, buf, 2);
+
+ /* Convert the PC read from memory as a big-endian to
+ little-endian order. */
+ tmp = buf[0];
+ buf[0] = buf[1];
+ buf[1] = tmp;
+
+ pc = (extract_unsigned_integer (buf, 2) * 2);
+
+ return frame_unwind_got_constant (this_frame, regnum, pc);
}
+
+ return frame_unwind_got_optimized (this_frame, regnum);
}
- else
- trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
}
static const struct frame_unwind avr_frame_unwind = {
NORMAL_FRAME,
avr_frame_this_id,
- avr_frame_prev_register
+ avr_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-const struct frame_unwind *
-avr_frame_sniffer (struct frame_info *next_frame)
-{
- return &avr_frame_unwind;
-}
-
static CORE_ADDR
-avr_frame_base_address (struct frame_info *next_frame, void **this_cache)
+avr_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
struct avr_unwind_cache *info
- = avr_frame_unwind_cache (next_frame, this_cache);
+ = avr_frame_unwind_cache (this_frame, this_cache);
return info->base;
}
avr_frame_base_address
};
-/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
- dummy frame. The frame ID's base needs to match the TOS value
- saved by save_dummy_frame_tos(), and the PC match the dummy frame's
- breakpoint. */
+/* Assuming THIS_FRAME is a dummy, return the frame ID of that dummy
+ frame. The frame ID's base needs to match the TOS value saved by
+ save_dummy_frame_tos(), and the PC match the dummy frame's breakpoint. */
static struct frame_id
-avr_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+avr_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
ULONGEST base;
- frame_unwind_unsigned_register (next_frame, AVR_SP_REGNUM, &base);
- return frame_id_build (avr_make_saddr (base), frame_pc_unwind (next_frame));
+ base = get_frame_register_unsigned (this_frame, AVR_SP_REGNUM);
+ return frame_id_build (avr_make_saddr (base), get_frame_pc (this_frame));
}
/* When arguments must be pushed onto the stack, they go on in reverse
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_breakpoint_from_pc (gdbarch, avr_breakpoint_from_pc);
- frame_unwind_append_sniffer (gdbarch, avr_frame_sniffer);
+ frame_unwind_append_unwinder (gdbarch, &avr_frame_unwind);
frame_base_set_default (gdbarch, &avr_frame_base);
- set_gdbarch_unwind_dummy_id (gdbarch, avr_unwind_dummy_id);
+ set_gdbarch_dummy_id (gdbarch, avr_dummy_id);
set_gdbarch_unwind_pc (gdbarch, avr_unwind_pc);
set_gdbarch_unwind_sp (gdbarch, avr_unwind_sp);