OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 #include "debugger/core/debug_api_mock.h" | |
5 #include "debugger/core/debug_event.h" | |
6 #include "debugger/core/debuggee_iprocess.h" | |
7 #include "debugger/core/debuggee_process_mock.h" | |
8 #include "debugger/core/debuggee_thread.h" | |
9 #include "gtest/gtest.h" | |
10 | |
11 namespace { | |
12 const int kFakeProcessId = 847; | |
13 const int kFakeThreadId = 378421; | |
14 const int kFakeThreadId2 = 308421; | |
15 HANDLE kFakeThreadHandle = 0; | |
16 HANDLE kFakeProcessHandle = 0; | |
17 HANDLE kFakeFileHandle = 0; | |
18 | |
19 const int kNexeThreadStarted = 1; | |
20 const int kThreadHalted = 2; | |
21 const int kThreadRunning = 3; | |
22 | |
23 const char* kNexeUuid = | |
24 "{7AA7C9CF-89EC-4ed3-8DAD-6DC84302AB11} -v 1" | |
25 " -event NaClThreadStart -mb c0000000 -ep 20080"; | |
26 const void* kNexeMemBaseAddr = reinterpret_cast<void*>(0xc0000000); | |
27 const void* kNexeEntryPoint = reinterpret_cast<void*>(0x20080); | |
28 const debug::DebuggeeThread* kNullThread = | |
29 reinterpret_cast<debug::DebuggeeThread*>(0); | |
30 const char* kNullCharPtr = reinterpret_cast<char*>(0); | |
31 | |
32 class TestableDebuggeeThread : public debug::DebuggeeThread { | |
33 public: | |
34 TestableDebuggeeThread(int id, | |
35 HANDLE handle, | |
36 debug::IDebuggeeProcess* parent_process) | |
37 : debug::DebuggeeThread(id, handle, parent_process) {} | |
38 | |
39 void Kill() { debug::DebuggeeThread::Kill(); } | |
40 void OnDebugEvent(debug::DebugEvent* debug_event) { | |
41 debug::DebuggeeThread::OnDebugEvent(debug_event); | |
42 } | |
43 bool Continue(debug::DebuggeeThread::ContinueOption option) { | |
44 return debug::DebuggeeThread::Continue(option); | |
45 } | |
46 debug::IDebuggeeProcess& parent_process() { | |
47 return debug::DebuggeeThread::parent_process(); | |
48 } | |
49 debug::DebugAPI& debug_api() { return debug::DebuggeeThread::debug_api(); } | |
50 | |
51 void SimulateBreakpointHit() { | |
52 DEBUG_EVENT wde; | |
53 memset(&wde, 0, sizeof(wde)); | |
54 wde.dwDebugEventCode = EXCEPTION_DEBUG_EVENT; | |
55 wde.u.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT; | |
56 wde.dwThreadId = id(); | |
57 | |
58 debug::DebugEvent de; | |
59 de.set_windows_debug_event(wde); | |
60 OnDebugEvent(&de); | |
61 } | |
62 }; | |
63 | |
64 // DebuggeeThread test fixture. | |
65 class DebuggeeThreadTest : public ::testing::Test { | |
66 public: | |
67 DebuggeeThreadTest() { | |
68 fake_proc_ = new debug::DebuggeeProcessMock(&fake_debug_api_); | |
69 fake_proc_->AddThread(kFakeThreadId2, kFakeThreadHandle); | |
70 | |
71 no_thread_ = new TestableDebuggeeThread(kFakeThreadId, | |
72 kFakeThreadHandle, | |
73 fake_proc_); | |
74 | |
75 this_thread_ = new TestableDebuggeeThread(GetCurrentThreadId(), | |
76 GetCurrentThread(), | |
77 fake_proc_); | |
78 | |
79 fake_thread_ = new TestableDebuggeeThread(kFakeThreadId, | |
80 kFakeThreadHandle, | |
81 fake_proc_); | |
82 DEBUG_EVENT wde; | |
83 memset(&wde, 0, sizeof(wde)); | |
84 wde.dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT; | |
85 wde.dwProcessId = fake_proc_->id(); | |
86 wde.dwThreadId = kFakeThreadId; | |
87 | |
88 debug::DebugEvent de; | |
89 de.set_windows_debug_event(wde); | |
90 fake_proc_->OnDebugEvent(&de); | |
91 } | |
92 | |
93 ~DebuggeeThreadTest() { | |
94 delete fake_proc_; | |
95 delete fake_thread_; | |
96 delete no_thread_; | |
97 delete this_thread_; | |
98 } | |
99 | |
100 void InitDebugEventWithString(const char* str, | |
101 int addr, | |
102 debug::DebugEvent* de) { | |
103 DEBUG_EVENT wde; | |
104 memset(&wde, 0, sizeof(wde)); | |
105 wde.dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; | |
106 wde.u.DebugString.lpDebugStringData = reinterpret_cast<char*>(addr); | |
107 wde.u.DebugString.nDebugStringLength = static_cast<WORD>(strlen(str)); | |
108 fake_proc_->WriteMemory( | |
109 wde.u.DebugString.lpDebugStringData, | |
110 strlen(str), | |
111 str); | |
112 de->set_windows_debug_event(wde); | |
113 } | |
114 | |
115 TestableDebuggeeThread* no_thread_; | |
116 TestableDebuggeeThread* this_thread_; | |
117 debug::DebuggeeProcessMock* fake_proc_; | |
118 TestableDebuggeeThread* fake_thread_; | |
119 debug::DebugAPIMock fake_debug_api_; | |
120 }; | |
121 | |
122 TEST_F(DebuggeeThreadTest, SimpleAccessors) { | |
123 EXPECT_EQ(fake_proc_, &no_thread_->parent_process()); | |
124 EXPECT_EQ(kFakeThreadId, no_thread_->id()); | |
125 EXPECT_EQ(&fake_proc_->debug_api(), &no_thread_->debug_api()); | |
126 EXPECT_EQ(debug::DebuggeeThread::kHalted, no_thread_->state()); | |
127 EXPECT_STREQ("kHalted", | |
128 debug::DebuggeeThread::GetStateName(no_thread_->state())); | |
129 } | |
130 | |
131 TEST_F(DebuggeeThreadTest, Nothread) { | |
132 EXPECT_FALSE(no_thread_->IsNaClAppThread()); | |
133 EXPECT_TRUE(no_thread_->IsHalted()); | |
134 CONTEXT context; | |
135 EXPECT_TRUE(no_thread_->GetContext(&context)); | |
136 EXPECT_TRUE(no_thread_->SetContext(context)); | |
137 | |
138 WOW64_CONTEXT wow; | |
139 EXPECT_TRUE(no_thread_->GetWowContext(&wow)); | |
140 EXPECT_TRUE(no_thread_->SetWowContext(wow)); | |
141 } | |
142 | |
143 TEST_F(DebuggeeThreadTest, NothreadShallNotCrash) { | |
144 no_thread_->Kill(); | |
145 no_thread_->Continue(debug::DebuggeeThread::kContinue); | |
146 no_thread_->Continue(debug::DebuggeeThread::kContinueAndPassException); | |
147 no_thread_->Continue(debug::DebuggeeThread::kSingleStep); | |
148 no_thread_->SetIP(NULL); | |
149 | |
150 debug::DebugEvent de; | |
151 no_thread_->OnDebugEvent(&de); | |
152 } | |
153 | |
154 TEST_F(DebuggeeThreadTest, SimpleAccessorsForThisThread) { | |
155 EXPECT_EQ(GetCurrentThreadId(), this_thread_->id()); | |
156 } | |
157 | |
158 TEST_F(DebuggeeThreadTest, ReadRegsForThisThread) { | |
159 CONTEXT zeroed_context; | |
160 memset(&zeroed_context, 0, sizeof(zeroed_context)); | |
161 CONTEXT context; | |
162 EXPECT_TRUE(this_thread_->GetContext(&context)); | |
163 EXPECT_NE(0, memcmp(&context, &zeroed_context, sizeof(context))); | |
164 const void* zero_ip = 0; | |
165 EXPECT_NE(zero_ip, this_thread_->GetIP()); | |
166 } | |
167 | |
168 TEST_F(DebuggeeThreadTest, RecvDebugUnicodeStringAndHalt) { | |
169 DEBUG_EVENT wde; | |
170 memset(&wde, 0, sizeof(wde)); | |
171 wde.dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; | |
172 wde.u.DebugString.fUnicode = 1; | |
173 | |
174 debug::DebugEvent de; | |
175 de.set_windows_debug_event(wde); | |
176 no_thread_->OnDebugEvent(&de); | |
177 EXPECT_TRUE(no_thread_->IsHalted()); | |
178 } | |
179 | |
180 TEST_F(DebuggeeThreadTest, RecvDebugStringB) { | |
181 debug::DebugEvent de; | |
182 InitDebugEventWithString("abc", 1, &de); | |
183 | |
184 fake_thread_->OnDebugEvent(&de); | |
185 EXPECT_TRUE(fake_thread_->IsHalted()); | |
186 EXPECT_EQ(debug::DebugEvent::kNotNaClDebugEvent, de.nacl_debug_event_code()); | |
187 } | |
188 | |
189 TEST_F(DebuggeeThreadTest, RecvNexeDebugString) { | |
190 debug::DebugEvent de; | |
191 InitDebugEventWithString(kNexeUuid, 2, &de); | |
192 | |
193 fake_thread_->OnDebugEvent(&de); | |
194 EXPECT_TRUE(fake_thread_->IsHalted()); | |
195 EXPECT_EQ(debug::DebugEvent::kThreadIsAboutToStart, | |
196 de.nacl_debug_event_code()); | |
197 } | |
198 | |
199 TEST_F(DebuggeeThreadTest, RecvNexeDebugStringValidateParams) { | |
200 debug::DebugEvent de; | |
201 InitDebugEventWithString(kNexeUuid, 2, &de); | |
202 fake_thread_->OnDebugEvent(&de); | |
203 | |
204 EXPECT_TRUE(fake_thread_->IsNaClAppThread()); | |
205 EXPECT_EQ(kNexeMemBaseAddr, fake_proc_->nexe_mem_base()); | |
206 EXPECT_EQ(kNexeEntryPoint, fake_proc_->nexe_entry_point()); | |
207 } | |
208 | |
209 TEST_F(DebuggeeThreadTest, RecvNexeDebugStringAndContinue) { | |
210 debug::DebugEvent de; | |
211 InitDebugEventWithString(kNexeUuid, 2, &de); | |
212 | |
213 fake_thread_->OnDebugEvent(&de); | |
214 | |
215 EXPECT_TRUE(fake_thread_->IsHalted()); | |
216 EXPECT_EQ(debug::DebuggeeThread::kHalted, fake_thread_->state()); | |
217 | |
218 fake_thread_->Continue(debug::DebuggeeThread::kContinue); | |
219 EXPECT_FALSE(fake_thread_->IsHalted()); | |
220 EXPECT_EQ(debug::DebuggeeThread::kRunning, fake_thread_->state()); | |
221 EXPECT_FALSE(fake_debug_api_.single_step_enabled_); | |
222 } | |
223 | |
224 TEST_F(DebuggeeThreadTest, RecvNexeDebugStringAndContinueB) { | |
225 debug::DebugEvent de; | |
226 InitDebugEventWithString(kNexeUuid, 2, &de); | |
227 fake_thread_->OnDebugEvent(&de); | |
228 | |
229 fake_thread_->Continue(debug::DebuggeeThread::kContinueAndPassException); | |
230 EXPECT_FALSE(fake_thread_->IsHalted()); | |
231 EXPECT_EQ(debug::DebuggeeThread::kRunning, fake_thread_->state()); | |
232 EXPECT_FALSE(fake_debug_api_.single_step_enabled_); | |
233 } | |
234 | |
235 TEST_F(DebuggeeThreadTest, RecvNexeDebugStringAndContinueVerifyCallList) { | |
236 debug::DebugEvent de; | |
237 InitDebugEventWithString(kNexeUuid, 2, &de); | |
238 fake_thread_->OnDebugEvent(&de); | |
239 | |
240 fake_debug_api_.ClearCallSequence(); | |
241 fake_thread_->Continue(debug::DebuggeeThread::kContinue); | |
242 | |
243 std::deque<debug::DebugAPIMock::FunctionId> call_list; | |
244 call_list.push_back(debug::DebugAPIMock::kContinueDebugEvent); | |
245 EXPECT_TRUE(fake_debug_api_.CompareCallSequence(call_list)); | |
246 } | |
247 | |
248 TEST_F(DebuggeeThreadTest, RecvNexeDebugStringAndContinueVerifyCallListB) { | |
249 debug::DebugEvent de; | |
250 InitDebugEventWithString(kNexeUuid, 2, &de); | |
251 fake_thread_->OnDebugEvent(&de); | |
252 | |
253 fake_debug_api_.ClearCallSequence(); | |
254 fake_thread_->Continue(debug::DebuggeeThread::kContinueAndPassException); | |
255 | |
256 std::deque<debug::DebugAPIMock::FunctionId> call_list; | |
257 call_list.push_back(debug::DebugAPIMock::kContinueDebugEvent); | |
258 EXPECT_TRUE(fake_debug_api_.CompareCallSequence(call_list)); | |
259 } | |
260 | |
261 TEST_F(DebuggeeThreadTest, RecvNexeDebugStringAndSingleStep) { | |
262 debug::DebugEvent de; | |
263 InitDebugEventWithString(kNexeUuid, 2, &de); | |
264 | |
265 fake_thread_->OnDebugEvent(&de); | |
266 EXPECT_TRUE(fake_thread_->IsHalted()); | |
267 | |
268 fake_thread_->Continue(debug::DebuggeeThread::kSingleStep); | |
269 EXPECT_FALSE(fake_thread_->IsHalted()); | |
270 EXPECT_TRUE(fake_debug_api_.single_step_enabled_); | |
271 } | |
272 | |
273 TEST_F(DebuggeeThreadTest, RecvNexeDebugStringAndSingleStepVerifyCallList) { | |
274 fake_debug_api_.ClearCallSequence(); | |
275 | |
276 debug::DebugEvent de; | |
277 InitDebugEventWithString(kNexeUuid, 2, &de); | |
278 fake_thread_->OnDebugEvent(&de); | |
279 fake_thread_->Continue(debug::DebuggeeThread::kSingleStep); | |
280 | |
281 std::deque<debug::DebugAPIMock::FunctionId> call_list; | |
282 call_list.push_back(debug::DebugAPIMock::kGetThreadContext); | |
283 call_list.push_back(debug::DebugAPIMock::kSetThreadContext); | |
284 call_list.push_back(debug::DebugAPIMock::kGetThreadContext); | |
285 call_list.push_back(debug::DebugAPIMock::kSetThreadContext); | |
286 call_list.push_back(debug::DebugAPIMock::kContinueDebugEvent); | |
287 | |
288 EXPECT_TRUE(fake_debug_api_.CompareCallSequence(call_list)); | |
289 } | |
290 | |
291 TEST_F(DebuggeeThreadTest, Kill) { | |
292 TestableDebuggeeThread thread(1, reinterpret_cast<HANDLE>(1), fake_proc_); | |
293 fake_debug_api_.ClearCallSequence(); | |
294 thread.Kill(); | |
295 | |
296 std::deque<debug::DebugAPIMock::FunctionId> call_list; | |
297 call_list.push_back(debug::DebugAPIMock::kTerminateThread); | |
298 EXPECT_TRUE(fake_debug_api_.CompareCallSequence(call_list)); | |
299 } | |
300 | |
301 TEST_F(DebuggeeThreadTest, SetContextVerifyCallList) { | |
302 fake_debug_api_.ClearCallSequence(); | |
303 debug::DebuggeeThread thread(1, reinterpret_cast<HANDLE>(1), fake_proc_); | |
304 | |
305 CONTEXT ct; | |
306 thread.GetContext(&ct); | |
307 thread.SetContext(ct); | |
308 | |
309 std::deque<debug::DebugAPIMock::FunctionId> call_list; | |
310 call_list.push_back(debug::DebugAPIMock::kGetThreadContext); | |
311 call_list.push_back(debug::DebugAPIMock::kSetThreadContext); | |
312 EXPECT_TRUE(fake_debug_api_.CompareCallSequence(call_list)); | |
313 } | |
314 | |
315 TEST_F(DebuggeeThreadTest, RecvAlienBreakpoint) { | |
316 fake_thread_->SimulateBreakpointHit(); | |
317 EXPECT_TRUE(fake_thread_->IsHalted()); | |
318 } | |
319 | |
320 TEST_F(DebuggeeThreadTest, FailContinue) { | |
321 fake_thread_->SimulateBreakpointHit(); | |
322 EXPECT_TRUE(fake_thread_->IsHalted()); | |
323 EXPECT_TRUE(fake_thread_->Continue(debug::DebuggeeThread::kContinue)); | |
324 EXPECT_FALSE(fake_thread_->IsHalted()); | |
325 EXPECT_FALSE(fake_thread_->Continue(debug::DebuggeeThread::kContinue)); | |
326 EXPECT_FALSE(fake_thread_->IsHalted()); | |
327 | |
328 fake_thread_->SimulateBreakpointHit(); | |
329 EXPECT_TRUE(fake_thread_->IsHalted()); | |
330 EXPECT_TRUE(fake_thread_->Continue(debug::DebuggeeThread::kSingleStep)); | |
331 EXPECT_FALSE(fake_thread_->IsHalted()); | |
332 EXPECT_FALSE(fake_thread_->Continue(debug::DebuggeeThread::kSingleStep)); | |
333 EXPECT_FALSE(fake_thread_->IsHalted()); | |
334 | |
335 fake_thread_->SimulateBreakpointHit(); | |
336 EXPECT_TRUE(fake_thread_->IsHalted()); | |
337 EXPECT_TRUE(fake_thread_->Continue( | |
338 debug::DebuggeeThread::kContinueAndPassException)); | |
339 EXPECT_FALSE(fake_thread_->IsHalted()); | |
340 EXPECT_FALSE(fake_thread_->Continue( | |
341 debug::DebuggeeThread::kContinueAndPassException)); | |
342 EXPECT_FALSE(fake_thread_->IsHalted()); | |
343 } | |
344 | |
345 TEST_F(DebuggeeThreadTest, FailIfNotHalted) { | |
346 fake_thread_->SimulateBreakpointHit(); | |
347 EXPECT_TRUE(fake_thread_->IsHalted()); | |
348 EXPECT_TRUE(fake_thread_->Continue(debug::DebuggeeThread::kContinue)); | |
349 | |
350 EXPECT_FALSE(fake_thread_->IsHalted()); | |
351 CONTEXT context; | |
352 EXPECT_FALSE(fake_thread_->GetContext(&context)); | |
353 EXPECT_FALSE(fake_thread_->SetContext(context)); | |
354 | |
355 WOW64_CONTEXT wow_ctx; | |
356 EXPECT_FALSE(fake_thread_->GetWowContext(&wow_ctx)); | |
357 EXPECT_FALSE(fake_thread_->SetWowContext(wow_ctx)); | |
358 | |
359 EXPECT_EQ(NULL, fake_thread_->GetIP()); | |
360 EXPECT_FALSE(fake_thread_->SetIP(NULL)); | |
361 } | |
362 | |
363 TEST_F(DebuggeeThreadTest, NotFailIfHalted) { | |
364 EXPECT_TRUE(fake_thread_->IsHalted()); | |
365 CONTEXT context; | |
366 EXPECT_TRUE(fake_thread_->GetContext(&context)); | |
367 EXPECT_TRUE(fake_thread_->SetContext(context)); | |
368 | |
369 WOW64_CONTEXT wow_ctx; | |
370 EXPECT_TRUE(fake_thread_->GetWowContext(&wow_ctx)); | |
371 EXPECT_TRUE(fake_thread_->SetWowContext(wow_ctx)); | |
372 | |
373 EXPECT_TRUE(fake_thread_->SetIP(NULL)); | |
374 } | |
375 | |
376 } // namespace | |
377 | |
OLD | NEW |