aboutsummaryrefslogtreecommitdiff
path: root/opcodes/s390-dis.c
diff options
context:
space:
mode:
authorAndreas Krebbel <krebbel@linux.vnet.ibm.com>2016-06-10 13:40:48 +0200
committerAndreas Krebbel <krebbel@linux.vnet.ibm.com>2016-06-10 13:41:42 +0200
commitb2cc3f6fc2c5abc0a5ac7e0f2b5fb2365e89d33f (patch)
treee5950cf7b7c812bf74115738105a672c50c52d4b /opcodes/s390-dis.c
parent5e13cf25436bf72d851d81f132fcd49b0c636607 (diff)
downloadfsf-binutils-gdb-b2cc3f6fc2c5abc0a5ac7e0f2b5fb2365e89d33f.zip
fsf-binutils-gdb-b2cc3f6fc2c5abc0a5ac7e0f2b5fb2365e89d33f.tar.gz
fsf-binutils-gdb-b2cc3f6fc2c5abc0a5ac7e0f2b5fb2365e89d33f.tar.bz2
S/390: Dump unknown instructions according to their length.
Unknown instructions are currently just dumped as .long 1234. On S/390 we can do a bit better since the instruction length is encoded in the opcode. That way also unknown instructions can be skipped according to their real length. That way we can continue correctly after that instruction. However, there are also some drawbacks with that behavior when dumping data. So for now that behavior is only enabled for text section but even there it might mess things up when having a literal pool embedded in the code. Therefore I've left the feature disabled by default and have added the -Minsnlength option to enable it explicitely. opcodes/ChangeLog: 2016-06-10 Andreas Krebbel <krebbel@linux.vnet.ibm.com> * s390-dis.c (option_use_insn_len_bits_p): New file scope variable. (init_disasm): Handle new command line option "insnlength". (print_s390_disassembler_options): Mention new option in help output. (print_insn_s390): Use the encoded insn length when dumping unknown instructions.
Diffstat (limited to 'opcodes/s390-dis.c')
-rw-r--r--opcodes/s390-dis.c55
1 files changed, 38 insertions, 17 deletions
diff --git a/opcodes/s390-dis.c b/opcodes/s390-dis.c
index eeaeaf8..8134073 100644
--- a/opcodes/s390-dis.c
+++ b/opcodes/s390-dis.c
@@ -29,6 +29,7 @@
static int init_flag = 0;
static int opc_index[256];
static int current_arch_mask = 0;
+static int option_use_insn_len_bits_p = 0;
/* Set up index table for first opcode byte. */
@@ -51,6 +52,8 @@ init_disasm (struct disassemble_info *info)
current_arch_mask = 1 << S390_OPCODE_ESA;
else if (CONST_STRNEQ (p, "zarch"))
current_arch_mask = 1 << S390_OPCODE_ZARCH;
+ else if (CONST_STRNEQ (p, "insnlength"))
+ option_use_insn_len_bits_p = 1;
else
fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
@@ -261,7 +264,7 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
bfd_byte buffer[6];
const struct s390_opcode *opcode = NULL;
unsigned int value;
- int status, opsize, bufsize;
+ int status, opsize, bufsize, bytes_to_dump, i;
if (init_flag == 0)
init_disasm (info);
@@ -307,38 +310,54 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
|| opcode_mask_more_specific (op, opcode)))
opcode = op;
}
- }
- if (opcode != NULL)
- {
- /* The instruction is valid. Print it and return its size. */
- s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
- return opsize;
+ if (opcode != NULL)
+ {
+ /* The instruction is valid. Print it and return its size. */
+ s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
+ return opsize;
+ }
}
+ /* For code sections it makes sense to skip unknown instructions
+ according to their length bits. */
+ if (status == 0
+ && option_use_insn_len_bits_p
+ && info->section != NULL
+ && (info->section->flags & SEC_CODE))
+ bytes_to_dump = opsize;
+ else
+ /* By default unknown instructions are printed as .long's/.short'
+ depending on how many bytes are available. */
+ bytes_to_dump = bufsize >= 4 ? 4 : bufsize;
+
+ if (bytes_to_dump == 0)
+ return 0;
+
/* Fall back to hex print. */
- if (bufsize >= 4)
+ switch (bytes_to_dump)
{
+ case 4:
value = (unsigned int) buffer[0];
value = (value << 8) + (unsigned int) buffer[1];
value = (value << 8) + (unsigned int) buffer[2];
value = (value << 8) + (unsigned int) buffer[3];
info->fprintf_func (info->stream, ".long\t0x%08x", value);
return 4;
- }
- else if (bufsize >= 2)
- {
+ case 2:
value = (unsigned int) buffer[0];
value = (value << 8) + (unsigned int) buffer[1];
info->fprintf_func (info->stream, ".short\t0x%04x", value);
return 2;
+ default:
+ info->fprintf_func (info->stream, ".byte\t0x%02x",
+ (unsigned int) buffer[0]);
+ for (i = 1; i < bytes_to_dump; i++)
+ info->fprintf_func (info->stream, ",0x%02x",
+ (unsigned int) buffer[i]);
+ return bytes_to_dump;
}
- else
- {
- value = (unsigned int) buffer[0];
- info->fprintf_func (info->stream, ".byte\t0x%02x", value);
- return 1;
- }
+ return 0;
}
void
@@ -350,4 +369,6 @@ with the -M switch (multiple options should be separated by commas):\n"));
fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));
+ fprintf (stream, _(" insnlength Print unknown instructions according "
+ "to length from first two bits\n"));
}