1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/refinery/process_state/process_state.h"
16 :
17 : #include <limits>
18 : #include <memory>
19 : #include <string>
20 :
21 : #include "base/strings/string_piece.h"
22 : #include "gtest/gtest.h"
23 : #include "syzygy/refinery/process_state/process_state_util.h"
24 : #include "syzygy/refinery/process_state/refinery.pb.h"
25 :
26 m : namespace refinery {
27 :
28 m : namespace {
29 :
30 m : void ValidateSingleRecordMatch(
31 m : AddressRange range,
32 m : const std::vector<BytesRecordPtr>& matching_records,
33 m : base::StringPiece testcase) {
34 m : ASSERT_EQ(1, matching_records.size()) << testcase;
35 m : ASSERT_EQ(range, matching_records[0]->range()) << testcase;
36 m : }
37 :
38 : // Adds a stack record to a process state.
39 m : void AddStackRecord(const AddressRange& range,
40 m : const size_t thread_id,
41 m : ProcessState* process_state,
42 m : StackRecordPtr* stack_record) {
43 m : StackLayerPtr stack_layer;
44 m : process_state->FindOrCreateLayer(&stack_layer);
45 m : stack_layer->CreateRecord(range, stack_record);
46 m : (*stack_record)
47 m : ->mutable_data()
48 m : ->mutable_thread_info()
49 m : ->set_thread_id(thread_id);
50 m : }
51 :
52 m : } // namespace
53 :
54 m : TEST(ProcessStateTest, FindOrCreateLayer) {
55 m : ProcessState report;
56 :
57 m : scoped_refptr<ProcessState::Layer<Bytes>> bytes_layer;
58 m : EXPECT_FALSE(report.FindLayer(&bytes_layer));
59 m : EXPECT_TRUE(bytes_layer == nullptr);
60 :
61 m : scoped_refptr<ProcessState::Layer<TypedBlock>> typed_layer;
62 m : EXPECT_FALSE(report.FindLayer(&typed_layer));
63 :
64 m : report.FindOrCreateLayer(&bytes_layer);
65 m : EXPECT_TRUE(bytes_layer != nullptr);
66 :
67 m : scoped_refptr<ProcessState::Layer<Bytes>> test_layer;
68 m : EXPECT_TRUE(report.FindLayer(&test_layer));
69 m : EXPECT_EQ(bytes_layer.get(), test_layer.get());
70 :
71 m : EXPECT_FALSE(report.FindLayer(&typed_layer));
72 m : }
73 :
74 m : TEST(ProcessStateTest, FindSingleRecord) {
75 m : const size_t kThreadId = 42;
76 m : const AddressRange kRecordAddressRange(80ULL, 10U);
77 m : ProcessState report;
78 m : StackRecordPtr retrieved;
79 :
80 : // Empty report: returns false.
81 m : ASSERT_FALSE(report.FindSingleRecord(84ULL, &retrieved));
82 :
83 : // Add a stack record to the report.
84 m : StackRecordPtr created;
85 m : AddStackRecord(kRecordAddressRange, kThreadId, &report, &created);
86 :
87 : // Search for address outside record's range.
88 m : ASSERT_FALSE(report.FindSingleRecord(79ULL, &retrieved));
89 m : ASSERT_FALSE(report.FindSingleRecord(90ULL, &retrieved));
90 :
91 : // Search for address within record's range.
92 m : ASSERT_TRUE(report.FindSingleRecord(84ULL, &retrieved));
93 m : ASSERT_EQ(created.get(), retrieved.get());
94 m : }
95 :
96 m : TEST(ProcessStateTest, FindStackRecord) {
97 m : const size_t kThreadId = 42;
98 m : ProcessState report;
99 m : StackRecordPtr retrieved;
100 :
101 : // Report doesn't have a stack layer.
102 m : ASSERT_FALSE(report.FindStackRecord(kThreadId, &retrieved));
103 :
104 : // Report has an empty stack layer.
105 m : StackLayerPtr stack_layer;
106 m : report.FindOrCreateLayer(&stack_layer);
107 m : ASSERT_FALSE(report.FindStackRecord(kThreadId, &retrieved));
108 :
109 : // Add a stack record to the report.
110 m : StackRecordPtr created;
111 m : AddStackRecord(AddressRange(8000ULL, 80U), kThreadId, &report, &created);
112 :
113 : // Search for a non-existing thread id.
114 m : ASSERT_FALSE(report.FindStackRecord(kThreadId + 1, &retrieved));
115 :
116 : // Search for the existing thread id.
117 m : ASSERT_TRUE(report.FindStackRecord(kThreadId, &retrieved));
118 m : ASSERT_EQ(created.get(), retrieved.get());
119 m : }
120 :
121 m : TEST(ProcessStateTest, ExceptionBasics) {
122 m : const int kExceptingThreadId = 1;
123 m : const int kExceptionCode = 2;
124 m : Exception exception;
125 m : exception.set_thread_id(kExceptingThreadId);
126 m : exception.set_exception_code(kExceptionCode);
127 :
128 m : ProcessState state;
129 m : size_t retrieved_thread_id = 0;
130 :
131 : // Retrieving excepting thread id on an empty state fails.
132 m : ASSERT_FALSE(state.GetExceptingThreadId(&retrieved_thread_id));
133 m : retrieved_thread_id = 0;
134 :
135 : // Setting an exception fails when thread isn't in the state.
136 m : ASSERT_FALSE(state.SetException(exception));
137 :
138 : // Add a stack record to the report.
139 m : StackRecordPtr stack_record;
140 m : AddStackRecord(AddressRange(8000ULL, 80U), kExceptingThreadId, &state,
141 m : &stack_record);
142 :
143 : // Setting an exception succeeds.
144 m : ASSERT_TRUE(state.SetException(exception));
145 m : ASSERT_TRUE(stack_record->data().thread_info().has_exception());
146 m : const Exception& retrieved_exception =
147 m : stack_record->data().thread_info().exception();
148 m : ASSERT_EQ(kExceptingThreadId, retrieved_exception.thread_id());
149 m : ASSERT_EQ(kExceptionCode, retrieved_exception.exception_code());
150 :
151 : // Retrieving the excepting thread id succeeds.
152 m : ASSERT_TRUE(state.GetExceptingThreadId(&retrieved_thread_id));
153 m : ASSERT_EQ(kExceptingThreadId, retrieved_thread_id);
154 :
155 : // Setting a second exception fails.
156 m : ASSERT_FALSE(state.SetException(exception));
157 m : }
158 :
159 m : TEST(ProcessStateTest, AddressRangeBasics) {
160 m : const Address kAddr = 0xCAFE0000ULL;
161 m : const Size kSize = 0xBABEU;
162 :
163 m : AddressRange valid_range(kAddr, kSize);
164 m : ASSERT_TRUE(valid_range.IsValid());
165 m : ASSERT_EQ(kAddr, valid_range.start());
166 m : ASSERT_EQ(kSize, valid_range.size());
167 m : ASSERT_EQ(kAddr, valid_range.start());
168 m : ASSERT_EQ(kAddr, valid_range.start());
169 m : ASSERT_EQ(0xCAFEBABEULL, valid_range.end());
170 :
171 m : AddressRange zero_range(kAddr, 0U);
172 m : ASSERT_FALSE(zero_range.IsValid());
173 :
174 m : AddressRange overflow_range(std::numeric_limits<Address>::max(), 1U);
175 m : ASSERT_FALSE(overflow_range.IsValid());
176 m : }
177 :
178 m : TEST(ProcessStateTest, CreateRecord) {
179 m : ProcessState report;
180 :
181 m : scoped_refptr<ProcessState::Layer<Bytes>> bytes_layer;
182 m : report.FindOrCreateLayer(&bytes_layer);
183 m : EXPECT_TRUE(bytes_layer != nullptr);
184 m : ASSERT_EQ(0, bytes_layer->size());
185 :
186 : // Add a record for a range of memory.
187 m : const Address kAddr = 0xCAFEBABEULL;
188 m : const Size kSize = 0xBABE;
189 m : scoped_refptr<ProcessState::Record<Bytes>> first_record;
190 m : bytes_layer->CreateRecord(AddressRange(kAddr, kSize), &first_record);
191 :
192 m : ASSERT_EQ(AddressRange(kAddr, kSize), first_record->range());
193 m : ASSERT_EQ(1, bytes_layer->size());
194 :
195 : // Add a second record for the same range.
196 m : scoped_refptr<ProcessState::Record<Bytes>> second_record;
197 m : bytes_layer->CreateRecord(AddressRange(kAddr, kSize), &second_record);
198 :
199 m : ASSERT_EQ(AddressRange(kAddr, kSize), second_record->range());
200 m : ASSERT_EQ(2, bytes_layer->size());
201 :
202 : // Verify that this produced two distinct objects.
203 m : ASSERT_NE(first_record.get(), second_record.get());
204 m : }
205 :
206 m : TEST(ProcessStateTest, GetRecordsAt) {
207 : // Create a report with a Bytes layer.
208 m : ProcessState report;
209 m : BytesLayerPtr bytes_layer;
210 m : report.FindOrCreateLayer(&bytes_layer);
211 m : EXPECT_TRUE(bytes_layer != nullptr);
212 m : ASSERT_EQ(0, bytes_layer->size());
213 :
214 : // Add a single record for basic testing.
215 m : BytesRecordPtr record;
216 m : bytes_layer->CreateRecord(AddressRange(80ULL, 16U), &record);
217 :
218 : // Get right before and right after - no match.
219 m : std::vector<BytesRecordPtr> matching_records;
220 m : bytes_layer->GetRecordsAt(79ULL, &matching_records);
221 m : ASSERT_EQ(0, matching_records.size());
222 m : bytes_layer->GetRecordsAt(81ULL, &matching_records);
223 m : ASSERT_EQ(0, matching_records.size());
224 :
225 : // Match.
226 m : bytes_layer->GetRecordsAt(80ULL, &matching_records);
227 m : ASSERT_EQ(1, matching_records.size());
228 m : ASSERT_EQ(record.get(), matching_records[0].get());
229 :
230 : // Add a second record. Match both.
231 m : matching_records.clear();
232 m : bytes_layer->CreateRecord(AddressRange(80ULL, 4U), &record);
233 m : bytes_layer->GetRecordsAt(80ULL, &matching_records);
234 m : ASSERT_EQ(2, matching_records.size());
235 m : }
236 :
237 m : TEST(ProcessStateTest, GetRecordsSpanningSingleRecord) {
238 : // Create a report with a Bytes layer.
239 m : ProcessState report;
240 m : BytesLayerPtr bytes_layer;
241 m : report.FindOrCreateLayer(&bytes_layer);
242 m : EXPECT_TRUE(bytes_layer != nullptr);
243 m : ASSERT_EQ(0, bytes_layer->size());
244 :
245 : // Add a single record for basic testing.
246 m : const Address kAddress = 80ULL;
247 m : const Size kSize = 16U;
248 m : BytesRecordPtr record;
249 m : bytes_layer->CreateRecord(AddressRange(kAddress, kSize), &record);
250 :
251 : // No match: requested region is outside.
252 m : std::vector<BytesRecordPtr> matching_records;
253 m : bytes_layer->GetRecordsSpanning(AddressRange(73ULL, 5U),
254 m : &matching_records);
255 m : ASSERT_EQ(0, matching_records.size());
256 m : bytes_layer->GetRecordsSpanning(AddressRange(96ULL, 3U),
257 m : &matching_records);
258 m : ASSERT_EQ(0, matching_records.size());
259 :
260 : // No match: requested region straddles.
261 m : bytes_layer->GetRecordsSpanning(AddressRange(75ULL, 10U),
262 m : &matching_records);
263 m : ASSERT_EQ(0, matching_records.size());
264 :
265 : // No match: requested region is a superset.
266 m : bytes_layer->GetRecordsSpanning(AddressRange(75ULL, 32U),
267 m : &matching_records);
268 m : ASSERT_EQ(0, matching_records.size());
269 :
270 : // Match: requested region is a subset.
271 m : bytes_layer->GetRecordsSpanning(AddressRange(84ULL, 4U),
272 m : &matching_records);
273 m : ValidateSingleRecordMatch(AddressRange(kAddress, kSize), matching_records,
274 m : "Case: Requested region is a subset");
275 m : matching_records.clear();
276 :
277 : // Match: region is exact match.
278 m : bytes_layer->GetRecordsSpanning(AddressRange(kAddress, kSize),
279 m : &matching_records);
280 m : ValidateSingleRecordMatch(AddressRange(kAddress, kSize), matching_records,
281 m : "Case: Requested region is exact match");
282 m : }
283 :
284 m : TEST(ProcessStateTest, GetRecordsSpanningMultipleRecords) {
285 : // Create a report with a Bytes layer.
286 m : ProcessState report;
287 m : BytesLayerPtr bytes_layer;
288 m : report.FindOrCreateLayer(&bytes_layer);
289 m : ASSERT_TRUE(bytes_layer != nullptr);
290 :
291 : // Add a few records (note the 2 records at the same address).
292 m : BytesRecordPtr record;
293 m : bytes_layer->CreateRecord(AddressRange(80ULL, 16U), &record);
294 m : bytes_layer->CreateRecord(AddressRange(75ULL, 25U), &record);
295 m : bytes_layer->CreateRecord(AddressRange(80ULL, 16U), &record);
296 :
297 : // Match a subset.
298 m : std::vector<BytesRecordPtr> matching_records;
299 m : bytes_layer->GetRecordsSpanning(AddressRange(82ULL, 4U),
300 m : &matching_records);
301 m : ASSERT_EQ(3, matching_records.size());
302 m : }
303 :
304 m : TEST(ProcessStateTest, GetRecordsIntersectingSingleRecord) {
305 : // Create a report with a Bytes layer.
306 m : ProcessState report;
307 m : BytesLayerPtr bytes_layer;
308 m : report.FindOrCreateLayer(&bytes_layer);
309 m : EXPECT_TRUE(bytes_layer != nullptr);
310 m : ASSERT_EQ(0, bytes_layer->size());
311 :
312 : // Add a single record for basic testing.
313 m : const Address kAddress = 80ULL;
314 m : const Size kSize = 16U;
315 m : BytesRecordPtr record;
316 m : bytes_layer->CreateRecord(AddressRange(kAddress, kSize), &record);
317 :
318 : // No match: requested region is outside.
319 m : std::vector<BytesRecordPtr> matching_records;
320 m : bytes_layer->GetRecordsIntersecting(AddressRange(73ULL, 5U),
321 m : &matching_records);
322 m : ASSERT_EQ(0, matching_records.size());
323 m : bytes_layer->GetRecordsIntersecting(AddressRange(96ULL, 3U),
324 m : &matching_records);
325 m : ASSERT_EQ(0, matching_records.size());
326 :
327 : // No match: requested region is contiguous.
328 m : bytes_layer->GetRecordsIntersecting(AddressRange(75ULL, 5U),
329 m : &matching_records);
330 m : ASSERT_EQ(0, matching_records.size());
331 m : bytes_layer->GetRecordsIntersecting(AddressRange(96ULL, 3U),
332 m : &matching_records);
333 m : ASSERT_EQ(0, matching_records.size());
334 :
335 : // Match: requested region straddles.
336 m : bytes_layer->GetRecordsIntersecting(AddressRange(75ULL, 10U),
337 m : &matching_records);
338 m : ValidateSingleRecordMatch(AddressRange(kAddress, kSize), matching_records,
339 m : "Case: Requested region straddles");
340 m : matching_records.clear();
341 :
342 : // Match: requested region is a superset.
343 m : bytes_layer->GetRecordsIntersecting(AddressRange(75ULL, 32U),
344 m : &matching_records);
345 m : ValidateSingleRecordMatch(AddressRange(kAddress, kSize), matching_records,
346 m : "Case: Requested region is a superset");
347 m : matching_records.clear();
348 :
349 : // Match: requested region is a subset.
350 m : bytes_layer->GetRecordsIntersecting(AddressRange(84ULL, 4U),
351 m : &matching_records);
352 m : ValidateSingleRecordMatch(AddressRange(kAddress, kSize), matching_records,
353 m : "Case: Requested region is a subset");
354 m : matching_records.clear();
355 :
356 : // Match: region is exact match.
357 m : bytes_layer->GetRecordsIntersecting(AddressRange(kAddress, kSize),
358 m : &matching_records);
359 m : ValidateSingleRecordMatch(AddressRange(kAddress, kSize), matching_records,
360 m : "Case: Requested region is an exact match");
361 m : matching_records.clear();
362 m : }
363 :
364 m : TEST(ProcessStateTest, GetRecordsIntersectingMultipleRecords) {
365 : // Create a report with a Bytes layer.
366 m : ProcessState report;
367 m : BytesLayerPtr bytes_layer;
368 m : report.FindOrCreateLayer(&bytes_layer);
369 m : ASSERT_TRUE(bytes_layer != nullptr);
370 :
371 : // Add a few records.
372 m : BytesRecordPtr record;
373 m : bytes_layer->CreateRecord(AddressRange(80ULL, 16U), &record);
374 m : bytes_layer->CreateRecord(AddressRange(75ULL, 25U), &record);
375 m : bytes_layer->CreateRecord(AddressRange(80ULL, 16U),
376 m : &record); // Second record at location.
377 :
378 : // Match a subset straddling region.
379 m : std::vector<BytesRecordPtr> matching_records;
380 m : bytes_layer->GetRecordsIntersecting(AddressRange(78ULL, 4U),
381 m : &matching_records);
382 m : ASSERT_EQ(3, matching_records.size());
383 m : }
384 :
385 m : TEST(ProcessStateTest, RemoveRecord) {
386 : // Create a report that has a Bytes layer with a single record.
387 m : ProcessState report;
388 m : BytesLayerPtr bytes_layer;
389 m : report.FindOrCreateLayer(&bytes_layer);
390 m : ASSERT_TRUE(bytes_layer != nullptr);
391 :
392 m : const Address kAddress = 80ULL;
393 m : const Size kSize = 16U;
394 m : BytesRecordPtr record;
395 m : bytes_layer->CreateRecord(AddressRange(kAddress, kSize), &record);
396 m : ASSERT_EQ(1, bytes_layer->size());
397 :
398 : // Remove record.
399 m : ASSERT_TRUE(bytes_layer->RemoveRecord(record));
400 m : ASSERT_EQ(0, bytes_layer->size());
401 :
402 : // Removing a second time fails.
403 m : ASSERT_FALSE(bytes_layer->RemoveRecord(record));
404 m : }
405 :
406 m : TEST(ProcessStateTest, LayerIteration) {
407 : // Create a report that has a Bytes layer with few records.
408 m : ProcessState report;
409 m : BytesLayerPtr bytes_layer;
410 m : report.FindOrCreateLayer(&bytes_layer);
411 m : ASSERT_TRUE(bytes_layer != nullptr);
412 :
413 m : BytesRecordPtr record;
414 m : bytes_layer->CreateRecord(AddressRange(80ULL, 4U), &record);
415 m : bytes_layer->CreateRecord(AddressRange(84ULL, 4U), &record);
416 m : bytes_layer->CreateRecord(AddressRange(88ULL, 4U), &record);
417 :
418 : // Manual iteration.
419 : // Note: for ease of testing, this test relies on the iterator returning
420 : // records by ascending address. However, this is not in the contract.
421 m : ProcessState::Layer<Bytes>::Iterator it = bytes_layer->begin();
422 m : ASSERT_EQ(80ULL, (*it)->range().start());
423 m : ++it;
424 m : ASSERT_EQ(84ULL, (*it)->range().start());
425 m : ++it;
426 m : ASSERT_EQ(88ULL, (*it)->range().start());
427 m : ++it;
428 m : ASSERT_EQ(bytes_layer->end(), it);
429 :
430 : // Range based for loop.
431 m : int record_count = 0;
432 m : for (BytesRecordPtr rec : *bytes_layer) {
433 m : ++record_count;
434 m : }
435 m : ASSERT_EQ(3, record_count);
436 m : }
437 :
438 m : class ProcessStateBitSourceTest : public testing::Test {
439 m : protected:
440 m : void SetUp() override {
441 : // Populate the process state with a single Bytes record at address_,
442 : // containing data_.
443 :
444 m : address_ = 80ULL;
445 m : data_ = "0123456789";
446 :
447 : // Note: range doesn't include trailing '\0'.
448 m : AddressRange record_range(address_, data_.size());
449 :
450 m : BytesLayerPtr bytes_layer;
451 m : process_state_.FindOrCreateLayer(&bytes_layer);
452 m : BytesRecordPtr bytes_record;
453 m : bytes_layer->CreateRecord(record_range, &bytes_record);
454 m : *bytes_record->mutable_data()->mutable_data() = data_;
455 m : }
456 :
457 m : Address address() { return address_; }
458 m : const std::string& data() { return data_; }
459 :
460 m : void PerformGetFromTest(AddressRange requested,
461 m : size_t expected_cnt,
462 m : bool bytes_requested,
463 m : const std::string& expected_bytes) {
464 m : size_t retrieved_cnt = 0U;
465 m : std::unique_ptr<char[]> buffer(new char[data().size()]);
466 m : memset(buffer.get(), 0, data().size());
467 :
468 m : ASSERT_TRUE(
469 m : process_state_.GetFrom(requested, &retrieved_cnt, buffer.get()));
470 :
471 m : ASSERT_EQ(expected_cnt, retrieved_cnt);
472 m : if (bytes_requested)
473 m : ASSERT_EQ(expected_bytes, std::string(buffer.get(), retrieved_cnt));
474 m : }
475 :
476 m : ProcessState process_state_;
477 :
478 m : private:
479 m : Address address_;
480 m : std::string data_;
481 m : };
482 :
483 m : TEST_F(ProcessStateBitSourceTest, GetAll) {
484 m : char retrieved = '-';
485 :
486 : // Fail to retrieve data that is not fully in the process state.
487 m : AddressRange desired_range = AddressRange(address() - 1, data().size());
488 m : ASSERT_FALSE(process_state_.GetAll(desired_range, &retrieved));
489 :
490 : // Successfully retrieve data that is in the process state.
491 m : retrieved = '-';
492 m : ASSERT_TRUE(process_state_.GetAll(AddressRange(address(), 1U), &retrieved));
493 m : ASSERT_EQ(data()[0], retrieved);
494 m : }
495 :
496 m : TEST_F(ProcessStateBitSourceTest, GetFrom) {
497 m : size_t retrieved_cnt = 0U;
498 m : std::unique_ptr<char[]> buffer(new char[data().size()]);
499 :
500 : // Fail to retrieve when the head is outside existing data.
501 m : AddressRange desired(address() - 1U, data().size());
502 m : ASSERT_FALSE(process_state_.GetFrom(desired, &retrieved_cnt, nullptr));
503 m : desired = AddressRange(address() + data().size(), 1U);
504 m : ASSERT_FALSE(process_state_.GetFrom(desired, &retrieved_cnt, buffer.get()));
505 :
506 : // Successful full retrieval - not asking for data.
507 m : desired = AddressRange(address() + 1, data().size() - 1);
508 m : PerformGetFromTest(desired, data().size() - 1, false, "");
509 :
510 : // Successful partial retrieval - not asking for data.
511 m : desired = AddressRange(address() + 1, data().size());
512 m : PerformGetFromTest(desired, data().size() - 1, false, "");
513 :
514 : // Successful full retrieval - asking for data.
515 m : std::string expected_bytes = data().substr(1, data().size() - 1);
516 m : desired = AddressRange(address() + 1, data().size() - 1);
517 m : PerformGetFromTest(desired, data().size() - 1, true, expected_bytes);
518 :
519 : // Successful partial retrieval - asking for data.
520 m : desired = AddressRange(address() + 1, data().size());
521 m : PerformGetFromTest(desired, data().size() - 1, true, expected_bytes);
522 m : }
523 :
524 m : } // namespace refinery
|