123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747 |
- /* Target dependent code for GNU/Linux ARC.
- Copyright 2020-2022 Free Software Foundation, Inc.
- 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/>. */
- /* GDB header files. */
- #include "defs.h"
- #include "linux-tdep.h"
- #include "objfiles.h"
- #include "opcode/arc.h"
- #include "osabi.h"
- #include "solib-svr4.h"
- #include "disasm.h"
- /* ARC header files. */
- #include "opcodes/arc-dis.h"
- #include "arc-linux-tdep.h"
- #include "arc-tdep.h"
- #include "arch/arc.h"
- /* Print an "arc-linux" debug statement. */
- #define arc_linux_debug_printf(fmt, ...) \
- debug_prefixed_printf_cond (arc_debug, "arc-linux", fmt, ##__VA_ARGS__)
- #define REGOFF(offset) (offset * ARC_REGISTER_SIZE)
- /* arc_linux_sc_reg_offsets[i] is the offset of register i in the `struct
- sigcontext'. Array index is an internal GDB register number, as defined in
- arc-tdep.h:arc_regnum.
- From <include/uapi/asm/sigcontext.h> and <include/uapi/asm/ptrace.h>.
- The layout of this struct is tightly bound to "arc_regnum" enum
- in arc-tdep.h. Any change of order in there, must be reflected
- here as well. */
- static const int arc_linux_sc_reg_offsets[] = {
- /* R0 - R12. */
- REGOFF (22), REGOFF (21), REGOFF (20), REGOFF (19),
- REGOFF (18), REGOFF (17), REGOFF (16), REGOFF (15),
- REGOFF (14), REGOFF (13), REGOFF (12), REGOFF (11),
- REGOFF (10),
- /* R13 - R25. */
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER,
- REGOFF (9), /* R26 (GP) */
- REGOFF (8), /* FP */
- REGOFF (23), /* SP */
- ARC_OFFSET_NO_REGISTER, /* ILINK */
- ARC_OFFSET_NO_REGISTER, /* R30 */
- REGOFF (7), /* BLINK */
- /* R32 - R59. */
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER,
- REGOFF (4), /* LP_COUNT */
- ARC_OFFSET_NO_REGISTER, /* RESERVED */
- ARC_OFFSET_NO_REGISTER, /* LIMM */
- ARC_OFFSET_NO_REGISTER, /* PCL */
- REGOFF (6), /* PC */
- REGOFF (5), /* STATUS32 */
- REGOFF (2), /* LP_START */
- REGOFF (3), /* LP_END */
- REGOFF (1), /* BTA */
- };
- /* arc_linux_core_reg_offsets[i] is the offset in the .reg section of GDB
- regnum i. Array index is an internal GDB register number, as defined in
- arc-tdep.h:arc_regnum.
- From include/uapi/asm/ptrace.h in the ARC Linux sources. */
- /* The layout of this struct is tightly bound to "arc_regnum" enum
- in arc-tdep.h. Any change of order in there, must be reflected
- here as well. */
- static const int arc_linux_core_reg_offsets[] = {
- /* R0 - R12. */
- REGOFF (22), REGOFF (21), REGOFF (20), REGOFF (19),
- REGOFF (18), REGOFF (17), REGOFF (16), REGOFF (15),
- REGOFF (14), REGOFF (13), REGOFF (12), REGOFF (11),
- REGOFF (10),
- /* R13 - R25. */
- REGOFF (37), REGOFF (36), REGOFF (35), REGOFF (34),
- REGOFF (33), REGOFF (32), REGOFF (31), REGOFF (30),
- REGOFF (29), REGOFF (28), REGOFF (27), REGOFF (26),
- REGOFF (25),
- REGOFF (9), /* R26 (GP) */
- REGOFF (8), /* FP */
- REGOFF (23), /* SP */
- ARC_OFFSET_NO_REGISTER, /* ILINK */
- ARC_OFFSET_NO_REGISTER, /* R30 */
- REGOFF (7), /* BLINK */
- /* R32 - R59. */
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
- ARC_OFFSET_NO_REGISTER,
- REGOFF (4), /* LP_COUNT */
- ARC_OFFSET_NO_REGISTER, /* RESERVED */
- ARC_OFFSET_NO_REGISTER, /* LIMM */
- ARC_OFFSET_NO_REGISTER, /* PCL */
- REGOFF (39), /* PC */
- REGOFF (5), /* STATUS32 */
- REGOFF (2), /* LP_START */
- REGOFF (3), /* LP_END */
- REGOFF (1), /* BTA */
- REGOFF (6) /* ERET */
- };
- /* Is THIS_FRAME a sigtramp function - the function that returns from
- signal handler into normal execution flow? This is the case if the PC is
- either at the start of, or in the middle of the two instructions:
- mov r8, __NR_rt_sigreturn ; __NR_rt_sigreturn == 139
- trap_s 0 ; `swi' for ARC700
- On ARC uClibc Linux this function is called __default_rt_sa_restorer.
- Returns TRUE if this is a sigtramp frame. */
- static bool
- arc_linux_is_sigtramp (struct frame_info *this_frame)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- CORE_ADDR pc = get_frame_pc (this_frame);
- arc_linux_debug_printf ("pc=%s", paddress(gdbarch, pc));
- static const gdb_byte insns_be_hs[] = {
- 0x20, 0x8a, 0x12, 0xc2, /* mov r8,nr_rt_sigreturn */
- 0x78, 0x1e /* trap_s 0 */
- };
- static const gdb_byte insns_be_700[] = {
- 0x20, 0x8a, 0x12, 0xc2, /* mov r8,nr_rt_sigreturn */
- 0x22, 0x6f, 0x00, 0x3f /* swi */
- };
- gdb_byte arc_sigtramp_insns[sizeof (insns_be_700)];
- size_t insns_sz;
- if (arc_mach_is_arcv2 (gdbarch))
- {
- insns_sz = sizeof (insns_be_hs);
- memcpy (arc_sigtramp_insns, insns_be_hs, insns_sz);
- }
- else
- {
- insns_sz = sizeof (insns_be_700);
- memcpy (arc_sigtramp_insns, insns_be_700, insns_sz);
- }
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
- {
- /* On little endian targets, ARC code section is in what is called
- "middle endian", where half-words are in the big-endian order,
- only bytes inside the halfwords are in the little endian order.
- As a result it is very easy to convert big endian instruction to
- little endian, since it is needed to swap bytes in the halfwords,
- so there is no need to have information on whether that is a
- 4-byte instruction or 2-byte. */
- gdb_assert ((insns_sz % 2) == 0);
- for (int i = 0; i < insns_sz; i += 2)
- std::swap (arc_sigtramp_insns[i], arc_sigtramp_insns[i+1]);
- }
- gdb_byte buf[insns_sz];
- /* Read the memory at the PC. Since we are stopped, any breakpoint must
- have been removed. */
- if (!safe_frame_unwind_memory (this_frame, pc, {buf, insns_sz}))
- {
- /* Failed to unwind frame. */
- return FALSE;
- }
- /* Is that code the sigtramp instruction sequence? */
- if (memcmp (buf, arc_sigtramp_insns, insns_sz) == 0)
- return TRUE;
- /* No - look one instruction earlier in the code... */
- if (!safe_frame_unwind_memory (this_frame, pc - 4, {buf, insns_sz}))
- {
- /* Failed to unwind frame. */
- return FALSE;
- }
- return (memcmp (buf, arc_sigtramp_insns, insns_sz) == 0);
- }
- /* Get sigcontext structure of sigtramp frame - it contains saved
- registers of interrupted frame.
- Stack pointer points to the rt_sigframe structure, and sigcontext can
- be found as in:
- struct rt_sigframe {
- struct siginfo info;
- struct ucontext uc;
- ...
- };
- struct ucontext {
- unsigned long uc_flags;
- struct ucontext *uc_link;
- stack_t uc_stack;
- struct sigcontext uc_mcontext;
- sigset_t uc_sigmask;
- };
- sizeof (struct siginfo) == 0x80
- offsetof (struct ucontext, uc_mcontext) == 0x14
- GDB cannot include linux headers and use offsetof () because those are
- target headers and GDB might be built for a different run host. There
- doesn't seem to be an established mechanism to figure out those offsets
- via gdbserver, so the only way is to hardcode values in the GDB,
- meaning that GDB will be broken if values will change. That seems to
- be a very unlikely scenario and other arches (aarch64, alpha, amd64,
- etc) in GDB hardcode values. */
- static CORE_ADDR
- arc_linux_sigcontext_addr (struct frame_info *this_frame)
- {
- const int ucontext_offset = 0x80;
- const int sigcontext_offset = 0x14;
- return get_frame_sp (this_frame) + ucontext_offset + sigcontext_offset;
- }
- /* Implement the "cannot_fetch_register" gdbarch method. */
- static int
- arc_linux_cannot_fetch_register (struct gdbarch *gdbarch, int regnum)
- {
- /* Assume that register is readable if it is unknown. */
- switch (regnum)
- {
- case ARC_ILINK_REGNUM:
- case ARC_RESERVED_REGNUM:
- case ARC_LIMM_REGNUM:
- return true;
- case ARC_R30_REGNUM:
- case ARC_R58_REGNUM:
- case ARC_R59_REGNUM:
- return !arc_mach_is_arcv2 (gdbarch);
- }
- return (regnum > ARC_BLINK_REGNUM) && (regnum < ARC_LP_COUNT_REGNUM);
- }
- /* Implement the "cannot_store_register" gdbarch method. */
- static int
- arc_linux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
- {
- /* Assume that register is writable if it is unknown. */
- switch (regnum)
- {
- case ARC_ILINK_REGNUM:
- case ARC_RESERVED_REGNUM:
- case ARC_LIMM_REGNUM:
- case ARC_PCL_REGNUM:
- return true;
- case ARC_R30_REGNUM:
- case ARC_R58_REGNUM:
- case ARC_R59_REGNUM:
- return !arc_mach_is_arcv2 (gdbarch);
- }
- return (regnum > ARC_BLINK_REGNUM) && (regnum < ARC_LP_COUNT_REGNUM);
- }
- /* For ARC Linux, breakpoints use the 16-bit TRAP_S 1 instruction, which
- is 0x3e78 (little endian) or 0x783e (big endian). */
- static const gdb_byte arc_linux_trap_s_be[] = { 0x78, 0x3e };
- static const gdb_byte arc_linux_trap_s_le[] = { 0x3e, 0x78 };
- static const int trap_size = 2; /* Number of bytes to insert "trap". */
- /* Implement the "breakpoint_kind_from_pc" gdbarch method. */
- static int
- arc_linux_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
- {
- return trap_size;
- }
- /* Implement the "sw_breakpoint_from_kind" gdbarch method. */
- static const gdb_byte *
- arc_linux_sw_breakpoint_from_kind (struct gdbarch *gdbarch,
- int kind, int *size)
- {
- gdb_assert (kind == trap_size);
- *size = kind;
- return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- ? arc_linux_trap_s_be
- : arc_linux_trap_s_le);
- }
- /* Check for an atomic sequence of instructions beginning with an
- LLOCK instruction and ending with a SCOND instruction.
- These patterns are hand coded in libc's (glibc and uclibc). Take
- a look at [1] for instance:
- main+14: llock r2,[r0]
- main+18: brne.nt r2,0,main+30
- main+22: scond r3,[r0]
- main+26: bne main+14
- main+30: mov_s r0,0
- If such a sequence is found, attempt to step over it.
- A breakpoint is placed at the end of the sequence.
- This function expects the INSN to be a "llock(d)" instruction.
- [1]
- https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/libc/ \
- sysdeps/linux/arc/bits/atomic.h#n46
- */
- static std::vector<CORE_ADDR>
- handle_atomic_sequence (arc_instruction insn, disassemble_info &di)
- {
- const int atomic_seq_len = 24; /* Instruction sequence length. */
- std::vector<CORE_ADDR> next_pcs;
- /* Sanity check. */
- gdb_assert (insn.insn_class == LLOCK);
- /* Data size we are dealing with: LLOCK vs. LLOCKD */
- arc_ldst_data_size llock_data_size_mode = insn.data_size_mode;
- /* Indicator if any conditional branch is found in the sequence. */
- bool found_bc = false;
- /* Becomes true if "LLOCK(D) .. SCOND(D)" sequence is found. */
- bool is_pattern_valid = false;
- for (int insn_count = 0; insn_count < atomic_seq_len; ++insn_count)
- {
- arc_insn_decode (arc_insn_get_linear_next_pc (insn),
- &di, arc_delayed_print_insn, &insn);
- if (insn.insn_class == BRCC)
- {
- /* If more than one conditional branch is found, this is not
- the pattern we are interested in. */
- if (found_bc)
- break;
- found_bc = true;
- continue;
- }
- /* This is almost a happy ending. */
- if (insn.insn_class == SCOND)
- {
- /* SCOND should match the LLOCK's data size. */
- if (insn.data_size_mode == llock_data_size_mode)
- is_pattern_valid = true;
- break;
- }
- }
- if (is_pattern_valid)
- {
- /* Get next instruction after scond(d). There is no limm. */
- next_pcs.push_back (insn.address + insn.length);
- }
- return next_pcs;
- }
- /* Implement the "software_single_step" gdbarch method. */
- static std::vector<CORE_ADDR>
- arc_linux_software_single_step (struct regcache *regcache)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- struct disassemble_info di = arc_disassemble_info (gdbarch);
- /* Read current instruction. */
- struct arc_instruction curr_insn;
- arc_insn_decode (regcache_read_pc (regcache), &di, arc_delayed_print_insn,
- &curr_insn);
- if (curr_insn.insn_class == LLOCK)
- return handle_atomic_sequence (curr_insn, di);
- CORE_ADDR next_pc = arc_insn_get_linear_next_pc (curr_insn);
- std::vector<CORE_ADDR> next_pcs;
- /* For instructions with delay slots, the fall thru is not the
- instruction immediately after the current instruction, but the one
- after that. */
- if (curr_insn.has_delay_slot)
- {
- struct arc_instruction next_insn;
- arc_insn_decode (next_pc, &di, arc_delayed_print_insn, &next_insn);
- next_pcs.push_back (arc_insn_get_linear_next_pc (next_insn));
- }
- else
- next_pcs.push_back (next_pc);
- ULONGEST status32;
- regcache_cooked_read_unsigned (regcache, gdbarch_ps_regnum (gdbarch),
- &status32);
- if (curr_insn.is_control_flow)
- {
- CORE_ADDR branch_pc = arc_insn_get_branch_target (curr_insn);
- if (branch_pc != next_pc)
- next_pcs.push_back (branch_pc);
- }
- /* Is current instruction the last in a loop body? */
- else if (tdep->has_hw_loops)
- {
- /* If STATUS32.L is 1, then ZD-loops are disabled. */
- if ((status32 & ARC_STATUS32_L_MASK) == 0)
- {
- ULONGEST lp_end, lp_start, lp_count;
- regcache_cooked_read_unsigned (regcache, ARC_LP_START_REGNUM,
- &lp_start);
- regcache_cooked_read_unsigned (regcache, ARC_LP_END_REGNUM, &lp_end);
- regcache_cooked_read_unsigned (regcache, ARC_LP_COUNT_REGNUM,
- &lp_count);
- arc_linux_debug_printf ("lp_start = %s, lp_end = %s, "
- "lp_count = %s, next_pc = %s",
- paddress (gdbarch, lp_start),
- paddress (gdbarch, lp_end),
- pulongest (lp_count),
- paddress (gdbarch, next_pc));
- if (next_pc == lp_end && lp_count > 1)
- {
- /* The instruction is in effect a jump back to the start of
- the loop. */
- next_pcs.push_back (lp_start);
- }
- }
- }
- /* Is this a delay slot? Then next PC is in BTA register. */
- if ((status32 & ARC_STATUS32_DE_MASK) != 0)
- {
- ULONGEST bta;
- regcache_cooked_read_unsigned (regcache, ARC_BTA_REGNUM, &bta);
- next_pcs.push_back (bta);
- }
- return next_pcs;
- }
- /* Implement the "skip_solib_resolver" gdbarch method.
- See glibc_skip_solib_resolver for details. */
- static CORE_ADDR
- arc_linux_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- /* For uClibc 0.9.26+.
- An unresolved PLT entry points to "__dl_linux_resolve", which calls
- "_dl_linux_resolver" to do the resolving and then eventually jumps to
- the function.
- So we look for the symbol `_dl_linux_resolver', and if we are there,
- gdb sets a breakpoint at the return address, and continues. */
- struct bound_minimal_symbol resolver
- = lookup_minimal_symbol ("_dl_linux_resolver", NULL, NULL);
- if (arc_debug)
- {
- if (resolver.minsym != nullptr)
- {
- CORE_ADDR res_addr = BMSYMBOL_VALUE_ADDRESS (resolver);
- arc_linux_debug_printf ("pc = %s, resolver at %s",
- print_core_address (gdbarch, pc),
- print_core_address (gdbarch, res_addr));
- }
- else
- arc_linux_debug_printf ("pc = %s, no resolver found",
- print_core_address (gdbarch, pc));
- }
- if (resolver.minsym != nullptr && BMSYMBOL_VALUE_ADDRESS (resolver) == pc)
- {
- /* Find the return address. */
- return frame_unwind_caller_pc (get_current_frame ());
- }
- else
- {
- /* No breakpoint required. */
- return 0;
- }
- }
- /* Populate REGCACHE with register REGNUM from BUF. */
- static void
- supply_register (struct regcache *regcache, int regnum, const gdb_byte *buf)
- {
- /* Skip non-existing registers. */
- if ((arc_linux_core_reg_offsets[regnum] == ARC_OFFSET_NO_REGISTER))
- return;
- regcache->raw_supply (regnum, buf + arc_linux_core_reg_offsets[regnum]);
- }
- void
- arc_linux_supply_gregset (const struct regset *regset,
- struct regcache *regcache,
- int regnum, const void *gregs, size_t size)
- {
- gdb_static_assert (ARC_LAST_REGNUM
- < ARRAY_SIZE (arc_linux_core_reg_offsets));
- const bfd_byte *buf = (const bfd_byte *) gregs;
- /* REGNUM == -1 means writing all the registers. */
- if (regnum == -1)
- for (int reg = 0; reg <= ARC_LAST_REGNUM; reg++)
- supply_register (regcache, reg, buf);
- else if (regnum <= ARC_LAST_REGNUM)
- supply_register (regcache, regnum, buf);
- else
- gdb_assert_not_reached ("Invalid regnum in arc_linux_supply_gregset.");
- }
- void
- arc_linux_supply_v2_regset (const struct regset *regset,
- struct regcache *regcache, int regnum,
- const void *v2_regs, size_t size)
- {
- const bfd_byte *buf = (const bfd_byte *) v2_regs;
- /* user_regs_arcv2 is defined in linux arch/arc/include/uapi/asm/ptrace.h. */
- if (regnum == -1 || regnum == ARC_R30_REGNUM)
- regcache->raw_supply (ARC_R30_REGNUM, buf);
- if (regnum == -1 || regnum == ARC_R58_REGNUM)
- regcache->raw_supply (ARC_R58_REGNUM, buf + REGOFF (1));
- if (regnum == -1 || regnum == ARC_R59_REGNUM)
- regcache->raw_supply (ARC_R59_REGNUM, buf + REGOFF (2));
- }
- /* Populate BUF with register REGNUM from the REGCACHE. */
- static void
- collect_register (const struct regcache *regcache, struct gdbarch *gdbarch,
- int regnum, gdb_byte *buf)
- {
- int offset;
- /* Skip non-existing registers. */
- if (arc_linux_core_reg_offsets[regnum] == ARC_OFFSET_NO_REGISTER)
- return;
- /* The address where the execution has stopped is in pseudo-register
- STOP_PC. However, when kernel code is returning from the exception,
- it uses the value from ERET register. Since, TRAP_S (the breakpoint
- instruction) commits, the ERET points to the next instruction. In
- other words: ERET != STOP_PC. To jump back from the kernel code to
- the correct address, ERET must be overwritten by GDB's STOP_PC. Else,
- the program will continue at the address after the current instruction.
- */
- if (regnum == gdbarch_pc_regnum (gdbarch))
- offset = arc_linux_core_reg_offsets[ARC_ERET_REGNUM];
- else
- offset = arc_linux_core_reg_offsets[regnum];
- regcache->raw_collect (regnum, buf + offset);
- }
- void
- arc_linux_collect_gregset (const struct regset *regset,
- const struct regcache *regcache,
- int regnum, void *gregs, size_t size)
- {
- gdb_static_assert (ARC_LAST_REGNUM
- < ARRAY_SIZE (arc_linux_core_reg_offsets));
- gdb_byte *buf = (gdb_byte *) gregs;
- struct gdbarch *gdbarch = regcache->arch ();
- /* REGNUM == -1 means writing all the registers. */
- if (regnum == -1)
- for (int reg = 0; reg <= ARC_LAST_REGNUM; reg++)
- collect_register (regcache, gdbarch, reg, buf);
- else if (regnum <= ARC_LAST_REGNUM)
- collect_register (regcache, gdbarch, regnum, buf);
- else
- gdb_assert_not_reached ("Invalid regnum in arc_linux_collect_gregset.");
- }
- void
- arc_linux_collect_v2_regset (const struct regset *regset,
- const struct regcache *regcache, int regnum,
- void *v2_regs, size_t size)
- {
- bfd_byte *buf = (bfd_byte *) v2_regs;
- if (regnum == -1 || regnum == ARC_R30_REGNUM)
- regcache->raw_collect (ARC_R30_REGNUM, buf);
- if (regnum == -1 || regnum == ARC_R58_REGNUM)
- regcache->raw_collect (ARC_R58_REGNUM, buf + REGOFF (1));
- if (regnum == -1 || regnum == ARC_R59_REGNUM)
- regcache->raw_collect (ARC_R59_REGNUM, buf + REGOFF (2));
- }
- /* Linux regset definitions. */
- static const struct regset arc_linux_gregset = {
- arc_linux_core_reg_offsets,
- arc_linux_supply_gregset,
- arc_linux_collect_gregset,
- };
- static const struct regset arc_linux_v2_regset = {
- NULL,
- arc_linux_supply_v2_regset,
- arc_linux_collect_v2_regset,
- };
- /* Implement the `iterate_over_regset_sections` gdbarch method. */
- static void
- arc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
- iterate_over_regset_sections_cb *cb,
- void *cb_data,
- const struct regcache *regcache)
- {
- /* There are 40 registers in Linux user_regs_struct, although some of
- them are now just a mere paddings, kept to maintain binary
- compatibility with older tools. */
- const int sizeof_gregset = 40 * ARC_REGISTER_SIZE;
- cb (".reg", sizeof_gregset, sizeof_gregset, &arc_linux_gregset, NULL,
- cb_data);
- cb (".reg-arc-v2", ARC_LINUX_SIZEOF_V2_REGSET, ARC_LINUX_SIZEOF_V2_REGSET,
- &arc_linux_v2_regset, NULL, cb_data);
- }
- /* Implement the `core_read_description` gdbarch method. */
- static const struct target_desc *
- arc_linux_core_read_description (struct gdbarch *gdbarch,
- struct target_ops *target,
- bfd *abfd)
- {
- arc_arch_features features
- = arc_arch_features_create (abfd,
- gdbarch_bfd_arch_info (gdbarch)->mach);
- return arc_lookup_target_description (features);
- }
- /* Initialization specific to Linux environment. */
- static void
- arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
- {
- arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- arc_linux_debug_printf ("GNU/Linux OS/ABI initialization.");
- /* Fill in target-dependent info in ARC-private structure. */
- tdep->is_sigtramp = arc_linux_is_sigtramp;
- tdep->sigcontext_addr = arc_linux_sigcontext_addr;
- tdep->sc_reg_offset = arc_linux_sc_reg_offsets;
- tdep->sc_num_regs = ARRAY_SIZE (arc_linux_sc_reg_offsets);
- /* If we are using Linux, we have in uClibc
- (libc/sysdeps/linux/arc/bits/setjmp.h):
- typedef int __jmp_buf[13+1+1+1]; //r13-r25, fp, sp, blink
- Where "blink" is a stored PC of a caller function.
- */
- tdep->jb_pc = 15;
- linux_init_abi (info, gdbarch, 0);
- /* Set up target dependent GDB architecture entries. */
- set_gdbarch_cannot_fetch_register (gdbarch, arc_linux_cannot_fetch_register);
- set_gdbarch_cannot_store_register (gdbarch, arc_linux_cannot_store_register);
- set_gdbarch_breakpoint_kind_from_pc (gdbarch,
- arc_linux_breakpoint_kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch,
- arc_linux_sw_breakpoint_from_kind);
- set_gdbarch_fetch_tls_load_module_address (gdbarch,
- svr4_fetch_objfile_link_map);
- set_gdbarch_software_single_step (gdbarch, arc_linux_software_single_step);
- set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
- set_gdbarch_skip_solib_resolver (gdbarch, arc_linux_skip_solib_resolver);
- set_gdbarch_iterate_over_regset_sections
- (gdbarch, arc_linux_iterate_over_regset_sections);
- set_gdbarch_core_read_description (gdbarch, arc_linux_core_read_description);
- /* GNU/Linux uses SVR4-style shared libraries, with 32-bit ints, longs
- and pointers (ILP32). */
- set_solib_svr4_fetch_link_map_offsets (gdbarch,
- linux_ilp32_fetch_link_map_offsets);
- }
- /* Suppress warning from -Wmissing-prototypes. */
- extern initialize_file_ftype _initialize_arc_linux_tdep;
- void
- _initialize_arc_linux_tdep ()
- {
- gdbarch_register_osabi (bfd_arch_arc, 0, GDB_OSABI_LINUX,
- arc_linux_init_osabi);
- }
|