1 : // Copyright 2012 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/pe/dia_util.h"
16 :
17 : #include <diacreate.h>
18 :
19 : #include "base/logging.h"
20 : #include "base/win/scoped_bstr.h"
21 : #include "base/win/scoped_comptr.h"
22 : #include "syzygy/common/com_utils.h"
23 :
24 : namespace pe {
25 :
26 : using base::win::ScopedBstr;
27 : using base::win::ScopedComPtr;
28 :
29 : #if _MSC_VER == 1800 // MSVS 2013.
30 : const wchar_t kDiaDllName[] = L"msdia120.dll";
31 : #elif _MSC_VER == 1900 // MSVS 2015.
32 : const wchar_t kDiaDllName[] = L"msdia140.dll";
33 : #endif
34 :
35 : const wchar_t kFixupDiaDebugStreamName[] = L"FIXUP";
36 : const wchar_t kOmapToDiaDebugStreamName[] = L"OMAPTO";
37 : const wchar_t kOmapFromDiaDebugStreamName[] = L"OMAPFROM";
38 :
39 : namespace internal {
40 :
41 : bool CreateDiaObject(void** created_object, const CLSID& class_id,
42 E : const IID& interface_identifier) {
43 E : DCHECK_NE(static_cast<void**>(nullptr), created_object);
44 :
45 E : *created_object = nullptr;
46 :
47 E : base::win::ScopedComPtr<IUnknown> dia_source;
48 :
49 E : HRESULT hr1 = NoRegCoCreate(kDiaDllName,
50 : class_id,
51 : interface_identifier,
52 : reinterpret_cast<void**>(&dia_source));
53 E : if (SUCCEEDED(hr1)) {
54 E : *created_object = dia_source.Detach();
55 E : return true;
56 : }
57 :
58 i : HRESULT hr2 = dia_source.CreateInstance(CLSID_DiaSource);
59 i : if (SUCCEEDED(hr2)) {
60 i : *created_object = dia_source.Detach();
61 i : return true;
62 : }
63 :
64 i : LOG(ERROR) << "Failed to create Dia object.";
65 i : LOG(ERROR) << " NoRegCoCreate failed with: " << common::LogHr(hr1);
66 i : LOG(ERROR) << " CreateInstance failed with: " << common::LogHr(hr2);
67 :
68 i : return false;
69 E : }
70 :
71 : } // namespace internal
72 :
73 E : bool CreateDiaSource(IDiaDataSource** created_source) {
74 E : return CreateDiaObject(created_source, CLSID_DiaSource);
75 E : }
76 :
77 : bool CreateDiaSession(const base::FilePath& file,
78 : IDiaDataSource* dia_source,
79 E : IDiaSession** dia_session) {
80 E : DCHECK(dia_source != NULL);
81 E : DCHECK(dia_session != NULL);
82 :
83 E : *dia_session = NULL;
84 :
85 E : HRESULT hr = E_FAIL;
86 :
87 E : if (file.Extension() == L".pdb") {
88 E : hr = dia_source->loadDataFromPdb(file.value().c_str());
89 E : } else {
90 E : hr = dia_source->loadDataForExe(file.value().c_str(), NULL, NULL);
91 : }
92 :
93 E : if (FAILED(hr)) {
94 i : LOG(ERROR) << "Failed to load DIA data for \"" << file.value() << "\": "
95 : << common::LogHr(hr) << ".";
96 i : return false;
97 : }
98 :
99 E : ScopedComPtr<IDiaSession> session;
100 E : hr = dia_source->openSession(session.Receive());
101 E : if (FAILED(hr)) {
102 i : LOG(ERROR) << "Failed to open DIA session for \"" << file.value() << "\" : "
103 : << common::LogHr(hr) << ".";
104 i : return false;
105 : }
106 :
107 E : *dia_session = session.Detach();
108 :
109 E : return true;
110 E : }
111 :
112 : SearchResult FindDiaTable(const IID& iid,
113 : IDiaSession* dia_session,
114 E : void** out_table) {
115 E : DCHECK(dia_session != NULL);
116 E : DCHECK(out_table != NULL);
117 :
118 E : *out_table = NULL;
119 :
120 : // Get the table enumerator.
121 E : base::win::ScopedComPtr<IDiaEnumTables> enum_tables;
122 E : HRESULT hr = dia_session->getEnumTables(enum_tables.Receive());
123 E : if (FAILED(hr)) {
124 i : LOG(ERROR) << "Failed to get DIA table enumerator: "
125 : << common::LogHr(hr) << ".";
126 i : return kSearchErrored;
127 : }
128 :
129 : // Iterate through the tables.
130 E : while (true) {
131 E : base::win::ScopedComPtr<IDiaTable> table;
132 E : ULONG fetched = 0;
133 E : hr = enum_tables->Next(1, table.Receive(), &fetched);
134 E : if (FAILED(hr)) {
135 i : LOG(ERROR) << "Failed to get DIA table: "
136 : << common::LogHr(hr) << ".";
137 i : return kSearchErrored;
138 : }
139 E : if (fetched == 0)
140 i : break;
141 :
142 E : hr = table.QueryInterface(iid, out_table);
143 E : if (SUCCEEDED(hr))
144 E : return kSearchSucceeded;
145 E : }
146 :
147 : // The search completed, even though we didn't find what we were looking for.
148 i : return kSearchFailed;
149 E : }
150 :
151 : SearchResult FindDiaDebugStream(const wchar_t* name,
152 : IDiaSession* dia_session,
153 E : IDiaEnumDebugStreamData** dia_debug_stream) {
154 E : DCHECK(name != NULL);
155 E : DCHECK(dia_session != NULL);
156 E : DCHECK(dia_debug_stream != NULL);
157 :
158 E : *dia_debug_stream = NULL;
159 :
160 E : HRESULT hr = E_FAIL;
161 E : ScopedComPtr<IDiaEnumDebugStreams> debug_streams;
162 E : if (FAILED(hr = dia_session->getEnumDebugStreams(debug_streams.Receive()))) {
163 i : LOG(ERROR) << "Unable to get debug streams: " << common::LogHr(hr) << ".";
164 i : return kSearchErrored;
165 : }
166 :
167 : // Iterate through the debug streams.
168 E : while (true) {
169 E : ScopedComPtr<IDiaEnumDebugStreamData> debug_stream;
170 E : ULONG count = 0;
171 E : HRESULT hr = debug_streams->Next(1, debug_stream.Receive(), &count);
172 E : if (FAILED(hr) || (hr != S_FALSE && count != 1)) {
173 i : LOG(ERROR) << "Unable to load debug stream: "
174 : << common::LogHr(hr) << ".";
175 i : return kSearchErrored;
176 E : } else if (hr == S_FALSE) {
177 : // No more records.
178 E : break;
179 : }
180 :
181 E : ScopedBstr stream_name;
182 E : if (FAILED(hr = debug_stream->get_name(stream_name.Receive()))) {
183 i : LOG(ERROR) << "Unable to get debug stream name: "
184 : << common::LogHr(hr) << ".";
185 i : return kSearchErrored;
186 : }
187 :
188 : // Found the stream?
189 E : if (wcscmp(common::ToString(stream_name), name) == 0) {
190 E : *dia_debug_stream = debug_stream.Detach();
191 E : return kSearchSucceeded;
192 : }
193 E : }
194 :
195 E : return kSearchFailed;
196 E : }
197 :
198 : bool GetSymIndexId(IDiaSymbol* symbol, uint32_t* sym_index_id) {
199 : DCHECK(symbol);
200 : DCHECK(sym_index_id);
201 :
202 : DWORD index_id = 0;
203 : HRESULT hr = symbol->get_symIndexId(&index_id);
204 : if (hr != S_OK) {
205 : LOG(ERROR) << "Error getting symbol's index id. " << common::LogHr(hr);
206 : return false;
207 : }
208 :
209 : *sym_index_id = static_cast<uint32_t>(index_id);
210 : return true;
211 : }
212 :
213 E : bool GetSymTag(IDiaSymbol* symbol, enum SymTagEnum* sym_tag) {
214 E : DCHECK(symbol != NULL);
215 E : DCHECK(sym_tag != NULL);
216 E : DWORD tmp_tag = SymTagNull;
217 E : *sym_tag = SymTagNull;
218 E : HRESULT hr = symbol->get_symTag(&tmp_tag);
219 E : if (hr != S_OK) {
220 i : LOG(ERROR) << "Error getting sym tag: " << common::LogHr(hr) << ".";
221 i : return false;
222 : }
223 E : *sym_tag = static_cast<enum SymTagEnum>(tmp_tag);
224 E : return true;
225 E : }
226 :
227 E : bool IsSymTag(IDiaSymbol* symbol, enum SymTagEnum expected_sym_tag) {
228 E : DCHECK(symbol != NULL);
229 E : DCHECK(expected_sym_tag != SymTagNull);
230 :
231 E : enum SymTagEnum sym_tag = SymTagNull;
232 E : if (!GetSymTag(symbol, &sym_tag))
233 i : return false;
234 :
235 E : return sym_tag == expected_sym_tag;
236 E : }
237 :
238 : bool GetSymName(IDiaSymbol* symbol, base::string16* name) {
239 : DCHECK(symbol); DCHECK(name);
240 :
241 : base::win::ScopedBstr tmp;
242 : HRESULT hr = symbol->get_name(tmp.Receive());
243 : if (hr != S_OK) {
244 : LOG(ERROR) << "Error getting symbol's name: " << common::LogHr(hr) << ".";
245 : return false;
246 : }
247 :
248 : *name = common::ToString(tmp);
249 : return true;
250 : }
251 :
252 : bool GetSymUndecoratedName(IDiaSymbol* symbol, base::string16* name) {
253 : DCHECK(symbol); DCHECK(name);
254 :
255 : base::win::ScopedBstr tmp;
256 : HRESULT hr = symbol->get_undecoratedName(tmp.Receive());
257 : if (hr != S_OK) {
258 : LOG(ERROR) << "Error getting symbol's undecorated name: "
259 : << common::LogHr(hr) << ".";
260 : return false;
261 : }
262 :
263 : *name = common::ToString(tmp);
264 : return true;
265 : }
266 :
267 : bool GetDataKind(IDiaSymbol* symbol, enum DataKind* data_kind) {
268 : DCHECK(symbol); DCHECK(data_kind);
269 :
270 : DWORD tmp = 0;
271 : HRESULT hr = symbol->get_dataKind(&tmp);
272 : if (hr != S_OK) {
273 : LOG(ERROR) << "Error getting symbol's data kind: " << common::LogHr(hr)
274 : << ".";
275 : return false;
276 : }
277 :
278 : *data_kind = static_cast<DataKind>(tmp);
279 : return true;
280 : }
281 :
282 : bool GetLocationType(IDiaSymbol* symbol, enum LocationType* location_type) {
283 : DCHECK(symbol); DCHECK(location_type);
284 :
285 : DWORD tmp = 0;
286 : HRESULT hr = symbol->get_locationType(&tmp);
287 : if (hr != S_OK) {
288 : LOG(ERROR) << "Error getting symbol's location type: " << common::LogHr(hr)
289 : << ".";
290 : return false;
291 : }
292 :
293 : *location_type = static_cast<LocationType>(tmp);
294 : return true;
295 : }
296 :
297 : bool GetRegisterId(IDiaSymbol* symbol, uint32_t* register_id) {
298 : DCHECK(symbol); DCHECK(register_id);
299 :
300 : DWORD tmp = 0;
301 : HRESULT hr = symbol->get_registerId(&tmp);
302 : if (hr != S_OK) {
303 : LOG(ERROR) << "Error getting symbol's register id: " << common::LogHr(hr)
304 : << ".";
305 : return false;
306 : }
307 :
308 : *register_id = static_cast<uint32_t>(tmp);
309 : return true;
310 : }
311 :
312 : bool GetSymOffset(IDiaSymbol* symbol, ptrdiff_t* offset) {
313 : DCHECK(symbol); DCHECK(offset);
314 :
315 : LONG tmp = 0;
316 : HRESULT hr = symbol->get_offset(&tmp);
317 : if (hr != S_OK) {
318 : LOG(ERROR) << "Error getting symbol's offset: " << common::LogHr(hr) << ".";
319 : return false;
320 : }
321 :
322 : *offset = static_cast<ptrdiff_t>(tmp);
323 : return true;
324 : }
325 :
326 : bool GetSymType(IDiaSymbol* symbol, base::win::ScopedComPtr<IDiaSymbol>* type) {
327 : DCHECK(symbol); DCHECK(type);
328 :
329 : base::win::ScopedComPtr<IDiaSymbol> tmp;
330 : HRESULT hr = symbol->get_type(tmp.Receive());
331 : if (hr != S_OK) {
332 : LOG(ERROR) << "Error getting symbol's type: " << common::LogHr(hr) << ".";
333 : return false;
334 : }
335 :
336 : *type = tmp;
337 : return true;
338 : }
339 :
340 : bool GetSymQualifiers(IDiaSymbol* symbol, bool* is_const, bool* is_volatile) {
341 : DCHECK(symbol); DCHECK(is_const); DCHECK(is_volatile);
342 :
343 : BOOL is_const_tmp = FALSE;
344 : HRESULT hr = symbol->get_constType(&is_const_tmp);
345 : if (hr != S_OK)
346 : return false;
347 :
348 : BOOL is_volatile_tmp = FALSE;
349 : hr = symbol->get_volatileType(&is_volatile_tmp);
350 : if (hr != S_OK)
351 : return false;
352 :
353 : *is_const = (is_const_tmp == TRUE);
354 : *is_volatile = (is_volatile_tmp == TRUE);
355 : return true;
356 : }
357 :
358 : bool GetSymCount(IDiaSymbol* symbol, size_t* count) {
359 : DCHECK(symbol); DCHECK(count);
360 :
361 : DWORD tmp = 0;
362 : HRESULT hr = symbol->get_count(&tmp);
363 : if (hr != S_OK)
364 : return false;
365 :
366 : *count = static_cast<size_t>(tmp);
367 : return true;
368 : }
369 :
370 : bool GetSymClassParent(IDiaSymbol* symbol,
371 : base::win::ScopedComPtr<IDiaSymbol>* parent) {
372 : DCHECK(symbol); DCHECK(parent);
373 : *parent = nullptr;
374 :
375 : base::win::ScopedComPtr<IDiaSymbol> tmp;
376 : HRESULT hr = symbol->get_classParent(tmp.Receive());
377 : if (hr == S_FALSE) {
378 : // This happens routinely for functions that aren't members.
379 : return true;
380 : }
381 : if (hr != S_OK) {
382 : LOG(ERROR) << "Error getting symbol's class parent: " << common::LogHr(hr)
383 : << ".";
384 : return false;
385 : }
386 :
387 : *parent = tmp;
388 : return true;
389 : }
390 :
391 : bool GetSymLexicalParent(IDiaSymbol* symbol,
392 : base::win::ScopedComPtr<IDiaSymbol>* parent) {
393 : DCHECK(symbol); DCHECK(parent);
394 :
395 : base::win::ScopedComPtr<IDiaSymbol> tmp;
396 : HRESULT hr = symbol->get_lexicalParent(tmp.Receive());
397 : if (hr != S_OK) {
398 : LOG(ERROR) << "Error getting symbol's lexical parent: " << common::LogHr(hr)
399 : << ".";
400 : return false;
401 : }
402 :
403 : *parent = tmp;
404 : return true;
405 : }
406 :
407 : bool GetFrameBase(IDiaStackFrame* frame, uint64_t* frame_base) {
408 : DCHECK(frame != NULL);
409 : DCHECK(frame_base != NULL);
410 :
411 : ULONGLONG base = 0ULL;
412 : HRESULT hr = frame->get_base(&base);
413 : if (hr != S_OK) {
414 : LOG(ERROR) << "Failed to get stack frame's base address: "
415 : << common::LogHr(hr) << ".";
416 : return false;
417 : }
418 :
419 : *frame_base = static_cast<uint64_t>(base);
420 : return true;
421 : }
422 :
423 : bool GetRegisterValue(IDiaStackFrame* frame,
424 : CV_HREG_e register_index,
425 : uint64_t* register_value) {
426 : DCHECK(frame != NULL);
427 : DCHECK(register_value != NULL);
428 :
429 : ULONGLONG value = 0ULL;
430 : HRESULT hr = frame->get_registerValue(register_index, &value);
431 : if (hr != S_OK) {
432 : // TODO(manzagop): print human readable register names.
433 : LOG(ERROR) << "Failed to get register value for index: "
434 : << register_index << ". Error: " << common::LogHr(hr) << ".";
435 : return false;
436 : }
437 :
438 : *register_value = static_cast<uint64_t>(value);
439 : return true;
440 : }
441 :
442 : bool GetSize(IDiaStackFrame* frame, uint32_t* frame_size) {
443 : DCHECK(frame != NULL);
444 : DCHECK(frame_size != NULL);
445 :
446 : DWORD size = 0U;
447 : HRESULT hr = frame->get_size(&size);
448 : if (hr != S_OK) {
449 : LOG(ERROR) << "Failed to get frame size: " << common::LogHr(hr) << ".";
450 : return false;
451 : }
452 :
453 : *frame_size = static_cast<uint32_t>(size);
454 : return true;
455 : }
456 :
457 : bool GetLocalsBase(IDiaStackFrame* frame, uint64_t* locals_base) {
458 : DCHECK(frame != NULL);
459 : DCHECK(locals_base != NULL);
460 :
461 : ULONGLONG base = 0ULL;
462 : HRESULT hr = frame->get_localsBase(&base);
463 : if (hr != S_OK) {
464 : LOG(ERROR) << "Failed to get base address of locals: " << common::LogHr(hr)
465 : << ".";
466 : return false;
467 : }
468 :
469 : *locals_base = static_cast<uint64_t>(base);
470 : return true;
471 : }
472 :
473 : ChildVisitor::ChildVisitor(IDiaSymbol* parent, enum SymTagEnum type)
474 E : : parent_(parent), type_(type), child_callback_(NULL) {
475 E : DCHECK(parent != NULL);
476 E : }
477 :
478 E : bool ChildVisitor::VisitChildren(const VisitSymbolCallback& child_callback) {
479 E : DCHECK(child_callback_ == NULL);
480 :
481 E : child_callback_ = &child_callback;
482 E : bool ret = VisitChildrenImpl();
483 E : child_callback_ = NULL;
484 :
485 E : return ret;
486 E : }
487 :
488 E : bool ChildVisitor::VisitChildrenImpl() {
489 E : DCHECK(child_callback_ != NULL);
490 :
491 : // Retrieve an enumerator for all children in this PDB.
492 E : base::win::ScopedComPtr<IDiaEnumSymbols> children;
493 E : HRESULT hr = parent_->findChildren(type_,
494 : NULL,
495 : nsNone,
496 : children.Receive());
497 E : if (FAILED(hr)) {
498 i : LOG(ERROR) << "Unable to get children: " << common::LogHr(hr);
499 i : return false;
500 : }
501 :
502 E : if (hr == S_FALSE)
503 i : return true; // No child.
504 :
505 E : return EnumerateChildren(children.get());
506 E : }
507 :
508 E : bool ChildVisitor::EnumerateChildren(IDiaEnumSymbols* children) {
509 E : DCHECK(children!= NULL);
510 :
511 E : while (true) {
512 E : base::win::ScopedComPtr<IDiaSymbol> child;
513 E : ULONG fetched = 0;
514 E : HRESULT hr = children->Next(1, child.Receive(), &fetched);
515 E : if (FAILED(hr)) {
516 i : DCHECK_EQ(0U, fetched);
517 i : DCHECK(child.get() != nullptr);
518 i : LOG(ERROR) << "Unable to iterate children: " << common::LogHr(hr);
519 i : return false;
520 : }
521 E : if (hr == S_FALSE)
522 E : break;
523 :
524 E : DCHECK_EQ(1U, fetched);
525 E : DCHECK(child.get() != nullptr);
526 :
527 E : if (!VisitChild(child.get()))
528 E : return false;
529 E : }
530 :
531 E : return true;
532 E : }
533 :
534 E : bool ChildVisitor::VisitChild(IDiaSymbol* child) {
535 E : DCHECK(child_callback_ != NULL);
536 :
537 E : return child_callback_->Run(child);
538 E : }
539 :
540 E : CompilandVisitor::CompilandVisitor(IDiaSession* session) : session_(session) {
541 E : DCHECK(session != NULL);
542 E : }
543 :
544 : bool CompilandVisitor::VisitAllCompilands(
545 E : const VisitCompilandCallback& compiland_callback) {
546 E : base::win::ScopedComPtr<IDiaSymbol> global;
547 E : HRESULT hr = session_->get_globalScope(global.Receive());
548 E : if (FAILED(hr)) {
549 i : LOG(ERROR) << "Unable to get global scope: " << common::LogHr(hr);
550 i : return false;
551 : }
552 :
553 E : ChildVisitor visitor(global.get(), SymTagCompiland);
554 :
555 E : return visitor.VisitChildren(compiland_callback);
556 E : }
557 :
558 : LineVisitor::LineVisitor(IDiaSession* session, IDiaSymbol* compiland)
559 E : : session_(session), compiland_(compiland), line_callback_(NULL) {
560 E : DCHECK(session != NULL);
561 E : }
562 :
563 E : bool LineVisitor::VisitLines(const VisitLineCallback& line_callback) {
564 E : DCHECK(line_callback_ == NULL);
565 :
566 E : line_callback_ = &line_callback;
567 E : bool ret = VisitLinesImpl();
568 E : line_callback_ = NULL;
569 :
570 E : return ret;
571 E : }
572 :
573 : bool LineVisitor::EnumerateCompilandSource(IDiaSymbol* compiland,
574 E : IDiaSourceFile* source_file) {
575 E : DCHECK(compiland != NULL);
576 E : DCHECK(source_file != NULL);
577 :
578 E : base::win::ScopedComPtr<IDiaEnumLineNumbers> line_numbers;
579 E : HRESULT hr = session_->findLines(compiland,
580 : source_file,
581 : line_numbers.Receive());
582 E : if (FAILED(hr)) {
583 : // This seems to happen for the occasional header file.
584 i : return true;
585 : }
586 :
587 E : while (true) {
588 E : base::win::ScopedComPtr<IDiaLineNumber> line_number;
589 E : ULONG fetched = 0;
590 E : hr = line_numbers->Next(1, line_number.Receive(), &fetched);
591 E : if (FAILED(hr)) {
592 i : DCHECK_EQ(0U, fetched);
593 i : DCHECK(line_number.get() != nullptr);
594 i : LOG(ERROR) << "Unable to iterate line numbers: " << common::LogHr(hr);
595 i : return false;
596 : }
597 E : if (hr == S_FALSE)
598 E : break;
599 :
600 E : DCHECK_EQ(1U, fetched);
601 E : DCHECK(line_number.get() != nullptr);
602 :
603 E : if (!VisitSourceLine(line_number.get()))
604 i : return false;
605 E : }
606 :
607 E : return true;
608 E : }
609 :
610 : bool LineVisitor::EnumerateCompilandSources(IDiaSymbol* compiland,
611 E : IDiaEnumSourceFiles* source_files) {
612 E : DCHECK(compiland != NULL);
613 E : DCHECK(source_files != NULL);
614 :
615 E : while (true) {
616 E : base::win::ScopedComPtr<IDiaSourceFile> source_file;
617 E : ULONG fetched = 0;
618 E : HRESULT hr = source_files->Next(1, source_file.Receive(), &fetched);
619 E : if (FAILED(hr)) {
620 i : DCHECK_EQ(0U, fetched);
621 i : DCHECK(source_file == NULL);
622 i : LOG(ERROR) << "Unable to iterate source files: " << common::LogHr(hr);
623 i : return false;
624 : }
625 E : if (hr == S_FALSE)
626 E : break;
627 :
628 E : DCHECK_EQ(1U, fetched);
629 E : DCHECK(compiland != NULL);
630 :
631 E : if (!EnumerateCompilandSource(compiland, source_file.get()))
632 i : return false;
633 E : }
634 :
635 E : return true;
636 E : }
637 :
638 E : bool LineVisitor::VisitLinesImpl() {
639 E : DCHECK(session_ != NULL);
640 E : DCHECK(compiland_ != NULL);
641 E : DCHECK(line_callback_ != NULL);
642 :
643 : // Enumerate all source files referenced by this compiland.
644 E : base::win::ScopedComPtr<IDiaEnumSourceFiles> source_files;
645 E : HRESULT hr = session_->findFile(compiland_.get(), NULL, nsNone,
646 : source_files.Receive());
647 E : if (FAILED(hr)) {
648 i : LOG(ERROR) << "Unable to get source files: " << common::LogHr(hr);
649 i : return false;
650 : }
651 :
652 E : return EnumerateCompilandSources(compiland_.get(), source_files.get());
653 E : }
654 :
655 E : bool LineVisitor::VisitSourceLine(IDiaLineNumber* line_number) {
656 E : DCHECK(line_callback_ != NULL);
657 :
658 E : return line_callback_->Run(line_number);
659 E : }
660 :
661 : } // namespace pe
|