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