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