diff options
-rw-r--r-- | binutils/ChangeLog | 6 | ||||
-rw-r--r-- | binutils/NEWS | 8 | ||||
-rw-r--r-- | binutils/doc/binutils.texi | 5 | ||||
-rw-r--r-- | gas/ChangeLog | 8 | ||||
-rw-r--r-- | gas/config/tc-aarch64.c | 132 | ||||
-rw-r--r-- | include/ChangeLog | 6 | ||||
-rw-r--r-- | include/opcode/aarch64.h | 4 | ||||
-rw-r--r-- | opcodes/ChangeLog | 9 | ||||
-rw-r--r-- | opcodes/aarch64-dis.c | 27 | ||||
-rw-r--r-- | opcodes/aarch64-opc.c | 2 |
10 files changed, 152 insertions, 55 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 8120850..8f139a5 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,9 @@ +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, diff --git a/binutils/NEWS b/binutils/NEWS index da841de..d90d889 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -2,6 +2,14 @@ * 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 diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 3a32cc4..e4d32b6 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -2342,6 +2342,11 @@ using the switch @option{--disassembler-options=force-thumb}. This can be 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. diff --git a/gas/ChangeLog b/gas/ChangeLog index 60a00f0..84bba4b 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,6 +1,14 @@ 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 * config/tc-aarch64.c (parse_sys_reg): Return register flags. (parse_operands): Fill in register flags. diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 750025a..b007fb3 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -4533,7 +4533,8 @@ print_operands (char *buf, const aarch64_opcode *opcode, 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') @@ -4579,12 +4580,14 @@ output_operand_error_record (const operand_error_record *record, char *str) 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; - case AARCH64_OPDE_SYNTAX_ERROR: case AARCH64_OPDE_RECOVERABLE: case AARCH64_OPDE_FATAL_SYNTAX_ERROR: @@ -4594,21 +4597,21 @@ output_operand_error_record (const operand_error_record *record, char *str) if (detail->error != NULL) { if (idx < 0) - as_bad (_("%s -- `%s'"), detail->error, str); + handler (_("%s -- `%s'"), detail->error, str); else - 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); - 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: - 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 @@ -4705,36 +4708,36 @@ output_operand_error_record (const operand_error_record *record, char *str) 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]) - 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); else - 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) - 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); else - 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: - 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); break; default: @@ -4748,10 +4751,15 @@ output_operand_error_record (const operand_error_record *record, char *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 - 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. */ static void -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; @@ -4769,9 +4777,14 @@ output_operand_error_report (char *str) /* 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); + } return; } @@ -4791,7 +4804,10 @@ output_operand_error_report (char *str) 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 @@ -4807,6 +4823,17 @@ output_operand_error_report (char *str) } } + /* 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]); @@ -6352,18 +6379,18 @@ parse_operands (char *str, const aarch64_opcode *opcode) 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)) @@ -6689,15 +6716,15 @@ do_encode (const aarch64_opcode *opcode, aarch64_inst *instr, aarch64_insn *code) { aarch64_operand_error error_info; + memset (&error_info, '\0', sizeof (error_info)); 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) return TRUE; - 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; } #ifdef DEBUG_AARCH64 @@ -6834,6 +6861,9 @@ md_assemble (char *str) memcpy (copy, &inst.base, sizeof (struct aarch64_inst)); output_inst (copy); } + + /* Issue non-fatal messages if any. */ + output_operand_error_report (str, TRUE); return; } @@ -6847,7 +6877,7 @@ md_assemble (char *str) 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. */ diff --git a/include/ChangeLog b/include/ChangeLog index 8c3d5df..f9868a2 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,6 +1,12 @@ 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 * opcode/aarch64.h (aarch64_opnd_info): Change sysreg to struct. (aarch64_decode_insn): Accept error struct. diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index 7bc88c5..1c0013e 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -1101,6 +1101,7 @@ struct aarch64_operand_error int index; const char *error; int data[3]; /* Some data for extra information. */ + bfd_boolean non_fatal; }; typedef struct aarch64_operand_error aarch64_operand_error; @@ -1125,7 +1126,8 @@ aarch64_get_opcode (enum aarch64_op); /* 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. */ diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index a30e823..a9656a3 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,6 +1,15 @@ 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 * aarch64-asm.h (aarch64_insert_operand, aarch64_##x): Return boolean and take error struct. * aarch64-asm.c (aarch64_ext_regno, aarch64_ins_reglane, diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 5994b2b..ae53e49 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -46,7 +46,8 @@ static bfd_vma last_mapping_addr = 0; /* Other options */ static int no_aliases = 0; /* If set disassemble as most general inst. */ - +static 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) @@ -69,6 +70,18 @@ parse_aarch64_dis_option (const char *option, unsigned int len ATTRIBUTE_UNUSED) return; } + 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")) { @@ -2950,6 +2963,7 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode, const aarch64_opnd_info *opnds, struct disassemble_info *info) { int i, pcrel_p, num_printed; + char *notes = NULL; for (i = 0, num_printed = 0; i < AARCH64_MAX_OPND_NUM; ++i) { char str[128]; @@ -2964,7 +2978,7 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode, /* Generate the operand string in STR. */ aarch64_print_operand (str, sizeof (str), pc, opcode, opnds, i, &pcrel_p, - &info->target); + &info->target, ¬es); /* Print the delimiter (taking account of omitted operand(s)). */ if (str[0] != '\0') @@ -2977,6 +2991,9 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode, 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. */ @@ -3337,6 +3354,12 @@ with the -M switch (multiple options should be separated by commas):\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")); diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index c688b7c7..9d7f941 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -3033,7 +3033,7 @@ void 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) + bfd_vma *address, char** notes ATTRIBUTE_UNUSED) { unsigned int i, num_conds; const char *name = NULL; |