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