#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "trad-frame.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "inferior.h"
#include "symfile.h"
#include "arch-utils.h"
#include "regcache.h"
#include "gdb_string.h"
#include "dis-asm.h"
#undef XMALLOC
#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
#undef EXTRACT_INSN
#define EXTRACT_INSN(addr) extract_unsigned_integer(addr,2)
enum
{
AVR_REG_W = 24,
AVR_REG_X = 26,
AVR_REG_Y = 28,
AVR_FP_REGNUM = 28,
AVR_REG_Z = 30,
AVR_SREG_REGNUM = 32,
AVR_SP_REGNUM = 33,
AVR_PC_REGNUM = 34,
AVR_NUM_REGS = 32 + 1 + 1 + 1 ,
AVR_NUM_REG_BYTES = 32 + 1 + 2 + 4 ,
AVR_PC_REG_INDEX = 35,
AVR_MAX_PROLOGUE_SIZE = 64,
AVR_MAX_PUSHES = 18,
AVR_LAST_PUSHED_REGNUM = 17,
AVR_ARG1_REGNUM = 24,
AVR_ARGN_REGNUM = 25,
AVR_RET1_REGNUM = 24,
AVR_RETN_REGNUM = 25,
AVR_IMEM_START = 0x00000000,
AVR_SMEM_START = 0x00800000,
#if 1
AVR_MEM_MASK = 0x00f00000,
#else
AVR_EMEM_START = 0x00810000,
AVR_MEM_MASK = 0x00ff0000,
#endif
};
enum {
AVR_PROLOGUE_NONE,
AVR_PROLOGUE_NORMAL,
AVR_PROLOGUE_CALL,
AVR_PROLOGUE_MAIN,
AVR_PROLOGUE_INTR,
AVR_PROLOGUE_SIG,
};
struct avr_unwind_cache
{
CORE_ADDR prev_sp;
CORE_ADDR base;
int size;
int prologue_type;
struct trad_frame_saved_reg *saved_regs;
};
struct gdbarch_tdep
{
int foo;
};
static const char *
avr_register_name (int regnum)
{
static char *register_names[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"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"
};
if (regnum < 0)
return NULL;
if (regnum >= (sizeof (register_names) / sizeof (*register_names)))
return NULL;
return register_names[regnum];
}
static struct type *
avr_register_type (struct gdbarch *gdbarch, int reg_nr)
{
if (reg_nr == AVR_PC_REGNUM)
return builtin_type_uint32;
if (reg_nr == AVR_SP_REGNUM)
return builtin_type_void_data_ptr;
else
return builtin_type_uint8;
}
static CORE_ADDR
avr_make_iaddr (CORE_ADDR x)
{
return ((x) | AVR_IMEM_START);
}
static CORE_ADDR
avr_convert_iaddr_to_raw (CORE_ADDR x)
{
return ((x) & 0xffffffff);
}
static CORE_ADDR
avr_make_saddr (CORE_ADDR x)
{
return ((x) | AVR_SMEM_START);
}
static CORE_ADDR
avr_convert_saddr_to_raw (CORE_ADDR x)
{
return ((x) & 0xffffffff);
}
static void
avr_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr)
{
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
|| TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
{
store_unsigned_integer (buf, TYPE_LENGTH (type),
avr_convert_iaddr_to_raw (addr >> 1));
}
else
{
store_unsigned_integer (buf, TYPE_LENGTH (type),
avr_convert_saddr_to_raw (addr));
}
}
static CORE_ADDR
avr_pointer_to_address (struct type *type, const void *buf)
{
CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
|| TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD
|| TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type)))
return avr_make_iaddr (addr << 1);
else
return avr_make_saddr (addr);
}
static CORE_ADDR
avr_read_pc (ptid_t ptid)
{
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;
}
static void
avr_write_pc (CORE_ADDR val, ptid_t ptid)
{
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));
}
static int
avr_scan_arg_moves (int vpc, unsigned char *prologue)
{
unsigned short insn;
for (; vpc < AVR_MAX_PROLOGUE_SIZE; vpc += 2)
{
insn = EXTRACT_INSN (&prologue[vpc]);
if ((insn & 0xff00) == 0x0100)
continue;
else if ((insn & 0xfc00) == 0x2c00)
continue;
else
break;
}
return vpc;
}
static CORE_ADDR
avr_scan_prologue (CORE_ADDR pc, struct avr_unwind_cache *info)
{
int i;
unsigned short insn;
int scan_stage = 0;
struct minimal_symbol *msymbol;
unsigned char prologue[AVR_MAX_PROLOGUE_SIZE];
int vpc = 0;
read_memory (pc, prologue, AVR_MAX_PROLOGUE_SIZE);
if (1)
{
CORE_ADDR locals;
unsigned char img[] = {
0xde, 0xbf,
0xcd, 0xbf
};
insn = EXTRACT_INSN (&prologue[vpc]);
if ((insn & 0xf0f0) == 0xe0c0)
{
locals = (insn & 0xf) | ((insn & 0x0f00) >> 4);
insn = EXTRACT_INSN (&prologue[vpc + 2]);
if ((insn & 0xf0f0) == 0xe0d0)
{
locals |= ((insn & 0xf) | ((insn & 0x0f00) >> 4)) << 8;
if (memcmp (prologue + vpc + 4, img, sizeof (img)) == 0)
{
info->prologue_type = AVR_PROLOGUE_MAIN;
info->base = locals;
return pc + 4;
}
}
}
}
while (1)
{
int loc_size;
int body_addr;
unsigned num_pushes;
int pc_offset = 0;
insn = EXTRACT_INSN (&prologue[vpc]);
if ((insn & 0xf0f0) != 0xe0a0)
break;
loc_size = (insn & 0xf) | ((insn & 0x0f00) >> 4);
pc_offset += 2;
insn = EXTRACT_INSN (&prologue[vpc + 2]);
if ((insn & 0xf0f0) != 0xe0b0)
break;
loc_size |= ((insn & 0xf) | ((insn & 0x0f00) >> 4)) << 8;
pc_offset += 2;
insn = EXTRACT_INSN (&prologue[vpc + 4]);
if ((insn & 0xf0f0) != 0xe0e0)
break;
body_addr = (insn & 0xf) | ((insn & 0x0f00) >> 4);
pc_offset += 2;
insn = EXTRACT_INSN (&prologue[vpc + 6]);
if ((insn & 0xf0f0) != 0xe0f0)
break;
body_addr |= ((insn & 0xf) | ((insn & 0x0f00) >> 4)) << 8;
pc_offset += 2;
msymbol = lookup_minimal_symbol ("__prologue_saves__", NULL, NULL);
if (!msymbol)
break;
insn = EXTRACT_INSN (&prologue[vpc + 8]);
if ((insn & 0xf000) == 0xc000)
{
i = (insn & 0xfff) | (insn & 0x800 ? (-1 ^ 0xfff) : 0);
i *= 2;
i += pc + 10;
if (body_addr != (pc + 10)/2)
break;
pc_offset += 2;
}
else if ((insn & 0xfe0e) == 0x940c)
{
i = (((insn & 0x1) | ((insn & 0x1f0) >> 3) << 16)
| (EXTRACT_INSN (&prologue[vpc + 10]) & 0xffff));
i *= 2;
if (body_addr != (pc + 12)/2)
break;
pc_offset += 4;
}
else
break;
num_pushes = AVR_MAX_PUSHES - (i - SYMBOL_VALUE_ADDRESS (msymbol)) / 2;
if (num_pushes > AVR_MAX_PUSHES)
{
fprintf_unfiltered (gdb_stderr, _("Num pushes too large: %d\n"),
num_pushes);
num_pushes = 0;
}
if (num_pushes)
{
int from;
info->saved_regs[AVR_FP_REGNUM + 1].addr = num_pushes;
if (num_pushes >= 2)
info->saved_regs[AVR_FP_REGNUM].addr = num_pushes - 1;
i = 0;
for (from = AVR_LAST_PUSHED_REGNUM + 1 - (num_pushes - 2);
from <= AVR_LAST_PUSHED_REGNUM; ++from)
info->saved_regs [from].addr = ++i;
}
info->size = loc_size + num_pushes;
info->prologue_type = AVR_PROLOGUE_CALL;
return pc + pc_offset;
}
if (1)
{
unsigned char img[] = {
0x78, 0x94,
0x1f, 0x92,
0x0f, 0x92,
0x0f, 0xb6,
0x0f, 0x92,
0x11, 0x24
};
if (memcmp (prologue, img, sizeof (img)) == 0)
{
info->prologue_type = AVR_PROLOGUE_INTR;
vpc += sizeof (img);
info->saved_regs[AVR_SREG_REGNUM].addr = 3;
info->saved_regs[0].addr = 2;
info->saved_regs[1].addr = 1;
info->size += 3;
}
else if (memcmp (img + 2, prologue, sizeof (img) - 2) == 0)
{
info->prologue_type = AVR_PROLOGUE_SIG;
vpc += sizeof (img) - 2;
info->saved_regs[AVR_SREG_REGNUM].addr = 3;
info->saved_regs[0].addr = 2;
info->saved_regs[1].addr = 1;
info->size += 3;
}
}
for (; vpc < AVR_MAX_PROLOGUE_SIZE; vpc += 2)
{
insn = EXTRACT_INSN (&prologue[vpc]);
if ((insn & 0xfe0f) == 0x920f)
{
int regno = (insn & 0x1f0) >> 4;
info->size++;
info->saved_regs[regno].addr = info->size;
scan_stage = 1;
}
else
break;
}
if (vpc >= AVR_MAX_PROLOGUE_SIZE)
fprintf_unfiltered (gdb_stderr,
_("Hit end of prologue while scanning pushes\n"));
if (scan_stage == 1 && vpc < AVR_MAX_PROLOGUE_SIZE)
{
unsigned char img[] = {
0xcd, 0xb7,
0xde, 0xb7
};
unsigned short insn1;
if (memcmp (prologue + vpc, img, sizeof (img)) == 0)
{
vpc += 4;
scan_stage = 2;
}
}
if (scan_stage == 2 && vpc < AVR_MAX_PROLOGUE_SIZE)
{
int locals_size = 0;
unsigned char img[] = {
0x0f, 0xb6,
0xf8, 0x94,
0xde, 0xbf,
0x0f, 0xbe,
0xcd, 0xbf
};
unsigned char img_sig[] = {
0xde, 0xbf,
0xcd, 0xbf
};
unsigned char img_int[] = {
0xf8, 0x94,
0xde, 0xbf,
0x78, 0x94,
0xcd, 0xbf
};
insn = EXTRACT_INSN (&prologue[vpc]);
vpc += 2;
if ((insn & 0xff30) == 0x9720)
locals_size = (insn & 0xf) | ((insn & 0xc0) >> 2);
else if ((insn & 0xf0f0) == 0x50c0)
{
locals_size = (insn & 0xf) | ((insn & 0xf00) >> 4);
insn = EXTRACT_INSN (&prologue[vpc]);
vpc += 2;
locals_size += ((insn & 0xf) | ((insn & 0xf00) >> 4) << 8);
}
else
return pc + vpc;
if (memcmp (prologue + vpc, img_sig, sizeof (img_sig)) == 0)
{
vpc += sizeof (img_sig);
}
else if (memcmp (prologue + vpc, img_int, sizeof (img_int)) == 0)
{
vpc += sizeof (img_int);
}
if (memcmp (prologue + vpc, img, sizeof (img)) == 0)
{
info->prologue_type = AVR_PROLOGUE_NORMAL;
vpc += sizeof (img);
}
info->size += locals_size;
return pc + avr_scan_arg_moves (vpc, prologue);
}
return pc + avr_scan_arg_moves (vpc, prologue);;
}
static CORE_ADDR
avr_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end;
CORE_ADDR prologue_end = pc;
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;
prologue_end = avr_scan_prologue (pc, &info);
if (info.prologue_type == AVR_PROLOGUE_NONE)
return pc;
else
{
sal = find_pc_line (func_addr, 0);
if (sal.line != 0 && sal.end < func_end)
return sal.end;
}
}
return prologue_end;
}
static const unsigned char *
avr_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
{
static unsigned char avr_break_insn [] = { 0x98, 0x95 };
*lenptr = sizeof (avr_break_insn);
return avr_break_insn;
}
static void
avr_extract_return_value (struct type *type, struct regcache *regcache,
void *valbuf)
{
ULONGEST r24, r25;
ULONGEST c;
int len;
if (TYPE_LENGTH (type) == 1)
{
regcache_cooked_read_unsigned (regcache, 24, &c);
store_unsigned_integer (valbuf, 1, c);
}
else
{
int i;
int lsb_reg = 25 - TYPE_LENGTH (type) + 1;
for (i=0; i< TYPE_LENGTH (type); i++)
{
regcache_cooked_read (regcache, lsb_reg + i,
(bfd_byte *) valbuf + i);
}
}
}
struct avr_unwind_cache *
avr_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
CORE_ADDR pc;
ULONGEST prev_sp;
ULONGEST this_base;
struct avr_unwind_cache *info;
int i;
if ((*this_prologue_cache))
return (*this_prologue_cache);
info = FRAME_OBSTACK_ZALLOC (struct avr_unwind_cache);
(*this_prologue_cache) = info;
info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
info->size = 0;
info->prologue_type = AVR_PROLOGUE_NONE;
pc = frame_func_unwind (next_frame);
if ((pc > 0) && (pc < frame_pc_unwind (next_frame)))
avr_scan_prologue (pc, info);
if ((info->prologue_type != AVR_PROLOGUE_NONE)
&& (info->prologue_type != AVR_PROLOGUE_MAIN))
{
ULONGEST high_base;
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 += (high_base << 8);
prev_sp = this_base + info->size;
}
else
{
frame_unwind_unsigned_register (next_frame, AVR_SP_REGNUM, &this_base);
prev_sp = this_base + info->size;
}
info->prev_sp = avr_make_saddr (prev_sp+1);
info->base = avr_make_saddr (this_base);
for (i = 0; i < NUM_REGS - 1; i++)
if (info->saved_regs[i].addr)
{
info->saved_regs[i].addr = (info->prev_sp - info->saved_regs[i].addr);
}
if (info->prologue_type != AVR_PROLOGUE_MAIN)
{
info->saved_regs[AVR_PC_REGNUM].addr = info->prev_sp;
}
trad_frame_set_value (info->saved_regs, AVR_SP_REGNUM, info->prev_sp+1);
return info;
}
static CORE_ADDR
avr_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST pc;
frame_unwind_unsigned_register (next_frame, AVR_PC_REGNUM, &pc);
return avr_make_iaddr (pc);
}
static void
avr_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct avr_unwind_cache *info
= avr_frame_unwind_cache (next_frame, this_prologue_cache);
CORE_ADDR base;
CORE_ADDR func;
struct frame_id id;
func = frame_func_unwind (next_frame);
base = info->prev_sp;
if (base == 0)
return;
id = frame_id_build (base, func);
(*this_id) = id;
}
static void
avr_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct avr_unwind_cache *info
= avr_frame_unwind_cache (next_frame, this_prologue_cache);
if (regnum == AVR_PC_REGNUM)
{
if (trad_frame_addr_p (info->saved_regs, regnum))
{
*optimizedp = opt_okay;
*lvalp = lval_memory;
*addrp = info->saved_regs[regnum].addr;
*realnump = -1;
if (bufferp != NULL)
{
ULONGEST pc;
unsigned char tmp;
unsigned char buf[2];
read_memory (info->saved_regs[regnum].addr, buf, 2);
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);
}
}
}
else
trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
}
static const struct frame_unwind avr_frame_unwind = {
NORMAL_FRAME,
avr_frame_this_id,
avr_frame_prev_register
};
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)
{
struct avr_unwind_cache *info
= avr_frame_unwind_cache (next_frame, this_cache);
return info->base;
}
static const struct frame_base avr_frame_base = {
&avr_frame_unwind,
avr_frame_base_address,
avr_frame_base_address,
avr_frame_base_address
};
static struct frame_id
avr_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_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));
}
struct stack_item
{
int len;
struct stack_item *prev;
void *data;
};
static struct stack_item *
push_stack_item (struct stack_item *prev, const bfd_byte *contents, int len)
{
struct stack_item *si;
si = xmalloc (sizeof (struct stack_item));
si->data = xmalloc (len);
si->len = len;
si->prev = prev;
memcpy (si->data, contents, len);
return si;
}
static struct stack_item *pop_stack_item (struct stack_item *si);
static struct stack_item *
pop_stack_item (struct stack_item *si)
{
struct stack_item *dead = si;
si = si->prev;
xfree (dead->data);
xfree (dead);
return si;
}
static CORE_ADDR
avr_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int i;
unsigned char buf[2];
CORE_ADDR return_pc = avr_convert_iaddr_to_raw (bp_addr);
int regnum = AVR_ARGN_REGNUM;
struct stack_item *si = NULL;
#if 0
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);
}
#endif
for (i = 0; i < nargs; i++)
{
int last_regnum;
int j;
struct value *arg = args[i];
struct type *type = check_typedef (value_type (arg));
const bfd_byte *contents = value_contents (arg);
int len = TYPE_LENGTH (type);
last_regnum = regnum - (len + (len & 1));
if ((si == NULL) && (last_regnum >= 8))
{
ULONGEST val;
if (len & 1)
regnum--;
val = extract_unsigned_integer (contents, len);
for (j=0; j<len; j++)
{
regcache_cooked_write_unsigned (regcache, regnum--,
val >> (8*(len-j-1)));
}
}
else
{
si = push_stack_item (si, contents, len);
}
}
while (si)
{
sp -= si->len;
write_memory (sp+1, si->data, si->len);
si = pop_stack_item (si);
}
buf[0] = (return_pc >> 8) & 0xff;
buf[1] = return_pc & 0xff;
sp -= 2;
write_memory (sp+1, buf, 2);
regcache_cooked_write_unsigned (regcache, AVR_SP_REGNUM,
avr_convert_saddr_to_raw (sp));
return sp;
}
static struct gdbarch *
avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
switch (info.bfd_arch_info->mach)
{
case bfd_mach_avr1:
case bfd_mach_avr2:
case bfd_mach_avr3:
case bfd_mach_avr4:
case bfd_mach_avr5:
break;
}
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);
set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
set_gdbarch_addr_bit (gdbarch, 32);
set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
set_gdbarch_double_format (gdbarch, &floatformat_ieee_single_little);
set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_single_little);
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_sp_regnum (gdbarch, AVR_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, AVR_PC_REGNUM);
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_print_insn (gdbarch, print_insn_avr);
set_gdbarch_push_dummy_call (gdbarch, avr_push_dummy_call);
set_gdbarch_address_to_pointer (gdbarch, avr_address_to_pointer);
set_gdbarch_pointer_to_address (gdbarch, avr_pointer_to_address);
set_gdbarch_skip_prologue (gdbarch, avr_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, avr_breakpoint_from_pc);
frame_unwind_append_sniffer (gdbarch, avr_frame_sniffer);
frame_base_set_default (gdbarch, &avr_frame_base);
set_gdbarch_unwind_dummy_id (gdbarch, avr_unwind_dummy_id);
set_gdbarch_unwind_pc (gdbarch, avr_unwind_pc);
return gdbarch;
}
static void
avr_io_reg_read_command (char *args, int from_tty)
{
LONGEST bufsiz = 0;
char buf[400];
char query[400];
char *p;
unsigned int nreg = 0;
unsigned int val;
int i, j, k, step;
bufsiz = target_read_partial (¤t_target, TARGET_OBJECT_AVR,
NULL, NULL, 0, 0);
if (bufsiz < 0)
{
fprintf_unfiltered (gdb_stderr,
_("ERR: info io_registers NOT supported "
"by current target\n"));
return;
}
if (bufsiz > sizeof (buf))
bufsiz = sizeof (buf);
strcpy (query, "avr.io_reg");
target_read_partial (¤t_target, TARGET_OBJECT_AVR, query, buf, 0,
bufsiz);
if (strncmp (buf, "", bufsiz) == 0)
{
fprintf_unfiltered (gdb_stderr,
_("info io_registers NOT supported by target\n"));
return;
}
if (sscanf (buf, "%x", &nreg) != 1)
{
fprintf_unfiltered (gdb_stderr,
_("Error fetching number of io registers\n"));
return;
}
reinitialize_more_filter ();
printf_unfiltered (_("Target has %u io registers:\n\n"), nreg);
step = 8;
for (i = 0; i < nreg; i += step)
{
j = step;
if ((i+j) >= nreg)
j = nreg - i;
snprintf (query, sizeof (query) - 1, "avr.io_reg:%x,%x", i, j);
target_read_partial (¤t_target, TARGET_OBJECT_AVR, query, buf,
0, bufsiz);
p = buf;
for (k = i; k < (i + j); k++)
{
if (sscanf (p, "%[^,],%x;", query, &val) == 2)
{
printf_filtered ("[%02x] %-15s : %02x\n", k, query, val);
while ((*p != ';') && (*p != '\0'))
p++;
p++;
if (*p == '\0')
break;
}
}
}
}
extern initialize_file_ftype _initialize_avr_tdep;
void
_initialize_avr_tdep (void)
{
register_gdbarch_init (bfd_arch_avr, avr_gdbarch_init);
add_cmd ("io_registers", class_info, avr_io_reg_read_command,
_("query remote avr target for io space register values"),
&infolist);
}