xref: /openbsd-src/sys/arch/powerpc/ddb/db_disasm.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: db_disasm.c,v 1.15 2007/10/21 17:30:18 drahn 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 		break;
898 	case Opf_mb:
899 		{
900 			u_int mb, mbl, mbh;
901 			mbl = extract_field(instr, 25, 4);
902 			mbh = extract_field(instr, 26, 1);
903 			mb = mbh << 4 | mbl;
904 			snprintf(lbuf, sizeof (lbuf), ", %d", mb);
905 			strlcat (disasm_buf, lbuf, bufsize);
906 		}
907 		break;
908 	case Opf_sh:
909 		{
910 			u_int sh, shl, shh;
911 			shl = extract_field(instr, 19, 4);
912 			shh = extract_field(instr, 20, 1);
913 			sh = shh << 4 | shl;
914 			snprintf(lbuf, sizeof (lbuf), ", %d", sh);
915 			strlcat (disasm_buf, lbuf, bufsize);
916 		}
917 		break;
918 	case Opf_spr:
919 		{
920 			u_int spr;
921 			u_int sprl;
922 			u_int sprh;
923 			char *reg;
924 			sprl = extract_field(instr, 15, 5);
925 			sprh = extract_field(instr, 20, 5);
926 			spr = sprh << 5 | sprl;
927 
928 			/* this table could be written better */
929 			switch (spr) {
930 			case	1:
931 				reg = "xer";
932 				break;
933 			case	8:
934 				reg = "lr";
935 				break;
936 			case	9:
937 				reg = "ctr";
938 				break;
939 			case	18:
940 				reg = "dsisr";
941 				break;
942 			case	19:
943 				reg = "dar";
944 				break;
945 			case	22:
946 				reg = "dec";
947 				break;
948 			case	25:
949 				reg = "sdr1";
950 				break;
951 			case	26:
952 				reg = "srr0";
953 				break;
954 			case	27:
955 				reg = "srr1";
956 				break;
957 			case	272:
958 				reg = "SPRG0";
959 				break;
960 			case	273:
961 				reg = "SPRG1";
962 				break;
963 			case	274:
964 				reg = "SPRG3";
965 				break;
966 			case	275:
967 				reg = "SPRG3";
968 				break;
969 			case	280:
970 				reg = "asr";
971 				break;
972 			case	282:
973 				reg = "aer";
974 				break;
975 			case	287:
976 				reg = "pvr";
977 				break;
978 			case	528:
979 				reg = "ibat0u";
980 				break;
981 			case	529:
982 				reg = "ibat0l";
983 				break;
984 			case	530:
985 				reg = "ibat1u";
986 				break;
987 			case	531:
988 				reg = "ibat1l";
989 				break;
990 			case	532:
991 				reg = "ibat2u";
992 				break;
993 			case	533:
994 				reg = "ibat2l";
995 				break;
996 			case	534:
997 				reg = "ibat3u";
998 				break;
999 			case	535:
1000 				reg = "ibat3l";
1001 				break;
1002 			case	536:
1003 				reg = "dbat0u";
1004 				break;
1005 			case	537:
1006 				reg = "dbat0l";
1007 				break;
1008 			case	538:
1009 				reg = "dbat1u";
1010 				break;
1011 			case	539:
1012 				reg = "dbat1l";
1013 				break;
1014 			case	540:
1015 				reg = "dbat2u";
1016 				break;
1017 			case	541:
1018 				reg = "dbat2l";
1019 				break;
1020 			case	542:
1021 				reg = "dbat3u";
1022 				break;
1023 			case	543:
1024 				reg = "dbat3l";
1025 				break;
1026 			case	1013:
1027 				reg = "dabr";
1028 				break;
1029 			default:
1030 				reg = 0;
1031 			}
1032 			if (reg == 0) {
1033 				snprintf(lbuf, sizeof (lbuf), "spr%d", spr);
1034 				strlcat (disasm_buf, lbuf, bufsize);
1035 			} else {
1036 				snprintf(lbuf, sizeof (lbuf), "%s", reg);
1037 				strlcat (disasm_buf, lbuf, bufsize);
1038 			}
1039 		}
1040 		break;
1041 	case Opf_tbr:
1042 		{
1043 			u_int tbr;
1044 			u_int tbrl;
1045 			u_int tbrh;
1046 			char *reg = NULL;
1047 			tbrl = extract_field(instr, 15, 5);
1048 			tbrh = extract_field(instr, 20, 5);
1049 			tbr = tbrh << 5 | tbrl;
1050 
1051 			switch (tbr) {
1052 			case 268:
1053 				reg = "tbl";
1054 				break;
1055 			case 269:
1056 				reg = "tbu";
1057 				break;
1058 			default:
1059 				reg = 0;
1060 			}
1061 			if (reg == NULL) {
1062 				snprintf(lbuf, sizeof (lbuf), "tbr%d", tbr);
1063 				strlcat (disasm_buf, lbuf, bufsize);
1064 			} else {
1065 				snprintf(lbuf, sizeof (lbuf), "%s", reg);
1066 				strlcat (disasm_buf, lbuf, bufsize);
1067 			}
1068 		}
1069 		break;
1070 	}
1071 }
1072 
1073 void
1074 disasm_fields(u_int32_t addr, const struct opcode *popcode, instr_t instr,
1075     char *disasm_str, size_t bufsize)
1076 {
1077 	char *pfmt;
1078 	char cbuf[2];
1079 	if (popcode->decode_str == NULL || popcode->decode_str[0] == '0') {
1080 		return;
1081 	}
1082 	pfmt = popcode->decode_str;
1083 	disasm_str[0] = '\0';
1084 
1085 	while (*pfmt != '\0')  {
1086 		if (*pfmt == '%') {
1087 			disasm_process_field(addr, instr, &pfmt, disasm_str,
1088 			    bufsize);
1089 		} else {
1090 			cbuf[0] = *pfmt;
1091 			cbuf[1] = '\0';
1092 			strlcat(disasm_str, cbuf, bufsize);
1093 			pfmt++;
1094 		}
1095 	}
1096 }
1097 
1098 void
1099 op_base(u_int32_t addr, instr_t instr)
1100 {
1101 	dis_ppc(addr, opcodes, instr);
1102 }
1103 
1104 void
1105 op_cl_x13(u_int32_t addr, instr_t instr)
1106 {
1107 	dis_ppc(addr, opcodes_13, instr);
1108 }
1109 
1110 void
1111 op_cl_x1e(u_int32_t addr, instr_t instr)
1112 {
1113 	dis_ppc(addr, opcodes_1e, instr);
1114 }
1115 
1116 void
1117 op_cl_x1f(u_int32_t addr, instr_t instr)
1118 {
1119 	dis_ppc(addr, opcodes_1f, instr);
1120 }
1121 
1122 void
1123 op_cl_x3a(u_int32_t addr, instr_t instr)
1124 {
1125 	dis_ppc(addr, opcodes_3a, instr);
1126 }
1127 
1128 void
1129 op_cl_x3b(u_int32_t addr, instr_t instr)
1130 {
1131 	dis_ppc(addr, opcodes_3b, instr);
1132 }
1133 
1134 void
1135 op_cl_x3e(u_int32_t addr, instr_t instr)
1136 {
1137 	dis_ppc(addr, opcodes_3e, instr);
1138 }
1139 
1140 void
1141 op_cl_x3f(u_int32_t addr, instr_t instr)
1142 {
1143 	dis_ppc(addr, opcodes_3f, instr);
1144 }
1145 
1146 void
1147 dis_ppc(u_int32_t addr, const struct opcode *opcodeset, instr_t instr)
1148 {
1149 	const struct opcode *op;
1150 	int i;
1151 	char disasm_str[80];
1152 
1153 	for (i=0; opcodeset[i].mask != 0; i++) {
1154 		op = &opcodeset[i];
1155 		if ((instr & op->mask) == op->code) {
1156 			disasm_fields(addr, op, instr, disasm_str,
1157 			    sizeof disasm_str);
1158 			db_printf("%s%s\n", op->name, disasm_str);
1159 			return;
1160 		}
1161 	}
1162 	op_ill(addr, instr);
1163 }
1164 
1165 db_addr_t
1166 db_disasm(db_addr_t loc, boolean_t extended)
1167 {
1168 	int class;
1169 	instr_t opcode;
1170 	opcode = *(instr_t *)(loc);
1171 	class = opcode >> 26;
1172 	(opcodes_base[class])(loc, opcode);
1173 
1174 	return loc + 4;
1175 }
1176