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/analyzers/exception_analyzer.h"
16 :
17 : #include <stdint.h>
18 :
19 : #include <vector>
20 :
21 : #include "base/files/scoped_temp_dir.h"
22 : #include "gtest/gtest.h"
23 : #include "syzygy/minidump/minidump.h"
24 : #include "syzygy/minidump/unittest_util.h"
25 : #include "syzygy/refinery/unittest_util.h"
26 : #include "syzygy/refinery/analyzers/thread_analyzer.h"
27 : #include "syzygy/refinery/process_state/process_state.h"
28 : #include "syzygy/refinery/process_state/process_state_util.h"
29 : #include "syzygy/refinery/process_state/refinery.pb.h"
30 :
31 : namespace refinery {
32 :
33 E : TEST(ExceptionAnalyzerTest, AnalyzeMinidump) {
34 E : minidump::Minidump minidump;
35 E : ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
36 :
37 E : ProcessState process_state;
38 :
39 E : ThreadAnalyzer thread_analyzer;
40 : ASSERT_EQ(Analyzer::ANALYSIS_COMPLETE,
41 E : thread_analyzer.Analyze(minidump, &process_state));
42 :
43 E : ExceptionAnalyzer analyzer;
44 : ASSERT_EQ(Analyzer::ANALYSIS_COMPLETE,
45 E : analyzer.Analyze(minidump, &process_state));
46 :
47 : // Ensure one thread has exception data.
48 E : StackLayerPtr stack_layer;
49 E : ASSERT_TRUE(process_state.FindLayer(&stack_layer));
50 E : for (StackRecordPtr stack : *stack_layer) {
51 E : const Stack& stack_proto = stack->data();
52 : if (stack_proto.has_thread_info() &&
53 E : stack_proto.thread_info().has_exception())
54 E : return;
55 i : }
56 i : FAIL() << "No exception data found.";
57 E : }
58 :
59 : class ExceptionAnalyzerSyntheticTest : public testing::SyntheticMinidumpTest {};
60 :
61 E : TEST_F(ExceptionAnalyzerSyntheticTest, NoExceptionTest) {
62 : // Create a minidump with no exception data.
63 E : const char kData[] = "ABCD";
64 E : testing::MinidumpSpecification::MemorySpecification mem_spec(80ULL, kData);
65 E : testing::MinidumpSpecification spec;
66 E : ASSERT_TRUE(spec.AddMemoryRegion(mem_spec));
67 E : ASSERT_NO_FATAL_FAILURE(Serialize(spec));
68 :
69 : // Ensure analysis succeeds.
70 E : minidump::Minidump minidump;
71 E : ASSERT_TRUE(minidump.Open(dump_file()));
72 :
73 E : ProcessState process_state;
74 E : ExceptionAnalyzer analyzer;
75 : ASSERT_EQ(Analyzer::ANALYSIS_COMPLETE,
76 E : analyzer.Analyze(minidump, &process_state));
77 E : }
78 :
79 E : TEST_F(ExceptionAnalyzerSyntheticTest, BasicTest) {
80 : using MemorySpecification =
81 : testing::MinidumpSpecification::MemorySpecification;
82 : using ThreadSpecification =
83 : testing::MinidumpSpecification::ThreadSpecification;
84 : using ExceptionSpecification =
85 : testing::MinidumpSpecification::ExceptionSpecification;
86 :
87 : // Generate a synthetic minidump with an exception (as well as thread
88 : // information and backing memory).
89 E : const size_t kThreadId = 42;
90 E : const Address kStackAddr = 80ULL;
91 E : const Address kStackSize = 16U;
92 :
93 E : ThreadSpecification thread_spec(kThreadId, kStackAddr, kStackSize);
94 E : MemorySpecification memory_spec;
95 E : testing::MinidumpSpecification spec;
96 E : thread_spec.FillStackMemorySpecification(&memory_spec);
97 E : ASSERT_TRUE(spec.AddMemoryRegion(memory_spec));
98 E : ASSERT_TRUE(spec.AddThread(thread_spec));
99 E : ExceptionSpecification exception_spec(kThreadId);
100 E : ASSERT_TRUE(spec.AddException(exception_spec));
101 :
102 E : ASSERT_NO_FATAL_FAILURE(Serialize(spec));
103 :
104 : // Analyze.
105 E : minidump::Minidump minidump;
106 E : ASSERT_TRUE(minidump.Open(dump_file()));
107 :
108 E : ProcessState process_state;
109 E : ThreadAnalyzer thread_analyzer;
110 : ASSERT_EQ(Analyzer::ANALYSIS_COMPLETE,
111 E : thread_analyzer.Analyze(minidump, &process_state));
112 :
113 E : ExceptionAnalyzer analyzer;
114 : ASSERT_EQ(Analyzer::ANALYSIS_COMPLETE,
115 E : analyzer.Analyze(minidump, &process_state));
116 :
117 : // Validate.
118 E : StackRecordPtr stack_record;
119 E : ASSERT_TRUE(process_state.FindStackRecord(kThreadId, &stack_record));
120 E : const Stack& stack_proto = stack_record->data();
121 : ASSERT_TRUE(stack_proto.has_thread_info() &&
122 E : stack_proto.thread_info().has_exception());
123 E : const Exception& exception = stack_proto.thread_info().exception();
124 E : ASSERT_EQ(kThreadId, exception.thread_id());
125 E : ASSERT_EQ(exception_spec.exception_code, exception.exception_code());
126 E : ASSERT_EQ(exception_spec.exception_flags, exception.exception_flags());
127 E : ASSERT_EQ(exception_spec.exception_record, exception.exception_record());
128 E : ASSERT_EQ(exception_spec.exception_address, exception.exception_address());
129 : ASSERT_EQ(exception_spec.exception_information.size(),
130 E : exception.exception_information_size());
131 : ASSERT_EQ(exception_spec.exception_information[0],
132 E : exception.exception_information(0));
133 : ASSERT_EQ(exception_spec.exception_information[1],
134 E : exception.exception_information(1));
135 :
136 : // Validate RegisterInformation once implemented.
137 E : const RegisterInformation& reg_info = exception.register_info();
138 : const CONTEXT* ctx =
139 E : reinterpret_cast<const CONTEXT*>(&exception_spec.context_data.at(0));
140 E : ASSERT_EQ(ctx->SegGs, reg_info.seg_gs());
141 E : ASSERT_EQ(ctx->SegFs, reg_info.seg_fs());
142 E : ASSERT_EQ(ctx->SegEs, reg_info.seg_es());
143 E : ASSERT_EQ(ctx->SegDs, reg_info.seg_ds());
144 E : ASSERT_EQ(ctx->Edi, reg_info.edi());
145 E : ASSERT_EQ(ctx->Esi, reg_info.esi());
146 E : ASSERT_EQ(ctx->Ebx, reg_info.ebx());
147 E : ASSERT_EQ(ctx->Edx, reg_info.edx());
148 E : ASSERT_EQ(ctx->Ecx, reg_info.ecx());
149 E : ASSERT_EQ(ctx->Eax, reg_info.eax());
150 E : ASSERT_EQ(ctx->Ebp, reg_info.ebp());
151 E : ASSERT_EQ(ctx->Eip, reg_info.eip());
152 E : ASSERT_EQ(ctx->SegCs, reg_info.seg_cs());
153 E : ASSERT_EQ(ctx->EFlags, reg_info.eflags());
154 E : ASSERT_EQ(ctx->Esp, reg_info.esp());
155 E : ASSERT_EQ(ctx->SegSs, reg_info.seg_ss());
156 E : }
157 :
158 : } // namespace refinery
|