aboutsummaryrefslogtreecommitdiff
path: root/opcodes
diff options
context:
space:
mode:
authorAndrew Burgess <aburgess@redhat.com>2022-05-26 13:11:11 +0100
committerAndrew Burgess <aburgess@redhat.com>2022-05-27 14:12:33 +0100
commit202be274a41a912f705141d9fb3574f4b0d415e1 (patch)
treeb916bd95dbcd7f04fd60a4c58712642740fc4ace /opcodes
parent601598589589734c21bacfc00cd4aed4f3fd1a1f (diff)
downloadgdb-202be274a41a912f705141d9fb3574f4b0d415e1.zip
gdb-202be274a41a912f705141d9fb3574f4b0d415e1.tar.gz
gdb-202be274a41a912f705141d9fb3574f4b0d415e1.tar.bz2
opcodes/i386: remove trailing whitespace from insns with zero operands
While working on another patch[1] I had need to touch this code in i386-dis.c: ins->obufp = ins->mnemonicendp; for (i = strlen (ins->obuf) + prefix_length; i < 6; i++) oappend (ins, " "); oappend (ins, " "); (*ins->info->fprintf_styled_func) (ins->info->stream, dis_style_mnemonic, "%s", ins->obuf); What this code does is add whitespace after the instruction mnemonic and before the instruction operands. The problem I ran into when working on this code can be seen by assembling this input file: .text nop retq Now, when I disassemble, here's the output. I've replaced trailing whitespace with '_' so that the issue is clearer: Disassembly of section .text: 0000000000000000 <.text>: 0: 90 nop 1: c3 retq___ Notice that there's no trailing whitespace after 'nop', but there are three spaces after 'retq'! What happens is that instruction mnemonics are emitted into a buffer instr_info::obuf, then instr_info::mnemonicendp is setup to point to the '\0' character at the end of the mnemonic. When we emit the whitespace, this is then added starting at the mnemonicendp position. Lets consider 'retq', first the buffer is setup like this: 'r' 'e' 't' 'q' '\0' Then we add whitespace characters at the '\0', converting the buffer to this: 'r' 'e' 't' 'q' ' ' ' ' ' ' '\0' However, 'nop' is actually an alias for 'xchg %rax,%rax', so, initially, the buffer is setup like this: 'x' 'c' 'h' 'g' '\0' Then in NOP_Fixup we spot that we have an instruction that is an alias for 'nop', and adjust the buffer to this: 'n' 'o' 'p' '\0' '\0' The second '\0' is left over from the original buffer contents. However, when we rewrite the buffer, we don't afjust mnemonicendp, which still points at the second '\0' character. Now, when we insert whitespace we get: 'n' 'o' 'p' '\0' ' ' ' ' ' ' ' ' '\0' Notice the whitespace is inserted after the first '\0', so, when we print the buffer, the whitespace is not printed. The fix for this is pretty easy, I can change NOP_Fixup to adjust mnemonicendp, but now a bunch of tests start failing, we now produce whitespace after the 'nop', which the tests don't expect. So, I could update the tests to expect the whitespace.... ...except I'm not a fan of trailing whitespace, so I'd really rather not. Turns out, I can pretty easily update the whitespace emitting code to spot instructions that have zero operands and just not emit any whitespace in this case. So this is what I've done. I've left in the fix for NOP_Fixup, I think updating mnemonicendp is probably a good thing, though this is not really required any more. I've then updated all the tests that I saw failing to adjust the expected patterns to account for the change in whitespace. [1] https://sourceware.org/pipermail/binutils/2022-April/120610.html
Diffstat (limited to 'opcodes')
-rw-r--r--opcodes/i386-dis.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c
index 414aa68..7b99969 100644
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -9318,6 +9318,7 @@ print_insn (bfd_vma pc, instr_info *ins)
const char *p;
struct dis_private priv;
int prefix_length;
+ int op_count;
ins->isa64 = 0;
ins->intel_mnemonic = !SYSV386_COMPAT;
@@ -9762,12 +9763,28 @@ print_insn (bfd_vma pc, instr_info *ins)
return MAX_CODE_LENGTH;
}
+ /* Calculate the number of operands this instruction has. */
+ op_count = 0;
+ for (i = 0; i < MAX_OPERANDS; ++i)
+ if (*ins->op_out[i] != '\0')
+ ++op_count;
+
+ /* Calculate the number of spaces to print after the mnemonic. */
ins->obufp = ins->mnemonicendp;
- for (i = strlen (ins->obuf) + prefix_length; i < 6; i++)
- oappend (ins, " ");
- oappend (ins, " ");
+ if (op_count > 0)
+ {
+ i = strlen (ins->obuf) + prefix_length;
+ if (i < 7)
+ i = 7 - i;
+ else
+ i = 1;
+ }
+ else
+ i = 0;
+
+ /* Print the instruction mnemonic along with any trailing whitespace. */
(*ins->info->fprintf_styled_func)
- (ins->info->stream, dis_style_mnemonic, "%s", ins->obuf);
+ (ins->info->stream, dis_style_mnemonic, "%s%*s", ins->obuf, i, "");
/* The enter and bound instructions are printed with operands in the same
order as the intel book; everything else is printed in reverse order. */
@@ -12741,7 +12758,7 @@ static void
NOP_Fixup (instr_info *ins, int opnd, int sizeflag)
{
if ((ins->prefixes & PREFIX_DATA) == 0 && (ins->rex & REX_B) == 0)
- strcpy (ins->obuf, "nop");
+ ins->mnemonicendp = stpcpy (ins->obuf, "nop");
else if (opnd == 0)
OP_REG (ins, eAX_reg, sizeflag);
else