OLD | NEW |
1 // Copyright 2015 Google Inc. All Rights Reserved. | 1 // Copyright 2015 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 | 47 |
48 struct SimpleUDT { | 48 struct SimpleUDT { |
49 int one; | 49 int one; |
50 const char two; | 50 const char two; |
51 }; | 51 }; |
52 | 52 |
53 __declspec(noinline) DWORD GetEip() { | 53 __declspec(noinline) DWORD GetEip() { |
54 return reinterpret_cast<DWORD>(_ReturnAddress()); | 54 return reinterpret_cast<DWORD>(_ReturnAddress()); |
55 } | 55 } |
56 | 56 |
57 bool AnalyzeMinidump(const base::FilePath& minidump_path, | |
58 ProcessState* process_state) { | |
59 minidump::Minidump minidump; | |
60 if (!minidump.Open(minidump_path)) | |
61 return false; | |
62 | |
63 scoped_refptr<DiaSymbolProvider> dia_symbol_provider(new DiaSymbolProvider()); | |
64 scoped_refptr<SymbolProvider> symbol_provider(new SymbolProvider()); | |
65 | |
66 AnalysisRunner runner; | |
67 scoped_ptr<Analyzer> analyzer(new refinery::MemoryAnalyzer()); | |
68 runner.AddAnalyzer(analyzer.Pass()); | |
69 analyzer.reset(new refinery::ThreadAnalyzer()); | |
70 runner.AddAnalyzer(analyzer.Pass()); | |
71 analyzer.reset(new refinery::ExceptionAnalyzer()); | |
72 runner.AddAnalyzer(analyzer.Pass()); | |
73 analyzer.reset(new refinery::ModuleAnalyzer()); | |
74 runner.AddAnalyzer(analyzer.Pass()); | |
75 analyzer.reset(new refinery::StackAnalyzer(dia_symbol_provider)); | |
76 runner.AddAnalyzer(analyzer.Pass()); | |
77 analyzer.reset( | |
78 new refinery::StackFrameAnalyzer(dia_symbol_provider, symbol_provider)); | |
79 runner.AddAnalyzer(analyzer.Pass()); | |
80 | |
81 return runner.Analyze(minidump, process_state) == Analyzer::ANALYSIS_COMPLETE; | |
82 } | |
83 | |
84 void ValidateTypedBlock(ProcessState* process_state, | |
85 Address expected_address, | |
86 Size expected_size, | |
87 const std::string& expected_variable_name, | |
88 const std::string& expected_type_name) { | |
89 TypedBlockRecordPtr typedblock_record; | |
90 // Note: using FindSingleRecord as there should be no typed block overlap in | |
91 // the context of this test. | |
92 ASSERT_TRUE( | |
93 process_state->FindSingleRecord(expected_address, &typedblock_record)); | |
94 | |
95 ASSERT_EQ(expected_address, typedblock_record->range().addr()); | |
96 ASSERT_EQ(expected_size, typedblock_record->range().size()); | |
97 const TypedBlock& typedblock = typedblock_record->data(); | |
98 ASSERT_EQ(expected_variable_name, typedblock.data_name()); | |
99 ASSERT_EQ(expected_type_name, typedblock.type_name()); | |
100 } | |
101 | |
102 } // namespace | 57 } // namespace |
103 | 58 |
104 class StackAndFrameAnalyzersTest : public testing::Test { | 59 class StackAndFrameAnalyzersTest : public testing::Test { |
105 protected: | 60 protected: |
106 void SetUp() override { | 61 void SetUp() override { |
107 // Override NT symbol path. | 62 // Override NT symbol path. |
108 ASSERT_TRUE(scoped_symbol_path_.Setup()); | 63 ASSERT_TRUE(scoped_symbol_path_.Setup()); |
109 | 64 |
| 65 symbol_provider_ = new SymbolProvider(); |
| 66 |
110 expected_esp_ = 0U; | 67 expected_esp_ = 0U; |
111 eip_lowerbound_ = 0U; | 68 eip_lowerbound_ = 0U; |
112 eip_upperbound_ = 0U; | 69 eip_upperbound_ = 0U; |
113 | 70 |
114 expected_param_address_ = 0ULL; | 71 expected_param_address_ = 0ULL; |
115 expected_udt_address_ = 0ULL; | 72 expected_udt_address_ = 0ULL; |
116 expected_udt_ptr_address_ = 0ULL; | 73 expected_udt_ptr_address_ = 0ULL; |
117 } | 74 } |
118 | 75 |
119 base::FilePath minidump_path() { return scoped_minidump_.minidump_path(); } | 76 base::FilePath minidump_path() { return scoped_minidump_.minidump_path(); } |
(...skipping 28 matching lines...) Expand all Loading... |
148 | 105 |
149 eip_upperbound_ = GetEip(); | 106 eip_upperbound_ = GetEip(); |
150 | 107 |
151 expected_param_address_ = reinterpret_cast<Address>(&dummy_param); | 108 expected_param_address_ = reinterpret_cast<Address>(&dummy_param); |
152 expected_udt_address_ = reinterpret_cast<Address>(&udt_local); | 109 expected_udt_address_ = reinterpret_cast<Address>(&udt_local); |
153 expected_udt_ptr_address_ = reinterpret_cast<Address>(&udt_ptr_local); | 110 expected_udt_ptr_address_ = reinterpret_cast<Address>(&udt_ptr_local); |
154 | 111 |
155 return success; | 112 return success; |
156 } | 113 } |
157 | 114 |
| 115 bool AnalyzeMinidump(ProcessState* process_state) { |
| 116 minidump::Minidump minidump; |
| 117 if (!minidump.Open(minidump_path())) |
| 118 return false; |
| 119 |
| 120 scoped_refptr<DiaSymbolProvider> dia_symbol_provider( |
| 121 new DiaSymbolProvider()); |
| 122 |
| 123 AnalysisRunner runner; |
| 124 scoped_ptr<Analyzer> analyzer(new refinery::MemoryAnalyzer()); |
| 125 runner.AddAnalyzer(analyzer.Pass()); |
| 126 analyzer.reset(new refinery::ThreadAnalyzer()); |
| 127 runner.AddAnalyzer(analyzer.Pass()); |
| 128 analyzer.reset(new refinery::ExceptionAnalyzer()); |
| 129 runner.AddAnalyzer(analyzer.Pass()); |
| 130 analyzer.reset(new refinery::ModuleAnalyzer()); |
| 131 runner.AddAnalyzer(analyzer.Pass()); |
| 132 analyzer.reset(new refinery::StackAnalyzer(dia_symbol_provider)); |
| 133 runner.AddAnalyzer(analyzer.Pass()); |
| 134 analyzer.reset(new refinery::StackFrameAnalyzer(dia_symbol_provider, |
| 135 symbol_provider_)); |
| 136 runner.AddAnalyzer(analyzer.Pass()); |
| 137 |
| 138 return runner.Analyze(minidump, process_state) == |
| 139 Analyzer::ANALYSIS_COMPLETE; |
| 140 } |
| 141 |
| 142 void ValidateTypedBlock(ProcessState* process_state, |
| 143 Address expected_address, |
| 144 Size expected_size, |
| 145 ModuleId expected_module_id, |
| 146 const std::string& expected_variable_name, |
| 147 const base::string16& expected_type_name) { |
| 148 TypedBlockRecordPtr typedblock_record; |
| 149 // Note: using FindSingleRecord as there should be no typed block overlap in |
| 150 // the context of this test. |
| 151 ASSERT_TRUE( |
| 152 process_state->FindSingleRecord(expected_address, &typedblock_record)); |
| 153 |
| 154 ASSERT_EQ(expected_address, typedblock_record->range().addr()); |
| 155 ASSERT_EQ(expected_size, typedblock_record->range().size()); |
| 156 |
| 157 const TypedBlock& typedblock = typedblock_record->data(); |
| 158 ASSERT_EQ(expected_module_id, typedblock.module_id()); |
| 159 |
| 160 // Validate the recovered type id corresponds to the expected name. |
| 161 ModuleLayerAccessor accessor(process_state); |
| 162 pe::PEFile::Signature signature; |
| 163 ASSERT_TRUE(accessor.GetModuleSignature(expected_module_id, &signature)); |
| 164 |
| 165 scoped_refptr<TypeRepository> type_repository; |
| 166 ASSERT_TRUE(symbol_provider_->FindOrCreateTypeRepository(signature, |
| 167 &type_repository)); |
| 168 |
| 169 TypePtr recovered_type = type_repository->GetType(typedblock.type_id()); |
| 170 ASSERT_NE(nullptr, recovered_type); |
| 171 ASSERT_EQ(expected_type_name, recovered_type->name()); |
| 172 |
| 173 ASSERT_EQ(expected_variable_name, typedblock.data_name()); |
| 174 } |
| 175 |
158 private: | 176 private: |
159 testing::ScopedMinidump scoped_minidump_; | 177 testing::ScopedMinidump scoped_minidump_; |
160 | 178 |
| 179 scoped_refptr<SymbolProvider> symbol_provider_; |
| 180 |
161 // For stack frame validation. | 181 // For stack frame validation. |
162 uint32 expected_esp_; | 182 uint32 expected_esp_; |
163 uint32 eip_lowerbound_; | 183 uint32 eip_lowerbound_; |
164 uint32 eip_upperbound_; | 184 uint32 eip_upperbound_; |
165 | 185 |
166 // Typed block validation. | 186 // Typed block validation. |
167 Address expected_param_address_; | 187 Address expected_param_address_; |
168 Address expected_udt_address_; | 188 Address expected_udt_address_; |
169 Address expected_udt_ptr_address_; | 189 Address expected_udt_ptr_address_; |
170 | 190 |
(...skipping 19 matching lines...) Expand all Loading... |
190 // address). | 210 // address). |
191 uint32 expected_frame_base = 0U; | 211 uint32 expected_frame_base = 0U; |
192 __asm { | 212 __asm { |
193 mov expected_frame_base, esp | 213 mov expected_frame_base, esp |
194 } | 214 } |
195 expected_frame_base -= (sizeof(void*) + sizeof(int)); | 215 expected_frame_base -= (sizeof(void*) + sizeof(int)); |
196 | 216 |
197 ASSERT_TRUE(SetupStackFrameAndGenerateMinidump(dummy_argument)); | 217 ASSERT_TRUE(SetupStackFrameAndGenerateMinidump(dummy_argument)); |
198 | 218 |
199 ProcessState process_state; | 219 ProcessState process_state; |
200 ASSERT_TRUE(AnalyzeMinidump(minidump_path(), &process_state)); | 220 ASSERT_TRUE(AnalyzeMinidump(&process_state)); |
201 | 221 |
202 // Ensure the test's thread was successfully walked. | 222 // Ensure the test's thread was successfully walked. |
203 StackRecordPtr stack; | 223 StackRecordPtr stack; |
204 DWORD thread_id = ::GetCurrentThreadId(); | 224 DWORD thread_id = ::GetCurrentThreadId(); |
205 ASSERT_TRUE( | 225 ASSERT_TRUE( |
206 process_state.FindStackRecord(static_cast<size_t>(thread_id), &stack)); | 226 process_state.FindStackRecord(static_cast<size_t>(thread_id), &stack)); |
207 ASSERT_TRUE(stack->data().stack_walk_success()); | 227 ASSERT_TRUE(stack->data().stack_walk_success()); |
208 | 228 |
209 // Validate SetupStackFrameAndGenerateMinidump's frame. | 229 // Validate SetupStackFrameAndGenerateMinidump's frame. |
210 StackFrameRecordPtr frame_record; | 230 StackFrameRecordPtr frame_record; |
(...skipping 15 matching lines...) Expand all Loading... |
226 ASSERT_LT(eip_upperbound() - eip_lowerbound(), 100); | 246 ASSERT_LT(eip_upperbound() - eip_lowerbound(), 100); |
227 | 247 |
228 // TODO(manzagop): validate frame_size_bytes. It should be sizeof(void*) | 248 // TODO(manzagop): validate frame_size_bytes. It should be sizeof(void*) |
229 // smaller than expected_frame_base - expected_esp(), to account for ebp | 249 // smaller than expected_frame_base - expected_esp(), to account for ebp |
230 // and since the function called into has no parameters. | 250 // and since the function called into has no parameters. |
231 | 251 |
232 // TODO(manzagop): validate locals_base. It should be sizeof(void*) off of | 252 // TODO(manzagop): validate locals_base. It should be sizeof(void*) off of |
233 // the frame base, to account for ebp. | 253 // the frame base, to account for ebp. |
234 | 254 |
235 // Validate typed block layer for SetupStackFrameAndGenerateMinidump. | 255 // Validate typed block layer for SetupStackFrameAndGenerateMinidump. |
| 256 ModuleLayerAccessor accessor(&process_state); |
| 257 ModuleId expected_module_id = accessor.GetModuleId(recovered_eip); |
| 258 ASSERT_NE(kNoModuleId, expected_module_id); |
| 259 |
236 // - Validate some locals. | 260 // - Validate some locals. |
237 ASSERT_NO_FATAL_FAILURE(ValidateTypedBlock( | 261 ASSERT_NO_FATAL_FAILURE( |
238 &process_state, expected_udt_address(), sizeof(SimpleUDT), "udt_local", | 262 ValidateTypedBlock(&process_state, expected_udt_address(), |
239 "refinery::`anonymous-namespace'::SimpleUDT")); | 263 sizeof(SimpleUDT), expected_module_id, "udt_local", |
| 264 L"refinery::`anonymous-namespace'::SimpleUDT")); |
240 ASSERT_NO_FATAL_FAILURE(ValidateTypedBlock( | 265 ASSERT_NO_FATAL_FAILURE(ValidateTypedBlock( |
241 &process_state, expected_udt_ptr_address(), sizeof(SimpleUDT*), | 266 &process_state, expected_udt_ptr_address(), sizeof(SimpleUDT*), |
242 "udt_ptr_local", "refinery::`anonymous-namespace'::SimpleUDT*")); | 267 expected_module_id, "udt_ptr_local", |
| 268 L"refinery::`anonymous-namespace'::SimpleUDT*")); |
243 // - Validate a parameter. | 269 // - Validate a parameter. |
244 ASSERT_NO_FATAL_FAILURE( | 270 ASSERT_NO_FATAL_FAILURE( |
245 ValidateTypedBlock(&process_state, expected_param_address(), sizeof(int), | 271 ValidateTypedBlock(&process_state, expected_param_address(), sizeof(int), |
246 "dummy_param", "int32_t")); | 272 expected_module_id, "dummy_param", L"int32_t")); |
247 } | 273 } |
248 | 274 |
249 } // namespace refinery | 275 } // namespace refinery |
OLD | NEW |