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