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