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); |
128 | bool RdIsZROrSP(const Instruction* instr) const { |
129 | return (instr->Rd() == kZeroRegCode); |
130 | } |
131 | |
132 | bool RnIsZROrSP(const Instruction* instr) const { |
133 | return (instr->Rn() == kZeroRegCode); |
134 | } |
135 | |
136 | bool RmIsZROrSP(const Instruction* instr) const { |
137 | return (instr->Rm() == kZeroRegCode); |
138 | } |
139 | |
140 | bool RaIsZROrSP(const Instruction* instr) const { |
141 | return (instr->Ra() == kZeroRegCode); |
142 | } |
143 | |
144 | bool IsMovzMovnImm(unsigned reg_size, uint64_t value); |
145 | |
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 | |
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: |
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 | |