aboutsummaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2025-03-07[gdb/tdep] Support REX2 and EVEX prefixTom de Vries1-1/+109
The following amd64 insn: ... 0: 67 d5 44 8d 3d 00 00 00 00 lea 0x0(%eip),%r31d ... uses the REX2 prefix [1], which is currently not supported in amd64_get_insn_details. Add the missing support in amd64_get_insn_details, as well as a corresponding unit test. Likewise for an amd64 insn using an EVEX prefix [2]: ... 0: 62 f1 7c 48 28 05 00 fc ff ff vmovaps -0x400(%rip),%zmm0 ... Tested on x86_64-linux. PR tdep/32725 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32725 [1] https://en.wikipedia.org/wiki/VEX_prefix [2] https://en.wikipedia.org/wiki/EVEX_prefix
2025-03-07[gdb/tdep] Fix vmovdqu decodingTom de Vries1-6/+77
PR tdep/31952 reports that displaced stepping over an instruction pointer relative insn "vmovdqu 0x20(%rip),%ymm1" gives the wrong results. This is caused by misclassification of the insn in amd64_get_insn_details, which results in details.modrm_offset == -1, while the instruction in fact does have a modrm byte. The instruction is encoded as follows: ... 400557: c5 fe 6f 0d 20 00 00 00 vmovdqu 0x20(%rip),%ymm1 ... where: - "0xc5 0xfe" is the vex2 prefix, - "0x6f" is the opcode, - "0x0d" is the modrm byte, and - "0x20 0x00 0x00 0x00" is a 32-bit displacement. The problem is related to details.opcode_len, which is 1. While it is true that the length of the opcode in the insn (0x6f) is 1 byte, the vex2 prefix implies that we're encoding an 2-byte opcode beginnning with 0x0f [1]. Consequently, we should be using the twobyte_has_modrm map rather than the onebyte_has_modrm map. Fix this in amd64_get_insn_details, and add a selftest to check this. Tested on x86_64-linux. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31952 [1] https://en.wikipedia.org/wiki/VEX_prefix
2025-03-07[gdb/tdep] Make amd64_get_insn_details more regularTom de Vries1-4/+7
In amd64_get_insn_details, I found this code with a comment explaining why enc_prefix_offset is not set: ... else if (vex2_prefix_p (*insn)) { /* Don't record the offset in this case because this prefix has no REX.B equivalent. */ insn += 2; } ... which I didn't understand until I looked at the only use of enc_prefix_offset, in fixup_riprel: ... /* REX.B should be unset (VEX.!B set) as we were using rip-relative addressing, but ensure it's unset (set for VEX) anyway, tmp_regno is not r8-r15. */ if (insn_details->enc_prefix_offset != -1) { gdb_byte *pfx = &dsc->insn_buf[insn_details->enc_prefix_offset]; if (rex_prefix_p (pfx[0])) pfx[0] &= ~REX_B; else if (vex3_prefix_p (pfx[0])) pfx[1] |= VEX3_NOT_B; else gdb_assert_not_reached ("unhandled prefix"); } ... Fix this by: - setting enc_prefix_offset for the vex2 case in amd64_get_insn_details, making the function more regular and easier to understand, and - handling the vex2 case in the "enc_prefix_offset != -1" clause in fixup_riprel. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Add vzeroupper and vzeroall in amd64-insn-decode selftestTom de Vries1-0/+34
After I posted a tentative patch for PR31952, Alexander Monakov pointed out that the patch broke instruction decoding for instructions vzeroall and vzeroupper. Add selftests for these two instructions in amd64-insn-decode, both using vex2 and vex3 prefixes. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Add vex2_to_vex3Tom de Vries1-0/+40
I noticed here [1] that the vex2 prefix is essentially a special case of the vex3 prefix, meaning it's possible to rewrite any insn with a vex2 prefix into an equivalent one with a vex3 prefix. Add function vex2_to_vex3 that does precisely that, in the selftests namespace. Add a selftest that exercises this function. Tested on x86_64-linux. [1] https://en.wikipedia.org/wiki/VEX_prefix
2025-03-07[gdb/tdep] Factor out part of fixup_riprelTom de Vries1-22/+37
Factor out the part of fixup_riprel that patches the insn, and use it in a unit test. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Fix rip-relative insn handling in amd64_get_used_input_int_regTom de Vries1-1/+12
I wanted to add a unit test for an an rip-relative amd64 insn, so I did: ... $ gcc -fPIE hello.c ... and used an rip-relative insn from main: ... 4005db: 48 8d 3d 1e 00 00 00 lea 0x1e(%rip),%rdi ... While writing the unit test, I found that amd64_get_used_input_int_reg returns rbp as input register. Fix this by using rip_relative_p in amd64_get_used_input_int_reg to handle this case. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Factor out rip_relative_pTom de Vries1-2/+14
Factor out rip_relative_p, and rewrite it to use MODRM_MOD_FIELD and MODRM_RM_FIELD. No functional changes. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Add amd64-insn-decode selftestTom de Vries1-8/+63
Add a selftest that checks the results of amd64_get_insn_details and related functions for two basic instructions. Add a parameter assumptions to amd64_get_used_input_int_regs, to make sure that this selftest: ... /* INSN: add %eax,(%rcx). */ ... SELF_CHECK (amd64_get_used_input_int_regs (&details, false) == ((1 << EAX_REG_NUM) | (1 << ECX_REG_NUM))); ... passes because it found the "%eax" in the insn, rather than passing because of this assumption: ... /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly use RAX. */ used_regs_mask |= 1 << EAX_REG_NUM; ... Tested on x86_64-linux.
2025-03-07[gdb/tdep] Factor out amd64_get_used_input_int_regsTom de Vries1-6/+17
The function amd64_get_unused_input_int_reg consists of two parts: - finding the used int registers in an insn, and - picking an unused int register. Factor out the first part as new function amd64_get_used_input_int_regs. No functional changes. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 3Tom de Vries1-21/+22
While reading amd64_get_unused_input_int_reg, I noticed that it avoids picking RSP, which has to do with how the result of the only call to it is going to be used. Likewise for picking a register in the RAX ... RDI range. Fix this by: - adding an allowed_regs_mask parameter to amd64_get_unused_input_int_reg, and - properly documenting the value of the corresponding argument in fixup_riprel. No functional changes. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 2Tom de Vries1-2/+2
I noticed that amd64_get_unused_input_int_reg uses a signed int for a bit mask: ... /* 1 bit for each reg */ int used_regs_mask = 0; ... There's an assert: ... gdb_assert (used_regs_mask < 256); ... which is meant to assert on register numbers >= 8, but if for instance sizeof (used_regs_mask) == 4 and used_regs_mask == (1 << 31), then that is not caught because of the signedness. We could fix this by changing the type to unsigned int, but that only guarantees 16 bits in the reg mask. Intel CPUs with the APX extension support 32 int registers. The implementation of amd64_get_unused_input_int_reg doesn't support analyzing registers with register number >= 8 yet, but now that we're changing the type, it seems like a good idea to anticipate this. Fix this by using uint32_t. Likewise, update the loop over the reg mask: ... for (i = 0; i < 8; ++i) { if (! (used_regs_mask & (1 << i))) return i; ... to handle any used_regs_mask value rather than just those for register number < 8. Tested on x86_64-linux.
2025-03-07[gdb/tdep] Refactor amd64_get_unused_input_int_reg, part 1Tom de Vries1-10/+19
While reading amd64_get_unused_input_int_reg, I noticed that it first asserts, then throws an internal_error if no unused register can be found. Looking at the documentation of gdbarch_displaced_step_copy_insn, it seems that a failure can be indicated less abruptly, by returning a nullptr. Fix this by: - returning -1 in case of failure to find an unused register in amd64_get_unused_input_int_reg, and - propagating this to amd64_displaced_step_copy_insn. Tested on x86_64-linux.
2025-03-07gas: leave expression symbols alone when processing equatesJan Beulich6-5/+46
PR gas/32721 In this bogus piece of code distilled from fuzzing and slightly edited: A=%eax|%! Y=A Z=A or $6,Z the first of the equates with A on the rhs changes A's section (due to the use of S_GET_VALUE()), from expression to register, thus yielding Y in the expression section (and X_op being O_symbol), but Z in the register section (and X_op being O_register with X_add_value being -1). There shouldn't be random O_register expressions, though, for targets setting md_register_arithmetic to false. Plus both Y and Z would better be exchangeable. In pseudo_set() wire handling of O_symbol expressions referencing a symbol in the expression section to that of other stuff ending up in this section. Also avoid bogus O_register expressions to be created, for targets setting md_register_arithmetic to false: S_GET_VALUE() would resolve any arithmetic, which must not happen for such targets. To be on the safe side for such targets, also amend resolve_register(). Correct another earlier oversight there too (affecting at least Z80), by using the new expr_copy() helper there as well. Undo 46b9f07dfe79 ("PR 32721, internal error in tc-i386.c:parse_register"), albeit without losing the simplification it did.
2025-03-07v850: improve linker scripts for relocatable linkingJan Beulich2-14/+14
Quite a few constructs where unconditional when they should take $RELOCATING into account. The original observation was that output of "ld -r" had .text start at 0x00100000.
2025-03-07gas: fold is_end_of_line[] into lex_type[]Jan Beulich6-73/+46
... by way of introducing LEX_EOL and LEX_EOS. As a prereq convert the remaining open-coded accesses. The Alpha change is actually a functional one: The array slot for '!' having been set to 1 is very unlikely to have been correct. 1 means "end of line", when surely "end of statement" was always meant.
2025-03-07include: drop bout.hJan Beulich1-192/+0
gas'es obj-bout.c was dropped about 20 years ago, while bfd's bout.c was dropped almost 7 years ago. Time for the unused header to go away, too.
2025-03-07rl78: drop redundant statement separator checkJan Beulich1-2/+1
With the switch to the use of is_end_of_stmt() in 2dd0370c433d ("rl78: use is_whitespace()") the open-coded checking against line_separator_chars[] can be dropped.
2025-03-07Z8k: use is_end_of_stmt()Jan Beulich1-5/+5
... instead of open-coding it.
2025-03-07x86: use is_end_of_stmt()Jan Beulich2-7/+7
... instead of open-coding it.
2025-03-07VAX: use is_end_of_stmt()Jan Beulich1-2/+2
... instead of open-coding it. This also fixes two array underrun issues, when plain char is a signed type.
2025-03-07TILEPro: use is_end_of_stmt()Jan Beulich1-4/+4
... instead of open-coding it. Also convert a variable to plain char (allowing to drop two casts), which is how it's actually used.
2025-03-07Tile-Gx: use is_end_of_stmt()Jan Beulich1-4/+4
... instead of open-coding it. Also convert a variable to plain char (allowing to drop two casts), which is how it's actually used.
2025-03-07C6x: use is_end_of_stmt()Jan Beulich1-13/+13
... instead of open-coding it.
2025-03-07C54x: use is_end_of_stmt()Jan Beulich1-19/+19
... instead of open-coding it. In tic54x_stringer() this also fixes an array overrun issue: Converting plain char to unsigned int could have yielded huge values when plain char is a signed type. In subsym_substitute() also convert a local variable to plain char, as that's what it's really holding (and how it's used everywhere else).
2025-03-07C4x: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it.
2025-03-07C30: use is_end_of_stmt()Jan Beulich1-3/+3
... instead of open-coding it.
2025-03-07Sparc: use is_end_of_stmt()Jan Beulich1-3/+3
... instead of open-coding it. This also fixes two array underrun issues, when plain char is a signed type.
2025-03-07SH: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it.
2025-03-07Score: use is_end_of_stmt()Jan Beulich2-8/+8
... instead of open-coding it.
2025-03-07RISC-V: use is_end_of_stmt()Jan Beulich1-2/+2
... instead of open-coding it.
2025-03-07pru: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it.
2025-03-07PPC: use is_end_of_stmt()Jan Beulich1-2/+2
... instead of open-coding it.
2025-03-07MMIX: use is_end_of_stmt()Jan Beulich1-2/+2
... instead of open-coding it.
2025-03-07MIPS: use is_end_of_stmt()Jan Beulich1-7/+7
... instead of open-coding it.
2025-03-07MicroBlaze: use is_end_of_stmt()Jan Beulich1-4/+4
... instead of open-coding it.
2025-03-07M68k: use is_end_of_stmt()Jan Beulich1-21/+21
... instead of open-coding it.
2025-03-07M68HC1x: use is_end_of_stmt()Jan Beulich1-7/+7
... instead of open-coding it. With this there's no need for op_end (and hence op_start) to be other than pointer to plain char. Which in turn eliminates the need for several questionable casts.
2025-03-07IQ2000: use is_end_of_stmt()Jan Beulich1-2/+2
... instead of open-coding it.
2025-03-07LoongArch: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it.
2025-03-07HP-PA: use is_end_of_stmt()Jan Beulich1-3/+3
... instead of open-coding it.
2025-03-07dlx: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it.
2025-03-07C-Sky: use is_end_of_stmt()Jan Beulich1-8/+8
... instead of open-coding it.
2025-03-07cris: use is_end_of_stmt()Jan Beulich1-1/+1
Fix use of is_end_of_line[] directly instead of through the is_end_of_stmt() macro.
2025-03-07aarch64: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it.
2025-03-07Arm: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it. This also fixes an array underrun issue: The wrong casting to plain int could have yielded negative values when plain char is a signed type.
2025-03-07Alpha: use is_end_of_stmt()Jan Beulich1-1/+1
... instead of open-coding it. Note that writes to the array need to be left alone; they can only be converted when the array is folded into lex_type[].
2025-03-07Mach-O: use is_end_of_stmt()Jan Beulich1-4/+4
... instead of open-coding it.
2025-03-07ELF: use is_end_of_stmt()Jan Beulich1-2/+2
... instead of open-coding it.
2025-03-07{,E}COFF: use is_end_of_stmt()Jan Beulich2-3/+3
... instead of open-coding it. Convert a variable's type to plain char then as well, as that's what it's really holding (and how it's used everywhere else).