disassembler_x86_unittest.cc
1 // Copyright 2010 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #ifdef HAVE_CONFIG_H 30 #include <config.h> // Must come first 31 #endif 32 33 #include <unistd.h> 34 35 #include "breakpad_googletest_includes.h" 36 #include "processor/disassembler_x86.h" 37 #include "third_party/libdisasm/libdis.h" 38 39 namespace { 40 41 using google_breakpad::DisassemblerX86; 42 43 unsigned char just_return[] = "\xc3"; // retn 44 45 unsigned char invalid_instruction[] = "\x00"; // invalid 46 47 unsigned char read_eax_jmp_eax[] = 48 "\x8b\x18" // mov ebx, [eax]; 49 "\x33\xc9" // xor ebx, ebx; 50 "\xff\x20" // jmp eax; 51 "\xc3"; // retn; 52 53 unsigned char write_eax_arg_to_call[] = 54 "\x89\xa8\x00\x02\x00\x00" // mov [eax+200], ebp; 55 "\xc1\xeb\x02" // shr ebx, 2; 56 "\x50" // push eax; 57 "\xe8\xd1\x24\x77\x88" // call something; 58 "\xc3"; // retn; 59 60 unsigned char read_edi_stosb[] = 61 "\x8b\x07" // mov eax, [edi]; 62 "\x8b\xc8" // mov ecx, eax; 63 "\xf3\xaa" // rep stosb; 64 "\xc3"; // retn; 65 66 unsigned char read_clobber_write[] = 67 "\x03\x18" // add ebx, [eax]; 68 "\x8b\xc1" // mov eax, ecx; 69 "\x89\x10" // mov [eax], edx; 70 "\xc3"; // retn; 71 72 unsigned char read_xchg_write[] = 73 "\x03\x18" // add ebx, [eax]; 74 "\x91" // xchg eax, ecx; 75 "\x89\x18" // mov [eax], ebx; 76 "\x89\x11" // mov [ecx], edx; 77 "\xc3"; // retn; 78 79 unsigned char read_cmp[] = 80 "\x03\x18" // add ebx, [eax]; 81 "\x83\xf8\x00" // cmp eax, 0; 82 "\x74\x04" // je +4; 83 "\xc3"; // retn; 84 85 TEST(DisassemblerX86Test, SimpleReturnInstruction) { 86 DisassemblerX86 dis(just_return, sizeof(just_return)-1, 0); 87 EXPECT_EQ(1U, dis.NextInstruction()); 88 EXPECT_TRUE(dis.currentInstructionValid()); 89 EXPECT_EQ(0U, dis.flags()); 90 EXPECT_TRUE(dis.endOfBlock()); 91 EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); 92 const libdis::x86_insn_t* instruction = dis.currentInstruction(); 93 EXPECT_EQ(libdis::insn_controlflow, instruction->group); 94 EXPECT_EQ(libdis::insn_return, instruction->type); 95 EXPECT_EQ(0U, dis.NextInstruction()); 96 EXPECT_FALSE(dis.currentInstructionValid()); 97 EXPECT_EQ(NULL, dis.currentInstruction()); 98 } 99 100 TEST(DisassemblerX86Test, SimpleInvalidInstruction) { 101 DisassemblerX86 dis(invalid_instruction, sizeof(invalid_instruction)-1, 0); 102 EXPECT_EQ(0U, dis.NextInstruction()); 103 EXPECT_FALSE(dis.currentInstructionValid()); 104 } 105 106 TEST(DisassemblerX86Test, BadReadLeadsToBranch) { 107 DisassemblerX86 dis(read_eax_jmp_eax, sizeof(read_eax_jmp_eax)-1, 0); 108 EXPECT_EQ(2U, dis.NextInstruction()); 109 EXPECT_TRUE(dis.currentInstructionValid()); 110 EXPECT_EQ(0U, dis.flags()); 111 EXPECT_FALSE(dis.endOfBlock()); 112 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 113 EXPECT_TRUE(dis.setBadRead()); 114 EXPECT_EQ(2U, dis.NextInstruction()); 115 EXPECT_TRUE(dis.currentInstructionValid()); 116 EXPECT_EQ(0U, dis.flags()); 117 EXPECT_FALSE(dis.endOfBlock()); 118 EXPECT_EQ(libdis::insn_logic, dis.currentInstructionGroup()); 119 EXPECT_EQ(2U, dis.NextInstruction()); 120 EXPECT_TRUE(dis.currentInstructionValid()); 121 EXPECT_EQ(google_breakpad::DISX86_BAD_BRANCH_TARGET, dis.flags()); 122 EXPECT_FALSE(dis.endOfBlock()); 123 EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); 124 } 125 126 TEST(DisassemblerX86Test, BadWriteLeadsToPushedArg) { 127 DisassemblerX86 dis(write_eax_arg_to_call, 128 sizeof(write_eax_arg_to_call)-1, 0); 129 EXPECT_EQ(6U, dis.NextInstruction()); 130 EXPECT_TRUE(dis.currentInstructionValid()); 131 EXPECT_EQ(0U, dis.flags()); 132 EXPECT_FALSE(dis.endOfBlock()); 133 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 134 EXPECT_TRUE(dis.setBadWrite()); 135 EXPECT_EQ(3U, dis.NextInstruction()); 136 EXPECT_TRUE(dis.currentInstructionValid()); 137 EXPECT_EQ(0U, dis.flags()); 138 EXPECT_FALSE(dis.endOfBlock()); 139 EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); 140 EXPECT_EQ(1U, dis.NextInstruction()); 141 EXPECT_TRUE(dis.currentInstructionValid()); 142 EXPECT_EQ(0U, dis.flags()); 143 EXPECT_FALSE(dis.endOfBlock()); 144 EXPECT_EQ(5U, dis.NextInstruction()); 145 EXPECT_TRUE(dis.currentInstructionValid()); 146 EXPECT_EQ(google_breakpad::DISX86_BAD_ARGUMENT_PASSED, dis.flags()); 147 EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); 148 EXPECT_FALSE(dis.endOfBlock()); 149 } 150 151 152 TEST(DisassemblerX86Test, BadReadLeadsToBlockWrite) { 153 DisassemblerX86 dis(read_edi_stosb, sizeof(read_edi_stosb)-1, 0); 154 EXPECT_EQ(2U, dis.NextInstruction()); 155 EXPECT_TRUE(dis.currentInstructionValid()); 156 EXPECT_EQ(0U, dis.flags()); 157 EXPECT_FALSE(dis.endOfBlock()); 158 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 159 EXPECT_TRUE(dis.setBadRead()); 160 EXPECT_EQ(2U, dis.NextInstruction()); 161 EXPECT_TRUE(dis.currentInstructionValid()); 162 EXPECT_EQ(0U, dis.flags()); 163 EXPECT_FALSE(dis.endOfBlock()); 164 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 165 EXPECT_EQ(2U, dis.NextInstruction()); 166 EXPECT_TRUE(dis.currentInstructionValid()); 167 EXPECT_EQ(google_breakpad::DISX86_BAD_BLOCK_WRITE, dis.flags()); 168 EXPECT_FALSE(dis.endOfBlock()); 169 EXPECT_EQ(libdis::insn_string, dis.currentInstructionGroup()); 170 } 171 172 TEST(DisassemblerX86Test, BadReadClobberThenWrite) { 173 DisassemblerX86 dis(read_clobber_write, sizeof(read_clobber_write)-1, 0); 174 EXPECT_EQ(2U, dis.NextInstruction()); 175 EXPECT_TRUE(dis.currentInstructionValid()); 176 EXPECT_EQ(0U, dis.flags()); 177 EXPECT_FALSE(dis.endOfBlock()); 178 EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); 179 EXPECT_TRUE(dis.setBadRead()); 180 EXPECT_EQ(2U, dis.NextInstruction()); 181 EXPECT_TRUE(dis.currentInstructionValid()); 182 EXPECT_EQ(0U, dis.flags()); 183 EXPECT_FALSE(dis.endOfBlock()); 184 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 185 EXPECT_EQ(2U, dis.NextInstruction()); 186 EXPECT_TRUE(dis.currentInstructionValid()); 187 EXPECT_EQ(0U, dis.flags()); 188 EXPECT_FALSE(dis.endOfBlock()); 189 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 190 } 191 192 TEST(DisassemblerX86Test, BadReadXCHGThenWrite) { 193 DisassemblerX86 dis(read_xchg_write, sizeof(read_xchg_write)-1, 0); 194 EXPECT_EQ(2U, dis.NextInstruction()); 195 EXPECT_TRUE(dis.currentInstructionValid()); 196 EXPECT_EQ(0U, dis.flags()); 197 EXPECT_FALSE(dis.endOfBlock()); 198 EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); 199 EXPECT_TRUE(dis.setBadRead()); 200 EXPECT_EQ(1U, dis.NextInstruction()); 201 EXPECT_TRUE(dis.currentInstructionValid()); 202 EXPECT_EQ(0U, dis.flags()); 203 EXPECT_FALSE(dis.endOfBlock()); 204 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 205 EXPECT_EQ(2U, dis.NextInstruction()); 206 EXPECT_TRUE(dis.currentInstructionValid()); 207 EXPECT_EQ(0U, dis.flags()); 208 EXPECT_FALSE(dis.endOfBlock()); 209 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 210 EXPECT_EQ(2U, dis.NextInstruction()); 211 EXPECT_TRUE(dis.currentInstructionValid()); 212 EXPECT_EQ(google_breakpad::DISX86_BAD_WRITE, dis.flags()); 213 EXPECT_FALSE(dis.endOfBlock()); 214 EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); 215 } 216 217 TEST(DisassemblerX86Test, BadReadThenCMP) { 218 DisassemblerX86 dis(read_cmp, sizeof(read_cmp)-1, 0); 219 EXPECT_EQ(2U, dis.NextInstruction()); 220 EXPECT_TRUE(dis.currentInstructionValid()); 221 EXPECT_EQ(0U, dis.flags()); 222 EXPECT_FALSE(dis.endOfBlock()); 223 EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); 224 EXPECT_TRUE(dis.setBadRead()); 225 EXPECT_EQ(3U, dis.NextInstruction()); 226 EXPECT_TRUE(dis.currentInstructionValid()); 227 EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags()); 228 EXPECT_FALSE(dis.endOfBlock()); 229 EXPECT_EQ(libdis::insn_comparison, dis.currentInstructionGroup()); 230 EXPECT_EQ(2U, dis.NextInstruction()); 231 EXPECT_TRUE(dis.currentInstructionValid()); 232 EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags()); 233 EXPECT_FALSE(dis.endOfBlock()); 234 EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); 235 } 236 }