#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
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 *
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