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