Print this page
6067 libdisasm: use C99 designated initializers for arch ops
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libdisasm/common/dis_sparc.c
+++ new/usr/src/lib/libdisasm/common/dis_sparc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Copyright 2007 Jason King. All rights reserved.
29 29 * Use is subject to license terms.
30 30 * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
31 31 */
32 32
33 33 /*
34 34 * The sparc disassembler is mostly straightforward, each instruction is
35 35 * represented by an inst_t structure. The inst_t definitions are organized
36 36 * into tables. The tables are correspond to the opcode maps documented in the
37 37 * various sparc architecture manuals. Each table defines the bit range of the
38 38 * instruction whose value act as an index into the array of instructions. A
39 39 * table can also refer to another table if needed. Each table also contains
40 40 * a function pointer of type format_fcn that knows how to output the
41 41 * instructions in the table, as well as handle any synthetic instructions
42 42 *
43 43 * Unfortunately, the changes from sparcv8 -> sparcv9 not only include new
44 44 * instructions, they sometimes renamed or just reused the same instruction to
45 45 * do different operations (i.e. the sparcv8 coprocessor instructions). To
46 46 * accommodate this, each table can define an overlay table. The overlay table
47 47 * is a list of (table index, architecture, new instruction definition) values.
48 48 *
49 49 *
50 50 * Traversal starts with the first table,
51 51 * get index value from the instruction
52 52 * if an relevant overlay entry exists for this index,
53 53 * grab the overlay definition
54 54 * else
55 55 * grab the definition from the array (corresponding to the index value)
56 56 *
57 57 * If the entry is an instruction,
58 58 * call print function of instruction.
59 59 * If the entry is a pointer to another table
60 60 * traverse the table
61 61 * If not valid,
62 62 * return an error
63 63 *
64 64 *
65 65 * To keep dis happy, for sparc, instead of actually returning an error, if
66 66 * the instruction cannot be disassembled, we instead merely place the value
67 67 * of the instruction into the output buffer.
68 68 *
69 69 * Adding new instructions:
70 70 *
71 71 * With the above information, it hopefully makes it clear how to add support
72 72 * for decoding new instructions. Presumably, with new instructions will come
73 73 * a new dissassembly mode (I.e. DIS_SPARC_V8, DIS_SPARC_V9, etc.).
74 74 *
75 75 * If the dissassembled format does not correspond to one of the existing
76 76 * formats, a new formatter will have to be written. The 'flags' value of
77 77 * inst_t is intended to instruct the corresponding formatter about how to
78 78 * output the instruction.
79 79 *
80 80 * If the corresponding entry in the correct table is currently unoccupied,
81 81 * simply replace the INVALID entry with the correct definition. The INST and
82 82 * TABLE macros are suggested to be used for this. If there is already an
83 83 * instruction defined, then the entry must be placed in an overlay table. If
84 84 * no overlay table exists for the instruction table, one will need to be
85 85 * created.
86 86 */
87 87
88 88 #include <libdisasm.h>
89 89 #include <stdlib.h>
90 90 #include <stdio.h>
91 91 #include <sys/types.h>
92 92 #include <sys/byteorder.h>
93 93 #include <string.h>
94 94
95 95 #include "libdisasm_impl.h"
96 96 #include "dis_sparc.h"
97 97
98 98 static const inst_t *dis_get_overlay(dis_handle_t *, const table_t *,
99 99 uint32_t);
100 100 static uint32_t dis_get_bits(uint32_t, int, int);
101 101
102 102 #if !defined(DIS_STANDALONE)
103 103 static void do_binary(uint32_t);
104 104 #endif /* DIS_STANDALONE */
105 105
106 106 static void
107 107 dis_sparc_handle_detach(dis_handle_t *dhp)
108 108 {
109 109 dis_free(dhp->dh_arch_private, sizeof (dis_handle_sparc_t));
110 110 dhp->dh_arch_private = NULL;
111 111 }
112 112
113 113 static int
114 114 dis_sparc_handle_attach(dis_handle_t *dhp)
115 115 {
116 116 dis_handle_sparc_t *dhx;
117 117
118 118 #if !defined(DIS_STANDALONE)
119 119 char *opt = NULL;
120 120 char *opt2, *save, *end;
121 121 #endif
122 122
123 123 /* Validate architecture flags */
124 124 if ((dhp->dh_flags & (DIS_SPARC_V8|DIS_SPARC_V9|DIS_SPARC_V9_SGI))
125 125 == 0) {
126 126 (void) dis_seterrno(E_DIS_INVALFLAG);
127 127 return (-1);
128 128 }
129 129
130 130 if ((dhx = dis_zalloc(sizeof (dis_handle_sparc_t))) == NULL) {
131 131 (void) dis_seterrno(E_DIS_NOMEM);
132 132 return (NULL);
133 133 }
134 134 dhx->dhx_debug = DIS_DEBUG_COMPAT;
135 135 dhp->dh_arch_private = dhx;
136 136
137 137 #if !defined(DIS_STANDALONE)
138 138
139 139 opt = getenv("_LIBDISASM_DEBUG");
140 140 if (opt == NULL)
141 141 return (0);
142 142
143 143 opt2 = strdup(opt);
144 144 if (opt2 == NULL) {
145 145 dis_handle_destroy(dhp);
146 146 dis_free(dhx, sizeof (dis_handle_sparc_t));
147 147 (void) dis_seterrno(E_DIS_NOMEM);
148 148 return (-1);
149 149 }
150 150 save = opt2;
151 151
152 152 while (opt2 != NULL) {
153 153 end = strchr(opt2, ',');
154 154
155 155 if (end != 0)
156 156 *end++ = '\0';
157 157
158 158 if (strcasecmp("synth-all", opt2) == 0)
159 159 dhx->dhx_debug |= DIS_DEBUG_SYN_ALL;
160 160
161 161 if (strcasecmp("compat", opt2) == 0)
162 162 dhx->dhx_debug |= DIS_DEBUG_COMPAT;
163 163
164 164 if (strcasecmp("synth-none", opt2) == 0)
165 165 dhx->dhx_debug &= ~(DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT);
166 166
167 167 if (strcasecmp("binary", opt2) == 0)
168 168 dhx->dhx_debug |= DIS_DEBUG_PRTBIN;
169 169
170 170 if (strcasecmp("format", opt2) == 0)
171 171 dhx->dhx_debug |= DIS_DEBUG_PRTFMT;
172 172
173 173 if (strcasecmp("all", opt2) == 0)
174 174 dhx->dhx_debug = DIS_DEBUG_ALL;
175 175
176 176 if (strcasecmp("none", opt2) == 0)
177 177 dhx->dhx_debug = DIS_DEBUG_NONE;
178 178
179 179 opt2 = end;
180 180 }
181 181 free(save);
182 182 #endif /* DIS_STANDALONE */
183 183 return (0);
184 184 }
185 185
186 186 /* ARGSUSED */
187 187 static int
188 188 dis_sparc_max_instrlen(dis_handle_t *dhp)
189 189 {
190 190 return (4);
191 191 }
192 192
193 193 /* ARGSUSED */
194 194 static int
195 195 dis_sparc_min_instrlen(dis_handle_t *dhp)
196 196 {
197 197 return (4);
198 198 }
199 199
200 200 /*
201 201 * The dis_i386.c comment for this says it returns the previous instruction,
202 202 * however, I'm fairly sure it's actually returning the _address_ of the
203 203 * nth previous instruction.
204 204 */
205 205 /* ARGSUSED */
206 206 static uint64_t
207 207 dis_sparc_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
208 208 {
209 209 if (n <= 0)
210 210 return (pc);
211 211
212 212 if (pc < n)
213 213 return (pc);
214 214
215 215 return (pc - n*4);
216 216 }
217 217
218 218 /* ARGSUSED */
219 219 static int
220 220 dis_sparc_instrlen(dis_handle_t *dhp, uint64_t pc)
221 221 {
222 222 return (4);
223 223 }
224 224
225 225 static int
226 226 dis_sparc_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf,
227 227 size_t buflen)
228 228 {
229 229 dis_handle_sparc_t *dhx = dhp->dh_arch_private;
230 230 const table_t *tp = &initial_table;
231 231 const inst_t *inp = NULL;
232 232
233 233 uint32_t instr;
234 234 uint32_t idx = 0;
235 235
236 236 if (dhp->dh_read(dhp->dh_data, addr, &instr, sizeof (instr)) !=
237 237 sizeof (instr))
238 238 return (-1);
239 239
240 240 dhx->dhx_buf = buf;
241 241 dhx->dhx_buflen = buflen;
242 242 dhp->dh_addr = addr;
243 243
244 244 buf[0] = '\0';
245 245
246 246 /* this allows sparc code to be tested on x86 */
247 247 #if !defined(DIS_STANDALONE)
248 248 instr = BE_32(instr);
249 249 #endif /* DIS_STANDALONE */
250 250
251 251 #if !defined(DIS_STANDALONE)
252 252 if ((dhx->dhx_debug & DIS_DEBUG_PRTBIN) != 0)
253 253 do_binary(instr);
254 254 #endif /* DIS_STANDALONE */
255 255
256 256 /* CONSTCOND */
257 257 while (1) {
258 258 idx = dis_get_bits(instr, tp->tbl_field, tp->tbl_len);
259 259 inp = &tp->tbl_inp[idx];
260 260
261 261 inp = dis_get_overlay(dhp, tp, idx);
262 262
263 263 if ((inp->in_type == INST_NONE) ||
264 264 ((inp->in_arch & dhp->dh_flags) == 0))
265 265 goto error;
266 266
267 267 if (inp->in_type == INST_TBL) {
268 268 tp = inp->in_data.in_tbl;
269 269 continue;
270 270 }
271 271
272 272 break;
273 273 }
274 274
275 275 if (tp->tbl_fmt(dhp, instr, inp, idx) == 0)
276 276 return (0);
277 277
278 278 error:
279 279
280 280 (void) dis_snprintf(buf, buflen,
281 281 ((dhp->dh_flags & DIS_OCTAL) != 0) ? "0%011lo" : "0x%08lx",
282 282 instr);
283 283
284 284 return (0);
285 285 }
286 286
287 287 static uint32_t
288 288 dis_get_bits(uint32_t instr, int offset, int length)
289 289 {
290 290 uint32_t mask, val;
291 291 int i;
292 292
293 293 for (i = 0, mask = 0; i < length; ++i)
294 294 mask |= (1UL << i);
295 295
296 296 mask = mask << (offset - length + 1);
297 297
298 298 val = instr & mask;
299 299
300 300 val = val >> (offset - length + 1);
301 301
302 302 return (val);
303 303 }
304 304
305 305 static const inst_t *
306 306 dis_get_overlay(dis_handle_t *dhp, const table_t *tp, uint32_t idx)
307 307 {
308 308 const inst_t *ip = &tp->tbl_inp[idx];
309 309 int i;
310 310
311 311 if (tp->tbl_ovp == NULL)
312 312 return (ip);
313 313
314 314 for (i = 0; tp->tbl_ovp[i].ov_idx != -1; ++i) {
315 315 if (tp->tbl_ovp[i].ov_idx != idx)
316 316 continue;
317 317
318 318 if ((tp->tbl_ovp[i].ov_inst.in_arch & dhp->dh_flags) == 0)
319 319 continue;
320 320
321 321 ip = &tp->tbl_ovp[i].ov_inst;
322 322 break;
323 323 }
324 324
325 325 return (ip);
326 326 }
327 327
328 328 #if !defined(DIS_STANDALONE)
329 329 static void
330 330 do_binary(uint32_t instr)
331 331 {
332 332 (void) fprintf(stderr, "DISASM: ");
333 333 prt_binary(instr, 32);
334 334 (void) fprintf(stderr, "\n");
335 335 }
336 336 #endif /* DIS_STANDALONE */
337 337
338 338 static int
339 339 dis_sparc_supports_flags(int flags)
340 340 {
↓ open down ↓ |
340 lines elided |
↑ open up ↑ |
341 341 int archflags = flags & DIS_ARCH_MASK;
342 342
343 343 if (archflags == DIS_SPARC_V8 ||
344 344 (archflags & (DIS_SPARC_V9 | DIS_SPARC_V8)) == DIS_SPARC_V9)
345 345 return (1);
346 346
347 347 return (0);
348 348 }
349 349
350 350 const dis_arch_t dis_arch_sparc = {
351 - dis_sparc_supports_flags,
352 - dis_sparc_handle_attach,
353 - dis_sparc_handle_detach,
354 - dis_sparc_disassemble,
355 - dis_sparc_previnstr,
356 - dis_sparc_min_instrlen,
357 - dis_sparc_max_instrlen,
358 - dis_sparc_instrlen
351 + .da_supports_flags = dis_sparc_supports_flags,
352 + .da_handle_attach = dis_sparc_handle_attach,
353 + .da_handle_detach = dis_sparc_handle_detach,
354 + .da_disassemble = dis_sparc_disassemble,
355 + .da_previnstr = dis_sparc_previnstr,
356 + .da_min_instrlen = dis_sparc_min_instrlen,
357 + .da_max_instrlen = dis_sparc_max_instrlen,
358 + .da_instrlen = dis_sparc_instrlen
359 359 };
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX