HPCToolkit
SparcISA.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //***************************************************************************
48 //
49 // File:
50 // $HeadURL$
51 //
52 // Purpose:
53 // [The purpose of this file]
54 //
55 // Description:
56 // [The set of functions, macros, etc. defined in the file]
57 //
58 //***************************************************************************
59 
60 //************************* System Include Files ****************************
61 
62 #include <iostream>
63 using std::ostream;
64 
65 #include <cstdarg>
66 #include <cstring> // for 'memcpy'
67 
68 //*************************** User Include Files ****************************
69 
70 #include <include/gnu_dis-asm.h>
71 
72 #include "SparcISA.hpp"
73 
75 
76 //*************************** Forward Declarations ***************************
77 
78 static VMA
79 GNUvma2vma(bfd_vma di_vma, MachInsn* insn_addr, VMA insn_vma)
80 {
81  // N.B.: The GNU decoders assume that the address of 'insn_addr' is
82  // the actual the VMA in order to calculate VMA-relative targets.
83  VMA x = (di_vma - PTR_TO_BFDVMA(insn_addr)) + insn_vma;
84  return x;
85 }
86 
87 
88 static void
89 GNUbu_print_addr(bfd_vma di_vma, struct disassemble_info* di)
90 {
91  GNUbu_disdata* data = (GNUbu_disdata*)di->application_data;
92 
93  VMA x = GNUvma2vma(di_vma, data->insn_addr, data->insn_vma);
94  ostream* os = (ostream*)di->stream;
95  *os << std::showbase << std::hex << x << std::dec;
96 }
97 
98 
99 //****************************************************************************
100 // SparcISA
101 //****************************************************************************
102 
104  : m_di(NULL), m_di_dis(NULL)
105 {
106  // See 'dis-asm.h'
107  m_di = new disassemble_info;
108  init_disassemble_info(m_di, stdout, GNUbu_fprintf_stub);
109  m_di->arch = bfd_arch_sparc; // bfd_get_arch (abfd);
110  m_di->mach = bfd_mach_sparc_v9; // bfd_get_mach(abfd)
111  m_di->endian = BFD_ENDIAN_BIG;
112  m_di->read_memory_func = GNUbu_read_memory; // vs. 'buffer_read_memory'
113  m_di->print_address_func = GNUbu_print_addr_stub; // vs. 'generic_print_addr'
114 
115  m_di_dis = new disassemble_info;
116  init_disassemble_info(m_di_dis, stdout, GNUbu_fprintf);
117  m_di_dis->application_data = (void*)&m_dis_data;
118  m_di_dis->arch = m_di->arch;
119  m_di_dis->mach = m_di->mach;
120  m_di_dis->endian = m_di->endian;
121  m_di_dis->read_memory_func = GNUbu_read_memory;
122  m_di_dis->print_address_func = GNUbu_print_addr;
123 }
124 
125 
127 {
128  delete m_di;
129  delete m_di_dis;
130 }
131 
132 
136 {
137  ISA::InsnDesc d;
138 
139  if (cacheLookup(mi) == NULL) {
140  int size = print_insn_sparc(PTR_TO_BFDVMA(mi), m_di);
141  cacheSet(mi, (ushort)size);
142  }
143 
144  // The target field is set (to an absolute vma) on PC-relative
145  // branches/jumps. However, the target field is also set after
146  // sequences of the form {sethi, insn}, where insn uses the same
147  // register as in sethi. Because {sethi, jmp} sequences are
148  // possible, the target field can also be set (to an absolute vma)
149  // in the case of a register indirect jump. We need some way to
150  // distinguish because of the way GNU calculates PC-relative
151  // targets.
152  bool isPCRel = (m_di->target2 == 0); // FIXME: binutils needs fixing
153 
154  switch (m_di->insn_type) {
155  case dis_noninsn:
157  break;
158  case dis_branch:
159  if (m_di->target != 0 && isPCRel) {
161  }
162  else {
164  }
165  break;
166  case dis_condbranch:
167  if (m_di->target != 0 && isPCRel) {
168  d.set(InsnDesc::INT_BR_COND_REL); // arbitrarily choose int
169  }
170  else {
171  d.set(InsnDesc::INT_BR_COND_IND); // arbitrarily choose int
172  }
173  break;
174  case dis_jsr:
175  if (m_di->target != 0 && isPCRel) {
177  }
178  else {
180  }
181  break;
182  case dis_condjsr:
183  d.set(InsnDesc::OTHER);
184  break;
185  case dis_return:
187  break;
188  case dis_dref:
189  case dis_dref2:
191  break;
192  default:
193  d.set(InsnDesc::OTHER);
194  break;
195  }
196  return d;
197 }
198 
199 
200 VMA
202 {
203  // N.B.: The GNU decoders assume that the address of 'mi' is
204  // actually the VMA in order to calculate VMA-relative targets.
205 
206  if (cacheLookup(mi) == NULL) {
207  int size = print_insn_sparc(PTR_TO_BFDVMA(mi), m_di);
208  cacheSet(mi, (ushort)size);
209  }
210 
211  ISA::InsnDesc d = getInsnDesc(mi, opIndex, sz);
212  if (d.isBrRel() || d.isSubrRel()) {
213  return GNUvma2vma(m_di->target, mi, vma);
214  }
215  else {
216  // return m_di->target; // return the results of sethi instruction chains
217  return 0;
218  }
219 }
220 
221 
222 ushort
224 {
225  // SPARC branch instructions have an architectural delay slot of one
226  // instruction, but in certain cases it can effectively be zero. If
227  // the annul bit is set in the case of an unconditional
228  // (branch-always or branch-never) branch instruction (that is, BA,
229  // FBA, CBA, BN, FBN, and CBN), the delay instruction is not
230  // executed.
231 
232  // Unfortunately there is not yet a good way to pass annullment
233  // information back from binutils. Fortunately, it is currently not
234  // that important.
235 
236  // (We don't care about delays on instructions such as loads/stores)
237 
238  ISA::InsnDesc d = getInsnDesc(mi, opIndex, sz);
239  if (d.isBr() || d.isSubr() || d.isSubrRet()) {
240  return 1;
241  }
242  else {
243  return 0;
244  }
245 }
246 
247 
248 void
249 SparcISA::decode(ostream& os, MachInsn* mi, VMA vma,
250  ushort GCC_ATTR_UNUSED opIndex)
251 {
253  m_dis_data.insn_vma = vma;
254 
255  m_di_dis->stream = (void*)&os;
256  print_insn_sparc(PTR_TO_BFDVMA(mi), m_di_dis);
257 }
258 
259 
260 //****************************************************************************
static void GNUbu_print_addr(bfd_vma di_vma, struct disassemble_info *di)
Definition: SparcISA.cpp:89
bool isSubrRel() const
Definition: ISA.hpp:278
bfd_vma VMA
Definition: ISATypes.hpp:79
virtual VMA getInsnTargetVMA(MachInsn *mi, VMA pc, ushort opIndex, ushort sz=0)
Definition: SparcISA.cpp:201
bool isSubr() const
Definition: ISA.hpp:273
virtual InsnDesc getInsnDesc(MachInsn *mi, ushort opIndex, ushort sz=0)
Definition: SparcISA.cpp:134
bool isBrRel() const
Definition: ISA.hpp:236
#define PTR_TO_BFDVMA(x)
Definition: ISATypes.hpp:94
int GNUbu_fprintf(void *stream, const char *format,...)
Definition: ISA.cpp:173
int GNUbu_fprintf_stub(void *GCC_ATTR_UNUSED stream, const char *GCC_ATTR_UNUSED format,...)
Definition: ISA.cpp:191
DecodingCache * cacheLookup(MachInsn *cmi)
Definition: ISA.hpp:489
GNUbu_disdata m_dis_data
Definition: SparcISA.hpp:136
#define dis_return
Definition: gnu_dis-asm.h:79
bool isSubrRet() const
Definition: ISA.hpp:288
virtual ~SparcISA()
Definition: SparcISA.cpp:126
unsigned short int ushort
Definition: uint.h:120
void set(IType t)
Definition: ISA.hpp:348
struct disassemble_info * m_di
Definition: SparcISA.hpp:134
struct disassemble_info * m_di_dis
Definition: SparcISA.hpp:135
bool isBr() const
Definition: ISA.hpp:231
int GNUbu_read_memory(bfd_vma vma, bfd_byte *myaddr, unsigned int len, struct disassemble_info *GCC_ATTR_UNUSED di)
Definition: ISA.cpp:206
void cacheSet(MachInsn *cmi, ushort size)
Definition: ISA.hpp:501
MachInsn * insn_addr
Definition: ISA.hpp:516
virtual ushort getInsnNumDelaySlots(MachInsn *mi, ushort opIndex, ushort sz=0)
Definition: SparcISA.cpp:223
void GNUbu_print_addr_stub(bfd_vma GCC_ATTR_UNUSED di_vma, struct disassemble_info *GCC_ATTR_UNUSED di)
Definition: ISA.cpp:199
VMA insn_vma
Definition: ISA.hpp:517
void MachInsn
Definition: ISATypes.hpp:87
static VMA GNUvma2vma(bfd_vma di_vma, MachInsn *insn_addr, VMA insn_vma)
Definition: SparcISA.cpp:79
#define NULL
Definition: ElfHelper.cpp:85
#define GCC_ATTR_UNUSED
Definition: gcc-attr.h:80
static MachInsn * mi
Definition: x86ISAXed.cpp:91
virtual void decode(std::ostream &os, MachInsn *mi, VMA vma, ushort opIndex)
Definition: SparcISA.cpp:249