1 // Copyright 2015, ARM Limited
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_A64_DISASM_A64_H
28 #define VIXL_A64_DISASM_A64_H
29 
30 #include "vixl/globals.h"
31 #include "vixl/utils.h"
32 #include "vixl/a64/instructions-a64.h"
33 #include "vixl/a64/decoder-a64.h"
34 #include "vixl/a64/assembler-a64.h"
35 
36 namespace vixl {
37 
38 class Disassembler: public DecoderVisitor {
39  public:
40   Disassembler();
41   Disassembler(char* text_buffer, int buffer_size);
42   virtual ~Disassembler();
43   char* GetOutput();
44 
45   // Declare all Visitor functions.
46   #define DECLARE(A) virtual void Visit##A(const Instruction* instr);
47   VISITOR_LIST(DECLARE)
48   #undef DECLARE
49 
50  protected:
51   virtual void ProcessOutput(const Instruction* instr);
52 
53   // Default output functions.  The functions below implement a default way of
54   // printing elements in the disassembly. A sub-class can override these to
55   // customize the disassembly output.
56 
57   // Prints the name of a register.
58   // TODO: This currently doesn't allow renaming of V registers.
59   virtual void AppendRegisterNameToOutput(const Instruction* instr,
60                                           const CPURegister& reg);
61 
62   // Prints a PC-relative offset. This is used for example when disassembling
63   // branches to immediate offsets.
64   virtual void AppendPCRelativeOffsetToOutput(const Instruction* instr,
65                                               int64_t offset);
66 
67   // Prints an address, in the general case. It can be code or data. This is
68   // used for example to print the target address of an ADR instruction.
69   virtual void AppendCodeRelativeAddressToOutput(const Instruction* instr,
70                                                  const void* addr);
71 
72   // Prints the address of some code.
73   // This is used for example to print the target address of a branch to an
74   // immediate offset.
75   // A sub-class can for example override this method to lookup the address and
76   // print an appropriate name.
77   virtual void AppendCodeRelativeCodeAddressToOutput(const Instruction* instr,
78                                                      const void* addr);
79 
80   // Prints the address of some data.
81   // This is used for example to print the source address of a load literal
82   // instruction.
83   virtual void AppendCodeRelativeDataAddressToOutput(const Instruction* instr,
84                                                      const void* addr);
85 
86   // Same as the above, but for addresses that are not relative to the code
87   // buffer. They are currently not used by VIXL.
88   virtual void AppendAddressToOutput(const Instruction* instr,
89                                      const void* addr);
90   virtual void AppendCodeAddressToOutput(const Instruction* instr,
91                                          const void* addr);
92   virtual void AppendDataAddressToOutput(const Instruction* instr,
93                                          const void* addr);
94 
95  public:
96   // Get/Set the offset that should be added to code addresses when printing
97   // code-relative addresses in the AppendCodeRelative<Type>AddressToOutput()
98   // helpers.
99   // Below is an example of how a branch immediate instruction in memory at
100   // address 0xb010200 would disassemble with different offsets.
101   // Base address | Disassembly
102   //          0x0 | 0xb010200:  b #+0xcc  (addr 0xb0102cc)
103   //      0x10000 | 0xb000200:  b #+0xcc  (addr 0xb0002cc)
104   //    0xb010200 |       0x0:  b #+0xcc  (addr 0xcc)
105   void MapCodeAddress(int64_t base_address, const Instruction* instr_address);
106   int64_t CodeRelativeAddress(const void* instr);
107 
108  private:
109   void Format(
110       const Instruction* instr, const char* mnemonic, const char* format);
111   void Substitute(const Instruction* instr, const char* string);
112   int SubstituteField(const Instruction* instr, const char* format);
113   int SubstituteRegisterField(const Instruction* instr, const char* format);
114   int SubstituteImmediateField(const Instruction* instr, const char* format);
115   int SubstituteLiteralField(const Instruction* instr, const char* format);
116   int SubstituteBitfieldImmediateField(
117       const Instruction* instr, const char* format);
118   int SubstituteShiftField(const Instruction* instr, const char* format);
119   int SubstituteExtendField(const Instruction* instr, const char* format);
120   int SubstituteConditionField(const Instruction* instr, const char* format);
121   int SubstitutePCRelAddressField(const Instruction* instr, const char* format);
122   int SubstituteBranchTargetField(const Instruction* instr, const char* format);
123   int SubstituteLSRegOffsetField(const Instruction* instr, const char* format);
124   int SubstitutePrefetchField(const Instruction* instr, const char* format);
125   int SubstituteBarrierField(const Instruction* instr, const char* format);
126   int SubstituteSysOpField(const Instruction* instr, const char* format);
127   int SubstituteCrField(const Instruction* instr, const char* format);
RdIsZROrSP(const Instruction * instr)128   bool RdIsZROrSP(const Instruction* instr) const {
129     return (instr->Rd() == kZeroRegCode);
130   }
131 
RnIsZROrSP(const Instruction * instr)132   bool RnIsZROrSP(const Instruction* instr) const {
133     return (instr->Rn() == kZeroRegCode);
134   }
135 
RmIsZROrSP(const Instruction * instr)136   bool RmIsZROrSP(const Instruction* instr) const {
137     return (instr->Rm() == kZeroRegCode);
138   }
139 
RaIsZROrSP(const Instruction * instr)140   bool RaIsZROrSP(const Instruction* instr) const {
141     return (instr->Ra() == kZeroRegCode);
142   }
143 
144   bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
145 
code_address_offset()146   int64_t code_address_offset() const { return code_address_offset_; }
147 
148  protected:
149   void ResetOutput();
150   void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3);
151 
set_code_address_offset(int64_t code_address_offset)152   void set_code_address_offset(int64_t code_address_offset) {
153     code_address_offset_ = code_address_offset;
154   }
155 
156   char* buffer_;
157   uint32_t buffer_pos_;
158   uint32_t buffer_size_;
159   bool own_buffer_;
160 
161   int64_t code_address_offset_;
162 };
163 
164 
165 class PrintDisassembler: public Disassembler {
166  public:
PrintDisassembler(FILE * stream)167   explicit PrintDisassembler(FILE* stream) : stream_(stream) { }
168 
169  protected:
170   virtual void ProcessOutput(const Instruction* instr);
171 
172  private:
173   FILE *stream_;
174 };
175 }  // namespace vixl
176 
177 #endif  // VIXL_A64_DISASM_A64_H
178