diff options
author | Stephane Carrez <stcarrez@nerim.fr> | 2002-08-13 16:40:46 +0000 |
---|---|---|
committer | Stephane Carrez <stcarrez@nerim.fr> | 2002-08-13 16:40:46 +0000 |
commit | 7df11f59811c830ac11cbd15a5483c8384dabf87 (patch) | |
tree | fc6ce34161b3e6286f259316c84d0aa2bef51c49 /gdb/m68hc11-tdep.c | |
parent | 5706502aab5d26fc794f0f3458450e4764fbba36 (diff) | |
download | gdb-7df11f59811c830ac11cbd15a5483c8384dabf87.zip gdb-7df11f59811c830ac11cbd15a5483c8384dabf87.tar.gz gdb-7df11f59811c830ac11cbd15a5483c8384dabf87.tar.bz2 |
* m68hc11-tdep.c (m68hc11_elf_make_msymbol_special): New function.
(m68hc11_gdbarch_init): Install it in gdbarch.
(MSYMBOL_SET_RTC, MSYMBOL_SET_RTI): New to set symbol specific flags.
(MSYMBOL_IS_RTC, MSYMBOL_IS_RTI): New to test these flags.
(MSYMBOL_SIZE): New for documentation.
(insn_return_kind): Enum to specify how a function returns.
(frame_extra_info): Cleanup and record the return mode.
(gdbarch_tdep, USE_PAGE_REGISTER): New to control the use of page
register in address computation.
(m68hc11_get_return_insn): New to obtain the return instruction used
by the function.
(m68hc11_frame_init_saved_regs): Take into account the return
instruction used by the function for far and interrupt functions.
(m68hc11_init_extra_frame_info): Take into account page register.
(m68hc11_frame_args_address): Adjust according to the return mode.
(show_regs): Print page register only when it's used.
Diffstat (limited to 'gdb/m68hc11-tdep.c')
-rw-r--r-- | gdb/m68hc11-tdep.c | 152 |
1 files changed, 139 insertions, 13 deletions
diff --git a/gdb/m68hc11-tdep.c b/gdb/m68hc11-tdep.c index c2f7a4b..0ad7c9d 100644 --- a/gdb/m68hc11-tdep.c +++ b/gdb/m68hc11-tdep.c @@ -39,6 +39,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "elf/m68hc11.h" #include "elf-bfd.h" +/* Macros for setting and testing a bit in a minimal symbol. + For 68HC11/68HC12 we have two flags that tell which return + type the function is using. This is used for prologue and frame + analysis to compute correct stack frame layout. + + The MSB of the minimal symbol's "info" field is used for this purpose. + This field is already being used to store the symbol size, so the + assumption is that the symbol size cannot exceed 2^30. + + MSYMBOL_SET_RTC Actually sets the "RTC" bit. + MSYMBOL_SET_RTI Actually sets the "RTI" bit. + MSYMBOL_IS_RTC Tests the "RTC" bit in a minimal symbol. + MSYMBOL_IS_RTI Tests the "RTC" bit in a minimal symbol. + MSYMBOL_SIZE Returns the size of the minimal symbol, + i.e. the "info" field with the "special" bit + masked out. */ + +#define MSYMBOL_SET_RTC(msym) \ + MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) \ + | 0x80000000) + +#define MSYMBOL_SET_RTI(msym) \ + MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) \ + | 0x40000000) + +#define MSYMBOL_IS_RTC(msym) \ + (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0) + +#define MSYMBOL_IS_RTI(msym) \ + (((long) MSYMBOL_INFO (msym) & 0x40000000) != 0) + +#define MSYMBOL_SIZE(msym) \ + ((long) MSYMBOL_INFO (msym) & 0x3fffffff) + +enum insn_return_kind { + RETURN_RTS, + RETURN_RTC, + RETURN_RTI +}; + + /* Register numbers of various important registers. Note that some of these values are "real" register numbers, and correspond to the general registers of the machine, @@ -99,20 +140,24 @@ struct gdbarch_tdep /* Description of instructions in the prologue. */ struct insn_sequence *prologue; + /* True if the page memory bank register is available + and must be used. */ + int use_page_register; + /* ELF flags for ABI. */ int elf_flags; }; #define M6811_TDEP gdbarch_tdep (current_gdbarch) #define STACK_CORRECTION (M6811_TDEP->stack_correction) +#define USE_PAGE_REGISTER (M6811_TDEP->use_page_register) struct frame_extra_info { - int frame_reg; CORE_ADDR return_pc; - CORE_ADDR dummy; int frameless; int size; + enum insn_return_kind return_kind; }; /* Table of registers for 68HC11. This includes the hard registers @@ -313,7 +358,15 @@ m68hc11_frame_saved_pc (struct frame_info *frame) static CORE_ADDR m68hc11_frame_args_address (struct frame_info *frame) { - return frame->frame + frame->extra_info->size + STACK_CORRECTION + 2; + CORE_ADDR addr; + + addr = frame->frame + frame->extra_info->size + STACK_CORRECTION + 2; + if (frame->extra_info->return_kind == RETURN_RTC) + addr += 1; + else if (frame->extra_info->return_kind == RETURN_RTI) + addr += 7; + + return addr; } static CORE_ADDR @@ -528,6 +581,28 @@ m68hc11_analyze_instruction (struct insn_sequence *seq, CORE_ADDR *pc, return 0; } +/* Return the instruction that the function at the PC is using. */ +static enum insn_return_kind +m68hc11_get_return_insn (CORE_ADDR pc) +{ + struct minimal_symbol *sym; + + /* A flag indicating that this is a STO_M68HC12_FAR or STO_M68HC12_INTERRUPT + function is stored by elfread.c in the high bit of the info field. + Use this to decide which instruction the function uses to return. */ + sym = lookup_minimal_symbol_by_pc (pc); + if (sym == 0) + return RETURN_RTS; + + if (MSYMBOL_IS_RTC (sym)) + return RETURN_RTC; + else if (MSYMBOL_IS_RTI (sym)) + return RETURN_RTI; + else + return RETURN_RTS; +} + + /* Analyze the function prologue to find some information about the function: - the PC of the first line (for m68hc11_skip_prologue) @@ -715,19 +790,35 @@ m68hc11_frame_init_saved_regs (struct frame_info *fi) { CORE_ADDR pc; CORE_ADDR addr; - + if (fi->saved_regs == NULL) frame_saved_regs_zalloc (fi); else memset (fi->saved_regs, 0, sizeof (fi->saved_regs)); pc = fi->pc; + fi->extra_info->return_kind = m68hc11_get_return_insn (pc); m68hc11_guess_from_prologue (pc, fi->frame, &pc, &fi->extra_info->size, fi->saved_regs); addr = fi->frame + fi->extra_info->size + STACK_CORRECTION; if (soft_regs[SOFT_FP_REGNUM].name) fi->saved_regs[SOFT_FP_REGNUM] = addr - 2; + + /* Take into account how the function was called/returns. */ + if (fi->extra_info->return_kind == RETURN_RTC) + { + fi->saved_regs[HARD_PAGE_REGNUM] = addr; + addr++; + } + else if (fi->extra_info->return_kind == RETURN_RTI) + { + fi->saved_regs[HARD_CCR_REGNUM] = addr; + fi->saved_regs[HARD_D_REGNUM] = addr + 1; + fi->saved_regs[HARD_X_REGNUM] = addr + 3; + fi->saved_regs[HARD_Y_REGNUM] = addr + 5; + addr += 7; + } fi->saved_regs[HARD_SP_REGNUM] = addr; fi->saved_regs[HARD_PC_REGNUM] = fi->saved_regs[HARD_SP_REGNUM]; } @@ -747,20 +838,27 @@ m68hc11_init_extra_frame_info (int fromleaf, struct frame_info *fi) if (fromleaf) { + fi->extra_info->return_kind = m68hc11_get_return_insn (fi->pc); fi->extra_info->return_pc = m68hc11_saved_pc_after_call (fi); } else { - addr = fi->frame + fi->extra_info->size + STACK_CORRECTION; + addr = fi->saved_regs[HARD_PC_REGNUM]; addr = read_memory_unsigned_integer (addr, 2) & 0x0ffff; + + /* Take into account the 68HC12 specific call (PC + page). */ + if (fi->extra_info->return_kind == RETURN_RTC + && addr >= 0x08000 && addr < 0x0c000 + && USE_PAGE_REGISTER) + { + CORE_ADDR page_addr = fi->saved_regs[HARD_PAGE_REGNUM]; + + unsigned page = read_memory_unsigned_integer (page_addr, 1); + addr -= 0x08000; + addr += ((page & 0x0ff) << 14); + addr += 0x1000000; + } fi->extra_info->return_pc = addr; -#if 0 - printf ("Pc@0x%04x, FR 0x%04x, size %d, read ret @0x%04x -> 0x%04x\n", - fi->pc, - fi->frame, fi->size, - addr & 0x0ffff, - fi->return_pc); -#endif } } @@ -786,11 +884,18 @@ show_regs (char *args, int from_tty) ccr & M6811_V_BIT ? 'V' : '-', ccr & M6811_C_BIT ? 'C' : '-'); - printf_filtered ("D=%04x IX=%04x IY=%04x\n", + printf_filtered ("D=%04x IX=%04x IY=%04x", (int) read_register (HARD_D_REGNUM), (int) read_register (HARD_X_REGNUM), (int) read_register (HARD_Y_REGNUM)); + if (USE_PAGE_REGISTER) + { + printf_filtered (" Page=%02x", + (int) read_register (HARD_PAGE_REGNUM)); + } + printf_filtered ("\n"); + nr = 0; for (i = SOFT_D1_REGNUM; i < M68HC11_ALL_REGS; i++) { @@ -1044,6 +1149,21 @@ m68hc11_register_raw_size (int reg_nr) } } +/* Test whether the ELF symbol corresponds to a function using rtc or + rti to return. */ + +static void +m68hc11_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym) +{ + unsigned char flags; + + flags = ((elf_symbol_type *)sym)->internal_elf_sym.st_other; + if (flags & STO_M68HC12_FAR) + MSYMBOL_SET_RTC (msym); + if (flags & STO_M68HC12_INTERRUPT) + MSYMBOL_SET_RTI (msym); +} + static int gdb_print_insn_m68hc11 (bfd_vma memaddr, disassemble_info *info) { @@ -1092,11 +1212,13 @@ m68hc11_gdbarch_init (struct gdbarch_info info, { case bfd_arch_m68hc11: tdep->stack_correction = 1; + tdep->use_page_register = 0; tdep->prologue = m6811_prologue; break; case bfd_arch_m68hc12: tdep->stack_correction = 0; + tdep->use_page_register = elf_flags & E_M68HC12_BANKS; tdep->prologue = m6812_prologue; break; @@ -1198,6 +1320,10 @@ m68hc11_gdbarch_init (struct gdbarch_info info, set_gdbarch_stack_align (gdbarch, m68hc11_stack_align); set_gdbarch_print_insn (gdbarch, gdb_print_insn_m68hc11); + /* Minsymbol frobbing. */ + set_gdbarch_elf_make_msymbol_special (gdbarch, + m68hc11_elf_make_msymbol_special); + set_gdbarch_believe_pcc_promotion (gdbarch, 1); return gdbarch; |