123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- /* Target-dependent code for the S12Z, for the GDB.
- Copyright (C) 2018-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- /* Much of this file is shamelessly copied from or1k-tdep.c and others. */
- #include "defs.h"
- #include "arch-utils.h"
- #include "dwarf2/frame.h"
- #include "gdbsupport/errors.h"
- #include "frame-unwind.h"
- #include "gdbcore.h"
- #include "gdbcmd.h"
- #include "inferior.h"
- #include "opcode/s12z.h"
- #include "trad-frame.h"
- #include "remote.h"
- #include "opcodes/s12z-opc.h"
- #include "gdbarch.h"
- #include "disasm.h"
- /* Two of the registers included in S12Z_N_REGISTERS are
- the CCH and CCL "registers" which are just views into
- the CCW register. */
- #define N_PHYSICAL_REGISTERS (S12Z_N_REGISTERS - 2)
- /* A permutation of all the physical registers. Indexing this array
- with an integer from gdb's internal representation will return the
- register enum. */
- static const int reg_perm[N_PHYSICAL_REGISTERS] =
- {
- REG_D0,
- REG_D1,
- REG_D2,
- REG_D3,
- REG_D4,
- REG_D5,
- REG_D6,
- REG_D7,
- REG_X,
- REG_Y,
- REG_S,
- REG_P,
- REG_CCW
- };
- /* The inverse of the above permutation. Indexing this
- array with a register enum (e.g. REG_D2) will return the register
- number in gdb's internal representation. */
- static const int inv_reg_perm[N_PHYSICAL_REGISTERS] =
- {
- 2, 3, 4, 5, /* d2, d3, d4, d5 */
- 0, 1, /* d0, d1 */
- 6, 7, /* d6, d7 */
- 8, 9, 10, 11, 12 /* x, y, s, p, ccw */
- };
- /* Return the name of the register REGNUM. */
- static const char *
- s12z_register_name (struct gdbarch *gdbarch, int regnum)
- {
- /* Registers is declared in opcodes/s12z.h. */
- return registers[reg_perm[regnum]].name;
- }
- static CORE_ADDR
- s12z_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- CORE_ADDR start_pc = 0;
- if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
- {
- CORE_ADDR prologue_end = skip_prologue_using_sal (gdbarch, pc);
- if (prologue_end != 0)
- return prologue_end;
- }
- warning (_("%s Failed to find end of prologue PC = %08x"),
- __FUNCTION__, (unsigned int) pc);
- return pc;
- }
- static struct type *
- s12z_register_type (struct gdbarch *gdbarch, int reg_nr)
- {
- switch (registers[reg_perm[reg_nr]].bytes)
- {
- case 1:
- return builtin_type (gdbarch)->builtin_uint8;
- case 2:
- return builtin_type (gdbarch)->builtin_uint16;
- case 3:
- return builtin_type (gdbarch)->builtin_uint24;
- case 4:
- return builtin_type (gdbarch)->builtin_uint32;
- default:
- return builtin_type (gdbarch)->builtin_uint32;
- }
- return builtin_type (gdbarch)->builtin_int0;
- }
- static int
- s12z_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int num)
- {
- switch (num)
- {
- case 15: return REG_S;
- case 7: return REG_X;
- case 8: return REG_Y;
- case 42: return REG_D0;
- case 43: return REG_D1;
- case 44: return REG_D2;
- case 45: return REG_D3;
- case 46: return REG_D4;
- case 47: return REG_D5;
- case 48: return REG_D6;
- case 49: return REG_D7;
- }
- return -1;
- }
- /* Support functions for frame handling. */
- /* Return a disassemble_info initialized for s12z disassembly, however,
- the disassembler will not actually print anything. */
- static struct disassemble_info
- s12z_disassemble_info (struct gdbarch *gdbarch)
- {
- struct disassemble_info di;
- init_disassemble_info_for_no_printing (&di);
- di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
- di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
- di.endian = gdbarch_byte_order (gdbarch);
- di.read_memory_func = [](bfd_vma memaddr, gdb_byte *myaddr,
- unsigned int len, struct disassemble_info *info)
- {
- return target_read_code (memaddr, myaddr, len);
- };
- 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 disassembler 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 *
- s12z_frame_cache (struct frame_info *this_frame, void **prologue_cache)
- {
- struct trad_frame_cache *info;
- CORE_ADDR this_sp;
- CORE_ADDR this_sp_for_id;
- CORE_ADDR start_addr;
- CORE_ADDR end_addr;
- /* Nothing to do if we already have this info. */
- if (NULL != *prologue_cache)
- return (struct trad_frame_cache *) *prologue_cache;
- /* Get a new prologue cache and populate it with default values. */
- info = trad_frame_cache_zalloc (this_frame);
- *prologue_cache = info;
- /* Find the start address of this function (which is a normal frame, even
- if the next frame is the sentinel frame) and the end of its prologue. */
- CORE_ADDR this_pc = get_frame_pc (this_frame);
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- find_pc_partial_function (this_pc, NULL, &start_addr, NULL);
- /* Get the stack pointer if we have one (if there's no process executing
- yet we won't have a frame. */
- this_sp = (NULL == this_frame) ? 0 :
- get_frame_register_unsigned (this_frame, REG_S);
- /* Return early if GDB couldn't find the function. */
- if (start_addr == 0)
- {
- warning (_("Couldn't find function including address %s SP is %s"),
- paddress (gdbarch, this_pc),
- paddress (gdbarch, this_sp));
- /* JPB: 28-Apr-11. This is a temporary patch, to get round GDB
- crashing right at the beginning. Build the frame ID as best we
- can. */
- trad_frame_set_id (info, frame_id_build (this_sp, this_pc));
- return info;
- }
- /* The default frame base of this frame (for ID purposes only - frame
- base is an overloaded term) is its stack pointer. For now we use the
- value of the SP register in this frame. However if the PC is in the
- prologue of this frame, before the SP has been set up, then the value
- will actually be that of the prev frame, and we'll need to adjust it
- later. */
- trad_frame_set_this_base (info, this_sp);
- this_sp_for_id = this_sp;
- /* We should only examine code that is in the prologue. This is all code
- up to (but not including) end_addr. We should only populate the cache
- while the address is up to (but not including) the PC or end_addr,
- whichever is first. */
- end_addr = s12z_skip_prologue (gdbarch, start_addr);
- /* All the following analysis only occurs if we are in the prologue and
- have executed the code. Check we have a sane prologue size, and if
- zero we are frameless and can give up here. */
- if (end_addr < start_addr)
- error (_("end addr %s is less than start addr %s"),
- paddress (gdbarch, end_addr), paddress (gdbarch, start_addr));
- CORE_ADDR addr = start_addr; /* Where we have got to? */
- int frame_size = 0;
- int saved_frame_size = 0;
- struct disassemble_info di = s12z_disassemble_info (gdbarch);
- 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;
- 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
- base will be wrong, and we adjust it. */
- if (this_pc < addr)
- {
- /* Only do if executing. */
- if (0 != this_sp)
- {
- this_sp_for_id = this_sp - frame_size;
- trad_frame_set_this_base (info, this_sp_for_id);
- }
- trad_frame_set_reg_value (info, REG_S, this_sp + 3);
- trad_frame_set_reg_addr (info, REG_P, this_sp);
- }
- else
- {
- gdb_assert (this_sp == this_sp_for_id);
- /* The stack pointer of the prev frame is frame_size greater
- than the stack pointer of this frame plus one address
- size (caused by the JSR or BSR). */
- trad_frame_set_reg_value (info, REG_S,
- this_sp + frame_size + 3);
- trad_frame_set_reg_addr (info, REG_P, this_sp + frame_size);
- }
- /* Build the frame ID. */
- trad_frame_set_id (info, frame_id_build (this_sp_for_id, start_addr));
- return info;
- }
- /* Implement the this_id function for the stub unwinder. */
- static void
- s12z_frame_this_id (struct frame_info *this_frame,
- void **prologue_cache, struct frame_id *this_id)
- {
- struct trad_frame_cache *info = s12z_frame_cache (this_frame,
- prologue_cache);
- trad_frame_get_id (info, this_id);
- }
- /* Implement the prev_register function for the stub unwinder. */
- static struct value *
- s12z_frame_prev_register (struct frame_info *this_frame,
- void **prologue_cache, int regnum)
- {
- struct trad_frame_cache *info = s12z_frame_cache (this_frame,
- prologue_cache);
- return trad_frame_get_register (info, this_frame, regnum);
- }
- /* Data structures for the normal prologue-analysis-based unwinder. */
- static const struct frame_unwind s12z_frame_unwind = {
- "s12z prologue",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- s12z_frame_this_id,
- s12z_frame_prev_register,
- NULL,
- default_frame_sniffer,
- NULL,
- };
- constexpr gdb_byte s12z_break_insn[] = {0x00};
- typedef BP_MANIPULATION (s12z_break_insn) s12z_breakpoint;
- struct s12z_gdbarch_tdep : gdbarch_tdep
- {
- };
- /* A vector of human readable characters representing the
- bits in the CCW register. Unused bits are represented as '-'.
- Lowest significant bit comes first. */
- static const char ccw_bits[] =
- {
- 'C', /* Carry */
- 'V', /* Two's Complement Overflow */
- 'Z', /* Zero */
- 'N', /* Negative */
- 'I', /* Interrupt */
- '-',
- 'X', /* Non-Maskable Interrupt */
- 'S', /* STOP Disable */
- '0', /* Interrupt priority level */
- '0', /* ditto */
- '0', /* ditto */
- '-',
- '-',
- '-',
- '-',
- 'U' /* User/Supervisor State. */
- };
- /* Print a human readable representation of the CCW register.
- For example: "u----000SX-Inzvc" corresponds to the value
- 0xD0. */
- static void
- s12z_print_ccw_info (struct gdbarch *gdbarch,
- struct ui_file *file,
- struct frame_info *frame,
- int reg)
- {
- struct value *v = value_of_register (reg, frame);
- const char *name = gdbarch_register_name (gdbarch, reg);
- uint32_t ccw = value_as_long (v);
- gdb_puts (name, file);
- size_t len = strlen (name);
- const int stop_1 = 15;
- const int stop_2 = 17;
- for (int i = 0; i < stop_1 - len; ++i)
- gdb_putc (' ', file);
- gdb_printf (file, "0x%04x", ccw);
- for (int i = 0; i < stop_2 - len; ++i)
- gdb_putc (' ', file);
- for (int b = 15; b >= 0; --b)
- {
- if (ccw & (0x1u << b))
- {
- if (ccw_bits[b] == 0)
- gdb_putc ('1', file);
- else
- gdb_putc (ccw_bits[b], file);
- }
- else
- gdb_putc (tolower (ccw_bits[b]), file);
- }
- gdb_putc ('\n', file);
- }
- static void
- s12z_print_registers_info (struct gdbarch *gdbarch,
- struct ui_file *file,
- struct frame_info *frame,
- int regnum, int print_all)
- {
- const int numregs = (gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch));
- if (regnum == -1)
- {
- for (int reg = 0; reg < numregs; reg++)
- {
- if (REG_CCW == reg_perm[reg])
- {
- s12z_print_ccw_info (gdbarch, file, frame, reg);
- continue;
- }
- default_print_registers_info (gdbarch, file, frame, reg, print_all);
- }
- }
- else if (REG_CCW == reg_perm[regnum])
- s12z_print_ccw_info (gdbarch, file, frame, regnum);
- else
- default_print_registers_info (gdbarch, file, frame, regnum, print_all);
- }
- static void
- s12z_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
- {
- int reg = -1;
- switch (TYPE_LENGTH (type))
- {
- case 0: /* Nothing to do */
- return;
- case 1:
- reg = REG_D0;
- break;
- case 2:
- reg = REG_D2;
- break;
- case 3:
- reg = REG_X;
- break;
- case 4:
- reg = REG_D6;
- break;
- default:
- error (_("bad size for return value"));
- return;
- }
- regcache->cooked_read (inv_reg_perm[reg], (gdb_byte *) valbuf);
- }
- static enum return_value_convention
- s12z_return_value (struct gdbarch *gdbarch, struct value *function,
- struct type *type, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
- {
- if (type->code () == TYPE_CODE_STRUCT
- || type->code () == TYPE_CODE_UNION
- || type->code () == TYPE_CODE_ARRAY
- || TYPE_LENGTH (type) > 4)
- return RETURN_VALUE_STRUCT_CONVENTION;
- if (readbuf)
- s12z_extract_return_value (type, regcache, readbuf);
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- static void
- show_bdccsr_command (const char *args, int from_tty)
- {
- struct string_file output;
- target_rcmd ("bdccsr", &output);
- gdb_printf ("The current BDCCSR value is %s\n", output.string().c_str());
- }
- static struct gdbarch *
- s12z_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
- {
- s12z_gdbarch_tdep *tdep = new s12z_gdbarch_tdep;
- struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
- add_cmd ("bdccsr", class_support, show_bdccsr_command,
- _("Show the current value of the microcontroller's BDCCSR."),
- &maintenanceinfolist);
- /* Target data types. */
- set_gdbarch_short_bit (gdbarch, 16);
- set_gdbarch_int_bit (gdbarch, 16);
- set_gdbarch_long_bit (gdbarch, 32);
- set_gdbarch_long_long_bit (gdbarch, 32);
- set_gdbarch_ptr_bit (gdbarch, 24);
- set_gdbarch_addr_bit (gdbarch, 24);
- set_gdbarch_char_signed (gdbarch, 0);
- set_gdbarch_ps_regnum (gdbarch, REG_CCW);
- set_gdbarch_pc_regnum (gdbarch, REG_P);
- set_gdbarch_sp_regnum (gdbarch, REG_S);
- set_gdbarch_print_registers_info (gdbarch, s12z_print_registers_info);
- set_gdbarch_breakpoint_kind_from_pc (gdbarch,
- s12z_breakpoint::kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch,
- s12z_breakpoint::bp_from_kind);
- set_gdbarch_num_regs (gdbarch, N_PHYSICAL_REGISTERS);
- set_gdbarch_register_name (gdbarch, s12z_register_name);
- set_gdbarch_skip_prologue (gdbarch, s12z_skip_prologue);
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, s12z_dwarf_reg_to_regnum);
- set_gdbarch_register_type (gdbarch, s12z_register_type);
- frame_unwind_append_unwinder (gdbarch, &s12z_frame_unwind);
- /* Currently, the only known producer for this architecture, produces buggy
- dwarf CFI. So don't append a dwarf unwinder until the situation is
- better understood. */
- set_gdbarch_return_value (gdbarch, s12z_return_value);
- return gdbarch;
- }
- void _initialize_s12z_tdep ();
- void
- _initialize_s12z_tdep ()
- {
- gdbarch_register (bfd_arch_s12z, s12z_gdbarch_init, NULL);
- }
|