diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c index ccc8b45..faa6a77 100644 --- a/gdb/avr-tdep.c +++ b/gdb/avr-tdep.c @@ -29,6 +29,7 @@ #include "trad-frame.h" #include "gdbcmd.h" #include "gdbcore.h" +#include "dwarf2-frame.h" #include "gdbtypes.h" #include "inferior.h" #include "symfile.h" @@ -97,7 +98,8 @@ enum /* Pseudo registers. */ AVR_PSEUDO_PC_REGNUM = 35, - AVR_NUM_PSEUDO_REGS = 1, + AVR_DWARF2_PC_REGNUM = 36 /*LR*/, + AVR_NUM_PSEUDO_REGS = 2, AVR_PC_REG_INDEX = 35, /* index into array of registers */ @@ -211,7 +213,7 @@ avr_register_name (struct gdbarch *gdbarch, int regnum) "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "SREG", "SP", "PC2", - "pc" + "pc", "LR" }; if (regnum < 0) return NULL; @@ -230,6 +232,8 @@ avr_register_type (struct gdbarch *gdbarch, int reg_nr) return builtin_type (gdbarch)->builtin_uint32; if (reg_nr == AVR_PSEUDO_PC_REGNUM) return gdbarch_tdep (gdbarch)->pc_type; + if (reg_nr == AVR_DWARF2_PC_REGNUM) + return gdbarch_tdep (gdbarch)->pc_type; if (reg_nr == AVR_SP_REGNUM) return builtin_type (gdbarch)->builtin_data_ptr; return builtin_type (gdbarch)->builtin_uint8; @@ -395,6 +399,10 @@ avr_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, val >>= 1; store_unsigned_integer (buf, 4, gdbarch_byte_order (gdbarch), val); return status; + case AVR_DWARF2_PC_REGNUM: + /* return that register is unavailable as we can't expect stack at all + times to read CFA, e.g. startup code. */ + return REG_UNAVAILABLE; default: internal_error (__FILE__, __LINE__, _("invalid regnum")); } @@ -413,6 +421,10 @@ avr_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, val <<= 1; regcache_raw_write_unsigned (regcache, AVR_PC_REGNUM, val); break; + case AVR_DWARF2_PC_REGNUM: + /* Do nothing. It is read-only; also we can't expect stack at all + times to write, e.g. startup code. */ + break; default: internal_error (__FILE__, __LINE__, _("invalid regnum")); } @@ -1355,6 +1367,38 @@ avr_push_dummy_call (struct gdbarch *gdbarch, struct value *function, return sp + call_length; } +static struct value * +avr_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache, + int regnum) +{ + struct gdbarch * gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep * tdep = gdbarch_tdep (gdbarch); + CORE_ADDR addr; + ULONGEST pc; + int i; + gdb_byte buf[3]; + + switch (regnum) + { + case AVR_PC_REGNUM: + case AVR_PSEUDO_PC_REGNUM: + addr = dwarf2_frame_addr (this_cache, AVR_DWARF2_PC_REGNUM); + read_memory (addr, buf, tdep->call_length); + pc = 0; + for (i = 0; i < tdep->call_length; i++) + pc = (pc << 8) | buf[i]; + /* Change it to byte address. */ + if (regnum == AVR_PC_REGNUM) + pc <<= 1; + return frame_unwind_got_constant (this_frame, regnum, pc); +// case AVR_PSEUDO_PC_REGNUM: +// internal_error (__FILE__, __LINE__, "I'm here"); + default: + internal_error (__FILE__, __LINE__, + _("Unexpected register %d"), regnum); + } +} + /* Unfortunately dwarf2 register for SP is 32. */ static int @@ -1362,11 +1406,38 @@ avr_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) { if (reg >= 0 && reg < 32) return reg; - if (reg == 32) - return AVR_SP_REGNUM; + switch (reg) + { + case 32: + return AVR_SP_REGNUM; + case 34: // AVR_PC_REGNUM + case 35: // AVR_PSEUDO_PC_REGNUM + case 36: // AVR_DWARF2_PC_REGNUM + return reg; + } return -1; } +static void +avr_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) +{ + switch (regnum) + { + /* Handle PC and PSEUDO PC registers by target function. */ + case AVR_PC_REGNUM: + case AVR_PSEUDO_PC_REGNUM: + reg->how = DWARF2_FRAME_REG_FN; + reg->loc.fn = avr_dwarf2_prev_register; + break; + /* Use CFA to handle SP register. */ + case AVR_SP_REGNUM: + reg->how = DWARF2_FRAME_REG_CFA; + break; + } +} + /* Implementation of `address_class_type_flags' gdbarch method. This method maps DW_AT_address_class attributes to a @@ -1478,6 +1549,9 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_addr_bit (gdbarch, 32); + /* Dwarf address is 4 bytes. Ref: DWARF2_ADDR_SIZE in avr-gcc. */ + set_gdbarch_dwarf2_addr_size (gdbarch, 4); + 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); @@ -1517,6 +1591,9 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_breakpoint_from_pc (gdbarch, avr_breakpoint_from_pc); + dwarf2_frame_set_init_reg (gdbarch, avr_dwarf2_frame_init_reg); + dwarf2_append_unwinders (gdbarch); + frame_unwind_append_unwinder (gdbarch, &avr_frame_unwind); frame_base_set_default (gdbarch, &avr_frame_base); diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index a640c26..54bab17 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -1524,6 +1524,21 @@ dwarf2_frame_cfa (struct frame_info *this_frame) return get_frame_base (this_frame); } + +/* Compute the frame address. */ +CORE_ADDR +dwarf2_frame_addr (void ** this_cache, int regnum) +{ + struct dwarf2_frame_cache *cache = *this_cache; + CORE_ADDR addr; + + gdb_assert (cache != NULL); + gdb_assert (cache->reg[regnum].how == DWARF2_FRAME_REG_SAVED_OFFSET); + + addr = cache->cfa + cache->reg[regnum].loc.offset; + + return addr; +} const struct objfile_data *dwarf2_frame_objfile_data; diff --git a/gdb/dwarf2-frame.h b/gdb/dwarf2-frame.h index b739744..cde88e5 100644 --- a/gdb/dwarf2-frame.h +++ b/gdb/dwarf2-frame.h @@ -119,6 +119,7 @@ extern const struct frame_base * /* Compute the DWARF CFA for a frame. */ CORE_ADDR dwarf2_frame_cfa (struct frame_info *this_frame); +CORE_ADDR dwarf2_frame_addr (void ** this_cache, int regnum); /* Find the CFA information for PC.