| /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger. |
| |
| Copyright (C) 1988-2012 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 "defs.h" |
| #include "gdb_string.h" |
| #include "gdb_assert.h" |
| #include "frame.h" |
| #include "inferior.h" |
| #include "symtab.h" |
| #include "value.h" |
| #include "gdbcmd.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 "frame-unwind.h" |
| #include "frame-base.h" |
| #include "trad-frame.h" |
| #include "infcall.h" |
| #include "floatformat.h" |
| #include "remote.h" |
| #include "target-descriptions.h" |
| #include "dwarf2-frame.h" |
| #include "user-regs.h" |
| #include "valprint.h" |
| #include "ax.h" |
| |
| static const struct objfile_data *mips_pdr_data; |
| |
| static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum); |
| |
| static int mips32_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR); |
| static int micromips_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR, |
| int); |
| static int mips16_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR, |
| int); |
| |
| /* 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 |
| }; |
| |
| /* 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 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; |
| |
| const struct mips_regnum * |
| mips_regnum (struct gdbarch *gdbarch) |
| { |
| return gdbarch_tdep (gdbarch)->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); |
| } |
| |
| #define MIPS_EABI(gdbarch) (gdbarch_tdep (gdbarch)->mips_abi \ |
| == MIPS_ABI_EABI32 \ |
| || gdbarch_tdep (gdbarch)->mips_abi == MIPS_ABI_EABI64) |
| |
| #define MIPS_LAST_FP_ARG_REGNUM(gdbarch) \ |
| (gdbarch_tdep (gdbarch)->mips_last_fp_arg_regnum) |
| |
| #define MIPS_LAST_ARG_REGNUM(gdbarch) \ |
| (gdbarch_tdep (gdbarch)->mips_last_arg_regnum) |
| |
| #define MIPS_FPU_TYPE(gdbarch) (gdbarch_tdep (gdbarch)->mips_fpu_type) |
| |
| /* Return the MIPS ABI associated with GDBARCH. */ |
| enum mips_abi |
| mips_abi (struct gdbarch *gdbarch) |
| { |
| return gdbarch_tdep (gdbarch)->mips_abi; |
| } |
| |
| int |
| mips_isa_regsize (struct gdbarch *gdbarch) |
| { |
| struct gdbarch_tdep *tdep = 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); |
| } |
| |
| /* 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 (__FILE__, __LINE__, _("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) |
| { |
| return gdbarch_tdep (gdbarch)->mips_isa == ISA_MIPS16; |
| } |
| |
| /* Return one iff compressed code is the microMIPS instruction set. */ |
| |
| static int |
| is_micromips_isa (struct gdbarch *gdbarch) |
| { |
| return gdbarch_tdep (gdbarch)->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); |
| } |
| |
| /* 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; in particular synthetic symbols such as for PLT stubs |
| have no ELF-private part at all. |
| |
| 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; |
| |
| if ((sym->flags & BSF_SYNTHETIC) != 0) |
| return; |
| |
| if (ELF_ST_IS_MICROMIPS (elfsym->internal_elf_sym.st_other)) |
| MSYMBOL_TARGET_FLAG_2 (msym) = 1; |
| else if (ELF_ST_IS_MIPS16 (elfsym->internal_elf_sym.st_other)) |
| MSYMBOL_TARGET_FLAG_1 (msym) = 1; |
| } |
| |
| /* Return one iff MSYM refers to standard ISA code. */ |
| |
| static int |
| msymbol_is_mips (struct minimal_symbol *msym) |
| { |
| return !(MSYMBOL_TARGET_FLAG_1 (msym) | MSYMBOL_TARGET_FLAG_2 (msym)); |
| } |
| |
| /* Return one iff MSYM refers to MIPS16 code. */ |
| |
| static int |
| msymbol_is_mips16 (struct minimal_symbol *msym) |
| { |
| return MSYMBOL_TARGET_FLAG_1 (msym); |
| } |
| |
| /* Return one iff MSYM refers to microMIPS code. */ |
| |
| static int |
| msymbol_is_micromips (struct minimal_symbol *msym) |
| { |
| return MSYMBOL_TARGET_FLAG_2 (msym); |
| } |
| |
| /* 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 (__FILE__, __LINE__, _("bad switch")); |
| } |
| if (mips_debug) |
| fprintf_unfiltered (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; |
| fprintf_unfiltered (gdb_stdlog, "out "); |
| for (i = 0; i < length; i++) |
| fprintf_unfiltered (gdb_stdlog, "%02x", out[buf_offset + i]); |
| } |
| if (in != NULL) |
| regcache_cooked_read_part (regcache, reg_num, reg_offset, length, |
| in + buf_offset); |
| if (out != NULL) |
| regcache_cooked_write_part (regcache, reg_num, reg_offset, length, |
| out + buf_offset); |
| if (mips_debug && in != NULL) |
| { |
| int i; |
| fprintf_unfiltered (gdb_stdlog, "in "); |
| for (i = 0; i < length; i++) |
| fprintf_unfiltered (gdb_stdlog, "%02x", in[buf_offset + i]); |
| } |
| if (mips_debug) |
| fprintf_unfiltered (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 (struct frame_info *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); |
| |
| static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *); |
| |
| /* 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 *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 IDT R3041 registers. */ |
| |
| static const char *mips_r3041_reg_names[] = { |
| "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", "", /*"fp" */ "", |
| "", "", "bus", "ccfg", "", "", "", "", |
| "", "", "port", "cmp", "", "", "epc", "prid", |
| }; |
| |
| /* Names of tx39 registers. */ |
| |
| static const char *mips_tx39_reg_names[NUM_MIPS_PROCESSOR_REGS] = { |
| "sr", "lo", "hi", "bad", "cause", "pc", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "", "", |
| "", "", "", "", "", "", "", "", |
| "", "", "config", "cache", "debug", "depc", "epc", |
| }; |
| |
| /* Names of IRIX registers. */ |
| static const char *mips_irix_reg_names[NUM_MIPS_PROCESSOR_REGS] = { |
| "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", |
| "pc", "cause", "bad", "hi", "lo", "fsr", "fir" |
| }; |
| |
| /* Names of registers with Linux kernels. */ |
| static const char *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) |
| { |
| struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); |
| /* GPR names for all ABIs other than n32/n64. */ |
| static 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 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 (__FILE__, __LINE__, |
| _("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, |
| 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 = TYPE_VECTOR (register_type (gdbarch, regnum)); |
| float_p = TYPE_CODE (register_type (gdbarch, regnum)) == 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) == NULL |
| || 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, |
| 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, struct 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 (regcache, rawnum, buf); |
| else if (register_size (gdbarch, rawnum) > |
| register_size (gdbarch, cookednum)) |
| { |
| if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p) |
| return regcache_raw_read_part (regcache, rawnum, 0, 4, buf); |
| else |
| { |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| LONGEST regval; |
| enum register_status status; |
| |
| status = regcache_raw_read_signed (regcache, rawnum, ®val); |
| if (status == REG_VALID) |
| store_signed_integer (buf, 4, byte_order, regval); |
| return status; |
| } |
| } |
| else |
| internal_error (__FILE__, __LINE__, _("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 (regcache, rawnum, buf); |
| else if (register_size (gdbarch, rawnum) > |
| register_size (gdbarch, cookednum)) |
| { |
| if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p) |
| regcache_raw_write_part (regcache, 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 (__FILE__, __LINE__, _("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)) |
| { |
| if (!gdbarch_tdep (gdbarch)->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 (__FILE__, __LINE__, _("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 unsigned 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 int mips64_transfers_32bit_regs_p = 0; |
| |
| static void |
| set_mips64_transfers_32bit_regs (char *args, int from_tty, |
| struct cmd_list_element *c) |
| { |
| struct gdbarch_info info; |
| gdbarch_info_init (&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 (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) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 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 (type) < 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 (struct frame_info *frame, int regnum, |
| struct type *type, gdb_byte *to, |
| int *optimizedp, int *unavailablep) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (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 (frame, regnum + 0, 0, 4, to + 4, |
| optimizedp, unavailablep)) |
| return 0; |
| |
| if (!get_frame_register_bytes (frame, regnum + 1, 0, 4, to + 0, |
| optimizedp, unavailablep)) |
| return 0; |
| *optimizedp = *unavailablep = 0; |
| return 1; |
| } |
| else if (mips_convert_register_gpreg_case_p (gdbarch, regnum, type)) |
| { |
| int len = TYPE_LENGTH (type); |
| CORE_ADDR offset; |
| |
| offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 - len : 0; |
| if (!get_frame_register_bytes (frame, regnum, offset, len, to, |
| optimizedp, unavailablep)) |
| return 0; |
| |
| *optimizedp = *unavailablep = 0; |
| return 1; |
| } |
| else |
| { |
| internal_error (__FILE__, __LINE__, |
| _("mips_register_to_value: unrecognized case")); |
| } |
| } |
| |
| static void |
| mips_value_to_register (struct frame_info *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)) |
| { |
| put_frame_register (frame, regnum + 0, from + 4); |
| put_frame_register (frame, regnum + 1, from + 0); |
| } |
| else if (mips_convert_register_gpreg_case_p (gdbarch, regnum, type)) |
| { |
| gdb_byte fill[8]; |
| int len = TYPE_LENGTH (type); |
| |
| /* 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 (frame, regnum, 0, 8 - len, fill); |
| put_frame_register_bytes (frame, regnum, 8 - len, len, from); |
| } |
| 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 (frame, regnum, 0, len, from); |
| put_frame_register_bytes (frame, regnum, len, 8 - len, fill); |
| } |
| } |
| else |
| { |
| internal_error (__FILE__, __LINE__, |
| _("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); |
| |
| /* 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_IRIX |
| && 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 (gdbarch_tdep (gdbarch)->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 (TYPE_LENGTH (rawtype) == 0) |
| return rawtype; |
| |
| if (mips_float_register_p (gdbarch, rawnum)) |
| /* Present the floating point registers however the hardware did; |
| do not try to convert between FPU layouts. */ |
| return rawtype; |
| |
| /* 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) |
| == TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr)) |
| { |
| 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 && TYPE_LENGTH (rawtype) == 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; |
| |
| if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX |
| && gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX |
| && rawnum >= MIPS_EMBED_FP0_REGNUM + 32 |
| && rawnum <= MIPS_LAST_EMBED_REGNUM) |
| { |
| /* 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. */ |
| 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? */ |
| enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO; |
| |
| static int |
| mips_mask_address_p (struct 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 (__FILE__, __LINE__, |
| _("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) |
| { |
| struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch); |
| |
| deprecated_show_value_hack (file, from_tty, c, value); |
| switch (mask_address_var) |
| { |
| case AUTO_BOOLEAN_TRUE: |
| printf_filtered ("The 32 bit mips address mask is enabled\n"); |
| break; |
| case AUTO_BOOLEAN_FALSE: |
| printf_filtered ("The 32 bit mips address mask is disabled\n"); |
| break; |
| case AUTO_BOOLEAN_AUTO: |
| printf_filtered |
| ("The 32 bit address mask is set automatically. Currently %s\n", |
| mips_mask_address_p (tdep) ? "enabled" : "disabled"); |
| break; |
| default: |
| internal_error (__FILE__, __LINE__, _("show_mask_address: bad switch")); |
| break; |
| } |
| } |
| |
| /* Tell if the program counter value in MEMADDR is in a standard ISA |
| function. */ |
| |
| int |
| mips_pc_is_mips (CORE_ADDR memaddr) |
| { |
| struct minimal_symbol *sym; |
| |
| /* 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. */ |
| sym = lookup_minimal_symbol_by_pc (memaddr); |
| if (sym) |
| return msymbol_is_mips (sym); |
| 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) |
| { |
| struct minimal_symbol *sym; |
| |
| /* 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. */ |
| sym = lookup_minimal_symbol_by_pc (memaddr); |
| if (sym) |
| return msymbol_is_mips16 (sym); |
| 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) |
| { |
| struct minimal_symbol *sym; |
| |
| /* 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. */ |
| sym = lookup_minimal_symbol_by_pc (memaddr); |
| if (sym) |
| return msymbol_is_micromips (sym); |
| 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) |
| { |
| struct minimal_symbol *sym; |
| |
| /* 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. */ |
| sym = lookup_minimal_symbol_by_pc (memaddr); |
| if (sym) |
| { |
| if (msymbol_is_micromips (sym)) |
| return ISA_MICROMIPS; |
| else if (msymbol_is_mips16 (sym)) |
| 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; |
| } |
| } |
| |
| /* 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 (strncmp (name, mips_str_mips16_call_stub, |
| strlen (mips_str_mips16_call_stub)) == 0) |
| return 1; |
| /* If the PC is in __call_stub_*, this is a call/return or a call stub. */ |
| if (strncmp (name, mips_str_call_stub, strlen (mips_str_call_stub)) == 0) |
| return 1; |
| /* If the PC is in __fn_stub_*, this is a call stub. */ |
| if (strncmp (name, mips_str_fn_stub, strlen (mips_str_fn_stub)) == 0) |
| 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 (struct regcache *regcache) |
| { |
| int regnum = gdbarch_pc_regnum (get_regcache_arch (regcache)); |
| ULONGEST pc; |
| |
| regcache_cooked_read_signed (regcache, regnum, &pc); |
| if (is_compact_addr (pc)) |
| pc = unmake_compact_addr (pc); |
| return pc; |
| } |
| |
| static CORE_ADDR |
| mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) |
| { |
| CORE_ADDR pc; |
| |
| pc = frame_unwind_register_signed (next_frame, gdbarch_pc_regnum (gdbarch)); |
| if (is_compact_addr (pc)) |
| pc = unmake_compact_addr (pc); |
| /* 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 (is_compact_addr (pc)) |
| pc = unmake_compact_addr (pc); |
| if (mips_in_frame_stub (pc)) |
| { |
| pc = frame_unwind_register_signed |
| (next_frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM); |
| if (is_compact_addr (pc)) |
| pc = unmake_compact_addr (pc); |
| } |
| } |
| return pc; |
| } |
| |
| static CORE_ADDR |
| mips_unwind_sp (struct gdbarch *gdbarch, struct frame_info *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, struct frame_info *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 (get_regcache_arch (regcache)); |
| |
| if (mips_pc_is_mips (pc)) |
| regcache_cooked_write_unsigned (regcache, regnum, pc); |
| else |
| regcache_cooked_write_unsigned (regcache, regnum, make_compact_addr (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 *statusp) |
| { |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| gdb_byte buf[MIPS_INSN32_SIZE]; |
| int instlen; |
| int status; |
| |
| 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 (__FILE__, __LINE__, _("invalid ISA")); |
| break; |
| } |
| status = target_read_memory (addr, buf, instlen); |
| if (statusp != NULL) |
| *statusp = status; |
| if (status) |
| { |
| if (statusp == NULL) |
| memory_error (status, 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) == 0x1f) |
| return 3 * MIPS_INSN16_SIZE; |
| else 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 (__FILE__, __LINE__, _("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 frame_info *frame, |
| 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 = get_frame_register_unsigned (frame, fcsr); |
| cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01); |
| |
| if (((cond >> cnum) & mask) != mask * !tf) |
| pc += mips32_relative_offset (inst); |
| else |
| pc += 4; |
| |
| return pc; |
| } |
| |
| /* Determine where to set a single step breakpoint while considering |
| branch prediction. */ |
| static CORE_ADDR |
| mips32_next_pc (struct frame_info *frame, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| unsigned long inst; |
| int op; |
| inst = mips_fetch_instruction (gdbarch, ISA_MIPS, pc, NULL); |
| if ((inst & 0xe0000000) != 0) /* Not a special, jump or branch |
| instruction. */ |
| { |
| if (itype_op (inst) >> 2 == 5) |
| /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */ |
| { |
| op = (itype_op (inst) & 0x03); |
| switch (op) |
| { |
| 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 (itype_op (inst) == 17 && itype_rs (inst) == 8) |
| /* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */ |
| pc = mips32_bc1_pc (gdbarch, frame, inst, pc + 4, 1); |
| else if (itype_op (inst) == 17 && itype_rs (inst) == 9 |
| && (itype_rt (inst) & 2) == 0) |
| /* BC1ANY2F, BC1ANY2T: 010001 01001 xxx0x */ |
| pc = mips32_bc1_pc (gdbarch, frame, inst, pc + 4, 2); |
| else if (itype_op (inst) == 17 && itype_rs (inst) == 10 |
| && (itype_rt (inst) & 2) == 0) |
| /* BC1ANY4F, BC1ANY4T: 010001 01010 xxx0x */ |
| pc = mips32_bc1_pc (gdbarch, frame, inst, pc + 4, 4); |
| else if (itype_op (inst) == 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 |
| pc += 4; /* Not a branch, next instruction is easy. */ |
| } |
| else |
| { /* This gets way messy. */ |
| |
| /* Further subdivide into SPECIAL, REGIMM and other. */ |
| switch (op = itype_op (inst) & 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 = get_frame_register_signed (frame, rtype_rs (inst)); |
| break; |
| case 12: /* SYSCALL */ |
| { |
| struct gdbarch_tdep *tdep; |
| |
| tdep = gdbarch_tdep (get_frame_arch (frame)); |
| if (tdep->syscall_next_pc != NULL) |
| pc = tdep->syscall_next_pc (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 (get_frame_register_signed (frame, 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 (get_frame_register_signed (frame, 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 ((get_frame_register_unsigned (frame, |
| 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 (get_frame_register_signed (frame, itype_rs (inst)) == |
| get_frame_register_signed (frame, itype_rt (inst))) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; |
| break; |
| case 5: /* BNE, BNEL */ |
| neq_branch: |
| if (get_frame_register_signed (frame, itype_rs (inst)) != |
| get_frame_register_signed (frame, itype_rt (inst))) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; |
| break; |
| case 6: /* BLEZ, BLEZL */ |
| if (get_frame_register_signed (frame, itype_rs (inst)) <= 0) |
| pc += mips32_relative_offset (inst) + 4; |
| else |
| pc += 8; |
| break; |
| case 7: |
| default: |
| greater_branch: /* BGTZ, BGTZL */ |
| if (get_frame_register_signed (frame, 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 frame_info *frame, |
| 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 = get_frame_register_unsigned (frame, 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 frame_info *frame, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| ULONGEST insn; |
| |
| insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, pc, NULL); |
| pc += MIPS_INSN16_SIZE; |
| switch (mips_insn_size (ISA_MICROMIPS, insn)) |
| { |
| /* 48-bit instructions. */ |
| case 3 * MIPS_INSN16_SIZE: /* POOL48A: bits 011111 */ |
| /* No branch or jump instructions in this category. */ |
| pc += 2 * MIPS_INSN16_SIZE; |
| break; |
| |
| /* 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 */ |
| if (b0s6_op (insn) == 0x3c |
| /* POOL32Axf: bits 000000 ... 111100 */ |
| && (b6s10_ext (insn) & 0x2bf) == 0x3c) |
| /* JALR, JALR.HB: 000000 000x111100 111100 */ |
| /* JALRS, JALRS.HB: 000000 010x111100 111100 */ |
| pc = get_frame_register_signed (frame, b0s5_reg (insn >> 16)); |
| 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 (get_frame_register_signed (frame, |
| 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 (get_frame_register_signed (frame, |
| 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 (get_frame_register_signed (frame, |
| 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 (get_frame_register_signed (frame, |
| b0s5_reg (insn >> 16)) != 0) |
| pc += micromips_relative_offset16 (insn); |
| break; |
| |
| case 0x06: /* BGTZ: bits 010000 00110 */ |
| if (get_frame_register_signed (frame, |
| 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 (get_frame_register_signed (frame, |
| 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 ((get_frame_register_unsigned (frame, |
| 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, frame, 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, frame, 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 (get_frame_register_signed (frame, b0s5_reg (insn >> 16)) |
| == get_frame_register_signed (frame, b5s5_reg (insn >> 16))) |
| pc += micromips_relative_offset16 (insn); |
| else |
| pc += micromips_pc_insn_size (gdbarch, pc); |
| break; |
| |
| case 0x2d: /* BNE: bits 101101 */ |
| if (get_frame_register_signed (frame, b0s5_reg (insn >> 16)) |
| != get_frame_register_signed (frame, 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 = get_frame_register_signed (frame, b0s5_reg (insn)); |
| else if (b5s5_op (insn) == 0x18) |
| /* JRADDIUSP: bits 010001 11000 */ |
| pc = get_frame_register_signed (frame, MIPS_RA_REGNUM); |
| break; |
| |
| case 0x23: /* BEQZ16: bits 100011 */ |
| { |
| int rs = mips_reg3_to_reg[b7s3_reg (insn)]; |
| |
| if (get_frame_register_signed (frame, 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 (get_frame_register_signed (frame, 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 &= 0xfffffffe; /* 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 (__FILE__, __LINE__, _("bad switch")); |
| } |
| upk->offset = offset; |
| upk->regx = regx; |
| upk->regy = regy; |
| } |
| |
| |
| static CORE_ADDR |
| add_offset_16 (CORE_ADDR pc, int offset) |
| { |
| return ((offset << 2) | ((pc + 2) & (~(CORE_ADDR) 0x0fffffff))); |
| } |
| |
| static CORE_ADDR |
| extended_mips16_next_pc (struct frame_info *frame, CORE_ADDR pc, |
| unsigned int extension, unsigned int insn) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| int op = (insn >> 11); |
| switch (op) |
| { |
| case 2: /* Branch */ |
| { |
| struct upk_mips16 upk; |
| unpack_mips16 (gdbarch, pc, extension, insn, itype, &upk); |
| pc += (upk.offset << 1) + 2; |
| 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 = add_offset_16 (pc, upk.offset); |
| 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 = get_frame_register_signed (frame, mips_reg3_to_reg[upk.regx]); |
| if (reg == 0) |
| pc += (upk.offset << 1) + 2; |
| else |
| pc += 2; |
| break; |
| } |
| case 5: /* bnez */ |
| { |
| struct upk_mips16 upk; |
| int reg; |
| unpack_mips16 (gdbarch, pc, extension, insn, ritype, &upk); |
| reg = get_frame_register_signed (frame, mips_reg3_to_reg[upk.regx]); |
| if (reg != 0) |
| pc += (upk.offset << 1) + 2; |
| 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 */ |
| reg = get_frame_register_signed (frame, 24); /* Test register is 24 */ |
| if (((upk.regx == 0) && (reg == 0)) /* BTEZ */ |
| || ((upk.regx == 1) && (reg != 0))) /* BTNEZ */ |
| /* pc = add_offset_16(pc,upk.offset) ; */ |
| pc += (upk.offset << 1) + 2; |
| 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 = get_frame_register_signed (frame, 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 (frame, pc, insn, |
| fetch_mips_16 (gdbarch, pc)); |
| break; |
| } |
| default: |
| { |
| pc += 2; |
| break; |
| } |
| } |
| return pc; |
| } |
| |
| static CORE_ADDR |
| mips16_next_pc (struct frame_info *frame, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| unsigned int insn = fetch_mips_16 (gdbarch, pc); |
| return extended_mips16_next_pc (frame, 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 isnt hard because all the data is available. |
| The MIPS32, MIPS16 and microMIPS variants are quite different. */ |
| static CORE_ADDR |
| mips_next_pc (struct frame_info *frame, CORE_ADDR pc) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (frame); |
| |
| if (mips_pc_is_mips16 (gdbarch, pc)) |
| return mips16_next_pc (frame, pc); |
| else if (mips_pc_is_micromips (gdbarch, pc)) |
| return micromips_next_pc (frame, pc); |
| else |
| return mips32_next_pc (frame, pc); |
| } |
| |
| struct mips_frame_cache |
| { |
| CORE_ADDR base; |
| struct 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].addr == -1) |
| { |
| this_cache->saved_regs[regnum + 0 * gdbarch_num_regs (gdbarch)].addr |
| = offset; |
| this_cache->saved_regs[regnum + 1 * gdbarch_num_regs (gdbarch)].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, |
| struct frame_info *this_frame, |
| struct mips_frame_cache *this_cache) |
| { |
| 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 reg, offset; |
| |
| int extend_bytes = 0; |
| int prev_extend_bytes; |
| CORE_ADDR end_prologue_addr = 0; |
| |
| /* 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; |
| |
| for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSN16_SIZE) |
| { |
| /* 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 & 0xf800) == 0x1800) /* jal(x) */ |
| cur_pc += MIPS_INSN16_SIZE; /* 32-bit instruction */ |
| 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 |
| { |
| /* This instruction is not an instruction typically found |
| in a prologue, so we must have reached the end of the |
| prologue. */ |
| if (end_prologue_addr == 0) |
| end_prologue_addr = 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]; |
| } |
| |
| /* If we didn't reach the end of the prologue when scanning the function |
| instructions, then set end_prologue_addr to the address of the |
| instruction immediately after the last one we scanned. */ |
| if (end_prologue_addr == 0) |
| end_prologue_addr = cur_pc; |
| |
| 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 (struct frame_info *this_frame, void **this_cache) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| struct mips_frame_cache *cache; |
| |
| if ((*this_cache) != NULL) |
| return (*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, *this_cache); |
| } |
| |
| /* gdbarch_sp_regnum contains the value and not the address. */ |
| trad_frame_set_value (cache->saved_regs, |
| gdbarch_num_regs (gdbarch) + MIPS_SP_REGNUM, |
| cache->base); |
| |
| return (*this_cache); |
| } |
| |
| static void |
| mips_insn16_frame_this_id (struct frame_info *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 (struct frame_info *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, |
| struct frame_info *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 = |
| { |
| 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 (struct frame_info *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 (struct frame_info *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, |
| struct frame_info *this_frame, |
| struct mips_frame_cache *this_cache) |
| { |
| CORE_ADDR end_prologue_addr = 0; |
| 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. */ |
| CORE_ADDR frame_addr = 0; /* Value of $30, used as frame pointer. */ |
| 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; |
| int treg; |
| int loc; |
| int op; |
| int s; |
| int i; |
| |
| /* 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 += loc) |
| { |
| this_non_prologue_insn = 0; |
| sp_adj = 0; |
| loc = 0; |
| insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, cur_pc, NULL); |
| loc += MIPS_INSN16_SIZE; |
| switch (mips_insn_size (ISA_MICROMIPS, insn)) |
| { |
| /* 48-bit instructions. */ |
| case 3 * MIPS_INSN16_SIZE: |
| /* No prologue instructions in this category. */ |
| this_non_prologue_insn = 1; |
| loc += 2 * MIPS_INSN16_SIZE; |
| break; |
| |
| /* 32-bit instructions. */ |
| case 2 * MIPS_INSN16_SIZE: |
| insn <<= 16; |
| insn |= mips_fetch_instruction (gdbarch, |
| ISA_MICROMIPS, cur_pc + loc, NULL); |
| loc += MIPS_INSN16_SIZE; |
| switch (micromips_op (insn >> 16)) |
| { |
| /* Record $sp/$fp adjustment. */ |
| /* Discard (D)ADDU $gp,$jp used for PIC code. */ |
| case 0x0: /* POOL32A: bits 000000 */ |
| case 0x16: /* POOL32S: bits 010110 */ |
| op = b0s11_op (insn); |
| sreg = b0s5_reg (insn >> 16); |
| treg = b5s5_reg (insn >> 16); |
| dreg = b11s5_reg (insn); |
| if (op == 0x1d0 |
| /* SUBU: bits 000000 00111010000 */ |
| /* DSUBU: bits 010110 00111010000 */ |
| && dreg == MIPS_SP_REGNUM && sreg == MIPS_SP_REGNUM |
| && treg == 3) |
| /* (D)SUBU $sp, $v1 */ |
| sp_adj = v1_off; |
| else if (op != 0x150 |
| /* ADDU: bits 000000 00101010000 */ |
| /* DADDU: bits 010110 00101010000 */ |
| || dreg != 28 || sreg != 28 || treg != MIPS_T9_REGNUM) |
| this_non_prologue_insn = 1; |
| break; |
| |
| case 0x8: /* POOL32B: bits 001000 */ |
| op = b12s4_op (insn); |
| breg = b0s5_reg (insn >> 16); |
| reglist = sreg = b5s5_reg (insn >> 16); |
| offset = (b0s12_imm (insn) ^ 0x800) - 0x800; |
| if ((op == 0x9 || op == 0xc) |
| /* SWP: bits 001000 1001 */ |
| /* SDP: bits 001000 1100 */ |
| && breg == MIPS_SP_REGNUM && sreg < MIPS_RA_REGNUM) |
| /* S[DW]P reg,offset($sp) */ |
| { |
| s = 4 << ((b12s4_op (insn) & 0x4) == 0x4); |
| set_reg_offset (gdbarch, this_cache, |
| sreg, sp + offset); |
| set_reg_offset (gdbarch, this_cache, |
| sreg + 1, sp + offset + s); |
| } |
| else if ((op == 0xd || op == 0xf) |
| /* SWM: bits 001000 1101 */ |
| /* SDM: bits 001000 1111 */ |
| && breg == MIPS_SP_REGNUM |
| /* SWM reglist,offset($sp) */ |
| && ((reglist >= 1 && reglist <= 9) |
| || (reglist >= 16 && reglist <= 25))) |
| { |
| int sreglist = min(reglist & 0xf, 8); |
| |
| s = 4 << ((b12s4_op (insn) & 0x2) == 0x2); |
| for (i = 0; i < sreglist; i++) |
| set_reg_offset (gdbarch, this_cache, 16 + i, sp + s * i); |
| if ((reglist & 0xf) > 8) |
| set_reg_offset (gdbarch, this_cache, 30, sp + s * i++); |
| if ((reglist & 0x10) == 0x10) |
| set_reg_offset (gdbarch, this_cache, |
| MIPS_RA_REGNUM, sp + s * i++); |
| } |
| else |
| this_non_prologue_insn = 1; |
| break; |
| |
| /* Record $sp/$fp adjustment. */ |
| /* Discard (D)ADDIU $gp used for PIC code. */ |
| case 0xc: /* ADDIU: bits 001100 */ |
| case 0x17: /* DADDIU: bits 010111 */ |
| sreg = b0s5_reg (insn >> 16); |
| dreg = b5s5_reg (insn >> 16); |
| offset = (b0s16_imm (insn) ^ 0x8000) - 0x8000; |
| if (sreg == MIPS_SP_REGNUM && dreg == MIPS_SP_REGNUM) |
| /* (D)ADDIU $sp, imm */ |
| sp_adj = offset; |
| else if (sreg == MIPS_SP_REGNUM && dreg == 30) |
| /* (D)ADDIU $fp, $sp, imm */ |
| { |
| frame_addr = sp + offset; |
| frame_adjust = offset; |
| frame_reg = 30; |
| } |
| else if (sreg != 28 || dreg != 28) |
| /* (D)ADDIU $gp, imm */ |
| this_non_prologue_insn = 1; |
| break; |
| |
| /* LUI $v1 is used for larger $sp adjustments. */ |
| /* Discard LUI $gp is used for PIC code. */ |
| case 0x10: /* POOL32I: bits 010000 */ |
| if (b5s5_op (insn >> 16) == 0xd |
| /* LUI: bits 010000 001101 */ |
| && b0s5_reg (insn >> 16) == 3) |
| /* LUI $v1, imm */ |
| v1_off = ((b0s16_imm (insn) << 16) ^ 0x80000000) - 0x80000000; |
| else if (b5s5_op (insn >> 16) != 0xd |
| /* LUI: bits 010000 001101 */ |
| || b0s5_reg (insn >> 16) != 28) |
| /* LUI $gp, imm */ |
| this_non_prologue_insn = 1; |
| break; |
| |
| /* ORI $v1 is used for larger $sp adjustments. */ |
| case 0x14: /* ORI: bits 010100 */ |
| sreg = b0s5_reg (insn >> 16); |
| dreg = b5s5_reg (insn >> 16); |
| if (sreg == 3 && dreg == 3) |
| /* ORI $v1, imm */ |
| v1_off |= b0s16_imm (insn); |
| else |
| this_non_prologue_insn = 1; |
| break; |
| |
| case 0x26: /* SWC1: bits 100110 */ |
| case 0x2e: /* SDC1: bits 101110 */ |
| breg = b0s5_reg (insn >> 16); |
| if (breg != MIPS_SP_REGNUM) |
| /* S[DW]C1 reg,offset($sp) */ |
| this_non_prologue_insn = 1; |
| break; |
| |
| case 0x36: /* SD: bits 110110 */ |
| case 0x3e: /* SW: bits 111110 */ |
| breg = b0s5_reg (insn >> 16); |
| sreg = b5s5_reg (insn >> 16); |
| offset = (b0s16_imm (insn) ^ 0x8000) - 0x8000; |
| if (breg == MIPS_SP_REGNUM) |
| /* S[DW] reg,offset($sp) */ |
| set_reg_offset (gdbarch, this_cache, sreg, sp + offset); |
| else |
| this_non_prologue_insn = 1; |
| break; |
| |
| default: |
| this_non_prologue_insn = 1; |
| break; |
| } |
| break; |
| |
| /* 16-bit instructions. */ |
| case MIPS_INSN16_SIZE: |
| switch (micromips_op (insn)) |
| { |
| case 0x3: /* MOVE: bits 000011 */ |
| sreg = b0s5_reg (insn); |
| dreg = b5s5_reg (insn); |
| if (sreg == MIPS_SP_REGNUM && dreg == 30) |
| /* MOVE $fp, $sp */ |
| { |
| frame_addr = sp; |
| frame_reg = 30; |
| } |
| else if ((sreg & 0x1c) != 0x4) |
| /* MOVE reg, $a0-$a3 */ |
| this_non_prologue_insn = 1; |
| break; |
| |
| case 0x11: /* POOL16C: bits 010001 */ |
| if (b6s4_op (insn) == 0x5) |
| /* SWM: bits 010001 0101 */ |
| { |
| offset = ((b0s4_imm (insn) << 2) ^ 0x20) - 0x20; |
| reglist = b4s2_regl (insn); |
| for (i = 0; i <= reglist; i++) |
| set_reg_offset (gdbarch, this_cache, 16 + |