+/* Determine the remote breakpoint kind suitable for the PC. The following
+ kinds are used:
+
+ * 2 -- 16-bit MIPS16 mode breakpoint,
+
+ * 3 -- 16-bit microMIPS mode breakpoint,
+
+ * 4 -- 32-bit standard MIPS mode breakpoint,
+
+ * 5 -- 32-bit microMIPS mode breakpoint. */
+
+static void
+mips_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+ int *kindptr)
+{
+ CORE_ADDR pc = *pcptr;
+
+ if (mips_pc_is_mips16 (gdbarch, pc))
+ {
+ *pcptr = unmake_compact_addr (pc);
+ *kindptr = 2;
+ }
+ else if (mips_pc_is_micromips (gdbarch, pc))
+ {
+ ULONGEST insn;
+ int status;
+ int size;
+
+ insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, pc, &status);
+ size = status ? 2 : mips_insn_size (ISA_MICROMIPS, insn) == 2 ? 2 : 4;
+ *pcptr = unmake_compact_addr (pc);
+ *kindptr = size | 1;
+ }
+ else
+ *kindptr = 4;
+}
+
+/* Return non-zero if the ADDR instruction has a branch delay slot
+ (i.e. it is a jump or branch instruction). This function is based
+ on mips32_next_pc. */
+
+static int
+mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ unsigned long inst;
+ int status;
+ int op;
+ int rs;
+ int rt;
+
+ inst = mips_fetch_instruction (gdbarch, ISA_MIPS, addr, &status);
+ if (status)
+ return 0;
+
+ op = itype_op (inst);
+ if ((inst & 0xe0000000) != 0)
+ {
+ rs = itype_rs (inst);
+ rt = itype_rt (inst);
+ return (is_octeon_bbit_op (op, gdbarch)
+ || op >> 2 == 5 /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
+ || op == 29 /* JALX: bits 011101 */
+ || (op == 17
+ && (rs == 8
+ /* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */
+ || (rs == 9 && (rt & 0x2) == 0)
+ /* BC1ANY2F, BC1ANY2T: bits 010001 01001 */
+ || (rs == 10 && (rt & 0x2) == 0))));
+ /* BC1ANY4F, BC1ANY4T: bits 010001 01010 */
+ }
+ else
+ switch (op & 0x07) /* extract bits 28,27,26 */
+ {
+ case 0: /* SPECIAL */
+ op = rtype_funct (inst);
+ return (op == 8 /* JR */
+ || op == 9); /* JALR */
+ break; /* end SPECIAL */
+ case 1: /* REGIMM */
+ rs = itype_rs (inst);
+ rt = itype_rt (inst); /* branch condition */
+ return ((rt & 0xc) == 0
+ /* BLTZ, BLTZL, BGEZ, BGEZL: bits 000xx */
+ /* BLTZAL, BLTZALL, BGEZAL, BGEZALL: 100xx */
+ || ((rt & 0x1e) == 0x1c && rs == 0));
+ /* BPOSGE32, BPOSGE64: bits 1110x */
+ break; /* end REGIMM */
+ default: /* J, JAL, BEQ, BNE, BLEZ, BGTZ */
+ return 1;
+ break;
+ }
+}
+
+/* Return non-zero if the ADDR instruction, which must be a 32-bit
+ instruction if MUSTBE32 is set or can be any instruction otherwise,
+ has a branch delay slot (i.e. it is a non-compact jump instruction). */
+
+static int
+micromips_instruction_has_delay_slot (struct gdbarch *gdbarch,
+ CORE_ADDR addr, int mustbe32)
+{
+ ULONGEST insn;
+ int status;
+
+ insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, addr, &status);
+ if (status)
+ return 0;
+
+ if (!mustbe32) /* 16-bit instructions. */
+ return (micromips_op (insn) == 0x11
+ /* POOL16C: bits 010001 */
+ && (b5s5_op (insn) == 0xc
+ /* JR16: bits 010001 01100 */
+ || (b5s5_op (insn) & 0x1e) == 0xe))
+ /* JALR16, JALRS16: bits 010001 0111x */
+ || (micromips_op (insn) & 0x37) == 0x23
+ /* BEQZ16, BNEZ16: bits 10x011 */
+ || micromips_op (insn) == 0x33;
+ /* B16: bits 110011 */
+
+ /* 32-bit instructions. */
+ if (micromips_op (insn) == 0x0)
+ /* POOL32A: bits 000000 */
+ {
+ insn <<= 16;
+ insn |= mips_fetch_instruction (gdbarch, ISA_MICROMIPS, addr, &status);
+ if (status)
+ return 0;
+ return 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 */
+ }
+
+ return (micromips_op (insn) == 0x10
+ /* POOL32I: bits 010000 */
+ && ((b5s5_op (insn) & 0x1c) == 0x0
+ /* BLTZ, BLTZAL, BGEZ, BGEZAL: 010000 000xx */
+ || (b5s5_op (insn) & 0x1d) == 0x4
+ /* BLEZ, BGTZ: bits 010000 001x0 */
+ || (b5s5_op (insn) & 0x1d) == 0x11
+ /* BLTZALS, BGEZALS: bits 010000 100x1 */
+ || ((b5s5_op (insn) & 0x1e) == 0x14
+ && (insn & 0x3) == 0x0)
+ /* BC2F, BC2T: bits 010000 1010x xxx00 */
+ || (b5s5_op (insn) & 0x1e) == 0x1a
+ /* BPOSGE64, BPOSGE32: bits 010000 1101x */
+ || ((b5s5_op (insn) & 0x1e) == 0x1c
+ && (insn & 0x3) == 0x0)
+ /* BC1F, BC1T: bits 010000 1110x xxx00 */
+ || ((b5s5_op (insn) & 0x1c) == 0x1c
+ && (insn & 0x3) == 0x1)))
+ /* BC1ANY*: bits 010000 111xx xxx01 */
+ || (micromips_op (insn) & 0x1f) == 0x1d
+ /* JALS, JAL: bits x11101 */
+ || (micromips_op (insn) & 0x37) == 0x25
+ /* BEQ, BNE: bits 10x101 */
+ || micromips_op (insn) == 0x35
+ /* J: bits 110101 */
+ || micromips_op (insn) == 0x3c;
+ /* JALX: bits 111100 */
+}
+
+static int
+mips16_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr,
+ int mustbe32)
+{
+ unsigned short inst;
+ int status;
+
+ inst = mips_fetch_instruction (gdbarch, ISA_MIPS16, addr, &status);
+ if (status)
+ return 0;
+
+ if (!mustbe32)
+ return (inst & 0xf89f) == 0xe800; /* JR/JALR (16-bit instruction) */
+ return (inst & 0xf800) == 0x1800; /* JAL/JALX (32-bit instruction) */
+}
+
+/* Calculate the starting address of the MIPS memory segment BPADDR is in.
+ This assumes KSSEG exists. */
+
+static CORE_ADDR
+mips_segment_boundary (CORE_ADDR bpaddr)
+{
+ CORE_ADDR mask = CORE_ADDR_MAX;
+ int segsize;
+
+ if (sizeof (CORE_ADDR) == 8)
+ /* Get the topmost two bits of bpaddr in a 32-bit safe manner (avoid
+ a compiler warning produced where CORE_ADDR is a 32-bit type even
+ though in that case this is dead code). */
+ switch (bpaddr >> ((sizeof (CORE_ADDR) << 3) - 2) & 3)
+ {
+ case 3:
+ if (bpaddr == (bfd_signed_vma) (int32_t) bpaddr)
+ segsize = 29; /* 32-bit compatibility segment */
+ else
+ segsize = 62; /* xkseg */
+ break;
+ case 2: /* xkphys */
+ segsize = 59;
+ break;
+ default: /* xksseg (1), xkuseg/kuseg (0) */
+ segsize = 62;
+ break;
+ }
+ else if (bpaddr & 0x80000000) /* kernel segment */
+ segsize = 29;
+ else
+ segsize = 31; /* user segment */
+ mask <<= segsize;
+ return bpaddr & mask;
+}
+
+/* Move the breakpoint at BPADDR out of any branch delay slot by shifting
+ it backwards if necessary. Return the address of the new location. */
+
+static CORE_ADDR
+mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
+{
+ CORE_ADDR prev_addr;
+ CORE_ADDR boundary;
+ CORE_ADDR func_addr;
+
+ /* If a breakpoint is set on the instruction in a branch delay slot,
+ GDB gets confused. When the breakpoint is hit, the PC isn't on
+ the instruction in the branch delay slot, the PC will point to
+ the branch instruction. Since the PC doesn't match any known
+ breakpoints, GDB reports a trap exception.
+
+ There are two possible fixes for this problem.
+
+ 1) When the breakpoint gets hit, see if the BD bit is set in the
+ Cause register (which indicates the last exception occurred in a
+ branch delay slot). If the BD bit is set, fix the PC to point to
+ the instruction in the branch delay slot.
+
+ 2) When the user sets the breakpoint, don't allow him to set the
+ breakpoint on the instruction in the branch delay slot. Instead
+ move the breakpoint to the branch instruction (which will have
+ the same result).
+
+ The problem with the first solution is that if the user then
+ single-steps the processor, the branch instruction will get
+ skipped (since GDB thinks the PC is on the instruction in the
+ branch delay slot).
+
+ So, we'll use the second solution. To do this we need to know if
+ the instruction we're trying to set the breakpoint on is in the
+ branch delay slot. */
+
+ boundary = mips_segment_boundary (bpaddr);
+
+ /* Make sure we don't scan back before the beginning of the current
+ function, since we may fetch constant data or insns that look like
+ a jump. Of course we might do that anyway if the compiler has
+ moved constants inline. :-( */
+ if (find_pc_partial_function (bpaddr, NULL, &func_addr, NULL)
+ && func_addr > boundary && func_addr <= bpaddr)
+ boundary = func_addr;
+
+ if (mips_pc_is_mips (bpaddr))
+ {
+ if (bpaddr == boundary)
+ return bpaddr;
+
+ /* If the previous instruction has a branch delay slot, we have
+ to move the breakpoint to the branch instruction. */
+ prev_addr = bpaddr - 4;
+ if (mips32_instruction_has_delay_slot (gdbarch, prev_addr))
+ bpaddr = prev_addr;
+ }
+ else
+ {
+ int (*instruction_has_delay_slot) (struct gdbarch *, CORE_ADDR, int);
+ CORE_ADDR addr, jmpaddr;
+ int i;
+
+ boundary = unmake_compact_addr (boundary);
+
+ /* The only MIPS16 instructions with delay slots are JAL, JALX,
+ JALR and JR. An absolute JAL/JALX is always 4 bytes long,
+ so try for that first, then try the 2 byte JALR/JR.
+ The microMIPS ASE has a whole range of jumps and branches
+ with delay slots, some of which take 4 bytes and some take
+ 2 bytes, so the idea is the same.
+ FIXME: We have to assume that bpaddr is not the second half
+ of an extended instruction. */
+ instruction_has_delay_slot = (mips_pc_is_micromips (gdbarch, bpaddr)
+ ? micromips_instruction_has_delay_slot
+ : mips16_instruction_has_delay_slot);
+
+ jmpaddr = 0;
+ addr = bpaddr;
+ for (i = 1; i < 4; i++)
+ {
+ if (unmake_compact_addr (addr) == boundary)
+ break;
+ addr -= MIPS_INSN16_SIZE;
+ if (i == 1 && instruction_has_delay_slot (gdbarch, addr, 0))
+ /* Looks like a JR/JALR at [target-1], but it could be
+ the second word of a previous JAL/JALX, so record it
+ and check back one more. */
+ jmpaddr = addr;
+ else if (i > 1 && instruction_has_delay_slot (gdbarch, addr, 1))
+ {
+ if (i == 2)
+ /* Looks like a JAL/JALX at [target-2], but it could also
+ be the second word of a previous JAL/JALX, record it,
+ and check back one more. */
+ jmpaddr = addr;
+ else
+ /* Looks like a JAL/JALX at [target-3], so any previously
+ recorded JAL/JALX or JR/JALR must be wrong, because:
+
+ >-3: JAL
+ -2: JAL-ext (can't be JAL/JALX)
+ -1: bdslot (can't be JR/JALR)
+ 0: target insn
+
+ Of course it could be another JAL-ext which looks
+ like a JAL, but in that case we'd have broken out
+ of this loop at [target-2]:
+
+ -4: JAL
+ >-3: JAL-ext
+ -2: bdslot (can't be jmp)
+ -1: JR/JALR
+ 0: target insn */
+ jmpaddr = 0;
+ }
+ else
+ {
+ /* Not a jump instruction: if we're at [target-1] this
+ could be the second word of a JAL/JALX, so continue;
+ otherwise we're done. */
+ if (i > 1)
+ break;
+ }
+ }
+
+ if (jmpaddr)
+ bpaddr = jmpaddr;
+ }
+
+ return bpaddr;
+}
+
+/* Return non-zero if SUFFIX is one of the numeric suffixes used for MIPS16
+ call stubs, one of 1, 2, 5, 6, 9, 10, or, if ZERO is non-zero, also 0. */
+
+static int
+mips_is_stub_suffix (const char *suffix, int zero)
+{
+ switch (suffix[0])
+ {
+ case '0':
+ return zero && suffix[1] == '\0';
+ case '1':
+ return suffix[1] == '\0' || (suffix[1] == '0' && suffix[2] == '\0');
+ case '2':
+ case '5':
+ case '6':
+ case '9':
+ return suffix[1] == '\0';
+ default:
+ return 0;
+ }
+}
+
+/* Return non-zero if MODE is one of the mode infixes used for MIPS16
+ call stubs, one of sf, df, sc, or dc. */
+
+static int
+mips_is_stub_mode (const char *mode)
+{
+ return ((mode[0] == 's' || mode[0] == 'd')
+ && (mode[1] == 'f' || mode[1] == 'c'));
+}
+
+/* Code at PC is a compiler-generated stub. Such a stub for a function
+ bar might have a name like __fn_stub_bar, and might look like this:
+
+ mfc1 $4, $f13
+ mfc1 $5, $f12
+ mfc1 $6, $f15
+ mfc1 $7, $f14
+
+ followed by (or interspersed with):
+
+ j bar
+
+ or:
+
+ lui $25, %hi(bar)
+ addiu $25, $25, %lo(bar)
+ jr $25
+
+ ($1 may be used in old code; for robustness we accept any register)
+ or, in PIC code:
+
+ lui $28, %hi(_gp_disp)
+ addiu $28, $28, %lo(_gp_disp)
+ addu $28, $28, $25
+ lw $25, %got(bar)
+ addiu $25, $25, %lo(bar)
+ jr $25
+
+ In the case of a __call_stub_bar stub, the sequence to set up
+ arguments might look like this:
+
+ mtc1 $4, $f13
+ mtc1 $5, $f12
+ mtc1 $6, $f15
+ mtc1 $7, $f14
+
+ followed by (or interspersed with) one of the jump sequences above.
+
+ In the case of a __call_stub_fp_bar stub, JAL or JALR is used instead
+ of J or JR, respectively, followed by:
+
+ mfc1 $2, $f0
+ mfc1 $3, $f1
+ jr $18
+
+ We are at the beginning of the stub here, and scan down and extract
+ the target address from the jump immediate instruction or, if a jump
+ register instruction is used, from the register referred. Return
+ the value of PC calculated or 0 if inconclusive.
+
+ The limit on the search is arbitrarily set to 20 instructions. FIXME. */
+
+static CORE_ADDR
+mips_get_mips16_fn_stub_pc (struct frame_info *frame, CORE_ADDR pc)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int addrreg = MIPS_ZERO_REGNUM;
+ CORE_ADDR start_pc = pc;
+ CORE_ADDR target_pc = 0;
+ CORE_ADDR addr = 0;
+ CORE_ADDR gp = 0;
+ int status = 0;
+ int i;
+
+ for (i = 0;
+ status == 0 && target_pc == 0 && i < 20;
+ i++, pc += MIPS_INSN32_SIZE)
+ {
+ ULONGEST inst = mips_fetch_instruction (gdbarch, ISA_MIPS, pc, NULL);
+ CORE_ADDR imm;
+ int rt;
+ int rs;
+ int rd;
+
+ switch (itype_op (inst))
+ {
+ case 0: /* SPECIAL */
+ switch (rtype_funct (inst))
+ {
+ case 8: /* JR */
+ case 9: /* JALR */
+ rs = rtype_rs (inst);
+ if (rs == MIPS_GP_REGNUM)
+ target_pc = gp; /* Hmm... */
+ else if (rs == addrreg)
+ target_pc = addr;
+ break;
+
+ case 0x21: /* ADDU */
+ rt = rtype_rt (inst);
+ rs = rtype_rs (inst);
+ rd = rtype_rd (inst);
+ if (rd == MIPS_GP_REGNUM
+ && ((rs == MIPS_GP_REGNUM && rt == MIPS_T9_REGNUM)
+ || (rs == MIPS_T9_REGNUM && rt == MIPS_GP_REGNUM)))
+ gp += start_pc;
+ break;
+ }
+ break;
+
+ case 2: /* J */
+ case 3: /* JAL */
+ target_pc = jtype_target (inst) << 2;
+ target_pc += ((pc + 4) & ~(CORE_ADDR) 0x0fffffff);
+ break;
+
+ case 9: /* ADDIU */
+ rt = itype_rt (inst);
+ rs = itype_rs (inst);
+ if (rt == rs)
+ {
+ imm = (itype_immediate (inst) ^ 0x8000) - 0x8000;
+ if (rt == MIPS_GP_REGNUM)
+ gp += imm;
+ else if (rt == addrreg)
+ addr += imm;
+ }
+ break;
+
+ case 0xf: /* LUI */
+ rt = itype_rt (inst);
+ imm = ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 16;
+ if (rt == MIPS_GP_REGNUM)
+ gp = imm;
+ else if (rt != MIPS_ZERO_REGNUM)
+ {
+ addrreg = rt;
+ addr = imm;
+ }
+ break;
+
+ case 0x23: /* LW */
+ rt = itype_rt (inst);
+ rs = itype_rs (inst);
+ imm = (itype_immediate (inst) ^ 0x8000) - 0x8000;
+ if (gp != 0 && rs == MIPS_GP_REGNUM)
+ {
+ gdb_byte buf[4];
+
+ memset (buf, 0, sizeof (buf));
+ status = target_read_memory (gp + imm, buf, sizeof (buf));
+ addrreg = rt;
+ addr = extract_signed_integer (buf, sizeof (buf), byte_order);
+ }
+ break;
+ }
+ }
+
+ return target_pc;
+}
+
+/* If PC is in a MIPS16 call or return stub, return the address of the
+ target PC, which is either the callee or the caller. There are several