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