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