xref: /openbsd/sys/arch/powerpc/ddb/db_disasm.c (revision a6445c1d)
1 /*	$OpenBSD: db_disasm.c,v 1.16 2014/04/26 06:17:26 jsg Exp $	*/
2 /*
3  * Copyright (c) 1996, 2001, 2003 Dale Rahn. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/proc.h>
28 #include <sys/systm.h>
29 
30 #include <machine/db_machdep.h>
31 
32 #include <ddb/db_access.h>
33 #include <ddb/db_sym.h>
34 #include <ddb/db_variables.h>
35 #include <ddb/db_interface.h>
36 #include <ddb/db_output.h>
37 
38 enum opf {
39 	Opf_INVALID,
40 	Opf_A,
41 	Opf_A0,
42 	Opf_B,
43 	Opf_BI,
44 	Opf_BI1,
45 	Opf_BO,
46 	Opf_CRM,
47 	Opf_D,
48 	Opf_S,
49 	Opf_FM,
50 	Opf_LK,
51 	Opf_RC,
52 	Opf_AA,
53 	Opf_LI,
54 	Opf_OE,
55 	Opf_SR,
56 	Opf_TO,
57 	Opf_SIMM,
58 	Opf_UIMM,
59 	Opf_d,
60 	Opf_crbA,
61 	Opf_crbB,
62 	Opf_crbD,
63 	Opf_crfD,
64 	Opf_crfS,
65 	Opf_spr,
66 	Opf_tbr,
67 
68 	Opf_BD,
69 	Opf_C,
70 
71 	Opf_NB,
72 
73 	Opf_sh,
74 	Opf_SH,
75 	Opf_mb,
76 	Opf_MB,
77 	Opf_ME,
78 };
79 
80 
81 struct db_field {
82 	char *name;
83 	enum opf opf;
84 } db_fields[] = {
85 	{ "A",		Opf_A },
86 	{ "A0",		Opf_A0 },
87 	{ "B",		Opf_B },
88 	{ "D",		Opf_D },
89 	{ "S",		Opf_S },
90 	{ "AA",		Opf_AA },
91 	{ "LI",		Opf_LI },
92 	{ "BD",		Opf_BD },
93 	{ "BI",		Opf_BI },
94 	{ "BI1",	Opf_BI1 },
95 	{ "BO",		Opf_BO },
96 	{ "CRM",	Opf_CRM },
97 	{ "FM",		Opf_FM },
98 	{ "LK",		Opf_LK },
99 	{ "MB",		Opf_MB },
100 	{ "ME",		Opf_ME },
101 	{ "NB",		Opf_NB },
102 	{ "OE",		Opf_OE },
103 	{ "RC",		Opf_RC },
104 	{ "SH",		Opf_SH },
105 	{ "SR",		Opf_SR },
106 	{ "TO",		Opf_TO },
107 	{ "SIMM",	Opf_SIMM },
108 	{ "UIMM",	Opf_UIMM },
109 	{ "crbA",	Opf_crbA },
110 	{ "crbB",	Opf_crbB },
111 	{ "crbD",	Opf_crbD },
112 	{ "crfD",	Opf_crfD },
113 	{ "crfS",	Opf_crfS },
114 	{ "d",		Opf_d },
115 	{ "mb",		Opf_mb },
116 	{ "sh",		Opf_sh },
117 	{ "spr",	Opf_spr },
118 	{ "tbr",	Opf_tbr },
119 	{ NULL,		0 }
120 };
121 
122 struct opcode {
123 	char *name;
124 	u_int32_t mask;
125 	u_int32_t code;
126 	char *decode_str;
127 };
128 
129 typedef u_int32_t instr_t;
130 typedef void (op_class_func) (u_int32_t addr, instr_t instr);
131 
132 u_int32_t extract_field(u_int32_t value, u_int32_t base, u_int32_t width);
133 void disasm_fields(u_int32_t addr, const struct opcode *popcode, instr_t instr,
134     char *disasm_str, size_t bufsize);
135 void disasm_process_field(u_int32_t addr, instr_t instr, char **ppfmt,
136     char *ppoutput, size_t bufsize);
137 void dis_ppc(u_int32_t addr, const struct opcode *opcodeset, instr_t instr);
138 
139 
140 op_class_func op_ill, op_base;
141 op_class_func op_cl_x13, op_cl_x1e, op_cl_x1f;
142 op_class_func op_cl_x3a, op_cl_x3b;
143 op_class_func op_cl_x3e, op_cl_x3f;
144 
145 op_class_func *opcodes_base[] = {
146 /*x00*/	op_ill,		op_ill,		op_base,	op_ill,
147 /*x04*/	op_ill,		op_ill,		op_ill,		op_base,
148 /*x08*/	op_base,	op_base,	op_base,	op_base,
149 /*x0C*/	op_base,	op_base,	op_base/*XXX*/,	op_base/*XXX*/,
150 /*x10*/	op_base,	op_base,	op_base,	op_cl_x13,
151 /*x14*/	op_base,	op_base,	op_ill,		op_base,
152 /*x18*/	op_base,	op_base,	op_base,	op_base,
153 /*x1C*/	op_base,	op_base,	op_cl_x1e,	op_cl_x1f,
154 /*x20*/	op_base,	op_base,	op_base,	op_base,
155 /*x24*/	op_base,	op_base,	op_base,	op_base,
156 /*x28*/	op_base,	op_base,	op_base,	op_base,
157 /*x2C*/	op_base,	op_base,	op_base,	op_base,
158 /*x30*/	op_base,	op_base,	op_base,	op_base,
159 /*x34*/	op_base,	op_base,	op_base,	op_base,
160 /*x38*/	op_ill,		op_ill,		op_cl_x3a,	op_cl_x3b,
161 /*x3C*/	op_ill,		op_ill,		op_cl_x3e,	op_cl_x3f
162 };
163 
164 
165 /* This table could be modified to make significant the "reserved" fields
166  * of the opcodes, But I didn't feel like it when typing in the table,
167  * I would recommend that this table be looked over for errors,
168  * This was derived from the table in Appendix A.2 of (Mot part # MPCFPE/AD)
169  * PowerPC Microprocessor Family: The Programming Environments
170  */
171 
172 const struct opcode opcodes[] = {
173 	{ "tdi",	0xfc000000, 0x08000000, " %{TO},%{A},%{SIMM}" },
174 	{ "twi",	0xfc000000, 0x0c000000, " %{TO},%{A},%{SIMM}" },
175 
176 	{ "mulli",	0xfc000000, 0x1c000000, " %{D},%{A},%{SIMM}" },
177 	{ "subfic",	0xfc000000, 0x20000000, " %{D},%{A},%{SIMM}" },
178 	{ "cmpli",	0xff800000, 0x28000000, " %{A},%{UIMM}" },
179 	{ "cmpli",	0xfc400000, 0x28000000, " %{crfD}%{A}, %{UIMM}" },
180 	{ "cmpi",	0xff800000, 0x2c000000, " %{A},%{SIMM}"},
181 	{ "cmpi",	0xfc400000, 0x2c000000, " %{crfD}%{A},%{SIMM}" },
182 	{ "addic",	0xfc000000, 0x30000000, " %{D},%{A},%{SIMM}" },
183 	{ "addic.",	0xfc000000, 0x34000000, " %{D},%{A},%{SIMM}" },
184 	{ "addi",	0xfc000000, 0x38000000, " %{D},%{A0}%{SIMM}" },
185 	{ "addis",	0xfc000000, 0x3c000000, " %{D},%{A0}%{SIMM}" },
186 	{ "sc",		0xffffffff, 0x44000002, "" },
187 	{ "b",		0xfc000000, 0x40000000, "%{BO}%{LK}%{AA} %{BI}%{BD}" },
188 	{ "b",		0xfc000000, 0x48000000, "%{LK}%{AA} %{LI}" },
189 
190 	{ "rlwimi",	0xfc000000, 0x50000000, "%{RC} %{A},%{S},%{SH},%{MB},%{ME}" },
191 	{ "rlwinm",	0xfc000000, 0x54000000, "%{RC} %{A},%{S},%{SH},%{MB},%{ME}" },
192 	{ "rlwnm",	0xfc000000, 0x5c000000, "%{RC} %{A},%{S},%{SH},%{MB},%{ME}" },
193 
194 	{ "ori",	0xfc000000, 0x60000000, " %{A},%{S},%{UIMM}" },
195 	{ "oris",	0xfc000000, 0x64000000, " %{A},%{S},%{UIMM}" },
196 	{ "xori",	0xfc000000, 0x68000000, " %{A},%{S},%{UIMM}" },
197 	{ "xoris",	0xfc000000, 0x6c000000, " %{A},%{S},%{UIMM}" },
198 
199 	{ "andi.",	0xfc000000, 0x70000000, " %{A},%{S},%{UIMM}" },
200 	{ "andis.",	0xfc000000, 0x74000000, " %{A},%{S},%{UIMM}" },
201 
202 	{ "lwz",	0xfc000000, 0x80000000, " %{D},%{d}(%{A})" },
203 	{ "lwzu",	0xfc000000, 0x84000000, " %{D},%{d}(%{A})" },
204 	{ "lbz",	0xfc000000, 0x88000000, " %{D},%{d}(%{A})" },
205 	{ "lbzu",	0xfc000000, 0x8c000000, " %{D},%{d}(%{A})" },
206 	{ "stw",	0xfc000000, 0x90000000, " %{S},%{d}(%{A})" },
207 	{ "stwu",	0xfc000000, 0x94000000, " %{S},%{d}(%{A})" },
208 	{ "stb",	0xfc000000, 0x98000000, " %{S},%{d}(%{A})" },
209 	{ "stbu",	0xfc000000, 0x9c000000, " %{S},%{d}(%{A})" },
210 
211 	{ "lhz",	0xfc000000, 0xa0000000, " %{D},%{d}(%{A})" },
212 	{ "lhzu",	0xfc000000, 0xa4000000, " %{D},%{d}(%{A})" },
213 	{ "lha",	0xfc000000, 0xa8000000, " %{D},%{d}(%{A})" },
214 	{ "lhau",	0xfc000000, 0xac000000, " %{D},%{d}(%{A})" },
215 	{ "sth",	0xfc000000, 0xb0000000, " %{S},%{d}(%{A})" },
216 	{ "sthu",	0xfc000000, 0xb4000000, " %{S},%{d}(%{A})" },
217 	{ "lmw",	0xfc000000, 0xb8000000, " %{D},%{d}(%{A})" },
218 	{ "stmw",	0xfc000000, 0xbc000000, " %{S},%{d}(%{A})" },
219 
220 	{ "lfs",	0xfc000000, 0xc0000000, " %{D},%{d}(%{A})" },
221 	{ "lfsu",	0xfc000000, 0xc4000000, " %{D},%{d}(%{A})" },
222 	{ "lfd",	0xfc000000, 0xc8000000, " %{D},%{d}(%{A})" },
223 	{ "lfdu",	0xfc000000, 0xcc000000, " %{D},%{d}(%{A})" },
224 
225 	{ "stfs",	0xfc000000, 0xd0000000, " %{S},%{d}(%{A})" },
226 	{ "stfsu",	0xfc000000, 0xd4000000, " %{S},%{d}(%{A})" },
227 	{ "stfd",	0xfc000000, 0xd8000000, " %{S},%{d}(%{A})" },
228 	{ "stfdu",	0xfc000000, 0xdc000000, " %{S},%{d}(%{A})" },
229 	{ "",		0x0,		0x0, "" }
230 
231 };
232 
233 /* 13 * 4 = 4c */
234 const struct opcode opcodes_13[] = {
235 /* 0x13 << 2 */
236 	{ "mcrf",	0xfc0007fe, 0x4c000000, " %{crfD},%{crfS}" },
237 	{ "b",/*bclr*/	0xfc0007fe, 0x4c000020, "%{BO}lr%{LK} %{BI1}" },
238 	{ "crnor",	0xfc0007fe, 0x4c000042, " %{crbD},%{crbA},%{crbB}" },
239 	{ "rfi",	0xfc0007fe, 0x4c000064, "" },
240 	{ "crandc",	0xfc0007fe, 0x4c000102, " %{crbD},%{crbA},%{crbB}" },
241 	{ "isync",	0xfc0007fe, 0x4c00012c, "" },
242 	{ "crxor",	0xfc0007fe, 0x4c000182, " %{crbD},%{crbA},%{crbB}" },
243 	{ "crnand",	0xfc0007fe, 0x4c0001c2, " %{crbD},%{crbA},%{crbB}" },
244 	{ "crand",	0xfc0007fe, 0x4c000202, " %{crbD},%{crbA},%{crbB}" },
245 	{ "creqv",	0xfc0007fe, 0x4c000242, " %{crbD},%{crbA},%{crbB}" },
246 	{ "crorc",	0xfc0007fe, 0x4c000342, " %{crbD},%{crbA},%{crbB}" },
247 	{ "cror",	0xfc0007fe, 0x4c000382, " %{crbD},%{crbA},%{crbB}" },
248 	{ "b"/*bcctr*/,	0xfc0007fe, 0x4c000420, "%{BO}ctr%{LK} %{BI1}" },
249 	{ "",		0x0,		0x0, "" }
250 };
251 
252 /* 1e * 4 = 78 */
253 const struct opcode opcodes_1e[] = {
254 	{ "rldicl",	0xfc00001c, 0x78000000, " %{A},%{S},%{sh},%{mb}" },
255 	{ "rldicr",	0xfc00001c, 0x78000004, " %{A},%{S},%{sh},%{mb}" },
256 	{ "rldic",	0xfc00001c, 0x78000008, " %{A},%{S},%{sh},%{mb}" },
257 	{ "rldimi",	0xfc00001c, 0x7800000c, " %{A},%{S},%{sh},%{mb}" },
258 	{ "rldcl",	0xfc00003e, 0x78000010, " %{A},%{S},%{B},%{mb}" },
259 	{ "rldcr",	0xfc00003e, 0x78000012, " %{A},%{S},%{B},%{mb}" },
260 	{ "",		0x0,		0x0, "" }
261 };
262 
263 /* 1f * 4 = 7c */
264 const struct opcode opcodes_1f[] = {
265 /* 1f << 2 */
266 	{ "cmpd",	0xfc2007fe, 0x7c200000, " %{crfD}%{A},%{B}" },
267 	{ "cmpw",	0xfc2007fe, 0x7c000000, " %{crfD}%{A},%{B}" },
268 	{ "tw",		0xfc0007fe, 0x7c000008, " %{TO},%{A},%{B}" },
269 	{ "subfc",	0xfc0003fe, 0x7c000010, "%{OE}%{RC} %{D},%{A},%{B}" },
270 	{ "mulhdu",	0xfc0007fe, 0x7c000012, "%{RC} %{D},%{A},%{B}" },
271 	{ "addc",	0xfc0003fe, 0x7c000014, "%{OE}%{RC} %{D},%{A},%{B}" },
272 	{ "mulhwu",	0xfc0007fe, 0x7c000016, "%{RC} %{D},%{A},%{B}" },
273 
274 	{ "mfcr",	0xfc0007fe, 0x7c000026, " %{D}" },
275 	{ "lwarx",	0xfc0007fe, 0x7c000028, " %{D},%{A0}%{B}" },
276 	{ "ldx",	0xfc0007fe, 0x7c00002a, " %{D},%{A0}%{B}" },
277 	{ "lwzx",	0xfc0007fe, 0x7c00002e, " %{D},%{A0}%{B}" },
278 	{ "slw",	0xfc0007fe, 0x7c000030, "%{RC} %{A},%{S},%{B}" },
279 	{ "cntlzw",	0xfc0007fe, 0x7c000034, "%{RC} %{A},%{S}" },
280 	{ "sld",	0xfc0007fe, 0x7c000036, "%{RC} %{A},%{S},%{B}" },
281 	{ "and",	0xfc0007fe, 0x7c000038, "%{RC} %{A},%{S},%{B}" },
282 	{ "cmpld",	0xfc2007fe, 0x7c200040, " %{crfD}%{A},%{B}" },
283 	{ "cmplw",	0xfc2007fe, 0x7c000040, " %{crfD}%{A},%{B}" },
284 	{ "subf",	0xfc0003fe, 0x7c000050, "%{OE}%{RC} %{D},%{A},%{B}" },
285 	{ "ldux",	0xfc0007fe, 0x7c00006a, " %{D},%{A},%{B}" },
286 	{ "dcbst",	0xfc0007fe, 0x7c00006c, " %{A0}%{B}" },
287 	{ "lwzux",	0xfc0007fe, 0x7c00006e, " %{D},%{A},%{B}" },
288 	{ "cntlzd",	0xfc0007fe, 0x7c000074, "%{RC} %{A},%{S}" },
289 	{ "andc",	0xfc0007fe, 0x7c000078, "%{RC} %{A},%{S},%{B}" },
290 	{ "td",		0xfc0007fe, 0x7c000088, " %{TO},%{A},%{B}" },
291 	{ "mulhd",	0xfc0007fe, 0x7c000092, "%{RC} %{D},%{A},%{B}" },
292 	{ "mulhw",	0xfc0007fe, 0x7c000096, "%{RC} %{D},%{A},%{B}" },
293 	{ "mfmsr",	0xfc0007fe, 0x7c0000a6, " %{D}" },
294 	{ "ldarx",	0xfc0007fe, 0x7c0000a8, " %{D},%{A0}%{B}" },
295 	{ "dcbf",	0xfc0007fe, 0x7c0000ac, " %{A0}%{B}" },
296 	{ "lbzx",	0xfc0007fe, 0x7c0000ae, " %{D},%{A0}%{B}" },
297 	{ "neg",	0xfc0003fe, 0x7c0000d0, "%{OE}%{RC} %{D},%{A}" },
298 	{ "lbzux",	0xfc0007fe, 0x7c0000ee, " %{D},%{A},%{B}" },
299 	{ "nor",	0xfc0007fe, 0x7c0000f8, "%{RC} %{A},%{S}" },
300 	{ "subfe",	0xfc0003fe, 0x7c000110, "%{OE}%{RC} %{D},%{A}" },
301 	{ "adde",	0xfc0003fe, 0x7c000114, "%{OE}%{RC} %{D},%{A}" },
302 	{ "mtcrf",	0xfc0007fe, 0x7c000120, " %{S},%{CRM}" },
303 	{ "mtmsr",	0xfc0007fe, 0x7c000124, " %{S}" },
304 	{ "stdx",	0xfc0007fe, 0x7c00012a, " %{S},%{A0}%{B}" },
305 	{ "stwcx.",	0xfc0007ff, 0x7c00012d, " %{S},%{A},%{B}" },
306 	{ "stwx",	0xfc0007fe, 0x7c00012e, " %{S},%{A},%{B}" },
307 	{ "stdux",	0xfc0007fe, 0x7c00016a, " %{S},%{A},%{B}" },
308 	{ "stwux",	0xfc0007fe, 0x7c00016e, " %{S},%{A},%{B}" },
309 	{ "subfze",	0xfc0003fe, 0x7c000190, "%{OE}%{RC} %{D},%{A}" },
310 	{ "addze",	0xfc0003fe, 0x7c000194, "%{OE}%{RC} %{D},%{A}" },
311 	{ "mtsr",	0xfc0007fe, 0x7c0001a4, " %{SR},%{S}" },
312 	{ "stdcx.",	0xfc0007ff, 0x7c0001ad, " %{S},%{A0}%{B}" },
313 	{ "stbx",	0xfc0007fe, 0x7c0001ae, " %{S},%{A0}%{B}" },
314 	{ "subfme",	0xfc0003fe, 0x7c0001d0, "%{OE}%{RC} %{D},%{A}" },
315 	{ "mulld",	0xfc0003fe, 0x7c0001d2, "%{OE}%{RC} %{D},%{A},%{B}" },
316 	{ "addme",	0xfc0003fe, 0x7c0001d4, "%{OE}%{RC} %{D},%{A}" },
317 	{ "mullw",	0xfc0003fe, 0x7c0001d6, "%{OE}%{RC} %{D},%{A},%{B}" },
318 	{ "mtsrin",	0xfc0007fe, 0x7c0001e4, " %{S},%{B}" },
319 	{ "dcbtst",	0xfc0007fe, 0x7c0001ec, " %{A0}%{B}" },
320 	{ "stbux",	0xfc0007fe, 0x7c0001ee, " %{S},%{A},%{B}" },
321 	{ "add",	0xfc0003fe, 0x7c000214, "" },
322 	{ "dcbt",	0xfc0007fe, 0x7c00022c, " %{A0}%{B}" },
323 	{ "lhzx",	0xfc0007ff, 0x7c00022e, " %{D},%{A0}%{B}" },
324 	{ "eqv",	0xfc0007fe, 0x7c000238, "%{RC} %{A},%{S},%{B}" },
325 	{ "tlbie",	0xfc0007fe, 0x7c000264, " %{B}" },
326 	{ "eciwx",	0xfc0007fe, 0x7c00026c, " %{D},%{A0}%{B}" },
327 	{ "lhzux",	0xfc0007fe, 0x7c00026e, " %{D},%{A},%{B}" },
328 	{ "xor",	0xfc0007fe, 0x7c000278, "%{RC} %{A},%{S},%{B}" },
329 	{ "mfspr",	0xfc0007fe, 0x7c0002a6, " %{D},%{spr}" },
330 	{ "lwax",	0xfc0007fe, 0x7c0002aa, " %{D},%{A0}%{B}" },
331 	{ "lhax",	0xfc0007fe, 0x7c0002ae, " %{D},%{A},%{B}" },
332 	{ "tlbia",	0xfc0007fe, 0x7c0002e4, "" },
333 	{ "mftb",	0xfc0007fe, 0x7c0002e6, " %{D},%{tbr}" },
334 	{ "lwaux",	0xfc0007fe, 0x7c0002ea, " %{D},%{A},%{B}" },
335 	{ "lhaux",	0xfc0007fe, 0x7c0002ee, " %{D},%{A},%{B}" },
336 	{ "sthx",	0xfc0007fe, 0x7c00032e, " %{S},%{A0}%{B}" },
337 	{ "orc",	0xfc0007fe, 0x7c000338, "%{RC} %{A},%{S},%{B}" },
338 	{ "ecowx",	0xfc0007fe, 0x7c00036c, "%{RC} %{S},%{A0}%{B}" },
339 	{ "slbie",	0xfc0007fc, 0x7c000364, " %{B}" },
340 	{ "sthux",	0xfc0007fe, 0x7c00036e, " %{S},%{A0}%{B}" },
341 	{ "or",		0xfc0007fe, 0x7c000378, "%{RC} %{A},%{S},%{B}" },
342 	{ "divdu",	0xfc0003fe, 0x7c000392, "%{OE}%{RC} %{S},%{A},%{B}" },
343 	{ "divwu",	0xfc0003fe, 0x7c000396, "%{OE}%{RC} %{S},%{A},%{B}" },
344 	{ "mtspr",	0xfc0007fe, 0x7c0003a6, " %{spr},%{S}" },
345 	{ "dcbi",	0xfc0007fe, 0x7c0003ac, " %{A0}%{B}" },
346 	{ "nand",	0xfc0007fe, 0x7c0003b8, "%{RC} %{A},%{S},%{B}" },
347 	{ "divd",	0xfc0003fe, 0x7c0003d2, "%{OE}%{RC} %{S},%{A},%{B}" },
348 	{ "divw",	0xfc0003fe, 0x7c0003d6, "%{OE}%{RC} %{S},%{A},%{B}" },
349 	{ "slbia",	0xfc0003fe, 0x7c0003e4, "%{OE}%{RC} %{S},%{A},%{B}" },
350 	{ "mcrxr",	0xfc0007fe, 0x7c000400, "crfD1" },
351 	{ "lswx",	0xfc0007fe, 0x7c00042a, " %{D},%{A0}%{B}" },
352 	{ "lwbrx",	0xfc0007fe, 0x7c00042c, " %{D},%{A0}%{B}" },
353 	{ "lfsx",	0xfc0007fe, 0x7c00042e, " %{D},%{A},%{B}" },
354 	{ "srw",	0xfc0007fe, 0x7c000430, "%{RC} %{A},%{S},%{B}" },
355 	{ "srd",	0xfc0007fe, 0x7c000436, "%{RC} %{A},%{S},%{B}" },
356 	{ "tlbsync",	0xffffffff, 0x7c00046c, "" },
357 	{ "lfsux",	0xfc0007fe, 0x7c00046e, " %{D},%{A},%{B}" },
358 	{ "mfsr",	0xfc0007fe, 0x7c0004a6, " %{D},%{SR}" },
359 	{ "lswi",	0xfc0007fe, 0x7c0004aa, " %{D},%{A},%{NB}" },
360 	{ "sync",	0xfc0007fe, 0x7c0004ac, "" },
361 	{ "lfdx",	0xfc0007fe, 0x7c0004ae, " %{D},%{A},%{B}" },
362 	{ "lfdux",	0xfc0007fe, 0x7c0004ee, " %{D},%{A},%{B}" },
363 	{ "mfsrin",	0xfc0007fe, 0x7c000526, "" },
364 	{ "stswx",	0xfc0007fe, 0x7c00052a, " %{S},%{A0}%{B}" },
365 	{ "stwbrx",	0xfc0007fe, 0x7c00052c, " %{S},%{A0}%{B}" },
366 	{ "stfsx",	0xfc0007fe, 0x7c00052e, " %{S},%{A0}%{B}" },
367 	{ "stfsux",	0xfc0007fe, 0x7c00056e, " %{S},%{A},%{B}" },
368 	{ "stswi",	0xfc0007fe, 0x7c0005aa, "%{S},%{A0}%{NB}" },
369 	{ "stfdx",	0xfc0007fe, 0x7c0005ae, " %{S},%{A0}%{B}" },
370 	{ "stfdux",	0xfc0007fe, 0x7c0005ee, " %{S},%{A},%{B}" },
371 	{ "lhbrx",	0xfc0007fe, 0x7c00062c, " %{D},%{A0}%{B}" },
372 	{ "sraw",	0xfc0007fe, 0x7c000630, " %{A},%{S},%{B}" },
373 	{ "srad",	0xfc0007fe, 0x7c000634, "%{RC} %{A},%{S},%{B}" },
374 	{ "srawi",	0xfc0007fe, 0x7c000670, "%{RC} %{A},%{SH}" },
375 	{ "sradi",	0xfc0007fc, 0x7c000674, " %{A},%{S},%{sh}" },
376 	{ "eieio",	0xfc0007fe, 0x7c0006ac, "" }, /* MASK? */
377 	{ "sthbrx",	0xfc0007fe, 0x7c00072c, " %{S},%{A0}%{B}" },
378 	{ "extsh",	0xfc0007fe, 0x7c000734, "%{RC} %{A},%{S}" },
379 	{ "extsb",	0xfc0007fe, 0x7c000774, "%{RC} %{A},%{S}" },
380 	{ "icbi",	0xfc0007fe, 0x7c0007ac, " %{A0}%{B}" },
381 
382 	{ "stfiwx",	0xfc0007fe, 0x7c0007ae, " %{S},%{A0}%{B}" },
383 	{ "extsw",	0xfc0007fe, 0x7c0007b4, "%{RC} %{A},%{S}" },
384 	{ "dcbz",	0xfc0007fe, 0x7c0007ec, " %{A0}%{B}" },
385 	{ "",		0x0,		0x0, 0, }
386 };
387 
388 /* 3a * 4 = e8 */
389 const struct opcode opcodes_3a[] = {
390 	{ "ld",		0xfc000003, 0xe8000000, " %{D},${ds}${A}" },
391 	{ "ldu",	0xfc000003, 0xe8000001, " %{D},${ds}${A}" },
392 	{ "lwa",	0xfc000003, 0xe8000002, " %{D},${ds}${A}" },
393 	{ "",		0x0,		0x0, "" }
394 };
395 
396 /* 3b * 4 = ec */
397 const struct opcode opcodes_3b[] = {
398 	{ "fdivs",	0xfc00003e, 0xec000024, "%{RC} f%{D},f%{A},f%{B}" },
399 	{ "fsubs",	0xfc00003e, 0xec000028, "%{RC} f%{D},f%{A},f%{B}" },
400 
401 	{ "fadds",	0xfc00003e, 0xec00002a, "%{RC} f%{D},f%{A},f%{B}" },
402 	{ "fsqrts",	0xfc00003e, 0xec00002c, "" },
403 	{ "fres",	0xfc00003e, 0xec000030, "" },
404 	{ "fmuls",	0xfc00003e, 0xec000032, "%{RC} f%{D},f%{A},f%{C}" },
405 	{ "fmsubs",	0xfc00003e, 0xec000038, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
406 	{ "fmadds",	0xfc00003e, 0xec00003a, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
407 	{ "fnmsubs",	0xfc00003e, 0xec00003c, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
408 	{ "fnmadds",	0xfc00003e, 0xec00003e, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
409 	{ "",		0x0,		0x0, "" }
410 };
411 
412 /* 3e * 4 = f8 */
413 const struct opcode opcodes_3e[] = {
414 	{ "std",	0xfc000003, 0xf8000000, " %{D},${ds}${A}" },
415 	{ "stdu",	0xfc000003, 0xf8000001, " %{D},${ds}${A}" },
416 	{ "",		0x0,		0x0, "" }
417 };
418 
419 /* 3f * 4 = fc */
420 const struct opcode opcodes_3f[] = {
421 	{ "fcmpu",	0xfc0007fe, 0xfc000000, " %{crfD},f%{A},f%{B}" },
422 	{ "frsp",	0xfc0007fe, 0xfc000018, "%{RC} f%{D},f%{B}" },
423 	{ "fctiw",	0xfc0007fe, 0xfc00001c, "%{RC} f%{D},f%{B}" },
424 	{ "fctiwz",	0xfc0007fe, 0xfc00001e, "%{RC} f%{D},f%{B}" },
425 
426 	{ "fdiv",	0xfc00003e, 0xfc000024, "%{RC} f%{D},f%{A},f%{B}" },
427 	{ "fsub",	0xfc00003e, 0xfc000028, "%{RC} f%{D},f%{A},f%{B}" },
428 	{ "fadd",	0xfc00003e, 0xfc00002a, "%{RC} f%{D},f%{A},f%{B}" },
429 	{ "fsqrt",	0xfc00003e, 0xfc00002c, "%{RC} f%{D},f%{B}" },
430 	{ "fsel",	0xfc00003e, 0xfc00002e, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
431 	{ "fmul",	0xfc00003e, 0xfc000032, "%{RC} f%{D},f%{A},f%{C}" },
432 	{ "frsqrte",	0xfc00003e, 0xfc000034, "%{RC} f%{D},f%{B}" },
433 	{ "fmsub",	0xfc00003e, 0xfc000038, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
434 	{ "fmadd",	0xfc00003e, 0xfc00003a, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
435 	{ "fnmsub",	0xfc00003e, 0xfc00003c, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
436 	{ "fnmadd",	0xfc00003e, 0xfc00003e, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
437 
438 	{ "fcmpo",	0xfc0007fe, 0xfc000040, "%{RC} f%{D},f%{A},f%{C}" },
439 	{ "mtfsb1",	0xfc0007fe, 0xfc00004c, "%{RC} f%{D},f%{A},f%{C}" },
440 	{ "fneg",	0xfc0007fe, 0xfc000050, "%{RC} f%{D},f%{A},f%{C}" },
441 	{ "mcrfs",	0xfc0007fe, 0xfc000080, "%{RC} f%{D},f%{A},f%{C}" },
442 	{ "mtfsb0",	0xfc0007fe, 0xfc00008c, "%{RC} %{crfD},f%{C}" },
443 	{ "fmr",	0xfc0007fe, 0xfc000090, "%{RC} f%{D},f%{B}" },
444 	{ "mtfsfi",	0xfc0007fe, 0xfc00010c, "%{RC} %{crfD},f%{C},%{IMM}" },
445 
446 	{ "fnabs",	0xfc0007fe, 0xfc000110, "%{RC} f%{D},f%{B}" },
447 	{ "fabs",	0xfc0007fe, 0xfc000210, "%{RC} f%{D},f%{B}" },
448 	{ "mffs",	0xfc0007fe, 0xfc00048e, "%{RC} f%{D},f%{B}" },
449 	{ "mtfsf",	0xfc0007fe, 0xfc00058e, "%{RC} %{FM},f%{B}" },
450 	{ "fctid",	0xfc0007fe, 0xfc00065c, "%{RC} f%{D},f%{B}" },
451 	{ "fctidz",	0xfc0007fe, 0xfc00065e, "%{RC} f%{D},f%{B}" },
452 	{ "fcfid",	0xfc0007fe, 0xfc00069c, "%{RC} f%{D},f%{B}" },
453 	{ "",		0x0,		0x0, "" }
454 };
455 
456 void
457 op_ill(u_int32_t addr, instr_t instr)
458 {
459 	db_printf("illegal instruction %x\n", instr);
460 }
461 
462 /*
463  * Extracts bits out of an instruction opcode, base indicates the lsb
464  * to keep.
465  * Note that this uses the PowerPC bit number for base, MSb == 0
466  * because all of the documentation is written that way.
467  */
468 u_int32_t
469 extract_field(u_int32_t value, u_int32_t base, u_int32_t width)
470 {
471 	u_int32_t mask = (1 << width) - 1;
472 	return ((value >> (31 - base)) & mask);
473 }
474 
475 const struct opcode * search_op(const struct opcode *);
476 
477 char *db_BOBI_cond[] = {
478 	"ge",
479 	"le",
480 	"ne",
481 	"ns",
482 	"lt",
483 	"gt",
484 	"eq",
485 	"so"
486 };
487 /* what about prediction directions? */
488 char *db_BO_op[] = {
489 	"dnzf",
490 	"dnzf-",
491 	"dzf",
492 	"dzf-",
493 	"",
494 	"",
495 	"",
496 	"",
497 	"dnzt",
498 	"dnzt-",
499 	"dzt",
500 	"dzt-",
501 	"",
502 	"",
503 	"",
504 	"",
505 	"dnz",
506 	"dnz",
507 	"dz",
508 	"dz",
509 	"",
510 	"",
511 	"",
512 	"",
513 	"dnz",
514 	"dnz",
515 	"dz",
516 	"dz",
517 	"",
518 	"",
519 	"",
520 	""
521 };
522 
523 char *BItbl[] = {
524 	"", "gt", "eq", "so"
525 };
526 
527 char BO_uses_tbl[32] = {
528 	/* 0 */ 1,
529 	/* 1 */ 1,
530 	/* 2 */ 1,
531 	/* 3 */ 1,
532 	/* 4 */ 0,
533 	/* 5 */ 0,
534 	/* 6 */ 0, /* invalid */
535 	/* 7 */ 0, /* invalid */
536 	/* 8 */ 1,
537 	/* 9 */ 1,
538 	/* a */ 1,
539 	/* b */ 1,
540 	/* c */ 0,
541 	/* d */ 0,
542 	/* e */ 0, /* invalid */
543 	/* f */ 1,
544 	/* 10 */        1,
545 	/* 11 */        1,
546 	/* 12 */        1,
547 	/* 13 */        1,
548 	/* 14 */        1,
549 	/* 15 */        0, /* invalid */
550 	/* 16 */        0, /* invalid */
551 	/* 17 */        0, /* invalid */
552 	/* 18 */        0, /* invalid */
553 	/* 19 */        0, /* invalid */
554 	/* 1a */        0, /* invalid */
555 	/* 1b */        0, /* invalid */
556 	/* 1c */        0, /* invalid */
557 	/* 1d */        0, /* invalid */
558 	/* 1e */        0, /* invalid */
559 	/* 1f */        0, /* invalid */
560 };
561 
562 void
563 disasm_process_field(u_int32_t addr, instr_t instr, char **ppfmt,
564     char *disasm_buf, size_t bufsize)
565 {
566 	char field [8];
567 	char lbuf[50];
568 	int i;
569 	char *pfmt = *ppfmt;
570 	enum opf opf;
571 	char *name;
572 	db_expr_t offset;
573 
574 	/* find field */
575 	if (pfmt[0] != '%' || pfmt[1] != '{') {
576 		printf("error in disasm fmt [%s]\n", pfmt);
577 	}
578 	pfmt = &pfmt[2];
579 	for (i = 0;
580 	    pfmt[i] != '\0' && pfmt[i] != '}' && i < sizeof(field);
581 	    i++) {
582 		field[i] = pfmt[i];
583 	}
584 	if (i == sizeof(field)) {
585 		printf("error in disasm fmt [%s]\n", pfmt);
586 		return;
587 	}
588 	field[i] = 0;
589 	if (pfmt[i] == '\0') {
590 		/* match following close paren { */
591 		printf("disasm_process_field: missing } in [%s]\n", pfmt);
592 	}
593 	*ppfmt = &pfmt[i+1];
594 	opf = Opf_INVALID;
595 	for (i = 0; db_fields[i].name != NULL; i++) {
596 		if (strcmp(db_fields[i].name, field) == 0) {
597 			opf = db_fields[i].opf;
598 			break;
599 		}
600 	}
601 	switch (opf) {
602 	case Opf_INVALID:
603 		{
604 			printf("unable to find variable [%s]\n", field);
605 		}
606 	case Opf_A:
607 		{
608 			u_int A;
609 			A = extract_field(instr, 15, 5);
610 			snprintf(lbuf, sizeof (lbuf), "r%d", A);
611 			strlcat (disasm_buf, lbuf, bufsize);
612 		}
613 		break;
614 	case Opf_A0:
615 		{
616 			u_int A;
617 			A = extract_field(instr, 15, 5);
618 			if (A != 0) {
619 				snprintf(lbuf, sizeof (lbuf), "r%d,", A);
620 				strlcat (disasm_buf, lbuf, bufsize);
621 			}
622 		}
623 		break;
624 	case Opf_AA:
625 		if (instr & 0x2) {
626 			strlcat (disasm_buf, "a", bufsize);
627 		}
628 		break;
629 	case Opf_LI:
630 		{
631 			u_int LI;
632 			LI = extract_field(instr, 29, 24);
633 			LI = LI << 2;
634 			if (LI & 0x02000000) {
635 				LI |= ~0x03ffffff;
636 			}
637 			if ((instr & (1 << 1)) == 0) {
638 				/* CHECK AA bit */
639 				LI = addr + LI;
640 			}
641 			db_find_sym_and_offset(LI, &name, &offset);
642 			if (name) {
643 				if (offset == 0) {
644 					snprintf(lbuf, sizeof (lbuf),
645 					    "0x%x (%s)", LI, name);
646 					strlcat (disasm_buf, lbuf, bufsize);
647 				} else {
648 					snprintf(lbuf, sizeof (lbuf),
649 					    "0x%x (%s+0x%lx)", LI, name,
650 					    offset);
651 					strlcat (disasm_buf, lbuf, bufsize);
652 				}
653 			} else {
654 				snprintf(lbuf, sizeof (lbuf), "0x%x", LI);
655 				strlcat (disasm_buf, lbuf, bufsize);
656 			}
657 		}
658 		break;
659 	case Opf_B:
660 		{
661 			u_int B;
662 			B = extract_field(instr, 20, 5);
663 			snprintf(lbuf, sizeof (lbuf), "r%d", B);
664 			strlcat (disasm_buf, lbuf, bufsize);
665 		}
666 		break;
667 	case Opf_BD:
668 		{
669 			u_int BD;
670 			BD = extract_field(instr, 29, 14);
671 			BD = BD << 2;
672 			if (BD & 0x00008000) {
673 				BD &= ~0x00007fff;
674 			}
675 			if ((instr & (1 << 1)) == 0) {
676 				/* CHECK AA bit */
677 				BD = addr + BD;
678 			}
679 			db_find_sym_and_offset(BD, &name, &offset);
680 			if (name) {
681 				if (offset == 0) {
682 					snprintf(lbuf, sizeof (lbuf),
683 					    "0x%x (%s)", BD, name);
684 					strlcat (disasm_buf, lbuf, bufsize);
685 				} else {
686 					snprintf(lbuf, sizeof (lbuf),
687 					    "0x%x (%s+0x%lx)", BD, name, offset);
688 					strlcat (disasm_buf, lbuf, bufsize);
689 				}
690 			} else {
691 				snprintf(lbuf, sizeof (lbuf), "0x%x", BD);
692 				strlcat (disasm_buf, lbuf, bufsize);
693 			}
694 		}
695 		break;
696 	case Opf_BI1:
697 	case Opf_BI:
698 		{
699 			int BO, BI, cr, printcomma = 0;
700 			BO = extract_field(instr, 10, 5);
701 			BI = extract_field(instr, 15, 5);
702 			cr =  (BI >> 2) & 7;
703 			if (cr != 0) {
704 				snprintf(lbuf, sizeof (lbuf), "cr%d", cr);
705 				strlcat (disasm_buf, lbuf, bufsize);
706 				printcomma = 1;
707 			}
708 			if (BO_uses_tbl[BO]) {
709 				if ((cr != 0) && ((BI & 3) != 0) &&
710 				    BO_uses_tbl[BO] != 0)
711 					strlcat (disasm_buf, "+", bufsize);
712 
713 				snprintf(lbuf, sizeof (lbuf), "%s",
714 				    BItbl[BI & 3]);
715 				strlcat (disasm_buf, lbuf, bufsize);
716 				printcomma = 1;
717 			}
718 			if ((opf == Opf_BI) && printcomma)
719 				strlcat (disasm_buf, ",", bufsize);
720 		}
721 		break;
722 	case Opf_BO:
723 		{
724 			int BO, BI;
725 			BO = extract_field(instr, 10, 5);
726 			strlcat (disasm_buf, db_BO_op[BO], bufsize);
727 			if ((BO & 4) != 0) {
728 				BI = extract_field(instr, 15, 5);
729 				strlcat (disasm_buf,
730 				    db_BOBI_cond[(BI & 0x3)| (((BO & 8) >> 1))],
731 				    bufsize);
732 
733 				if (BO & 1)
734 					strlcat (disasm_buf, "-", bufsize);
735 			}
736 		}
737 		break;
738 	case Opf_C:
739 		{
740 			u_int C;
741 			C = extract_field(instr, 25, 5);
742 			snprintf(lbuf, sizeof (lbuf), "r%d, ", C);
743 			strlcat (disasm_buf, lbuf, bufsize);
744 		}
745 		break;
746 	case Opf_CRM:
747 		{
748 			u_int CRM;
749 			CRM = extract_field(instr, 19, 8);
750 			snprintf(lbuf, sizeof (lbuf), "0x%x", CRM);
751 			strlcat (disasm_buf, lbuf, bufsize);
752 		}
753 		break;
754 	case Opf_FM:
755 		{
756 			u_int FM;
757 			FM = extract_field(instr, 10, 8);
758 			snprintf(lbuf, sizeof (lbuf), "%d", FM);
759 			strlcat (disasm_buf, lbuf, bufsize);
760 		}
761 		break;
762 	case Opf_LK:
763 		if (instr & 0x1) {
764 			strlcat (disasm_buf, "l", bufsize);
765 		}
766 		break;
767 	case Opf_MB:
768 		{
769 			u_int MB;
770 			MB = extract_field(instr, 20, 5);
771 			snprintf(lbuf, sizeof (lbuf), "%d", MB);
772 			strlcat (disasm_buf, lbuf, bufsize);
773 		}
774 		break;
775 	case Opf_ME:
776 		{
777 			u_int ME;
778 			ME = extract_field(instr, 25, 5);
779 			snprintf(lbuf, sizeof (lbuf), "%d", ME);
780 			strlcat (disasm_buf, lbuf, bufsize);
781 		}
782 		break;
783 	case Opf_NB:
784 		{
785 			u_int NB;
786 			NB = extract_field(instr, 20, 5);
787 			if (NB == 0 ) {
788 				NB=32;
789 			}
790 			snprintf(lbuf, sizeof (lbuf), "%d", NB);
791 			strlcat (disasm_buf, lbuf, bufsize);
792 		}
793 		break;
794 	case Opf_OE:
795 		if (instr & (1 << (31-21))) {
796 			strlcat (disasm_buf, "o", bufsize);
797 		}
798 		break;
799 	case Opf_RC:
800 		if (instr & 0x1) {
801 			strlcat (disasm_buf, ".", bufsize);
802 		}
803 		break;
804 	case Opf_S:
805 	case Opf_D:
806 		{
807 			u_int D;
808 			/* S and D are the same */
809 			D = extract_field(instr, 10, 5);
810 			snprintf(lbuf, sizeof (lbuf), "r%d", D);
811 			strlcat (disasm_buf, lbuf, bufsize);
812 		}
813 		break;
814 	case Opf_SH:
815 		{
816 			u_int SH;
817 			SH = extract_field(instr, 20, 5);
818 			snprintf(lbuf, sizeof (lbuf), "%d", SH);
819 			strlcat (disasm_buf, lbuf, bufsize);
820 		}
821 		break;
822 	case Opf_SIMM:
823 	case Opf_d:
824 		{
825 			int32_t IMM;
826 			IMM = extract_field(instr, 31, 16);
827 			if (IMM & 0x8000)
828 				IMM |= ~0x7fff;
829 			snprintf(lbuf, sizeof (lbuf), "%d", IMM);
830 			strlcat (disasm_buf, lbuf, bufsize);
831 		}
832 		break;
833 	case Opf_UIMM:
834 		{
835 			u_int32_t IMM;
836 			IMM = extract_field(instr, 31, 16);
837 			snprintf(lbuf, sizeof (lbuf), "0x%x", IMM);
838 			strlcat (disasm_buf, lbuf, bufsize);
839 		}
840 		break;
841 	case Opf_SR:
842 		{
843 			u_int SR;
844 			SR = extract_field(instr, 15, 3);
845 			snprintf(lbuf, sizeof (lbuf), "sr%d", SR);
846 			strlcat (disasm_buf, lbuf, bufsize);
847 		}
848 		break;
849 	case Opf_TO:
850 		{
851 			u_int TO;
852 			TO = extract_field(instr, 10, 1);
853 			snprintf(lbuf, sizeof (lbuf), "%d", TO);
854 			strlcat (disasm_buf, lbuf, bufsize);
855 		}
856 		break;
857 	case Opf_crbA:
858 		{
859 			u_int crbA;
860 			crbA = extract_field(instr, 15, 5);
861 			snprintf(lbuf, sizeof (lbuf), "%d", crbA);
862 			strlcat (disasm_buf, lbuf, bufsize);
863 		}
864 		break;
865 	case Opf_crbB:
866 		{
867 			u_int crbB;
868 			crbB = extract_field(instr, 20, 5);
869 			snprintf(lbuf, sizeof (lbuf), "%d", crbB);
870 			strlcat (disasm_buf, lbuf, bufsize);
871 		}
872 		break;
873 	case Opf_crbD:
874 		{
875 			u_int crfD;
876 			crfD = extract_field(instr, 8, 3);
877 			snprintf(lbuf, sizeof (lbuf), "crf%d", crfD);
878 			strlcat (disasm_buf, lbuf, bufsize);
879 		}
880 		break;
881 	case Opf_crfD:
882 		{
883 			u_int crfD;
884 			crfD = extract_field(instr, 8, 3);
885 			snprintf(lbuf, sizeof (lbuf), "crf%d", crfD);
886 			strlcat (disasm_buf, lbuf, bufsize);
887 		}
888 		break;
889 	case Opf_crfS:
890 		{
891 			u_int crfS;
892 			crfS = extract_field(instr, 13, 3);
893 			snprintf(lbuf, sizeof (lbuf), "%d", crfS);
894 			strlcat (disasm_buf, lbuf, bufsize);
895 		}
896 		break;
897 	case Opf_mb:
898 		{
899 			u_int mb, mbl, mbh;
900 			mbl = extract_field(instr, 25, 4);
901 			mbh = extract_field(instr, 26, 1);
902 			mb = mbh << 4 | mbl;
903 			snprintf(lbuf, sizeof (lbuf), ", %d", mb);
904 			strlcat (disasm_buf, lbuf, bufsize);
905 		}
906 		break;
907 	case Opf_sh:
908 		{
909 			u_int sh, shl, shh;
910 			shl = extract_field(instr, 19, 4);
911 			shh = extract_field(instr, 20, 1);
912 			sh = shh << 4 | shl;
913 			snprintf(lbuf, sizeof (lbuf), ", %d", sh);
914 			strlcat (disasm_buf, lbuf, bufsize);
915 		}
916 		break;
917 	case Opf_spr:
918 		{
919 			u_int spr;
920 			u_int sprl;
921 			u_int sprh;
922 			char *reg;
923 			sprl = extract_field(instr, 15, 5);
924 			sprh = extract_field(instr, 20, 5);
925 			spr = sprh << 5 | sprl;
926 
927 			/* this table could be written better */
928 			switch (spr) {
929 			case	1:
930 				reg = "xer";
931 				break;
932 			case	8:
933 				reg = "lr";
934 				break;
935 			case	9:
936 				reg = "ctr";
937 				break;
938 			case	18:
939 				reg = "dsisr";
940 				break;
941 			case	19:
942 				reg = "dar";
943 				break;
944 			case	22:
945 				reg = "dec";
946 				break;
947 			case	25:
948 				reg = "sdr1";
949 				break;
950 			case	26:
951 				reg = "srr0";
952 				break;
953 			case	27:
954 				reg = "srr1";
955 				break;
956 			case	272:
957 				reg = "SPRG0";
958 				break;
959 			case	273:
960 				reg = "SPRG1";
961 				break;
962 			case	274:
963 				reg = "SPRG3";
964 				break;
965 			case	275:
966 				reg = "SPRG3";
967 				break;
968 			case	280:
969 				reg = "asr";
970 				break;
971 			case	282:
972 				reg = "aer";
973 				break;
974 			case	287:
975 				reg = "pvr";
976 				break;
977 			case	528:
978 				reg = "ibat0u";
979 				break;
980 			case	529:
981 				reg = "ibat0l";
982 				break;
983 			case	530:
984 				reg = "ibat1u";
985 				break;
986 			case	531:
987 				reg = "ibat1l";
988 				break;
989 			case	532:
990 				reg = "ibat2u";
991 				break;
992 			case	533:
993 				reg = "ibat2l";
994 				break;
995 			case	534:
996 				reg = "ibat3u";
997 				break;
998 			case	535:
999 				reg = "ibat3l";
1000 				break;
1001 			case	536:
1002 				reg = "dbat0u";
1003 				break;
1004 			case	537:
1005 				reg = "dbat0l";
1006 				break;
1007 			case	538:
1008 				reg = "dbat1u";
1009 				break;
1010 			case	539:
1011 				reg = "dbat1l";
1012 				break;
1013 			case	540:
1014 				reg = "dbat2u";
1015 				break;
1016 			case	541:
1017 				reg = "dbat2l";
1018 				break;
1019 			case	542:
1020 				reg = "dbat3u";
1021 				break;
1022 			case	543:
1023 				reg = "dbat3l";
1024 				break;
1025 			case	1013:
1026 				reg = "dabr";
1027 				break;
1028 			default:
1029 				reg = 0;
1030 			}
1031 			if (reg == 0) {
1032 				snprintf(lbuf, sizeof (lbuf), "spr%d", spr);
1033 				strlcat (disasm_buf, lbuf, bufsize);
1034 			} else {
1035 				snprintf(lbuf, sizeof (lbuf), "%s", reg);
1036 				strlcat (disasm_buf, lbuf, bufsize);
1037 			}
1038 		}
1039 		break;
1040 	case Opf_tbr:
1041 		{
1042 			u_int tbr;
1043 			u_int tbrl;
1044 			u_int tbrh;
1045 			char *reg = NULL;
1046 			tbrl = extract_field(instr, 15, 5);
1047 			tbrh = extract_field(instr, 20, 5);
1048 			tbr = tbrh << 5 | tbrl;
1049 
1050 			switch (tbr) {
1051 			case 268:
1052 				reg = "tbl";
1053 				break;
1054 			case 269:
1055 				reg = "tbu";
1056 				break;
1057 			default:
1058 				reg = 0;
1059 			}
1060 			if (reg == NULL) {
1061 				snprintf(lbuf, sizeof (lbuf), "tbr%d", tbr);
1062 				strlcat (disasm_buf, lbuf, bufsize);
1063 			} else {
1064 				snprintf(lbuf, sizeof (lbuf), "%s", reg);
1065 				strlcat (disasm_buf, lbuf, bufsize);
1066 			}
1067 		}
1068 		break;
1069 	}
1070 }
1071 
1072 void
1073 disasm_fields(u_int32_t addr, const struct opcode *popcode, instr_t instr,
1074     char *disasm_str, size_t bufsize)
1075 {
1076 	char *pfmt;
1077 	char cbuf[2];
1078 	if (popcode->decode_str == NULL || popcode->decode_str[0] == '0') {
1079 		return;
1080 	}
1081 	pfmt = popcode->decode_str;
1082 	disasm_str[0] = '\0';
1083 
1084 	while (*pfmt != '\0')  {
1085 		if (*pfmt == '%') {
1086 			disasm_process_field(addr, instr, &pfmt, disasm_str,
1087 			    bufsize);
1088 		} else {
1089 			cbuf[0] = *pfmt;
1090 			cbuf[1] = '\0';
1091 			strlcat(disasm_str, cbuf, bufsize);
1092 			pfmt++;
1093 		}
1094 	}
1095 }
1096 
1097 void
1098 op_base(u_int32_t addr, instr_t instr)
1099 {
1100 	dis_ppc(addr, opcodes, instr);
1101 }
1102 
1103 void
1104 op_cl_x13(u_int32_t addr, instr_t instr)
1105 {
1106 	dis_ppc(addr, opcodes_13, instr);
1107 }
1108 
1109 void
1110 op_cl_x1e(u_int32_t addr, instr_t instr)
1111 {
1112 	dis_ppc(addr, opcodes_1e, instr);
1113 }
1114 
1115 void
1116 op_cl_x1f(u_int32_t addr, instr_t instr)
1117 {
1118 	dis_ppc(addr, opcodes_1f, instr);
1119 }
1120 
1121 void
1122 op_cl_x3a(u_int32_t addr, instr_t instr)
1123 {
1124 	dis_ppc(addr, opcodes_3a, instr);
1125 }
1126 
1127 void
1128 op_cl_x3b(u_int32_t addr, instr_t instr)
1129 {
1130 	dis_ppc(addr, opcodes_3b, instr);
1131 }
1132 
1133 void
1134 op_cl_x3e(u_int32_t addr, instr_t instr)
1135 {
1136 	dis_ppc(addr, opcodes_3e, instr);
1137 }
1138 
1139 void
1140 op_cl_x3f(u_int32_t addr, instr_t instr)
1141 {
1142 	dis_ppc(addr, opcodes_3f, instr);
1143 }
1144 
1145 void
1146 dis_ppc(u_int32_t addr, const struct opcode *opcodeset, instr_t instr)
1147 {
1148 	const struct opcode *op;
1149 	int i;
1150 	char disasm_str[80];
1151 
1152 	for (i=0; opcodeset[i].mask != 0; i++) {
1153 		op = &opcodeset[i];
1154 		if ((instr & op->mask) == op->code) {
1155 			disasm_fields(addr, op, instr, disasm_str,
1156 			    sizeof disasm_str);
1157 			db_printf("%s%s\n", op->name, disasm_str);
1158 			return;
1159 		}
1160 	}
1161 	op_ill(addr, instr);
1162 }
1163 
1164 db_addr_t
1165 db_disasm(db_addr_t loc, boolean_t extended)
1166 {
1167 	int class;
1168 	instr_t opcode;
1169 	opcode = *(instr_t *)(loc);
1170 	class = opcode >> 26;
1171 	(opcodes_base[class])(loc, opcode);
1172 
1173 	return loc + 4;
1174 }
1175