/ src / processor / disassembler_x86_unittest.cc
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  }