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