blob: c6bb0a584f80b39e55da256f2a34dd338bac2534 [file] [log] [blame]
Ulrich Drepper515d8d72008-01-03 07:41:03 +00001/* Disassembler for x86.
Ulrich Drepper92287fd2009-01-01 20:18:48 -08002 Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
Ulrich Drepper515d8d72008-01-03 07:41:03 +00003 This file is part of Red Hat elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2007.
5
6 Red Hat elfutils is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 2 of the License.
9
10 Red Hat elfutils is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with Red Hat elfutils; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18
19 Red Hat elfutils is an included package of the Open Invention Network.
20 An included package of the Open Invention Network is a package for which
21 Open Invention Network licensees cross-license their patents. No patent
22 license is granted, either expressly or impliedly, by designation as an
23 included package. Should you wish to participate in the Open Invention
24 Network licensing program, please visit www.openinventionnetwork.com
25 <http://www.openinventionnetwork.com>. */
26
27#ifdef HAVE_CONFIG_H
28# include <config.h>
29#endif
30
Ulrich Drepper3cbdd382008-01-02 17:44:39 +000031#include <assert.h>
32#include <config.h>
33#include <ctype.h>
34#include <endian.h>
35#include <errno.h>
36#include <gelf.h>
37#include <stddef.h>
38#include <stdint.h>
39#include <stdlib.h>
40#include <string.h>
41#include <sys/param.h>
42
43#include "../libebl/libeblP.h"
44
45#define MACHINE_ENCODING __LITTLE_ENDIAN
46#include "memory-access.h"
47
48
49#ifndef MNEFILE
50# define MNEFILE "i386.mnemonics"
51#endif
52
53#define MNESTRFIELD(line) MNESTRFIELD1 (line)
54#define MNESTRFIELD1(line) str##line
55static const union mnestr_t
56{
57 struct
58 {
59#define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)];
60#include MNEFILE
61#undef MNE
62 };
63 char str[0];
64} mnestr =
65 {
66 {
67#define MNE(name) #name,
68#include MNEFILE
69#undef MNE
70 }
71 };
72
73/* The index can be stored in the instrtab. */
74enum
75 {
76#define MNE(name) MNE_##name,
77#include MNEFILE
78#undef MNE
79 MNE_INVALID
80 };
81
82static const unsigned short int mneidx[] =
83 {
84#define MNE(name) \
85 [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)),
86#include MNEFILE
87#undef MNE
88 };
89
90
91enum
92 {
Ulrich Drepperff993222008-01-09 05:39:28 +000093 idx_rex_b = 0,
94 idx_rex_x,
95 idx_rex_r,
96 idx_rex_w,
97 idx_rex,
98 idx_cs,
Ulrich Drepper3cbdd382008-01-02 17:44:39 +000099 idx_ds,
100 idx_es,
101 idx_fs,
102 idx_gs,
103 idx_ss,
104 idx_data16,
105 idx_addr16,
106 idx_rep,
107 idx_repne,
108 idx_lock
109 };
110
111enum
112 {
113#define prefbit(pref) has_##pref = 1 << idx_##pref
Ulrich Drepperff993222008-01-09 05:39:28 +0000114 prefbit (rex_b),
115 prefbit (rex_x),
116 prefbit (rex_r),
117 prefbit (rex_w),
118 prefbit (rex),
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000119 prefbit (cs),
120 prefbit (ds),
121 prefbit (es),
122 prefbit (fs),
123 prefbit (gs),
124 prefbit (ss),
125 prefbit (data16),
126 prefbit (addr16),
127 prefbit (rep),
128 prefbit (repne),
129 prefbit (lock)
130#undef prefbit
131 };
132#define SEGMENT_PREFIXES \
133 (has_cs | has_ds | has_es | has_fs | has_gs | has_ss)
134
135#define prefix_cs 0x2e
136#define prefix_ds 0x3e
137#define prefix_es 0x26
138#define prefix_fs 0x64
139#define prefix_gs 0x65
140#define prefix_ss 0x36
141#define prefix_data16 0x66
142#define prefix_addr16 0x67
143#define prefix_rep 0xf3
144#define prefix_repne 0xf2
145#define prefix_lock 0xf0
146
147
148static const uint8_t known_prefixes[] =
149 {
150#define newpref(pref) [idx_##pref] = prefix_##pref
151 newpref (cs),
152 newpref (ds),
153 newpref (es),
154 newpref (fs),
155 newpref (gs),
156 newpref (ss),
157 newpref (data16),
158 newpref (addr16),
159 newpref (rep),
160 newpref (repne),
161 newpref (lock)
162#undef newpref
163 };
164#define nknown_prefixes (sizeof (known_prefixes) / sizeof (known_prefixes[0]))
165
166
167#if 0
168static const char *prefix_str[] =
169 {
170#define newpref(pref) [idx_##pref] = #pref
171 newpref (cs),
172 newpref (ds),
173 newpref (es),
174 newpref (fs),
175 newpref (gs),
176 newpref (ss),
177 newpref (data16),
178 newpref (addr16),
179 newpref (rep),
180 newpref (repne),
181 newpref (lock)
182#undef newpref
183 };
184#endif
185
186
Ulrich Drepper5a04b9f2008-12-19 01:14:12 -0800187static const char amd3dnowstr[] =
188#define MNE_3DNOW_PAVGUSB 1
189 "pavgusb\0"
190#define MNE_3DNOW_PFADD (MNE_3DNOW_PAVGUSB + 8)
191 "pfadd\0"
192#define MNE_3DNOW_PFSUB (MNE_3DNOW_PFADD + 6)
193 "pfsub\0"
194#define MNE_3DNOW_PFSUBR (MNE_3DNOW_PFSUB + 6)
195 "pfsubr\0"
196#define MNE_3DNOW_PFACC (MNE_3DNOW_PFSUBR + 7)
197 "pfacc\0"
198#define MNE_3DNOW_PFCMPGE (MNE_3DNOW_PFACC + 6)
199 "pfcmpge\0"
200#define MNE_3DNOW_PFCMPGT (MNE_3DNOW_PFCMPGE + 8)
201 "pfcmpgt\0"
202#define MNE_3DNOW_PFCMPEQ (MNE_3DNOW_PFCMPGT + 8)
203 "pfcmpeq\0"
204#define MNE_3DNOW_PFMIN (MNE_3DNOW_PFCMPEQ + 8)
205 "pfmin\0"
206#define MNE_3DNOW_PFMAX (MNE_3DNOW_PFMIN + 6)
207 "pfmax\0"
208#define MNE_3DNOW_PI2FD (MNE_3DNOW_PFMAX + 6)
209 "pi2fd\0"
210#define MNE_3DNOW_PF2ID (MNE_3DNOW_PI2FD + 6)
211 "pf2id\0"
212#define MNE_3DNOW_PFRCP (MNE_3DNOW_PF2ID + 6)
213 "pfrcp\0"
214#define MNE_3DNOW_PFRSQRT (MNE_3DNOW_PFRCP + 6)
215 "pfrsqrt\0"
216#define MNE_3DNOW_PFMUL (MNE_3DNOW_PFRSQRT + 8)
217 "pfmul\0"
218#define MNE_3DNOW_PFRCPIT1 (MNE_3DNOW_PFMUL + 6)
219 "pfrcpit1\0"
220#define MNE_3DNOW_PFRSQIT1 (MNE_3DNOW_PFRCPIT1 + 9)
221 "pfrsqit1\0"
222#define MNE_3DNOW_PFRCPIT2 (MNE_3DNOW_PFRSQIT1 + 9)
223 "pfrcpit2\0"
224#define MNE_3DNOW_PMULHRW (MNE_3DNOW_PFRCPIT2 + 9)
225 "pmulhrw";
226
227#define AMD3DNOW_LOW_IDX 0x0d
228#define AMD3DNOW_HIGH_IDX (sizeof (amd3dnow) + AMD3DNOW_LOW_IDX - 1)
229#define AMD3DNOW_IDX(val) ((val) - AMD3DNOW_LOW_IDX)
Ulrich Drepperb51abc62008-12-31 09:12:50 -0800230static const unsigned char amd3dnow[] =
Ulrich Drepper5a04b9f2008-12-19 01:14:12 -0800231 {
232 [AMD3DNOW_IDX (0xbf)] = MNE_3DNOW_PAVGUSB,
233 [AMD3DNOW_IDX (0x9e)] = MNE_3DNOW_PFADD,
234 [AMD3DNOW_IDX (0x9a)] = MNE_3DNOW_PFSUB,
235 [AMD3DNOW_IDX (0xaa)] = MNE_3DNOW_PFSUBR,
236 [AMD3DNOW_IDX (0xae)] = MNE_3DNOW_PFACC,
237 [AMD3DNOW_IDX (0x90)] = MNE_3DNOW_PFCMPGE,
238 [AMD3DNOW_IDX (0xa0)] = MNE_3DNOW_PFCMPGT,
239 [AMD3DNOW_IDX (0xb0)] = MNE_3DNOW_PFCMPEQ,
240 [AMD3DNOW_IDX (0x94)] = MNE_3DNOW_PFMIN,
241 [AMD3DNOW_IDX (0xa4)] = MNE_3DNOW_PFMAX,
242 [AMD3DNOW_IDX (0x0d)] = MNE_3DNOW_PI2FD,
243 [AMD3DNOW_IDX (0x1d)] = MNE_3DNOW_PF2ID,
244 [AMD3DNOW_IDX (0x96)] = MNE_3DNOW_PFRCP,
245 [AMD3DNOW_IDX (0x97)] = MNE_3DNOW_PFRSQRT,
246 [AMD3DNOW_IDX (0xb4)] = MNE_3DNOW_PFMUL,
247 [AMD3DNOW_IDX (0xa6)] = MNE_3DNOW_PFRCPIT1,
248 [AMD3DNOW_IDX (0xa7)] = MNE_3DNOW_PFRSQIT1,
249 [AMD3DNOW_IDX (0xb6)] = MNE_3DNOW_PFRCPIT2,
250 [AMD3DNOW_IDX (0xb7)] = MNE_3DNOW_PMULHRW
251 };
252
253
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000254struct output_data
255{
256 GElf_Addr addr;
257 int *prefixes;
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000258 size_t opoff1;
259 size_t opoff2;
260 size_t opoff3;
261 char *bufp;
262 size_t *bufcntp;
263 size_t bufsize;
264 const uint8_t *data;
265 const uint8_t **param_start;
266 const uint8_t *end;
Ulrich Drepperfd479892008-01-12 03:06:47 +0000267 char *labelbuf;
268 size_t labelbufsize;
269 enum
270 {
271 addr_none = 0,
272 addr_abs_symbolic,
273 addr_abs_always,
274 addr_rel_symbolic,
275 addr_rel_always
276 } symaddr_use;
277 GElf_Addr symaddr;
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000278};
279
280
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000281#ifndef DISFILE
282# define DISFILE "i386_dis.h"
283#endif
284#include DISFILE
285
286
287#define ADD_CHAR(ch) \
288 do { \
289 if (unlikely (bufcnt == bufsize)) \
290 goto enomem; \
291 buf[bufcnt++] = (ch); \
292 } while (0)
293
294#define ADD_STRING(str) \
295 do { \
296 const char *_str = (str); \
297 size_t _len = strlen (_str); \
298 if (unlikely (bufcnt + _len > bufsize)) \
299 goto enomem; \
300 memcpy (buf + bufcnt, str, _len); \
301 bufcnt += _len; \
302 } while (0)
303
304
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000305int
306i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
307 const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
308 void *outcbarg, void *symcbarg)
309{
310 const char *save_fmt = fmt;
311
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000312#define BUFSIZE 512
313 char initbuf[BUFSIZE];
314 int prefixes;
315 size_t bufcnt;
316 size_t bufsize = BUFSIZE;
317 char *buf = initbuf;
318 const uint8_t *param_start;
319
320 struct output_data output_data =
321 {
322 .prefixes = &prefixes,
323 .bufp = buf,
324 .bufsize = bufsize,
325 .bufcntp = &bufcnt,
326 .param_start = &param_start,
Ulrich Drepperebe0fce2008-01-12 07:15:51 +0000327 .end = end
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000328 };
329
330 int retval = 0;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000331 while (1)
332 {
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000333 prefixes = 0;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000334
335 const uint8_t *data = *startp;
336 const uint8_t *begin = data;
337
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000338 /* Recognize all prefixes. */
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000339 int last_prefix_bit = 0;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000340 while (data < end)
341 {
342 unsigned int i;
Ulrich Drepperff993222008-01-09 05:39:28 +0000343 for (i = idx_cs; i < nknown_prefixes; ++i)
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000344 if (known_prefixes[i] == *data)
345 break;
346 if (i == nknown_prefixes)
347 break;
348
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000349 prefixes |= last_prefix_bit = 1 << i;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000350
351 ++data;
352 }
353
Ulrich Drepperff993222008-01-09 05:39:28 +0000354#ifdef X86_64
355 if (data < end && (*data & 0xf0) == 0x40)
356 prefixes |= ((*data++) & 0xf) | has_rex;
357#endif
358
Ulrich Dreppera492e8e2008-12-31 12:03:45 -0800359 bufcnt = 0;
360 size_t cnt = 0;
361
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000362 const uint8_t *curr = match_data;
363 const uint8_t *const match_end = match_data + sizeof (match_data);
364
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000365 assert (data <= end);
366 if (data == end)
367 {
368 if (prefixes != 0)
369 goto print_prefix;
370
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000371 retval = -1;
372 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000373 }
374
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800375 next_match:
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000376 while (curr < match_end)
377 {
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800378 uint_fast8_t len = *curr++;
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800379 uint_fast8_t clen = len >> 4;
380 len &= 0xf;
381 const uint8_t *next_curr = curr + clen + (len - clen) * 2;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000382
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000383 assert (len > 0);
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800384 assert (curr + clen + 2 * (len - clen) <= match_end);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000385
386 const uint8_t *codep = data;
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000387 int correct_prefix = 0;
388 int opoff = 0;
389
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800390 if (data > begin && codep[-1] == *curr && clen > 0)
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000391 {
392 /* We match a prefix byte. This is exactly one byte and
393 is matched exactly, without a mask. */
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000394 --len;
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800395 --clen;
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000396 opoff = 8;
397
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800398 ++curr;
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000399
400 assert (last_prefix_bit != 0);
401 correct_prefix = last_prefix_bit;
402 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000403
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800404 size_t avail = len;
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800405 while (clen > 0)
406 {
407 if (*codep++ != *curr++)
408 goto not;
409 --avail;
410 --clen;
411 if (codep == end && avail > 0)
412 goto do_ret;
413 }
414
Ulrich Drepper7f923f42008-12-17 22:24:14 -0800415 while (avail > 0)
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000416 {
417 uint_fast8_t masked = *codep++ & *curr++;
418 if (masked != *curr++)
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800419 {
420 not:
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800421 curr = next_curr;
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800422 ++cnt;
Ulrich Drepper3bf57592009-01-01 18:52:05 -0800423 bufcnt = 0;
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800424 goto next_match;
425 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000426
427 --avail;
428 if (codep == end && avail > 0)
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000429 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000430 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000431
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000432 if (len > end - data)
433 /* There is not enough data for the entire instruction. The
434 caller can figure this out by looking at the pointer into
435 the input data. */
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000436 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000437
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000438 assert (correct_prefix == 0
439 || (prefixes & correct_prefix) != 0);
440 prefixes ^= correct_prefix;
441
Ulrich Dreppera492e8e2008-12-31 12:03:45 -0800442 if (0)
443 {
444 /* Resize the buffer. */
445 char *oldbuf;
446 enomem:
447 oldbuf = buf;
448 if (buf == initbuf)
449 buf = malloc (2 * bufsize);
450 else
451 buf = realloc (buf, 2 * bufsize);
452 if (buf == NULL)
453 {
454 buf = oldbuf;
455 retval = ENOMEM;
456 goto do_ret;
457 }
458 bufsize *= 2;
459
460 output_data.bufp = buf;
461 output_data.bufsize = bufsize;
462 bufcnt = 0;
463
464 if (data == end)
465 {
466 assert (prefixes != 0);
467 goto print_prefix;
468 }
469
470 /* gcc is not clever enough to see the following variables
471 are not used uninitialized. */
472 asm (""
473 : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800474 "=mr" (next_curr), "=mr" (len));
Ulrich Dreppera492e8e2008-12-31 12:03:45 -0800475 }
476
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000477 size_t prefix_size = 0;
478
479 // XXXonly print as prefix if valid?
480 if ((prefixes & has_lock) != 0)
481 {
482 ADD_STRING ("lock ");
483 prefix_size += 5;
484 }
485
486 if (instrtab[cnt].rep)
487 {
488 if ((prefixes & has_rep) != 0)
489 {
490 ADD_STRING ("rep ");
491 prefix_size += 4;
492 }
493 }
494 else if (instrtab[cnt].repe
495 && (prefixes & (has_rep | has_repne)) != 0)
496 {
497 if ((prefixes & has_repne) != 0)
498 {
499 ADD_STRING ("repne ");
500 prefix_size += 6;
501 }
502 else if ((prefixes & has_rep) != 0)
503 {
504 ADD_STRING ("repe ");
505 prefix_size += 5;
506 }
507 }
508 else if ((prefixes & (has_rep | has_repne)) != 0)
509 {
510 uint_fast8_t byte;
511 print_prefix:
512 bufcnt = 0;
513 byte = *begin;
514 /* This is a prefix byte. Print it. */
515 switch (byte)
516 {
517 case prefix_rep:
518 ADD_STRING ("rep");
519 break;
520 case prefix_repne:
521 ADD_STRING ("repne");
522 break;
523 case prefix_cs:
524 ADD_STRING ("cs");
525 break;
526 case prefix_ds:
527 ADD_STRING ("ds");
528 break;
529 case prefix_es:
530 ADD_STRING ("es");
531 break;
532 case prefix_fs:
533 ADD_STRING ("fs");
534 break;
535 case prefix_gs:
536 ADD_STRING ("gs");
537 break;
538 case prefix_ss:
539 ADD_STRING ("ss");
540 break;
541 case prefix_data16:
542 ADD_STRING ("data16");
543 break;
544 case prefix_addr16:
545 ADD_STRING ("addr16");
546 break;
547 case prefix_lock:
548 ADD_STRING ("lock");
549 break;
Ulrich Drepper54a6d4b2008-12-31 10:21:51 -0800550#ifdef X86_64
551 case 0x40 ... 0x4f:
552 ADD_STRING ("rex");
553 if (byte != 0x40)
554 {
555 ADD_CHAR ('.');
556 if (byte & 0x8)
557 ADD_CHAR ('w');
558 if (byte & 0x4)
559 ADD_CHAR ('r');
560 if (byte & 0x3)
561 ADD_CHAR ('x');
562 if (byte & 0x1)
563 ADD_CHAR ('b');
564 }
565 break;
566#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000567 default:
568 /* Cannot happen. */
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000569 puts ("unknown prefix");
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000570 abort ();
571 }
572 data = begin + 1;
573 ++addr;
574
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000575 goto out;
576 }
577
578 /* We have a match. First determine how many bytes are
579 needed for the adressing mode. */
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000580 param_start = codep;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000581 if (instrtab[cnt].modrm)
582 {
583 uint_fast8_t modrm = codep[-1];
584
Ulrich Drepperff993222008-01-09 05:39:28 +0000585#ifndef X86_64
586 if (likely ((prefixes & has_addr16) != 0))
587 {
588 /* Account for displacement. */
589 if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
590 param_start += 2;
591 else if ((modrm & 0xc0) == 0x40)
592 param_start += 1;
593 }
594 else
595#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000596 {
597 /* Account for SIB. */
598 if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
599 param_start += 1;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000600
Ulrich Drepperff993222008-01-09 05:39:28 +0000601 /* Account for displacement. */
602 if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
603 || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
604 param_start += 4;
605 else if ((modrm & 0xc0) == 0x40)
606 param_start += 1;
607 }
Ulrich Drepper9e6925d2008-01-04 21:42:14 +0000608
609 if (unlikely (param_start > end))
610 goto not;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000611 }
612
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000613 output_data.addr = addr + (data - begin);
614 output_data.data = data;
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000615
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000616 unsigned long string_end_idx = 0;
Ulrich Drepper35f2fe62008-01-14 19:17:36 +0000617 fmt = save_fmt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000618 while (*fmt != '\0')
619 {
620 if (*fmt != '%')
621 {
622 char ch = *fmt++;
623 if (ch == '\\')
624 {
625 switch ((ch = *fmt++))
626 {
627 case '0' ... '7':
628 {
629 int val = ch - '0';
630 ch = *fmt;
631 if (ch >= '0' && ch <= '7')
632 {
633 val *= 8;
634 val += ch - '0';
635 ch = *++fmt;
636 if (ch >= '0' && ch <= '7' && val < 32)
637 {
638 val *= 8;
639 val += ch - '0';
640 ++fmt;
641 }
642 }
643 ch = val;
644 }
645 break;
646
647 case 'n':
648 ch = '\n';
649 break;
650
651 case 't':
652 ch = '\t';
653 break;
654
655 default:
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000656 retval = EINVAL;
657 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000658 }
659 }
660 ADD_CHAR (ch);
661 continue;
662 }
663 ++fmt;
664
665 int width = 0;
666 while (isdigit (*fmt))
667 width = width * 10 + (*fmt++ - '0');
668
669 int prec = 0;
670 if (*fmt == '.')
671 while (isdigit (*++fmt))
672 prec = prec * 10 + (*fmt - '0');
673
674 size_t start_idx = bufcnt;
675 switch (*fmt++)
676 {
Ulrich Drepperff993222008-01-09 05:39:28 +0000677 char mnebuf[16];
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000678 const char *str;
679
680 case 'm':
681 /* Mnemonic. */
682
683 if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
684 {
685 switch (*data)
686 {
Ulrich Drepper35f2fe62008-01-14 19:17:36 +0000687#ifdef X86_64
688 case 0x90:
689 if (prefixes & has_rex_b)
690 goto not;
691 str = "nop";
692 break;
693#endif
694
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000695 case 0x98:
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000696#ifdef X86_64
Ulrich Drepper4d8bc812008-01-22 06:02:31 +0000697 if (prefixes == (has_rex_w | has_rex))
698 {
699 str = "cltq";
700 break;
701 }
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000702#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000703 if (prefixes & ~has_data16)
704 goto print_prefix;
705 str = prefixes & has_data16 ? "cbtw" : "cwtl";
706 break;
707
708 case 0x99:
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000709#ifdef X86_64
Ulrich Drepper4d8bc812008-01-22 06:02:31 +0000710 if (prefixes == (has_rex_w | has_rex))
711 {
712 str = "cqto";
713 break;
714 }
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000715#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000716 if (prefixes & ~has_data16)
717 goto print_prefix;
718 str = prefixes & has_data16 ? "cwtd" : "cltd";
719 break;
720
721 case 0xe3:
722 if (prefixes & ~has_addr16)
723 goto print_prefix;
Ulrich Drepperff993222008-01-09 05:39:28 +0000724#ifdef X86_64
725 str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
726#else
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000727 str = prefixes & has_addr16 ? "jcxz" : "jecxz";
Ulrich Drepperff993222008-01-09 05:39:28 +0000728#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000729 break;
730
Ulrich Drepperff993222008-01-09 05:39:28 +0000731 case 0x0f:
Ulrich Drepper5a04b9f2008-12-19 01:14:12 -0800732 if (data[1] == 0x0f)
733 {
734 /* AMD 3DNOW. We need one more byte. */
735 if (param_start >= end)
736 goto not;
737 if (*param_start < AMD3DNOW_LOW_IDX
738 || *param_start > AMD3DNOW_HIGH_IDX)
739 goto not;
740 unsigned int idx
741 = amd3dnow[AMD3DNOW_IDX (*param_start)];
742 if (idx == 0)
743 goto not;
744 str = amd3dnowstr + idx - 1;
745 /* Eat the immediate byte indicating the
746 operation. */
747 ++param_start;
748 break;
749 }
Ulrich Drepperff993222008-01-09 05:39:28 +0000750#ifdef X86_64
751 if (data[1] == 0xc7)
752 {
753 str = ((prefixes & has_rex_w)
754 ? "cmpxchg16b" : "cmpxchg8b");
755 break;
756 }
757#endif
758 if (data[1] == 0xc2)
759 {
760 if (param_start >= end)
761 goto not;
762 if (*param_start > 7)
763 goto not;
764 static const char cmpops[][9] =
765 {
766 [0] = "cmpeq",
767 [1] = "cmplt",
768 [2] = "cmple",
769 [3] = "cmpunord",
770 [4] = "cmpneq",
771 [5] = "cmpnlt",
772 [6] = "cmpnle",
773 [7] = "cmpord"
774 };
775 char *cp = stpcpy (mnebuf, cmpops[*param_start]);
776 if (correct_prefix & (has_rep | has_repne))
777 *cp++ = 's';
778 else
779 *cp++ = 'p';
780 if (correct_prefix & (has_data16 | has_repne))
781 *cp++ = 'd';
782 else
783 *cp++ = 's';
784 *cp = '\0';
785 str = mnebuf;
786 /* Eat the immediate byte indicating the
787 operation. */
788 ++param_start;
789 break;
790 }
791
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000792 default:
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000793 assert (! "INVALID not handled");
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000794 }
795 }
796 else
797 str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
798
799 ADD_STRING (str);
800
801 switch (instrtab[cnt].suffix)
802 {
803 case suffix_none:
804 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000805
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000806 case suffix_w:
807 if ((codep[-1] & 0xc0) != 0xc0)
808 {
809 char ch;
810
811 if (data[0] & 1)
812 {
813 if (prefixes & has_data16)
814 ch = 'w';
Ulrich Drepper96a73992008-01-11 06:17:06 +0000815#ifdef X86_64
816 else if (prefixes & has_rex_w)
817 ch = 'q';
818#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000819 else
820 ch = 'l';
821 }
822 else
823 ch = 'b';
824
825 ADD_CHAR (ch);
826 }
827 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000828
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000829 case suffix_w0:
830 if ((codep[-1] & 0xc0) != 0xc0)
831 ADD_CHAR ('l');
832 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000833
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000834 case suffix_w1:
835 if ((data[0] & 0x4) == 0)
836 ADD_CHAR ('l');
837 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000838
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000839 case suffix_W:
840 if (prefixes & has_data16)
841 {
842 ADD_CHAR ('w');
843 prefixes &= ~has_data16;
844 }
Ulrich Drepperff993222008-01-09 05:39:28 +0000845#ifdef X86_64
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000846 else
Ulrich Drepperff993222008-01-09 05:39:28 +0000847 ADD_CHAR ('q');
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000848#endif
849 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000850
Ulrich Drepperff993222008-01-09 05:39:28 +0000851 case suffix_W1:
852 if (prefixes & has_data16)
853 {
854 ADD_CHAR ('w');
855 prefixes &= ~has_data16;
856 }
857#ifdef X86_64
858 else if (prefixes & has_rex_w)
859 ADD_CHAR ('q');
860#endif
861 break;
862
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000863 case suffix_tttn:;
864 static const char tttn[16][3] =
865 {
866 "o", "no", "b", "ae", "e", "ne", "be", "a",
867 "s", "ns", "p", "np", "l", "ge", "le", "g"
868 };
869 ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
870 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000871
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000872 case suffix_D:
873 if ((codep[-1] & 0xc0) != 0xc0)
874 ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
875 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000876
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000877 default:
878 printf("unknown suffix %d\n", instrtab[cnt].suffix);
879 abort ();
880 }
881
882 string_end_idx = bufcnt;
883 break;
884
885 case 'o':
886 if (prec == 1 && instrtab[cnt].fct1 != 0)
887 {
888 /* First parameter. */
889 if (instrtab[cnt].str1 != 0)
Ulrich Drepper71696ba2008-12-31 11:34:47 -0800890 ADD_STRING (op1_str
891 + op1_str_idx[instrtab[cnt].str1 - 1]);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000892
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000893 output_data.opoff1 = (instrtab[cnt].off1_1
894 + OFF1_1_BIAS - opoff);
895 output_data.opoff2 = (instrtab[cnt].off1_2
896 + OFF1_2_BIAS - opoff);
897 output_data.opoff3 = (instrtab[cnt].off1_3
898 + OFF1_3_BIAS - opoff);
899 int r = op1_fct[instrtab[cnt].fct1] (&output_data);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000900 if (r < 0)
901 goto not;
902 if (r > 0)
903 goto enomem;
904
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000905 string_end_idx = bufcnt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000906 }
907 else if (prec == 2 && instrtab[cnt].fct2 != 0)
908 {
909 /* Second parameter. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000910 if (instrtab[cnt].str2 != 0)
Ulrich Drepper71696ba2008-12-31 11:34:47 -0800911 ADD_STRING (op2_str
912 + op2_str_idx[instrtab[cnt].str2 - 1]);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000913
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000914 output_data.opoff1 = (instrtab[cnt].off2_1
915 + OFF2_1_BIAS - opoff);
916 output_data.opoff2 = (instrtab[cnt].off2_2
917 + OFF2_2_BIAS - opoff);
918 output_data.opoff3 = (instrtab[cnt].off2_3
919 + OFF2_3_BIAS - opoff);
920 int r = op2_fct[instrtab[cnt].fct2] (&output_data);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000921 if (r < 0)
922 goto not;
923 if (r > 0)
924 goto enomem;
925
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000926 string_end_idx = bufcnt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000927 }
928 else if (prec == 3 && instrtab[cnt].fct3 != 0)
929 {
930 /* Third parameter. */
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000931 if (instrtab[cnt].str3 != 0)
Ulrich Drepper71696ba2008-12-31 11:34:47 -0800932 ADD_STRING (op3_str
933 + op3_str_idx[instrtab[cnt].str3 - 1]);
Ulrich Dreppere219f1c2008-01-09 05:49:49 +0000934
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000935 output_data.opoff1 = (instrtab[cnt].off3_1
936 + OFF3_1_BIAS - opoff);
937 output_data.opoff2 = (instrtab[cnt].off3_2
938 + OFF3_2_BIAS - opoff);
Ulrich Dreppere219f1c2008-01-09 05:49:49 +0000939#ifdef OFF3_3_BITS
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000940 output_data.opoff3 = (instrtab[cnt].off3_3
941 + OFF3_3_BIAS - opoff);
Ulrich Dreppere219f1c2008-01-09 05:49:49 +0000942#else
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000943 output_data.opoff3 = 0;
Ulrich Dreppere219f1c2008-01-09 05:49:49 +0000944#endif
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000945 int r = op3_fct[instrtab[cnt].fct3] (&output_data);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000946 if (r < 0)
947 goto not;
948 if (r > 0)
949 goto enomem;
950
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000951 string_end_idx = bufcnt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000952 }
Ulrich Drepperfd479892008-01-12 03:06:47 +0000953 else
954 bufcnt = string_end_idx;
955 break;
956
957 case 'e':
958 string_end_idx = bufcnt;
959 break;
960
961 case 'a':
962 /* Pad to requested column. */
963 while (bufcnt < (size_t) width)
964 ADD_CHAR (' ');
965 width = 0;
966 break;
967
968 case 'l':
969 if (output_data.labelbuf != NULL
970 && output_data.labelbuf[0] != '\0')
971 {
972 ADD_STRING (output_data.labelbuf);
973 output_data.labelbuf[0] = '\0';
974 string_end_idx = bufcnt;
975 }
976 else if (output_data.symaddr_use != addr_none)
977 {
978 GElf_Addr symaddr = output_data.symaddr;
979 if (output_data.symaddr_use >= addr_rel_symbolic)
980 symaddr += addr + param_start - begin;
981
982 // XXX Lookup symbol based on symaddr
983 const char *symstr = NULL;
Ulrich Drepperebe0fce2008-01-12 07:15:51 +0000984 if (symcb != NULL
985 && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
986 &output_data.labelbuf,
987 &output_data.labelbufsize, symcbarg) == 0)
988 symstr = output_data.labelbuf;
Ulrich Drepperfd479892008-01-12 03:06:47 +0000989
990 size_t bufavail = bufsize - bufcnt;
991 int r = 0;
992 if (symstr != NULL)
Ulrich Drepperebe0fce2008-01-12 07:15:51 +0000993 r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
994 symstr);
Ulrich Drepperfd479892008-01-12 03:06:47 +0000995 else if (output_data.symaddr_use == addr_abs_always
996 || output_data.symaddr_use == addr_rel_always)
997 r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
998 (uint64_t) symaddr);
999
Ulrich Drepper3bf57592009-01-01 18:52:05 -08001000 assert (r >= 0);
Ulrich Drepperfd479892008-01-12 03:06:47 +00001001 if ((size_t) r >= bufavail)
1002 goto enomem;
1003 bufcnt += r;
1004 string_end_idx = bufcnt;
1005
1006 output_data.symaddr_use = addr_none;
1007 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001008 break;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001009 }
1010
1011 /* Pad according to the specified width. */
1012 while (bufcnt + prefix_size < start_idx + width)
1013 ADD_CHAR (' ');
1014 prefix_size = 0;
1015 }
1016
1017 if ((prefixes & SEGMENT_PREFIXES) != 0)
1018 goto print_prefix;
1019
Ulrich Drepper5eee1222008-01-11 10:12:18 +00001020 assert (string_end_idx != ~0ul);
1021 bufcnt = string_end_idx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001022
1023 addr += param_start - begin;
1024 data = param_start;
1025
1026 goto out;
1027 }
1028
1029 /* Invalid (or at least unhandled) opcode. */
1030 if (prefixes != 0)
1031 goto print_prefix;
1032 assert (*startp == data);
1033 ++data;
1034 ADD_STRING ("(bad)");
1035 addr += data - begin;
1036
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001037 out:
Ulrich Drepper5eee1222008-01-11 10:12:18 +00001038 if (bufcnt == bufsize)
1039 goto enomem;
1040 buf[bufcnt] = '\0';
1041
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001042 *startp = data;
Ulrich Drepper5eee1222008-01-11 10:12:18 +00001043 retval = outcb (buf, bufcnt, outcbarg);
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +00001044 if (retval != 0)
1045 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001046 }
1047
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +00001048 do_ret:
Ulrich Drepperfd479892008-01-12 03:06:47 +00001049 free (output_data.labelbuf);
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +00001050 if (buf != initbuf)
1051 free (buf);
1052
1053 return retval;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001054}