+/* If the current PC is the start of a non-PIC-to-PIC stub, return the
+ PC of the stub target. The stub just loads $t9 and jumps to it,
+ so that $t9 has the correct value at function entry. */
+
+static CORE_ADDR
+mips_skip_pic_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct minimal_symbol *msym;
+ int i;
+ gdb_byte stub_code[16];
+ int32_t stub_words[4];
+
+ /* The stub for foo is named ".pic.foo", and is either two
+ instructions inserted before foo or a three instruction sequence
+ which jumps to foo. */
+ msym = lookup_minimal_symbol_by_pc (pc);
+ if (msym == NULL
+ || SYMBOL_VALUE_ADDRESS (msym) != pc
+ || SYMBOL_LINKAGE_NAME (msym) == NULL
+ || strncmp (SYMBOL_LINKAGE_NAME (msym), ".pic.", 5) != 0)
+ return 0;
+
+ /* A two-instruction header. */
+ if (MSYMBOL_SIZE (msym) == 8)
+ return pc + 8;
+
+ /* A three-instruction (plus delay slot) trampoline. */
+ if (MSYMBOL_SIZE (msym) == 16)
+ {
+ if (target_read_memory (pc, stub_code, 16) != 0)
+ return 0;
+ for (i = 0; i < 4; i++)
+ stub_words[i] = extract_unsigned_integer (stub_code + i * 4,
+ 4, byte_order);
+
+ /* A stub contains these instructions:
+ lui t9, %hi(target)
+ j target
+ addiu t9, t9, %lo(target)
+ nop
+
+ This works even for N64, since stubs are only generated with
+ -msym32. */
+ if ((stub_words[0] & 0xffff0000U) == 0x3c190000
+ && (stub_words[1] & 0xfc000000U) == 0x08000000
+ && (stub_words[2] & 0xffff0000U) == 0x27390000
+ && stub_words[3] == 0x00000000)
+ return (((stub_words[0] & 0x0000ffff) << 16)
+ + (stub_words[2] & 0x0000ffff));
+ }
+
+ /* Not a recognized stub. */
+ return 0;
+}
+
+static CORE_ADDR
+mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+ CORE_ADDR target_pc;
+
+ target_pc = mips_skip_mips16_trampoline_code (frame, pc);
+ if (target_pc)
+ return target_pc;
+
+ target_pc = find_solib_trampoline_target (frame, pc);
+ if (target_pc)
+ return target_pc;
+
+ target_pc = mips_skip_pic_trampoline_code (frame, pc);
+ if (target_pc)
+ return target_pc;
+
+ return 0;
+}
+