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