diff options
Diffstat (limited to 'opcodes/s390-dis.c')
-rw-r--r-- | opcodes/s390-dis.c | 55 |
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")); } |