+ /* See what the symbol table says. */
+ if (find_pc_partial_function (pc, &func_name, &func_addr, NULL))
+ {
+ /* Found a function. */
+ CORE_ADDR postprologue_pc
+ = skip_prologue_using_sal (gdbarch, func_addr);
+
+ if (postprologue_pc != 0)
+ return std::max (pc, postprologue_pc);
+ }
+
+ /* No prologue info in symbol table, have to analyze prologue. */
+
+ /* Find an upper limit on the function prologue using the debug
+ information. If there is no debug information about prologue end, then
+ skip_prologue_using_sal will return 0. */
+ CORE_ADDR limit_pc = skip_prologue_using_sal (gdbarch, pc);
+
+ /* If there is no debug information at all, it is required to give some
+ semi-arbitrary hard limit on amount of bytes to scan during prologue
+ analysis. */
+ if (limit_pc == 0)
+ limit_pc = pc + MAX_PROLOGUE_LENGTH;
+
+ /* Find the address of the first instruction after the prologue by scanning
+ through it - no other information is needed, so pass NULL as a cache. */
+ return arc_analyze_prologue (gdbarch, pc, limit_pc, NULL);
+}
+
+/* Implement the "print_insn" gdbarch method.
+
+ arc_get_disassembler () may return different functions depending on bfd
+ type, so it is not possible to pass print_insn directly to
+ set_gdbarch_print_insn (). Instead this wrapper function is used. It also
+ may be used by other functions to get disassemble_info for address. It is
+ important to note, that those print_insn from opcodes always print
+ instruction to the stream specified in the INFO. If this is not desired,
+ then either `print_insn` function in INFO should be set to some function
+ that will not print, or `stream` should be different from standard
+ gdb_stdlog. */
+
+int
+arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info)
+{
+ /* Standard BFD "machine number" field allows libopcodes disassembler to
+ distinguish ARC 600, 700 and v2 cores, however v2 encompasses both ARC EM
+ and HS, which have some difference between. There are two ways to specify
+ what is the target core:
+ 1) via the disassemble_info->disassembler_options;
+ 2) otherwise libopcodes will use private (architecture-specific) ELF
+ header.
+
+ Using disassembler_options is preferable, because it comes directly from
+ GDBserver which scanned an actual ARC core identification info. However,
+ not all GDBservers report core architecture, so as a fallback GDB still
+ should support analysis of ELF header. The libopcodes disassembly code
+ uses the section to find the BFD and the BFD to find the ELF header,
+ therefore this function should set disassemble_info->section properly.
+
+ disassembler_options was already set by non-target specific code with
+ proper options obtained via gdbarch_disassembler_options ().
+
+ This function might be called multiple times in a sequence, reusing same
+ disassemble_info. */
+ if ((info->disassembler_options == NULL) && (info->section == NULL))
+ {
+ struct obj_section *s = find_pc_section (addr);
+ if (s != NULL)
+ info->section = s->the_bfd_section;
+ }
+
+ return default_print_insn (addr, info);
+}
+
+/* Baremetal breakpoint instructions.
+
+ ARC supports both big- and little-endian. However, instructions for
+ little-endian processors are encoded in the middle-endian: half-words are
+ in big-endian, while bytes inside the half-words are in little-endian; data
+ is represented in the "normal" little-endian. Big-endian processors treat
+ data and code identically.
+
+ Assuming the number 0x01020304, it will be presented this way:
+
+ Address : N N+1 N+2 N+3
+ little-endian : 0x04 0x03 0x02 0x01
+ big-endian : 0x01 0x02 0x03 0x04
+ ARC middle-endian : 0x02 0x01 0x04 0x03
+ */
+
+static const gdb_byte arc_brk_s_be[] = { 0x7f, 0xff };
+static const gdb_byte arc_brk_s_le[] = { 0xff, 0x7f };
+static const gdb_byte arc_brk_be[] = { 0x25, 0x6f, 0x00, 0x3f };
+static const gdb_byte arc_brk_le[] = { 0x6f, 0x25, 0x3f, 0x00 };
+
+/* For ARC ELF, breakpoint uses the 16-bit BRK_S instruction, which is 0x7fff
+ (little endian) or 0xff7f (big endian). We used to insert BRK_S even
+ instead of 32-bit instructions, which works mostly ok, unless breakpoint is
+ inserted into delay slot instruction. In this case if branch is taken
+ BLINK value will be set to address of instruction after delay slot, however
+ if we replaced 32-bit instruction in delay slot with 16-bit long BRK_S,
+ then BLINK value will have an invalid value - it will point to the address
+ after the BRK_S (which was there at the moment of branch execution) while
+ it should point to the address after the 32-bit long instruction. To avoid
+ such issues this function disassembles instruction at target location and
+ evaluates it value.
+
+ ARC 600 supports only 16-bit BRK_S.
+
+ NB: Baremetal GDB uses BRK[_S], while user-space GDB uses TRAP_S. BRK[_S]
+ is much better because it doesn't commit unlike TRAP_S, so it can be set in
+ delay slots; however it cannot be used in user-mode, hence usage of TRAP_S
+ in GDB for user-space. */
+
+/* Implement the "breakpoint_kind_from_pc" gdbarch method. */
+
+static int
+arc_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+ size_t length_with_limm = gdb_insn_length (gdbarch, *pcptr);
+
+ /* Replace 16-bit instruction with BRK_S, replace 32-bit instructions with
+ BRK. LIMM is part of instruction length, so it can be either 4 or 8
+ bytes for 32-bit instructions. */
+ if ((length_with_limm == 4 || length_with_limm == 8)
+ && !arc_mach_is_arc600 (gdbarch))
+ return sizeof (arc_brk_le);
+ else
+ return sizeof (arc_brk_s_le);
+}
+
+/* Implement the "sw_breakpoint_from_kind" gdbarch method. */
+
+static const gdb_byte *
+arc_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)