x86: properly initialize struct instr_info instance(s)

Commit 39fb369834a3 ("opcodes: Make i386-dis.c thread-safe") introduced
a lot of uninitialized data. Alan has in particular observed ubsan
taking issue with the loop inverting the order of operands, where
op_riprel[] - an array of bool - can hold values other than 0 or 1.

Move instantiation of struct instr_info into print_insn() (thus having
just a single central point), and make use of C99 dedicated initializers
to fill fields right in the initializer where possible. This way all
fields not explicitly initialized will be zero-filled, which in turn
allows dropping of some other explicit initialization later in the
function or in ckprefix(). Additionally this removes a lot of
indirection, as all "ins->info" uses can simply become "info".

Make one further arrangement though, to limit the amount of data needing
(zero)initializing on every invocation: Convert the op_out structure
member to just an array of pointers, with the actual arrays living
inside print_insn() (and, as befoe, having just their 1st char filled
with nul).

While there, instead of adjusting print_insn()'s forward declaration,
arrange for no such declaration to be needed in the first place.
This commit is contained in:
Jan Beulich
2022-06-13 09:51:38 +02:00
parent 536595b712
commit 384e201e5a

View File

@ -42,7 +42,6 @@
#include <setjmp.h> #include <setjmp.h>
typedef struct instr_info instr_info; typedef struct instr_info instr_info;
static int print_insn (bfd_vma, instr_info *);
static void dofloat (instr_info *, int); static void dofloat (instr_info *, int);
static void OP_ST (instr_info *, int, int); static void OP_ST (instr_info *, int, int);
static void OP_STi (instr_info *, int, int); static void OP_STi (instr_info *, int, int);
@ -234,7 +233,7 @@ struct instr_info
unsigned char op_ad; unsigned char op_ad;
signed char op_index[MAX_OPERANDS]; signed char op_index[MAX_OPERANDS];
bool op_riprel[MAX_OPERANDS]; bool op_riprel[MAX_OPERANDS];
char op_out[MAX_OPERANDS][100]; char *op_out[MAX_OPERANDS];
bfd_vma op_address[MAX_OPERANDS]; bfd_vma op_address[MAX_OPERANDS];
bfd_vma start_pc; bfd_vma start_pc;
@ -8545,22 +8544,7 @@ static int
ckprefix (instr_info *ins) ckprefix (instr_info *ins)
{ {
int newrex, i, length; int newrex, i, length;
ins->rex = 0;
ins->prefixes = 0;
ins->used_prefixes = 0;
ins->rex_used = 0;
ins->evex_used = 0;
ins->last_lock_prefix = -1;
ins->last_repz_prefix = -1;
ins->last_repnz_prefix = -1;
ins->last_data_prefix = -1;
ins->last_addr_prefix = -1;
ins->last_rex_prefix = -1;
ins->last_seg_prefix = -1;
ins->fwait_prefix = -1;
ins->active_seg_prefix = 0;
for (i = 0; i < (int) ARRAY_SIZE (ins->all_prefixes); i++)
ins->all_prefixes[i] = 0;
i = 0; i = 0;
length = 0; length = 0;
/* The maximum instruction length is 15bytes. */ /* The maximum instruction length is 15bytes. */
@ -8769,39 +8753,6 @@ prefix_name (instr_info *ins, int pref, int sizeflag)
} }
} }
/* Here for backwards compatibility. When gdb stops using
print_insn_i386_att and print_insn_i386_intel these functions can
disappear, and print_insn_i386 be merged into print_insn. */
int
print_insn_i386_att (bfd_vma pc, disassemble_info *info)
{
instr_info ins;
ins.info = info;
ins.intel_syntax = 0;
return print_insn (pc, &ins);
}
int
print_insn_i386_intel (bfd_vma pc, disassemble_info *info)
{
instr_info ins;
ins.info = info;
ins.intel_syntax = 1;
return print_insn (pc, &ins);
}
int
print_insn_i386 (bfd_vma pc, disassemble_info *info)
{
instr_info ins;
ins.info = info;
ins.intel_syntax = -1;
return print_insn (pc, &ins);
}
void void
print_i386_disassembler_options (FILE *stream) print_i386_disassembler_options (FILE *stream)
{ {
@ -9421,7 +9372,7 @@ i386_dis_printf (instr_info *ins, enum disassembler_style style,
} }
static int static int
print_insn (bfd_vma pc, instr_info *ins) print_insn (bfd_vma pc, disassemble_info *info, int intel_syntax)
{ {
const struct dis386 *dp; const struct dis386 *dp;
int i; int i;
@ -9433,60 +9384,75 @@ print_insn (bfd_vma pc, instr_info *ins)
struct dis_private priv; struct dis_private priv;
int prefix_length; int prefix_length;
int op_count; int op_count;
instr_info ins = {
.info = info,
.intel_syntax = intel_syntax >= 0
? intel_syntax
: (info->mach & bfd_mach_i386_intel_syntax) != 0,
.intel_mnemonic = !SYSV386_COMPAT,
.op_index[0 ... MAX_OPERANDS - 1] = -1,
.start_pc = pc,
.start_codep = priv.the_buffer,
.codep = priv.the_buffer,
.obufp = ins.obuf,
.last_lock_prefix = -1,
.last_repz_prefix = -1,
.last_repnz_prefix = -1,
.last_data_prefix = -1,
.last_addr_prefix = -1,
.last_rex_prefix = -1,
.last_seg_prefix = -1,
.fwait_prefix = -1,
};
char op_out[MAX_OPERANDS][100];
ins->isa64 = 0;
ins->intel_mnemonic = !SYSV386_COMPAT;
ins->op_is_jump = false;
priv.orig_sizeflag = AFLAG | DFLAG; priv.orig_sizeflag = AFLAG | DFLAG;
if ((ins->info->mach & bfd_mach_i386_i386) != 0) if ((info->mach & bfd_mach_i386_i386) != 0)
ins->address_mode = mode_32bit; ins.address_mode = mode_32bit;
else if (ins->info->mach == bfd_mach_i386_i8086) else if (info->mach == bfd_mach_i386_i8086)
{ {
ins->address_mode = mode_16bit; ins.address_mode = mode_16bit;
priv.orig_sizeflag = 0; priv.orig_sizeflag = 0;
} }
else else
ins->address_mode = mode_64bit; ins.address_mode = mode_64bit;
if (ins->intel_syntax == (char) -1) for (p = info->disassembler_options; p != NULL;)
ins->intel_syntax = (ins->info->mach & bfd_mach_i386_intel_syntax) != 0;
for (p = ins->info->disassembler_options; p != NULL;)
{ {
if (startswith (p, "amd64")) if (startswith (p, "amd64"))
ins->isa64 = amd64; ins.isa64 = amd64;
else if (startswith (p, "intel64")) else if (startswith (p, "intel64"))
ins->isa64 = intel64; ins.isa64 = intel64;
else if (startswith (p, "x86-64")) else if (startswith (p, "x86-64"))
{ {
ins->address_mode = mode_64bit; ins.address_mode = mode_64bit;
priv.orig_sizeflag |= AFLAG | DFLAG; priv.orig_sizeflag |= AFLAG | DFLAG;
} }
else if (startswith (p, "i386")) else if (startswith (p, "i386"))
{ {
ins->address_mode = mode_32bit; ins.address_mode = mode_32bit;
priv.orig_sizeflag |= AFLAG | DFLAG; priv.orig_sizeflag |= AFLAG | DFLAG;
} }
else if (startswith (p, "i8086")) else if (startswith (p, "i8086"))
{ {
ins->address_mode = mode_16bit; ins.address_mode = mode_16bit;
priv.orig_sizeflag &= ~(AFLAG | DFLAG); priv.orig_sizeflag &= ~(AFLAG | DFLAG);
} }
else if (startswith (p, "intel")) else if (startswith (p, "intel"))
{ {
ins->intel_syntax = 1; ins.intel_syntax = 1;
if (startswith (p + 5, "-mnemonic")) if (startswith (p + 5, "-mnemonic"))
ins->intel_mnemonic = true; ins.intel_mnemonic = true;
} }
else if (startswith (p, "att")) else if (startswith (p, "att"))
{ {
ins->intel_syntax = 0; ins.intel_syntax = 0;
if (startswith (p + 3, "-mnemonic")) if (startswith (p + 3, "-mnemonic"))
ins->intel_mnemonic = false; ins.intel_mnemonic = false;
} }
else if (startswith (p, "addr")) else if (startswith (p, "addr"))
{ {
if (ins->address_mode == mode_64bit) if (ins.address_mode == mode_64bit)
{ {
if (p[4] == '3' && p[5] == '2') if (p[4] == '3' && p[5] == '2')
priv.orig_sizeflag &= ~AFLAG; priv.orig_sizeflag &= ~AFLAG;
@ -9516,46 +9482,41 @@ print_insn (bfd_vma pc, instr_info *ins)
p++; p++;
} }
if (ins->address_mode == mode_64bit && sizeof (bfd_vma) < 8) if (ins.address_mode == mode_64bit && sizeof (bfd_vma) < 8)
{ {
i386_dis_printf (ins, dis_style_text, _("64-bit address is disabled")); i386_dis_printf (&ins, dis_style_text, _("64-bit address is disabled"));
return -1; return -1;
} }
if (ins->intel_syntax) if (ins.intel_syntax)
{ {
ins->open_char = '['; ins.open_char = '[';
ins->close_char = ']'; ins.close_char = ']';
ins->separator_char = '+'; ins.separator_char = '+';
ins->scale_char = '*'; ins.scale_char = '*';
} }
else else
{ {
ins->open_char = '('; ins.open_char = '(';
ins->close_char = ')'; ins.close_char = ')';
ins->separator_char = ','; ins.separator_char = ',';
ins->scale_char = ','; ins.scale_char = ',';
} }
/* The output looks better if we put 7 bytes on a line, since that /* The output looks better if we put 7 bytes on a line, since that
puts most long word instructions on a single line. */ puts most long word instructions on a single line. */
ins->info->bytes_per_line = 7; info->bytes_per_line = 7;
ins->info->private_data = &priv; info->private_data = &priv;
priv.max_fetched = priv.the_buffer; priv.max_fetched = priv.the_buffer;
priv.insn_start = pc; priv.insn_start = pc;
ins->obuf[0] = 0;
for (i = 0; i < MAX_OPERANDS; ++i) for (i = 0; i < MAX_OPERANDS; ++i)
{ {
ins->op_out[i][0] = 0; op_out[i][0] = 0;
ins->op_index[i] = -1; ins.op_out[i] = op_out[i];
} }
ins->start_pc = pc;
ins->start_codep = priv.the_buffer;
ins->codep = priv.the_buffer;
if (OPCODES_SIGSETJMP (priv.bailout) != 0) if (OPCODES_SIGSETJMP (priv.bailout) != 0)
{ {
const char *name; const char *name;
@ -9563,17 +9524,17 @@ print_insn (bfd_vma pc, instr_info *ins)
/* Getting here means we tried for data but didn't get it. That /* Getting here means we tried for data but didn't get it. That
means we have an incomplete instruction of some sort. Just means we have an incomplete instruction of some sort. Just
print the first byte as a prefix or a .byte pseudo-op. */ print the first byte as a prefix or a .byte pseudo-op. */
if (ins->codep > priv.the_buffer) if (ins.codep > priv.the_buffer)
{ {
name = prefix_name (ins, priv.the_buffer[0], priv.orig_sizeflag); name = prefix_name (&ins, priv.the_buffer[0], priv.orig_sizeflag);
if (name != NULL) if (name != NULL)
i386_dis_printf (ins, dis_style_mnemonic, "%s", name); i386_dis_printf (&ins, dis_style_mnemonic, "%s", name);
else else
{ {
/* Just print the first byte as a .byte instruction. */ /* Just print the first byte as a .byte instruction. */
i386_dis_printf (ins, dis_style_assembler_directive, i386_dis_printf (&ins, dis_style_assembler_directive,
".byte "); ".byte ");
i386_dis_printf (ins, dis_style_immediate, "0x%x", i386_dis_printf (&ins, dis_style_immediate, "0x%x",
(unsigned int) priv.the_buffer[0]); (unsigned int) priv.the_buffer[0]);
} }
@ -9583,134 +9544,129 @@ print_insn (bfd_vma pc, instr_info *ins)
return -1; return -1;
} }
ins->obufp = ins->obuf;
sizeflag = priv.orig_sizeflag; sizeflag = priv.orig_sizeflag;
if (!ckprefix (ins) || ins->rex_used) if (!ckprefix (&ins) || ins.rex_used)
{ {
/* Too many ins->prefixes or unused REX ins->prefixes. */ /* Too many prefixes or unused REX prefixes. */
for (i = 0; for (i = 0;
i < (int) ARRAY_SIZE (ins->all_prefixes) && ins->all_prefixes[i]; i < (int) ARRAY_SIZE (ins.all_prefixes) && ins.all_prefixes[i];
i++) i++)
i386_dis_printf (ins, dis_style_mnemonic, "%s%s", i386_dis_printf (&ins, dis_style_mnemonic, "%s%s",
(i == 0 ? "" : " "), (i == 0 ? "" : " "),
prefix_name (ins, ins->all_prefixes[i], sizeflag)); prefix_name (&ins, ins.all_prefixes[i], sizeflag));
return i; return i;
} }
ins->insn_codep = ins->codep; ins.insn_codep = ins.codep;
FETCH_DATA (ins->info, ins->codep + 1); FETCH_DATA (info, ins.codep + 1);
ins->two_source_ops = (*ins->codep == 0x62) || (*ins->codep == 0xc8); ins.two_source_ops = (*ins.codep == 0x62) || (*ins.codep == 0xc8);
if (((ins->prefixes & PREFIX_FWAIT) if (((ins.prefixes & PREFIX_FWAIT)
&& ((*ins->codep < 0xd8) || (*ins->codep > 0xdf)))) && ((*ins.codep < 0xd8) || (*ins.codep > 0xdf))))
{ {
/* Handle ins->prefixes before fwait. */ /* Handle ins.prefixes before fwait. */
for (i = 0; i < ins->fwait_prefix && ins->all_prefixes[i]; for (i = 0; i < ins.fwait_prefix && ins.all_prefixes[i];
i++) i++)
i386_dis_printf (ins, dis_style_mnemonic, "%s ", i386_dis_printf (&ins, dis_style_mnemonic, "%s ",
prefix_name (ins, ins->all_prefixes[i], sizeflag)); prefix_name (&ins, ins.all_prefixes[i], sizeflag));
i386_dis_printf (ins, dis_style_mnemonic, "fwait"); i386_dis_printf (&ins, dis_style_mnemonic, "fwait");
return i + 1; return i + 1;
} }
if (*ins->codep == 0x0f) if (*ins.codep == 0x0f)
{ {
unsigned char threebyte; unsigned char threebyte;
ins->codep++; ins.codep++;
FETCH_DATA (ins->info, ins->codep + 1); FETCH_DATA (info, ins.codep + 1);
threebyte = *ins->codep; threebyte = *ins.codep;
dp = &dis386_twobyte[threebyte]; dp = &dis386_twobyte[threebyte];
ins->need_modrm = twobyte_has_modrm[threebyte]; ins.need_modrm = twobyte_has_modrm[threebyte];
ins->codep++; ins.codep++;
} }
else else
{ {
dp = &dis386[*ins->codep]; dp = &dis386[*ins.codep];
ins->need_modrm = onebyte_has_modrm[*ins->codep]; ins.need_modrm = onebyte_has_modrm[*ins.codep];
ins->codep++; ins.codep++;
} }
/* Save sizeflag for printing the extra ins->prefixes later before updating /* Save sizeflag for printing the extra ins.prefixes later before updating
it for mnemonic and operand processing. The prefix names depend it for mnemonic and operand processing. The prefix names depend
only on the address mode. */ only on the address mode. */
orig_sizeflag = sizeflag; orig_sizeflag = sizeflag;
if (ins->prefixes & PREFIX_ADDR) if (ins.prefixes & PREFIX_ADDR)
sizeflag ^= AFLAG; sizeflag ^= AFLAG;
if ((ins->prefixes & PREFIX_DATA)) if ((ins.prefixes & PREFIX_DATA))
sizeflag ^= DFLAG; sizeflag ^= DFLAG;
ins->end_codep = ins->codep; ins.end_codep = ins.codep;
if (ins->need_modrm) if (ins.need_modrm)
{ {
FETCH_DATA (ins->info, ins->codep + 1); FETCH_DATA (info, ins.codep + 1);
ins->modrm.mod = (*ins->codep >> 6) & 3; ins.modrm.mod = (*ins.codep >> 6) & 3;
ins->modrm.reg = (*ins->codep >> 3) & 7; ins.modrm.reg = (*ins.codep >> 3) & 7;
ins->modrm.rm = *ins->codep & 7; ins.modrm.rm = *ins.codep & 7;
} }
else
memset (&ins->modrm, 0, sizeof (ins->modrm));
ins->need_vex = false;
memset (&ins->vex, 0, sizeof (ins->vex));
if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE) if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE)
{ {
get_sib (ins, sizeflag); get_sib (&ins, sizeflag);
dofloat (ins, sizeflag); dofloat (&ins, sizeflag);
} }
else else
{ {
dp = get_valid_dis386 (dp, ins); dp = get_valid_dis386 (dp, &ins);
if (dp != NULL && putop (ins, dp->name, sizeflag) == 0) if (dp != NULL && putop (&ins, dp->name, sizeflag) == 0)
{ {
get_sib (ins, sizeflag); get_sib (&ins, sizeflag);
for (i = 0; i < MAX_OPERANDS; ++i) for (i = 0; i < MAX_OPERANDS; ++i)
{ {
ins->obufp = ins->op_out[i]; ins.obufp = ins.op_out[i];
ins->op_ad = MAX_OPERANDS - 1 - i; ins.op_ad = MAX_OPERANDS - 1 - i;
if (dp->op[i].rtn) if (dp->op[i].rtn)
(*dp->op[i].rtn) (ins, dp->op[i].bytemode, sizeflag); (*dp->op[i].rtn) (&ins, dp->op[i].bytemode, sizeflag);
/* For EVEX instruction after the last operand masking /* For EVEX instruction after the last operand masking
should be printed. */ should be printed. */
if (i == 0 && ins->vex.evex) if (i == 0 && ins.vex.evex)
{ {
/* Don't print {%k0}. */ /* Don't print {%k0}. */
if (ins->vex.mask_register_specifier) if (ins.vex.mask_register_specifier)
{ {
const char *reg_name const char *reg_name
= att_names_mask[ins->vex.mask_register_specifier]; = att_names_mask[ins.vex.mask_register_specifier];
oappend (ins, "{");
oappend_register (ins, reg_name); oappend (&ins, "{");
oappend (ins, "}"); oappend_register (&ins, reg_name);
oappend (&ins, "}");
} }
if (ins->vex.zeroing) if (ins.vex.zeroing)
oappend (ins, "{z}"); oappend (&ins, "{z}");
/* S/G insns require a mask and don't allow /* S/G insns require a mask and don't allow
zeroing-masking. */ zeroing-masking. */
if ((dp->op[0].bytemode == vex_vsib_d_w_dq_mode if ((dp->op[0].bytemode == vex_vsib_d_w_dq_mode
|| dp->op[0].bytemode == vex_vsib_q_w_dq_mode) || dp->op[0].bytemode == vex_vsib_q_w_dq_mode)
&& (ins->vex.mask_register_specifier == 0 && (ins.vex.mask_register_specifier == 0
|| ins->vex.zeroing)) || ins.vex.zeroing))
oappend (ins, "/(bad)"); oappend (&ins, "/(bad)");
} }
} }
/* Check whether rounding control was enabled for an insn not /* Check whether rounding control was enabled for an insn not
supporting it. */ supporting it. */
if (ins->modrm.mod == 3 && ins->vex.b if (ins.modrm.mod == 3 && ins.vex.b
&& !(ins->evex_used & EVEX_b_used)) && !(ins.evex_used & EVEX_b_used))
{ {
for (i = 0; i < MAX_OPERANDS; ++i) for (i = 0; i < MAX_OPERANDS; ++i)
{ {
ins->obufp = ins->op_out[i]; ins.obufp = ins.op_out[i];
if (*ins->obufp) if (*ins.obufp)
continue; continue;
oappend (ins, names_rounding[ins->vex.ll]); oappend (&ins, names_rounding[ins.vex.ll]);
oappend (ins, "bad}"); oappend (&ins, "bad}");
break; break;
} }
} }
@ -9718,15 +9674,15 @@ print_insn (bfd_vma pc, instr_info *ins)
} }
/* Clear instruction information. */ /* Clear instruction information. */
ins->info->insn_info_valid = 0; info->insn_info_valid = 0;
ins->info->branch_delay_insns = 0; info->branch_delay_insns = 0;
ins->info->data_size = 0; info->data_size = 0;
ins->info->insn_type = dis_noninsn; info->insn_type = dis_noninsn;
ins->info->target = 0; info->target = 0;
ins->info->target2 = 0; info->target2 = 0;
/* Reset jump operation indicator. */ /* Reset jump operation indicator. */
ins->op_is_jump = false; ins.op_is_jump = false;
{ {
int jump_detection = 0; int jump_detection = 0;
@ -9747,28 +9703,28 @@ print_insn (bfd_vma pc, instr_info *ins)
/* Determine if this is a jump or branch. */ /* Determine if this is a jump or branch. */
if ((jump_detection & 0x3) == 0x3) if ((jump_detection & 0x3) == 0x3)
{ {
ins->op_is_jump = true; ins.op_is_jump = true;
if (jump_detection & 0x4) if (jump_detection & 0x4)
ins->info->insn_type = dis_condbranch; info->insn_type = dis_condbranch;
else else
ins->info->insn_type = (dp->name && !strncmp (dp->name, "call", 4)) info->insn_type = (dp->name && !strncmp (dp->name, "call", 4))
? dis_jsr : dis_branch; ? dis_jsr : dis_branch;
} }
} }
/* If VEX.vvvv and EVEX.vvvv are unused, they must be all 1s, which /* If VEX.vvvv and EVEX.vvvv are unused, they must be all 1s, which
are all 0s in inverted form. */ are all 0s in inverted form. */
if (ins->need_vex && ins->vex.register_specifier != 0) if (ins.need_vex && ins.vex.register_specifier != 0)
{ {
i386_dis_printf (ins, dis_style_text, "(bad)"); i386_dis_printf (&ins, dis_style_text, "(bad)");
return ins->end_codep - priv.the_buffer; return ins.end_codep - priv.the_buffer;
} }
/* If EVEX.z is set, there must be an actual mask register in use. */ /* If EVEX.z is set, there must be an actual mask register in use. */
if (ins->vex.zeroing && ins->vex.mask_register_specifier == 0) if (ins.vex.zeroing && ins.vex.mask_register_specifier == 0)
{ {
i386_dis_printf (ins, dis_style_text, "(bad)"); i386_dis_printf (&ins, dis_style_text, "(bad)");
return ins->end_codep - priv.the_buffer; return ins.end_codep - priv.the_buffer;
} }
switch (dp->prefix_requirement) switch (dp->prefix_requirement)
@ -9776,12 +9732,12 @@ print_insn (bfd_vma pc, instr_info *ins)
case PREFIX_DATA: case PREFIX_DATA:
/* If only the data prefix is marked as mandatory, its absence renders /* If only the data prefix is marked as mandatory, its absence renders
the encoding invalid. Most other PREFIX_OPCODE rules still apply. */ the encoding invalid. Most other PREFIX_OPCODE rules still apply. */
if (ins->need_vex ? !ins->vex.prefix : !(ins->prefixes & PREFIX_DATA)) if (ins.need_vex ? !ins.vex.prefix : !(ins.prefixes & PREFIX_DATA))
{ {
i386_dis_printf (ins, dis_style_text, "(bad)"); i386_dis_printf (&ins, dis_style_text, "(bad)");
return ins->end_codep - priv.the_buffer; return ins.end_codep - priv.the_buffer;
} }
ins->used_prefixes |= PREFIX_DATA; ins.used_prefixes |= PREFIX_DATA;
/* Fall through. */ /* Fall through. */
case PREFIX_OPCODE: case PREFIX_OPCODE:
/* If the mandatory PREFIX_REPZ/PREFIX_REPNZ/PREFIX_DATA prefix is /* If the mandatory PREFIX_REPZ/PREFIX_REPNZ/PREFIX_DATA prefix is
@ -9789,79 +9745,79 @@ print_insn (bfd_vma pc, instr_info *ins)
used by putop and MMX/SSE operand and may be overridden by the used by putop and MMX/SSE operand and may be overridden by the
PREFIX_REPZ/PREFIX_REPNZ fix, we check the PREFIX_DATA prefix PREFIX_REPZ/PREFIX_REPNZ fix, we check the PREFIX_DATA prefix
separately. */ separately. */
if (((ins->need_vex if (((ins.need_vex
? ins->vex.prefix == REPE_PREFIX_OPCODE ? ins.vex.prefix == REPE_PREFIX_OPCODE
|| ins->vex.prefix == REPNE_PREFIX_OPCODE || ins.vex.prefix == REPNE_PREFIX_OPCODE
: (ins->prefixes : (ins.prefixes
& (PREFIX_REPZ | PREFIX_REPNZ)) != 0) & (PREFIX_REPZ | PREFIX_REPNZ)) != 0)
&& (ins->used_prefixes && (ins.used_prefixes
& (PREFIX_REPZ | PREFIX_REPNZ)) == 0) & (PREFIX_REPZ | PREFIX_REPNZ)) == 0)
|| (((ins->need_vex || (((ins.need_vex
? ins->vex.prefix == DATA_PREFIX_OPCODE ? ins.vex.prefix == DATA_PREFIX_OPCODE
: ((ins->prefixes : ((ins.prefixes
& (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA)) & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA))
== PREFIX_DATA)) == PREFIX_DATA))
&& (ins->used_prefixes & PREFIX_DATA) == 0)) && (ins.used_prefixes & PREFIX_DATA) == 0))
|| (ins->vex.evex && dp->prefix_requirement != PREFIX_DATA || (ins.vex.evex && dp->prefix_requirement != PREFIX_DATA
&& !ins->vex.w != !(ins->used_prefixes & PREFIX_DATA))) && !ins.vex.w != !(ins.used_prefixes & PREFIX_DATA)))
{ {
i386_dis_printf (ins, dis_style_text, "(bad)"); i386_dis_printf (&ins, dis_style_text, "(bad)");
return ins->end_codep - priv.the_buffer; return ins.end_codep - priv.the_buffer;
} }
break; break;
case PREFIX_IGNORED: case PREFIX_IGNORED:
/* Zap data size and rep prefixes from used_prefixes and reinstate their /* Zap data size and rep prefixes from used_prefixes and reinstate their
origins in all_prefixes. */ origins in all_prefixes. */
ins->used_prefixes &= ~PREFIX_OPCODE; ins.used_prefixes &= ~PREFIX_OPCODE;
if (ins->last_data_prefix >= 0) if (ins.last_data_prefix >= 0)
ins->all_prefixes[ins->last_data_prefix] = 0x66; ins.all_prefixes[ins.last_data_prefix] = 0x66;
if (ins->last_repz_prefix >= 0) if (ins.last_repz_prefix >= 0)
ins->all_prefixes[ins->last_repz_prefix] = 0xf3; ins.all_prefixes[ins.last_repz_prefix] = 0xf3;
if (ins->last_repnz_prefix >= 0) if (ins.last_repnz_prefix >= 0)
ins->all_prefixes[ins->last_repnz_prefix] = 0xf2; ins.all_prefixes[ins.last_repnz_prefix] = 0xf2;
break; break;
} }
/* Check if the REX prefix is used. */ /* Check if the REX prefix is used. */
if ((ins->rex ^ ins->rex_used) == 0 if ((ins.rex ^ ins.rex_used) == 0
&& !ins->need_vex && ins->last_rex_prefix >= 0) && !ins.need_vex && ins.last_rex_prefix >= 0)
ins->all_prefixes[ins->last_rex_prefix] = 0; ins.all_prefixes[ins.last_rex_prefix] = 0;
/* Check if the SEG prefix is used. */ /* Check if the SEG prefix is used. */
if ((ins->prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS | PREFIX_ES if ((ins.prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS | PREFIX_ES
| PREFIX_FS | PREFIX_GS)) != 0 | PREFIX_FS | PREFIX_GS)) != 0
&& (ins->used_prefixes & ins->active_seg_prefix) != 0) && (ins.used_prefixes & ins.active_seg_prefix) != 0)
ins->all_prefixes[ins->last_seg_prefix] = 0; ins.all_prefixes[ins.last_seg_prefix] = 0;
/* Check if the ADDR prefix is used. */ /* Check if the ADDR prefix is used. */
if ((ins->prefixes & PREFIX_ADDR) != 0 if ((ins.prefixes & PREFIX_ADDR) != 0
&& (ins->used_prefixes & PREFIX_ADDR) != 0) && (ins.used_prefixes & PREFIX_ADDR) != 0)
ins->all_prefixes[ins->last_addr_prefix] = 0; ins.all_prefixes[ins.last_addr_prefix] = 0;
/* Check if the DATA prefix is used. */ /* Check if the DATA prefix is used. */
if ((ins->prefixes & PREFIX_DATA) != 0 if ((ins.prefixes & PREFIX_DATA) != 0
&& (ins->used_prefixes & PREFIX_DATA) != 0 && (ins.used_prefixes & PREFIX_DATA) != 0
&& !ins->need_vex) && !ins.need_vex)
ins->all_prefixes[ins->last_data_prefix] = 0; ins.all_prefixes[ins.last_data_prefix] = 0;
/* Print the extra ins->prefixes. */ /* Print the extra ins.prefixes. */
prefix_length = 0; prefix_length = 0;
for (i = 0; i < (int) ARRAY_SIZE (ins->all_prefixes); i++) for (i = 0; i < (int) ARRAY_SIZE (ins.all_prefixes); i++)
if (ins->all_prefixes[i]) if (ins.all_prefixes[i])
{ {
const char *name; const char *name;
name = prefix_name (ins, ins->all_prefixes[i], orig_sizeflag); name = prefix_name (&ins, ins.all_prefixes[i], orig_sizeflag);
if (name == NULL) if (name == NULL)
abort (); abort ();
prefix_length += strlen (name) + 1; prefix_length += strlen (name) + 1;
i386_dis_printf (ins, dis_style_mnemonic, "%s ", name); i386_dis_printf (&ins, dis_style_mnemonic, "%s ", name);
} }
/* Check maximum code length. */ /* Check maximum code length. */
if ((ins->codep - ins->start_codep) > MAX_CODE_LENGTH) if ((ins.codep - ins.start_codep) > MAX_CODE_LENGTH)
{ {
i386_dis_printf (ins, dis_style_text, "(bad)"); i386_dis_printf (&ins, dis_style_text, "(bad)");
return MAX_CODE_LENGTH; return MAX_CODE_LENGTH;
} }
@ -9872,10 +9828,10 @@ print_insn (bfd_vma pc, instr_info *ins)
++op_count; ++op_count;
/* Calculate the number of spaces to print after the mnemonic. */ /* Calculate the number of spaces to print after the mnemonic. */
ins->obufp = ins->mnemonicendp; ins.obufp = ins.mnemonicendp;
if (op_count > 0) if (op_count > 0)
{ {
i = strlen (ins->obuf) + prefix_length; i = strlen (ins.obuf) + prefix_length;
if (i < 7) if (i < 7)
i = 7 - i; i = 7 - i;
else else
@ -9885,21 +9841,21 @@ print_insn (bfd_vma pc, instr_info *ins)
i = 0; i = 0;
/* Print the instruction mnemonic along with any trailing whitespace. */ /* Print the instruction mnemonic along with any trailing whitespace. */
i386_dis_printf (ins, dis_style_mnemonic, "%s%*s", ins->obuf, i, ""); i386_dis_printf (&ins, dis_style_mnemonic, "%s%*s", ins.obuf, i, "");
/* The enter and bound instructions are printed with operands in the same /* The enter and bound instructions are printed with operands in the same
order as the intel book; everything else is printed in reverse order. */ order as the intel book; everything else is printed in reverse order. */
intel_swap_2_3 = false; intel_swap_2_3 = false;
if (ins->intel_syntax || ins->two_source_ops) if (ins.intel_syntax || ins.two_source_ops)
{ {
for (i = 0; i < MAX_OPERANDS; ++i) for (i = 0; i < MAX_OPERANDS; ++i)
op_txt[i] = ins->op_out[i]; op_txt[i] = ins.op_out[i];
if (ins->intel_syntax && dp && dp->op[2].rtn == OP_Rounding if (ins.intel_syntax && dp && dp->op[2].rtn == OP_Rounding
&& dp->op[3].rtn == OP_E && dp->op[4].rtn == NULL) && dp->op[3].rtn == OP_E && dp->op[4].rtn == NULL)
{ {
op_txt[2] = ins->op_out[3]; op_txt[2] = ins.op_out[3];
op_txt[3] = ins->op_out[2]; op_txt[3] = ins.op_out[2];
intel_swap_2_3 = true; intel_swap_2_3 = true;
} }
@ -9907,18 +9863,18 @@ print_insn (bfd_vma pc, instr_info *ins)
{ {
bool riprel; bool riprel;
ins->op_ad = ins->op_index[i]; ins.op_ad = ins.op_index[i];
ins->op_index[i] = ins->op_index[MAX_OPERANDS - 1 - i]; ins.op_index[i] = ins.op_index[MAX_OPERANDS - 1 - i];
ins->op_index[MAX_OPERANDS - 1 - i] = ins->op_ad; ins.op_index[MAX_OPERANDS - 1 - i] = ins.op_ad;
riprel = ins->op_riprel[i]; riprel = ins.op_riprel[i];
ins->op_riprel[i] = ins->op_riprel[MAX_OPERANDS - 1 - i]; ins.op_riprel[i] = ins.op_riprel[MAX_OPERANDS - 1 - i];
ins->op_riprel[MAX_OPERANDS - 1 - i] = riprel; ins.op_riprel[MAX_OPERANDS - 1 - i] = riprel;
} }
} }
else else
{ {
for (i = 0; i < MAX_OPERANDS; ++i) for (i = 0; i < MAX_OPERANDS; ++i)
op_txt[MAX_OPERANDS - 1 - i] = ins->op_out[i]; op_txt[MAX_OPERANDS - 1 - i] = ins.op_out[i];
} }
needcomma = 0; needcomma = 0;
@ -9928,7 +9884,7 @@ print_insn (bfd_vma pc, instr_info *ins)
/* In Intel syntax embedded rounding / SAE are not separate operands. /* In Intel syntax embedded rounding / SAE are not separate operands.
Instead they're attached to the prior register operand. Simply Instead they're attached to the prior register operand. Simply
suppress emission of the comma to achieve that effect. */ suppress emission of the comma to achieve that effect. */
switch (i & -(ins->intel_syntax && dp)) switch (i & -(ins.intel_syntax && dp))
{ {
case 2: case 2:
if (dp->op[2].rtn == OP_Rounding && !intel_swap_2_3) if (dp->op[2].rtn == OP_Rounding && !intel_swap_2_3)
@ -9940,36 +9896,58 @@ print_insn (bfd_vma pc, instr_info *ins)
break; break;
} }
if (needcomma) if (needcomma)
i386_dis_printf (ins, dis_style_text, ","); i386_dis_printf (&ins, dis_style_text, ",");
if (ins->op_index[i] != -1 && !ins->op_riprel[i]) if (ins.op_index[i] != -1 && !ins.op_riprel[i])
{ {
bfd_vma target = (bfd_vma) ins->op_address[ins->op_index[i]]; bfd_vma target = (bfd_vma) ins.op_address[ins.op_index[i]];
if (ins->op_is_jump) if (ins.op_is_jump)
{ {
ins->info->insn_info_valid = 1; info->insn_info_valid = 1;
ins->info->branch_delay_insns = 0; info->branch_delay_insns = 0;
ins->info->data_size = 0; info->data_size = 0;
ins->info->target = target; info->target = target;
ins->info->target2 = 0; info->target2 = 0;
} }
(*ins->info->print_address_func) (target, ins->info); (*info->print_address_func) (target, info);
} }
else else
i386_dis_printf (ins, dis_style_text, "%s", op_txt[i]); i386_dis_printf (&ins, dis_style_text, "%s", op_txt[i]);
needcomma = 1; needcomma = 1;
} }
for (i = 0; i < MAX_OPERANDS; i++) for (i = 0; i < MAX_OPERANDS; i++)
if (ins->op_index[i] != -1 && ins->op_riprel[i]) if (ins.op_index[i] != -1 && ins.op_riprel[i])
{ {
i386_dis_printf (ins, dis_style_comment_start, " # "); i386_dis_printf (&ins, dis_style_comment_start, " # ");
(*ins->info->print_address_func) ((bfd_vma) (*info->print_address_func)
(ins->start_pc + (ins->codep - ins->start_codep) ((bfd_vma)(ins.start_pc + (ins.codep - ins.start_codep)
+ ins->op_address[ins->op_index[i]]), ins->info); + ins.op_address[ins.op_index[i]]),
info);
break; break;
} }
return ins->codep - priv.the_buffer; return ins.codep - priv.the_buffer;
}
/* Here for backwards compatibility. When gdb stops using
print_insn_i386_att and print_insn_i386_intel these functions can
disappear, and print_insn_i386 be merged into print_insn. */
int
print_insn_i386_att (bfd_vma pc, disassemble_info *info)
{
return print_insn (pc, info, 0);
}
int
print_insn_i386_intel (bfd_vma pc, disassemble_info *info)
{
return print_insn (pc, info, 1);
}
int
print_insn_i386 (bfd_vma pc, disassemble_info *info)
{
return print_insn (pc, info, -1);
} }
static const char *float_mem[] = { static const char *float_mem[] = {