[PATCH v2 2/2] gdbserver: Add GNU/Linux support for ARC
Simon Marchi
simark@simark.ca
Wed Oct 7 02:28:54 GMT 2020
Some minor comments, but otherwise this is fine. Please merge after
going through the comments.
On 2020-10-06 12:42 p.m., Shahab Vahedi wrote:
> +/* Using a mere "uint16_t arc_linux_traps_s = TRAP_S_1_OPCODE" would
> + work as well, because the endianness will end up correctly when
> + the code is compiled for the same endianness as the target (see
> + the notes for "low_breakpoint_at" in this file). However, this
> + illustrates how the __BIG_ENDIAN__ macro can be used to make
> + easy-to-understand codes. */
If you have a simpler way that doesn't use __BIG_ENDIAN__, that's fine
too. Don't feel forced to use it only because I suggested it.
> +bool
> +arc_target::low_cannot_store_register (int regno)
> +{
> + return (regno >= current_process ()->tdesc->reg_defs.size ());
> +}
> +
> +/* This works for both endianness. Below you see an illustration of how
> + the "trap_s 1" instruction encoded for both endianness in the memory
> + will end up as the TRAP_S_1_OPCODE constant:
> +
> + BE: 0x78 0x3e --> at INSN addr: 0x78 0x3e --> INSN = 0x783e
> + LE: 0x3e 0x78 --> at INSN addr: 0x3e 0x78 --> INSN = 0x783e
> +
> + One can employ "memcmp()" for comparing the arrays too.
> + A big shout-out to Simon Marchi (simark) for clearing this up.
Heh, please don't mention this :).
> + */
> +
> +bool
> +arc_target::low_breakpoint_at (CORE_ADDR where)
> +{
> + uint16_t insn;
> +
> + /* Since "this" is "the_target", no point in using the latter. */
This is not a very useful comment IMO. "this" is the "current"
arc_target object, which is obvious to anybody familiar with C++.
> + this->read_memory (where, (gdb_byte *) &insn, TRAP_S_1_SIZE);
> + return (insn == TRAP_S_1_OPCODE);
> +}
> +
> +/* PTRACE_GETREGSET/NT_PRSTATUS and PTRACE_SETREGSET/NT_PRSTATUS work with
> + regsets in a struct, "user_regs_struct", defined in the
> + linux/arch/arc/include/uapi/asm/ptrace.h header. This code supports
> + ARC Linux ABI v3 and v4. */
> +
> +/* Populate a ptrace NT_PRSTATUS regset from a regcache.
> +
> + This appears to be a unique approach to populating the buffer, but
> + being name, rather than offset based, it is robust to future API
> + changes, as there is no need to create a regmap of registers in the
> + user_regs_struct. */
> +
> +static void
> +arc_fill_gregset (struct regcache *regcache, void *buf)
> +{
> + struct user_regs_struct *regbuf = (struct user_regs_struct *) buf;
> +
> + /* Core registers. */
> + collect_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
> + collect_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
> + collect_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
> + collect_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
> + collect_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
> + collect_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
> + collect_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
> + collect_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
> + collect_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
> + collect_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
> + collect_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
> + collect_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
> + collect_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
> + collect_register_by_name (regcache, "r13", &(regbuf->callee.r13));
> + collect_register_by_name (regcache, "r14", &(regbuf->callee.r14));
> + collect_register_by_name (regcache, "r15", &(regbuf->callee.r15));
> + collect_register_by_name (regcache, "r16", &(regbuf->callee.r16));
> + collect_register_by_name (regcache, "r17", &(regbuf->callee.r17));
> + collect_register_by_name (regcache, "r18", &(regbuf->callee.r18));
> + collect_register_by_name (regcache, "r19", &(regbuf->callee.r19));
> + collect_register_by_name (regcache, "r20", &(regbuf->callee.r20));
> + collect_register_by_name (regcache, "r21", &(regbuf->callee.r21));
> + collect_register_by_name (regcache, "r22", &(regbuf->callee.r22));
> + collect_register_by_name (regcache, "r23", &(regbuf->callee.r23));
> + collect_register_by_name (regcache, "r24", &(regbuf->callee.r24));
> + collect_register_by_name (regcache, "r25", &(regbuf->callee.r25));
> + collect_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
> + collect_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
> + collect_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
> + collect_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
> +
> + /* Loop registers. */
> + collect_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
> + collect_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
> + collect_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
> +
> + /* The current "pc" value must be written to "eret" (exception return
> + address) register, because that is the address that the kernel code
> + will jump back to after a breakpoint exception has been raised.
> + The "pc_stop" value is ignored by the genregs_set() in
> + linux/arch/arc/kernel/ptrace.c. */
> + collect_register_by_name (regcache, "pc", &(regbuf->scratch.ret));
> +
> + /* Currently ARC Linux ptrace doesn't allow writes to status32 because
> + some of its bits are kernel mode-only and shoudn't be writable from
> + user-space. Writing status32 from debugger could be useful, though,
> + so ability to write non-priviliged bits will be added to kernel
> + sooner or later. */
> +
> + /* BTA. */
> + collect_register_by_name (regcache, "bta", &(regbuf->scratch.bta));
> +}
> +
> +/* Populate a regcache from a ptrace NT_PRSTATUS regset. */
> +
> +static void
> +arc_store_gregset (struct regcache *regcache, const void *buf)
> +{
> + const struct user_regs_struct *regbuf = (const struct user_regs_struct *) buf;
> +
> + /* Core registers. */
> + supply_register_by_name (regcache, "r0", &(regbuf->scratch.r0));
> + supply_register_by_name (regcache, "r1", &(regbuf->scratch.r1));
> + supply_register_by_name (regcache, "r2", &(regbuf->scratch.r2));
> + supply_register_by_name (regcache, "r3", &(regbuf->scratch.r3));
> + supply_register_by_name (regcache, "r4", &(regbuf->scratch.r4));
> + supply_register_by_name (regcache, "r5", &(regbuf->scratch.r5));
> + supply_register_by_name (regcache, "r6", &(regbuf->scratch.r6));
> + supply_register_by_name (regcache, "r7", &(regbuf->scratch.r7));
> + supply_register_by_name (regcache, "r8", &(regbuf->scratch.r8));
> + supply_register_by_name (regcache, "r9", &(regbuf->scratch.r9));
> + supply_register_by_name (regcache, "r10", &(regbuf->scratch.r10));
> + supply_register_by_name (regcache, "r11", &(regbuf->scratch.r11));
> + supply_register_by_name (regcache, "r12", &(regbuf->scratch.r12));
> + supply_register_by_name (regcache, "r13", &(regbuf->callee.r13));
> + supply_register_by_name (regcache, "r14", &(regbuf->callee.r14));
> + supply_register_by_name (regcache, "r15", &(regbuf->callee.r15));
> + supply_register_by_name (regcache, "r16", &(regbuf->callee.r16));
> + supply_register_by_name (regcache, "r17", &(regbuf->callee.r17));
> + supply_register_by_name (regcache, "r18", &(regbuf->callee.r18));
> + supply_register_by_name (regcache, "r19", &(regbuf->callee.r19));
> + supply_register_by_name (regcache, "r20", &(regbuf->callee.r20));
> + supply_register_by_name (regcache, "r21", &(regbuf->callee.r21));
> + supply_register_by_name (regcache, "r22", &(regbuf->callee.r22));
> + supply_register_by_name (regcache, "r23", &(regbuf->callee.r23));
> + supply_register_by_name (regcache, "r24", &(regbuf->callee.r24));
> + supply_register_by_name (regcache, "r25", &(regbuf->callee.r25));
> + supply_register_by_name (regcache, "gp", &(regbuf->scratch.gp));
> + supply_register_by_name (regcache, "fp", &(regbuf->scratch.fp));
> + supply_register_by_name (regcache, "sp", &(regbuf->scratch.sp));
> + supply_register_by_name (regcache, "blink", &(regbuf->scratch.blink));
> +
> + /* Loop registers. */
> + supply_register_by_name (regcache, "lp_count", &(regbuf->scratch.lp_count));
> + supply_register_by_name (regcache, "lp_start", &(regbuf->scratch.lp_start));
> + supply_register_by_name (regcache, "lp_end", &(regbuf->scratch.lp_end));
> +
> + /* The genregs_get() in linux/arch/arc/kernel/ptrace.c populates the
> + pseudo register "stop_pc" with the "efa" (exception fault address)
> + register. This was deemed necessary, because the breakpoint
> + instruction, "trap_s 1", is a committing one; i.e. the "eret"
> + (excpetion return address) register will be pointing to the next
excpetion -> exception
Simon
More information about the Gdb-patches
mailing list