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