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