• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014, 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 #include "custom-disassembler.h"
28 
29 #include <regex>
30 
31 #include "examples.h"
32 
33 using namespace vixl;
34 using namespace vixl::aarch64;
35 
36 #define __ masm->
37 
38 
39 // We override this method to specify how register names should be disassembled.
AppendRegisterNameToOutput(const Instruction * instr,const CPURegister & reg)40 void CustomDisassembler::AppendRegisterNameToOutput(const Instruction* instr,
41                                                     const CPURegister& reg) {
42   USE(instr);
43   if (reg.IsRegister()) {
44     switch (reg.GetCode()) {
45       case 16:
46         AppendToOutput(reg.Is64Bits() ? "ip0" : "wip0");
47         return;
48       case 17:
49         AppendToOutput(reg.Is64Bits() ? "ip1" : "wip1");
50         return;
51       case 30:
52         AppendToOutput(reg.Is64Bits() ? "lr" : "w30");
53         return;
54       case kSPRegInternalCode:
55         AppendToOutput(reg.Is64Bits() ? "x_stack_pointer" : "w_stack_pointer");
56         return;
57       case 31:
58         AppendToOutput(reg.Is64Bits() ? "x_zero_reg" : "w_zero_reg");
59         return;
60       default:
61         // Fall through.
62         break;
63     }
64   }
65   // Print other register names as usual.
66   Disassembler::AppendRegisterNameToOutput(instr, reg);
67 }
68 
69 
FakeLookupTargetDescription(const void * address)70 static const char* FakeLookupTargetDescription(const void* address) {
71   USE(address);
72   // We fake looking up the address.
73   static int i = 0;
74   const char* desc = NULL;
75   if (i == 0) {
76     desc = "label: somewhere";
77   } else if (i == 2) {
78     desc = "label: somewhere else";
79   }
80   i++;
81   return desc;
82 }
83 
84 
85 // We override this method to add a description to addresses that we know about.
86 // In this example we fake looking up a description, but in practice one could
87 // for example use a table mapping addresses to function names.
AppendCodeRelativeCodeAddressToOutput(const Instruction * instr,const void * addr)88 void CustomDisassembler::AppendCodeRelativeCodeAddressToOutput(
89     const Instruction* instr, const void* addr) {
90   USE(instr);
91   // Print the address.
92   int64_t rel_addr = CodeRelativeAddress(addr);
93   if (rel_addr >= 0) {
94     AppendToOutput("(addr 0x%" PRIx64, rel_addr);
95   } else {
96     AppendToOutput("(addr -0x%" PRIx64, -rel_addr);
97   }
98 
99   // If available, print a description of the address.
100   const char* address_desc = FakeLookupTargetDescription(addr);
101   if (address_desc != NULL) {
102     Disassembler::AppendToOutput(" ; %s", address_desc);
103   }
104   AppendToOutput(")");
105 }
106 
107 
108 // We override this method to add a comment to some instructions. Helpers from
109 // the vixl::Instruction class can be used to analyse the instruction being
110 // disassembled.
Visit(Metadata * metadata,const Instruction * instr)111 void CustomDisassembler::Visit(Metadata* metadata, const Instruction* instr) {
112   vixl::aarch64::Disassembler::Visit(metadata, instr);
113   const std::string& form = (*metadata)["form"];
114 
115   // Match the forms for 32/64-bit add/subtract with shift, with optional flag
116   // setting.
117   if (std::regex_match(form,  // NOLINT: avoid clang-tidy-4.0 errors.
118                        std::regex("(?:add|sub)s?_(?:32|64)_addsub_shift"))) {
119     if (instr->GetRd() == 10) {
120       AppendToOutput(" // add/sub to x10");
121     }
122   }
123   ProcessOutput(instr);
124 }
125 
126 
GenerateCustomDisassemblerTestCode(MacroAssembler * masm)127 void GenerateCustomDisassemblerTestCode(MacroAssembler* masm) {
128   // Generate some code to illustrate how the modified disassembler changes the
129   // disassembly output.
130   Label begin, end;
131   __ Bind(&begin);
132   __ Add(x10, x16, x17);
133   __ Cbz(x10, &end);
134   __ Add(x11, ip0, ip1);
135   __ Add(w5, w6, w30);
136   __ Tbz(x10, 2, &begin);
137   __ Tbnz(x10, 3, &begin);
138   __ Br(x30);
139   __ Br(lr);
140   __ Fadd(d30, d16, d17);
141   __ Push(xzr, xzr);
142   __ Pop(x16, x20);
143   __ Bind(&end);
144 }
145 
146 
TestCustomDisassembler()147 void TestCustomDisassembler() {
148   MacroAssembler masm;
149 
150   // Generate the code.
151   Label code_start, code_end;
152   masm.Bind(&code_start);
153   GenerateCustomDisassemblerTestCode(&masm);
154   masm.Bind(&code_end);
155   masm.FinalizeCode();
156   Instruction* instr_start = masm.GetLabelAddress<Instruction*>(&code_start);
157   Instruction* instr_end = masm.GetLabelAddress<Instruction*>(&code_end);
158 
159   // Instantiate a standard disassembler, our custom disassembler, and register
160   // them with a decoder.
161   Decoder decoder;
162   Disassembler disasm;
163   CustomDisassembler custom_disasm;
164   decoder.AppendVisitor(&disasm);
165   decoder.AppendVisitor(&custom_disasm);
166 
167   // In our custom disassembler, disassemble as if the base address was -0x8.
168   // Note that this can also be achieved with
169   //   custom_disasm.MapCodeAddress(0x0, instr_start + 2 * kInstructionSize);
170   // Users may generally want to map the start address to 0x0. Mapping to a
171   // negative offset can be used to focus on the section of the
172   // disassembly at address 0x0.
173   custom_disasm.MapCodeAddress(-0x8, instr_start);
174 
175   // Iterate through the instructions to show the difference in the disassembly.
176   Instruction* instr;
177   for (instr = instr_start; instr < instr_end; instr += kInstructionSize) {
178     decoder.Decode(instr);
179     printf("\n");
180     printf("VIXL disasm\t %p:\t%s\n",
181            reinterpret_cast<void*>(instr),
182            disasm.GetOutput());
183     int64_t rel_addr =
184         custom_disasm.CodeRelativeAddress(reinterpret_cast<void*>(instr));
185     char rel_addr_sign_char = ' ';
186     if (rel_addr < 0) {
187       rel_addr_sign_char = '-';
188       rel_addr = -rel_addr;
189     }
190     printf("custom disasm\t%c0x%" PRIx64 ":\t%s\n",
191            rel_addr_sign_char,
192            rel_addr,
193            custom_disasm.GetOutput());
194   }
195 }
196 
197 
198 #ifndef TEST_EXAMPLES
main()199 int main() {
200   TestCustomDisassembler();
201   return 0;
202 }
203 #endif
204