diff options
-rw-r--r-- | gdb/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/s12z-tdep.c | 234 |
2 files changed, 178 insertions, 63 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c82d70f..6c23281 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2019-05-15 John Darrington <john@darrington.wattle.id.au> + + * s12z-tdep.c (push_pull_get_stack_adjustment): New function. + (advance, posn, abstract_read_memory): New functions. + [struct mem_read_abstraction]: New struct. + (s12z_frame_cache): Use opcodes API to interpret stack frame code. + 2019-05-14 Tom Tromey <tromey@adacore.com> * ada-lang.c (coerce_unspec_val_to_type): Only set address when diff --git a/gdb/s12z-tdep.c b/gdb/s12z-tdep.c index cef92d8..b549862 100644 --- a/gdb/s12z-tdep.c +++ b/gdb/s12z-tdep.c @@ -30,6 +30,7 @@ #include "opcode/s12z.h" #include "trad-frame.h" #include "remote.h" +#include "opcodes/s12z-opc.h" /* Two of the registers included in S12Z_N_REGISTERS are the CCH and CCL "registers" which are just views into @@ -162,6 +163,104 @@ s12z_disassemble_info (struct gdbarch *gdbarch) return di; } + +/* A struct (based on mem_read_abstraction_base) to read memory + through the disassemble_info API. */ +struct mem_read_abstraction +{ + struct mem_read_abstraction_base base; /* The parent struct. */ + bfd_vma memaddr; /* Where to read from. */ + struct disassemble_info* info; /* The disassember to use for reading. */ +}; + +/* Advance the reader by one byte. */ +static void +advance (struct mem_read_abstraction_base *b) +{ + struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; + mra->memaddr++; +} + +/* Return the current position of the reader. */ +static bfd_vma +posn (struct mem_read_abstraction_base *b) +{ + struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; + return mra->memaddr; +} + +/* Read the N bytes at OFFSET using B. The bytes read are stored in BYTES. + It is the caller's responsibility to ensure that this is of at least N + in size. */ +static int +abstract_read_memory (struct mem_read_abstraction_base *b, + int offset, + size_t n, bfd_byte *bytes) +{ + struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; + + int status = + (*mra->info->read_memory_func) (mra->memaddr + offset, + bytes, n, mra->info); + + if (status != 0) + { + (*mra->info->memory_error_func) (status, mra->memaddr, mra->info); + return -1; + } + + return 0; +} + + +/* Return the stack adjustment caused by a push or pull instruction. */ +static int +push_pull_get_stack_adjustment (int n_operands, + struct operand *const *operands) +{ + int stack_adjustment = 0; + gdb_assert (n_operands > 0); + if (operands[0]->cl == OPND_CL_REGISTER_ALL) + stack_adjustment = 26; /* All the regs are involved. */ + else if (operands[0]->cl == OPND_CL_REGISTER_ALL16) + stack_adjustment = 4 * 2; /* All four 16 bit regs are involved. */ + else + for (int i = 0; i < n_operands; ++i) + { + if (operands[i]->cl != OPND_CL_REGISTER) + continue; /* I don't think this can ever happen. */ + const struct register_operand *op + = (const struct register_operand *) operands[i]; + switch (op->reg) + { + case REG_X: + case REG_Y: + stack_adjustment += 3; + break; + case REG_D7: + case REG_D6: + stack_adjustment += 4; + break; + case REG_D2: + case REG_D3: + case REG_D4: + case REG_D5: + stack_adjustment += 2; + break; + case REG_D0: + case REG_D1: + case REG_CCL: + case REG_CCH: + stack_adjustment += 1; + break; + default: + gdb_assert_not_reached ("Invalid register in push/pull operation."); + break; + } + } + return stack_adjustment; +} + /* Initialize a prologue cache. */ static struct trad_frame_cache * @@ -234,73 +333,82 @@ s12z_frame_cache (struct frame_info *this_frame, void **prologue_cache) CORE_ADDR addr = start_addr; /* Where we have got to? */ int frame_size = 0; int saved_frame_size = 0; - while (this_pc > addr) - { - struct disassemble_info di = s12z_disassemble_info (gdbarch); - - /* No instruction can be more than 11 bytes long, I think. */ - gdb_byte buf[11]; - int nb = print_insn_s12z (addr, &di); - gdb_assert (nb <= 11); + struct disassemble_info di = s12z_disassemble_info (gdbarch); - if (0 != target_read_code (addr, buf, nb)) - memory_error (TARGET_XFER_E_IO, addr); - if (buf[0] == 0x05) /* RTS */ - { - frame_size = saved_frame_size; - } - /* Conditional Branches. If any of these are encountered, then - it is likely that a RTS will terminate it. So we need to save - the frame size so it can be restored. */ - else if ( (buf[0] == 0x02) /* BRSET */ - || (buf[0] == 0x0B) /* DBcc / TBcc */ - || (buf[0] == 0x03)) /* BRCLR */ - { - saved_frame_size = frame_size; - } - else if (buf[0] == 0x04) /* PUL/ PSH .. */ - { - bool pull = buf[1] & 0x80; - int stack_adjustment = 0; - if (buf[1] & 0x40) - { - if (buf[1] & 0x01) stack_adjustment += 3; /* Y */ - if (buf[1] & 0x02) stack_adjustment += 3; /* X */ - if (buf[1] & 0x04) stack_adjustment += 4; /* D7 */ - if (buf[1] & 0x08) stack_adjustment += 4; /* D6 */ - if (buf[1] & 0x10) stack_adjustment += 2; /* D5 */ - if (buf[1] & 0x20) stack_adjustment += 2; /* D4 */ - } - else - { - if (buf[1] & 0x01) stack_adjustment += 2; /* D3 */ - if (buf[1] & 0x02) stack_adjustment += 2; /* D2 */ - if (buf[1] & 0x04) stack_adjustment += 1; /* D1 */ - if (buf[1] & 0x08) stack_adjustment += 1; /* D0 */ - if (buf[1] & 0x10) stack_adjustment += 1; /* CCL */ - if (buf[1] & 0x20) stack_adjustment += 1; /* CCH */ - } + struct mem_read_abstraction mra; + mra.base.read = (int (*)(mem_read_abstraction_base*, + int, size_t, bfd_byte*)) abstract_read_memory; + mra.base.advance = advance ; + mra.base.posn = posn; + mra.info = &di; - if (!pull) - stack_adjustment = -stack_adjustment; - frame_size -= stack_adjustment; - } - else if (buf[0] == 0x0a) /* LEA S, (xxx, S) */ - { - if (0x06 == (buf[1] >> 4)) - { - int simm = (signed char) (buf[1] & 0x0F); - frame_size -= simm; - } - } - else if (buf[0] == 0x1a) /* LEA S, (S, xxxx) */ - { - int simm = (signed char) buf[1]; - frame_size -= simm; - } - addr += nb; + while (this_pc > addr) + { + enum optr optr = OP_INVALID; + short osize; + int n_operands = 0; + struct operand *operands[6]; + mra.memaddr = addr; + int n_bytes = + decode_s12z (&optr, &osize, &n_operands, operands, + (mem_read_abstraction_base *) &mra); + + switch (optr) + { + case OP_tbNE: + case OP_tbPL: + case OP_tbMI: + case OP_tbGT: + case OP_tbLE: + case OP_dbNE: + case OP_dbEQ: + case OP_dbPL: + case OP_dbMI: + case OP_dbGT: + case OP_dbLE: + /* Conditional Branches. If any of these are encountered, then + it is likely that a RTS will terminate it. So we need to save + the frame size so it can be restored. */ + saved_frame_size = frame_size; + break; + case OP_rts: + /* Restore the frame size from a previously saved value. */ + frame_size = saved_frame_size; + break; + case OP_push: + frame_size += push_pull_get_stack_adjustment (n_operands, operands); + break; + case OP_pull: + frame_size -= push_pull_get_stack_adjustment (n_operands, operands); + break; + case OP_lea: + if (operands[0]->cl == OPND_CL_REGISTER) + { + int reg = ((struct register_operand *) (operands[0]))->reg; + if ((reg == REG_S) && (operands[1]->cl == OPND_CL_MEMORY)) + { + const struct memory_operand *mo + = (const struct memory_operand * ) operands[1]; + if (mo->n_regs == 1 && !mo->indirect + && mo->regs[0] == REG_S + && mo->mutation == OPND_RM_NONE) + { + /* LEA S, (xxx, S) -- Decrement the stack. This is + almost certainly the start of a frame. */ + int simm = (signed char) mo->base_offset; + frame_size -= simm; + } + } + } + break; + default: + break; + } + addr += n_bytes; + for (int o = 0; o < n_operands; ++o) + free (operands[o]); } /* If the PC has not actually got to this point, then the frame |