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
25extern const pj_opc_info_t pj_opc_info[512];
26
27static int
28get_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
41int
42print_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}
176