blob: 832241f2cdb366d160433a654103f5284a44e224 [file] [log] [blame]
Ulrich Drepper515d8d72008-01-03 07:41:03 +00001/* Disassembler for x86.
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05002 Copyright (C) 2007, 2008, 2009, 2011 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepper515d8d72008-01-03 07:41:03 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 2007.
5
Mark Wielaardde2ed972012-06-05 17:15:16 +02006 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
Ulrich Drepper515d8d72008-01-03 07:41:03 +00008
Mark Wielaardde2ed972012-06-05 17:15:16 +02009 * 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
Ulrich Drepper515d8d72008-01-03 07:41:03 +000022 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020026 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/>. */
Ulrich Drepper515d8d72008-01-03 07:41:03 +000029
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
Ulrich Drepper3cbdd382008-01-02 17:44:39 +000034#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
58static 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. */
77enum
78 {
79#define MNE(name) MNE_##name,
80#include MNEFILE
81#undef MNE
82 MNE_INVALID
83 };
84
85static 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
94enum
95 {
Ulrich Drepperff993222008-01-09 05:39:28 +000096 idx_rex_b = 0,
97 idx_rex_x,
98 idx_rex_r,
99 idx_rex_w,
100 idx_rex,
101 idx_cs,
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000102 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
114enum
115 {
116#define prefbit(pref) has_##pref = 1 << idx_##pref
Ulrich Drepperff993222008-01-09 05:39:28 +0000117 prefbit (rex_b),
118 prefbit (rex_x),
119 prefbit (rex_r),
120 prefbit (rex_w),
121 prefbit (rex),
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000122 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
151static 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
171static 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
Ulrich Drepper5a04b9f2008-12-19 01:14:12 -0800190static 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)
Ulrich Drepperb51abc62008-12-31 09:12:50 -0800233static const unsigned char amd3dnow[] =
Ulrich Drepper5a04b9f2008-12-19 01:14:12 -0800234 {
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
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000257struct output_data
258{
259 GElf_Addr addr;
260 int *prefixes;
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000261 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;
Ulrich Drepperfd479892008-01-12 03:06:47 +0000270 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;
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000281};
282
283
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000284#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 { \
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500299 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 { \
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000306 const char *_str = (str); \
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500307 size_t _len = (len); \
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000308 if (unlikely (bufcnt + _len > bufsize)) \
309 goto enomem; \
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500310 memcpy (buf + bufcnt, _str, _len); \
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000311 bufcnt += _len; \
312 } while (0)
313
314
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000315int
316i386_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 const char *save_fmt = fmt;
321
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000322#define BUFSIZE 512
323 char initbuf[BUFSIZE];
324 int prefixes;
325 size_t bufcnt;
326 size_t bufsize = BUFSIZE;
327 char *buf = initbuf;
328 const uint8_t *param_start;
329
330 struct output_data output_data =
331 {
332 .prefixes = &prefixes,
333 .bufp = buf,
334 .bufsize = bufsize,
335 .bufcntp = &bufcnt,
336 .param_start = &param_start,
Ulrich Drepperebe0fce2008-01-12 07:15:51 +0000337 .end = end
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000338 };
339
340 int retval = 0;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000341 while (1)
342 {
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000343 prefixes = 0;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000344
345 const uint8_t *data = *startp;
346 const uint8_t *begin = data;
347
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000348 /* Recognize all prefixes. */
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000349 int last_prefix_bit = 0;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000350 while (data < end)
351 {
352 unsigned int i;
Ulrich Drepperff993222008-01-09 05:39:28 +0000353 for (i = idx_cs; i < nknown_prefixes; ++i)
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000354 if (known_prefixes[i] == *data)
355 break;
356 if (i == nknown_prefixes)
357 break;
358
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000359 prefixes |= last_prefix_bit = 1 << i;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000360
361 ++data;
362 }
363
Ulrich Drepperff993222008-01-09 05:39:28 +0000364#ifdef X86_64
365 if (data < end && (*data & 0xf0) == 0x40)
366 prefixes |= ((*data++) & 0xf) | has_rex;
367#endif
368
Ulrich Dreppera492e8e2008-12-31 12:03:45 -0800369 bufcnt = 0;
370 size_t cnt = 0;
371
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000372 const uint8_t *curr = match_data;
373 const uint8_t *const match_end = match_data + sizeof (match_data);
374
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000375 assert (data <= end);
376 if (data == end)
377 {
378 if (prefixes != 0)
379 goto print_prefix;
380
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000381 retval = -1;
382 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000383 }
384
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800385 next_match:
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000386 while (curr < match_end)
387 {
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800388 uint_fast8_t len = *curr++;
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800389 uint_fast8_t clen = len >> 4;
390 len &= 0xf;
391 const uint8_t *next_curr = curr + clen + (len - clen) * 2;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000392
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000393 assert (len > 0);
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800394 assert (curr + clen + 2 * (len - clen) <= match_end);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000395
396 const uint8_t *codep = data;
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000397 int correct_prefix = 0;
398 int opoff = 0;
399
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800400 if (data > begin && codep[-1] == *curr && clen > 0)
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000401 {
402 /* We match a prefix byte. This is exactly one byte and
403 is matched exactly, without a mask. */
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000404 --len;
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800405 --clen;
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000406 opoff = 8;
407
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800408 ++curr;
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000409
410 assert (last_prefix_bit != 0);
411 correct_prefix = last_prefix_bit;
412 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000413
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800414 size_t avail = len;
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800415 while (clen > 0)
416 {
417 if (*codep++ != *curr++)
418 goto not;
419 --avail;
420 --clen;
421 if (codep == end && avail > 0)
422 goto do_ret;
423 }
424
Ulrich Drepper7f923f42008-12-17 22:24:14 -0800425 while (avail > 0)
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000426 {
427 uint_fast8_t masked = *codep++ & *curr++;
428 if (masked != *curr++)
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800429 {
430 not:
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800431 curr = next_curr;
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800432 ++cnt;
Ulrich Drepper3bf57592009-01-01 18:52:05 -0800433 bufcnt = 0;
Ulrich Drepper98c245e2008-12-31 10:15:30 -0800434 goto next_match;
435 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000436
437 --avail;
438 if (codep == end && avail > 0)
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000439 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000440 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000441
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000442 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. */
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000446 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000447
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000448 assert (correct_prefix == 0
449 || (prefixes & correct_prefix) != 0);
450 prefixes ^= correct_prefix;
451
Ulrich Dreppera492e8e2008-12-31 12:03:45 -0800452 if (0)
453 {
454 /* Resize the buffer. */
455 char *oldbuf;
456 enomem:
457 oldbuf = buf;
458 if (buf == initbuf)
459 buf = malloc (2 * bufsize);
460 else
461 buf = realloc (buf, 2 * bufsize);
462 if (buf == NULL)
463 {
464 buf = oldbuf;
465 retval = ENOMEM;
466 goto do_ret;
467 }
468 bufsize *= 2;
469
470 output_data.bufp = buf;
471 output_data.bufsize = bufsize;
472 bufcnt = 0;
473
474 if (data == end)
475 {
476 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 asm (""
483 : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
Ulrich Drepper92287fd2009-01-01 20:18:48 -0800484 "=mr" (next_curr), "=mr" (len));
Ulrich Dreppera492e8e2008-12-31 12:03:45 -0800485 }
486
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000487 size_t prefix_size = 0;
488
489 // XXXonly print as prefix if valid?
490 if ((prefixes & has_lock) != 0)
491 {
492 ADD_STRING ("lock ");
493 prefix_size += 5;
494 }
495
496 if (instrtab[cnt].rep)
497 {
498 if ((prefixes & has_rep) != 0)
499 {
500 ADD_STRING ("rep ");
501 prefix_size += 4;
502 }
503 }
504 else if (instrtab[cnt].repe
505 && (prefixes & (has_rep | has_repne)) != 0)
506 {
507 if ((prefixes & has_repne) != 0)
508 {
509 ADD_STRING ("repne ");
510 prefix_size += 6;
511 }
512 else if ((prefixes & has_rep) != 0)
513 {
514 ADD_STRING ("repe ");
515 prefix_size += 5;
516 }
517 }
518 else if ((prefixes & (has_rep | has_repne)) != 0)
519 {
520 uint_fast8_t byte;
521 print_prefix:
522 bufcnt = 0;
523 byte = *begin;
524 /* This is a prefix byte. Print it. */
525 switch (byte)
526 {
527 case prefix_rep:
528 ADD_STRING ("rep");
529 break;
530 case prefix_repne:
531 ADD_STRING ("repne");
532 break;
533 case prefix_cs:
534 ADD_STRING ("cs");
535 break;
536 case prefix_ds:
537 ADD_STRING ("ds");
538 break;
539 case prefix_es:
540 ADD_STRING ("es");
541 break;
542 case prefix_fs:
543 ADD_STRING ("fs");
544 break;
545 case prefix_gs:
546 ADD_STRING ("gs");
547 break;
548 case prefix_ss:
549 ADD_STRING ("ss");
550 break;
551 case prefix_data16:
552 ADD_STRING ("data16");
553 break;
554 case prefix_addr16:
555 ADD_STRING ("addr16");
556 break;
557 case prefix_lock:
558 ADD_STRING ("lock");
559 break;
Ulrich Drepper54a6d4b2008-12-31 10:21:51 -0800560#ifdef X86_64
561 case 0x40 ... 0x4f:
562 ADD_STRING ("rex");
563 if (byte != 0x40)
564 {
565 ADD_CHAR ('.');
566 if (byte & 0x8)
567 ADD_CHAR ('w');
568 if (byte & 0x4)
569 ADD_CHAR ('r');
570 if (byte & 0x3)
571 ADD_CHAR ('x');
572 if (byte & 0x1)
573 ADD_CHAR ('b');
574 }
575 break;
576#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000577 default:
578 /* Cannot happen. */
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000579 puts ("unknown prefix");
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000580 abort ();
581 }
582 data = begin + 1;
583 ++addr;
584
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000585 goto out;
586 }
587
588 /* We have a match. First determine how many bytes are
589 needed for the adressing mode. */
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000590 param_start = codep;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000591 if (instrtab[cnt].modrm)
592 {
593 uint_fast8_t modrm = codep[-1];
594
Ulrich Drepperff993222008-01-09 05:39:28 +0000595#ifndef X86_64
596 if (likely ((prefixes & has_addr16) != 0))
597 {
598 /* Account for displacement. */
599 if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
600 param_start += 2;
601 else if ((modrm & 0xc0) == 0x40)
602 param_start += 1;
603 }
604 else
605#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000606 {
607 /* Account for SIB. */
608 if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
609 param_start += 1;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000610
Ulrich Drepperff993222008-01-09 05:39:28 +0000611 /* Account for displacement. */
612 if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
613 || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
614 param_start += 4;
615 else if ((modrm & 0xc0) == 0x40)
616 param_start += 1;
617 }
Ulrich Drepper9e6925d2008-01-04 21:42:14 +0000618
619 if (unlikely (param_start > end))
620 goto not;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000621 }
622
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000623 output_data.addr = addr + (data - begin);
624 output_data.data = data;
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000625
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000626 unsigned long string_end_idx = 0;
Ulrich Drepper35f2fe62008-01-14 19:17:36 +0000627 fmt = save_fmt;
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500628 const char *deferred_start = NULL;
629 size_t deferred_len = 0;
630 // XXX Can we get this from color.c?
631 static const char color_off[] = "\e[0m";
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000632 while (*fmt != '\0')
633 {
634 if (*fmt != '%')
635 {
636 char ch = *fmt++;
637 if (ch == '\\')
638 {
639 switch ((ch = *fmt++))
640 {
641 case '0' ... '7':
642 {
643 int val = ch - '0';
644 ch = *fmt;
645 if (ch >= '0' && ch <= '7')
646 {
647 val *= 8;
648 val += ch - '0';
649 ch = *++fmt;
650 if (ch >= '0' && ch <= '7' && val < 32)
651 {
652 val *= 8;
653 val += ch - '0';
654 ++fmt;
655 }
656 }
657 ch = val;
658 }
659 break;
660
661 case 'n':
662 ch = '\n';
663 break;
664
665 case 't':
666 ch = '\t';
667 break;
668
669 default:
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +0000670 retval = EINVAL;
671 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000672 }
673 }
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500674 else if (ch == '\e' && *fmt == '[')
675 {
676 deferred_start = fmt - 1;
677 do
678 ++fmt;
679 while (*fmt != 'm' && *fmt != '\0');
680
681 if (*fmt == 'm')
682 {
683 deferred_len = ++fmt - deferred_start;
684 continue;
685 }
686
687 fmt = deferred_start + 1;
688 deferred_start = NULL;
689 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000690 ADD_CHAR (ch);
691 continue;
692 }
693 ++fmt;
694
695 int width = 0;
696 while (isdigit (*fmt))
697 width = width * 10 + (*fmt++ - '0');
698
699 int prec = 0;
700 if (*fmt == '.')
701 while (isdigit (*++fmt))
702 prec = prec * 10 + (*fmt - '0');
703
704 size_t start_idx = bufcnt;
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500705 size_t non_printing = 0;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000706 switch (*fmt++)
707 {
Ulrich Drepperff993222008-01-09 05:39:28 +0000708 char mnebuf[16];
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000709 const char *str;
710
711 case 'm':
712 /* Mnemonic. */
713
714 if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
715 {
716 switch (*data)
717 {
Ulrich Drepper35f2fe62008-01-14 19:17:36 +0000718#ifdef X86_64
719 case 0x90:
720 if (prefixes & has_rex_b)
721 goto not;
722 str = "nop";
723 break;
724#endif
725
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000726 case 0x98:
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000727#ifdef X86_64
Ulrich Drepper4d8bc812008-01-22 06:02:31 +0000728 if (prefixes == (has_rex_w | has_rex))
729 {
730 str = "cltq";
731 break;
732 }
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000733#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000734 if (prefixes & ~has_data16)
735 goto print_prefix;
736 str = prefixes & has_data16 ? "cbtw" : "cwtl";
737 break;
738
739 case 0x99:
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000740#ifdef X86_64
Ulrich Drepper4d8bc812008-01-22 06:02:31 +0000741 if (prefixes == (has_rex_w | has_rex))
742 {
743 str = "cqto";
744 break;
745 }
Ulrich Drepper06ec9db2008-01-22 06:08:30 +0000746#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000747 if (prefixes & ~has_data16)
748 goto print_prefix;
749 str = prefixes & has_data16 ? "cwtd" : "cltd";
750 break;
751
752 case 0xe3:
753 if (prefixes & ~has_addr16)
754 goto print_prefix;
Ulrich Drepperff993222008-01-09 05:39:28 +0000755#ifdef X86_64
756 str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
757#else
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000758 str = prefixes & has_addr16 ? "jcxz" : "jecxz";
Ulrich Drepperff993222008-01-09 05:39:28 +0000759#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000760 break;
761
Ulrich Drepperff993222008-01-09 05:39:28 +0000762 case 0x0f:
Ulrich Drepper5a04b9f2008-12-19 01:14:12 -0800763 if (data[1] == 0x0f)
764 {
765 /* AMD 3DNOW. We need one more byte. */
766 if (param_start >= end)
767 goto not;
768 if (*param_start < AMD3DNOW_LOW_IDX
769 || *param_start > AMD3DNOW_HIGH_IDX)
770 goto not;
771 unsigned int idx
772 = amd3dnow[AMD3DNOW_IDX (*param_start)];
773 if (idx == 0)
774 goto not;
775 str = amd3dnowstr + idx - 1;
776 /* Eat the immediate byte indicating the
777 operation. */
778 ++param_start;
779 break;
780 }
Ulrich Drepperff993222008-01-09 05:39:28 +0000781#ifdef X86_64
782 if (data[1] == 0xc7)
783 {
784 str = ((prefixes & has_rex_w)
785 ? "cmpxchg16b" : "cmpxchg8b");
786 break;
787 }
788#endif
789 if (data[1] == 0xc2)
790 {
791 if (param_start >= end)
792 goto not;
793 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 char *cp = stpcpy (mnebuf, cmpops[*param_start]);
807 if (correct_prefix & (has_rep | has_repne))
808 *cp++ = 's';
809 else
810 *cp++ = 'p';
811 if (correct_prefix & (has_data16 | has_repne))
812 *cp++ = 'd';
813 else
814 *cp++ = 's';
815 *cp = '\0';
816 str = mnebuf;
817 /* Eat the immediate byte indicating the
818 operation. */
819 ++param_start;
820 break;
821 }
822
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000823 default:
Ulrich Drepper515d8d72008-01-03 07:41:03 +0000824 assert (! "INVALID not handled");
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000825 }
826 }
827 else
828 str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
829
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500830 if (deferred_start != NULL)
831 {
832 ADD_NSTRING (deferred_start, deferred_len);
833 non_printing += deferred_len;
834 }
835
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000836 ADD_STRING (str);
837
838 switch (instrtab[cnt].suffix)
839 {
840 case suffix_none:
841 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000842
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000843 case suffix_w:
844 if ((codep[-1] & 0xc0) != 0xc0)
845 {
846 char ch;
847
848 if (data[0] & 1)
849 {
850 if (prefixes & has_data16)
851 ch = 'w';
Ulrich Drepper96a73992008-01-11 06:17:06 +0000852#ifdef X86_64
853 else if (prefixes & has_rex_w)
854 ch = 'q';
855#endif
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000856 else
857 ch = 'l';
858 }
859 else
860 ch = 'b';
861
862 ADD_CHAR (ch);
863 }
864 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000865
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000866 case suffix_w0:
867 if ((codep[-1] & 0xc0) != 0xc0)
868 ADD_CHAR ('l');
869 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000870
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000871 case suffix_w1:
872 if ((data[0] & 0x4) == 0)
873 ADD_CHAR ('l');
874 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000875
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000876 case suffix_W:
877 if (prefixes & has_data16)
878 {
879 ADD_CHAR ('w');
880 prefixes &= ~has_data16;
881 }
Ulrich Drepperff993222008-01-09 05:39:28 +0000882#ifdef X86_64
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000883 else
Ulrich Drepperff993222008-01-09 05:39:28 +0000884 ADD_CHAR ('q');
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000885#endif
886 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000887
Ulrich Drepperff993222008-01-09 05:39:28 +0000888 case suffix_W1:
889 if (prefixes & has_data16)
890 {
891 ADD_CHAR ('w');
892 prefixes &= ~has_data16;
893 }
894#ifdef X86_64
895 else if (prefixes & has_rex_w)
896 ADD_CHAR ('q');
897#endif
898 break;
899
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000900 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 ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
907 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000908
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000909 case suffix_D:
910 if ((codep[-1] & 0xc0) != 0xc0)
911 ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
912 break;
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000913
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000914 default:
915 printf("unknown suffix %d\n", instrtab[cnt].suffix);
916 abort ();
917 }
918
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500919 if (deferred_start != NULL)
920 {
921 ADD_STRING (color_off);
922 non_printing += strlen (color_off);
923 }
924
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000925 string_end_idx = bufcnt;
926 break;
927
928 case 'o':
929 if (prec == 1 && instrtab[cnt].fct1 != 0)
930 {
931 /* First parameter. */
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500932 if (deferred_start != NULL)
933 {
934 ADD_NSTRING (deferred_start, deferred_len);
935 non_printing += deferred_len;
936 }
937
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000938 if (instrtab[cnt].str1 != 0)
Ulrich Drepper71696ba2008-12-31 11:34:47 -0800939 ADD_STRING (op1_str
940 + op1_str_idx[instrtab[cnt].str1 - 1]);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000941
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000942 output_data.opoff1 = (instrtab[cnt].off1_1
943 + OFF1_1_BIAS - opoff);
944 output_data.opoff2 = (instrtab[cnt].off1_2
945 + OFF1_2_BIAS - opoff);
946 output_data.opoff3 = (instrtab[cnt].off1_3
947 + OFF1_3_BIAS - opoff);
948 int r = op1_fct[instrtab[cnt].fct1] (&output_data);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000949 if (r < 0)
950 goto not;
951 if (r > 0)
952 goto enomem;
953
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500954 if (deferred_start != NULL)
955 {
956 ADD_STRING (color_off);
957 non_printing += strlen (color_off);
958 }
959
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000960 string_end_idx = bufcnt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000961 }
962 else if (prec == 2 && instrtab[cnt].fct2 != 0)
963 {
964 /* Second parameter. */
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500965 if (deferred_start != NULL)
966 {
967 ADD_NSTRING (deferred_start, deferred_len);
968 non_printing += deferred_len;
969 }
970
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000971 if (instrtab[cnt].str2 != 0)
Ulrich Drepper71696ba2008-12-31 11:34:47 -0800972 ADD_STRING (op2_str
973 + op2_str_idx[instrtab[cnt].str2 - 1]);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000974
Ulrich Drepperd117ed82008-01-11 05:10:32 +0000975 output_data.opoff1 = (instrtab[cnt].off2_1
976 + OFF2_1_BIAS - opoff);
977 output_data.opoff2 = (instrtab[cnt].off2_2
978 + OFF2_2_BIAS - opoff);
979 output_data.opoff3 = (instrtab[cnt].off2_3
980 + OFF2_3_BIAS - opoff);
981 int r = op2_fct[instrtab[cnt].fct2] (&output_data);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000982 if (r < 0)
983 goto not;
984 if (r > 0)
985 goto enomem;
986
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500987 if (deferred_start != NULL)
988 {
989 ADD_STRING (color_off);
990 non_printing += strlen (color_off);
991 }
992
Ulrich Drepper5eee1222008-01-11 10:12:18 +0000993 string_end_idx = bufcnt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +0000994 }
995 else if (prec == 3 && instrtab[cnt].fct3 != 0)
996 {
997 /* Third parameter. */
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500998 if (deferred_start != NULL)
999 {
1000 ADD_NSTRING (deferred_start, deferred_len);
1001 non_printing += deferred_len;
1002 }
1003
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001004 if (instrtab[cnt].str3 != 0)
Ulrich Drepper71696ba2008-12-31 11:34:47 -08001005 ADD_STRING (op3_str
1006 + op3_str_idx[instrtab[cnt].str3 - 1]);
Ulrich Dreppere219f1c2008-01-09 05:49:49 +00001007
Ulrich Drepperd117ed82008-01-11 05:10:32 +00001008 output_data.opoff1 = (instrtab[cnt].off3_1
1009 + OFF3_1_BIAS - opoff);
1010 output_data.opoff2 = (instrtab[cnt].off3_2
1011 + OFF3_2_BIAS - opoff);
Ulrich Dreppere219f1c2008-01-09 05:49:49 +00001012#ifdef OFF3_3_BITS
Ulrich Drepperd117ed82008-01-11 05:10:32 +00001013 output_data.opoff3 = (instrtab[cnt].off3_3
1014 + OFF3_3_BIAS - opoff);
Ulrich Dreppere219f1c2008-01-09 05:49:49 +00001015#else
Ulrich Drepperd117ed82008-01-11 05:10:32 +00001016 output_data.opoff3 = 0;
Ulrich Dreppere219f1c2008-01-09 05:49:49 +00001017#endif
Ulrich Drepperd117ed82008-01-11 05:10:32 +00001018 int r = op3_fct[instrtab[cnt].fct3] (&output_data);
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001019 if (r < 0)
1020 goto not;
1021 if (r > 0)
1022 goto enomem;
1023
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001024 if (deferred_start != NULL)
1025 {
1026 ADD_STRING (color_off);
1027 non_printing += strlen (color_off);
1028 }
1029
Ulrich Drepper5eee1222008-01-11 10:12:18 +00001030 string_end_idx = bufcnt;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001031 }
Ulrich Drepperfd479892008-01-12 03:06:47 +00001032 else
1033 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. */
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001042 while (bufcnt - non_printing < (size_t) width)
Ulrich Drepperfd479892008-01-12 03:06:47 +00001043 ADD_CHAR (' ');
1044 width = 0;
1045 break;
1046
1047 case 'l':
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001048 if (deferred_start != NULL)
1049 {
1050 ADD_NSTRING (deferred_start, deferred_len);
1051 non_printing += deferred_len;
1052 }
1053
Ulrich Drepperfd479892008-01-12 03:06:47 +00001054 if (output_data.labelbuf != NULL
1055 && output_data.labelbuf[0] != '\0')
1056 {
1057 ADD_STRING (output_data.labelbuf);
1058 output_data.labelbuf[0] = '\0';
1059 string_end_idx = bufcnt;
1060 }
1061 else if (output_data.symaddr_use != addr_none)
1062 {
1063 GElf_Addr symaddr = output_data.symaddr;
1064 if (output_data.symaddr_use >= addr_rel_symbolic)
1065 symaddr += addr + param_start - begin;
1066
1067 // XXX Lookup symbol based on symaddr
1068 const char *symstr = NULL;
Ulrich Drepperebe0fce2008-01-12 07:15:51 +00001069 if (symcb != NULL
1070 && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
1071 &output_data.labelbuf,
1072 &output_data.labelbufsize, symcbarg) == 0)
1073 symstr = output_data.labelbuf;
Ulrich Drepperfd479892008-01-12 03:06:47 +00001074
1075 size_t bufavail = bufsize - bufcnt;
1076 int r = 0;
1077 if (symstr != NULL)
Ulrich Drepperebe0fce2008-01-12 07:15:51 +00001078 r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
1079 symstr);
Ulrich Drepperfd479892008-01-12 03:06:47 +00001080 else if (output_data.symaddr_use == addr_abs_always
1081 || output_data.symaddr_use == addr_rel_always)
1082 r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
1083 (uint64_t) symaddr);
1084
Ulrich Drepper3bf57592009-01-01 18:52:05 -08001085 assert (r >= 0);
Ulrich Drepperfd479892008-01-12 03:06:47 +00001086 if ((size_t) r >= bufavail)
1087 goto enomem;
1088 bufcnt += r;
1089 string_end_idx = bufcnt;
1090
1091 output_data.symaddr_use = addr_none;
1092 }
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001093 if (deferred_start != NULL)
1094 {
1095 ADD_STRING (color_off);
1096 non_printing += strlen (color_off);
1097 }
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001098 break;
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001099
1100 default:
1101 abort ();
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001102 }
1103
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001104 deferred_start = NULL;
1105
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001106 /* Pad according to the specified width. */
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001107 while (bufcnt + prefix_size - non_printing < start_idx + width)
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001108 ADD_CHAR (' ');
1109 prefix_size = 0;
1110 }
1111
1112 if ((prefixes & SEGMENT_PREFIXES) != 0)
1113 goto print_prefix;
1114
Ulrich Drepper5eee1222008-01-11 10:12:18 +00001115 assert (string_end_idx != ~0ul);
1116 bufcnt = string_end_idx;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001117
1118 addr += param_start - begin;
1119 data = param_start;
1120
1121 goto out;
1122 }
1123
1124 /* Invalid (or at least unhandled) opcode. */
1125 if (prefixes != 0)
1126 goto print_prefix;
1127 assert (*startp == data);
1128 ++data;
1129 ADD_STRING ("(bad)");
1130 addr += data - begin;
1131
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001132 out:
Ulrich Drepper5eee1222008-01-11 10:12:18 +00001133 if (bufcnt == bufsize)
1134 goto enomem;
1135 buf[bufcnt] = '\0';
1136
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001137 *startp = data;
Ulrich Drepper5eee1222008-01-11 10:12:18 +00001138 retval = outcb (buf, bufcnt, outcbarg);
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +00001139 if (retval != 0)
1140 goto do_ret;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001141 }
1142
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +00001143 do_ret:
Ulrich Drepperfd479892008-01-12 03:06:47 +00001144 free (output_data.labelbuf);
Ulrich Drepper8a3ca3a2008-01-11 09:35:15 +00001145 if (buf != initbuf)
1146 free (buf);
1147
1148 return retval;
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001149}