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