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