This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / opcodes / pj-dis.c
1 /* pj-dis.c -- Disassemble picoJava instructions.
2    Copyright 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
3    Contributed by Steve Chamberlain, of Transmeta (sac@pobox.com).
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
18    MA 02110-1301, USA.  */
19
20 #include <stdio.h>
21 #include "sysdep.h"
22 #include "opcode/pj.h"
23 #include "dis-asm.h"
24
25 extern const pj_opc_info_t pj_opc_info[512];
26
27 static int
28 get_int (bfd_vma memaddr, int *iptr, struct disassemble_info *info)
29 {
30   unsigned char ival[4];
31   int status = info->read_memory_func (memaddr, ival, 4, info);
32
33   *iptr = (ival[0] << 24)
34     | (ival[1] << 16)
35     | (ival[2] << 8)
36     | (ival[3] << 0);
37
38   return status;
39 }
40
41 int
42 print_insn_pj (bfd_vma addr, struct disassemble_info *info)
43 {
44   fprintf_ftype fprintf_fn = info->fprintf_func;
45   void *stream = info->stream;
46   unsigned char opcode;
47   int status;
48
49   if ((status = info->read_memory_func (addr, &opcode, 1, info)))
50     goto fail;
51
52   if (opcode == 0xff)
53     {
54       unsigned char byte_2;
55
56       if ((status = info->read_memory_func (addr + 1, &byte_2, 1, info)))
57         goto fail;
58       fprintf_fn (stream, "%s\t", pj_opc_info[opcode + byte_2].u.name);
59       return 2;
60     }
61   else
62     {
63       char *sep = "\t";
64       int insn_start = addr;
65       const pj_opc_info_t *op = &pj_opc_info[opcode];
66       int a;
67
68       addr++;
69       fprintf_fn (stream, "%s", op->u.name);
70
71       /* The tableswitch instruction is followed by the default
72          address, low value, high value and the destinations.  */
73
74       if (strcmp (op->u.name, "tableswitch") == 0)
75         {
76           int lowval;
77           int highval;
78           int val;
79
80           addr = (addr + 3) & ~3;
81           if ((status = get_int (addr, &val, info)))
82             goto fail;
83
84           fprintf_fn (stream, " default: ");
85           (*info->print_address_func) (val + insn_start, info);
86           addr += 4;
87
88           if ((status = get_int (addr, &lowval, info)))
89             goto fail;
90           addr += 4;
91
92           if ((status = get_int (addr, &highval, info)))
93             goto fail;
94           addr += 4;
95
96           while (lowval <= highval)
97             {
98               if ((status = get_int (addr, &val, info)))
99                 goto fail;
100               fprintf_fn (stream, " %d:[", lowval);
101               (*info->print_address_func) (val + insn_start, info);
102               fprintf_fn (stream, " ]");
103               addr += 4;
104               lowval++;
105             }
106           return addr - insn_start;
107         }
108
109       /* The lookupswitch instruction is followed by the default
110          address, element count and pairs of values and
111          addresses.  */
112       if (strcmp (op->u.name, "lookupswitch") == 0)
113         {
114           int count;
115           int val;
116
117           addr = (addr + 3) & ~3;
118           if ((status = get_int (addr, &val, info)))
119             goto fail;
120           addr += 4;
121
122           fprintf_fn (stream, " default: ");
123           (*info->print_address_func) (val + insn_start, info);
124
125           if ((status = get_int (addr, &count, info)))
126             goto fail;
127           addr += 4;
128
129           while (count--)
130             {
131               if ((status = get_int (addr, &val, info)))
132                 goto fail;
133               addr += 4;
134               fprintf_fn (stream, " %d:[", val);
135
136               if ((status = get_int (addr, &val, info)))
137                 goto fail;
138               addr += 4;
139
140               (*info->print_address_func) (val + insn_start, info);
141               fprintf_fn (stream, " ]");
142             }
143           return addr - insn_start;
144         }
145
146       for (a = 0; op->arg[a]; a++)
147         {
148           unsigned char data[4];
149           int val = 0;
150           int i;
151           int size = ASIZE (op->arg[a]);
152
153           if ((status = info->read_memory_func (addr, data, size, info)))
154             goto fail;
155
156           val = (UNS (op->arg[0]) || ((data[0] & 0x80) == 0)) ? 0 : -1;
157
158           for (i = 0; i < size; i++)
159             val = (val << 8) | (data[i] & 0xff);
160
161           if (PCREL (op->arg[a]))
162             (*info->print_address_func) (val + insn_start, info);
163           else
164             fprintf_fn (stream, "%s%d", sep, val);
165
166           sep = ",";
167           addr += size;
168         }
169       return op->len;
170     }
171
172  fail:
173   info->memory_error_func (status, addr, info);
174   return -1;
175 }