Coverage Report

Created: 2025-07-12 06:44

/src/elfutils/libcpu/i386_disasm.c
Line
Count
Source (jump to first uncovered line)
1
/* Disassembler for x86.
2
   Copyright (C) 2007, 2008, 2009, 2011 Red Hat, Inc.
3
   This file is part of elfutils.
4
   Written by Ulrich Drepper <drepper@redhat.com>, 2007.
5
6
   This file is free software; you can redistribute it and/or modify
7
   it under the terms of either
8
9
     * the GNU Lesser General Public License as published by the Free
10
       Software Foundation; either version 3 of the License, or (at
11
       your option) any later version
12
13
   or
14
15
     * the GNU General Public License as published by the Free
16
       Software Foundation; either version 2 of the License, or (at
17
       your option) any later version
18
19
   or both in parallel, as here.
20
21
   elfutils is distributed in the hope that it will be useful, but
22
   WITHOUT ANY WARRANTY; without even the implied warranty of
23
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24
   General Public License for more details.
25
26
   You should have received copies of the GNU General Public License and
27
   the GNU Lesser General Public License along with this program.  If
28
   not, see <http://www.gnu.org/licenses/>.  */
29
30
#ifdef HAVE_CONFIG_H
31
# include <config.h>
32
#endif
33
34
#include <assert.h>
35
#include <config.h>
36
#include <ctype.h>
37
#include <errno.h>
38
#include <gelf.h>
39
#include <stddef.h>
40
#include <stdint.h>
41
#include <stdlib.h>
42
#include <string.h>
43
44
#include "libeblP.h"
45
46
#define MACHINE_ENCODING LITTLE_ENDIAN
47
#include "memory-access.h"
48
49
#include "i386_mne.h"
50
51
#define MNESTRFIELD(line) MNESTRFIELD1 (line)
52
#define MNESTRFIELD1(line) str##line
53
static const union mnestr_t
54
{
55
  struct
56
  {
57
#define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)];
58
#include MNEFILE
59
#undef MNE
60
  };
61
  char str[0];
62
} mnestr =
63
  {
64
    {
65
#define MNE(name) #name,
66
#include MNEFILE
67
#undef MNE
68
    }
69
  };
70
71
static const unsigned short int mneidx[] =
72
  {
73
#define MNE(name) \
74
  [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)),
75
#include MNEFILE
76
#undef MNE
77
  };
78
79
80
enum
81
  {
82
    idx_rex_b = 0,
83
    idx_rex_x,
84
    idx_rex_r,
85
    idx_rex_w,
86
    idx_rex,
87
    idx_cs,
88
    idx_ds,
89
    idx_es,
90
    idx_fs,
91
    idx_gs,
92
    idx_ss,
93
    idx_data16,
94
    idx_addr16,
95
    idx_rep,
96
    idx_repne,
97
    idx_lock
98
  };
99
100
enum
101
  {
102
#define prefbit(pref) has_##pref = 1 << idx_##pref
103
    prefbit (rex_b),
104
    prefbit (rex_x),
105
    prefbit (rex_r),
106
    prefbit (rex_w),
107
    prefbit (rex),
108
    prefbit (cs),
109
    prefbit (ds),
110
    prefbit (es),
111
    prefbit (fs),
112
    prefbit (gs),
113
    prefbit (ss),
114
    prefbit (data16),
115
    prefbit (addr16),
116
    prefbit (rep),
117
    prefbit (repne),
118
    prefbit (lock)
119
#undef prefbit
120
  };
121
#define SEGMENT_PREFIXES \
122
0
  (has_cs | has_ds | has_es | has_fs | has_gs | has_ss)
123
124
0
#define prefix_cs 0x2e
125
0
#define prefix_ds 0x3e
126
0
#define prefix_es 0x26
127
0
#define prefix_fs 0x64
128
0
#define prefix_gs 0x65
129
0
#define prefix_ss 0x36
130
0
#define prefix_data16 0x66
131
0
#define prefix_addr16 0x67
132
0
#define prefix_rep  0xf3
133
0
#define prefix_repne  0xf2
134
0
#define prefix_lock 0xf0
135
136
137
static const uint8_t known_prefixes[] =
138
  {
139
#define newpref(pref) [idx_##pref] = prefix_##pref
140
    newpref (cs),
141
    newpref (ds),
142
    newpref (es),
143
    newpref (fs),
144
    newpref (gs),
145
    newpref (ss),
146
    newpref (data16),
147
    newpref (addr16),
148
    newpref (rep),
149
    newpref (repne),
150
    newpref (lock)
151
#undef newpref
152
  };
153
0
#define nknown_prefixes (sizeof (known_prefixes) / sizeof (known_prefixes[0]))
154
155
156
#if 0
157
static const char *prefix_str[] =
158
  {
159
#define newpref(pref) [idx_##pref] = #pref
160
    newpref (cs),
161
    newpref (ds),
162
    newpref (es),
163
    newpref (fs),
164
    newpref (gs),
165
    newpref (ss),
166
    newpref (data16),
167
    newpref (addr16),
168
    newpref (rep),
169
    newpref (repne),
170
    newpref (lock)
171
#undef newpref
172
  };
173
#endif
174
175
176
static const char amd3dnowstr[] =
177
#define MNE_3DNOW_PAVGUSB 1
178
  "pavgusb\0"
179
#define MNE_3DNOW_PFADD (MNE_3DNOW_PAVGUSB + 8)
180
  "pfadd\0"
181
#define MNE_3DNOW_PFSUB (MNE_3DNOW_PFADD + 6)
182
  "pfsub\0"
183
#define MNE_3DNOW_PFSUBR (MNE_3DNOW_PFSUB + 6)
184
  "pfsubr\0"
185
#define MNE_3DNOW_PFACC (MNE_3DNOW_PFSUBR + 7)
186
  "pfacc\0"
187
#define MNE_3DNOW_PFCMPGE (MNE_3DNOW_PFACC + 6)
188
  "pfcmpge\0"
189
#define MNE_3DNOW_PFCMPGT (MNE_3DNOW_PFCMPGE + 8)
190
  "pfcmpgt\0"
191
#define MNE_3DNOW_PFCMPEQ (MNE_3DNOW_PFCMPGT + 8)
192
  "pfcmpeq\0"
193
#define MNE_3DNOW_PFMIN (MNE_3DNOW_PFCMPEQ + 8)
194
  "pfmin\0"
195
#define MNE_3DNOW_PFMAX (MNE_3DNOW_PFMIN + 6)
196
  "pfmax\0"
197
#define MNE_3DNOW_PI2FD (MNE_3DNOW_PFMAX + 6)
198
  "pi2fd\0"
199
#define MNE_3DNOW_PF2ID (MNE_3DNOW_PI2FD + 6)
200
  "pf2id\0"
201
#define MNE_3DNOW_PFRCP (MNE_3DNOW_PF2ID + 6)
202
  "pfrcp\0"
203
#define MNE_3DNOW_PFRSQRT (MNE_3DNOW_PFRCP + 6)
204
  "pfrsqrt\0"
205
#define MNE_3DNOW_PFMUL (MNE_3DNOW_PFRSQRT + 8)
206
  "pfmul\0"
207
#define MNE_3DNOW_PFRCPIT1 (MNE_3DNOW_PFMUL + 6)
208
  "pfrcpit1\0"
209
#define MNE_3DNOW_PFRSQIT1 (MNE_3DNOW_PFRCPIT1 + 9)
210
  "pfrsqit1\0"
211
#define MNE_3DNOW_PFRCPIT2 (MNE_3DNOW_PFRSQIT1 + 9)
212
  "pfrcpit2\0"
213
#define MNE_3DNOW_PMULHRW (MNE_3DNOW_PFRCPIT2 + 9)
214
  "pmulhrw";
215
216
0
#define AMD3DNOW_LOW_IDX 0x0d
217
0
#define AMD3DNOW_HIGH_IDX (sizeof (amd3dnow) + AMD3DNOW_LOW_IDX - 1)
218
0
#define AMD3DNOW_IDX(val) ((val) - AMD3DNOW_LOW_IDX)
219
static const unsigned char amd3dnow[] =
220
  {
221
    [AMD3DNOW_IDX (0xbf)] = MNE_3DNOW_PAVGUSB,
222
    [AMD3DNOW_IDX (0x9e)] = MNE_3DNOW_PFADD,
223
    [AMD3DNOW_IDX (0x9a)] = MNE_3DNOW_PFSUB,
224
    [AMD3DNOW_IDX (0xaa)] = MNE_3DNOW_PFSUBR,
225
    [AMD3DNOW_IDX (0xae)] = MNE_3DNOW_PFACC,
226
    [AMD3DNOW_IDX (0x90)] = MNE_3DNOW_PFCMPGE,
227
    [AMD3DNOW_IDX (0xa0)] = MNE_3DNOW_PFCMPGT,
228
    [AMD3DNOW_IDX (0xb0)] = MNE_3DNOW_PFCMPEQ,
229
    [AMD3DNOW_IDX (0x94)] = MNE_3DNOW_PFMIN,
230
    [AMD3DNOW_IDX (0xa4)] = MNE_3DNOW_PFMAX,
231
    [AMD3DNOW_IDX (0x0d)] = MNE_3DNOW_PI2FD,
232
    [AMD3DNOW_IDX (0x1d)] = MNE_3DNOW_PF2ID,
233
    [AMD3DNOW_IDX (0x96)] = MNE_3DNOW_PFRCP,
234
    [AMD3DNOW_IDX (0x97)] = MNE_3DNOW_PFRSQRT,
235
    [AMD3DNOW_IDX (0xb4)] = MNE_3DNOW_PFMUL,
236
    [AMD3DNOW_IDX (0xa6)] = MNE_3DNOW_PFRCPIT1,
237
    [AMD3DNOW_IDX (0xa7)] = MNE_3DNOW_PFRSQIT1,
238
    [AMD3DNOW_IDX (0xb6)] = MNE_3DNOW_PFRCPIT2,
239
    [AMD3DNOW_IDX (0xb7)] = MNE_3DNOW_PMULHRW
240
  };
241
242
243
struct output_data
244
{
245
  GElf_Addr addr;
246
  int *prefixes;
247
  size_t opoff1;
248
  size_t opoff2;
249
  size_t opoff3;
250
  char *bufp;
251
  size_t *bufcntp;
252
  size_t bufsize;
253
  const uint8_t *data;
254
  const uint8_t **param_start;
255
  const uint8_t *end;
256
  char *labelbuf;
257
  size_t labelbufsize;
258
  enum
259
    {
260
      addr_none = 0,
261
      addr_abs_symbolic,
262
      addr_abs_always,
263
      addr_rel_symbolic,
264
      addr_rel_always
265
    } symaddr_use;
266
  GElf_Addr symaddr;
267
};
268
269
270
#ifndef DISFILE
271
# define DISFILE "i386_dis.h"
272
#endif
273
#include DISFILE
274
275
276
#define ADD_CHAR(ch) \
277
0
  do {                       \
278
0
    if (unlikely (bufcnt == bufsize))               \
279
0
      goto enomem;                   \
280
0
    buf[bufcnt++] = (ch);                  \
281
0
  } while (0)
282
283
#define ADD_STRING(str) \
284
0
  do {                       \
285
0
    const char *_str0 = (str);                  \
286
0
    size_t _len0 = strlen (_str0);                \
287
0
    ADD_NSTRING (_str0, _len0);                  \
288
0
  } while (0)
289
290
#define ADD_NSTRING(str, len) \
291
0
  do {                       \
292
0
    const char *_str = (str);                 \
293
0
    size_t _len = (len);                  \
294
0
    if (unlikely (bufcnt + _len > bufsize))             \
295
0
      goto enomem;                   \
296
0
    memcpy (buf + bufcnt, _str, _len);                \
297
0
    bufcnt += _len;                   \
298
0
  } while (0)
299
300
301
int
302
i386_disasm (Ebl *ebl __attribute__((unused)),
303
       const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
304
       const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
305
       void *outcbarg, void *symcbarg)
306
0
{
307
0
  const char *save_fmt = fmt;
308
309
0
#define BUFSIZE 512
310
0
  char initbuf[BUFSIZE];
311
0
  int prefixes;
312
0
  size_t bufcnt;
313
0
  size_t bufsize = BUFSIZE;
314
0
  char *buf = initbuf;
315
0
  const uint8_t *param_start;
316
317
0
  struct output_data output_data =
318
0
    {
319
0
      .prefixes = &prefixes,
320
0
      .bufp = buf,
321
0
      .bufsize = bufsize,
322
0
      .bufcntp = &bufcnt,
323
0
      .param_start = &param_start,
324
0
      .end = end
325
0
    };
326
327
0
  int retval = 0;
328
0
  while (1)
329
0
    {
330
0
      prefixes = 0;
331
332
0
      const uint8_t *data = *startp;
333
0
      const uint8_t *begin = data;
334
335
      /* Recognize all prefixes.  */
336
0
      int last_prefix_bit = 0;
337
0
      while (data < end)
338
0
  {
339
0
    unsigned int i;
340
0
    for (i = idx_cs; i < nknown_prefixes; ++i)
341
0
      if (known_prefixes[i] == *data)
342
0
        break;
343
0
    if (i == nknown_prefixes)
344
0
      break;
345
346
0
    prefixes |= last_prefix_bit = 1 << i;
347
348
0
    ++data;
349
0
  }
350
351
#ifdef X86_64
352
0
      if (data < end && (*data & 0xf0) == 0x40)
353
0
  prefixes |= ((*data++) & 0xf) | has_rex;
354
#endif
355
356
0
      bufcnt = 0;
357
0
      size_t cnt = 0;
358
359
0
      const uint8_t *curr = match_data;
360
0
      const uint8_t *const match_end = match_data + sizeof (match_data);
361
362
0
      assert (data <= end);
363
0
      if (data == end)
364
0
  {
365
0
    if (prefixes != 0)
366
0
      goto print_prefix;
367
368
0
    retval = -1;
369
0
    goto do_ret;
370
0
  }
371
372
0
    next_match:
373
0
      while (curr < match_end)
374
0
  {
375
0
    uint_fast8_t len = *curr++;
376
0
    uint_fast8_t clen = len >> 4;
377
0
    len &= 0xf;
378
0
    const uint8_t *next_curr = curr + clen + (len - clen) * 2;
379
380
0
    assert (len > 0);
381
0
    assert (curr + clen + 2 * (len - clen) <= match_end);
382
383
0
    const uint8_t *codep = data;
384
0
    int correct_prefix = 0;
385
0
    int opoff = 0;
386
387
0
    if (data > begin && codep[-1] == *curr && clen > 0)
388
0
      {
389
        /* We match a prefix byte.  This is exactly one byte and
390
     is matched exactly, without a mask.  */
391
0
        --len;
392
0
        --clen;
393
0
        opoff = 8;
394
395
0
        ++curr;
396
397
0
        if (last_prefix_bit == 0)
398
0
    goto invalid_op;
399
0
        correct_prefix = last_prefix_bit;
400
0
      }
401
402
0
    size_t avail = len;
403
0
    while (clen > 0)
404
0
      {
405
0
        if (*codep++ != *curr++)
406
0
    goto not;
407
0
        --avail;
408
0
        --clen;
409
0
        if (codep == end && avail > 0)
410
0
    goto do_ret;
411
0
      }
412
413
0
    while (avail > 0)
414
0
      {
415
0
        uint_fast8_t masked = *codep++ & *curr++;
416
0
        if (masked != *curr++)
417
0
    {
418
0
    not:
419
0
      curr = next_curr;
420
0
      ++cnt;
421
0
      bufcnt = 0;
422
0
      goto next_match;
423
0
    }
424
425
0
        --avail;
426
0
        if (codep == end && avail > 0)
427
0
    goto do_ret;
428
0
      }
429
430
0
    if (len > end - data)
431
      /* There is not enough data for the entire instruction.  The
432
         caller can figure this out by looking at the pointer into
433
         the input data.  */
434
0
      goto do_ret;
435
436
0
    if (correct_prefix != 0 && (prefixes & correct_prefix) == 0)
437
0
      goto invalid_op;
438
0
    prefixes ^= correct_prefix;
439
440
0
    if (0)
441
0
      {
442
        /* Resize the buffer.  */
443
0
        char *oldbuf;
444
0
      enomem:
445
0
        oldbuf = buf;
446
0
        if (buf == initbuf)
447
0
    buf = malloc (2 * bufsize);
448
0
        else
449
0
    buf = realloc (buf, 2 * bufsize);
450
0
        if (buf == NULL)
451
0
    {
452
0
      buf = oldbuf;
453
0
      retval = ENOMEM;
454
0
      goto do_ret;
455
0
    }
456
0
        bufsize *= 2;
457
458
0
        output_data.bufp = buf;
459
0
        output_data.bufsize = bufsize;
460
0
        bufcnt = 0;
461
462
0
        if (data == end)
463
0
    {
464
0
      if (prefixes == 0)
465
0
        goto invalid_op;
466
0
      goto print_prefix;
467
0
    }
468
469
        /* gcc is not clever enough to see the following variables
470
     are not used uninitialized.  */
471
0
        __asm (""
472
0
         : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
473
0
         "=mr" (next_curr), "=mr" (len));
474
0
      }
475
476
0
    size_t prefix_size = 0;
477
478
    // XXXonly print as prefix if valid?
479
0
    if ((prefixes & has_lock) != 0)
480
0
      {
481
0
        ADD_STRING ("lock ");
482
0
        prefix_size += 5;
483
0
      }
484
485
0
    if (instrtab[cnt].rep)
486
0
      {
487
0
        if ((prefixes & has_rep) !=  0)
488
0
    {
489
0
      ADD_STRING ("rep ");
490
0
      prefix_size += 4;
491
0
    }
492
0
      }
493
0
    else if (instrtab[cnt].repe
494
0
       && (prefixes & (has_rep | has_repne)) != 0)
495
0
      {
496
0
        if ((prefixes & has_repne) != 0)
497
0
    {
498
0
      ADD_STRING ("repne ");
499
0
      prefix_size += 6;
500
0
    }
501
0
        else if ((prefixes & has_rep) != 0)
502
0
    {
503
0
      ADD_STRING ("repe ");
504
0
      prefix_size += 5;
505
0
    }
506
0
      }
507
0
    else if ((prefixes & (has_rep | has_repne)) != 0)
508
0
      {
509
0
        uint_fast8_t byte;
510
0
      print_prefix:
511
0
        bufcnt = 0;
512
0
        byte = *begin;
513
        /* This is a prefix byte.  Print it.  */
514
0
        switch (byte)
515
0
    {
516
0
    case prefix_rep:
517
0
      ADD_STRING ("rep");
518
0
      break;
519
0
    case prefix_repne:
520
0
      ADD_STRING ("repne");
521
0
      break;
522
0
    case prefix_cs:
523
0
      ADD_STRING ("cs");
524
0
      break;
525
0
    case prefix_ds:
526
0
      ADD_STRING ("ds");
527
0
      break;
528
0
    case prefix_es:
529
0
      ADD_STRING ("es");
530
0
      break;
531
0
    case prefix_fs:
532
0
      ADD_STRING ("fs");
533
0
      break;
534
0
    case prefix_gs:
535
0
      ADD_STRING ("gs");
536
0
      break;
537
0
    case prefix_ss:
538
0
      ADD_STRING ("ss");
539
0
      break;
540
0
    case prefix_data16:
541
0
      ADD_STRING ("data16");
542
0
      break;
543
0
    case prefix_addr16:
544
0
      ADD_STRING ("addr16");
545
0
      break;
546
0
    case prefix_lock:
547
0
      ADD_STRING ("lock");
548
0
      break;
549
#ifdef X86_64
550
0
    case 0x40 ... 0x4f:
551
0
      ADD_STRING ("rex");
552
0
      if (byte != 0x40)
553
0
        {
554
0
          ADD_CHAR ('.');
555
0
          if (byte & 0x8)
556
0
      ADD_CHAR ('w');
557
0
          if (byte & 0x4)
558
0
      ADD_CHAR ('r');
559
0
          if (byte & 0x3)
560
0
      ADD_CHAR ('x');
561
0
          if (byte & 0x1)
562
0
      ADD_CHAR ('b');
563
0
        }
564
0
      break;
565
0
#endif
566
0
    default:
567
      /* Cannot happen.  */
568
0
      puts ("unknown prefix");
569
0
      abort ();
570
0
    }
571
0
        data = begin + 1;
572
0
        ++addr;
573
574
0
        goto out;
575
0
      }
576
577
    /* We have a match.  First determine how many bytes are
578
       needed for the addressing mode.  */
579
0
    param_start = codep;
580
0
    if (instrtab[cnt].modrm)
581
0
      {
582
0
        uint_fast8_t modrm = codep[-1];
583
584
#ifndef X86_64
585
0
        if (likely ((prefixes & has_addr16) != 0))
586
0
    {
587
      /* Account for displacement.  */
588
0
      if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
589
0
        param_start += 2;
590
0
      else if ((modrm & 0xc0) == 0x40)
591
0
        param_start += 1;
592
0
    }
593
0
        else
594
0
#endif
595
0
    {
596
      /* Account for SIB.  */
597
0
      if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
598
0
        param_start += 1;
599
600
      /* Account for displacement.  */
601
0
      if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
602
0
          || ((modrm & 0xc7) == 0x4
603
0
        && param_start < end
604
0
        && (codep[0] & 0x7) == 0x5))
605
0
        param_start += 4;
606
0
      else if ((modrm & 0xc0) == 0x40)
607
0
        param_start += 1;
608
0
    }
609
610
0
        if (unlikely (param_start > end))
611
0
    goto not;
612
0
      }
613
614
0
    output_data.addr = addr + (data - begin);
615
0
    output_data.data = data;
616
617
0
    unsigned long string_end_idx = 0;
618
0
    fmt = save_fmt;
619
0
    const char *deferred_start = NULL;
620
0
    size_t deferred_len = 0;
621
    // XXX Can we get this from color.c?
622
0
    static const char color_off[] = "\e[0m";
623
0
    while (*fmt != '\0')
624
0
      {
625
0
        if (*fmt != '%')
626
0
    {
627
0
      char ch = *fmt++;
628
0
      if (ch == '\\')
629
0
        {
630
0
          switch ((ch = *fmt++))
631
0
      {
632
0
      case '0' ... '7':
633
0
        {
634
0
          int val = ch - '0';
635
0
          ch = *fmt;
636
0
          if (ch >= '0' && ch <= '7')
637
0
            {
638
0
        val *= 8;
639
0
        val += ch - '0';
640
0
        ch = *++fmt;
641
0
        if (ch >= '0' && ch <= '7' && val < 32)
642
0
          {
643
0
            val *= 8;
644
0
            val += ch - '0';
645
0
            ++fmt;
646
0
          }
647
0
            }
648
0
          ch = val;
649
0
        }
650
0
        break;
651
652
0
      case 'n':
653
0
        ch = '\n';
654
0
        break;
655
656
0
      case 't':
657
0
        ch = '\t';
658
0
        break;
659
660
0
      default:
661
0
        retval = EINVAL;
662
0
        goto do_ret;
663
0
      }
664
0
        }
665
0
      else if (ch == '\e' && *fmt == '[')
666
0
        {
667
0
          deferred_start = fmt - 1;
668
0
          do
669
0
      ++fmt;
670
0
          while (*fmt != 'm' && *fmt != '\0');
671
672
0
          if (*fmt == 'm')
673
0
      {
674
0
        deferred_len = ++fmt - deferred_start;
675
0
        continue;
676
0
      }
677
678
0
          fmt = deferred_start + 1;
679
0
          deferred_start = NULL;
680
0
        }
681
0
      ADD_CHAR (ch);
682
0
      continue;
683
0
    }
684
0
        ++fmt;
685
686
0
        int width = 0;
687
0
        while (isdigit (*fmt))
688
0
    width = width * 10 + (*fmt++ - '0');
689
690
0
        int prec = 0;
691
0
        if (*fmt == '.')
692
0
    while (isdigit (*++fmt))
693
0
      prec = prec * 10 + (*fmt - '0');
694
695
0
        size_t start_idx = bufcnt;
696
0
        size_t non_printing = 0;
697
0
        switch (*fmt++)
698
0
    {
699
0
      char mnebuf[16];
700
0
      const char *str;
701
702
0
    case 'm':
703
      /* Mnemonic.  */
704
705
0
      if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
706
0
        {
707
0
          switch (*data)
708
0
      {
709
#ifdef X86_64
710
0
      case 0x90:
711
0
        if (prefixes & has_rex_b)
712
0
          goto not;
713
0
        str = "nop";
714
0
        break;
715
0
#endif
716
717
0
      case 0x98:
718
#ifdef X86_64
719
0
        if (prefixes == (has_rex_w | has_rex))
720
0
          {
721
0
            str = "cltq";
722
0
            break;
723
0
          }
724
0
#endif
725
0
        if (prefixes & ~has_data16)
726
0
          goto print_prefix;
727
0
        str = prefixes & has_data16 ? "cbtw" : "cwtl";
728
0
        break;
729
730
0
      case 0x99:
731
#ifdef X86_64
732
0
        if (prefixes == (has_rex_w | has_rex))
733
0
          {
734
0
            str = "cqto";
735
0
            break;
736
0
          }
737
0
#endif
738
0
        if (prefixes & ~has_data16)
739
0
          goto print_prefix;
740
0
        str = prefixes & has_data16 ? "cwtd" : "cltd";
741
0
        break;
742
743
0
      case 0xe3:
744
0
        if (prefixes & ~has_addr16)
745
0
          goto print_prefix;
746
#ifdef X86_64
747
0
        str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
748
#else
749
0
        str = prefixes & has_addr16 ? "jcxz" : "jecxz";
750
#endif
751
0
        break;
752
753
0
      case 0x0f:
754
0
        if (data[1] == 0x0f)
755
0
          {
756
            /* AMD 3DNOW.  We need one more byte.  */
757
0
            if (param_start >= end)
758
0
        goto not;
759
0
            if (*param_start < AMD3DNOW_LOW_IDX
760
0
          || *param_start > AMD3DNOW_HIGH_IDX)
761
0
        goto not;
762
0
            unsigned int idx
763
0
        = amd3dnow[AMD3DNOW_IDX (*param_start)];
764
0
            if (idx == 0)
765
0
        goto not;
766
0
            str = amd3dnowstr + idx - 1;
767
            /* Eat the immediate byte indicating the
768
         operation.  */
769
0
            ++param_start;
770
0
            break;
771
0
          }
772
#ifdef X86_64
773
0
        if (data[1] == 0xc7)
774
0
          {
775
0
            str = ((prefixes & has_rex_w)
776
0
             ? "cmpxchg16b" : "cmpxchg8b");
777
0
            break;
778
0
          }
779
0
#endif
780
0
        if (data[1] == 0xc2)
781
0
          {
782
0
            if (param_start >= end)
783
0
        goto not;
784
0
            if (*param_start > 7)
785
0
        goto not;
786
0
            static const char cmpops[][9] =
787
0
        {
788
0
          [0] = "cmpeq",
789
0
          [1] = "cmplt",
790
0
          [2] = "cmple",
791
0
          [3] = "cmpunord",
792
0
          [4] = "cmpneq",
793
0
          [5] = "cmpnlt",
794
0
          [6] = "cmpnle",
795
0
          [7] = "cmpord"
796
0
        };
797
0
            char *cp = stpcpy (mnebuf, cmpops[*param_start]);
798
0
            if (correct_prefix & (has_rep | has_repne))
799
0
        *cp++ = 's';
800
0
            else
801
0
        *cp++ = 'p';
802
0
            if (correct_prefix & (has_data16 | has_repne))
803
0
        *cp++ = 'd';
804
0
            else
805
0
        *cp++ = 's';
806
0
            *cp = '\0';
807
0
            str = mnebuf;
808
            /* Eat the immediate byte indicating the
809
         operation.  */
810
0
            ++param_start;
811
0
            break;
812
0
          }
813
0
        FALLTHROUGH;
814
0
      default:
815
0
        str = "INVALID not handled";
816
0
        break;
817
0
      }
818
0
        }
819
0
      else
820
0
        str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
821
822
0
      if (deferred_start != NULL)
823
0
        {
824
0
          ADD_NSTRING (deferred_start, deferred_len);
825
0
          non_printing += deferred_len;
826
0
        }
827
828
0
      ADD_STRING (str);
829
830
0
      switch (instrtab[cnt].suffix)
831
0
        {
832
0
        case suffix_none:
833
0
          break;
834
835
0
        case suffix_w:
836
0
          if ((codep[-1] & 0xc0) != 0xc0)
837
0
      {
838
0
        char ch;
839
840
0
        if (data[0] & 1)
841
0
          {
842
0
            if (prefixes & has_data16)
843
0
        ch = 'w';
844
#ifdef X86_64
845
0
            else if (prefixes & has_rex_w)
846
0
        ch = 'q';
847
0
#endif
848
0
            else
849
0
        ch = 'l';
850
0
          }
851
0
        else
852
0
          ch = 'b';
853
854
0
        ADD_CHAR (ch);
855
0
      }
856
0
          break;
857
858
0
        case suffix_w0:
859
0
          if ((codep[-1] & 0xc0) != 0xc0)
860
0
      ADD_CHAR ('l');
861
0
          break;
862
863
0
        case suffix_w1:
864
0
          if ((data[0] & 0x4) == 0)
865
0
      ADD_CHAR ('l');
866
0
          break;
867
868
0
        case suffix_W:
869
0
          if (prefixes & has_data16)
870
0
      {
871
0
        ADD_CHAR ('w');
872
0
        prefixes &= ~has_data16;
873
0
      }
874
#ifdef X86_64
875
          else
876
0
      ADD_CHAR ('q');
877
0
#endif
878
0
          break;
879
880
0
        case suffix_W1:
881
0
          if (prefixes & has_data16)
882
0
      {
883
0
        ADD_CHAR ('w');
884
0
        prefixes &= ~has_data16;
885
0
      }
886
#ifdef X86_64
887
0
          else if (prefixes & has_rex_w)
888
0
      ADD_CHAR ('q');
889
0
#endif
890
0
          break;
891
892
0
        case suffix_tttn:;
893
0
          static const char tttn[16][3] =
894
0
      {
895
0
        "o", "no", "b", "ae", "e", "ne", "be", "a",
896
0
        "s", "ns", "p", "np", "l", "ge", "le", "g"
897
0
      };
898
0
          ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
899
0
          break;
900
901
0
        case suffix_D:
902
0
          if ((codep[-1] & 0xc0) != 0xc0)
903
0
      ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
904
0
          break;
905
906
0
        default:
907
0
          printf("unknown suffix %d\n", instrtab[cnt].suffix);
908
0
          abort ();
909
0
        }
910
911
0
      if (deferred_start != NULL)
912
0
        {
913
0
          ADD_STRING (color_off);
914
0
          non_printing += strlen (color_off);
915
0
        }
916
917
0
      string_end_idx = bufcnt;
918
0
      break;
919
920
0
    case 'o':
921
0
      if (prec == 1 && instrtab[cnt].fct1 != 0)
922
0
        {
923
          /* First parameter.  */
924
0
          if (deferred_start != NULL)
925
0
      {
926
0
        ADD_NSTRING (deferred_start, deferred_len);
927
0
        non_printing += deferred_len;
928
0
      }
929
930
0
          if (instrtab[cnt].str1 != 0)
931
0
      ADD_STRING (op1_str
932
0
            + op1_str_idx[instrtab[cnt].str1 - 1]);
933
934
0
          output_data.opoff1 = (instrtab[cnt].off1_1
935
0
              + OFF1_1_BIAS - opoff);
936
0
          output_data.opoff2 = (instrtab[cnt].off1_2
937
0
              + OFF1_2_BIAS - opoff);
938
0
          output_data.opoff3 = (instrtab[cnt].off1_3
939
0
              + OFF1_3_BIAS - opoff);
940
0
          int r = op1_fct[instrtab[cnt].fct1] (&output_data);
941
0
          if (r < 0)
942
0
      goto not;
943
0
          if (r > 0)
944
0
      goto enomem;
945
946
0
          if (deferred_start != NULL)
947
0
      {
948
0
        ADD_STRING (color_off);
949
0
        non_printing += strlen (color_off);
950
0
      }
951
952
0
          string_end_idx = bufcnt;
953
0
        }
954
0
      else if (prec == 2 && instrtab[cnt].fct2 != 0)
955
0
        {
956
          /* Second parameter.  */
957
0
          if (deferred_start != NULL)
958
0
      {
959
0
        ADD_NSTRING (deferred_start, deferred_len);
960
0
        non_printing += deferred_len;
961
0
      }
962
963
0
          if (instrtab[cnt].str2 != 0)
964
0
      ADD_STRING (op2_str
965
0
            + op2_str_idx[instrtab[cnt].str2 - 1]);
966
967
0
          output_data.opoff1 = (instrtab[cnt].off2_1
968
0
              + OFF2_1_BIAS - opoff);
969
0
          output_data.opoff2 = (instrtab[cnt].off2_2
970
0
              + OFF2_2_BIAS - opoff);
971
0
          output_data.opoff3 = (instrtab[cnt].off2_3
972
0
              + OFF2_3_BIAS - opoff);
973
0
          int r = op2_fct[instrtab[cnt].fct2] (&output_data);
974
0
          if (r < 0)
975
0
      goto not;
976
0
          if (r > 0)
977
0
      goto enomem;
978
979
0
          if (deferred_start != NULL)
980
0
      {
981
0
        ADD_STRING (color_off);
982
0
        non_printing += strlen (color_off);
983
0
      }
984
985
0
          string_end_idx = bufcnt;
986
0
        }
987
0
      else if (prec == 3 && instrtab[cnt].fct3 != 0)
988
0
        {
989
          /* Third parameter.  */
990
0
          if (deferred_start != NULL)
991
0
      {
992
0
        ADD_NSTRING (deferred_start, deferred_len);
993
0
        non_printing += deferred_len;
994
0
      }
995
996
0
          if (instrtab[cnt].str3 != 0)
997
0
      ADD_STRING (op3_str
998
0
            + op3_str_idx[instrtab[cnt].str3 - 1]);
999
1000
0
          output_data.opoff1 = (instrtab[cnt].off3_1
1001
0
              + OFF3_1_BIAS - opoff);
1002
0
          output_data.opoff2 = (instrtab[cnt].off3_2
1003
0
              + OFF3_2_BIAS - opoff);
1004
#ifdef OFF3_3_BITS
1005
          output_data.opoff3 = (instrtab[cnt].off3_3
1006
              + OFF3_3_BIAS - opoff);
1007
#else
1008
0
          output_data.opoff3 = 0;
1009
0
#endif
1010
0
          int r = op3_fct[instrtab[cnt].fct3] (&output_data);
1011
0
          if (r < 0)
1012
0
      goto not;
1013
0
          if (r > 0)
1014
0
      goto enomem;
1015
1016
0
          if (deferred_start != NULL)
1017
0
      {
1018
0
        ADD_STRING (color_off);
1019
0
        non_printing += strlen (color_off);
1020
0
      }
1021
1022
0
          string_end_idx = bufcnt;
1023
0
        }
1024
0
      else
1025
0
        start_idx = bufcnt = string_end_idx;
1026
0
      break;
1027
1028
0
    case 'e':
1029
0
      string_end_idx = bufcnt;
1030
0
      break;
1031
1032
0
    case 'a':
1033
      /* Pad to requested column.  */
1034
0
      while (bufcnt - non_printing < (size_t) width)
1035
0
        ADD_CHAR (' ');
1036
0
      width = 0;
1037
0
      break;
1038
1039
0
    case 'l':
1040
0
      if (deferred_start != NULL)
1041
0
        {
1042
0
          ADD_NSTRING (deferred_start, deferred_len);
1043
0
          non_printing += deferred_len;
1044
0
        }
1045
1046
0
      if (output_data.labelbuf != NULL
1047
0
          && output_data.labelbuf[0] != '\0')
1048
0
        {
1049
0
          ADD_STRING (output_data.labelbuf);
1050
0
          output_data.labelbuf[0] = '\0';
1051
0
          string_end_idx = bufcnt;
1052
0
        }
1053
0
      else if (output_data.symaddr_use != addr_none)
1054
0
        {
1055
0
          GElf_Addr symaddr = output_data.symaddr;
1056
0
          if (output_data.symaddr_use >= addr_rel_symbolic)
1057
0
      symaddr += addr + param_start - begin;
1058
1059
          // XXX Lookup symbol based on symaddr
1060
0
          const char *symstr = NULL;
1061
0
          if (symcb != NULL
1062
0
        && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
1063
0
            &output_data.labelbuf,
1064
0
            &output_data.labelbufsize, symcbarg) == 0)
1065
0
      symstr = output_data.labelbuf;
1066
1067
0
          size_t bufavail = bufsize - bufcnt;
1068
0
          int r = 0;
1069
0
          if (symstr != NULL)
1070
0
      r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
1071
0
              symstr);
1072
0
          else if (output_data.symaddr_use == addr_abs_always
1073
0
             || output_data.symaddr_use == addr_rel_always)
1074
0
      r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
1075
0
              (uint64_t) symaddr);
1076
1077
0
          assert (r >= 0);
1078
0
          if ((size_t) r >= bufavail)
1079
0
      goto enomem;
1080
0
          bufcnt += r;
1081
0
          string_end_idx = bufcnt;
1082
1083
0
          output_data.symaddr_use = addr_none;
1084
0
        }
1085
0
      if (deferred_start != NULL)
1086
0
        {
1087
0
          ADD_STRING (color_off);
1088
0
          non_printing += strlen (color_off);
1089
0
        }
1090
0
      break;
1091
1092
0
    default:
1093
0
      abort ();
1094
0
    }
1095
1096
0
        deferred_start = NULL;
1097
1098
        /* Pad according to the specified width.  */
1099
0
        while (bufcnt + prefix_size - non_printing < start_idx + width)
1100
0
    ADD_CHAR (' ');
1101
0
        prefix_size = 0;
1102
0
      }
1103
1104
0
    if ((prefixes & SEGMENT_PREFIXES) != 0)
1105
0
      goto print_prefix;
1106
1107
0
    assert (string_end_idx != ~0ul);
1108
0
    bufcnt = string_end_idx;
1109
1110
0
    addr += param_start - begin;
1111
0
    data = param_start;
1112
1113
0
    goto out;
1114
0
  }
1115
1116
      /* Invalid (or at least unhandled) opcode.  */
1117
0
    invalid_op:
1118
0
      if (prefixes != 0)
1119
0
  goto print_prefix;
1120
      /* Make sure we get past the unrecognized opcode if we haven't yet.  */
1121
0
      if (*startp == data)
1122
0
  ++data;
1123
0
      ADD_STRING ("(bad)");
1124
0
      addr += data - begin;
1125
1126
0
    out:
1127
0
      if (bufcnt == bufsize)
1128
0
  goto enomem;
1129
0
      buf[bufcnt] = '\0';
1130
1131
0
      *startp = data;
1132
0
      retval = outcb (buf, bufcnt, outcbarg);
1133
0
      if (retval != 0)
1134
0
  goto do_ret;
1135
0
    }
1136
1137
0
 do_ret:
1138
0
  free (output_data.labelbuf);
1139
0
  if (buf != initbuf)
1140
0
    free (buf);
1141
1142
0
  return retval;
1143
0
}
Unexecuted instantiation: i386_disasm
Unexecuted instantiation: x86_64_disasm