• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of ARM Limited nor the names of its contributors may be
13 //     used to endorse or promote products derived from this software without
14 //     specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #ifndef VIXL_AARCH64_DISASM_AARCH64_H
28 #define VIXL_AARCH64_DISASM_AARCH64_H
29 
30 #include <utility>
31 
32 #include "../globals-vixl.h"
33 #include "../utils-vixl.h"
34 
35 #include "cpu-features-auditor-aarch64.h"
36 #include "decoder-aarch64.h"
37 #include "instructions-aarch64.h"
38 #include "operands-aarch64.h"
39 
40 namespace vixl {
41 namespace aarch64 {
42 
43 class Disassembler : public DecoderVisitor {
44  public:
45   Disassembler();
46   Disassembler(char* text_buffer, int buffer_size);
47   virtual ~Disassembler();
48   char* GetOutput();
49 
50 // Declare all Visitor functions.
51 #define DECLARE(A) \
52   virtual void Visit##A(const Instruction* instr) VIXL_OVERRIDE;
53   VISITOR_LIST(DECLARE)
54 #undef DECLARE
55 
56  protected:
57   virtual void ProcessOutput(const Instruction* instr);
58 
59   // Default output functions. The functions below implement a default way of
60   // printing elements in the disassembly. A sub-class can override these to
61   // customize the disassembly output.
62 
63   // Prints the name of a register.
64   // TODO: This currently doesn't allow renaming of V registers.
65   virtual void AppendRegisterNameToOutput(const Instruction* instr,
66                                           const CPURegister& reg);
67 
68   // Prints a PC-relative offset. This is used for example when disassembling
69   // branches to immediate offsets.
70   virtual void AppendPCRelativeOffsetToOutput(const Instruction* instr,
71                                               int64_t offset);
72 
73   // Prints an address, in the general case. It can be code or data. This is
74   // used for example to print the target address of an ADR instruction.
75   virtual void AppendCodeRelativeAddressToOutput(const Instruction* instr,
76                                                  const void* addr);
77 
78   // Prints the address of some code.
79   // This is used for example to print the target address of a branch to an
80   // immediate offset.
81   // A sub-class can for example override this method to lookup the address and
82   // print an appropriate name.
83   virtual void AppendCodeRelativeCodeAddressToOutput(const Instruction* instr,
84                                                      const void* addr);
85 
86   // Prints the address of some data.
87   // This is used for example to print the source address of a load literal
88   // instruction.
89   virtual void AppendCodeRelativeDataAddressToOutput(const Instruction* instr,
90                                                      const void* addr);
91 
92   // Same as the above, but for addresses that are not relative to the code
93   // buffer. They are currently not used by VIXL.
94   virtual void AppendAddressToOutput(const Instruction* instr,
95                                      const void* addr);
96   virtual void AppendCodeAddressToOutput(const Instruction* instr,
97                                          const void* addr);
98   virtual void AppendDataAddressToOutput(const Instruction* instr,
99                                          const void* addr);
100 
101  public:
102   // Get/Set the offset that should be added to code addresses when printing
103   // code-relative addresses in the AppendCodeRelative<Type>AddressToOutput()
104   // helpers.
105   // Below is an example of how a branch immediate instruction in memory at
106   // address 0xb010200 would disassemble with different offsets.
107   // Base address | Disassembly
108   //          0x0 | 0xb010200:  b #+0xcc  (addr 0xb0102cc)
109   //      0x10000 | 0xb000200:  b #+0xcc  (addr 0xb0002cc)
110   //    0xb010200 |       0x0:  b #+0xcc  (addr 0xcc)
111   void MapCodeAddress(int64_t base_address, const Instruction* instr_address);
112   int64_t CodeRelativeAddress(const void* instr);
113 
114  private:
115   void Format(const Instruction* instr,
116               const char* mnemonic,
117               const char* format0,
118               const char* format1 = NULL);
119   void Substitute(const Instruction* instr, const char* string);
120   int SubstituteField(const Instruction* instr, const char* format);
121   int SubstituteRegisterField(const Instruction* instr, const char* format);
122   int SubstitutePredicateRegisterField(const Instruction* instr,
123                                        const char* format);
124   int SubstituteImmediateField(const Instruction* instr, const char* format);
125   int SubstituteLiteralField(const Instruction* instr, const char* format);
126   int SubstituteBitfieldImmediateField(const Instruction* instr,
127                                        const char* format);
128   int SubstituteShiftField(const Instruction* instr, const char* format);
129   int SubstituteExtendField(const Instruction* instr, const char* format);
130   int SubstituteConditionField(const Instruction* instr, const char* format);
131   int SubstitutePCRelAddressField(const Instruction* instr, const char* format);
132   int SubstituteBranchTargetField(const Instruction* instr, const char* format);
133   int SubstituteLSRegOffsetField(const Instruction* instr, const char* format);
134   int SubstitutePrefetchField(const Instruction* instr, const char* format);
135   int SubstituteBarrierField(const Instruction* instr, const char* format);
136   int SubstituteSysOpField(const Instruction* instr, const char* format);
137   int SubstituteCrField(const Instruction* instr, const char* format);
138   int SubstituteIntField(const Instruction* instr, const char* format);
139   int SubstituteSVESize(const Instruction* instr, const char* format);
140   int SubstituteTernary(const Instruction* instr, const char* format);
141 
142   std::pair<unsigned, unsigned> GetRegNumForField(const Instruction* instr,
143                                                   char reg_prefix,
144                                                   const char* field);
145 
RdIsZROrSP(const Instruction * instr)146   bool RdIsZROrSP(const Instruction* instr) const {
147     return (instr->GetRd() == kZeroRegCode);
148   }
149 
RnIsZROrSP(const Instruction * instr)150   bool RnIsZROrSP(const Instruction* instr) const {
151     return (instr->GetRn() == kZeroRegCode);
152   }
153 
RmIsZROrSP(const Instruction * instr)154   bool RmIsZROrSP(const Instruction* instr) const {
155     return (instr->GetRm() == kZeroRegCode);
156   }
157 
RaIsZROrSP(const Instruction * instr)158   bool RaIsZROrSP(const Instruction* instr) const {
159     return (instr->GetRa() == kZeroRegCode);
160   }
161 
162   bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
163 
code_address_offset()164   int64_t code_address_offset() const { return code_address_offset_; }
165 
166  protected:
167   void ResetOutput();
168   void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3);
169 
set_code_address_offset(int64_t code_address_offset)170   void set_code_address_offset(int64_t code_address_offset) {
171     code_address_offset_ = code_address_offset;
172   }
173 
174   char* buffer_;
175   uint32_t buffer_pos_;
176   uint32_t buffer_size_;
177   bool own_buffer_;
178 
179   int64_t code_address_offset_;
180 };
181 
182 
183 class PrintDisassembler : public Disassembler {
184  public:
PrintDisassembler(FILE * stream)185   explicit PrintDisassembler(FILE* stream)
186       : cpu_features_auditor_(NULL),
187         cpu_features_prefix_("// Needs: "),
188         cpu_features_suffix_(""),
189         signed_addresses_(false),
190         stream_(stream) {}
191 
192   // Convenience helpers for quick disassembly, without having to manually
193   // create a decoder.
194   void DisassembleBuffer(const Instruction* start, uint64_t size);
195   void DisassembleBuffer(const Instruction* start, const Instruction* end);
196   void Disassemble(const Instruction* instr);
197 
198   // If a CPUFeaturesAuditor is specified, it will be used to annotate
199   // disassembly. The CPUFeaturesAuditor is expected to visit the instructions
200   // _before_ the disassembler, such that the CPUFeatures information is
201   // available when the disassembler is called.
RegisterCPUFeaturesAuditor(CPUFeaturesAuditor * auditor)202   void RegisterCPUFeaturesAuditor(CPUFeaturesAuditor* auditor) {
203     cpu_features_auditor_ = auditor;
204   }
205 
206   // Set the prefix to appear before the CPU features annotations.
SetCPUFeaturesPrefix(const char * prefix)207   void SetCPUFeaturesPrefix(const char* prefix) {
208     VIXL_ASSERT(prefix != NULL);
209     cpu_features_prefix_ = prefix;
210   }
211 
212   // Set the suffix to appear after the CPU features annotations.
SetCPUFeaturesSuffix(const char * suffix)213   void SetCPUFeaturesSuffix(const char* suffix) {
214     VIXL_ASSERT(suffix != NULL);
215     cpu_features_suffix_ = suffix;
216   }
217 
218   // By default, addresses are printed as simple, unsigned 64-bit hex values.
219   //
220   // With `PrintSignedAddresses(true)`:
221   //  - negative addresses are printed as "-0x1234...",
222   //  - positive addresses have a leading space, like " 0x1234...", to maintain
223   //    alignment.
224   //
225   // This is most useful in combination with Disassembler::MapCodeAddress(...).
PrintSignedAddresses(bool s)226   void PrintSignedAddresses(bool s) { signed_addresses_ = s; }
227 
228  protected:
229   virtual void ProcessOutput(const Instruction* instr) VIXL_OVERRIDE;
230 
231   CPUFeaturesAuditor* cpu_features_auditor_;
232   const char* cpu_features_prefix_;
233   const char* cpu_features_suffix_;
234   bool signed_addresses_;
235 
236  private:
237   FILE* stream_;
238 };
239 }  // namespace aarch64
240 }  // namespace vixl
241 
242 #endif  // VIXL_AARCH64_DISASM_AARCH64_H
243