From 908f682f971deccd9287e2c22cf8a3ad6effa11d Mon Sep 17 00:00:00 2001 From: Stephane Carrez Date: Sat, 2 Dec 2000 16:55:37 +0000 Subject: [PATCH] 2000-12-03 Stephane Carrez * m68hc11-tdep.c (m68hc11_frame_args_address): Fix args address computation. (m68hc11_frame_init_saved_regs): Frame pointer is saved only if the symbol exist. (m68hc11_analyze_instruction): New function. (m6811_prologue, m6812_prologue): New prologue description tables. (m68hc11_guess_from_prologue): Use the above. (m68hc11_gdbarch_init): Setup gdbarch_tdep for the prologue descriptions. --- gdb/ChangeLog | 12 ++ gdb/m68hc11-tdep.c | 385 +++++++++++++++++++++++++-------------------- 2 files changed, 229 insertions(+), 168 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6e05b5e017a..4fd100fc01e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2000-12-03 Stephane Carrez + + * m68hc11-tdep.c (m68hc11_frame_args_address): Fix args address + computation. + (m68hc11_frame_init_saved_regs): Frame pointer is saved only if + the symbol exist. + (m68hc11_analyze_instruction): New function. + (m6811_prologue, m6812_prologue): New prologue description tables. + (m68hc11_guess_from_prologue): Use the above. + (m68hc11_gdbarch_init): Setup gdbarch_tdep for the prologue + descriptions. + Sun Dec 3 02:28:26 2000 Andrew Cagney * ser-pipe.c (pipe_open): Only use vfork when available. diff --git a/gdb/m68hc11-tdep.c b/gdb/m68hc11-tdep.c index 197c4a42f21..92b738cd37a 100644 --- a/gdb/m68hc11-tdep.c +++ b/gdb/m68hc11-tdep.c @@ -1,4 +1,4 @@ -/* Target-dependent code for Motorola 68HC11 +/* Target-dependent code for Motorola 68HC11 & 68HC12 Copyright (C) 1999, 2000 Free Software Foundation, Inc. Contributed by Stephane Carrez, stcarrez@worldnet.fr @@ -77,6 +77,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define M68HC11_REG_SIZE (2) +struct insn_sequence; struct gdbarch_tdep { /* from the elf header */ @@ -87,6 +88,9 @@ struct gdbarch_tdep the address where the last value is saved. For 68hc12, the stack pointer points to the last value pushed. No offset is necessary. */ int stack_correction; + + /* Description of instructions in the prologue. */ + struct insn_sequence *prologue; }; #define M6811_TDEP gdbarch_tdep (current_gdbarch) @@ -298,7 +302,7 @@ m68hc11_frame_saved_pc (struct frame_info *frame) static CORE_ADDR m68hc11_frame_args_address (struct frame_info *frame) { - return frame->frame; + return frame->frame + frame->extra_info->size + STACK_CORRECTION + 2; } static CORE_ADDR @@ -337,6 +341,176 @@ m68hc11_pop_frame (void) flush_cached_frames (); } + +/* 68HC11 & 68HC12 prologue analysis. + + */ +#define MAX_CODES 12 + +/* 68HC11 opcodes. */ +#undef M6811_OP_PAGE2 +#define M6811_OP_PAGE2 (0x18) +#define M6811_OP_LDX (0xde) +#define M6811_OP_PSHX (0x3c) +#define M6811_OP_STS (0x9f) +#define M6811_OP_TSX (0x30) +#define M6811_OP_XGDX (0x8f) +#define M6811_OP_ADDD (0xc3) +#define M6811_OP_TXS (0x35) +#define M6811_OP_DES (0x34) + +/* 68HC12 opcodes. */ +#define M6812_OP_PAGE2 (0x18) +#define M6812_OP_MOVW (0x01) +#define M6812_PB_PSHW (0xae) +#define M6812_OP_STS (0x7f) +#define M6812_OP_LEAS (0x1b) + +/* Operand extraction. */ +#define OP_DIRECT (0x100) /* 8-byte direct addressing. */ +#define OP_IMM_LOW (0x200) /* Low part of 16-bit constant/address. */ +#define OP_IMM_HIGH (0x300) /* High part of 16-bit constant/address. */ +#define OP_PBYTE (0x400) /* 68HC12 indexed operand. */ + +/* Identification of the sequence. */ +enum m6811_seq_type +{ + P_LAST = 0, + P_SAVE_REG, /* Save a register on the stack. */ + P_SET_FRAME, /* Setup the frame pointer. */ + P_LOCAL_1, /* Allocate 1 byte for locals. */ + P_LOCAL_2, /* Allocate 2 bytes for locals. */ + P_LOCAL_N /* Allocate N bytes for locals. */ +}; + +struct insn_sequence { + enum m6811_seq_type type; + unsigned length; + unsigned short code[MAX_CODES]; +}; + +/* Sequence of instructions in the 68HC11 function prologue. */ +static struct insn_sequence m6811_prologue[] = { + /* Sequences to save a soft-register. */ + { P_SAVE_REG, 3, { M6811_OP_LDX, OP_DIRECT, + M6811_OP_PSHX } }, + { P_SAVE_REG, 5, { M6811_OP_PAGE2, M6811_OP_LDX, OP_DIRECT, + M6811_OP_PAGE2, M6811_OP_PSHX } }, + + /* Sequences to allocate local variables. */ + { P_LOCAL_N, 7, { M6811_OP_TSX, + M6811_OP_XGDX, + M6811_OP_ADDD, OP_IMM_HIGH, OP_IMM_LOW, + M6811_OP_XGDX, + M6811_OP_TXS } }, + { P_LOCAL_N, 11, { M6811_OP_PAGE2, M6811_OP_TSX, + M6811_OP_PAGE2, M6811_OP_XGDX, + M6811_OP_ADDD, OP_IMM_HIGH, OP_IMM_LOW, + M6811_OP_PAGE2, M6811_OP_XGDX, + M6811_OP_PAGE2, M6811_OP_TXS } }, + { P_LOCAL_1, 1, { M6811_OP_DES } }, + { P_LOCAL_2, 1, { M6811_OP_PSHX } }, + { P_LOCAL_2, 2, { M6811_OP_PAGE2, M6811_OP_PSHX } }, + + /* Initialize the frame pointer. */ + { P_SET_FRAME, 2, { M6811_OP_STS, OP_DIRECT } }, + { P_LAST, 0, { 0 } } +}; + + +/* Sequence of instructions in the 68HC12 function prologue. */ +static struct insn_sequence m6812_prologue[] = { + { P_SAVE_REG, 5, { M6812_OP_PAGE2, M6812_OP_MOVW, M6812_PB_PSHW, + OP_IMM_HIGH, OP_IMM_LOW } }, + { P_SET_FRAME, 3, { M6812_OP_STS, OP_IMM_HIGH, OP_IMM_LOW } }, + { P_LOCAL_N, 2, { M6812_OP_LEAS, OP_PBYTE } }, + { P_LAST, 0 } +}; + + +/* Analyze the sequence of instructions starting at the given address. + Returns a pointer to the sequence when it is recognized and + the optional value (constant/address) associated with it. + Advance the pc for the next sequence. */ +static struct insn_sequence * +m68hc11_analyze_instruction (struct insn_sequence *seq, CORE_ADDR *pc, + CORE_ADDR *val) +{ + unsigned char buffer[MAX_CODES]; + unsigned bufsize; + unsigned j; + CORE_ADDR cur_val; + short v = 0; + + bufsize = 0; + for (; seq->type != P_LAST; seq++) + { + cur_val = 0; + for (j = 0; j < seq->length; j++) + { + if (bufsize < j + 1) + { + buffer[bufsize] = read_memory_unsigned_integer (*pc + bufsize, + 1); + bufsize++; + } + /* Continue while we match the opcode. */ + if (seq->code[j] == buffer[j]) + continue; + + if ((seq->code[j] & 0xf00) == 0) + break; + + /* Extract a sequence parameter (address or constant). */ + switch (seq->code[j]) + { + case OP_DIRECT: + cur_val = (CORE_ADDR) buffer[j]; + break; + + case OP_IMM_HIGH: + cur_val = cur_val & 0x0ff; + cur_val |= (buffer[j] << 8); + break; + + case OP_IMM_LOW: + cur_val &= 0x0ff00; + cur_val |= buffer[j]; + break; + + case OP_PBYTE: + if ((buffer[j] & 0xE0) == 0x80) + { + v = buffer[j] & 0x1f; + if (v & 0x10) + v |= 0xfff0; + } + else if ((buffer[j] & 0xfe) == 0xf0) + { + v = read_memory_unsigned_integer (*pc + j + 1, 1); + if (buffer[j] & 1) + v |= 0xff00; + } + else if (buffer[j] == 0xf2) + { + v = read_memory_unsigned_integer (*pc + j + 1, 2); + } + cur_val = v; + break; + } + } + + /* We have a full match. */ + if (j == seq->length) + { + *val = cur_val; + *pc = *pc + j; + return seq; + } + } + return 0; +} + /* Analyze the function prologue to find some information about the function: - the PC of the first line (for m68hc11_skip_prologue) @@ -349,13 +523,12 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR fp, { CORE_ADDR save_addr; CORE_ADDR func_end; - unsigned char op0, op1, op2; - int add_sp_mode; - int sp_adjust = 0; int size; int found_frame_point; int saved_reg; CORE_ADDR first_pc; + int done = 0; + struct insn_sequence *seq_table; first_pc = get_pc_function_start (pc); size = 0; @@ -368,21 +541,8 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR fp, return; } -#define OP_PAGE2 (0x18) -#define OP_LDX (0xde) -#define OP_LDY (0xde) -#define OP_PSHX (0x3c) -#define OP_PSHY (0x3c) -#define OP_STS (0x9f) -#define OP_TSX (0x30) -#define OP_TSY (0x30) -#define OP_XGDX (0x8f) -#define OP_XGDY (0x8f) -#define OP_ADDD (0xc3) -#define OP_TXS (0x35) -#define OP_TYS (0x35) -#define OP_DES (0x34) - + seq_table = gdbarch_tdep (current_gdbarch)->prologue; + /* The 68hc11 stack is as follows: @@ -426,169 +586,55 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR fp, */ pc = first_pc; func_end = pc + 128; - add_sp_mode = 0; found_frame_point = 0; - while (pc + 2 < func_end) + *frame_offset = 0; + save_addr = fp; + while (!done && pc + 2 < func_end) { - op0 = read_memory_unsigned_integer (pc, 1); - op1 = read_memory_unsigned_integer (pc + 1, 1); - op2 = read_memory_unsigned_integer (pc + 2, 1); + struct insn_sequence *seq; + CORE_ADDR val; - /* ldx *frame */ - if (op0 == OP_LDX && op1 == M68HC11_FP_ADDR) - { - pc += 2; - } + seq = m68hc11_analyze_instruction (seq_table, &pc, &val); + if (seq == 0) + break; - /* ldy *frame */ - else if (op0 == OP_PAGE2 && op1 == OP_LDY - && op2 == M68HC11_FP_ADDR) + if (seq->type == P_SAVE_REG) { - pc += 3; - } - - /* pshx */ - else if (op0 == OP_PSHX) - { - pc += 1; - size += 2; - } + if (found_frame_point) + { + saved_reg = m68hc11_which_soft_register (val); + if (saved_reg < 0) + break; - /* pshy */ - else if (op0 == OP_PAGE2 && op1 == OP_PSHX) - { - pc += 2; - size += 2; + save_addr -= 2; + if (pushed_regs) + pushed_regs[saved_reg] = save_addr; + } + else + { + size += 2; + } } - - /* sts *frame */ - else if (op0 == OP_STS && op1 == M68HC11_FP_ADDR) + else if (seq->type == P_SET_FRAME) { found_frame_point = 1; - pc += 2; - break; + *frame_offset = size; } - else if (op0 == OP_TSX && op1 == OP_XGDX) + else if (seq->type == P_LOCAL_1) { - add_sp_mode = 1; - pc += 2; - } - /* des to allocate 1 byte on the stack */ - else if (op0 == OP_DES) - { - pc += 1; size += 1; } - else if (op0 == OP_PAGE2 && op1 == OP_TSY && op2 == OP_PAGE2) - { - op0 = read_memory_unsigned_integer (pc + 3, 1); - if (op0 != OP_XGDY) - break; - - add_sp_mode = 2; - pc += 4; - } - else if (add_sp_mode && op0 == OP_ADDD) - { - sp_adjust = read_memory_unsigned_integer (pc + 1, 2); - if (sp_adjust & 0x8000) - sp_adjust |= 0xffff0000L; - - sp_adjust = -sp_adjust; - add_sp_mode |= 4; - pc += 3; - } - else if (add_sp_mode == (1 | 4) && op0 == OP_XGDX - && op1 == OP_TXS) - { - size += sp_adjust; - pc += 2; - add_sp_mode = 0; - } - else if (add_sp_mode == (2 | 4) && op0 == OP_PAGE2 - && op1 == OP_XGDY && op2 == OP_PAGE2) - { - op0 = read_memory_unsigned_integer (pc + 3, 1); - if (op0 != OP_TYS) - break; - - size += sp_adjust; - pc += 4; - add_sp_mode = 0; - } - else - { - break; - } - } - - if (found_frame_point == 0) - { - *frame_offset = 0; - } - else - { - *frame_offset = size; - } - - /* Now, look forward to see how many registers are pushed on the stack. - We look only for soft registers so there must be a first LDX *REG - before a PSHX. */ - saved_reg = -1; - save_addr = fp; - while (pc + 2 < func_end) - { - op0 = read_memory_unsigned_integer (pc, 1); - op1 = read_memory_unsigned_integer (pc + 1, 1); - op2 = read_memory_unsigned_integer (pc + 2, 1); - if (op0 == OP_LDX) - { - saved_reg = m68hc11_which_soft_register (op1); - if (saved_reg < 0 || saved_reg == SOFT_FP_REGNUM) - break; - - pc += 2; - } - else if (op0 == OP_PAGE2 && op1 == OP_LDY) + else if (seq->type == P_LOCAL_2) { - saved_reg = m68hc11_which_soft_register (op2); - if (saved_reg < 0 || saved_reg == SOFT_FP_REGNUM) - break; - - pc += 3; - } - else if (op0 == OP_PSHX) - { - /* If there was no load, this is a push for a function call. */ - if (saved_reg < 0 || saved_reg >= M68HC11_ALL_REGS) - break; - - /* Keep track of the address where that register is saved - on the stack. */ - save_addr -= 2; - if (pushed_regs) - pushed_regs[saved_reg] = save_addr; - - pc += 1; - saved_reg = -1; - } - else if (op0 == OP_PAGE2 && op1 == OP_PSHY) - { - if (saved_reg < 0 || saved_reg >= M68HC11_ALL_REGS) - break; - - /* Keep track of the address where that register is saved - on the stack. */ - save_addr -= 2; - if (pushed_regs) - pushed_regs[saved_reg] = save_addr; - - pc += 2; - saved_reg = -1; + size += 2; } - else + else if (seq->type == P_LOCAL_N) { - break; + /* Stack pointer is decremented for the allocation. */ + if (val & 0x8000) + size -= (int) (val) | 0xffff0000; + else + size -= val; } } *first_line = pc; @@ -668,7 +714,8 @@ m68hc11_frame_init_saved_regs (struct frame_info *fi) fi->saved_regs); addr = fi->frame + fi->extra_info->size + STACK_CORRECTION; - fi->saved_regs[SOFT_FP_REGNUM] = addr - 2; + if (soft_regs[SOFT_FP_REGNUM].name) + fi->saved_regs[SOFT_FP_REGNUM] = addr - 2; fi->saved_regs[HARD_SP_REGNUM] = addr; fi->saved_regs[HARD_PC_REGNUM] = fi->saved_regs[HARD_SP_REGNUM]; } @@ -1009,10 +1056,12 @@ m68hc11_gdbarch_init (struct gdbarch_info info, { case bfd_arch_m68hc11: tdep->stack_correction = 1; + tdep->prologue = m6811_prologue; break; case bfd_arch_m68hc12: tdep->stack_correction = 0; + tdep->prologue = m6812_prologue; break; default: -- 2.30.2