This patch adds a new platform option "notes" that can be used to indicate if
disassembly notes should be placed in the disassembly as comments.
These notes can contain information about a failing constraint such as reading
from a write-only register. The disassembly will not be blocked because of this
but -M notes will emit a comment saying that the operation is not allowed.
For assembly this patch adds a new non-fatal status for errors. This is
essentially a warning. The reason for not creating an actual warning type is
that this causes the interaction between the ordering of warnings and errors to
be problematic. Currently the error buffer is almost always filled because of
the way operands are matched during assembly. An earlier template may have put
an error there that would only be displayed if no other template matches or
generates a higher priority error. But by definition a warning is lower
priority than a warning, so the error (which is incorrect if another template
matched) will supersede the warning. By treating warnings as errors and only
later relaxing the severity this relationship keeps working and the existing
reporting infrastructure can be re-used.
binutils/
PR binutils/21446
* doc/binutils.texi (-M): Document AArch64 options.
* NEWS: Document notes and warnings.
gas/
PR binutils/21446
* config/tc-aarch64.c (print_operands): Indicate no notes.
(output_operand_error_record): Support non-fatal errors.
(output_operand_error_report, warn_unpredictable_ldst, md_assemble):
Likewise.
include/
PR binutils/21446
* opcode/aarch64.h (aarch64_operand_error): Add non_fatal.
(aarch64_print_operand): Support notes.
opcodes/
PR binutils/21446
* aarch64-dis.c (no_notes: New.
(parse_aarch64_dis_option): Support notes.
(aarch64_decode_insn, print_operands): Likewise.
(print_aarch64_disassembler_options): Document notes.
* aarch64-opc.c (aarch64_print_operand): Support notes.
+2018-05-15 Tamar Christina <tamar.christina@arm.com>
+
+ PR binutils/21446
+ * doc/binutils.texi (-M): Document AArch64 options.
+ * NEWS: Document notes and warnings.
+
2018-05-15 Alan Modra <amodra@gmail.com>
* testsuite/lib/binutils-common.exp (is_elf_format): Add chorus,
2018-05-15 Alan Modra <amodra@gmail.com>
* testsuite/lib/binutils-common.exp (is_elf_format): Add chorus,
* Add support for disassembling netronome Flow Processor (NFP) firmware files.
* Add support for disassembling netronome Flow Processor (NFP) firmware files.
+* The AArch64 port now supports showing disassembly notes which are emitted
+ when inconsistencies are found with the instruction that may result in the
+ instruction being invalid. These can be turned on with the option -M notes
+ to objdump.
+
+* The AArch64 port now emits warnings when a combination of an instruction and
+ a named register could be invalid.
+
Changes in 2.30:
* Add --debug-dump=links option to readelf and --dwarf=links option to objdump
Changes in 2.30:
* Add --debug-dump=links option to readelf and --dwarf=links option to objdump
useful when attempting to disassemble thumb code produced by other
compilers.
useful when attempting to disassemble thumb code produced by other
compilers.
+For AArch64 targets this switch can be used to set whether instructions are
+disassembled as the most general instruction using the @option{-M no-aliases}
+option or whether instruction notes should be generated as comments in the
+disasssembly using @option{-M notes}.
+
For the x86, some of the options duplicate functions of the @option{-m}
switch, but allow finer grained control. Multiple selections from the
following may be specified as a comma separated string.
For the x86, some of the options duplicate functions of the @option{-m}
switch, but allow finer grained control. Multiple selections from the
following may be specified as a comma separated string.
+2018-05-15 Tamar Christina <tamar.christina@arm.com>
+
+ PR binutils/21446
+ * config/tc-aarch64.c (print_operands): Indicate no notes.
+ (output_operand_error_record): Support non-fatal errors.
+ (output_operand_error_report, warn_unpredictable_ldst, md_assemble):
+ Likewise.
+
2018-05-15 Tamar Christina <tamar.christina@arm.com>
PR binutils/21446
2018-05-15 Tamar Christina <tamar.christina@arm.com>
PR binutils/21446
break;
/* Generate the operand string in STR. */
break;
/* Generate the operand string in STR. */
- aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL);
+ aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL,
+ NULL);
/* Delimiter. */
if (str[0] != '\0')
/* Delimiter. */
if (str[0] != '\0')
enum aarch64_opnd opd_code = (idx >= 0 ? opcode->operands[idx]
: AARCH64_OPND_NIL);
enum aarch64_opnd opd_code = (idx >= 0 ? opcode->operands[idx]
: AARCH64_OPND_NIL);
+ typedef void (*handler_t)(const char *format, ...);
+ handler_t handler = detail->non_fatal ? as_warn : as_bad;
+
switch (detail->kind)
{
case AARCH64_OPDE_NIL:
gas_assert (0);
break;
switch (detail->kind)
{
case AARCH64_OPDE_NIL:
gas_assert (0);
break;
case AARCH64_OPDE_SYNTAX_ERROR:
case AARCH64_OPDE_RECOVERABLE:
case AARCH64_OPDE_FATAL_SYNTAX_ERROR:
case AARCH64_OPDE_SYNTAX_ERROR:
case AARCH64_OPDE_RECOVERABLE:
case AARCH64_OPDE_FATAL_SYNTAX_ERROR:
if (detail->error != NULL)
{
if (idx < 0)
if (detail->error != NULL)
{
if (idx < 0)
- as_bad (_("%s -- `%s'"), detail->error, str);
+ handler (_("%s -- `%s'"), detail->error, str);
- as_bad (_("%s at operand %d -- `%s'"),
- detail->error, idx + 1, str);
+ handler (_("%s at operand %d -- `%s'"),
+ detail->error, idx + 1, str);
}
else
{
gas_assert (idx >= 0);
}
else
{
gas_assert (idx >= 0);
- as_bad (_("operand %d must be %s -- `%s'"), idx + 1,
- aarch64_get_operand_desc (opd_code), str);
+ handler (_("operand %d must be %s -- `%s'"), idx + 1,
+ aarch64_get_operand_desc (opd_code), str);
}
break;
case AARCH64_OPDE_INVALID_VARIANT:
}
break;
case AARCH64_OPDE_INVALID_VARIANT:
- as_bad (_("operand mismatch -- `%s'"), str);
+ handler (_("operand mismatch -- `%s'"), str);
if (verbose_error_p)
{
/* We will try to correct the erroneous instruction and also provide
if (verbose_error_p)
{
/* We will try to correct the erroneous instruction and also provide
break;
case AARCH64_OPDE_UNTIED_OPERAND:
break;
case AARCH64_OPDE_UNTIED_OPERAND:
- as_bad (_("operand %d must be the same register as operand 1 -- `%s'"),
- detail->index + 1, str);
+ handler (_("operand %d must be the same register as operand 1 -- `%s'"),
+ detail->index + 1, str);
break;
case AARCH64_OPDE_OUT_OF_RANGE:
if (detail->data[0] != detail->data[1])
break;
case AARCH64_OPDE_OUT_OF_RANGE:
if (detail->data[0] != detail->data[1])
- as_bad (_("%s out of range %d to %d at operand %d -- `%s'"),
- detail->error ? detail->error : _("immediate value"),
- detail->data[0], detail->data[1], idx + 1, str);
+ handler (_("%s out of range %d to %d at operand %d -- `%s'"),
+ detail->error ? detail->error : _("immediate value"),
+ detail->data[0], detail->data[1], idx + 1, str);
- as_bad (_("%s must be %d at operand %d -- `%s'"),
- detail->error ? detail->error : _("immediate value"),
- detail->data[0], idx + 1, str);
+ handler (_("%s must be %d at operand %d -- `%s'"),
+ detail->error ? detail->error : _("immediate value"),
+ detail->data[0], idx + 1, str);
break;
case AARCH64_OPDE_REG_LIST:
if (detail->data[0] == 1)
break;
case AARCH64_OPDE_REG_LIST:
if (detail->data[0] == 1)
- as_bad (_("invalid number of registers in the list; "
- "only 1 register is expected at operand %d -- `%s'"),
- idx + 1, str);
+ handler (_("invalid number of registers in the list; "
+ "only 1 register is expected at operand %d -- `%s'"),
+ idx + 1, str);
- as_bad (_("invalid number of registers in the list; "
- "%d registers are expected at operand %d -- `%s'"),
- detail->data[0], idx + 1, str);
+ handler (_("invalid number of registers in the list; "
+ "%d registers are expected at operand %d -- `%s'"),
+ detail->data[0], idx + 1, str);
break;
case AARCH64_OPDE_UNALIGNED:
break;
case AARCH64_OPDE_UNALIGNED:
- as_bad (_("immediate value must be a multiple of "
- "%d at operand %d -- `%s'"),
- detail->data[0], idx + 1, str);
+ handler (_("immediate value must be a multiple of "
+ "%d at operand %d -- `%s'"),
+ detail->data[0], idx + 1, str);
When this function is called, the operand error information had
been collected for an assembly line and there will be multiple
errors in the case of multiple instruction templates; output the
When this function is called, the operand error information had
been collected for an assembly line and there will be multiple
errors in the case of multiple instruction templates; output the
- error message that most closely describes the problem. */
+ error message that most closely describes the problem.
+
+ The errors to be printed can be filtered on printing all errors
+ or only non-fatal errors. This distinction has to be made because
+ the error buffer may already be filled with fatal errors we don't want to
+ print due to the different instruction templates. */
-output_operand_error_report (char *str)
+output_operand_error_report (char *str, bfd_boolean non_fatal_only)
{
int largest_error_pos;
const char *msg = NULL;
{
int largest_error_pos;
const char *msg = NULL;
/* Only one error. */
if (head == operand_error_report.tail)
{
/* Only one error. */
if (head == operand_error_report.tail)
{
- DEBUG_TRACE ("single opcode entry with error kind: %s",
- operand_mismatch_kind_names[head->detail.kind]);
- output_operand_error_record (head, str);
+ /* If the only error is a non-fatal one and we don't want to print it,
+ just exit. */
+ if (!non_fatal_only || head->detail.non_fatal)
+ {
+ DEBUG_TRACE ("single opcode entry with error kind: %s",
+ operand_mismatch_kind_names[head->detail.kind]);
+ output_operand_error_record (head, str);
+ }
largest_error_pos = -2; /* Index can be -1 which means unknown index. */
for (curr = head; curr != NULL; curr = curr->next)
{
largest_error_pos = -2; /* Index can be -1 which means unknown index. */
for (curr = head; curr != NULL; curr = curr->next)
{
- if (curr->detail.kind != kind)
+ /* If we don't want to print non-fatal errors then don't consider them
+ at all. */
+ if (curr->detail.kind != kind
+ || (non_fatal_only && !head->detail.non_fatal))
continue;
/* If there are multiple errors, pick up the one with the highest
mismatching operand index. In the case of multiple errors with
continue;
/* If there are multiple errors, pick up the one with the highest
mismatching operand index. In the case of multiple errors with
+ /* The way errors are collected in the back-end is a bit non-intuitive. But
+ essentially, because each operand template is tried recursively you may
+ always have errors collected from the previous tried OPND. These are
+ usually skipped if there is one successful match. However now with the
+ non-fatal errors we have to ignore those previously collected hard errors
+ when we're only interested in printing the non-fatal ones. This condition
+ prevents us from printing errors that are not appropriate, since we did
+ match a condition, but it also has warnings that it wants to print. */
+ if (non_fatal_only && !record)
+ return;
+
gas_assert (largest_error_pos != -2 && record != NULL);
DEBUG_TRACE ("Pick up error kind %s to report",
operand_mismatch_kind_names[record->detail.kind]);
gas_assert (largest_error_pos != -2 && record != NULL);
DEBUG_TRACE ("Pick up error kind %s to report",
operand_mismatch_kind_names[record->detail.kind]);
goto regoff_addr;
case AARCH64_OPND_SYSREG:
goto regoff_addr;
case AARCH64_OPND_SYSREG:
- {
- uint32_t sysreg_flags;
- if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0,
- &sysreg_flags)) == PARSE_FAIL)
- {
- set_syntax_error (_("unknown or missing system register name"));
- goto failure;
- }
- inst.base.operands[i].sysreg.value = val;
- inst.base.operands[i].sysreg.flags = sysreg_flags;
- break;
- }
+ {
+ uint32_t sysreg_flags;
+ if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0,
+ &sysreg_flags)) == PARSE_FAIL)
+ {
+ set_syntax_error (_("unknown or missing system register name"));
+ goto failure;
+ }
+ inst.base.operands[i].sysreg.value = val;
+ inst.base.operands[i].sysreg.flags = sysreg_flags;
+ break;
+ }
case AARCH64_OPND_PSTATEFIELD:
if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1, NULL))
case AARCH64_OPND_PSTATEFIELD:
if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1, NULL))
aarch64_insn *code)
{
aarch64_operand_error error_info;
aarch64_insn *code)
{
aarch64_operand_error error_info;
+ memset (&error_info, '\0', sizeof (error_info));
error_info.kind = AARCH64_OPDE_NIL;
error_info.kind = AARCH64_OPDE_NIL;
- if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info))
+ if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info)
+ && !error_info.non_fatal)
- else
- {
- gas_assert (error_info.kind != AARCH64_OPDE_NIL);
- record_operand_error_info (opcode, &error_info);
- return FALSE;
- }
+
+ gas_assert (error_info.kind != AARCH64_OPDE_NIL);
+ record_operand_error_info (opcode, &error_info);
+ return error_info.non_fatal;
memcpy (copy, &inst.base, sizeof (struct aarch64_inst));
output_inst (copy);
}
memcpy (copy, &inst.base, sizeof (struct aarch64_inst));
output_inst (copy);
}
+
+ /* Issue non-fatal messages if any. */
+ output_operand_error_report (str, TRUE);
while (template != NULL);
/* Issue the error messages if any. */
while (template != NULL);
/* Issue the error messages if any. */
- output_operand_error_report (str);
+ output_operand_error_report (str, FALSE);
}
/* Various frobbings of labels and their addresses. */
}
/* Various frobbings of labels and their addresses. */
+2018-05-15 Tamar Christina <tamar.christina@arm.com>
+
+ PR binutils/21446
+ * opcode/aarch64.h (aarch64_operand_error): Add non_fatal.
+ (aarch64_print_operand): Support notes.
+
2018-05-15 Tamar Christina <tamar.christina@arm.com>
PR binutils/21446
2018-05-15 Tamar Christina <tamar.christina@arm.com>
PR binutils/21446
int index;
const char *error;
int data[3]; /* Some data for extra information. */
int index;
const char *error;
int data[3]; /* Some data for extra information. */
};
typedef struct aarch64_operand_error aarch64_operand_error;
};
typedef struct aarch64_operand_error aarch64_operand_error;
/* Generate the string representation of an operand. */
extern void
aarch64_print_operand (char *, size_t, bfd_vma, const aarch64_opcode *,
/* Generate the string representation of an operand. */
extern void
aarch64_print_operand (char *, size_t, bfd_vma, const aarch64_opcode *,
- const aarch64_opnd_info *, int, int *, bfd_vma *);
+ const aarch64_opnd_info *, int, int *, bfd_vma *,
+ char **);
/* Miscellaneous interface. */
/* Miscellaneous interface. */
+2018-05-15 Tamar Christina <tamar.christina@arm.com>
+
+ PR binutils/21446
+ * aarch64-dis.c (no_notes: New.
+ (parse_aarch64_dis_option): Support notes.
+ (aarch64_decode_insn, print_operands): Likewise.
+ (print_aarch64_disassembler_options): Document notes.
+ * aarch64-opc.c (aarch64_print_operand): Support notes.
+
2018-05-15 Tamar Christina <tamar.christina@arm.com>
PR binutils/21446
2018-05-15 Tamar Christina <tamar.christina@arm.com>
PR binutils/21446
/* Other options */
static int no_aliases = 0; /* If set disassemble as most general inst. */
/* Other options */
static int no_aliases = 0; /* If set disassemble as most general inst. */
+\fstatic int no_notes = 1; /* If set do not print disassemble notes in the
+ output as comments. */
static void
set_default_aarch64_dis_options (struct disassemble_info *info ATTRIBUTE_UNUSED)
static void
set_default_aarch64_dis_options (struct disassemble_info *info ATTRIBUTE_UNUSED)
+ if (CONST_STRNEQ (option, "no-notes"))
+ {
+ no_notes = 1;
+ return;
+ }
+
+ if (CONST_STRNEQ (option, "notes"))
+ {
+ no_notes = 0;
+ return;
+ }
+
#ifdef DEBUG_AARCH64
if (CONST_STRNEQ (option, "debug_dump"))
{
#ifdef DEBUG_AARCH64
if (CONST_STRNEQ (option, "debug_dump"))
{
const aarch64_opnd_info *opnds, struct disassemble_info *info)
{
int i, pcrel_p, num_printed;
const aarch64_opnd_info *opnds, struct disassemble_info *info)
{
int i, pcrel_p, num_printed;
for (i = 0, num_printed = 0; i < AARCH64_MAX_OPND_NUM; ++i)
{
char str[128];
for (i = 0, num_printed = 0; i < AARCH64_MAX_OPND_NUM; ++i)
{
char str[128];
/* Generate the operand string in STR. */
aarch64_print_operand (str, sizeof (str), pc, opcode, opnds, i, &pcrel_p,
/* Generate the operand string in STR. */
aarch64_print_operand (str, sizeof (str), pc, opcode, opnds, i, &pcrel_p,
+ &info->target, ¬es);
/* Print the delimiter (taking account of omitted operand(s)). */
if (str[0] != '\0')
/* Print the delimiter (taking account of omitted operand(s)). */
if (str[0] != '\0')
else
(*info->fprintf_func) (info->stream, "%s", str);
}
else
(*info->fprintf_func) (info->stream, "%s", str);
}
+
+ if (notes && !no_notes)
+ (*info->fprintf_func) (info->stream, "\t; note: %s", notes);
}
/* Set NAME to a copy of INST's mnemonic with the "." suffix removed. */
}
/* Set NAME to a copy of INST's mnemonic with the "." suffix removed. */
fprintf (stream, _("\n\
aliases Do print instruction aliases.\n"));
fprintf (stream, _("\n\
aliases Do print instruction aliases.\n"));
+ fprintf (stream, _("\n\
+ no-notes Don't print instruction notes.\n"));
+
+ fprintf (stream, _("\n\
+ notes Do print instruction notes.\n"));
+
#ifdef DEBUG_AARCH64
fprintf (stream, _("\n\
debug_dump Temp switch for debug trace.\n"));
#ifdef DEBUG_AARCH64
fprintf (stream, _("\n\
debug_dump Temp switch for debug trace.\n"));
aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
const aarch64_opcode *opcode,
const aarch64_opnd_info *opnds, int idx, int *pcrel_p,
aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
const aarch64_opcode *opcode,
const aarch64_opnd_info *opnds, int idx, int *pcrel_p,
+ bfd_vma *address, char** notes ATTRIBUTE_UNUSED)
{
unsigned int i, num_conds;
const char *name = NULL;
{
unsigned int i, num_conds;
const char *name = NULL;