/src/binutils-gdb/opcodes/sparc-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Print SPARC instructions. |
2 | | Copyright (C) 1989-2025 Free Software Foundation, Inc. |
3 | | |
4 | | This file is part of the GNU opcodes library. |
5 | | |
6 | | This library is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3, or (at your option) |
9 | | any later version. |
10 | | |
11 | | It is distributed in the hope that it will be useful, but WITHOUT |
12 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
13 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
14 | | License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; if not, write to the Free Software |
18 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
19 | | MA 02110-1301, USA. */ |
20 | | |
21 | | #include "sysdep.h" |
22 | | #include <stdio.h> |
23 | | #include "opcode/sparc.h" |
24 | | #include "dis-asm.h" |
25 | | #include "libiberty.h" |
26 | | #include "opintl.h" |
27 | | |
28 | | /* Bitmask of v9 architectures. */ |
29 | | #define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \ |
30 | | | (1 << SPARC_OPCODE_ARCH_V9A) \ |
31 | | | (1 << SPARC_OPCODE_ARCH_V9B) \ |
32 | | | (1 << SPARC_OPCODE_ARCH_V9C) \ |
33 | | | (1 << SPARC_OPCODE_ARCH_V9D) \ |
34 | | | (1 << SPARC_OPCODE_ARCH_V9E) \ |
35 | | | (1 << SPARC_OPCODE_ARCH_V9V) \ |
36 | | | (1 << SPARC_OPCODE_ARCH_V9M) \ |
37 | | | (1 << SPARC_OPCODE_ARCH_M8)) |
38 | | /* 1 if INSN is for v9 only. */ |
39 | | #define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9)) |
40 | | /* 1 if INSN is for v9. */ |
41 | | #define V9_P(insn) (((insn)->architecture & MASK_V9) != 0) |
42 | | |
43 | | /* The sorted opcode table. */ |
44 | | static const sparc_opcode **sorted_opcodes; |
45 | | |
46 | | /* For faster lookup, after insns are sorted they are hashed. */ |
47 | | /* ??? I think there is room for even more improvement. */ |
48 | | |
49 | 910 | #define HASH_SIZE 256 |
50 | | /* It is important that we only look at insn code bits as that is how the |
51 | | opcode table is hashed. OPCODE_BITS is a table of valid bits for each |
52 | | of the main types (0,1,2,3). */ |
53 | | static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 }; |
54 | | #define HASH_INSN(INSN) \ |
55 | 2.93M | ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19)) |
56 | | typedef struct sparc_opcode_hash |
57 | | { |
58 | | struct sparc_opcode_hash *next; |
59 | | const sparc_opcode *opcode; |
60 | | } sparc_opcode_hash; |
61 | | |
62 | | static sparc_opcode_hash *opcode_hash_table[HASH_SIZE]; |
63 | | |
64 | | /* Sign-extend a value which is N bits long. */ |
65 | | #define SEX(value, bits) \ |
66 | 727k | ((int) (((value & ((1u << (bits - 1) << 1) - 1)) \ |
67 | 727k | ^ (1u << (bits - 1))) - (1u << (bits - 1)))) |
68 | | |
69 | | static char *reg_names[] = |
70 | | { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", |
71 | | "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", |
72 | | "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", |
73 | | "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", |
74 | | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
75 | | "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", |
76 | | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
77 | | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
78 | | "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", |
79 | | "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", |
80 | | "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", |
81 | | "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63", |
82 | | /* psr, wim, tbr, fpsr, cpsr are v8 only. */ |
83 | | "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" |
84 | | }; |
85 | | |
86 | 22.5k | #define freg_names (®_names[4 * 8]) |
87 | | |
88 | | /* These are ordered according to there register number in |
89 | | rdpr and wrpr insns. */ |
90 | | static char *v9_priv_reg_names[] = |
91 | | { |
92 | | "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl", |
93 | | "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", |
94 | | "wstate", "fq", "gl" |
95 | | /* "ver" and "pmcdper" - special cased */ |
96 | | }; |
97 | | |
98 | | /* These are ordered according to there register number in |
99 | | rdhpr and wrhpr insns. */ |
100 | | static char *v9_hpriv_reg_names[] = |
101 | | { |
102 | | "hpstate", "htstate", "resv2", "hintp", "resv4", "htba", "hver", |
103 | | "resv7", "resv8", "resv9", "resv10", "resv11", "resv12", "resv13", |
104 | | "resv14", "resv15", "resv16", "resv17", "resv18", "resv19", "resv20", |
105 | | "resv21", "resv22", "hmcdper", "hmcddfr", "resv25", "resv26", "hva_mask_nz", |
106 | | "hstick_offset", "hstick_enable", "resv30", "hstick_cmpr" |
107 | | }; |
108 | | |
109 | | /* These are ordered according to there register number in |
110 | | rd and wr insns (-16). */ |
111 | | static char *v9a_asr_reg_names[] = |
112 | | { |
113 | | "pcr", "pic", "dcr", "gsr", "softint_set", "softint_clear", |
114 | | "softint", "tick_cmpr", "stick", "stick_cmpr", "cfr", |
115 | | "pause", "mwait" |
116 | | }; |
117 | | |
118 | | /* Macros used to extract instruction fields. Not all fields have |
119 | | macros defined here, only those which are actually used. */ |
120 | | |
121 | 3.90M | #define X_RD(i) (((i) >> 25) & 0x1f) |
122 | 988k | #define X_RS1(i) (((i) >> 14) & 0x1f) |
123 | 454 | #define X_LDST_I(i) (((i) >> 13) & 1) |
124 | 27.6k | #define X_ASI(i) (((i) >> 5) & 0xff) |
125 | 967k | #define X_RS2(i) (((i) >> 0) & 0x1f) |
126 | 151 | #define X_RS3(i) (((i) >> 9) & 0x1f) |
127 | 10.4k | #define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1)) |
128 | 172k | #define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n)) |
129 | 96.6k | #define X_DISP22(i) (((i) >> 0) & 0x3fffff) |
130 | 96.6k | #define X_IMM22(i) X_DISP22 (i) |
131 | | #define X_DISP30(i) (((i) >> 0) & 0x3fffffff) |
132 | 127 | #define X_IMM2(i) (((i & 0x10) >> 3) | (i & 0x1)) |
133 | | |
134 | | /* These are for v9. */ |
135 | | #define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff)) |
136 | | #define X_DISP10(i) (((((i) >> 19) & 3) << 8) | (((i) >> 5) & 0xff)) |
137 | | #define X_DISP19(i) (((i) >> 0) & 0x7ffff) |
138 | 0 | #define X_MEMBAR(i) ((i) & 0x7f) |
139 | | |
140 | | /* Here is the union which was used to extract instruction fields |
141 | | before the shift and mask macros were written. |
142 | | |
143 | | union sparc_insn |
144 | | { |
145 | | unsigned long int code; |
146 | | struct |
147 | | { |
148 | | unsigned int anop:2; |
149 | | #define op ldst.anop |
150 | | unsigned int anrd:5; |
151 | | #define rd ldst.anrd |
152 | | unsigned int op3:6; |
153 | | unsigned int anrs1:5; |
154 | | #define rs1 ldst.anrs1 |
155 | | unsigned int i:1; |
156 | | unsigned int anasi:8; |
157 | | #define asi ldst.anasi |
158 | | unsigned int anrs2:5; |
159 | | #define rs2 ldst.anrs2 |
160 | | #define shcnt rs2 |
161 | | } ldst; |
162 | | struct |
163 | | { |
164 | | unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; |
165 | | unsigned int IMM13:13; |
166 | | #define imm13 IMM13.IMM13 |
167 | | } IMM13; |
168 | | struct |
169 | | { |
170 | | unsigned int anop:2; |
171 | | unsigned int a:1; |
172 | | unsigned int cond:4; |
173 | | unsigned int op2:3; |
174 | | unsigned int DISP22:22; |
175 | | #define disp22 branch.DISP22 |
176 | | #define imm22 disp22 |
177 | | } branch; |
178 | | struct |
179 | | { |
180 | | unsigned int anop:2; |
181 | | unsigned int a:1; |
182 | | unsigned int z:1; |
183 | | unsigned int rcond:3; |
184 | | unsigned int op2:3; |
185 | | unsigned int DISP16HI:2; |
186 | | unsigned int p:1; |
187 | | unsigned int _rs1:5; |
188 | | unsigned int DISP16LO:14; |
189 | | } branch16; |
190 | | struct |
191 | | { |
192 | | unsigned int anop:2; |
193 | | unsigned int adisp30:30; |
194 | | #define disp30 call.adisp30 |
195 | | } call; |
196 | | }; */ |
197 | | |
198 | | /* Nonzero if INSN is the opcode for a delayed branch. */ |
199 | | |
200 | | static int |
201 | | is_delayed_branch (unsigned long insn) |
202 | 100k | { |
203 | 100k | sparc_opcode_hash *op; |
204 | | |
205 | 2.86M | for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) |
206 | 2.86M | { |
207 | 2.86M | const sparc_opcode *opcode = op->opcode; |
208 | | |
209 | 2.86M | if ((opcode->match & insn) == opcode->match |
210 | 2.86M | && (opcode->lose & insn) == 0) |
211 | 95.5k | return opcode->flags & F_DELAYED; |
212 | 2.86M | } |
213 | 4.51k | return 0; |
214 | 100k | } |
215 | | |
216 | | /* extern void qsort (); */ |
217 | | |
218 | | /* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value |
219 | | to compare_opcodes. */ |
220 | | static unsigned int current_arch_mask; |
221 | | |
222 | | /* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */ |
223 | | |
224 | | static int |
225 | | compute_arch_mask (unsigned long mach) |
226 | 455 | { |
227 | 455 | switch (mach) |
228 | 455 | { |
229 | 92 | case 0 : |
230 | 103 | case bfd_mach_sparc : |
231 | 103 | return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8) |
232 | 103 | | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_LEON)); |
233 | 30 | case bfd_mach_sparc_sparclet : |
234 | 30 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET); |
235 | 9 | case bfd_mach_sparc_sparclite : |
236 | 12 | case bfd_mach_sparc_sparclite_le : |
237 | | /* sparclites insns are recognized by default (because that's how |
238 | | they've always been treated, for better or worse). Kludge this by |
239 | | indicating generic v8 is also selected. */ |
240 | 12 | return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) |
241 | 12 | | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); |
242 | 59 | case bfd_mach_sparc_v8plus : |
243 | 62 | case bfd_mach_sparc_v9 : |
244 | 62 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); |
245 | 21 | case bfd_mach_sparc_v8plusa : |
246 | 24 | case bfd_mach_sparc_v9a : |
247 | 24 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A); |
248 | 7 | case bfd_mach_sparc_v8plusb : |
249 | 13 | case bfd_mach_sparc_v9b : |
250 | 13 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B); |
251 | 0 | case bfd_mach_sparc_v8plusc : |
252 | 3 | case bfd_mach_sparc_v9c : |
253 | 3 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9C); |
254 | 0 | case bfd_mach_sparc_v8plusd : |
255 | 22 | case bfd_mach_sparc_v9d : |
256 | 22 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9D); |
257 | 14 | case bfd_mach_sparc_v8pluse : |
258 | 54 | case bfd_mach_sparc_v9e : |
259 | 54 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9E); |
260 | 32 | case bfd_mach_sparc_v8plusv : |
261 | 33 | case bfd_mach_sparc_v9v : |
262 | 33 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9V); |
263 | 2 | case bfd_mach_sparc_v8plusm : |
264 | 2 | case bfd_mach_sparc_v9m : |
265 | 2 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9M); |
266 | 68 | case bfd_mach_sparc_v8plusm8 : |
267 | 97 | case bfd_mach_sparc_v9m8 : |
268 | 97 | return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_M8); |
269 | 455 | } |
270 | 0 | abort (); |
271 | 455 | } |
272 | | |
273 | | /* Compare opcodes A and B. */ |
274 | | |
275 | | static int |
276 | | compare_opcodes (const void * a, const void * b) |
277 | 16.0M | { |
278 | 16.0M | sparc_opcode *op0 = * (sparc_opcode **) a; |
279 | 16.0M | sparc_opcode *op1 = * (sparc_opcode **) b; |
280 | 16.0M | unsigned long int match0 = op0->match, match1 = op1->match; |
281 | 16.0M | unsigned long int lose0 = op0->lose, lose1 = op1->lose; |
282 | 16.0M | register unsigned int i; |
283 | | |
284 | | /* If one (and only one) insn isn't supported by the current architecture, |
285 | | prefer the one that is. If neither are supported, but they're both for |
286 | | the same architecture, continue processing. Otherwise (both unsupported |
287 | | and for different architectures), prefer lower numbered arch's (fudged |
288 | | by comparing the bitmasks). */ |
289 | 16.0M | if (op0->architecture & current_arch_mask) |
290 | 10.9M | { |
291 | 10.9M | if (! (op1->architecture & current_arch_mask)) |
292 | 288k | return -1; |
293 | 10.9M | } |
294 | 5.16M | else |
295 | 5.16M | { |
296 | 5.16M | if (op1->architecture & current_arch_mask) |
297 | 185k | return 1; |
298 | 4.98M | else if (op0->architecture != op1->architecture) |
299 | 673k | return op0->architecture - op1->architecture; |
300 | 5.16M | } |
301 | | |
302 | | /* If a bit is set in both match and lose, there is something |
303 | | wrong with the opcode table. */ |
304 | 14.9M | if (match0 & lose0) |
305 | 0 | { |
306 | 0 | opcodes_error_handler |
307 | | /* xgettext:c-format */ |
308 | 0 | (_("internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), |
309 | 0 | op0->name, match0, lose0); |
310 | 0 | op0->lose &= ~op0->match; |
311 | 0 | lose0 = op0->lose; |
312 | 0 | } |
313 | | |
314 | 14.9M | if (match1 & lose1) |
315 | 0 | { |
316 | 0 | opcodes_error_handler |
317 | | /* xgettext:c-format */ |
318 | 0 | (_("internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), |
319 | 0 | op1->name, match1, lose1); |
320 | 0 | op1->lose &= ~op1->match; |
321 | 0 | lose1 = op1->lose; |
322 | 0 | } |
323 | | |
324 | | /* Because the bits that are variable in one opcode are constant in |
325 | | another, it is important to order the opcodes in the right order. */ |
326 | 296M | for (i = 0; i < 32; ++i) |
327 | 295M | { |
328 | 295M | unsigned long int x = 1ul << i; |
329 | 295M | int x0 = (match0 & x) != 0; |
330 | 295M | int x1 = (match1 & x) != 0; |
331 | | |
332 | 295M | if (x0 != x1) |
333 | 13.8M | return x1 - x0; |
334 | 295M | } |
335 | | |
336 | 22.6M | for (i = 0; i < 32; ++i) |
337 | 22.0M | { |
338 | 22.0M | unsigned long int x = 1ul << i; |
339 | 22.0M | int x0 = (lose0 & x) != 0; |
340 | 22.0M | int x1 = (lose1 & x) != 0; |
341 | | |
342 | 22.0M | if (x0 != x1) |
343 | 484k | return x1 - x0; |
344 | 22.0M | } |
345 | | |
346 | | /* They are functionally equal. So as long as the opcode table is |
347 | | valid, we can put whichever one first we want, on aesthetic grounds. */ |
348 | | |
349 | | /* Our first aesthetic ground is that aliases defer to real insns. */ |
350 | 573k | { |
351 | 573k | int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); |
352 | | |
353 | 573k | if (alias_diff != 0) |
354 | | /* Put the one that isn't an alias first. */ |
355 | 292k | return alias_diff; |
356 | 573k | } |
357 | | |
358 | | /* Except for aliases, two "identical" instructions had |
359 | | better have the same opcode. This is a sanity check on the table. */ |
360 | 281k | i = strcmp (op0->name, op1->name); |
361 | 281k | if (i) |
362 | 71.3k | { |
363 | 71.3k | if (op0->flags & F_ALIAS) |
364 | 71.3k | { |
365 | 71.3k | if (op0->flags & F_PREFERRED) |
366 | 8.19k | return -1; |
367 | 63.1k | if (op1->flags & F_PREFERRED) |
368 | 0 | return 1; |
369 | | |
370 | | /* If they're both aliases, and neither is marked as preferred, |
371 | | be arbitrary. */ |
372 | 63.1k | return i; |
373 | 63.1k | } |
374 | 0 | else |
375 | 0 | opcodes_error_handler |
376 | | /* xgettext:c-format */ |
377 | 0 | (_("internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), |
378 | 0 | op0->name, op1->name); |
379 | 71.3k | } |
380 | | |
381 | | /* Fewer arguments are preferred. */ |
382 | 209k | { |
383 | 209k | int length_diff = strlen (op0->args) - strlen (op1->args); |
384 | | |
385 | 209k | if (length_diff != 0) |
386 | | /* Put the one with fewer arguments first. */ |
387 | 135k | return length_diff; |
388 | 209k | } |
389 | | |
390 | | /* Put 1+i before i+1. */ |
391 | 74.1k | { |
392 | 74.1k | char *p0 = (char *) strchr (op0->args, '+'); |
393 | 74.1k | char *p1 = (char *) strchr (op1->args, '+'); |
394 | | |
395 | 74.1k | if (p0 && p1) |
396 | 58.6k | { |
397 | | /* There is a plus in both operands. Note that a plus |
398 | | sign cannot be the first character in args, |
399 | | so the following [-1]'s are valid. */ |
400 | 58.6k | if (p0[-1] == 'i' && p1[1] == 'i') |
401 | | /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ |
402 | 0 | return 1; |
403 | 58.6k | if (p0[1] == 'i' && p1[-1] == 'i') |
404 | | /* op0 is 1+i and op1 is i+1, so op0 goes first. */ |
405 | 52.7k | return -1; |
406 | 58.6k | } |
407 | 74.1k | } |
408 | | |
409 | | /* Put 1,i before i,1. */ |
410 | 21.3k | { |
411 | 21.3k | int i0 = strncmp (op0->args, "i,1", 3) == 0; |
412 | 21.3k | int i1 = strncmp (op1->args, "i,1", 3) == 0; |
413 | | |
414 | 21.3k | if (i0 ^ i1) |
415 | 14.1k | return i0 - i1; |
416 | 21.3k | } |
417 | | |
418 | | /* They are, as far as we can tell, identical. |
419 | | Since qsort may have rearranged the table partially, there is |
420 | | no way to tell which one was first in the opcode table as |
421 | | written, so just say there are equal. */ |
422 | | /* ??? This is no longer true now that we sort a vector of pointers, |
423 | | not the table itself. */ |
424 | 7.28k | return 0; |
425 | 21.3k | } |
426 | | |
427 | | /* Build a hash table from the opcode table. |
428 | | OPCODE_TABLE is a sorted list of pointers into the opcode table. */ |
429 | | |
430 | | static void |
431 | | build_hash_table (const sparc_opcode **opcode_table, |
432 | | sparc_opcode_hash **hash_table, |
433 | | int num_opcodes) |
434 | 455 | { |
435 | 455 | int i; |
436 | 455 | int hash_count[HASH_SIZE]; |
437 | 455 | static sparc_opcode_hash *hash_buf = NULL; |
438 | | |
439 | | /* Start at the end of the table and work backwards so that each |
440 | | chain is sorted. */ |
441 | | |
442 | 455 | memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0])); |
443 | 455 | memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0])); |
444 | 455 | free (hash_buf); |
445 | 455 | hash_buf = xmalloc (sizeof (* hash_buf) * num_opcodes); |
446 | 1.60M | for (i = num_opcodes - 1; i >= 0; --i) |
447 | 1.60M | { |
448 | 1.60M | int hash = HASH_INSN (opcode_table[i]->match); |
449 | 1.60M | sparc_opcode_hash *h = &hash_buf[i]; |
450 | | |
451 | 1.60M | h->next = hash_table[hash]; |
452 | 1.60M | h->opcode = opcode_table[i]; |
453 | 1.60M | hash_table[hash] = h; |
454 | 1.60M | ++hash_count[hash]; |
455 | 1.60M | } |
456 | | |
457 | | #if 0 /* for debugging */ |
458 | | { |
459 | | int min_count = num_opcodes, max_count = 0; |
460 | | int total; |
461 | | |
462 | | for (i = 0; i < HASH_SIZE; ++i) |
463 | | { |
464 | | if (hash_count[i] < min_count) |
465 | | min_count = hash_count[i]; |
466 | | if (hash_count[i] > max_count) |
467 | | max_count = hash_count[i]; |
468 | | total += hash_count[i]; |
469 | | } |
470 | | |
471 | | printf ("Opcode hash table stats: min %d, max %d, ave %f\n", |
472 | | min_count, max_count, (double) total / HASH_SIZE); |
473 | | } |
474 | | #endif |
475 | 455 | } |
476 | | |
477 | | /* Print one instruction from MEMADDR on INFO->STREAM. |
478 | | |
479 | | We suffix the instruction with a comment that gives the absolute |
480 | | address involved, as well as its symbolic form, if the instruction |
481 | | is preceded by a findable `sethi' and it either adds an immediate |
482 | | displacement to that register, or it is an `add' or `or' instruction |
483 | | on that register. */ |
484 | | |
485 | | int |
486 | | print_insn_sparc (bfd_vma memaddr, disassemble_info *info) |
487 | 1.22M | { |
488 | 1.22M | FILE *stream = info->stream; |
489 | 1.22M | bfd_byte buffer[4]; |
490 | 1.22M | unsigned long insn; |
491 | 1.22M | sparc_opcode_hash *op; |
492 | | /* Nonzero of opcode table has been initialized. */ |
493 | 1.22M | static int opcodes_initialized = 0; |
494 | | /* bfd mach number of last call. */ |
495 | 1.22M | static unsigned long current_mach = 0; |
496 | 1.22M | bfd_vma (*getword) (const void *); |
497 | | |
498 | 1.22M | if (!opcodes_initialized |
499 | 1.22M | || info->mach != current_mach) |
500 | 455 | { |
501 | 455 | int i; |
502 | | |
503 | 455 | current_arch_mask = compute_arch_mask (info->mach); |
504 | | |
505 | 455 | if (!opcodes_initialized) |
506 | 2 | sorted_opcodes = |
507 | 2 | xmalloc (sparc_num_opcodes * sizeof (sparc_opcode *)); |
508 | | /* Reset the sorted table so we can resort it. */ |
509 | 1.60M | for (i = 0; i < sparc_num_opcodes; ++i) |
510 | 1.60M | sorted_opcodes[i] = &sparc_opcodes[i]; |
511 | 455 | qsort ((char *) sorted_opcodes, sparc_num_opcodes, |
512 | 455 | sizeof (sorted_opcodes[0]), compare_opcodes); |
513 | | |
514 | 455 | build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); |
515 | 455 | current_mach = info->mach; |
516 | 455 | opcodes_initialized = 1; |
517 | 455 | } |
518 | | |
519 | 1.22M | { |
520 | 1.22M | int status = |
521 | 1.22M | (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); |
522 | | |
523 | 1.22M | if (status != 0) |
524 | 425 | { |
525 | 425 | (*info->memory_error_func) (status, memaddr, info); |
526 | 425 | return -1; |
527 | 425 | } |
528 | 1.22M | } |
529 | | |
530 | | /* On SPARClite variants such as DANlite (sparc86x), instructions |
531 | | are always big-endian even when the machine is in little-endian mode. */ |
532 | 1.22M | if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite) |
533 | 1.03M | getword = bfd_getb32; |
534 | 194k | else |
535 | 194k | getword = bfd_getl32; |
536 | | |
537 | 1.22M | insn = getword (buffer); |
538 | | |
539 | 1.22M | info->insn_info_valid = 1; /* We do return this info. */ |
540 | 1.22M | info->insn_type = dis_nonbranch; /* Assume non branch insn. */ |
541 | 1.22M | info->branch_delay_insns = 0; /* Assume no delay. */ |
542 | 1.22M | info->target = 0; /* Assume no target known. */ |
543 | | |
544 | 30.0M | for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) |
545 | 29.7M | { |
546 | 29.7M | const sparc_opcode *opcode = op->opcode; |
547 | | |
548 | | /* If the insn isn't supported by the current architecture, skip it. */ |
549 | 29.7M | if (! (opcode->architecture & current_arch_mask)) |
550 | 9.95M | continue; |
551 | | |
552 | 19.8M | if ((opcode->match & insn) == opcode->match |
553 | 19.8M | && (opcode->lose & insn) == 0) |
554 | 970k | { |
555 | | /* Nonzero means that we have found an instruction which has |
556 | | the effect of adding or or'ing the imm13 field to rs1. */ |
557 | 970k | int imm_added_to_rs1 = 0; |
558 | 970k | int imm_ored_to_rs1 = 0; |
559 | | |
560 | | /* Nonzero means that we have found a plus sign in the args |
561 | | field of the opcode table. */ |
562 | 970k | int found_plus = 0; |
563 | | |
564 | | /* Nonzero means we have an annulled branch. */ |
565 | 970k | int is_annulled = 0; |
566 | | |
567 | | /* Do we have an `add' or `or' instruction combining an |
568 | | immediate with rs1? */ |
569 | 970k | if (opcode->match == 0x80102000) /* or */ |
570 | 30.2k | imm_ored_to_rs1 = 1; |
571 | 970k | if (opcode->match == 0x80002000) /* add */ |
572 | 8.67k | imm_added_to_rs1 = 1; |
573 | | |
574 | 970k | if (X_RS1 (insn) != X_RD (insn) |
575 | 970k | && strchr (opcode->args, 'r') != 0) |
576 | | /* Can't do simple format if source and dest are different. */ |
577 | 2.73k | continue; |
578 | 967k | if (X_RS2 (insn) != X_RD (insn) |
579 | 967k | && strchr (opcode->args, 'O') != 0) |
580 | | /* Can't do simple format if source and dest are different. */ |
581 | 101 | continue; |
582 | | |
583 | 967k | (*info->fprintf_func) (stream, "%s", opcode->name); |
584 | | |
585 | 967k | { |
586 | 967k | const char *s; |
587 | | |
588 | 967k | if (opcode->args[0] != ',') |
589 | 910k | (*info->fprintf_func) (stream, " "); |
590 | | |
591 | 2.96M | for (s = opcode->args; *s != '\0'; ++s) |
592 | 1.99M | { |
593 | 2.58M | while (*s == ',') |
594 | 588k | { |
595 | 588k | (*info->fprintf_func) (stream, ","); |
596 | 588k | ++s; |
597 | 588k | switch (*s) |
598 | 588k | { |
599 | 33.7k | case 'a': |
600 | 33.7k | (*info->fprintf_func) (stream, "a"); |
601 | 33.7k | is_annulled = 1; |
602 | 33.7k | ++s; |
603 | 33.7k | continue; |
604 | 34.3k | case 'N': |
605 | 34.3k | (*info->fprintf_func) (stream, "pn"); |
606 | 34.3k | ++s; |
607 | 34.3k | continue; |
608 | | |
609 | 0 | case 'T': |
610 | 0 | (*info->fprintf_func) (stream, "pt"); |
611 | 0 | ++s; |
612 | 0 | continue; |
613 | | |
614 | 520k | default: |
615 | 520k | break; |
616 | 588k | } |
617 | 588k | } |
618 | | |
619 | 1.99M | (*info->fprintf_func) (stream, " "); |
620 | | |
621 | 1.99M | switch (*s) |
622 | 1.99M | { |
623 | 97.3k | case '+': |
624 | 97.3k | found_plus = 1; |
625 | | /* Fall through. */ |
626 | | |
627 | 400k | default: |
628 | 400k | (*info->fprintf_func) (stream, "%c", *s); |
629 | 400k | break; |
630 | | |
631 | 0 | case '#': |
632 | 0 | (*info->fprintf_func) (stream, "0"); |
633 | 0 | break; |
634 | | |
635 | 649k | #define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) |
636 | 247k | case '1': |
637 | 252k | case 'r': |
638 | 252k | reg (X_RS1 (insn)); |
639 | 252k | break; |
640 | | |
641 | 85.7k | case '2': |
642 | 85.8k | case 'O': |
643 | 85.8k | reg (X_RS2 (insn)); |
644 | 85.8k | break; |
645 | | |
646 | 310k | case 'd': |
647 | 310k | reg (X_RD (insn)); |
648 | 310k | break; |
649 | 0 | #undef reg |
650 | | |
651 | 14.2k | #define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n]) |
652 | 8.25k | #define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)]) |
653 | 1.05k | case 'e': |
654 | 1.05k | freg (X_RS1 (insn)); |
655 | 1.05k | break; |
656 | 821 | case 'v': /* Double/even. */ |
657 | 900 | case 'V': /* Quad/multiple of 4. */ |
658 | 903 | case ';': /* Double/even multiple of 8 doubles. */ |
659 | 903 | fregx (X_RS1 (insn)); |
660 | 903 | break; |
661 | | |
662 | 1.32k | case 'f': |
663 | 1.32k | freg (X_RS2 (insn)); |
664 | 1.32k | break; |
665 | 785 | case 'B': /* Double/even. */ |
666 | 868 | case 'R': /* Quad/multiple of 4. */ |
667 | 871 | case ':': /* Double/even multiple of 8 doubles. */ |
668 | 871 | fregx (X_RS2 (insn)); |
669 | 871 | break; |
670 | | |
671 | 967 | case '4': |
672 | 967 | freg (X_RS3 (insn)); |
673 | 967 | break; |
674 | 337 | case '5': /* Double/even. */ |
675 | 337 | fregx (X_RS3 (insn)); |
676 | 337 | break; |
677 | | |
678 | 10.9k | case 'g': |
679 | 10.9k | freg (X_RD (insn)); |
680 | 10.9k | break; |
681 | 3.24k | case 'H': /* Double/even. */ |
682 | 6.01k | case 'J': /* Quad/multiple of 4. */ |
683 | 6.01k | case '}': /* Double/even. */ |
684 | 6.01k | fregx (X_RD (insn)); |
685 | 6.01k | break; |
686 | | |
687 | 3 | case '^': /* Double/even multiple of 8 doubles. */ |
688 | 3 | fregx (X_RD (insn) & ~0x6); |
689 | 3 | break; |
690 | | |
691 | 127 | case '\'': /* Double/even in FPCMPSHL. */ |
692 | 127 | fregx (X_RS2 (insn | 0x11)); |
693 | 127 | break; |
694 | | |
695 | 0 | #undef freg |
696 | 0 | #undef fregx |
697 | | |
698 | 703 | #define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) |
699 | 0 | case 'b': |
700 | 0 | creg (X_RS1 (insn)); |
701 | 0 | break; |
702 | | |
703 | 0 | case 'c': |
704 | 0 | creg (X_RS2 (insn)); |
705 | 0 | break; |
706 | | |
707 | 703 | case 'D': |
708 | 703 | creg (X_RD (insn)); |
709 | 703 | break; |
710 | 0 | #undef creg |
711 | | |
712 | 88.4k | case 'h': |
713 | 88.4k | (*info->fprintf_func) (stream, "%%hi(%#x)", |
714 | 88.4k | (unsigned) X_IMM22 (insn) << 10); |
715 | 88.4k | break; |
716 | | |
717 | 162k | case 'i': /* 13 bit immediate. */ |
718 | 163k | case 'I': /* 11 bit immediate. */ |
719 | 164k | case 'j': /* 10 bit immediate. */ |
720 | 164k | { |
721 | 164k | int imm; |
722 | | |
723 | 164k | if (*s == 'i') |
724 | 162k | imm = X_SIMM (insn, 13); |
725 | 1.37k | else if (*s == 'I') |
726 | 814 | imm = X_SIMM (insn, 11); |
727 | 564 | else |
728 | 564 | imm = X_SIMM (insn, 10); |
729 | | |
730 | | /* Check to see whether we have a 1+i, and take |
731 | | note of that fact. |
732 | | |
733 | | Note: because of the way we sort the table, |
734 | | we will be matching 1+i rather than i+1, |
735 | | so it is OK to assume that i is after +, |
736 | | not before it. */ |
737 | 164k | if (found_plus) |
738 | 72.4k | imm_added_to_rs1 = 1; |
739 | | |
740 | 164k | if (imm <= 9) |
741 | 95.2k | (*info->fprintf_func) (stream, "%d", imm); |
742 | 68.8k | else |
743 | 68.8k | (*info->fprintf_func) (stream, "%#x", imm); |
744 | 164k | } |
745 | 164k | break; |
746 | | |
747 | 151 | case ')': /* 5 bit unsigned immediate from RS3. */ |
748 | 151 | (info->fprintf_func) (stream, "%#x", (unsigned int) X_RS3 (insn)); |
749 | 151 | break; |
750 | | |
751 | 5.17k | case 'X': /* 5 bit unsigned immediate. */ |
752 | 5.20k | case 'Y': /* 6 bit unsigned immediate. */ |
753 | 5.20k | { |
754 | 5.20k | int imm = X_IMM (insn, *s == 'X' ? 5 : 6); |
755 | | |
756 | 5.20k | if (imm <= 9) |
757 | 2.43k | (info->fprintf_func) (stream, "%d", imm); |
758 | 2.77k | else |
759 | 2.77k | (info->fprintf_func) (stream, "%#x", (unsigned) imm); |
760 | 5.20k | } |
761 | 5.20k | break; |
762 | | |
763 | 0 | case '3': |
764 | 0 | (info->fprintf_func) (stream, "%ld", X_IMM (insn, 3)); |
765 | 0 | break; |
766 | | |
767 | 0 | case 'K': |
768 | 0 | { |
769 | 0 | int mask = X_MEMBAR (insn); |
770 | 0 | int bit = 0x40, printed_one = 0; |
771 | 0 | const char *name; |
772 | |
|
773 | 0 | if (mask == 0) |
774 | 0 | (info->fprintf_func) (stream, "0"); |
775 | 0 | else |
776 | 0 | while (bit) |
777 | 0 | { |
778 | 0 | if (mask & bit) |
779 | 0 | { |
780 | 0 | if (printed_one) |
781 | 0 | (info->fprintf_func) (stream, "|"); |
782 | 0 | name = sparc_decode_membar (bit); |
783 | 0 | (info->fprintf_func) (stream, "%s", name); |
784 | 0 | printed_one = 1; |
785 | 0 | } |
786 | 0 | bit >>= 1; |
787 | 0 | } |
788 | 0 | break; |
789 | 5.17k | } |
790 | | |
791 | 700 | case '=': |
792 | 700 | info->target = memaddr + SEX (X_DISP10 (insn), 10) * 4; |
793 | 700 | (*info->print_address_func) (info->target, info); |
794 | 700 | break; |
795 | | |
796 | 3.67k | case 'k': |
797 | 3.67k | info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4; |
798 | 3.67k | (*info->print_address_func) (info->target, info); |
799 | 3.67k | break; |
800 | | |
801 | 63.9k | case 'G': |
802 | 63.9k | info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4; |
803 | 63.9k | (*info->print_address_func) (info->target, info); |
804 | 63.9k | break; |
805 | | |
806 | 2.70k | case '6': |
807 | 4.94k | case '7': |
808 | 7.43k | case '8': |
809 | 10.3k | case '9': |
810 | 10.3k | (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0'); |
811 | 10.3k | break; |
812 | | |
813 | 33.9k | case 'z': |
814 | 33.9k | (*info->fprintf_func) (stream, "%%icc"); |
815 | 33.9k | break; |
816 | | |
817 | 20.8k | case 'Z': |
818 | 20.8k | (*info->fprintf_func) (stream, "%%xcc"); |
819 | 20.8k | break; |
820 | | |
821 | 96 | case 'E': |
822 | 96 | (*info->fprintf_func) (stream, "%%ccr"); |
823 | 96 | break; |
824 | | |
825 | 113 | case 's': |
826 | 113 | (*info->fprintf_func) (stream, "%%fprs"); |
827 | 113 | break; |
828 | | |
829 | 105 | case '{': |
830 | 105 | (*info->fprintf_func) (stream, "%%mcdper"); |
831 | 105 | break; |
832 | | |
833 | 0 | case '&': |
834 | 0 | (*info->fprintf_func) (stream, "%%entropy"); |
835 | 0 | break; |
836 | | |
837 | 15.5k | case 'o': |
838 | 15.5k | (*info->fprintf_func) (stream, "%%asi"); |
839 | 15.5k | break; |
840 | | |
841 | 69 | case 'W': |
842 | 69 | (*info->fprintf_func) (stream, "%%tick"); |
843 | 69 | break; |
844 | | |
845 | 65 | case 'P': |
846 | 65 | (*info->fprintf_func) (stream, "%%pc"); |
847 | 65 | break; |
848 | | |
849 | 24 | case '?': |
850 | 24 | if (X_RS1 (insn) == 31) |
851 | 0 | (*info->fprintf_func) (stream, "%%ver"); |
852 | 24 | else if (X_RS1 (insn) == 23) |
853 | 0 | (*info->fprintf_func) (stream, "%%pmcdper"); |
854 | 24 | else if ((unsigned) X_RS1 (insn) < 17) |
855 | 24 | (*info->fprintf_func) (stream, "%%%s", |
856 | 24 | v9_priv_reg_names[X_RS1 (insn)]); |
857 | 0 | else |
858 | 0 | (*info->fprintf_func) (stream, "%%reserved"); |
859 | 24 | break; |
860 | | |
861 | 1.96k | case '!': |
862 | 1.96k | if (X_RD (insn) == 31) |
863 | 68 | (*info->fprintf_func) (stream, "%%ver"); |
864 | 1.90k | else if (X_RD (insn) == 23) |
865 | 12 | (*info->fprintf_func) (stream, "%%pmcdper"); |
866 | 1.88k | else if ((unsigned) X_RD (insn) < 17) |
867 | 1.88k | (*info->fprintf_func) (stream, "%%%s", |
868 | 1.88k | v9_priv_reg_names[X_RD (insn)]); |
869 | 0 | else |
870 | 0 | (*info->fprintf_func) (stream, "%%reserved"); |
871 | 1.96k | break; |
872 | | |
873 | 43 | case '$': |
874 | 43 | if ((unsigned) X_RS1 (insn) < 32) |
875 | 43 | (*info->fprintf_func) (stream, "%%%s", |
876 | 43 | v9_hpriv_reg_names[X_RS1 (insn)]); |
877 | 0 | else |
878 | 0 | (*info->fprintf_func) (stream, "%%reserved"); |
879 | 43 | break; |
880 | | |
881 | 246 | case '%': |
882 | 246 | if ((unsigned) X_RD (insn) < 32) |
883 | 246 | (*info->fprintf_func) (stream, "%%%s", |
884 | 246 | v9_hpriv_reg_names[X_RD (insn)]); |
885 | 0 | else |
886 | 0 | (*info->fprintf_func) (stream, "%%reserved"); |
887 | 246 | break; |
888 | | |
889 | 114 | case '/': |
890 | 114 | if (X_RS1 (insn) < 16 || X_RS1 (insn) > 28) |
891 | 0 | (*info->fprintf_func) (stream, "%%reserved"); |
892 | 114 | else |
893 | 114 | (*info->fprintf_func) (stream, "%%%s", |
894 | 114 | v9a_asr_reg_names[X_RS1 (insn)-16]); |
895 | 114 | break; |
896 | | |
897 | 171 | case '_': |
898 | 171 | if (X_RD (insn) < 16 || X_RD (insn) > 28) |
899 | 0 | (*info->fprintf_func) (stream, "%%reserved"); |
900 | 171 | else |
901 | 171 | (*info->fprintf_func) (stream, "%%%s", |
902 | 171 | v9a_asr_reg_names[X_RD (insn)-16]); |
903 | 171 | break; |
904 | | |
905 | 3.80k | case '*': |
906 | 3.80k | { |
907 | 3.80k | const char *name = sparc_decode_prefetch (X_RD (insn)); |
908 | | |
909 | 3.80k | if (name) |
910 | 2.20k | (*info->fprintf_func) (stream, "%s", name); |
911 | 1.59k | else |
912 | 1.59k | (*info->fprintf_func) (stream, "%ld", X_RD (insn)); |
913 | 3.80k | break; |
914 | 7.43k | } |
915 | | |
916 | 45 | case 'M': |
917 | 45 | (*info->fprintf_func) (stream, "%%asr%ld", X_RS1 (insn)); |
918 | 45 | break; |
919 | | |
920 | 850 | case 'm': |
921 | 850 | (*info->fprintf_func) (stream, "%%asr%ld", X_RD (insn)); |
922 | 850 | break; |
923 | | |
924 | 229k | case 'L': |
925 | 229k | info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; |
926 | 229k | (*info->print_address_func) (info->target, info); |
927 | 229k | break; |
928 | | |
929 | 193k | case 'n': |
930 | 193k | (*info->fprintf_func) |
931 | 193k | (stream, "%#x", SEX (X_DISP22 (insn), 22)); |
932 | 193k | break; |
933 | | |
934 | 64.2k | case 'l': |
935 | 64.2k | info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4; |
936 | 64.2k | (*info->print_address_func) (info->target, info); |
937 | 64.2k | break; |
938 | | |
939 | 18.7k | case 'A': |
940 | 18.7k | { |
941 | 18.7k | const char *name = sparc_decode_asi (X_ASI (insn)); |
942 | | |
943 | 18.7k | if (name) |
944 | 10.2k | (*info->fprintf_func) (stream, "%s", name); |
945 | 8.43k | else |
946 | 8.43k | (*info->fprintf_func) (stream, "(%ld)", X_ASI (insn)); |
947 | 18.7k | break; |
948 | 7.43k | } |
949 | | |
950 | 235 | case 'C': |
951 | 235 | (*info->fprintf_func) (stream, "%%csr"); |
952 | 235 | break; |
953 | | |
954 | 170 | case 'F': |
955 | 170 | (*info->fprintf_func) (stream, "%%fsr"); |
956 | 170 | break; |
957 | | |
958 | 96 | case '(': |
959 | 96 | (*info->fprintf_func) (stream, "%%efsr"); |
960 | 96 | break; |
961 | | |
962 | 109 | case 'p': |
963 | 109 | (*info->fprintf_func) (stream, "%%psr"); |
964 | 109 | break; |
965 | | |
966 | 304 | case 'q': |
967 | 304 | (*info->fprintf_func) (stream, "%%fq"); |
968 | 304 | break; |
969 | | |
970 | 149 | case 'Q': |
971 | 149 | (*info->fprintf_func) (stream, "%%cq"); |
972 | 149 | break; |
973 | | |
974 | 94 | case 't': |
975 | 94 | (*info->fprintf_func) (stream, "%%tbr"); |
976 | 94 | break; |
977 | | |
978 | 49 | case 'w': |
979 | 49 | (*info->fprintf_func) (stream, "%%wim"); |
980 | 49 | break; |
981 | | |
982 | 454 | case 'x': |
983 | 454 | (*info->fprintf_func) (stream, "%ld", |
984 | 454 | ((X_LDST_I (insn) << 8) |
985 | 454 | + X_ASI (insn))); |
986 | 454 | break; |
987 | | |
988 | 127 | case '|': /* 2-bit immediate */ |
989 | 127 | (*info->fprintf_func) (stream, "%ld", X_IMM2 (insn)); |
990 | 127 | break; |
991 | | |
992 | 216 | case 'y': |
993 | 216 | (*info->fprintf_func) (stream, "%%y"); |
994 | 216 | break; |
995 | | |
996 | 159 | case 'u': |
997 | 273 | case 'U': |
998 | 273 | { |
999 | 273 | int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn); |
1000 | 273 | const char *name = sparc_decode_sparclet_cpreg (val); |
1001 | | |
1002 | 273 | if (name) |
1003 | 159 | (*info->fprintf_func) (stream, "%s", name); |
1004 | 114 | else |
1005 | 114 | (*info->fprintf_func) (stream, "%%cpreg(%d)", val); |
1006 | 273 | break; |
1007 | 159 | } |
1008 | 1.99M | } |
1009 | 1.99M | } |
1010 | 967k | } |
1011 | | |
1012 | | /* If we are adding or or'ing something to rs1, then |
1013 | | check to see whether the previous instruction was |
1014 | | a sethi to the same register as in the sethi. |
1015 | | If so, attempt to print the result of the add or |
1016 | | or (in this context add and or do the same thing) |
1017 | | and its symbolic value. */ |
1018 | 967k | if (imm_ored_to_rs1 || imm_added_to_rs1) |
1019 | 111k | { |
1020 | 111k | unsigned long prev_insn; |
1021 | 111k | int errcode; |
1022 | | |
1023 | 111k | if (memaddr >= 4) |
1024 | 111k | errcode = |
1025 | 111k | (*info->read_memory_func) |
1026 | 111k | (memaddr - 4, buffer, sizeof (buffer), info); |
1027 | 2 | else |
1028 | 2 | errcode = 1; |
1029 | | |
1030 | 111k | prev_insn = getword (buffer); |
1031 | | |
1032 | 111k | if (errcode == 0) |
1033 | 100k | { |
1034 | | /* If it is a delayed branch, we need to look at the |
1035 | | instruction before the delayed branch. This handles |
1036 | | sequences such as: |
1037 | | |
1038 | | sethi %o1, %hi(_foo), %o1 |
1039 | | call _printf |
1040 | | or %o1, %lo(_foo), %o1 */ |
1041 | | |
1042 | 100k | if (is_delayed_branch (prev_insn)) |
1043 | 30.6k | { |
1044 | 30.6k | if (memaddr >= 8) |
1045 | 30.6k | errcode = (*info->read_memory_func) |
1046 | 30.6k | (memaddr - 8, buffer, sizeof (buffer), info); |
1047 | 0 | else |
1048 | 0 | errcode = 1; |
1049 | | |
1050 | 30.6k | prev_insn = getword (buffer); |
1051 | 30.6k | } |
1052 | 100k | } |
1053 | | |
1054 | | /* If there was a problem reading memory, then assume |
1055 | | the previous instruction was not sethi. */ |
1056 | 111k | if (errcode == 0) |
1057 | 100k | { |
1058 | | /* Is it sethi to the same register? */ |
1059 | 100k | if ((prev_insn & 0xc1c00000) == 0x01000000 |
1060 | 100k | && X_RD (prev_insn) == X_RS1 (insn)) |
1061 | 8.19k | { |
1062 | 8.19k | (*info->fprintf_func) (stream, "\t! "); |
1063 | 8.19k | info->target = (unsigned) X_IMM22 (prev_insn) << 10; |
1064 | 8.19k | if (imm_added_to_rs1) |
1065 | 5.30k | info->target += X_SIMM (insn, 13); |
1066 | 2.88k | else |
1067 | 2.88k | info->target |= X_SIMM (insn, 13); |
1068 | 8.19k | (*info->print_address_func) (info->target, info); |
1069 | 8.19k | info->insn_type = dis_dref; |
1070 | 8.19k | info->data_size = 4; /* FIXME!!! */ |
1071 | 8.19k | } |
1072 | 100k | } |
1073 | 111k | } |
1074 | | |
1075 | 967k | if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR)) |
1076 | 364k | { |
1077 | | /* FIXME -- check is_annulled flag. */ |
1078 | 364k | (void) is_annulled; |
1079 | 364k | if (opcode->flags & F_UNBR) |
1080 | 28.8k | info->insn_type = dis_branch; |
1081 | 364k | if (opcode->flags & F_CONDBR) |
1082 | 104k | info->insn_type = dis_condbranch; |
1083 | 364k | if (opcode->flags & F_JSR) |
1084 | 230k | info->insn_type = dis_jsr; |
1085 | 364k | if (opcode->flags & F_DELAYED) |
1086 | 363k | info->branch_delay_insns = 1; |
1087 | 364k | } |
1088 | | |
1089 | 967k | return sizeof (buffer); |
1090 | 967k | } |
1091 | 19.8M | } |
1092 | | |
1093 | 261k | info->insn_type = dis_noninsn; /* Mark as non-valid instruction. */ |
1094 | 261k | (*info->fprintf_func) (stream, _("unknown")); |
1095 | 261k | return sizeof (buffer); |
1096 | 1.22M | } |