Coverage Report

Created: 2025-07-08 11:15

/src/binutils-gdb/opcodes/s390-dis.c
Line
Count
Source (jump to first uncovered line)
1
/* s390-dis.c -- Disassemble S390 instructions
2
   Copyright (C) 2000-2025 Free Software Foundation, Inc.
3
   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
4
5
   This file is part of the GNU opcodes library.
6
7
   This library is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3, or (at your option)
10
   any later version.
11
12
   It is distributed in the hope that it will be useful, but WITHOUT
13
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15
   License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this file; see the file COPYING.  If not, write to the
19
   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
22
#include "sysdep.h"
23
#include <stdio.h>
24
#include "ansidecl.h"
25
#include "disassemble.h"
26
#include "opintl.h"
27
#include "opcode/s390.h"
28
#include "libiberty.h"
29
#include "dis-asm.h"
30
31
static int opc_index[256];
32
static int current_arch_mask = 0;
33
static int option_use_insn_len_bits_p = 0;
34
static int option_print_insn_desc = 0;
35
36
typedef struct
37
{
38
  const char *name;
39
  const char *description;
40
} s390_options_t;
41
42
static const s390_options_t options[] =
43
{
44
  { "esa" ,       N_("Disassemble in ESA architecture mode") },
45
  /* TRANSLATORS: Please do not translate 'z/Architecture' as this is a technical name.  */
46
  { "zarch",      N_("Disassemble in z/Architecture mode") },
47
  { "insnlength", N_("Print unknown instructions according to "
48
         "length from first two bits") },
49
  { "insndesc",   N_("Print instruction description as comment") },
50
};
51
52
/* Set up index table for first opcode byte.  */
53
54
void
55
disassemble_init_s390 (struct disassemble_info *info)
56
207
{
57
207
  int i;
58
207
  const char *p;
59
60
207
  memset (opc_index, 0, sizeof (opc_index));
61
62
  /* Reverse order, such that each opc_index ends up pointing to the
63
     first matching entry instead of the last.  */
64
569k
  for (i = s390_num_opcodes; i--; )
65
568k
    opc_index[s390_opcodes[i].opcode[0]] = i;
66
67
207
  current_arch_mask = 1 << S390_OPCODE_ZARCH;
68
207
  option_use_insn_len_bits_p = 0;
69
207
  option_print_insn_desc = 0;
70
71
207
  for (p = info->disassembler_options; p != NULL; )
72
0
    {
73
0
      if (startswith (p, "esa"))
74
0
  current_arch_mask = 1 << S390_OPCODE_ESA;
75
0
      else if (startswith (p, "zarch"))
76
0
  current_arch_mask = 1 << S390_OPCODE_ZARCH;
77
0
      else if (startswith (p, "insnlength"))
78
0
  option_use_insn_len_bits_p = 1;
79
0
      else if (startswith (p, "insndesc"))
80
0
  option_print_insn_desc = 1;
81
0
      else
82
  /* xgettext:c-format */
83
0
  opcodes_error_handler (_("unknown S/390 disassembler option: %s"), p);
84
85
0
      p = strchr (p, ',');
86
0
      if (p != NULL)
87
0
  p++;
88
0
    }
89
207
}
90
91
/* Derive the length of an instruction from its first byte.  */
92
93
static inline int
94
s390_insn_length (const bfd_byte *buffer)
95
4.83M
{
96
  /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6.  */
97
4.83M
  return ((buffer[0] >> 6) + 3) & ~1U;
98
4.83M
}
99
100
/* Match the instruction in BUFFER against the given OPCODE, excluding
101
   the first byte.  */
102
103
static inline int
104
s390_insn_matches_opcode (const bfd_byte *buffer,
105
        const struct s390_opcode *opcode)
106
236M
{
107
236M
  return (buffer[1] & opcode->mask[1]) == opcode->opcode[1]
108
236M
    && (buffer[2] & opcode->mask[2]) == opcode->opcode[2]
109
236M
    && (buffer[3] & opcode->mask[3]) == opcode->opcode[3]
110
236M
    && (buffer[4] & opcode->mask[4]) == opcode->opcode[4]
111
236M
    && (buffer[5] & opcode->mask[5]) == opcode->opcode[5];
112
236M
}
113
114
union operand_value
115
{
116
  int i;
117
  unsigned int u;
118
};
119
120
/* Extracts an operand value from an instruction.  */
121
/* We do not perform the shift operation for larl-type address
122
   operands here since that would lead to an overflow of the 32 bit
123
   integer value.  Instead the shift operation is done when printing
124
   the operand.  */
125
126
static inline union operand_value
127
s390_extract_operand (const bfd_byte *insn,
128
          const struct s390_operand *operand)
129
9.75M
{
130
9.75M
  union operand_value ret;
131
9.75M
  unsigned int val;
132
9.75M
  int bits;
133
9.75M
  const bfd_byte *orig_insn = insn;
134
135
  /* Extract fragments of the operand byte for byte.  */
136
9.75M
  insn += operand->shift / 8;
137
9.75M
  bits = (operand->shift & 7) + operand->bits;
138
9.75M
  val = 0;
139
9.75M
  do
140
14.1M
    {
141
14.1M
      val <<= 8;
142
14.1M
      val |= (unsigned int) *insn++;
143
14.1M
      bits -= 8;
144
14.1M
    }
145
14.1M
  while (bits > 0);
146
9.75M
  val >>= -bits;
147
9.75M
  val &= ((1U << (operand->bits - 1)) << 1) - 1;
148
149
  /* Check for special long displacement case.  */
150
9.75M
  if (operand->bits == 20 && operand->shift == 20)
151
795
    val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
152
153
  /* Sign extend value if the operand is signed or pc relative.  Avoid
154
     integer overflows.  */
155
9.75M
  if (operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
156
1.01M
    {
157
1.01M
      unsigned int m = 1U << (operand->bits - 1);
158
159
1.01M
      if (val >= m)
160
365k
  ret.i = (int) (val - m) - 1 - (int) (m - 1U);
161
652k
      else
162
652k
  ret.i = (int) val;
163
1.01M
    }
164
8.73M
  else if (operand->flags & S390_OPERAND_LENGTH)
165
    /* Length x in an instruction has real length x + 1.  */
166
95.5k
    ret.u = val + 1;
167
168
8.64M
  else if (operand->flags & S390_OPERAND_VR)
169
1.22k
    {
170
      /* Extract the extra bits for a vector register operand stored
171
   in the RXB field.  */
172
1.22k
      unsigned vr = operand->shift == 32 ? 3
173
1.22k
  : (unsigned) operand->shift / 4 - 2;
174
175
1.22k
      ret.u = val | ((orig_insn[4] & (1 << (3 - vr))) << (vr + 1));
176
1.22k
    }
177
8.63M
  else
178
8.63M
    ret.u = val;
179
180
9.75M
  return ret;
181
9.75M
}
182
183
/* Return remaining operand count.  */
184
185
static unsigned int
186
operand_count (const unsigned char *opindex_ptr)
187
17.9k
{
188
17.9k
  unsigned int count = 0;
189
190
38.1k
  for (; *opindex_ptr != 0; opindex_ptr++)
191
20.1k
    {
192
      /* Count D(X,B), D(B), and D(L,B) as one operand.  Assuming correct
193
   instruction operand definitions simply do not count D, X, and L.  */
194
20.1k
      if (!(s390_operands[*opindex_ptr].flags & (S390_OPERAND_DISP
195
20.1k
            | S390_OPERAND_INDEX
196
20.1k
            | S390_OPERAND_LENGTH)))
197
18.4k
  count++;
198
20.1k
    }
199
200
17.9k
  return count;
201
17.9k
}
202
203
/* Return true if all remaining instruction operands are optional.  */
204
205
static bool
206
skip_optargs_p (unsigned int opcode_flags, const unsigned char *opindex_ptr)
207
6.06M
{
208
6.06M
  if ((opcode_flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2)))
209
17.9k
    {
210
17.9k
      unsigned int opcount = operand_count (opindex_ptr);
211
212
17.9k
      if (opcount == 1)
213
17.7k
  return true;
214
215
269
      if ((opcode_flags & S390_INSTR_FLAG_OPTPARM2) && opcount == 2)
216
19
  return true;
217
269
    }
218
219
6.04M
  return false;
220
6.06M
}
221
222
/* Return true if all remaining instruction operands are optional
223
   and their values are zero.  */
224
225
static bool
226
skip_optargs_zero_p (const bfd_byte *buffer, unsigned int opcode_flags,
227
         const unsigned char *opindex_ptr)
228
6.06M
{
229
  /* Test if remaining operands are optional.  */
230
6.06M
  if (!skip_optargs_p (opcode_flags, opindex_ptr))
231
6.04M
    return false;
232
233
  /* Test if remaining operand values are zero.  */
234
22.3k
  for (; *opindex_ptr != 0; opindex_ptr++)
235
18.4k
    {
236
18.4k
      const struct s390_operand *operand = &s390_operands[*opindex_ptr];
237
18.4k
      union operand_value value = s390_extract_operand (buffer, operand);
238
239
18.4k
      if (value.u != 0)
240
13.7k
  return false;
241
18.4k
    }
242
243
3.95k
  return true;
244
17.7k
}
245
246
/* Print the S390 instruction in BUFFER, assuming that it matches the
247
   given OPCODE.  */
248
249
static void
250
s390_print_insn_with_opcode (bfd_vma memaddr,
251
           struct disassemble_info *info,
252
           const bfd_byte *buffer,
253
           const struct s390_opcode *opcode)
254
3.20M
{
255
3.20M
  const unsigned char *opindex;
256
3.20M
  char separator;
257
258
  /* Mnemonic.  */
259
3.20M
  info->fprintf_styled_func (info->stream, dis_style_mnemonic,
260
3.20M
           "%s", opcode->name);
261
262
  /* Operands.  */
263
3.20M
  separator = '\t';
264
11.5M
  for (opindex = opcode->operands; *opindex != 0; opindex++)
265
8.30M
    {
266
8.30M
      const struct s390_operand *operand = s390_operands + *opindex;
267
8.30M
      union operand_value val = s390_extract_operand (buffer, operand);
268
8.30M
      unsigned long flags = operand->flags;
269
270
      /* Omit index register 0, except for vector index register 0.  */
271
8.30M
      if ((flags & S390_OPERAND_INDEX) && !(flags & S390_OPERAND_VR)
272
8.30M
    && val.u == 0)
273
485k
  continue;
274
      /* Omit base register 0, if no or omitted index register 0.  */
275
7.81M
      if ((flags & S390_OPERAND_BASE) && val.u == 0 && separator == '(')
276
109k
  {
277
109k
    separator = ',';
278
109k
    continue;
279
109k
  }
280
281
      /* Omit optional last operands with a value of zero, except if
282
   within an addressing operand sequence D(X,B), D(B), and D(L,B).
283
   Index and base register operands with a value of zero are
284
   handled separately, as they may not be omitted unconditionally.  */
285
7.70M
      if (!(operand->flags & (S390_OPERAND_BASE
286
7.70M
            | S390_OPERAND_INDEX
287
7.70M
            | S390_OPERAND_LENGTH))
288
7.70M
    && skip_optargs_zero_p (buffer, opcode->flags, opindex))
289
3.95k
  break;
290
291
7.70M
      if (flags & S390_OPERAND_GPR)
292
4.31M
  {
293
4.31M
    info->fprintf_styled_func (info->stream, dis_style_text,
294
4.31M
             "%c", separator);
295
4.31M
    if ((flags & (S390_OPERAND_BASE | S390_OPERAND_INDEX))
296
4.31M
        && val.u == 0)
297
70.2k
      info->fprintf_styled_func (info->stream, dis_style_register,
298
70.2k
               "%u", val.u);
299
4.24M
    else
300
4.24M
      info->fprintf_styled_func (info->stream, dis_style_register,
301
4.24M
               "%%r%u", val.u);
302
4.31M
  }
303
3.38M
      else if (flags & S390_OPERAND_FPR)
304
827k
  {
305
827k
    info->fprintf_styled_func (info->stream, dis_style_text,
306
827k
             "%c", separator);
307
827k
    info->fprintf_styled_func (info->stream, dis_style_register,
308
827k
             "%%f%u", val.u);
309
827k
  }
310
2.55M
      else if (flags & S390_OPERAND_VR)
311
1.22k
  {
312
1.22k
    info->fprintf_styled_func (info->stream, dis_style_text,
313
1.22k
             "%c", separator);
314
1.22k
    info->fprintf_styled_func (info->stream, dis_style_register,
315
1.22k
             "%%v%u", val.u);
316
1.22k
  }
317
2.55M
      else if (flags & S390_OPERAND_AR)
318
7.27k
  {
319
7.27k
    info->fprintf_styled_func (info->stream, dis_style_text,
320
7.27k
             "%c", separator);
321
7.27k
    info->fprintf_styled_func (info->stream, dis_style_register,
322
7.27k
             "%%a%u", val.u);
323
7.27k
  }
324
2.55M
      else if (flags & S390_OPERAND_CR)
325
4.62k
  {
326
4.62k
    info->fprintf_styled_func (info->stream, dis_style_text,
327
4.62k
             "%c", separator);
328
4.62k
    info->fprintf_styled_func (info->stream, dis_style_register,
329
4.62k
             "%%c%u", val.u);
330
4.62k
  }
331
2.54M
      else if (flags & S390_OPERAND_PCREL)
332
703k
  {
333
703k
    bfd_vma target = memaddr + val.i + val.i;
334
335
    /* Provide info for jump visualization.  May be evaluated by p_a_f().  */
336
703k
    info->target = target;
337
338
703k
    info->fprintf_styled_func (info->stream, dis_style_text,
339
703k
             "%c", separator);
340
703k
    info->print_address_func (target, info);
341
703k
  }
342
1.84M
      else if (flags & S390_OPERAND_SIGNED)
343
313k
  {
344
313k
    enum disassembler_style style;
345
346
313k
    info->fprintf_styled_func (info->stream, dis_style_text,
347
313k
             "%c", separator);
348
313k
    style = ((flags & S390_OPERAND_DISP)
349
313k
       ? dis_style_address_offset : dis_style_immediate);
350
313k
    info->fprintf_styled_func (info->stream, style, "%i", val.i);
351
313k
  }
352
1.52M
      else
353
1.52M
  {
354
1.52M
    enum disassembler_style style;
355
356
1.52M
    if (!(flags & S390_OPERAND_LENGTH))
357
1.43M
      {
358
1.43M
        union operand_value insn_opval;
359
360
        /* Mask any constant operand bits set in insn template.  */
361
1.43M
        insn_opval = s390_extract_operand (opcode->opcode, operand);
362
1.43M
        val.u &= ~insn_opval.u;
363
1.43M
      }
364
365
1.52M
    if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
366
1.52M
        && val.u == 0
367
1.52M
        && opindex[1] == 0)
368
0
      break;
369
370
1.52M
    info->fprintf_styled_func (info->stream, dis_style_text,
371
1.52M
             "%c", separator);
372
1.52M
    style = ((flags & S390_OPERAND_DISP)
373
1.52M
       ? dis_style_address_offset : dis_style_immediate);
374
1.52M
    info->fprintf_styled_func (info->stream, style, "%u", val.u);
375
1.52M
  }
376
377
7.70M
      if (flags & S390_OPERAND_DISP)
378
1.29M
  separator = '(';
379
6.40M
      else if (flags & S390_OPERAND_BASE)
380
1.18M
  {
381
1.18M
    info->fprintf_styled_func (info->stream, dis_style_text, ")");
382
1.18M
    separator = ',';
383
1.18M
  }
384
5.22M
      else
385
5.22M
  separator = ',';
386
7.70M
    }
387
388
  /* Optional: instruction name.  */
389
3.20M
  if (option_print_insn_desc && opcode->description
390
3.20M
      && opcode->description[0] != '\0')
391
0
    info->fprintf_styled_func (info->stream, dis_style_comment_start, "\t# %s",
392
0
             opcode->description);
393
3.20M
}
394
395
/* Check whether opcode A's mask is more specific than that of B.  */
396
397
static int
398
opcode_mask_more_specific (const struct s390_opcode *a,
399
         const struct s390_opcode *b)
400
2.11M
{
401
2.11M
  return (((int) a->mask[0] + a->mask[1] + a->mask[2]
402
2.11M
     + a->mask[3] + a->mask[4] + a->mask[5])
403
2.11M
    > ((int) b->mask[0] + b->mask[1] + b->mask[2]
404
2.11M
       + b->mask[3] + b->mask[4] + b->mask[5]));
405
2.11M
}
406
407
/* Print a S390 instruction.  */
408
409
int
410
print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
411
4.83M
{
412
4.83M
  bfd_byte buffer[6];
413
4.83M
  const struct s390_opcode *opcode = NULL;
414
4.83M
  unsigned int value;
415
4.83M
  int status, opsize, bufsize, bytes_to_dump, i;
416
417
  /* The output looks better if we put 6 bytes on a line.  */
418
4.83M
  info->bytes_per_line = 6;
419
420
  /* Set some defaults for the insn info.  */
421
4.83M
  info->insn_info_valid    = 0;
422
4.83M
  info->branch_delay_insns = 0;
423
4.83M
  info->data_size          = 0;
424
4.83M
  info->insn_type          = dis_nonbranch;
425
4.83M
  info->target             = 0;
426
4.83M
  info->target2            = 0;
427
428
  /* Every S390 instruction is max 6 bytes long.  */
429
4.83M
  memset (buffer, 0, 6);
430
4.83M
  status = info->read_memory_func (memaddr, buffer, 6, info);
431
4.83M
  if (status != 0)
432
676
    {
433
2.94k
      for (bufsize = 0; bufsize < 6; bufsize++)
434
2.94k
  if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
435
676
    break;
436
676
      if (bufsize <= 0)
437
1
  {
438
1
    info->memory_error_func (status, memaddr, info);
439
1
    return -1;
440
1
  }
441
675
      opsize = s390_insn_length (buffer);
442
675
      status = opsize > bufsize;
443
675
    }
444
4.83M
  else
445
4.83M
    {
446
4.83M
      bufsize = 6;
447
4.83M
      opsize = s390_insn_length (buffer);
448
4.83M
    }
449
450
4.83M
  if (status == 0)
451
4.83M
    {
452
4.83M
      const struct s390_opcode *op;
453
454
      /* Find the "best match" in the opcode table.  */
455
4.83M
      for (op = s390_opcodes + opc_index[buffer[0]];
456
241M
     op != s390_opcodes + s390_num_opcodes
457
241M
       && op->opcode[0] == buffer[0];
458
236M
     op++)
459
236M
  {
460
236M
    if ((op->modes & current_arch_mask)
461
236M
        && s390_insn_matches_opcode (buffer, op)
462
236M
        && (opcode == NULL
463
5.32M
      || opcode_mask_more_specific (op, opcode)))
464
3.56M
      opcode = op;
465
236M
  }
466
467
4.83M
      if (opcode != NULL)
468
3.20M
  {
469
    /* Provide info for jump visualization.  Must be done before print.  */
470
3.20M
    switch (opcode->flags & S390_INSTR_FLAG_CLASS_MASK)
471
3.20M
      {
472
106k
      case S390_INSTR_FLAGS_CLASS_JUMP:
473
106k
        info->insn_type = dis_branch;
474
106k
        break;
475
277k
      case S390_INSTR_FLAGS_CLASS_CONDJUMP:
476
277k
        info->insn_type = dis_condbranch;
477
277k
        break;
478
159k
      case S390_INSTR_FLAGS_CLASS_JUMPSR:
479
159k
        info->insn_type = dis_jsr;
480
159k
        break;
481
2.66M
      default:
482
2.66M
        info->insn_type = dis_nonbranch;
483
3.20M
      }
484
3.20M
    info->insn_info_valid = 1;
485
486
    /* The instruction is valid.  Print it and return its size.  */
487
3.20M
    s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
488
3.20M
    return opsize;
489
3.20M
  }
490
4.83M
    }
491
492
  /* For code sections it makes sense to skip unknown instructions
493
     according to their length bits.  */
494
1.62M
  if (status == 0
495
1.62M
      && option_use_insn_len_bits_p
496
1.62M
      && info->section != NULL
497
1.62M
      && (info->section->flags & SEC_CODE))
498
0
    bytes_to_dump = opsize;
499
1.62M
  else
500
    /* By default unknown instructions are printed as .long's/.short'
501
       depending on how many bytes are available.  */
502
1.62M
    bytes_to_dump = bufsize >= 4 ? 4 : bufsize;
503
504
1.62M
  if (bytes_to_dump == 0)
505
0
    return 0;
506
507
1.62M
  info->insn_type = dis_noninsn;
508
1.62M
  info->insn_info_valid = 1;
509
510
  /* Fall back to hex print.  */
511
1.62M
  switch (bytes_to_dump)
512
1.62M
    {
513
1.62M
    case 4:
514
1.62M
      value = (unsigned int) buffer[0];
515
1.62M
      value = (value << 8) + (unsigned int) buffer[1];
516
1.62M
      value = (value << 8) + (unsigned int) buffer[2];
517
1.62M
      value = (value << 8) + (unsigned int) buffer[3];
518
1.62M
      info->fprintf_styled_func (info->stream, dis_style_assembler_directive,
519
1.62M
         ".long");
520
1.62M
      info->fprintf_styled_func (info->stream, dis_style_text,
521
1.62M
         "\t");
522
1.62M
      info->fprintf_styled_func (info->stream, dis_style_immediate,
523
1.62M
         "0x%08x", value);
524
1.62M
      return 4;
525
79
    case 2:
526
79
      value = (unsigned int) buffer[0];
527
79
      value = (value << 8) + (unsigned int) buffer[1];
528
79
      info->fprintf_styled_func (info->stream, dis_style_assembler_directive,
529
79
         ".short");
530
79
      info->fprintf_styled_func (info->stream, dis_style_text,
531
79
         "\t");
532
79
      info->fprintf_styled_func (info->stream, dis_style_immediate,
533
79
         "0x%04x", value);
534
79
      return 2;
535
87
    default:
536
87
      info->fprintf_styled_func (info->stream, dis_style_assembler_directive,
537
87
         ".byte");
538
87
      info->fprintf_styled_func (info->stream, dis_style_text,
539
87
         "\t");
540
87
      info->fprintf_styled_func (info->stream, dis_style_immediate,
541
87
         "0x%02x", (unsigned int) buffer[0]);
542
169
      for (i = 1; i < bytes_to_dump; i++)
543
82
  info->fprintf_styled_func (info->stream, dis_style_immediate,
544
82
           "0x%02x", (unsigned int) buffer[i]);
545
87
      return bytes_to_dump;
546
1.62M
    }
547
0
  return 0;
548
1.62M
}
549
550
const disasm_options_and_args_t *
551
disassembler_options_s390 (void)
552
0
{
553
0
  static disasm_options_and_args_t *opts_and_args;
554
555
0
  if (opts_and_args == NULL)
556
0
    {
557
0
      size_t i, num_options = ARRAY_SIZE (options);
558
0
      disasm_options_t *opts;
559
560
0
      opts_and_args = XNEW (disasm_options_and_args_t);
561
0
      opts_and_args->args = NULL;
562
563
0
      opts = &opts_and_args->options;
564
0
      opts->name = XNEWVEC (const char *, num_options + 1);
565
0
      opts->description = XNEWVEC (const char *, num_options + 1);
566
0
      opts->arg = NULL;
567
0
      for (i = 0; i < num_options; i++)
568
0
  {
569
0
    opts->name[i] = options[i].name;
570
0
    opts->description[i] = _(options[i].description);
571
0
  }
572
      /* The array we return must be NULL terminated.  */
573
0
      opts->name[i] = NULL;
574
0
      opts->description[i] = NULL;
575
0
    }
576
577
0
  return opts_and_args;
578
0
}
579
580
void
581
print_s390_disassembler_options (FILE *stream)
582
0
{
583
0
  unsigned int i, max_len = 0;
584
0
  fprintf (stream, _("\n\
585
0
The following S/390 specific disassembler options are supported for use\n\
586
0
with the -M switch (multiple options should be separated by commas):\n"));
587
588
0
  for (i = 0; i < ARRAY_SIZE (options); i++)
589
0
    {
590
0
      unsigned int len = strlen (options[i].name);
591
0
      if (max_len < len)
592
0
  max_len = len;
593
0
    }
594
595
0
  for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
596
0
    fprintf (stream, "  %s%*c %s\n",
597
0
       options[i].name,
598
0
       (int)(max_len - strlen (options[i].name)), ' ',
599
0
       _(options[i].description));
600
0
}