| /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger. |
| |
| Copyright (C) 1988-2024 Free Software Foundation, Inc. |
| |
| Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU |
| and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. |
| |
| 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/>. */ |
| |
| #include "extract-store-integer.h" |
| #include "frame.h" |
| #include "inferior.h" |
| #include "symtab.h" |
| #include "value.h" |
| #include "cli/cli-cmds.h" |
| #include "language.h" |
| #include "gdbcore.h" |
| #include "symfile.h" |
| #include "objfiles.h" |
| #include "gdbtypes.h" |
| #include "target.h" |
| #include "arch-utils.h" |
| #include "regcache.h" |
| #include "osabi.h" |
| #include "mips-tdep.h" |
| #include "block.h" |
| #include "reggroups.h" |
| #include "opcode/mips.h" |
| #include "elf/mips.h" |
| #include "elf-bfd.h" |
| #include "symcat.h" |
| #include "sim-regno.h" |
| #include "dis-asm.h" |
| #include "disasm.h" |
| #include "frame-unwind.h" |
| #include "frame-base.h" |
| #include "trad-frame.h" |
| #include "infcall.h" |
| #include "remote.h" |
| #include "target-descriptions.h" |
| #include "dwarf2/frame.h" |
| #include "user-regs.h" |
| #include "valprint.h" |
| #include "ax.h" |
| #include "target-float.h" |
| #include <algorithm> |
| |
| static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum); |
| |
| static int mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, |
| ULONGEST inst); |
| static int micromips_instruction_has_delay_slot (ULONGEST insn, int mustbe32); |
| static int mips16_instruction_has_delay_slot (unsigned short inst, |
| int mustbe32); |
| |
| static int mips32_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch, |
| CORE_ADDR addr); |
| static int micromips_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch, |
| CORE_ADDR addr, int mustbe32); |
| static int mips16_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch, |
| CORE_ADDR addr, int mustbe32); |
| |
| static void mips_print_float_info (struct gdbarch *, struct ui_file *, |
| const frame_info_ptr &, const char *); |
| |
| /* A useful bit in the CP0 status register (MIPS_PS_REGNUM). */ |
| /* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip. */ |
| #define ST0_FR (1 << 26) |
| |
| /* The sizes of floating point registers. */ |
| |
| enum |
| { |
| MIPS_FPU_SINGLE_REGSIZE = 4, |
| MIPS_FPU_DOUBLE_REGSIZE = 8 |
| }; |
| |
| enum |
| { |
| MIPS32_REGSIZE = 4, |
| MIPS64_REGSIZE = 8 |
| }; |
| |
| static const char *mips_abi_string; |
| |
| static const char *const mips_abi_strings[] = { |
| "auto", |
| "n32", |
| "o32", |
| "n64", |
| "o64", |
| "eabi32", |
| "eabi64", |
| NULL |
| }; |
| |
| /* Enum describing the different kinds of breakpoints. */ |
| |
| enum mips_breakpoint_kind |
| { |
| /* 16-bit MIPS16 mode breakpoint. */ |
| MIPS_BP_KIND_MIPS16 = 2, |
| |
| /* 16-bit microMIPS mode breakpoint. */ |
| MIPS_BP_KIND_MICROMIPS16 = 3, |
| |
| /* 32-bit standard MIPS mode breakpoint. */ |
| MIPS_BP_KIND_MIPS32 = 4, |
| |
| /* 32-bit microMIPS mode breakpoint. */ |
| MIPS_BP_KIND_MICROMIPS32 = 5, |
| }; |
| |
| /* For backwards compatibility we default to MIPS16. This flag is |
| overridden as soon as unambiguous ELF file flags tell us the |
| compressed ISA encoding used. */ |
| static const char mips_compression_mips16[] = "mips16"; |
| static const char mips_compression_micromips[] = "micromips"; |
| static const char *const mips_compression_strings[] = |
| { |
| mips_compression_mips16, |
| mips_compression_micromips, |
| NULL |
| }; |
| |
| static const char *mips_compression_string = mips_compression_mips16; |
| |
| /* The standard register names, and all the valid aliases for them. */ |
| struct register_alias |
| { |
| const char *name; |
| int regnum; |
| }; |
| |
| /* Aliases for o32 and most other ABIs. */ |
| const struct register_alias mips_o32_aliases[] = { |
| { "ta0", 12 }, |
| { "ta1", 13 }, |
| { "ta2", 14 }, |
| { "ta3", 15 } |
| }; |
| |
| /* Aliases for n32 and n64. */ |
| const struct register_alias mips_n32_n64_aliases[] = { |
| { "ta0", 8 }, |
| { "ta1", 9 }, |
| { "ta2", 10 }, |
| { "ta3", 11 } |
| }; |
| |
| /* Aliases for ABI-independent registers. */ |
| const struct register_alias mips_register_aliases[] = { |
| /* The architecture manuals specify these ABI-independent names for |
| the GPRs. */ |
| #define R(n) { "r" #n, n } |
| R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), |
| R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), |
| R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), |
| R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), |
| #undef R |
| |
| /* k0 and k1 are sometimes called these instead (for "kernel |
| temp"). */ |
| { "kt0", 26 }, |
| { "kt1", 27 }, |
| |
| /* This is the traditional GDB name for the CP0 status register. */ |
| { "sr", MIPS_PS_REGNUM }, |
| |
| /* This is the traditional GDB name for the CP0 BadVAddr register. */ |
| { "bad", MIPS_EMBED_BADVADDR_REGNUM }, |
| |
| /* This is the traditional GDB name for the FCSR. */ |
| { "fsr", MIPS_EMBED_FP0_REGNUM + 32 } |
| }; |
| |
| const struct register_alias mips_numeric_register_aliases[] = { |
| #define R(n) { #n, n } |
| R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), |
| R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), |
| R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), |
| R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), |
| #undef R |
| }; |
| |
| #ifndef MIPS_DEFAULT_FPU_TYPE |
| #define MIPS_DEFAULT_FPU_TYPE MIPS_FPU_DOUBLE |
| #endif |
| static int mips_fpu_type_auto = 1; |
| static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE; |
| |
| static unsigned int mips_debug = 0; |
| |
| /* Properties (for struct target_desc) describing the g/G packet |
| layout. */ |
| #define PROPERTY_GP32 "internal: transfers-32bit-registers" |
| #define PROPERTY_GP64 "internal: transfers-64bit-registers" |
| |
| struct target_desc *mips_tdesc_gp32; |
| struct target_desc *mips_tdesc_gp64; |
| |
| /* The current set of options to be passed to the disassembler. */ |
| static std::string mips_disassembler_options; |
| |
| /* Implicit disassembler options for individual ABIs. These tell |
| libopcodes to use general-purpose register names corresponding |
| to the ABI we have selected, perhaps via a `set mips abi ...' |
| override, rather than ones inferred from the ABI set in the ELF |
| headers of the binary file selected for debugging. */ |
| static const char mips_disassembler_options_o32[] = "gpr-names=32"; |
| static const char mips_disassembler_options_n32[] = "gpr-names=n32"; |
| static const char mips_disassembler_options_n64[] = "gpr-names=64"; |
| |
| const struct mips_regnum * |
| mips_regnum (struct gdbarch *gdbarch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| return tdep->regnum; |
| } |
| |
| static int |
| mips_fpa0_regnum (struct gdbarch *gdbarch) |
| { |
| return mips_regnum (gdbarch)->fp0 + 12; |
| } |
| |
| /* Return 1 if REGNUM refers to a floating-point general register, raw |
| or cooked. Otherwise return 0. */ |
| |
| static int |
| mips_float_register_p (struct gdbarch *gdbarch, int regnum) |
| { |
| int rawnum = regnum % gdbarch_num_regs (gdbarch); |
| |
| return (rawnum >= mips_regnum (gdbarch)->fp0 |
| && rawnum < mips_regnum (gdbarch)->fp0 + 32); |
| } |
| |
| static bool |
| mips_eabi (gdbarch *arch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (arch); |
| return (tdep->mips_abi == MIPS_ABI_EABI32 \ |
| || tdep->mips_abi == MIPS_ABI_EABI64); |
| } |
| |
| static int |
| mips_last_fp_arg_regnum (gdbarch *arch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (arch); |
| return tdep->mips_last_fp_arg_regnum; |
| } |
| |
| static int |
| mips_last_arg_regnum (gdbarch *arch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (arch); |
| return tdep->mips_last_arg_regnum; |
| } |
| |
| static enum mips_fpu_type |
| mips_get_fpu_type (gdbarch *arch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (arch); |
| return tdep->mips_fpu_type; |
| } |
| |
| /* Return the MIPS ABI associated with GDBARCH. */ |
| enum mips_abi |
| mips_abi (struct gdbarch *gdbarch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| return tdep->mips_abi; |
| } |
| |
| int |
| mips_isa_regsize (struct gdbarch *gdbarch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| |
| /* If we know how big the registers are, use that size. */ |
| if (tdep->register_size_valid_p) |
| return tdep->register_size; |
| |
| /* Fall back to the previous behavior. */ |
| return (gdbarch_bfd_arch_info (gdbarch)->bits_per_word |
| / gdbarch_bfd_arch_info (gdbarch)->bits_per_byte); |
| } |
| |
| /* Max saved register size. */ |
| #define MAX_MIPS_ABI_REGSIZE 8 |
| |
| /* Return the currently configured (or set) saved register size. */ |
| |
| unsigned int |
| mips_abi_regsize (struct gdbarch *gdbarch) |
| { |
| switch (mips_abi (gdbarch)) |
| { |
| case MIPS_ABI_EABI32: |
| case MIPS_ABI_O32: |
| return 4; |
| case MIPS_ABI_N32: |
| case MIPS_ABI_N64: |
| case MIPS_ABI_O64: |
| case MIPS_ABI_EABI64: |
| return 8; |
| case MIPS_ABI_UNKNOWN: |
| case MIPS_ABI_LAST: |
| default: |
| internal_error (_("bad switch")); |
| } |
| } |
| |
| /* MIPS16/microMIPS function addresses are odd (bit 0 is set). Here |
| are some functions to handle addresses associated with compressed |
| code including but not limited to testing, setting, or clearing |
| bit 0 of such addresses. */ |
| |
| /* Return one iff compressed code is the MIPS16 instruction set. */ |
| |
| static int |
| is_mips16_isa (struct gdbarch *gdbarch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| return tdep->mips_isa == ISA_MIPS16; |
| } |
| |
| /* Return one iff compressed code is the microMIPS instruction set. */ |
| |
| static int |
| is_micromips_isa (struct gdbarch *gdbarch) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| return tdep->mips_isa == ISA_MICROMIPS; |
| } |
| |
| /* Return one iff ADDR denotes compressed code. */ |
| |
| static int |
| is_compact_addr (CORE_ADDR addr) |
| { |
| return ((addr) & 1); |
| } |
| |
| /* Return one iff ADDR denotes standard ISA code. */ |
| |
| static int |
| is_mips_addr (CORE_ADDR addr) |
| { |
| return !is_compact_addr (addr); |
| } |
| |
| /* Return one iff ADDR denotes MIPS16 code. */ |
| |
| static int |
| is_mips16_addr (struct gdbarch *gdbarch, CORE_ADDR addr) |
| { |
| return is_compact_addr (addr) && is_mips16_isa (gdbarch); |
| } |
| |
| /* Return one iff ADDR denotes microMIPS code. */ |
| |
| static int |
| is_micromips_addr (struct gdbarch *gdbarch, CORE_ADDR addr) |
| { |
| return is_compact_addr (addr) && is_micromips_isa (gdbarch); |
| } |
| |
| /* Strip the ISA (compression) bit off from ADDR. */ |
| |
| static CORE_ADDR |
| unmake_compact_addr (CORE_ADDR addr) |
| { |
| return ((addr) & ~(CORE_ADDR) 1); |
| } |
| |
| /* Add the ISA (compression) bit to ADDR. */ |
| |
| static CORE_ADDR |
| make_compact_addr (CORE_ADDR addr) |
| { |
| return ((addr) | (CORE_ADDR) 1); |
| } |
| |
| /* Extern version of unmake_compact_addr; we use a separate function |
| so that unmake_compact_addr can be inlined throughout this file. */ |
| |
| CORE_ADDR |
| mips_unmake_compact_addr (CORE_ADDR addr) |
| { |
| return unmake_compact_addr (addr); |
| } |
| |
| /* Functions for setting and testing a bit in a minimal symbol that |
| marks it as MIPS16 or microMIPS function. The MSB of the minimal |
| symbol's "info" field is used for this purpose. |
| |
| gdbarch_elf_make_msymbol_special tests whether an ELF symbol is |
| "special", i.e. refers to a MIPS16 or microMIPS function, and sets |
| one of the "special" bits in a minimal symbol to mark it accordingly. |
| The test checks an ELF-private flag that is valid for true function |
| symbols only; for synthetic symbols such as for PLT stubs that have |
| no ELF-private part at all the MIPS BFD backend arranges for this |
| information to be carried in the asymbol's udata field instead. |
| |
| msymbol_is_mips16 and msymbol_is_micromips test the "special" bit |
| in a minimal symbol. */ |
| |
| static void |
| mips_elf_make_msymbol_special (asymbol * sym, struct minimal_symbol *msym) |
| { |
| elf_symbol_type *elfsym = (elf_symbol_type *) sym; |
| unsigned char st_other; |
| |
| if ((sym->flags & BSF_SYNTHETIC) == 0) |
| st_other = elfsym->internal_elf_sym.st_other; |
| else if ((sym->flags & BSF_FUNCTION) != 0) |
| st_other = sym->udata.i; |
| else |
| return; |
| |
| if (ELF_ST_IS_MICROMIPS (st_other)) |
| { |
| SET_MSYMBOL_TARGET_FLAG_MICROMIPS (msym); |
| CORE_ADDR fixed = CORE_ADDR (msym->unrelocated_address ()) | 1; |
| msym->set_unrelocated_address (unrelocated_addr (fixed)); |
| } |
| else if (ELF_ST_IS_MIPS16 (st_other)) |
| { |
| SET_MSYMBOL_TARGET_FLAG_MIPS16 (msym); |
| CORE_ADDR fixed = CORE_ADDR (msym->unrelocated_address ()) | 1; |
| msym->set_unrelocated_address (unrelocated_addr (fixed)); |
| } |
| } |
| |
| /* Return one iff MSYM refers to standard ISA code. */ |
| |
| static int |
| msymbol_is_mips (struct minimal_symbol *msym) |
| { |
| return !(MSYMBOL_TARGET_FLAG_MIPS16 (msym) |
| || MSYMBOL_TARGET_FLAG_MICROMIPS (msym)); |
| } |
| |
| /* Return one iff MSYM refers to MIPS16 code. */ |
| |
| static int |
| msymbol_is_mips16 (struct minimal_symbol *msym) |
| { |
| return MSYMBOL_TARGET_FLAG_MIPS16 (msym); |
| } |
| |
| /* Return one iff MSYM refers to microMIPS code. */ |
| |
| static int |
| msymbol_is_micromips (struct minimal_symbol *msym) |
| { |
| return MSYMBOL_TARGET_FLAG_MICROMIPS (msym); |
| } |
| |
| /* Set the ISA bit in the main symbol too, complementing the corresponding |
| minimal symbol setting and reflecting the run-time value of the symbol. |
| The need for comes from the ISA bit having been cleared as code in |
| `_bfd_mips_elf_symbol_processing' separated it into the ELF symbol's |
| `st_other' STO_MIPS16 or STO_MICROMIPS annotation, making the values |
| of symbols referring to compressed code different in GDB to the values |
| used by actual code. That in turn makes them evaluate incorrectly in |
| expressions, producing results different to what the same expressions |
| yield when compiled into the program being debugged. */ |
| |
| static void |
| mips_make_symbol_special (struct symbol *sym, struct objfile *objfile) |
| { |
| if (sym->aclass () == LOC_BLOCK) |
| { |
| /* We are in symbol reading so it is OK to cast away constness. */ |
| struct block *block = (struct block *) sym->value_block (); |
| CORE_ADDR compact_block_start; |
| |
| compact_block_start = block->start () | 1; |
| bound_minimal_symbol msym |
| = lookup_minimal_symbol_by_pc (compact_block_start); |
| if (msym.minsym && !msymbol_is_mips (msym.minsym)) |
| { |
| block->set_start (compact_block_start); |
| } |
| } |
| } |
| |
| /* XFER a value from the big/little/left end of the register. |
| Depending on the size of the value it might occupy the entire |
| register or just part of it. Make an allowance for this, aligning |
| things accordingly. */ |
| |
| static void |
| mips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache, |
| int reg_num, int length, |
| enum bfd_endian endian, gdb_byte *in, |
| const gdb_byte *out, int buf_offset) |
| { |
| int reg_offset = 0; |
| |
| gdb_assert (reg_num >= gdbarch_num_regs (gdbarch)); |
| /* Need to transfer the left or right part of the register, based on |
| the targets byte order. */ |
| switch (endian) |
| { |
| case BFD_ENDIAN_BIG: |
| reg_offset = register_size (gdbarch, reg_num) - length; |
| break; |
| case BFD_ENDIAN_LITTLE: |
| reg_offset = 0; |
| break; |
| case BFD_ENDIAN_UNKNOWN: /* Indicates no alignment. */ |
| reg_offset = 0; |
| break; |
| default: |
| internal_error (_("bad switch")); |
| } |
| if (mips_debug) |
| gdb_printf (gdb_stderr, |
| "xfer $%d, reg offset %d, buf offset %d, length %d, ", |
| reg_num, reg_offset, buf_offset, length); |
| if (mips_debug && out != NULL) |
| { |
| int i; |
| gdb_printf (gdb_stdlog, "out "); |
| for (i = 0; i < length; i++) |
| gdb_printf (gdb_stdlog, "%02x", out[buf_offset + i]); |
| } |
| if (in != NULL) |
| regcache->cooked_read_part (reg_num, reg_offset, length, in + buf_offset); |
| if (out != NULL) |
| regcache->cooked_write_part (reg_num, reg_offset, length, out + buf_offset); |
| if (mips_debug && in != NULL) |
| { |
| int i; |
| gdb_printf (gdb_stdlog, "in "); |
| for (i = 0; i < length; i++) |
| gdb_printf (gdb_stdlog, "%02x", in[buf_offset + i]); |
| } |
| if (mips_debug) |
| gdb_printf (gdb_stdlog, "\n"); |
| } |
| |
| /* Determine if a MIPS3 or later cpu is operating in MIPS{1,2} FPU |
| compatiblity mode. A return value of 1 means that we have |
| physical 64-bit registers, but should treat them as 32-bit registers. */ |
| |
| static int |
| mips2_fp_compat (const frame_info_ptr &frame) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not |
| meaningful. */ |
| if (register_size (gdbarch, mips_regnum (gdbarch)->fp0) == 4) |
| return 0; |
| |
| #if 0 |
| /* FIXME drow 2002-03-10: This is disabled until we can do it consistently, |
| in all the places we deal with FP registers. PR gdb/413. */ |
| /* Otherwise check the FR bit in the status register - it controls |
| the FP compatiblity mode. If it is clear we are in compatibility |
| mode. */ |
| if ((get_frame_register_unsigned (frame, MIPS_PS_REGNUM) & ST0_FR) == 0) |
| return 1; |
| #endif |
| |
| return 0; |
| } |
| |
| #define VM_MIN_ADDRESS (CORE_ADDR)0x400000 |
| |
| static CORE_ADDR heuristic_proc_start (struct gdbarch *, CORE_ADDR); |
| |
| /* The list of available "set mips " and "show mips " commands. */ |
| |
| static struct cmd_list_element *setmipscmdlist = NULL; |
| static struct cmd_list_element *showmipscmdlist = NULL; |
| |
| /* Integer registers 0 thru 31 are handled explicitly by |
| mips_register_name(). Processor specific registers 32 and above |
| are listed in the following tables. */ |
| |
| enum |
| { NUM_MIPS_PROCESSOR_REGS = (90 - 32) }; |
| |
| /* Generic MIPS. */ |
| |
| static const char * const mips_generic_reg_names[NUM_MIPS_PROCESSOR_REGS] = { |
| "sr", "lo", "hi", "bad", "cause", "pc", |
| "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
| "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", |
| "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
| "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
| "fsr", "fir", |
| }; |
| |
| /* Names of tx39 registers. */ |
| |
| static const char * const mips_tx39_reg_names[NUM_MIPS_PROCESSOR_REGS] = { |
| "sr", "lo", "hi", "bad", "cause", "pc", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "config", "cache", "debug", "depc", "epc", |
| }; |
| |
| /* Names of registers with Linux kernels. */ |
| static const char * const mips_linux_reg_names[NUM_MIPS_PROCESSOR_REGS] = { |
| "sr", "lo", "hi", "bad", "cause", "pc", |
| "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
| "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", |
| "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
| "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
| "fsr", "fir" |
| }; |
| |
| |
| /* Return the name of the register corresponding to REGNO. */ |
| static const char * |
| mips_register_name (struct gdbarch *gdbarch, int regno) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| /* GPR names for all ABIs other than n32/n64. */ |
| static const char *mips_gpr_names[] = { |
| "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
| "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", |
| "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
| "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", |
| }; |
| |
| /* GPR names for n32 and n64 ABIs. */ |
| static const char *mips_n32_n64_gpr_names[] = { |
| "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
| "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", |
| "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
| "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" |
| }; |
| |
| enum mips_abi abi = mips_abi (gdbarch); |
| |
| /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers, |
| but then don't make the raw register names visible. This (upper) |
| range of user visible register numbers are the pseudo-registers. |
| |
| This approach was adopted accommodate the following scenario: |
| It is possible to debug a 64-bit device using a 32-bit |
| programming model. In such instances, the raw registers are |
| configured to be 64-bits wide, while the pseudo registers are |
| configured to be 32-bits wide. The registers that the user |
| sees - the pseudo registers - match the users expectations |
| given the programming model being used. */ |
| int rawnum = regno % gdbarch_num_regs (gdbarch); |
| if (regno < gdbarch_num_regs (gdbarch)) |
| return ""; |
| |
| /* The MIPS integer registers are always mapped from 0 to 31. The |
| names of the registers (which reflects the conventions regarding |
| register use) vary depending on the ABI. */ |
| if (0 <= rawnum && rawnum < 32) |
| { |
| if (abi == MIPS_ABI_N32 || abi == MIPS_ABI_N64) |
| return mips_n32_n64_gpr_names[rawnum]; |
| else |
| return mips_gpr_names[rawnum]; |
| } |
| else if (tdesc_has_registers (gdbarch_target_desc (gdbarch))) |
| return tdesc_register_name (gdbarch, rawnum); |
| else if (32 <= rawnum && rawnum < gdbarch_num_regs (gdbarch)) |
| { |
| gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS); |
| if (tdep->mips_processor_reg_names[rawnum - 32]) |
| return tdep->mips_processor_reg_names[rawnum - 32]; |
| return ""; |
| } |
| else |
| internal_error (_("mips_register_name: bad register number %d"), rawnum); |
| } |
| |
| /* Return the groups that a MIPS register can be categorised into. */ |
| |
| static int |
| mips_register_reggroup_p (struct gdbarch *gdbarch, int regnum, |
| const struct reggroup *reggroup) |
| { |
| int vector_p; |
| int float_p; |
| int raw_p; |
| int rawnum = regnum % gdbarch_num_regs (gdbarch); |
| int pseudo = regnum / gdbarch_num_regs (gdbarch); |
| if (reggroup == all_reggroup) |
| return pseudo; |
| vector_p = register_type (gdbarch, regnum)->is_vector (); |
| float_p = register_type (gdbarch, regnum)->code () == TYPE_CODE_FLT; |
| /* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs |
| (gdbarch), as not all architectures are multi-arch. */ |
| raw_p = rawnum < gdbarch_num_regs (gdbarch); |
| if (gdbarch_register_name (gdbarch, regnum)[0] == '\0') |
| return 0; |
| if (reggroup == float_reggroup) |
| return float_p && pseudo; |
| if (reggroup == vector_reggroup) |
| return vector_p && pseudo; |
| if (reggroup == general_reggroup) |
| return (!vector_p && !float_p) && pseudo; |
| /* Save the pseudo registers. Need to make certain that any code |
| extracting register values from a saved register cache also uses |
| pseudo registers. */ |
| if (reggroup == save_reggroup) |
| return raw_p && pseudo; |
| /* Restore the same pseudo register. */ |
| if (reggroup == restore_reggroup) |
| return raw_p && pseudo; |
| return 0; |
| } |
| |
| /* Return the groups that a MIPS register can be categorised into. |
| This version is only used if we have a target description which |
| describes real registers (and their groups). */ |
| |
| static int |
| mips_tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regnum, |
| const struct reggroup *reggroup) |
| { |
| int rawnum = regnum % gdbarch_num_regs (gdbarch); |
| int pseudo = regnum / gdbarch_num_regs (gdbarch); |
| int ret; |
| |
| /* Only save, restore, and display the pseudo registers. Need to |
| make certain that any code extracting register values from a |
| saved register cache also uses pseudo registers. |
| |
| Note: saving and restoring the pseudo registers is slightly |
| strange; if we have 64 bits, we should save and restore all |
| 64 bits. But this is hard and has little benefit. */ |
| if (!pseudo) |
| return 0; |
| |
| ret = tdesc_register_in_reggroup_p (gdbarch, rawnum, reggroup); |
| if (ret != -1) |
| return ret; |
| |
| return mips_register_reggroup_p (gdbarch, regnum, reggroup); |
| } |
| |
| /* Map the symbol table registers which live in the range [1 * |
| gdbarch_num_regs .. 2 * gdbarch_num_regs) back onto the corresponding raw |
| registers. Take care of alignment and size problems. */ |
| |
| static enum register_status |
| mips_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache, |
| int cookednum, gdb_byte *buf) |
| { |
| int rawnum = cookednum % gdbarch_num_regs (gdbarch); |
| gdb_assert (cookednum >= gdbarch_num_regs (gdbarch) |
| && cookednum < 2 * gdbarch_num_regs (gdbarch)); |
| if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum)) |
| return regcache->raw_read (rawnum, buf); |
| else if (register_size (gdbarch, rawnum) > |
| register_size (gdbarch, cookednum)) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| |
| if (tdep->mips64_transfers_32bit_regs_p) |
| return regcache->raw_read_part (rawnum, 0, 4, buf); |
| else |
| { |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| LONGEST regval; |
| enum register_status status; |
| |
| status = regcache->raw_read (rawnum, ®val); |
| if (status == REG_VALID) |
| store_signed_integer (buf, 4, byte_order, regval); |
| return status; |
| } |
| } |
| else |
| internal_error (_("bad register size")); |
| } |
| |
| static void |
| mips_pseudo_register_write (struct gdbarch *gdbarch, |
| struct regcache *regcache, int cookednum, |
| const gdb_byte *buf) |
| { |
| int rawnum = cookednum % gdbarch_num_regs (gdbarch); |
| gdb_assert (cookednum >= gdbarch_num_regs (gdbarch) |
| && cookednum < 2 * gdbarch_num_regs (gdbarch)); |
| if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum)) |
| regcache->raw_write (rawnum, buf); |
| else if (register_size (gdbarch, rawnum) > |
| register_size (gdbarch, cookednum)) |
| { |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| |
| if (tdep->mips64_transfers_32bit_regs_p) |
| regcache->raw_write_part (rawnum, 0, 4, buf); |
| else |
| { |
| /* Sign extend the shortened version of the register prior |
| to placing it in the raw register. This is required for |
| some mips64 parts in order to avoid unpredictable behavior. */ |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| LONGEST regval = extract_signed_integer (buf, 4, byte_order); |
| regcache_raw_write_signed (regcache, rawnum, regval); |
| } |
| } |
| else |
| internal_error (_("bad register size")); |
| } |
| |
| static int |
| mips_ax_pseudo_register_collect (struct gdbarch *gdbarch, |
| struct agent_expr *ax, int reg) |
| { |
| int rawnum = reg % gdbarch_num_regs (gdbarch); |
| gdb_assert (reg >= gdbarch_num_regs (gdbarch) |
| && reg < 2 * gdbarch_num_regs (gdbarch)); |
| |
| ax_reg_mask (ax, rawnum); |
| |
| return 0; |
| } |
| |
| static int |
| mips_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, |
| struct agent_expr *ax, int reg) |
| { |
| int rawnum = reg % gdbarch_num_regs (gdbarch); |
| gdb_assert (reg >= gdbarch_num_regs (gdbarch) |
| && reg < 2 * gdbarch_num_regs (gdbarch)); |
| if (register_size (gdbarch, rawnum) >= register_size (gdbarch, reg)) |
| { |
| ax_reg (ax, rawnum); |
| |
| if (register_size (gdbarch, rawnum) > register_size (gdbarch, reg)) |
| { |
| mips_gdbarch_tdep *tdep |
| = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| |
| if (!tdep->mips64_transfers_32bit_regs_p |
| || gdbarch_byte_order (gdbarch) != BFD_ENDIAN_BIG) |
| { |
| ax_const_l (ax, 32); |
| ax_simple (ax, aop_lsh); |
| } |
| ax_const_l (ax, 32); |
| ax_simple (ax, aop_rsh_signed); |
| } |
| } |
| else |
| internal_error (_("bad register size")); |
| |
| return 0; |
| } |
| |
| /* Table to translate 3-bit register field to actual register number. */ |
| static const signed char mips_reg3_to_reg[8] = { 16, 17, 2, 3, 4, 5, 6, 7 }; |
| |
| /* Heuristic_proc_start may hunt through the text section for a long |
| time across a 2400 baud serial line. Allows the user to limit this |
| search. */ |
| |
| static int heuristic_fence_post = 0; |
| |
| /* Number of bytes of storage in the actual machine representation for |
| register N. NOTE: This defines the pseudo register type so need to |
| rebuild the architecture vector. */ |
| |
| static bool mips64_transfers_32bit_regs_p = false; |
| |
| static void |
| set_mips64_transfers_32bit_regs (const char *args, int from_tty, |
| struct cmd_list_element *c) |
| { |
| struct gdbarch_info info; |
| /* FIXME: cagney/2003-11-15: Should be setting a field in "info" |
| instead of relying on globals. Doing that would let generic code |
| handle the search for this specific architecture. */ |
| if (!gdbarch_update_p (current_inferior (), info)) |
| { |
| mips64_transfers_32bit_regs_p = 0; |
| error (_("32-bit compatibility mode not supported")); |
| } |
| } |
| |
| /* Convert to/from a register and the corresponding memory value. */ |
| |
| /* This predicate tests for the case of an 8 byte floating point |
| value that is being transferred to or from a pair of floating point |
| registers each of which are (or are considered to be) only 4 bytes |
| wide. */ |
| static int |
| mips_convert_register_float_case_p (struct gdbarch *gdbarch, int regnum, |
| struct type *type) |
| { |
| return (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG |
| && register_size (gdbarch, regnum) == 4 |
| && mips_float_register_p (gdbarch, regnum) |
| && type->code () == TYPE_CODE_FLT && type->length () == 8); |
| } |
| |
| /* This predicate tests for the case of a value of less than 8 |
| bytes in width that is being transfered to or from an 8 byte |
| general purpose register. */ |
| static int |
| mips_convert_register_gpreg_case_p (struct gdbarch *gdbarch, int regnum, |
| struct type *type) |
| { |
| int num_regs = gdbarch_num_regs (gdbarch); |
| |
| return (register_size (gdbarch, regnum) == 8 |
| && regnum % num_regs > 0 && regnum % num_regs < 32 |
| && type->length () < 8); |
| } |
| |
| static int |
| mips_convert_register_p (struct gdbarch *gdbarch, |
| int regnum, struct type *type) |
| { |
| return (mips_convert_register_float_case_p (gdbarch, regnum, type) |
| || mips_convert_register_gpreg_case_p (gdbarch, regnum, type)); |
| } |
| |
| static int |
| mips_register_to_value (const frame_info_ptr &frame, int regnum, |
| struct type *type, gdb_byte *to, |
| int *optimizedp, int *unavailablep) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| frame_info_ptr next_frame = get_next_frame_sentinel_okay (frame); |
| |
| if (mips_convert_register_float_case_p (gdbarch, regnum, type)) |
| { |
| get_frame_register (frame, regnum + 0, to + 4); |
| get_frame_register (frame, regnum + 1, to + 0); |
| |
| if (!get_frame_register_bytes (next_frame, regnum + 0, 0, { to + 4, 4 }, |
| optimizedp, unavailablep)) |
| return 0; |
| |
| if (!get_frame_register_bytes (next_frame, regnum + 1, 0, { to + 0, 4 }, |
| optimizedp, unavailablep)) |
| return 0; |
| *optimizedp = *unavailablep = 0; |
| return 1; |
| } |
| else if (mips_convert_register_gpreg_case_p (gdbarch, regnum, type)) |
| { |
| size_t len = type->length (); |
| CORE_ADDR offset; |
| |
| offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 - len : 0; |
| if (!get_frame_register_bytes (next_frame, regnum, offset, { to, len }, |
| optimizedp, unavailablep)) |
| return 0; |
| |
| *optimizedp = *unavailablep = 0; |
| return 1; |
| } |
| else |
| { |
| internal_error (_("mips_register_to_value: unrecognized case")); |
| } |
| } |
| |
| static void |
| mips_value_to_register (const frame_info_ptr &frame, int regnum, |
| struct type *type, const gdb_byte *from) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| |
| if (mips_convert_register_float_case_p (gdbarch, regnum, type)) |
| { |
| auto from_view = gdb::make_array_view (from, 8); |
| frame_info_ptr next_frame = get_next_frame_sentinel_okay (frame); |
| put_frame_register (next_frame, regnum, from_view.slice (4)); |
| put_frame_register (next_frame, regnum + 1, from_view.slice (0, 4)); |
| } |
| else if (mips_convert_register_gpreg_case_p (gdbarch, regnum, type)) |
| { |
| gdb_byte fill[8]; |
| size_t len = type->length (); |
| frame_info_ptr next_frame = get_next_frame_sentinel_okay (frame); |
| |
| /* Sign extend values, irrespective of type, that are stored to |
| a 64-bit general purpose register. (32-bit unsigned values |
| are stored as signed quantities within a 64-bit register. |
| When performing an operation, in compiled code, that combines |
| a 32-bit unsigned value with a signed 64-bit value, a type |
| conversion is first performed that zeroes out the high 32 bits.) */ |
| if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) |
| { |
| if (from[0] & 0x80) |
| store_signed_integer (fill, 8, BFD_ENDIAN_BIG, -1); |
| else |
| store_signed_integer (fill, 8, BFD_ENDIAN_BIG, 0); |
| put_frame_register_bytes (next_frame, regnum, 0, {fill, 8 - len}); |
| put_frame_register_bytes (next_frame, regnum, 8 - len, {from, len}); |
| } |
| else |
| { |
| if (from[len-1] & 0x80) |
| store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, -1); |
| else |
| store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, 0); |
| put_frame_register_bytes (next_frame, regnum, 0, {from, len}); |
| put_frame_register_bytes (next_frame, regnum, len, {fill, 8 - len}); |
| } |
| } |
| else |
| { |
| internal_error (_("mips_value_to_register: unrecognized case")); |
| } |
| } |
| |
| /* Return the GDB type object for the "standard" data type of data in |
| register REG. */ |
| |
| static struct type * |
| mips_register_type (struct gdbarch *gdbarch, int regnum) |
| { |
| gdb_assert (regnum >= 0 && regnum < 2 * gdbarch_num_regs (gdbarch)); |
| if (mips_float_register_p (gdbarch, regnum)) |
| { |
| /* The floating-point registers raw, or cooked, always match |
| mips_isa_regsize(), and also map 1:1, byte for byte. */ |
| if (mips_isa_regsize (gdbarch) == 4) |
| return builtin_type (gdbarch)->builtin_float; |
| else |
| return builtin_type (gdbarch)->builtin_double; |
| } |
| else if (regnum < gdbarch_num_regs (gdbarch)) |
| { |
| /* The raw or ISA registers. These are all sized according to |
| the ISA regsize. */ |
| if (mips_isa_regsize (gdbarch) == 4) |
| return builtin_type (gdbarch)->builtin_int32; |
| else |
| return builtin_type (gdbarch)->builtin_int64; |
| } |
| else |
| { |
| int rawnum = regnum - gdbarch_num_regs (gdbarch); |
| mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| |
| /* The cooked or ABI registers. These are sized according to |
| the ABI (with a few complications). */ |
| if (rawnum == mips_regnum (gdbarch)->fp_control_status |
| || rawnum == mips_regnum (gdbarch)->fp_implementation_revision) |
| return builtin_type (gdbarch)->builtin_int32; |
| else if (gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX |
| && rawnum >= MIPS_FIRST_EMBED_REGNUM |
| && rawnum <= MIPS_LAST_EMBED_REGNUM) |
| /* The pseudo/cooked view of the embedded registers is always |
| 32-bit. The raw view is handled below. */ |
| return builtin_type (gdbarch)->builtin_int32; |
| else if (tdep->mips64_transfers_32bit_regs_p) |
| /* The target, while possibly using a 64-bit register buffer, |
| is only transfering 32-bits of each integer register. |
| Reflect this in the cooked/pseudo (ABI) register value. */ |
| return builtin_type (gdbarch)->builtin_int32; |
| else if (mips_abi_regsize (gdbarch) == 4) |
| /* The ABI is restricted to 32-bit registers (the ISA could be |
| 32- or 64-bit). */ |
| return builtin_type (gdbarch)->builtin_int32; |
| else |
| /* 64-bit ABI. */ |
| return builtin_type (gdbarch)->builtin_int64; |
| } |
| } |
| |
| /* Return the GDB type for the pseudo register REGNUM, which is the |
| ABI-level view. This function is only called if there is a target |
| description which includes registers, so we know precisely the |
| types of hardware registers. */ |
| |
| static struct type * |
| mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum) |
| { |
| const int num_regs = gdbarch_num_regs (gdbarch); |
| int rawnum = regnum % num_regs; |
| struct type *rawtype; |
| |
| gdb_assert (regnum >= num_regs && regnum < 2 * num_regs); |
| |
| /* Absent registers are still absent. */ |
| rawtype = gdbarch_register_type (gdbarch, rawnum); |
| if (rawtype->length () == 0) |
| return rawtype; |
| |
| /* Present the floating point registers however the hardware did; |
| do not try to convert between FPU layouts. */ |
| if (mips_float_register_p (gdbarch, rawnum)) |
| return rawtype; |
| |
| /* Floating-point control registers are always 32-bit even though for |
| backwards compatibility reasons 64-bit targets will transfer them |
| as 64-bit quantities even if using XML descriptions. */ |
| if (rawnum == mips_regnum (gdbarch)->fp_control_status |
| || rawnum == mips_regnum (gdbarch)->fp_implementation_revision) |
| return builtin_type (gdbarch)->builtin_int32; |
| |
| /* Use pointer types for registers if we can. For n32 we can not, |
| since we do not have a 64-bit pointer type. */ |
| if (mips_abi_regsize (gdbarch) |
| == builtin_type (gdbarch)->builtin_data_ptr->length()) |
| { |
| if (rawnum == MIPS_SP_REGNUM |
| || rawnum == mips_regnum (gdbarch)->badvaddr) |
| return builtin_type (gdbarch)->builtin_data_ptr; |
| else if (rawnum == mips_regnum (gdbarch)->pc) |
| return builtin_type (gdbarch)->builtin_func_ptr; |
| } |
| |
| if (mips_abi_regsize (gdbarch) == 4 && rawtype->length () == 8 |
| && ((rawnum >= MIPS_ZERO_REGNUM && rawnum <= MIPS_PS_REGNUM) |
| || rawnum == mips_regnum (gdbarch)->lo |
| || rawnum == mips_regnum (gdbarch)->hi |
| || rawnum == mips_regnum (gdbarch)->badvaddr |
| || rawnum == mips_regnum (gdbarch)->cause |
| || rawnum == mips_regnum (gdbarch)->pc |
| || (mips_regnum (gdbarch)->dspacc != -1 |
| && rawnum >= mips_regnum (gdbarch)->dspacc |
| && rawnum < mips_regnum (gdbarch)->dspacc + 6))) |
| return builtin_type (gdbarch)->builtin_int32; |
| |
| /* The pseudo/cooked view of embedded registers is always |
| 32-bit, even if the target transfers 64-bit values for them. |
| New targets relying on XML descriptions should only transfer |
| the necessary 32 bits, but older versions of GDB expected 64, |
| so allow the target to provide 64 bits without interfering |
| with the displayed type. */ |
| if (gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX |
| && rawnum >= MIPS_FIRST_EMBED_REGNUM |
| && rawnum <= MIPS_LAST_EMBED_REGNUM) |
| return builtin_type (gdbarch)->builtin_int32; |
| |
| /* For all other registers, pass through the hardware type. */ |
| return rawtype; |
| } |
| |
| /* Should the upper word of 64-bit addresses be zeroed? */ |
| static enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO; |
| |
| static int |
| mips_mask_address_p (mips_gdbarch_tdep *tdep) |
| { |
| switch (mask_address_var) |
| { |
| case AUTO_BOOLEAN_TRUE: |
| return 1; |
| case AUTO_BOOLEAN_FALSE: |
| return 0; |
| break; |
| case AUTO_BOOLEAN_AUTO: |
| return tdep->default_mask_address_p; |
| default: |
| internal_error (_("mips_mask_address_p: bad switch")); |
| return -1; |
| } |
| } |
| |
| static void |
| show_mask_address (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, const char *value) |
| { |
| const char *additional_text = ""; |
| if (mask_address_var == AUTO_BOOLEAN_AUTO) |
| { |
| if (gdbarch_bfd_arch_info (current_inferior ()->arch ())->arch |
| != bfd_arch_mips) |
| additional_text = _(" (current architecture is not MIPS)"); |
| else |
| { |
| mips_gdbarch_tdep *tdep |
| = gdbarch_tdep<mips_gdbarch_tdep> (current_inferior ()->arch ()); |
| |
| if (mips_mask_address_p (tdep)) |
| additional_text = _(" (currently \"on\")"); |
| else |
| additional_text = _(" (currently \"off\")"); |
| } |
| } |
| |
| gdb_printf (file, _("Zeroing of upper 32 bits of 64-bit addresses is \"%s\"%s.\n"), |
| value, additional_text); |
| } |
| |
| /* Tell if the program counter value in MEMADDR is in a standard ISA |
| function. */ |
| |
| int |
| mips_pc_is_mips (CORE_ADDR memaddr) |
| { |
| /* Flags indicating that this is a MIPS16 or microMIPS function is |
| stored by elfread.c in the high bit of the info field. Use this |
| to decide if the function is standard MIPS. Otherwise if bit 0 |
| of the address is clear, then this is a standard MIPS function. */ |
| bound_minimal_symbol sym |
| = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); |
| if (sym.minsym) |
| return msymbol_is_mips (sym.minsym); |
| else |
| return is_mips_addr (memaddr); |
| } |
| |
| /* Tell if the program counter value in MEMADDR is in a MIPS16 function. */ |
| |
| int |
| mips_pc_is_mips16 (struct gdbarch *gdbarch, CORE_ADDR memaddr) |
| { |
| /* A flag indicating that this is a MIPS16 function is stored by |
| elfread.c in the high bit of the info field. Use this to decide |
| if the function is MIPS16. Otherwise if bit 0 of the address is |
| set, then ELF file flags will tell if this is a MIPS16 function. */ |
| bound_minimal_symbol sym |
| = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); |
| if (sym.minsym) |
| return msymbol_is_mips16 (sym.minsym); |
| else |
| return is_mips16_addr (gdbarch, memaddr); |
| } |
| |
| /* Tell if the program counter value in MEMADDR is in a microMIPS function. */ |
| |
| int |
| mips_pc_is_micromips (struct gdbarch *gdbarch, CORE_ADDR memaddr) |
| { |
| /* A flag indicating that this is a microMIPS function is stored by |
| elfread.c in the high bit of the info field. Use this to decide |
| if the function is microMIPS. Otherwise if bit 0 of the address |
| is set, then ELF file flags will tell if this is a microMIPS |
| function. */ |
| bound_minimal_symbol sym |
| = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); |
| if (sym.minsym) |
| return msymbol_is_micromips (sym.minsym); |
| else |
| return is_micromips_addr (gdbarch, memaddr); |
| } |
| |
| /* Tell the ISA type of the function the program counter value in MEMADDR |
| is in. */ |
| |
| static enum mips_isa |
| mips_pc_isa (struct gdbarch *gdbarch, CORE_ADDR memaddr) |
| { |
| /* A flag indicating that this is a MIPS16 or a microMIPS function |
| is stored by elfread.c in the high bit of the info field. Use |
| this to decide if the function is MIPS16 or microMIPS or normal |
| MIPS. Otherwise if bit 0 of the address is set, then ELF file |
| flags will tell if this is a MIPS16 or a microMIPS function. */ |
| bound_minimal_symbol sym |
| = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); |
| if (sym.minsym) |
| { |
| if (msymbol_is_micromips (sym.minsym)) |
| return ISA_MICROMIPS; |
| else if (msymbol_is_mips16 (sym.minsym)) |
| return ISA_MIPS16; |
| else |
| return ISA_MIPS; |
| } |
| else |
| { |
| if (is_mips_addr (memaddr)) |
| return ISA_MIPS; |
| else if (is_micromips_addr (gdbarch, memaddr)) |
| return ISA_MICROMIPS; |
| else |
| return ISA_MIPS16; |
| } |
| } |
| |
| /* Set the ISA bit correctly in the PC, used by DWARF-2 machinery. |
| The need for comes from the ISA bit having been cleared, making |
| addresses in FDE, range records, etc. referring to compressed code |
| different to those in line information, the symbol table and finally |
| the PC register. That in turn confuses many operations. */ |
| |
| static CORE_ADDR |
| mips_adjust_dwarf2_addr (CORE_ADDR pc) |
| { |
| pc = unmake_compact_addr (pc); |
| return mips_pc_is_mips (pc) ? pc : make_compact_addr (pc); |
| } |
| |
| /* Recalculate the line record requested so that the resulting PC has |
| the ISA bit set correctly, used by DWARF-2 machinery. The need for |
| this adjustment comes from some records associated with compressed |
| code having the ISA bit cleared, most notably at function prologue |
| ends. The ISA bit is in this context retrieved from the minimal |
| symbol covering the address requested, which in turn has been |
| constructed from the binary's symbol table rather than DWARF-2 |
| information. The correct setting of the ISA bit is required for |
| breakpoint addresses to correctly match against the stop PC. |
| |
| As line entries can specify relative address adjustments we need to |
| keep track of the absolute value of the last line address recorded |
| in line information, so that we can calculate the actual address to |
| apply the ISA bit adjustment to. We use PC for this tracking and |
| keep the original address there. |
| |
| As such relative address adjustments can be odd within compressed |
| code we need to keep track of the last line address with the ISA |
| bit adjustment applied too, as the original address may or may not |
| have had the ISA bit set. We use ADJ_PC for this tracking and keep |
| the adjusted address there. |
| |
| For relative address adjustments we then use these variables to |
| calculate the address intended by line information, which will be |
| PC-relative, and return an updated adjustment carrying ISA bit |
| information, which will be ADJ_PC-relative. For absolute address |
| adjustments we just return the same address that we store in ADJ_PC |
| too. |
| |
| As the first line entry can be relative to an implied address value |
| of 0 we need to have the initial address set up that we store in PC |
| and ADJ_PC. This is arranged with a call from `dwarf_decode_lines_1' |
| that sets PC to 0 and ADJ_PC accordingly, usually 0 as well. */ |
| |
| static CORE_ADDR |
| mips_adjust_dwarf2_line (CORE_ADDR addr, int rel) |
| { |
| static CORE_ADDR adj_pc; |
| static CORE_ADDR pc; |
| CORE_ADDR isa_pc; |
| |
| pc = rel ? pc + addr : addr; |
| isa_pc = mips_adjust_dwarf2_addr (pc); |
| addr = rel ? isa_pc - adj_pc : isa_pc; |
| adj_pc = isa_pc; |
| return addr; |
| } |
| |
| /* Various MIPS16 thunk (aka stub or trampoline) names. */ |
| |
| static const char mips_str_mips16_call_stub[] = "__mips16_call_stub_"; |
| static const char mips_str_mips16_ret_stub[] = "__mips16_ret_"; |
| static const char mips_str_call_fp_stub[] = "__call_stub_fp_"; |
| static const char mips_str_call_stub[] = "__call_stub_"; |
| static const char mips_str_fn_stub[] = "__fn_stub_"; |
| |
| /* This is used as a PIC thunk prefix. */ |
| |
| static const char mips_str_pic[] = ".pic."; |
| |
| /* Return non-zero if the PC is inside a call thunk (aka stub or |
| trampoline) that should be treated as a temporary frame. */ |
| |
| static int |
| mips_in_frame_stub (CORE_ADDR pc) |
| { |
| CORE_ADDR start_addr; |
| const char *name; |
| |
| /* Find the starting address of the function containing the PC. */ |
| if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0) |
| return 0; |
| |
| /* If the PC is in __mips16_call_stub_*, this is a call/return stub. */ |
| if (startswith (name, mips_str_mips16_call_stub)) |
| return 1; |
| /* If the PC is in __call_stub_*, this is a call/return or a call stub. */ |
| if (startswith (name, mips_str_call_stub)) |
| return 1; |
| /* If the PC is in __fn_stub_*, this is a call stub. */ |
| if (startswith (name, mips_str_fn_stub)) |
| return 1; |
| |
| return 0; /* Not a stub. */ |
| } |
| |
| /* MIPS believes that the PC has a sign extended value. Perhaps the |
| all registers should be sign extended for simplicity? */ |
| |
| static CORE_ADDR |
| mips_read_pc (readable_regcache *regcache) |
| { |
| int regnum = gdbarch_pc_regnum (regcache->arch ()); |
| LONGEST pc; |
| |
| regcache->cooked_read (regnum, &pc); |
| return pc; |
| } |
| |
| static CORE_ADDR |
| mips_unwind_pc (struct gdbarch *gdbarch, const frame_info_ptr &next_frame) |
| { |
| CORE_ADDR pc; |
| |
| pc = frame_unwind_register_signed (next_frame, gdbarch_pc_regnum (gdbarch)); |
| /* macro/2012-04-20: This hack skips over MIPS16 call thunks as |
| intermediate frames. In this case we can get the caller's address |
| from $ra, or if $ra contains an address within a thunk as well, then |
| it must be in the return path of __mips16_call_stub_{s,d}{f,c}_{0..10} |
| and thus the caller's address is in $s2. */ |
| if (frame_relative_level (next_frame) >= 0 && mips_in_frame_stub (pc)) |
| { |
| pc = frame_unwind_register_signed |
| (next_frame, gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM); |
| if (mips_in_frame_stub (pc)) |
| pc = frame_unwind_register_signed |
| (next_frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM); |
| } |
| return pc; |
| } |
| |
| static CORE_ADDR |
| mips_unwind_sp (struct gdbarch *gdbarch, const frame_info_ptr &next_frame) |
| { |
| return frame_unwind_register_signed |
| (next_frame, gdbarch_num_regs (gdbarch) + MIPS_SP_REGNUM); |
| } |
| |
| /* Assuming THIS_FRAME is a dummy, return the frame ID of that |
| dummy frame. The frame ID's base needs to match the TOS value |
| saved by save_dummy_frame_tos(), and the PC match the dummy frame's |
| breakpoint. */ |
| |
| static struct frame_id |
| mips_dummy_id (struct gdbarch *gdbarch, const frame_info_ptr &this_frame) |
| { |
| return frame_id_build |
| (get_frame_register_signed (this_frame, |
| gdbarch_num_regs (gdbarch) |
| + MIPS_SP_REGNUM), |
| get_frame_pc (this_frame)); |
| } |
| |
| /* Implement the "write_pc" gdbarch method. */ |
| |
| void |
| mips_write_pc (struct regcache *regcache, CORE_ADDR pc) |
| { |
| int regnum = gdbarch_pc_regnum (regcache->arch ()); |
| |
| regcache_cooked_write_unsigned (regcache, regnum, pc); |
| } |
| |
| /* Fetch and return instruction from the specified location. Handle |
| MIPS16/microMIPS as appropriate. */ |
| |
| static ULONGEST |
| mips_fetch_instruction (struct gdbarch *gdbarch, |
| enum mips_isa isa, CORE_ADDR addr, int *errp) |
| { |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| gdb_byte buf[MIPS_INSN32_SIZE]; |
| int instlen; |
| int err; |
| |
| switch (isa) |
| { |
| case ISA_MICROMIPS: |
| case ISA_MIPS16: |
| instlen = MIPS_INSN16_SIZE; |
| addr = unmake_compact_addr (addr); |
| break; |
| case ISA_MIPS: |
| instlen = MIPS_INSN32_SIZE; |
| break; |
| default: |
| internal_error (_("invalid ISA")); |
| break; |
| } |
| err = target_read_memory (addr, buf, instlen); |
| if (errp != NULL) |
| *errp = err; |
| if (err != 0) |
| { |
| if (errp == NULL) |
| memory_error (TARGET_XFER_E_IO, addr); |
| return 0; |
| } |
| return extract_unsigned_integer (buf, instlen, byte_order); |
| } |
| |
| /* These are the fields of 32 bit mips instructions. */ |
| #define mips32_op(x) (x >> 26) |
| #define itype_op(x) (x >> 26) |
| #define itype_rs(x) ((x >> 21) & 0x1f) |
| #define itype_rt(x) ((x >> 16) & 0x1f) |
| #define itype_immediate(x) (x & 0xffff) |
| |
| #define jtype_op(x) (x >> 26) |
| #define jtype_target(x) (x & 0x03ffffff) |
| |
| #define rtype_op(x) (x >> 26) |
| #define rtype_rs(x) ((x >> 21) & 0x1f) |
| #define rtype_rt(x) ((x >> 16) & 0x1f) |
| #define rtype_rd(x) ((x >> 11) & 0x1f) |
| #define rtype_shamt(x) ((x >> 6) & 0x1f) |
| #define rtype_funct(x) (x & 0x3f) |
| |
| /* MicroMIPS instruction fields. */ |
| #define micromips_op(x) ((x) >> 10) |
| |
| /* 16-bit/32-bit-high-part instruction formats, B and S refer to the lowest |
| bit and the size respectively of the field extracted. */ |
| #define b0s4_imm(x) ((x) & 0xf) |
| #define b0s5_imm(x) ((x) & 0x1f) |
| #define b0s5_reg(x) ((x) & 0x1f) |
| #define b0s7_imm(x) ((x) & 0x7f) |
| #define b0s10_imm(x) ((x) & 0x3ff) |
| #define b1s4_imm(x) (((x) >> 1) & 0xf) |
| #define b1s9_imm(x) (((x) >> 1) & 0x1ff) |
| #define b2s3_cc(x) (((x) >> 2) & 0x7) |
| #define b4s2_regl(x) (((x) >> 4) & 0x3) |
| #define b5s5_op(x) (((x) >> 5) & 0x1f) |
| #define b5s5_reg(x) (((x) >> 5) & 0x1f) |
| #define b6s4_op(x) (((x) >> 6) & 0xf) |
| #define b7s3_reg(x) (((x) >> 7) & 0x7) |
| |
| /* 32-bit instruction formats, B and S refer to the lowest bit and the size |
| respectively of the field extracted. */ |
| #define b0s6_op(x) ((x) & 0x3f) |
| #define b0s11_op(x) ((x) & 0x7ff) |
| #define b0s12_imm(x) ((x) & 0xfff) |
| #define b0s16_imm(x) ((x) & 0xffff) |
| #define b0s26_imm(x) ((x) & 0x3ffffff) |
| #define b6s10_ext(x) (((x) >> 6) & 0x3ff) |
| #define b11s5_reg(x) (((x) >> 11) & 0x1f) |
| #define b12s4_op(x) (((x) >> 12) & 0xf) |
| |
| /* Return the size in bytes of the instruction INSN encoded in the ISA |
| instruction set. */ |
| |
| static int |
| mips_insn_size (enum mips_isa isa, ULONGEST insn) |
| { |
| switch (isa) |
| { |
| case ISA_MICROMIPS: |
| if ((micromips_op (insn) & 0x4) == 0x4 |
| || (micromips_op (insn) & 0x7) == 0x0) |
| return 2 * MIPS_INSN16_SIZE; |
| else |
| return MIPS_INSN16_SIZE; |
| case ISA_MIPS16: |
| if ((insn & 0xf800) == 0xf000) |
| return 2 * MIPS_INSN16_SIZE; |
| else |
| return MIPS_INSN16_SIZE; |
| case ISA_MIPS: |
| return MIPS_INSN32_SIZE; |
| } |
| internal_error (_("invalid ISA")); |
| } |
| |
| static LONGEST |
| mips32_relative_offset (ULONGEST inst) |
| { |
| return ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 2; |
| } |
| |
| /* Determine the address of the next instruction executed after the INST |
| floating condition branch instruction at PC. COUNT specifies the |
| number of the floating condition bits tested by the branch. */ |
| |
| static CORE_ADDR |
| mips32_bc1_pc (struct gdbarch *gdbarch, struct regcache *regcache, |
| ULONGEST inst, CORE_ADDR pc, int count) |
| { |
| int fcsr = mips_regnum (gdbarch)->fp_control_status; |
| int cnum = (itype_rt (inst) >> 2) & (count - 1); |
| int tf = itype_rt (inst) & 1; |
| int mask = (1 << count) - 1; |
| ULONGEST fcs; |
| int cond; |
| |
| if (fcsr == -1) |
| /* No way to handle; it'll most likely trap anyway. */ |
| return pc; |
| |
| fcs = regcache_raw_get_unsigned (regcache, fcsr); |
| cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01); |
| |
| if (((cond >> cnum) & mask) != mask * !tf) |
| pc += mips32_relative_offset (inst); |
| else |
| pc += 4; |
| |
| return pc; |
| } |
| |
| /* Return nonzero if the gdbarch is an Octeon series. */ |
| |
| static int |
| is_octeon (struct gdbarch *gdbarch) |
| { |
| const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch); |
| |
| return (info->mach == bfd_mach_mips_octeon |
| || info->mach == bfd_mach_mips_octeonp |
| || info->mach == bfd_mach_mips_octeon2); |
| } |
| |
| /* Return true if the OP represents the Octeon's BBIT instruction. */ |
| |
| static int |
| is_octeon_bbit_op (int op, struct gdbarch *gdbarch) |
| { |
| if (!is_octeon (gdbarch)) |
| return 0; |
| /* BBIT0 is encoded as LWC2: 110 010. */ |
| /* BBIT032 is encoded as LDC2: 110 110. */ |
| /* BBIT1 is encoded as SWC2: 111 010. */ |
| /* BBIT132 is encoded as SDC2: 111 110. */ |
| if (op == 50 || op == 54 || op == 58 || op == 62) |
| return 1; |
| return 0; |
| } |
| |
| |
| /* Determine where to set a single step breakpoint while considering |
| branch prediction. */ |
| |
| static CORE_ADDR |
| mips32_next_pc (struct regcache *regcache, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| unsigned long inst; |
| int op; |
| inst = mips_fetch_instruction (gdbarch, ISA_MIPS, pc, NULL); |
| op = itype_op (inst); |
| if ((inst & 0xe0000000) != 0) /* Not a special, jump or branch |
| instruction. */ |
| { |
| if (op >> 2 == 5) |
| /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */ |
| { |
| switch (op & 0x03) |
| { |
| case 0: /* BEQL */ |
| goto equal_branch; |
| case 1: /* BNEL */ |
| goto neq_branch; |
| case 2: /* BLEZL */ |
| goto less_branch; |
| case 3: /* BGTZL */ |
| goto greater_branch; |
| default: |
| pc += 4; |
| } |
| } |
| else if (op == 17 && itype_rs (inst) == 8) |
| /* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */ |
| pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 1); |
| else if (op == 17 && itype_rs (inst) == 9 |
| && (itype_rt (inst) & 2) == 0) |
| /* BC1ANY2F, BC1ANY2T: 010001 01001 xxx0x */ |
| pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 2); |
| else if (op == 17 && itype_rs (inst) == 10 |
| && (itype_rt (inst) & 2) == 0) |
| /* BC1ANY4F, BC1ANY4T: 010001 01010 xxx0x */ |
| pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 4); |
| else if (op == 29) |
| /* JALX: 011101 */ |
| /* The new PC will be alternate mode. */ |
| { |
| unsigned long reg; |
| |
| reg = jtype_target (inst) << 2; |
| /* Add 1 to indicate 16-bit mode -- invert ISA mode. */ |
| pc = ((pc + 4) & ~(CORE_ADDR) 0x0fffffff) + reg + 1; |
| } |
| else if (is_octeon_bbit_op (op, gdbarch)) |
| { |
| int bit, branch_if; |
| |
| branch_if = op == 58 || op == 62; |
| bit = itype_rt (inst); |
| |
| /* Take into account the *32 instructions. */ |
| if (op == 54 || op == 62) |
| bit += 32; |
| |
| if (((regcache_raw_get_signed (regcache, |
| itype_rs (inst)) >> bit) & 1) |
| == branch_if) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; /* After the delay slot. */ |
| } |
| |
| else |
| pc += 4; /* Not a branch, next instruction is easy. */ |
| } |
| else |
| { /* This gets way messy. */ |
| |
| /* Further subdivide into SPECIAL, REGIMM and other. */ |
| switch (op & 0x07) /* Extract bits 28,27,26. */ |
| { |
| case 0: /* SPECIAL */ |
| op = rtype_funct (inst); |
| switch (op) |
| { |
| case 8: /* JR */ |
| case 9: /* JALR */ |
| /* Set PC to that address. */ |
| pc = regcache_raw_get_signed (regcache, rtype_rs (inst)); |
| break; |
| case 12: /* SYSCALL */ |
| { |
| mips_gdbarch_tdep *tdep |
| = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| |
| if (tdep->syscall_next_pc != NULL) |
| pc = tdep->syscall_next_pc (get_current_frame ()); |
| else |
| pc += 4; |
| } |
| break; |
| default: |
| pc += 4; |
| } |
| |
| break; /* end SPECIAL */ |
| case 1: /* REGIMM */ |
| { |
| op = itype_rt (inst); /* branch condition */ |
| switch (op) |
| { |
| case 0: /* BLTZ */ |
| case 2: /* BLTZL */ |
| case 16: /* BLTZAL */ |
| case 18: /* BLTZALL */ |
| less_branch: |
| if (regcache_raw_get_signed (regcache, itype_rs (inst)) < 0) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; /* after the delay slot */ |
| break; |
| case 1: /* BGEZ */ |
| case 3: /* BGEZL */ |
| case 17: /* BGEZAL */ |
| case 19: /* BGEZALL */ |
| if (regcache_raw_get_signed (regcache, itype_rs (inst)) >= 0) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; /* after the delay slot */ |
| break; |
| case 0x1c: /* BPOSGE32 */ |
| case 0x1e: /* BPOSGE64 */ |
| pc += 4; |
| if (itype_rs (inst) == 0) |
| { |
| unsigned int pos = (op & 2) ? 64 : 32; |
| int dspctl = mips_regnum (gdbarch)->dspctl; |
| |
| if (dspctl == -1) |
| /* No way to handle; it'll most likely trap anyway. */ |
| break; |
| |
| if ((regcache_raw_get_unsigned (regcache, |
| dspctl) & 0x7f) >= pos) |
| pc += mips32_relative_offset (inst); |
| else |
| pc += 4; |
| } |
| break; |
| /* All of the other instructions in the REGIMM category */ |
| default: |
| pc += 4; |
| } |
| } |
| break; /* end REGIMM */ |
| case 2: /* J */ |
| case 3: /* JAL */ |
| { |
| unsigned long reg; |
| reg = jtype_target (inst) << 2; |
| /* Upper four bits get never changed... */ |
| pc = reg + ((pc + 4) & ~(CORE_ADDR) 0x0fffffff); |
| } |
| break; |
| case 4: /* BEQ, BEQL */ |
| equal_branch: |
| if (regcache_raw_get_signed (regcache, itype_rs (inst)) == |
| regcache_raw_get_signed (regcache, itype_rt (inst))) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; |
| break; |
| case 5: /* BNE, BNEL */ |
| neq_branch: |
| if (regcache_raw_get_signed (regcache, itype_rs (inst)) != |
| regcache_raw_get_signed (regcache, itype_rt (inst))) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; |
| break; |
| case 6: /* BLEZ, BLEZL */ |
| if (regcache_raw_get_signed (regcache, itype_rs (inst)) <= 0) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; |
| break; |
| case 7: |
| default: |
| greater_branch: /* BGTZ, BGTZL */ |
| if (regcache_raw_get_signed (regcache, itype_rs (inst)) > 0) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; |
| break; |
| } /* switch */ |
| } /* else */ |
| return pc; |
| } /* mips32_next_pc */ |
| |
| /* Extract the 7-bit signed immediate offset from the microMIPS instruction |
| INSN. */ |
| |
| static LONGEST |
| micromips_relative_offset7 (ULONGEST insn) |
| { |
| return ((b0s7_imm (insn) ^ 0x40) - 0x40) << 1; |
| } |
| |
| /* Extract the 10-bit signed immediate offset from the microMIPS instruction |
| INSN. */ |
| |
| static LONGEST |
| micromips_relative_offset10 (ULONGEST insn) |
| { |
| return ((b0s10_imm (insn) ^ 0x200) - 0x200) << 1; |
| } |
| |
| /* Extract the 16-bit signed immediate offset from the microMIPS instruction |
| INSN. */ |
| |
| static LONGEST |
| micromips_relative_offset16 (ULONGEST insn) |
| { |
| return ((b0s16_imm (insn) ^ 0x8000) - 0x8000) << 1; |
| } |
| |
| /* Return the size in bytes of the microMIPS instruction at the address PC. */ |
| |
| static int |
| micromips_pc_insn_size (struct gdbarch *gdbarch, CORE_ADDR pc) |
| { |
| ULONGEST insn; |
| |
| insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, pc, NULL); |
| return mips_insn_size (ISA_MICROMIPS, insn); |
| } |
| |
| /* Calculate the address of the next microMIPS instruction to execute |
| after the INSN coprocessor 1 conditional branch instruction at the |
| address PC. COUNT denotes the number of coprocessor condition bits |
| examined by the branch. */ |
| |
| static CORE_ADDR |
| micromips_bc1_pc (struct gdbarch *gdbarch, struct regcache *regcache, |
| ULONGEST insn, CORE_ADDR pc, int count) |
| { |
| int fcsr = mips_regnum (gdbarch)->fp_control_status; |
| int cnum = b2s3_cc (insn >> 16) & (count - 1); |
| int tf = b5s5_op (insn >> 16) & 1; |
| int mask = (1 << count) - 1; |
| ULONGEST fcs; |
| int cond; |
| |
| if (fcsr == -1) |
| /* No way to handle; it'll most likely trap anyway. */ |
| return pc; |
| |
| fcs = regcache_raw_get_unsigned (regcache, fcsr); |
| cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01); |
| |
| if (((cond >> cnum) & mask) != mask * !tf) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| |
| return pc; |
| } |
| |
| /* Calculate the address of the next microMIPS instruction to execute |
| after the instruction at the address PC. */ |
| |
| static CORE_ADDR |
| micromips_next_pc (struct regcache *regcache, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| ULONGEST insn; |
| |
| insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, pc, NULL); |
| pc += MIPS_INSN16_SIZE; |
| switch (mips_insn_size (ISA_MICROMIPS, insn)) |
| { |
| /* 32-bit instructions. */ |
| case 2 * MIPS_INSN16_SIZE: |
| insn <<= 16; |
| insn |= mips_fetch_instruction (gdbarch, ISA_MICROMIPS, pc, NULL); |
| pc += MIPS_INSN16_SIZE; |
| switch (micromips_op (insn >> 16)) |
| { |
| case 0x00: /* POOL32A: bits 000000 */ |
| switch (b0s6_op (insn)) |
| { |
| case 0x3c: /* POOL32Axf: bits 000000 ... 111100 */ |
| switch (b6s10_ext (insn)) |
| { |
| case 0x3c: /* JALR: 000000 0000111100 111100 */ |
| case 0x7c: /* JALR.HB: 000000 0001111100 111100 */ |
| case 0x13c: /* JALRS: 000000 0100111100 111100 */ |
| case 0x17c: /* JALRS.HB: 000000 0101111100 111100 */ |
| pc = regcache_raw_get_signed (regcache, |
| b0s5_reg (insn >> 16)); |
| break; |
| case 0x22d: /* SYSCALL: 000000 1000101101 111100 */ |
| { |
| mips_gdbarch_tdep *tdep |
| = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch); |
| |
| if (tdep->syscall_next_pc != NULL) |
| pc = tdep->syscall_next_pc (get_current_frame ()); |
| } |
| break; |
| } |
| break; |
| } |
| break; |
| |
| case 0x10: /* POOL32I: bits 010000 */ |
| switch (b5s5_op (insn >> 16)) |
| { |
| case 0x00: /* BLTZ: bits 010000 00000 */ |
| case 0x01: /* BLTZAL: bits 010000 00001 */ |
| case 0x11: /* BLTZALS: bits 010000 10001 */ |
| if (regcache_raw_get_signed (regcache, |
| b0s5_reg (insn >> 16)) < 0) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| break; |
| |
| case 0x02: /* BGEZ: bits 010000 00010 */ |
| case 0x03: /* BGEZAL: bits 010000 00011 */ |
| case 0x13: /* BGEZALS: bits 010000 10011 */ |
| if (regcache_raw_get_signed (regcache, |
| b0s5_reg (insn >> 16)) >= 0) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| break; |
| |
| case 0x04: /* BLEZ: bits 010000 00100 */ |
| if (regcache_raw_get_signed (regcache, |
| b0s5_reg (insn >> 16)) <= 0) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| break; |
| |
| case 0x05: /* BNEZC: bits 010000 00101 */ |
| if (regcache_raw_get_signed (regcache, |
| b0s5_reg (insn >> 16)) != 0) |
| pc += micromips_relative_offset16 (insn); |
| break; |
| |
| case 0x06: /* BGTZ: bits 010000 00110 */ |
| if (regcache_raw_get_signed (regcache, |
| b0s5_reg (insn >> 16)) > 0) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| break; |
| |
| case 0x07: /* BEQZC: bits 010000 00111 */ |
| if (regcache_raw_get_signed (regcache, |
| b0s5_reg (insn >> 16)) == 0) |
| pc += micromips_relative_offset16 (insn); |
| break; |
| |
| case 0x14: /* BC2F: bits 010000 10100 xxx00 */ |
| case 0x15: /* BC2T: bits 010000 10101 xxx00 */ |
| if (((insn >> 16) & 0x3) == 0x0) |
| /* BC2F, BC2T: don't know how to handle these. */ |
| break; |
| break; |
| |
| case 0x1a: /* BPOSGE64: bits 010000 11010 */ |
| case 0x1b: /* BPOSGE32: bits 010000 11011 */ |
| { |
| unsigned int pos = (b5s5_op (insn >> 16) & 1) ? 32 : 64; |
| int dspctl = mips_regnum (gdbarch)->dspctl; |
| |
| if (dspctl == -1) |
| /* No way to handle; it'll most likely trap anyway. */ |
| break; |
| |
| if ((regcache_raw_get_unsigned (regcache, |
| dspctl) & 0x7f) >= pos) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| } |
| break; |
| |
| case 0x1c: /* BC1F: bits 010000 11100 xxx00 */ |
| /* BC1ANY2F: bits 010000 11100 xxx01 */ |
| case 0x1d: /* BC1T: bits 010000 11101 xxx00 */ |
| /* BC1ANY2T: bits 010000 11101 xxx01 */ |
| if (((insn >> 16) & 0x2) == 0x0) |
| pc = micromips_bc1_pc (gdbarch, regcache, insn, pc, |
| ((insn >> 16) & 0x1) + 1); |
| break; |
| |
| case 0x1e: /* BC1ANY4F: bits 010000 11110 xxx01 */ |
| case 0x1f: /* BC1ANY4T: bits 010000 11111 xxx01 */ |
| if (((insn >> 16) & 0x3) == 0x1) |
| pc = micromips_bc1_pc (gdbarch, regcache, insn, pc, 4); |
| break; |
| } |
| break; |
| |
| case 0x1d: /* JALS: bits 011101 */ |
| case 0x35: /* J: bits 110101 */ |
| case 0x3d: /* JAL: bits 111101 */ |
| pc = ((pc | 0x7fffffe) ^ 0x7fffffe) | (b0s26_imm (insn) << 1); |
| break; |
| |
| case 0x25: /* BEQ: bits 100101 */ |
| if (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16)) |
| == regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16))) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| break; |
| |
| case 0x2d: /* BNE: bits 101101 */ |
| if (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16)) |
| != regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16))) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| break; |
| |
| case 0x3c: /* JALX: bits 111100 */ |
| pc = ((pc | 0xfffffff) ^ 0xfffffff) | (b0s26_imm (insn) << 2); |
| break; |
| } |
| break; |
| |
| /* 16-bit instructions. */ |
| case MIPS_INSN16_SIZE: |
| switch (micromips_op (insn)) |
| { |
| case 0x11: /* POOL16C: bits 010001 */ |
| if ((b5s5_op (insn) & 0x1c) == 0xc) |
| /* JR16, JRC, JALR16, JALRS16: 010001 011xx */ |
| pc = regcache_raw_get_signed (regcache, b0s5_reg (insn)); |
| else if (b5s5_op (insn) == 0x18) |
| /* JRADDIUSP: bits 010001 11000 */ |
| pc = regcache_raw_get_signed (regcache, MIPS_RA_REGNUM); |
| break; |
| |
| case 0x23: /* BEQZ16: bits 100011 */ |
| { |
| int rs = mips_reg3_to_reg[b7s3_reg (insn)]; |
| |
| if (regcache_raw_get_signed (regcache, rs) == 0) |
| pc += micromips_relative_offset7 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| } |
| break; |
| |
| case 0x2b: /* BNEZ16: bits 101011 */ |
| { |
| int rs = mips_reg3_to_reg[b7s3_reg (insn)]; |
| |
| if (regcache_raw_get_signed (regcache, rs) != 0) |
| pc += micromips_relative_offset7 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| } |
| break; |
| |
| case 0x33: /* B16: bits 110011 */ |
| pc += micromips_relative_offset10 (insn); |
| break; |
| } |
| break; |
| } |
| |
| return pc; |
| } |
| |
| /* Decoding the next place to set a breakpoint is irregular for the |
| mips 16 variant, but fortunately, there fewer instructions. We have |
| to cope ith extensions for 16 bit instructions and a pair of actual |
| 32 bit instructions. We dont want to set a single step instruction |
| on the extend instruction either. */ |
| |
| /* Lots of mips16 instruction formats */ |
| /* Predicting jumps requires itype,ritype,i8type |
| and their extensions extItype,extritype,extI8type. */ |
| enum mips16_inst_fmts |
| { |
| itype, /* 0 immediate 5,10 */ |
| ritype, /* 1 5,3,8 */ |
| rrtype, /* 2 5,3,3,5 */ |
| rritype, /* 3 5,3,3,5 */ |
| rrrtype, /* 4 5,3,3,3,2 */ |
| rriatype, /* 5 5,3,3,1,4 */ |
| shifttype, /* 6 5,3,3,3,2 */ |
| i8type, /* 7 5,3,8 */ |
| i8movtype, /* 8 5,3,3,5 */ |
| i8mov32rtype, /* 9 5,3,5,3 */ |
| i64type, /* 10 5,3,8 */ |
| ri64type, /* 11 5,3,3,5 */ |
| jalxtype, /* 12 5,1,5,5,16 - a 32 bit instruction */ |
| exiItype, /* 13 5,6,5,5,1,1,1,1,1,1,5 */ |
| extRitype, /* 14 5,6,5,5,3,1,1,1,5 */ |
| extRRItype, /* 15 5,5,5,5,3,3,5 */ |
| extRRIAtype, /* 16 5,7,4,5,3,3,1,4 */ |
| EXTshifttype, /* 17 5,5,1,1,1,1,1,1,5,3,3,1,1,1,2 */ |
| extI8type, /* 18 5,6,5,5,3,1,1,1,5 */ |
| extI64type, /* 19 5,6,5,5,3,1,1,1,5 */ |
| extRi64type, /* 20 5,6,5,5,3,3,5 */ |
| extshift64type /* 21 5,5,1,1,1,1,1,1,5,1,1,1,3,5 */ |
| }; |
| /* I am heaping all the fields of the formats into one structure and |
| then, only the fields which are involved in instruction extension. */ |
| struct upk_mips16 |
| { |
| CORE_ADDR offset; |
| unsigned int regx; /* Function in i8 type. */ |
| unsigned int regy; |
| }; |
| |
| |
| /* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same format |
| for the bits which make up the immediate extension. */ |
| |
| static CORE_ADDR |
| extended_offset (unsigned int extension) |
| { |
| CORE_ADDR value; |
| |
| value = (extension >> 16) & 0x1f; /* Extract 15:11. */ |
| value = value << 6; |
| value |= (extension >> 21) & 0x3f; /* Extract 10:5. */ |
| value = value << 5; |
| value |= extension & 0x1f; /* Extract 4:0. */ |
| |
| return value; |
| } |
| |
| /* Only call this function if you know that this is an extendable |
| instruction. It won't malfunction, but why make excess remote memory |
| references? If the immediate operands get sign extended or something, |
| do it after the extension is performed. */ |
| /* FIXME: Every one of these cases needs to worry about sign extension |
| when the offset is to be used in relative addressing. */ |
| |
| static unsigned int |
| fetch_mips_16 (struct gdbarch *gdbarch, CORE_ADDR pc) |
| { |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| gdb_byte buf[8]; |
| |
| pc = unmake_compact_addr (pc); /* Clear the low order bit. */ |
| target_read_memory (pc, buf, 2); |
| return extract_unsigned_integer (buf, 2, byte_order); |
| } |
| |
| static void |
| unpack_mips16 (struct gdbarch *gdbarch, CORE_ADDR pc, |
| unsigned int extension, |
| unsigned int inst, |
| enum mips16_inst_fmts insn_format, struct upk_mips16 *upk) |
| { |
| CORE_ADDR offset; |
| int regx; |
| int regy; |
| switch (insn_format) |
| { |
| case itype: |
| { |
| CORE_ADDR value; |
| if (extension) |
| { |
| value = extended_offset ((extension << 16) | inst); |
| value = (value ^ 0x8000) - 0x8000; /* Sign-extend. */ |
| } |
| else |
| { |
| value = inst & 0x7ff; |
| value = (value ^ 0x400) - 0x400; /* Sign-extend. */ |
| } |
| offset = value; |
| regx = -1; |
| regy = -1; |
| } |
| break; |
| case ritype: |
| case i8type: |
| { /* A register identifier and an offset. */ |
| /* Most of the fields are the same as I type but the |
| immediate value is of a different length. */ |
| CORE_ADDR value; |
| if (extension) |
| { |
| value = extended_offset ((extension << 16) | inst); |
| value = (value ^ 0x8000) - 0x8000; /* Sign-extend. */ |
| } |
| else |
| { |
| value = inst & 0xff; /* 8 bits */ |
| value = (value ^ 0x80) - 0x80; /* Sign-extend. */ |
| } |
| offset = value; |
| regx = (inst >> 8) & 0x07; /* i8 funct */ |
| regy = -1; |
| break; |
| } |
| case jalxtype: |
| { |
| unsigned long value; |
| unsigned int nexthalf; |
| value = ((inst & 0x1f) << 5) | ((inst >> 5) & 0x1f); |
| value = value << 16; |
| nexthalf = mips_fetch_instruction (gdbarch, ISA_MIPS16, pc + 2, NULL); |
| /* Low bit still set. */ |
| value |= nexthalf; |
| offset = value; |
| regx = -1; |
| regy = -1; |
| break; |
| } |
| default: |
| internal_error (_("bad switch")); |
| } |
| upk->offset = offset; |
| upk->regx = regx; |
| upk->regy = regy; |
| } |
| |
| |
| /* Calculate the destination of a branch whose 16-bit opcode word is at PC, |
| and having a signed 16-bit OFFSET. */ |
| |
| static CORE_ADDR |
| add_offset_16 (CORE_ADDR pc, int offset) |
| { |
| return pc + (offset << 1) + 2; |
| } |
| |
| static CORE_ADDR |
| extended_mips16_next_pc (regcache *regcache, CORE_ADDR pc, |
| unsigned int extension, unsigned int insn) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| int op = (insn >> 11); |
| switch (op) |
| { |
| case 2: /* Branch */ |
| { |
| struct upk_mips16 upk; |
| unpack_mips16 (gdbarch, pc, extension, insn, itype, &upk); |
| pc = add_offset_16 (pc, upk.offset); |
| break; |
| } |
| case 3: /* JAL , JALX - Watch out, these are 32 bit |
| instructions. */ |
| { |
| struct upk_mips16 upk; |
| unpack_mips16 (gdbarch, pc, extension, insn, jalxtype, &upk); |
| pc = ((pc + 2) & (~(CORE_ADDR) 0x0fffffff)) | (upk.offset << 2); |
| if ((insn >> 10) & 0x01) /* Exchange mode */ |
| pc = pc & ~0x01; /* Clear low bit, indicate 32 bit mode. */ |
| else |
| pc |= 0x01; |
| break; |
| } |
| case 4: /* beqz */ |
| { |
| struct upk_mips16 upk; |
| int reg; |
| unpack_mips16 (gdbarch, pc, extension, insn, ritype, &upk); |
| reg = regcache_raw_get_signed (regcache, mips_reg3_to_reg[upk.regx]); |
| if (reg == 0) |
| pc = add_offset_16 (pc, upk.offset); |
| else |
| pc += 2; |
| break; |
| } |
| case 5: /* bnez */ |
| { |
| struct upk_mips16 upk; |
| int reg; |
| unpack_mips16 (gdbarch, pc, extension, insn, ritype, &upk); |
| reg = regcache_raw_get_signed (regcache, mips_reg3_to_reg[upk.regx]); |
| if (reg != 0) |
| pc = add_offset_16 (pc, upk.offset); |
| else |
| pc += 2; |
| break; |
| } |
| case 12: /* I8 Formats btez btnez */ |
| { |
| struct upk_mips16 upk; |
| int reg; |
| unpack_mips16 (gdbarch, pc, extension, insn, i8type, &upk); |
| /* upk.regx contains the opcode */ |
| /* Test register is 24 */ |
| reg = regcache_raw_get_signed (regcache, 24); |
| if (((upk.regx == 0) && (reg == 0)) /* BTEZ */ |
| || ((upk.regx == 1) && (reg != 0))) /* BTNEZ */ |
| pc = add_offset_16 (pc, upk.offset); |
| else |
| pc += 2; |
| break; |
| } |
| case 29: /* RR Formats JR, JALR, JALR-RA */ |
| { |
| struct upk_mips16 upk; |
| /* upk.fmt = rrtype; */ |
| op = insn & 0x1f; |
| if (op == 0) |
| { |
| int reg; |
| upk.regx = (insn >> 8) & 0x07; |
| upk.regy = (insn >> 5) & 0x07; |
| if ((upk.regy & 1) == 0) |
| reg = mips_reg3_to_reg[upk.regx]; |
| else |
| reg = 31; /* Function return instruction. */ |
| pc = regcache_raw_get_signed (regcache, reg); |
| } |
| else |
| pc += 2; |
| break; |
| } |
| case 30: |
| /* This is an instruction extension. Fetch the real instruction |
| (which follows the extension) and decode things based on |
| that. */ |
| { |
| pc += 2; |
| pc = extended_mips16_next_pc (regcache, pc, insn, |
| fetch_mips_16 (gdbarch, pc)); |
| break; |
| } |
| default: |
| { |
| pc += 2; |
| break; |
| } |
| } |
| return pc; |
| } |
| |
| static CORE_ADDR |
| mips16_next_pc (struct regcache *regcache, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| unsigned int insn = fetch_mips_16 (gdbarch, pc); |
| return extended_mips16_next_pc (regcache, pc, 0, insn); |
| } |
| |
| /* The mips_next_pc function supports single_step when the remote |
| target monitor or stub is not developed enough to do a single_step. |
| It works by decoding the current instruction and predicting where a |
| branch will go. This isn't hard because all the data is available. |
| The MIPS32, MIPS16 and microMIPS variants are quite different. */ |
| static CORE_ADDR |
| mips_next_pc (struct regcache *regcache, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = regcache->arch (); |
| |
| if (mips_pc_is_mips16 (gdbarch, pc)) |
| return mips16_next_pc (regcache, pc); |
| else if (mips_pc_is_micromips (gdbarch, pc)) |
| return micromips_next_pc (regcache, pc); |
| else |
| return mips32_next_pc (regcache, pc); |
| } |
| |
| /* Return non-zero if the MIPS16 instruction INSN is a compact branch |
| or jump. */ |
| |
| static int |
| mips16_instruction_is_compact_branch (unsigned short insn) |
| { |
| switch (insn & 0xf800) |
| { |
| case 0xe800: |
| return (insn & 0x009f) == 0x80; /* JALRC/JRC */ |
| case 0x6000: |
| return (insn & 0x0600) == 0; /* BTNEZ/BTEQZ */ |
| case 0x2800: /* BNEZ */ |
| case 0x2000: /* BEQZ */ |
| case 0x1000: /* B */ |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| |
| /* Return non-zero if the microMIPS instruction INSN is a compact branch |
| or jump. */ |
| |
| static int |
| micromips_instruction_is_compact_branch (unsigned short insn) |
| { |
| switch (micromips_op (insn)) |
| { |
| case 0x11: /* POOL16C: bits 010001 */ |
| return (b5s5_op (insn) == 0x18 |
| /* JRADDIUSP: bits 010001 11000 */ |
| || b5s5_op (insn) == 0xd); |
| /* JRC: bits 010011 01101 */ |
| case 0x10: /* POOL32I: bits 010000 */ |
| return (b5s5_op (insn) & 0x1d) == 0x5; |
| /* BEQZC/BNEZC: bits 010000 001x1 */ |
| default: |
| return 0; |
| } |
| } |
| |
| struct mips_frame_cache |
| { |
| CORE_ADDR base; |
| trad_frame_saved_reg *saved_regs; |
| }; |
| |
| /* Set a register's saved stack address in temp_saved_regs. If an |
| address has already been set for this register, do nothing; this |
| way we will only recognize the first save of a given register in a |
| function prologue. |
| |
| For simplicity, save the address in both [0 .. gdbarch_num_regs) and |
| [gdbarch_num_regs .. 2*gdbarch_num_regs). |
| Strictly speaking, only the second range is used as it is only second |
| range (the ABI instead of ISA registers) that comes into play when finding |
| saved registers in a frame. */ |
| |
| static void |
| set_reg_offset (struct gdbarch *gdbarch, struct mips_frame_cache *this_cache, |
| int regnum, CORE_ADDR offset) |
| { |
| if (this_cache != NULL |
| && this_cache->saved_regs[regnum].is_realreg () |
| && this_cache->saved_regs[regnum].realreg () == regnum) |
| { |
| this_cache->saved_regs[regnum + 0 |
| * gdbarch_num_regs (gdbarch)].set_addr (offset); |
| this_cache->saved_regs[regnum + 1 |
| * gdbarch_num_regs (gdbarch)].set_addr (offset); |
| } |
| } |
| |
| |
| /* Fetch the immediate value from a MIPS16 instruction. |
| If the previous instruction was an EXTEND, use it to extend |
| the upper bits of the immediate value. This is a helper function |
| for mips16_scan_prologue. */ |
| |
| static int |
| mips16_get_imm (unsigned short prev_inst, /* previous instruction */ |
| unsigned short inst, /* current instruction */ |
| int nbits, /* number of bits in imm field */ |
| int scale, /* scale factor to be applied to imm */ |
| int is_signed) /* is the imm field signed? */ |
| { |
| int offset; |
| |
| if ((prev_inst & 0xf800) == 0xf000) /* prev instruction was EXTEND? */ |
| { |
| offset = ((prev_inst & 0x1f) << 11) | (prev_inst & 0x7e0); |
| if (offset & 0x8000) /* check for negative extend */ |
| offset = 0 - (0x10000 - (offset & 0xffff)); |
| return offset | (inst & 0x1f); |
| } |
| else |
| { |
| int max_imm = 1 << nbits; |
| int mask = max_imm - 1; |
| int sign_bit = max_imm >> 1; |
| |
| offset = inst & mask; |
| if (is_signed && (offset & sign_bit)) |
| offset = 0 - (max_imm - offset); |
| return offset * scale; |
| } |
| } |
| |
| |
| /* Analyze the function prologue from START_PC to LIMIT_PC. Builds |
| the associated FRAME_CACHE if not null. |
| Return the address of the first instruction past the prologue. */ |
| |
| static CORE_ADDR |
| mips16_scan_prologue (struct gdbarch *gdbarch, |
| CORE_ADDR start_pc, CORE_ADDR limit_pc, |
| const frame_info_ptr &this_frame, |
| struct mips_frame_cache *this_cache) |
| { |
| int prev_non_prologue_insn = 0; |
| int this_non_prologue_insn; |
| int non_prologue_insns = 0; |
| CORE_ADDR prev_pc; |
| CORE_ADDR cur_pc; |
| CORE_ADDR frame_addr = 0; /* Value of $r17, used as frame pointer. */ |
| CORE_ADDR sp; |
| long frame_offset = 0; /* Size of stack frame. */ |
| long frame_adjust = 0; /* Offset of FP from SP. */ |
| int frame_reg = MIPS_SP_REGNUM; |
| unsigned short prev_inst = 0; /* saved copy of previous instruction. */ |
| unsigned inst = 0; /* current instruction */ |
| unsigned entry_inst = 0; /* the entry instruction */ |
| unsigned save_inst = 0; /* the save instruction */ |
| int prev_delay_slot = 0; |
| int in_delay_slot; |
| int reg, offset; |
| |
| int extend_bytes = 0; |
| int prev_extend_bytes = 0; |
| CORE_ADDR end_prologue_addr; |
| |
| /* Can be called when there's no process, and hence when there's no |
| THIS_FRAME. */ |
| if (this_frame != NULL) |
| sp = get_frame_register_signed (this_frame, |
| gdbarch_num_regs (gdbarch) |
| + MIPS_SP_REGNUM); |
| else |
| sp = 0; |
| |
| if (limit_pc > start_pc + 200) |
| limit_pc = start_pc + 200; |
| prev_pc = start_pc; |
| |
| /* Permit at most one non-prologue non-control-transfer instruction |
| in the middle which may have been reordered by the compiler for |
| optimisation. */ |
| for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSN16_SIZE) |
| { |
| this_non_prologue_insn = 0; |
| in_delay_slot = 0; |
| |
| /* Save the previous instruction. If it's an EXTEND, we'll extract |
| the immediate offset extension from it in mips16_get_imm. */ |
| prev_inst = inst; |
| |
| /* Fetch and decode the instruction. */ |
| inst = (unsigned short) mips_fetch_instruction (gdbarch, ISA_MIPS16, |
| cur_pc, NULL); |
| |
| /* Normally we ignore extend instructions. However, if it is |
| not followed by a valid prologue instruction, then this |
| instruction is not part of the prologue either. We must |
| remember in this case to adjust the end_prologue_addr back |
| over the extend. */ |
| if ((inst & 0xf800) == 0xf000) /* extend */ |
| { |
| extend_bytes = MIPS_INSN16_SIZE; |
| continue; |
| } |
| |
| prev_extend_bytes = extend_bytes; |
| extend_bytes = 0; |
| |
| if ((inst & 0xff00) == 0x6300 /* addiu sp */ |
| || (inst & 0xff00) == 0xfb00) /* daddiu sp */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 8, 8, 1); |
| if (offset < 0) /* Negative stack adjustment? */ |
| frame_offset -= offset; |
| else |
| /* Exit loop if a positive stack adjustment is found, which |
| usually means that the stack cleanup code in the function |
| epilogue is reached. */ |
| break; |
| } |
| else if ((inst & 0xf800) == 0xd000) /* sw reg,n($sp) */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 8, 4, 0); |
| reg = mips_reg3_to_reg[(inst & 0x700) >> 8]; |
| set_reg_offset (gdbarch, this_cache, reg, sp + offset); |
| } |
| else if ((inst & 0xff00) == 0xf900) /* sd reg,n($sp) */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 5, 8, 0); |
| reg = mips_reg3_to_reg[(inst & 0xe0) >> 5]; |
| set_reg_offset (gdbarch, this_cache, reg, sp + offset); |
| } |
| else if ((inst & 0xff00) == 0x6200) /* sw $ra,n($sp) */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 8, 4, 0); |
| set_reg_offset (gdbarch, this_cache, MIPS_RA_REGNUM, sp + offset); |
| } |
| else if ((inst & 0xff00) == 0xfa00) /* sd $ra,n($sp) */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 8, 8, 0); |
| set_reg_offset (gdbarch, this_cache, MIPS_RA_REGNUM, sp + offset); |
| } |
| else if (inst == 0x673d) /* move $s1, $sp */ |
| { |
| frame_addr = sp; |
| frame_reg = 17; |
| } |
| else if ((inst & 0xff00) == 0x0100) /* addiu $s1,sp,n */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 8, 4, 0); |
| frame_addr = sp + offset; |
| frame_reg = 17; |
| frame_adjust = offset; |
| } |
| else if ((inst & 0xFF00) == 0xd900) /* sw reg,offset($s1) */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 5, 4, 0); |
| reg = mips_reg3_to_reg[(inst & 0xe0) >> 5]; |
| set_reg_offset (gdbarch, this_cache, reg, frame_addr + offset); |
| } |
| else if ((inst & 0xFF00) == 0x7900) /* sd reg,offset($s1) */ |
| { |
| offset = mips16_get_imm (prev_inst, inst, 5, 8, 0); |
| reg = mips_reg3_to_reg[(inst & 0xe0) >> 5]; |
| set_reg_offset (gdbarch, this_cache, reg, frame_addr + offset); |
| } |
| else if ((inst & 0xf81f) == 0xe809 |
| && (inst & 0x700) != 0x700) /* entry */ |
| entry_inst = inst; /* Save for later processing. */ |
| else if ((inst & 0xff80) == 0x6480) /* save */ |
| { |
| save_inst = inst; /* Save for later processing. */ |
| if (prev_extend_bytes) /* extend */ |
| save_inst |= prev_inst << 16; |
| } |
| else if ((inst & 0xff1c) == 0x6704) /* move reg,$a0-$a3 */ |
| { |
| /* This instruction is part of the prologue, but we don't |
| need to do anything special to handle it. */ |
| } |
| else if (mips16_instruction_has_delay_slot (inst, 0)) |
| /* JAL/JALR/JALX/JR */ |
| { |
| /* The instruction in the delay slot can be a part |
| of the prologue, so move forward once more. */ |
| in_delay_slot = 1; |
| if (mips16_instruction_has_delay_slot (inst, 1)) |
| /* JAL/JALX */ |
| { |
| prev_extend_bytes = MIPS_INSN16_SIZE; |
| cur_pc += MIPS_INSN16_SIZE; /* 32-bit instruction */ |
| } |
| } |
| else |
| { |
| this_non_prologue_insn = 1; |
| } |
| |
| non_prologue_insns += this_non_prologue_insn; |
| |
| /* A jump or branch, or enough non-prologue insns seen? If so, |
| then we must have reached the end of the prologue by now. */ |
| if (prev_delay_slot || non_prologue_insns > 1 |
| || mips16_instruction_is_compact_branch (inst)) |
| break; |
| |
| prev_non_prologue_insn = this_non_prologue_insn; |
| prev_delay_slot = in_delay_slot; |
| prev_pc = cur_pc - prev_extend_bytes; |
| } |
| |
| /* The entry instruction is typically the first instruction in a function, |
| and it stores registers at offsets relative to the value of the old SP |
| (before the prologue). But the value of the sp parameter to this |
| function is the new SP (after the prologue has been executed). So we |
| can't calculate those offsets until we've seen the entire prologue, |
| and can calculate what the old SP must have been. */ |
| if (entry_inst != 0) |
| { |
| int areg_count = (entry_inst >> 8) & 7; |
| int sreg_count = (entry_inst >> 6) & 3; |
| |
| /* The entry instruction always subtracts 32 from the SP. */ |
| frame_offset += 32; |
| |
| /* Now we can calculate what the SP must have been at the |
| start of the function prologue. */ |
| sp += frame_offset; |
| |
| /* Check if a0-a3 were saved in the caller's argument save area. */ |
| for (reg = 4, offset = 0; reg < areg_count + 4; reg++) |
| { |
| set_reg_offset (gdbarch, this_cache, reg, sp + offset); |
| offset += mips_abi_regsize (gdbarch); |
| } |
| |
| /* Check if the ra register was pushed on the stack. */ |
| offset = -4; |
| if (entry_inst & 0x20) |
| { |
| set_reg_offset (gdbarch, this_cache, MIPS_RA_REGNUM, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| } |
| |
| /* Check if the s0 and s1 registers were pushed on the stack. */ |
| for (reg = 16; reg < sreg_count + 16; reg++) |
| { |
| set_reg_offset (gdbarch, this_cache, reg, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| } |
| } |
| |
| /* The SAVE instruction is similar to ENTRY, except that defined by the |
| MIPS16e ASE of the MIPS Architecture. Unlike with ENTRY though, the |
| size of the frame is specified as an immediate field of instruction |
| and an extended variation exists which lets additional registers and |
| frame space to be specified. The instruction always treats registers |
| as 32-bit so its usefulness for 64-bit ABIs is questionable. */ |
| if (save_inst != 0 && mips_abi_regsize (gdbarch) == 4) |
| { |
| static int args_table[16] = { |
| 0, 0, 0, 0, 1, 1, 1, 1, |
| 2, 2, 2, 0, 3, 3, 4, -1, |
| }; |
| static int astatic_table[16] = { |
| 0, 1, 2, 3, 0, 1, 2, 3, |
| 0, 1, 2, 4, 0, 1, 0, -1, |
| }; |
| int aregs = (save_inst >> 16) & 0xf; |
| int xsregs = (save_inst >> 24) & 0x7; |
| int args = args_table[aregs]; |
| int astatic = astatic_table[aregs]; |
| long frame_size; |
| |
| if (args < 0) |
| { |
| warning (_("Invalid number of argument registers encoded in SAVE.")); |
| args = 0; |
| } |
| if (astatic < 0) |
| { |
| warning (_("Invalid number of static registers encoded in SAVE.")); |
| astatic = 0; |
| } |
| |
| /* For standard SAVE the frame size of 0 means 128. */ |
| frame_size = ((save_inst >> 16) & 0xf0) | (save_inst & 0xf); |
| if (frame_size == 0 && (save_inst >> 16) == 0) |
| frame_size = 16; |
| frame_size *= 8; |
| frame_offset += frame_size; |
| |
| /* Now we can calculate what the SP must have been at the |
| start of the function prologue. */ |
| sp += frame_offset; |
| |
| /* Check if A0-A3 were saved in the caller's argument save area. */ |
| for (reg = MIPS_A0_REGNUM, offset = 0; reg < args + 4; reg++) |
| { |
| set_reg_offset (gdbarch, this_cache, reg, sp + offset); |
| offset += mips_abi_regsize (gdbarch); |
| } |
| |
| offset = -4; |
| |
| /* Check if the RA register was pushed on the stack. */ |
| if (save_inst & 0x40) |
| { |
| set_reg_offset (gdbarch, this_cache, MIPS_RA_REGNUM, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| } |
| |
| /* Check if the S8 register was pushed on the stack. */ |
| if (xsregs > 6) |
| { |
| set_reg_offset (gdbarch, this_cache, 30, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| xsregs--; |
| } |
| /* Check if S2-S7 were pushed on the stack. */ |
| for (reg = 18 + xsregs - 1; reg > 18 - 1; reg--) |
| { |
| set_reg_offset (gdbarch, this_cache, reg, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| } |
| |
| /* Check if the S1 register was pushed on the stack. */ |
| if (save_inst & 0x10) |
| { |
| set_reg_offset (gdbarch, this_cache, 17, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| } |
| /* Check if the S0 register was pushed on the stack. */ |
| if (save_inst & 0x20) |
| { |
| set_reg_offset (gdbarch, this_cache, 16, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| } |
| |
| /* Check if A0-A3 were pushed on the stack. */ |
| for (reg = MIPS_A0_REGNUM + 3; reg > MIPS_A0_REGNUM + 3 - astatic; reg--) |
| { |
| set_reg_offset (gdbarch, this_cache, reg, sp + offset); |
| offset -= mips_abi_regsize (gdbarch); |
| } |
| } |
| |
| if (this_cache != NULL) |
| { |
| this_cache->base = |
| (get_frame_register_signed (this_frame, |
| gdbarch_num_regs (gdbarch) + frame_reg) |
| + frame_offset - frame_adjust); |
| /* FIXME: brobecker/2004-10-10: Just as in the mips32 case, we should |
| be able to get rid of the assignment below, evetually. But it's |
| still needed for now. */ |
| this_cache->saved_regs[gdbarch_num_regs (gdbarch) |
| + mips_regnum (gdbarch)->pc] |
| = this_cache->saved_regs[gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM]; |
| } |
| |
| /* Set end_prologue_addr to the address of the instruction immediately |
| after the last one we scanned. Unless the last one looked like a |
| non-prologue instruction (and we looked ahead), in which case use |
| its address instead. */ |
| end_prologue_addr = (prev_non_prologue_insn || prev_delay_slot |
| ? prev_pc : cur_pc - prev_extend_bytes); |
| |
| return end_prologue_addr; |
| } |
| |
| /* Heuristic unwinder for 16-bit MIPS instruction set (aka MIPS16). |
| Procedures that use the 32-bit instruction set are handled by the |
| mips_insn32 unwinder. */ |
| |
| static struct mips_frame_cache * |
| mips_insn16_frame_cache (const frame_info_ptr &this_frame, void **this_cache) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| struct mips_frame_cache *cache; |
| |
| if ((*this_cache) != NULL) |
| return (struct mips_frame_cache *) (*this_cache); |
| cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache); |
| (*this_cache) = cache; |
| cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); |
| |
| /* Analyze the function prologue. */ |
| { |
| const CORE_ADDR pc = get_frame_address_in_block (this_frame); |
| CORE_ADDR start_addr; |
| |
| find_pc_partial_function (pc, NULL, &start_addr, NULL); |
| if (start_addr == 0) |
| start_addr = heuristic_proc_start (gdbarch, pc); |
| /* We can't analyze the prologue if we couldn't find the begining |
| of the function. */ |
| if (start_addr == 0) |
| return cache; |
| |
| mips16_scan_prologue (gdbarch, start_addr, pc, this_frame, |
| (struct mips_frame_cache *) *this_cache); |
| } |
| |
| /* gdbarch_sp_regnum contains the value and not the address. */ |
| cache->saved_regs[gdbarch_num_regs (gdbarch) |
| + MIPS_SP_REGNUM].set_value (cache->base); |
| |
| return (struct mips_frame_cache *) (*this_cache); |
| } |
| |
| static void |
| mips_insn16_frame_this_id (const frame_info_ptr &this_frame, void **this_cache, |
| struct frame_id *this_id) |
| { |
| struct mips_frame_cache *info = mips_insn16_frame_cache (this_frame, |
| this_cache); |
| /* This marks the outermost frame. */ |
| if (info->base == 0) |
| return; |
| (*this_id) = frame_id_build (info->base, get_frame_func (this_frame)); |
| } |
| |
| static struct value * |
| mips_insn16_frame_prev_register (const frame_info_ptr &this_frame, |
| void **this_cache, int regnum) |
| { |
| struct mips_frame_cache *info = mips_insn16_frame_cache (this_frame, |
| this_cache); |
| return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); |
| } |
| |
| static int |
| mips_insn16_frame_sniffer (const struct frame_unwind *self, |
| const frame_info_ptr &this_frame, void **this_cache) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| CORE_ADDR pc = get_frame_pc (this_frame); |
| if (mips_pc_is_mips16 (gdbarch, pc)) |
| return 1; |
| return 0; |
| } |
| |
| static const struct frame_unwind mips_insn16_frame_unwind = |
| { |
| "mips insn16 prologue", |
| NORMAL_FRAME, |
| default_frame_unwind_stop_reason, |
| mips_insn16_frame_this_id, |
| mips_insn16_frame_prev_register, |
| NULL, |
| mips_insn16_frame_sniffer |
| }; |
| |
| static CORE_ADDR |
| mips_insn16_frame_base_address (const frame_info_ptr &this_frame, |
| void **this_cache) |
| { |
| struct mips_frame_cache *info = mips_insn16_frame_cache (this_frame, |
| this_cache); |
| return info->base; |
| } |
| |
| static const struct frame_base mips_insn16_frame_base = |
| { |
| &mips_insn16_frame_unwind, |
| mips_insn16_frame_base_address, |
| mips_insn16_frame_base_address, |
| mips_insn16_frame_base_address |
| }; |
| |
| static const struct frame_base * |
| mips_insn16_frame_base_sniffer (const frame_info_ptr &this_frame) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| CORE_ADDR pc = get_frame_pc (this_frame); |
| if (mips_pc_is_mips16 (gdbarch, pc)) |
| return &mips_insn16_frame_base; |
| else |
| return NULL; |
| } |
| |
| /* Decode a 9-bit signed immediate argument of ADDIUSP -- -2 is mapped |
| to -258, -1 -- to -257, 0 -- to 256, 1 -- to 257 and other values are |
| interpreted directly, and then multiplied by 4. */ |
| |
| static int |
| micromips_decode_imm9 (int imm) |
| { |
| imm = (imm ^ 0x100) - 0x100; |
| if (imm > -3 && imm < 2) |
| imm ^= 0x100; |
| return imm << 2; |
| } |
| |
| /* Analyze the function prologue from START_PC to LIMIT_PC. Return |
| the address of the first instruction past the prologue. */ |
| |
| static CORE_ADDR |
| micromips_scan_prologue (struct gdbarch *gdbarch, |
| CORE_ADDR start_pc, CORE_ADDR limit_pc, |
| const frame_info_ptr &this_frame, |
| struct mips_frame_cache *this_cache) |
| { |
| CORE_ADDR end_prologue_addr; |
| int prev_non_prologue_insn = 0; |
| int frame_reg = MIPS_SP_REGNUM; |
| int this_non_prologue_insn; |
| int non_prologue_insns = 0; |
| long frame_offset = 0; /* Size of stack frame. */ |
| long frame_adjust = 0; /* Offset of FP from SP. */ |
| int prev_delay_slot = 0; |
| int in_delay_slot; |
| CORE_ADDR prev_pc; |
| CORE_ADDR cur_pc; |
| ULONGEST insn; /* current instruction */ |
| CORE_ADDR sp; |
| long offset; |
| long sp_adj; |
| long v1_off = 0; /* The assumption is LUI will replace it. */ |
| int reglist; |
| int breg; |
| int dreg; |
| int sreg |