Commit | Line | Data |
---|---|---|
d0ba1cea ILT |
1 | /* Print mips instructions for GDB, the GNU debugger, or for objdump. |
2 | Copyright 1989, 1991, 1992 Free Software Foundation, Inc. | |
3 | Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | #include "sysdep.h" | |
22 | #include <stdio.h> | |
23 | #include "bfd.h" | |
24 | #include "opcode/mips.h" | |
25 | ||
26 | /* FIXME: we need direct access to the swapping functions. */ | |
27 | #include "libbfd.h" | |
28 | ||
29 | /* We use bfd_vma in a couple of places where gdb expects CORE_ADDR. */ | |
30 | #ifdef HOST_64_BIT | |
31 | #error FIXME: bfd_vma will not match gdb expectations | |
32 | #endif | |
33 | ||
34 | /* This file is used both by gdb and by objdump. A program which | |
35 | wants to use this code must provide an external function | |
36 | print_address. */ | |
37 | extern int print_address PARAMS ((bfd_vma, FILE *)); | |
38 | ||
39 | /* Mips instructions are never longer than this many bytes. */ | |
40 | #define MAXLEN 4 | |
41 | ||
42 | /* Number of elements in the opcode table. */ | |
43 | #define NOPCODES (sizeof mips_opcodes / sizeof mips_opcodes[0]) | |
44 | \f | |
45 | /* FIXME: This should be shared with gdb somehow. */ | |
46 | #define REGISTER_NAMES \ | |
47 | { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ | |
48 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ | |
49 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ | |
50 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", \ | |
51 | "sr", "lo", "hi", "bad", "cause","pc", \ | |
52 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ | |
53 | "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ | |
54 | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\ | |
55 | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\ | |
56 | "fsr", "fir", "fp", "inx", "rand", "tlblo","ctxt", "tlbhi",\ | |
57 | "epc", "prid"\ | |
58 | } | |
59 | ||
60 | static CONST char * CONST reg_names[] = REGISTER_NAMES; | |
61 | \f | |
62 | /* subroutine */ | |
63 | static unsigned char * | |
64 | print_insn_arg (d, l, stream, pc) | |
65 | char *d; | |
66 | register unsigned long int *l; | |
67 | FILE *stream; | |
68 | bfd_vma pc; | |
69 | { | |
70 | switch (*d) | |
71 | { | |
72 | case ',': | |
73 | case '(': | |
74 | case ')': | |
75 | fputc (*d, stream); | |
76 | break; | |
77 | ||
78 | case 's': | |
79 | fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rs]); | |
80 | break; | |
81 | ||
82 | case 't': | |
83 | fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rt]); | |
84 | break; | |
85 | ||
86 | case 'i': | |
87 | fprintf (stream, "%d", ((struct op_i_fmt *) l)->immediate); | |
88 | break; | |
89 | ||
90 | case 'j': /* same as i, but sign-extended */ | |
91 | fprintf (stream, "%d", ((struct op_b_fmt *) l)->delta); | |
92 | break; | |
93 | ||
94 | case 'a': | |
95 | print_address ((pc & 0xF0000000) | (((struct op_j_fmt *)l)->target << 2), | |
96 | stream); | |
97 | break; | |
98 | ||
99 | case 'b': | |
100 | print_address ((((struct op_b_fmt *) l)->delta << 2) + pc + 4, stream); | |
101 | break; | |
102 | ||
103 | case 'd': | |
104 | fprintf (stream, "$%s", reg_names[((struct op_r_fmt *) l)->rd]); | |
105 | break; | |
106 | ||
107 | case 'h': | |
108 | fprintf (stream, "0x%x", ((struct op_r_fmt *) l)->shamt); | |
109 | break; | |
110 | ||
111 | case 'B': | |
112 | fprintf (stream, "0x%x", ((struct op_brk_fmt *) l)->code); | |
113 | break; | |
114 | ||
115 | case 'S': | |
116 | fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fs); | |
117 | break; | |
118 | ||
119 | case 'T': | |
120 | fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->ft); | |
121 | break; | |
122 | ||
123 | case 'D': | |
124 | fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fd); | |
125 | break; | |
126 | ||
127 | default: | |
128 | fprintf (stream, "# internal error, undefined modifier(%c)", *d); | |
129 | break; | |
130 | } | |
131 | } | |
132 | \f | |
133 | /* Print the mips instruction at address MEMADDR in debugged memory, | |
134 | on STREAM. Returns length of the instruction, in bytes, which is | |
135 | always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if | |
136 | this is little-endian code. */ | |
137 | ||
138 | int | |
139 | print_insn_mips (memaddr, buffer, stream, bigendian) | |
140 | bfd_vma memaddr; | |
141 | bfd_byte *buffer; | |
142 | FILE *stream; | |
143 | int bigendian; | |
144 | { | |
145 | register int i; | |
146 | register char *d; | |
147 | unsigned long int l; | |
148 | ||
149 | /* FIXME: can't we export these functions from bfd? */ | |
150 | if (bigendian) | |
151 | l = _do_getb32 (buffer); | |
152 | else | |
153 | l = _do_getl32 (buffer); | |
154 | ||
155 | for (i = 0; i < NOPCODES; i++) | |
156 | { | |
157 | register unsigned int opcode = mips_opcodes[i].opcode; | |
158 | register unsigned int match = mips_opcodes[i].match; | |
159 | if ((l & match) == opcode) | |
160 | break; | |
161 | } | |
162 | ||
163 | /* Handle undefined instructions. */ | |
164 | if (i == NOPCODES) | |
165 | { | |
166 | fprintf (stream, "0x%x",l); | |
167 | return 4; | |
168 | } | |
169 | ||
170 | fprintf (stream, "%s", mips_opcodes[i].name); | |
171 | ||
172 | if (!(d = mips_opcodes[i].args)) | |
173 | return 4; | |
174 | ||
175 | fputc (' ', stream); | |
176 | ||
177 | while (*d) | |
178 | print_insn_arg (d++, &l, stream, memaddr); | |
179 | ||
180 | return 4; | |
181 | } |