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
36 namespace {
37
38 using google_breakpad::DisassemblerX86;
39
40 unsigned char just_return[] = "\xc3"; // retn
41
42 unsigned char invalid_instruction[] = "\x00"; // invalid
43
44 unsigned 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
50 unsigned 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
57 unsigned 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
63 unsigned 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
69 unsigned 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
76 unsigned 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
TEST(DisassemblerX86Test,SimpleReturnInstruction)82 TEST(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
TEST(DisassemblerX86Test,SimpleInvalidInstruction)97 TEST(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
TEST(DisassemblerX86Test,BadReadLeadsToBranch)103 TEST(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
TEST(DisassemblerX86Test,BadWriteLeadsToPushedArg)123 TEST(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
TEST(DisassemblerX86Test,BadReadLeadsToBlockWrite)149 TEST(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
TEST(DisassemblerX86Test,BadReadClobberThenWrite)169 TEST(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
TEST(DisassemblerX86Test,BadReadXCHGThenWrite)189 TEST(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
TEST(DisassemblerX86Test,BadReadThenCMP)214 TEST(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