1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "common/windows/pdb_source_line_writer.h"
31
32 #include <windows.h>
33 #include <winnt.h>
34 #include <atlbase.h>
35 #include <dia2.h>
36 #include <ImageHlp.h>
37 #include <stdio.h>
38
39 #include <limits>
40 #include <set>
41
42 #include "common/windows/dia_util.h"
43 #include "common/windows/guid_string.h"
44 #include "common/windows/string_utils-inl.h"
45
46 // This constant may be missing from DbgHelp.h. See the documentation for
47 // IDiaSymbol::get_undecoratedNameEx.
48 #ifndef UNDNAME_NO_ECSU
49 #define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union.
50 #endif // UNDNAME_NO_ECSU
51
52 /*
53 * Not defined in WinNT.h for some reason. Definitions taken from:
54 * http://uninformed.org/index.cgi?v=4&a=1&p=13
55 *
56 */
57 typedef unsigned char UBYTE;
58
59 #if !defined(_WIN64)
60 #define UNW_FLAG_EHANDLER 0x01
61 #define UNW_FLAG_UHANDLER 0x02
62 #define UNW_FLAG_CHAININFO 0x04
63 #endif
64
65 union UnwindCode {
66 struct {
67 UBYTE offset_in_prolog;
68 UBYTE unwind_operation_code : 4;
69 UBYTE operation_info : 4;
70 };
71 USHORT frame_offset;
72 };
73
74 enum UnwindOperationCodes {
75 UWOP_PUSH_NONVOL = 0, /* info == register number */
76 UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
77 UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
78 UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
79 UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
80 UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
81 // XXX: these are missing from MSDN!
82 // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
83 UWOP_SAVE_XMM,
84 UWOP_SAVE_XMM_FAR,
85 UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
86 UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
87 UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
88 };
89
90 // See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
91 // Note: some fields removed as we don't use them.
92 struct UnwindInfo {
93 UBYTE version : 3;
94 UBYTE flags : 5;
95 UBYTE size_of_prolog;
96 UBYTE count_of_codes;
97 UBYTE frame_register : 4;
98 UBYTE frame_offset : 4;
99 UnwindCode unwind_code[1];
100 };
101
102 namespace google_breakpad {
103
104 namespace {
105
106 using std::vector;
107
108 // A helper class to scope a PLOADED_IMAGE.
109 class AutoImage {
110 public:
AutoImage(PLOADED_IMAGE img)111 explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
~AutoImage()112 ~AutoImage() {
113 if (img_)
114 ImageUnload(img_);
115 }
116
operator PLOADED_IMAGE()117 operator PLOADED_IMAGE() { return img_; }
operator ->()118 PLOADED_IMAGE operator->() { return img_; }
119
120 private:
121 PLOADED_IMAGE img_;
122 };
123
124 } // namespace
125
PDBSourceLineWriter()126 PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
127 }
128
~PDBSourceLineWriter()129 PDBSourceLineWriter::~PDBSourceLineWriter() {
130 }
131
SetCodeFile(const wstring & exe_file)132 bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
133 if (code_file_.empty()) {
134 code_file_ = exe_file;
135 return true;
136 }
137 // Setting a different code file path is an error. It is success only if the
138 // file paths are the same.
139 return exe_file == code_file_;
140 }
141
Open(const wstring & file,FileFormat format)142 bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
143 Close();
144 code_file_.clear();
145
146 if (FAILED(CoInitialize(NULL))) {
147 fprintf(stderr, "CoInitialize failed\n");
148 return false;
149 }
150
151 CComPtr<IDiaDataSource> data_source;
152 if (FAILED(data_source.CoCreateInstance(CLSID_DiaSource))) {
153 const int kGuidSize = 64;
154 wchar_t classid[kGuidSize] = {0};
155 StringFromGUID2(CLSID_DiaSource, classid, kGuidSize);
156 // vc80 uses bce36434-2c24-499e-bf49-8bd99b0eeb68.
157 // vc90 uses 4C41678E-887B-4365-A09E-925D28DB33C2.
158 // vc100 uses B86AE24D-BF2F-4AC9-B5A2-34B14E4CE11D.
159 fprintf(stderr, "CoCreateInstance CLSID_DiaSource %S failed "
160 "(msdia*.dll unregistered?)\n", classid);
161 return false;
162 }
163
164 switch (format) {
165 case PDB_FILE:
166 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
167 fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str());
168 return false;
169 }
170 break;
171 case EXE_FILE:
172 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
173 fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str());
174 return false;
175 }
176 code_file_ = file;
177 break;
178 case ANY_FILE:
179 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
180 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
181 fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n",
182 file.c_str());
183 return false;
184 }
185 code_file_ = file;
186 }
187 break;
188 default:
189 fprintf(stderr, "Unknown file format\n");
190 return false;
191 }
192
193 if (FAILED(data_source->openSession(&session_))) {
194 fprintf(stderr, "openSession failed\n");
195 }
196
197 return true;
198 }
199
PrintLines(IDiaEnumLineNumbers * lines)200 bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) {
201 // The line number format is:
202 // <rva> <line number> <source file id>
203 CComPtr<IDiaLineNumber> line;
204 ULONG count;
205
206 while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
207 DWORD rva;
208 if (FAILED(line->get_relativeVirtualAddress(&rva))) {
209 fprintf(stderr, "failed to get line rva\n");
210 return false;
211 }
212
213 DWORD length;
214 if (FAILED(line->get_length(&length))) {
215 fprintf(stderr, "failed to get line code length\n");
216 return false;
217 }
218
219 DWORD dia_source_id;
220 if (FAILED(line->get_sourceFileId(&dia_source_id))) {
221 fprintf(stderr, "failed to get line source file id\n");
222 return false;
223 }
224 // duplicate file names are coalesced to share one ID
225 DWORD source_id = GetRealFileID(dia_source_id);
226
227 DWORD line_num;
228 if (FAILED(line->get_lineNumber(&line_num))) {
229 fprintf(stderr, "failed to get line number\n");
230 return false;
231 }
232
233 AddressRangeVector ranges;
234 MapAddressRange(image_map_, AddressRange(rva, length), &ranges);
235 for (size_t i = 0; i < ranges.size(); ++i) {
236 fprintf(output_, "%x %x %d %d\n", ranges[i].rva, ranges[i].length,
237 line_num, source_id);
238 }
239 line.Release();
240 }
241 return true;
242 }
243
PrintFunction(IDiaSymbol * function,IDiaSymbol * block)244 bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
245 IDiaSymbol *block) {
246 // The function format is:
247 // FUNC <address> <length> <param_stack_size> <function>
248 DWORD rva;
249 if (FAILED(block->get_relativeVirtualAddress(&rva))) {
250 fprintf(stderr, "couldn't get rva\n");
251 return false;
252 }
253
254 ULONGLONG length;
255 if (FAILED(block->get_length(&length))) {
256 fprintf(stderr, "failed to get function length\n");
257 return false;
258 }
259
260 if (length == 0) {
261 // Silently ignore zero-length functions, which can infrequently pop up.
262 return true;
263 }
264
265 CComBSTR name;
266 int stack_param_size;
267 if (!GetSymbolFunctionName(function, &name, &stack_param_size)) {
268 return false;
269 }
270
271 // If the decorated name didn't give the parameter size, try to
272 // calculate it.
273 if (stack_param_size < 0) {
274 stack_param_size = GetFunctionStackParamSize(function);
275 }
276
277 AddressRangeVector ranges;
278 MapAddressRange(image_map_, AddressRange(rva, static_cast<DWORD>(length)),
279 &ranges);
280 for (size_t i = 0; i < ranges.size(); ++i) {
281 fprintf(output_, "FUNC %x %x %x %ws\n",
282 ranges[i].rva, ranges[i].length, stack_param_size, name);
283 }
284
285 CComPtr<IDiaEnumLineNumbers> lines;
286 if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) {
287 return false;
288 }
289
290 if (!PrintLines(lines)) {
291 return false;
292 }
293 return true;
294 }
295
PrintSourceFiles()296 bool PDBSourceLineWriter::PrintSourceFiles() {
297 CComPtr<IDiaSymbol> global;
298 if (FAILED(session_->get_globalScope(&global))) {
299 fprintf(stderr, "get_globalScope failed\n");
300 return false;
301 }
302
303 CComPtr<IDiaEnumSymbols> compilands;
304 if (FAILED(global->findChildren(SymTagCompiland, NULL,
305 nsNone, &compilands))) {
306 fprintf(stderr, "findChildren failed\n");
307 return false;
308 }
309
310 CComPtr<IDiaSymbol> compiland;
311 ULONG count;
312 while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
313 CComPtr<IDiaEnumSourceFiles> source_files;
314 if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) {
315 return false;
316 }
317 CComPtr<IDiaSourceFile> file;
318 while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) {
319 DWORD file_id;
320 if (FAILED(file->get_uniqueId(&file_id))) {
321 return false;
322 }
323
324 CComBSTR file_name;
325 if (FAILED(file->get_fileName(&file_name))) {
326 return false;
327 }
328
329 wstring file_name_string(file_name);
330 if (!FileIDIsCached(file_name_string)) {
331 // this is a new file name, cache it and output a FILE line.
332 CacheFileID(file_name_string, file_id);
333 fwprintf(output_, L"FILE %d %s\n", file_id, file_name);
334 } else {
335 // this file name has already been seen, just save this
336 // ID for later lookup.
337 StoreDuplicateFileID(file_name_string, file_id);
338 }
339 file.Release();
340 }
341 compiland.Release();
342 }
343 return true;
344 }
345
PrintFunctions()346 bool PDBSourceLineWriter::PrintFunctions() {
347 ULONG count = 0;
348 DWORD rva = 0;
349 CComPtr<IDiaSymbol> global;
350 HRESULT hr;
351
352 if (FAILED(session_->get_globalScope(&global))) {
353 fprintf(stderr, "get_globalScope failed\n");
354 return false;
355 }
356
357 CComPtr<IDiaEnumSymbols> symbols = NULL;
358
359 // Find all function symbols first.
360 std::set<DWORD> rvas;
361 hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols);
362
363 if (SUCCEEDED(hr)) {
364 CComPtr<IDiaSymbol> symbol = NULL;
365
366 while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
367 if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
368 // To maintain existing behavior of one symbol per address, place the
369 // rva onto a set here to uniquify them.
370 rvas.insert(rva);
371 } else {
372 fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
373 return false;
374 }
375
376 symbol.Release();
377 }
378
379 symbols.Release();
380 }
381
382 // Find all public symbols. Store public symbols that are not also private
383 // symbols for later.
384 std::set<DWORD> public_only_rvas;
385 hr = global->findChildren(SymTagPublicSymbol, NULL, nsNone, &symbols);
386
387 if (SUCCEEDED(hr)) {
388 CComPtr<IDiaSymbol> symbol = NULL;
389
390 while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
391 if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
392 if (rvas.count(rva) == 0) {
393 rvas.insert(rva); // Keep symbols in rva order.
394 public_only_rvas.insert(rva);
395 }
396 } else {
397 fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
398 return false;
399 }
400
401 symbol.Release();
402 }
403
404 symbols.Release();
405 }
406
407 std::set<DWORD>::iterator it;
408
409 // For each rva, dump the first symbol DIA knows about at the address.
410 for (it = rvas.begin(); it != rvas.end(); ++it) {
411 CComPtr<IDiaSymbol> symbol = NULL;
412 // If the symbol is not in the public list, look for SymTagFunction. This is
413 // a workaround to a bug where DIA will hang if searching for a private
414 // symbol at an address where only a public symbol exists.
415 // See http://connect.microsoft.com/VisualStudio/feedback/details/722366
416 if (public_only_rvas.count(*it) == 0) {
417 if (SUCCEEDED(session_->findSymbolByRVA(*it, SymTagFunction, &symbol))) {
418 // Sometimes findSymbolByRVA returns S_OK, but NULL.
419 if (symbol) {
420 if (!PrintFunction(symbol, symbol))
421 return false;
422 symbol.Release();
423 }
424 } else {
425 fprintf(stderr, "findSymbolByRVA SymTagFunction failed\n");
426 return false;
427 }
428 } else if (SUCCEEDED(session_->findSymbolByRVA(*it,
429 SymTagPublicSymbol,
430 &symbol))) {
431 // Sometimes findSymbolByRVA returns S_OK, but NULL.
432 if (symbol) {
433 if (!PrintCodePublicSymbol(symbol))
434 return false;
435 symbol.Release();
436 }
437 } else {
438 fprintf(stderr, "findSymbolByRVA SymTagPublicSymbol failed\n");
439 return false;
440 }
441 }
442
443 // When building with PGO, the compiler can split functions into
444 // "hot" and "cold" blocks, and move the "cold" blocks out to separate
445 // pages, so the function can be noncontiguous. To find these blocks,
446 // we have to iterate over all the compilands, and then find blocks
447 // that are children of them. We can then find the lexical parents
448 // of those blocks and print out an extra FUNC line for blocks
449 // that are not contained in their parent functions.
450 CComPtr<IDiaEnumSymbols> compilands;
451 if (FAILED(global->findChildren(SymTagCompiland, NULL,
452 nsNone, &compilands))) {
453 fprintf(stderr, "findChildren failed on the global\n");
454 return false;
455 }
456
457 CComPtr<IDiaSymbol> compiland;
458 while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
459 CComPtr<IDiaEnumSymbols> blocks;
460 if (FAILED(compiland->findChildren(SymTagBlock, NULL,
461 nsNone, &blocks))) {
462 fprintf(stderr, "findChildren failed on a compiland\n");
463 return false;
464 }
465
466 CComPtr<IDiaSymbol> block;
467 while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) {
468 // find this block's lexical parent function
469 CComPtr<IDiaSymbol> parent;
470 DWORD tag;
471 if (SUCCEEDED(block->get_lexicalParent(&parent)) &&
472 SUCCEEDED(parent->get_symTag(&tag)) &&
473 tag == SymTagFunction) {
474 // now get the block's offset and the function's offset and size,
475 // and determine if the block is outside of the function
476 DWORD func_rva, block_rva;
477 ULONGLONG func_length;
478 if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) &&
479 SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) &&
480 SUCCEEDED(parent->get_length(&func_length))) {
481 if (block_rva < func_rva || block_rva > (func_rva + func_length)) {
482 if (!PrintFunction(parent, block)) {
483 return false;
484 }
485 }
486 }
487 }
488 parent.Release();
489 block.Release();
490 }
491 blocks.Release();
492 compiland.Release();
493 }
494
495 global.Release();
496 return true;
497 }
498
499 #undef max
500
PrintFrameDataUsingPDB()501 bool PDBSourceLineWriter::PrintFrameDataUsingPDB() {
502 // It would be nice if it were possible to output frame data alongside the
503 // associated function, as is done with line numbers, but the DIA API
504 // doesn't make it possible to get the frame data in that way.
505
506 CComPtr<IDiaEnumFrameData> frame_data_enum;
507 if (!FindTable(session_, &frame_data_enum))
508 return false;
509
510 DWORD last_type = std::numeric_limits<DWORD>::max();
511 DWORD last_rva = std::numeric_limits<DWORD>::max();
512 DWORD last_code_size = 0;
513 DWORD last_prolog_size = std::numeric_limits<DWORD>::max();
514
515 CComPtr<IDiaFrameData> frame_data;
516 ULONG count = 0;
517 while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) &&
518 count == 1) {
519 DWORD type;
520 if (FAILED(frame_data->get_type(&type)))
521 return false;
522
523 DWORD rva;
524 if (FAILED(frame_data->get_relativeVirtualAddress(&rva)))
525 return false;
526
527 DWORD code_size;
528 if (FAILED(frame_data->get_lengthBlock(&code_size)))
529 return false;
530
531 DWORD prolog_size;
532 if (FAILED(frame_data->get_lengthProlog(&prolog_size)))
533 return false;
534
535 // parameter_size is the size of parameters passed on the stack. If any
536 // parameters are not passed on the stack (such as in registers), their
537 // sizes will not be included in parameter_size.
538 DWORD parameter_size;
539 if (FAILED(frame_data->get_lengthParams(¶meter_size)))
540 return false;
541
542 DWORD saved_register_size;
543 if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size)))
544 return false;
545
546 DWORD local_size;
547 if (FAILED(frame_data->get_lengthLocals(&local_size)))
548 return false;
549
550 // get_maxStack can return S_FALSE, just use 0 in that case.
551 DWORD max_stack_size = 0;
552 if (FAILED(frame_data->get_maxStack(&max_stack_size)))
553 return false;
554
555 // get_programString can return S_FALSE, indicating that there is no
556 // program string. In that case, check whether %ebp is used.
557 HRESULT program_string_result;
558 CComBSTR program_string;
559 if (FAILED(program_string_result = frame_data->get_program(
560 &program_string))) {
561 return false;
562 }
563
564 // get_allocatesBasePointer can return S_FALSE, treat that as though
565 // %ebp is not used.
566 BOOL allocates_base_pointer = FALSE;
567 if (program_string_result != S_OK) {
568 if (FAILED(frame_data->get_allocatesBasePointer(
569 &allocates_base_pointer))) {
570 return false;
571 }
572 }
573
574 // Only print out a line if type, rva, code_size, or prolog_size have
575 // changed from the last line. It is surprisingly common (especially in
576 // system library PDBs) for DIA to return a series of identical
577 // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86,
578 // this check reduces the size of the dumped symbol file by a third.
579 if (type != last_type || rva != last_rva || code_size != last_code_size ||
580 prolog_size != last_prolog_size) {
581 // The prolog and the code portions of the frame have to be treated
582 // independently as they may have independently changed in size, or may
583 // even have been split.
584 // NOTE: If epilog size is ever non-zero, we have to do something
585 // similar with it.
586
587 // Figure out where the prolog bytes have landed.
588 AddressRangeVector prolog_ranges;
589 if (prolog_size > 0) {
590 MapAddressRange(image_map_, AddressRange(rva, prolog_size),
591 &prolog_ranges);
592 }
593
594 // And figure out where the code bytes have landed.
595 AddressRangeVector code_ranges;
596 MapAddressRange(image_map_,
597 AddressRange(rva + prolog_size,
598 code_size - prolog_size),
599 &code_ranges);
600
601 struct FrameInfo {
602 DWORD rva;
603 DWORD code_size;
604 DWORD prolog_size;
605 };
606 std::vector<FrameInfo> frame_infos;
607
608 // Special case: The prolog and the code bytes remain contiguous. This is
609 // only done for compactness of the symbol file, and we could actually
610 // be outputting independent frame info for the prolog and code portions.
611 if (prolog_ranges.size() == 1 && code_ranges.size() == 1 &&
612 prolog_ranges[0].end() == code_ranges[0].rva) {
613 FrameInfo fi = { prolog_ranges[0].rva,
614 prolog_ranges[0].length + code_ranges[0].length,
615 prolog_ranges[0].length };
616 frame_infos.push_back(fi);
617 } else {
618 // Otherwise we output the prolog and code frame info independently.
619 for (size_t i = 0; i < prolog_ranges.size(); ++i) {
620 FrameInfo fi = { prolog_ranges[i].rva,
621 prolog_ranges[i].length,
622 prolog_ranges[i].length };
623 frame_infos.push_back(fi);
624 }
625 for (size_t i = 0; i < code_ranges.size(); ++i) {
626 FrameInfo fi = { code_ranges[i].rva, code_ranges[i].length, 0 };
627 frame_infos.push_back(fi);
628 }
629 }
630
631 for (size_t i = 0; i < frame_infos.size(); ++i) {
632 const FrameInfo& fi(frame_infos[i]);
633 fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ",
634 type, fi.rva, fi.code_size, fi.prolog_size,
635 0 /* epilog_size */, parameter_size, saved_register_size,
636 local_size, max_stack_size, program_string_result == S_OK);
637 if (program_string_result == S_OK) {
638 fprintf(output_, "%ws\n", program_string);
639 } else {
640 fprintf(output_, "%d\n", allocates_base_pointer);
641 }
642 }
643
644 last_type = type;
645 last_rva = rva;
646 last_code_size = code_size;
647 last_prolog_size = prolog_size;
648 }
649
650 frame_data.Release();
651 }
652
653 return true;
654 }
655
PrintFrameDataUsingEXE()656 bool PDBSourceLineWriter::PrintFrameDataUsingEXE() {
657 if (code_file_.empty() && !FindPEFile()) {
658 fprintf(stderr, "Couldn't locate EXE or DLL file.\n");
659 return false;
660 }
661
662 // Convert wchar to native charset because ImageLoad only takes
663 // a PSTR as input.
664 string code_file;
665 if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
666 return false;
667 }
668
669 AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
670 if (!img) {
671 fprintf(stderr, "Failed to load %s\n", code_file.c_str());
672 return false;
673 }
674 PIMAGE_OPTIONAL_HEADER64 optional_header =
675 &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
676 if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
677 fprintf(stderr, "Not a PE32+ image\n");
678 return false;
679 }
680
681 // Read Exception Directory
682 DWORD exception_rva = optional_header->
683 DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
684 DWORD exception_size = optional_header->
685 DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
686 PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
687 static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
688 ImageRvaToVa(img->FileHeader,
689 img->MappedAddress,
690 exception_rva,
691 &img->LastRvaSection));
692 for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
693 DWORD unwind_rva = funcs[i].UnwindInfoAddress;
694 // handle chaining
695 while (unwind_rva & 0x1) {
696 unwind_rva ^= 0x1;
697 PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
698 static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
699 ImageRvaToVa(img->FileHeader,
700 img->MappedAddress,
701 unwind_rva,
702 &img->LastRvaSection));
703 unwind_rva = chained_func->UnwindInfoAddress;
704 }
705
706 UnwindInfo *unwind_info = static_cast<UnwindInfo *>(
707 ImageRvaToVa(img->FileHeader,
708 img->MappedAddress,
709 unwind_rva,
710 &img->LastRvaSection));
711
712 DWORD stack_size = 8; // minimal stack size is 8 for RIP
713 DWORD rip_offset = 8;
714 do {
715 for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
716 UnwindCode *unwind_code = &unwind_info->unwind_code[c];
717 switch (unwind_code->unwind_operation_code) {
718 case UWOP_PUSH_NONVOL: {
719 stack_size += 8;
720 break;
721 }
722 case UWOP_ALLOC_LARGE: {
723 if (unwind_code->operation_info == 0) {
724 c++;
725 if (c < unwind_info->count_of_codes)
726 stack_size += (unwind_code + 1)->frame_offset * 8;
727 } else {
728 c += 2;
729 if (c < unwind_info->count_of_codes)
730 stack_size += (unwind_code + 1)->frame_offset |
731 ((unwind_code + 2)->frame_offset << 16);
732 }
733 break;
734 }
735 case UWOP_ALLOC_SMALL: {
736 stack_size += unwind_code->operation_info * 8 + 8;
737 break;
738 }
739 case UWOP_SET_FPREG:
740 case UWOP_SAVE_XMM:
741 case UWOP_SAVE_XMM_FAR:
742 break;
743 case UWOP_SAVE_NONVOL:
744 case UWOP_SAVE_XMM128: {
745 c++; // skip slot with offset
746 break;
747 }
748 case UWOP_SAVE_NONVOL_FAR:
749 case UWOP_SAVE_XMM128_FAR: {
750 c += 2; // skip 2 slots with offset
751 break;
752 }
753 case UWOP_PUSH_MACHFRAME: {
754 if (unwind_code->operation_info) {
755 stack_size += 88;
756 } else {
757 stack_size += 80;
758 }
759 rip_offset += 80;
760 break;
761 }
762 }
763 }
764 if (unwind_info->flags & UNW_FLAG_CHAININFO) {
765 PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
766 reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
767 (unwind_info->unwind_code +
768 ((unwind_info->count_of_codes + 1) & ~1)));
769
770 unwind_info = static_cast<UnwindInfo *>(
771 ImageRvaToVa(img->FileHeader,
772 img->MappedAddress,
773 chained_func->UnwindInfoAddress,
774 &img->LastRvaSection));
775 } else {
776 unwind_info = NULL;
777 }
778 } while (unwind_info);
779 fprintf(output_, "STACK CFI INIT %x %x .cfa: $rsp .ra: .cfa %d - ^\n",
780 funcs[i].BeginAddress,
781 funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
782 fprintf(output_, "STACK CFI %x .cfa: $rsp %d +\n",
783 funcs[i].BeginAddress, stack_size);
784 }
785
786 return true;
787 }
788
PrintFrameData()789 bool PDBSourceLineWriter::PrintFrameData() {
790 PDBModuleInfo info;
791 if (GetModuleInfo(&info) && info.cpu == L"x86_64") {
792 return PrintFrameDataUsingEXE();
793 } else {
794 return PrintFrameDataUsingPDB();
795 }
796 return false;
797 }
798
PrintCodePublicSymbol(IDiaSymbol * symbol)799 bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
800 BOOL is_code;
801 if (FAILED(symbol->get_code(&is_code))) {
802 return false;
803 }
804 if (!is_code) {
805 return true;
806 }
807
808 DWORD rva;
809 if (FAILED(symbol->get_relativeVirtualAddress(&rva))) {
810 return false;
811 }
812
813 CComBSTR name;
814 int stack_param_size;
815 if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) {
816 return false;
817 }
818
819 AddressRangeVector ranges;
820 MapAddressRange(image_map_, AddressRange(rva, 1), &ranges);
821 for (size_t i = 0; i < ranges.size(); ++i) {
822 fprintf(output_, "PUBLIC %x %x %ws\n", ranges[i].rva,
823 stack_param_size > 0 ? stack_param_size : 0, name);
824 }
825 return true;
826 }
827
PrintPDBInfo()828 bool PDBSourceLineWriter::PrintPDBInfo() {
829 PDBModuleInfo info;
830 if (!GetModuleInfo(&info)) {
831 return false;
832 }
833
834 // Hard-code "windows" for the OS because that's the only thing that makes
835 // sense for PDB files. (This might not be strictly correct for Windows CE
836 // support, but we don't care about that at the moment.)
837 fprintf(output_, "MODULE windows %ws %ws %ws\n",
838 info.cpu.c_str(), info.debug_identifier.c_str(),
839 info.debug_file.c_str());
840
841 return true;
842 }
843
PrintPEInfo()844 bool PDBSourceLineWriter::PrintPEInfo() {
845 PEModuleInfo info;
846 if (!GetPEInfo(&info)) {
847 return false;
848 }
849
850 fprintf(output_, "INFO CODE_ID %ws %ws\n",
851 info.code_identifier.c_str(),
852 info.code_file.c_str());
853 return true;
854 }
855
856 // wcstol_positive_strict is sort of like wcstol, but much stricter. string
857 // should be a buffer pointing to a null-terminated string containing only
858 // decimal digits. If the entire string can be converted to an integer
859 // without overflowing, and there are no non-digit characters before the
860 // result is set to the value and this function returns true. Otherwise,
861 // this function returns false. This is an alternative to the strtol, atoi,
862 // and scanf families, which are not as strict about input and in some cases
863 // don't provide a good way for the caller to determine if a conversion was
864 // successful.
wcstol_positive_strict(wchar_t * string,int * result)865 static bool wcstol_positive_strict(wchar_t *string, int *result) {
866 int value = 0;
867 for (wchar_t *c = string; *c != '\0'; ++c) {
868 int last_value = value;
869 value *= 10;
870 // Detect overflow.
871 if (value / 10 != last_value || value < 0) {
872 return false;
873 }
874 if (*c < '0' || *c > '9') {
875 return false;
876 }
877 unsigned int c_value = *c - '0';
878 last_value = value;
879 value += c_value;
880 // Detect overflow.
881 if (value < last_value) {
882 return false;
883 }
884 // Forbid leading zeroes unless the string is just "0".
885 if (value == 0 && *(c+1) != '\0') {
886 return false;
887 }
888 }
889 *result = value;
890 return true;
891 }
892
FindPEFile()893 bool PDBSourceLineWriter::FindPEFile() {
894 CComPtr<IDiaSymbol> global;
895 if (FAILED(session_->get_globalScope(&global))) {
896 fprintf(stderr, "get_globalScope failed\n");
897 return false;
898 }
899
900 CComBSTR symbols_file;
901 if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) {
902 wstring file(symbols_file);
903
904 // Look for an EXE or DLL file.
905 const wchar_t *extensions[] = { L"exe", L"dll" };
906 for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) {
907 size_t dot_pos = file.find_last_of(L".");
908 if (dot_pos != wstring::npos) {
909 file.replace(dot_pos + 1, wstring::npos, extensions[i]);
910 // Check if this file exists.
911 if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) {
912 code_file_ = file;
913 return true;
914 }
915 }
916 }
917 }
918
919 return false;
920 }
921
922 // static
GetSymbolFunctionName(IDiaSymbol * function,BSTR * name,int * stack_param_size)923 bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
924 BSTR *name,
925 int *stack_param_size) {
926 *stack_param_size = -1;
927 const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS |
928 UNDNAME_NO_FUNCTION_RETURNS |
929 UNDNAME_NO_ALLOCATION_MODEL |
930 UNDNAME_NO_ALLOCATION_LANGUAGE |
931 UNDNAME_NO_THISTYPE |
932 UNDNAME_NO_ACCESS_SPECIFIERS |
933 UNDNAME_NO_THROW_SIGNATURES |
934 UNDNAME_NO_MEMBER_TYPE |
935 UNDNAME_NO_RETURN_UDT_MODEL |
936 UNDNAME_NO_ECSU;
937
938 // Use get_undecoratedNameEx to get readable C++ names with arguments.
939 if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) {
940 if (function->get_name(name) != S_OK) {
941 fprintf(stderr, "failed to get function name\n");
942 return false;
943 }
944 // If a name comes from get_name because no undecorated form existed,
945 // it's already formatted properly to be used as output. Don't do any
946 // additional processing.
947 //
948 // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's.
949 // This will result in calling get_name for some C++ symbols, so
950 // all of the parameter and return type information may not be included in
951 // the name string.
952 } else {
953 // C++ uses a bogus "void" argument for functions and methods that don't
954 // take any parameters. Take it out of the undecorated name because it's
955 // ugly and unnecessary.
956 const wchar_t *replace_string = L"(void)";
957 const size_t replace_length = wcslen(replace_string);
958 const wchar_t *replacement_string = L"()";
959 size_t length = wcslen(*name);
960 if (length >= replace_length) {
961 wchar_t *name_end = *name + length - replace_length;
962 if (wcscmp(name_end, replace_string) == 0) {
963 WindowsStringUtils::safe_wcscpy(name_end, replace_length,
964 replacement_string);
965 length = wcslen(*name);
966 }
967 }
968
969 // Undecorate names used for stdcall and fastcall. These names prefix
970 // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it
971 // with '@' followed by the number of bytes of parameters, in decimal.
972 // If such a name is found, take note of the size and undecorate it.
973 // Only do this for names that aren't C++, which is determined based on
974 // whether the undecorated name contains any ':' or '(' characters.
975 if (!wcschr(*name, ':') && !wcschr(*name, '(') &&
976 (*name[0] == '_' || *name[0] == '@')) {
977 wchar_t *last_at = wcsrchr(*name + 1, '@');
978 if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) {
979 // If this function adheres to the fastcall convention, it accepts up
980 // to the first 8 bytes of parameters in registers (%ecx and %edx).
981 // We're only interested in the stack space used for parameters, so
982 // so subtract 8 and don't let the size go below 0.
983 if (*name[0] == '@') {
984 if (*stack_param_size > 8) {
985 *stack_param_size -= 8;
986 } else {
987 *stack_param_size = 0;
988 }
989 }
990
991 // Undecorate the name by moving it one character to the left in its
992 // buffer, and terminating it where the last '@' had been.
993 WindowsStringUtils::safe_wcsncpy(*name, length,
994 *name + 1, last_at - *name - 1);
995 } else if (*name[0] == '_') {
996 // This symbol's name is encoded according to the cdecl rules. The
997 // name doesn't end in a '@' character followed by a decimal positive
998 // integer, so it's not a stdcall name. Strip off the leading
999 // underscore.
1000 WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length);
1001 }
1002 }
1003 }
1004
1005 return true;
1006 }
1007
1008 // static
GetFunctionStackParamSize(IDiaSymbol * function)1009 int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) {
1010 // This implementation is highly x86-specific.
1011
1012 // Gather the symbols corresponding to data.
1013 CComPtr<IDiaEnumSymbols> data_children;
1014 if (FAILED(function->findChildren(SymTagData, NULL, nsNone,
1015 &data_children))) {
1016 return 0;
1017 }
1018
1019 // lowest_base is the lowest %ebp-relative byte offset used for a parameter.
1020 // highest_end is one greater than the highest offset (i.e. base + length).
1021 // Stack parameters are assumed to be contiguous, because in reality, they
1022 // are.
1023 int lowest_base = INT_MAX;
1024 int highest_end = INT_MIN;
1025
1026 CComPtr<IDiaSymbol> child;
1027 DWORD count;
1028 while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) {
1029 // If any operation fails at this point, just proceed to the next child.
1030 // Use the next_child label instead of continue because child needs to
1031 // be released before it's reused. Declare constructable/destructable
1032 // types early to avoid gotos that cross initializations.
1033 CComPtr<IDiaSymbol> child_type;
1034
1035 // DataIsObjectPtr is only used for |this|. Because |this| can be passed
1036 // as a stack parameter, look for it in addition to traditional
1037 // parameters.
1038 DWORD child_kind;
1039 if (FAILED(child->get_dataKind(&child_kind)) ||
1040 (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) {
1041 goto next_child;
1042 }
1043
1044 // Only concentrate on register-relative parameters. Parameters may also
1045 // be enregistered (passed directly in a register), but those don't
1046 // consume any stack space, so they're not of interest.
1047 DWORD child_location_type;
1048 if (FAILED(child->get_locationType(&child_location_type)) ||
1049 child_location_type != LocIsRegRel) {
1050 goto next_child;
1051 }
1052
1053 // Of register-relative parameters, the only ones that make any sense are
1054 // %ebp- or %esp-relative. Note that MSVC's debugging information always
1055 // gives parameters as %ebp-relative even when a function doesn't use a
1056 // traditional frame pointer and stack parameters are accessed relative to
1057 // %esp, so just look for %ebp-relative parameters. If you wanted to
1058 // access parameters, you'd probably want to treat these %ebp-relative
1059 // offsets as if they were relative to %esp before a function's prolog
1060 // executed.
1061 DWORD child_register;
1062 if (FAILED(child->get_registerId(&child_register)) ||
1063 child_register != CV_REG_EBP) {
1064 goto next_child;
1065 }
1066
1067 LONG child_register_offset;
1068 if (FAILED(child->get_offset(&child_register_offset))) {
1069 goto next_child;
1070 }
1071
1072 // IDiaSymbol::get_type can succeed but still pass back a NULL value.
1073 if (FAILED(child->get_type(&child_type)) || !child_type) {
1074 goto next_child;
1075 }
1076
1077 ULONGLONG child_length;
1078 if (FAILED(child_type->get_length(&child_length))) {
1079 goto next_child;
1080 }
1081
1082 int child_end = child_register_offset + static_cast<ULONG>(child_length);
1083 if (child_register_offset < lowest_base) {
1084 lowest_base = child_register_offset;
1085 }
1086 if (child_end > highest_end) {
1087 highest_end = child_end;
1088 }
1089
1090 next_child:
1091 child.Release();
1092 }
1093
1094 int param_size = 0;
1095 // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest
1096 // possible address to find a stack parameter before executing a function's
1097 // prolog (see above). Some optimizations cause parameter offsets to be
1098 // lower than 4, but we're not concerned with those because we're only
1099 // looking for parameters contained in addresses higher than where the
1100 // return address is stored.
1101 if (lowest_base < 4) {
1102 lowest_base = 4;
1103 }
1104 if (highest_end > lowest_base) {
1105 // All stack parameters are pushed as at least 4-byte quantities. If the
1106 // last type was narrower than 4 bytes, promote it. This assumes that all
1107 // parameters' offsets are 4-byte-aligned, which is always the case. Only
1108 // worry about the last type, because we're not summing the type sizes,
1109 // just looking at the lowest and highest offsets.
1110 int remainder = highest_end % 4;
1111 if (remainder) {
1112 highest_end += 4 - remainder;
1113 }
1114
1115 param_size = highest_end - lowest_base;
1116 }
1117
1118 return param_size;
1119 }
1120
WriteMap(FILE * map_file)1121 bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
1122 output_ = map_file;
1123
1124 // Load the OMAP information, and disable auto-translation of addresses in
1125 // preference of doing it ourselves.
1126 OmapData omap_data;
1127 if (!GetOmapDataAndDisableTranslation(session_, &omap_data))
1128 return false;
1129 BuildImageMap(omap_data, &image_map_);
1130
1131 bool ret = PrintPDBInfo();
1132 // This is not a critical piece of the symbol file.
1133 PrintPEInfo();
1134 ret = ret &&
1135 PrintSourceFiles() &&
1136 PrintFunctions() &&
1137 PrintFrameData();
1138
1139 output_ = NULL;
1140 return ret;
1141 }
1142
Close()1143 void PDBSourceLineWriter::Close() {
1144 session_.Release();
1145 }
1146
GetModuleInfo(PDBModuleInfo * info)1147 bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
1148 if (!info) {
1149 return false;
1150 }
1151
1152 info->debug_file.clear();
1153 info->debug_identifier.clear();
1154 info->cpu.clear();
1155
1156 CComPtr<IDiaSymbol> global;
1157 if (FAILED(session_->get_globalScope(&global))) {
1158 return false;
1159 }
1160
1161 DWORD machine_type;
1162 // get_machineType can return S_FALSE.
1163 if (global->get_machineType(&machine_type) == S_OK) {
1164 // The documentation claims that get_machineType returns a value from
1165 // the CV_CPU_TYPE_e enumeration, but that's not the case.
1166 // Instead, it returns one of the IMAGE_FILE_MACHINE values as
1167 // defined here:
1168 // http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx
1169 switch (machine_type) {
1170 case IMAGE_FILE_MACHINE_I386:
1171 info->cpu = L"x86";
1172 break;
1173 case IMAGE_FILE_MACHINE_AMD64:
1174 info->cpu = L"x86_64";
1175 break;
1176 default:
1177 info->cpu = L"unknown";
1178 break;
1179 }
1180 } else {
1181 // Unexpected, but handle gracefully.
1182 info->cpu = L"unknown";
1183 }
1184
1185 // DWORD* and int* are not compatible. This is clean and avoids a cast.
1186 DWORD age;
1187 if (FAILED(global->get_age(&age))) {
1188 return false;
1189 }
1190
1191 bool uses_guid;
1192 if (!UsesGUID(&uses_guid)) {
1193 return false;
1194 }
1195
1196 if (uses_guid) {
1197 GUID guid;
1198 if (FAILED(global->get_guid(&guid))) {
1199 return false;
1200 }
1201
1202 // Use the same format that the MS symbol server uses in filesystem
1203 // hierarchies.
1204 wchar_t age_string[9];
1205 swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
1206 L"%x", age);
1207
1208 // remove when VC++7.1 is no longer supported
1209 age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
1210
1211 info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid);
1212 info->debug_identifier.append(age_string);
1213 } else {
1214 DWORD signature;
1215 if (FAILED(global->get_signature(&signature))) {
1216 return false;
1217 }
1218
1219 // Use the same format that the MS symbol server uses in filesystem
1220 // hierarchies.
1221 wchar_t identifier_string[17];
1222 swprintf(identifier_string,
1223 sizeof(identifier_string) / sizeof(identifier_string[0]),
1224 L"%08X%x", signature, age);
1225
1226 // remove when VC++7.1 is no longer supported
1227 identifier_string[sizeof(identifier_string) /
1228 sizeof(identifier_string[0]) - 1] = L'\0';
1229
1230 info->debug_identifier = identifier_string;
1231 }
1232
1233 CComBSTR debug_file_string;
1234 if (FAILED(global->get_symbolsFileName(&debug_file_string))) {
1235 return false;
1236 }
1237 info->debug_file =
1238 WindowsStringUtils::GetBaseName(wstring(debug_file_string));
1239
1240 return true;
1241 }
1242
GetPEInfo(PEModuleInfo * info)1243 bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
1244 if (!info) {
1245 return false;
1246 }
1247
1248 if (code_file_.empty() && !FindPEFile()) {
1249 fprintf(stderr, "Couldn't locate EXE or DLL file.\n");
1250 return false;
1251 }
1252
1253 // Convert wchar to native charset because ImageLoad only takes
1254 // a PSTR as input.
1255 string code_file;
1256 if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
1257 return false;
1258 }
1259
1260 AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
1261 if (!img) {
1262 fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str());
1263 return false;
1264 }
1265
1266 info->code_file = WindowsStringUtils::GetBaseName(code_file_);
1267
1268 // The date and time that the file was created by the linker.
1269 DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
1270 // The size of the file in bytes, including all headers.
1271 DWORD SizeOfImage = 0;
1272 PIMAGE_OPTIONAL_HEADER64 opt =
1273 &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
1274 if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1275 // 64-bit PE file.
1276 SizeOfImage = opt->SizeOfImage;
1277 } else {
1278 // 32-bit PE file.
1279 SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
1280 }
1281 wchar_t code_identifier[32];
1282 swprintf(code_identifier,
1283 sizeof(code_identifier) / sizeof(code_identifier[0]),
1284 L"%08X%X", TimeDateStamp, SizeOfImage);
1285 info->code_identifier = code_identifier;
1286
1287 return true;
1288 }
1289
UsesGUID(bool * uses_guid)1290 bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
1291 if (!uses_guid)
1292 return false;
1293
1294 CComPtr<IDiaSymbol> global;
1295 if (FAILED(session_->get_globalScope(&global)))
1296 return false;
1297
1298 GUID guid;
1299 if (FAILED(global->get_guid(&guid)))
1300 return false;
1301
1302 DWORD signature;
1303 if (FAILED(global->get_signature(&signature)))
1304 return false;
1305
1306 // There are two possibilities for guid: either it's a real 128-bit GUID
1307 // as identified in a code module by a new-style CodeView record, or it's
1308 // a 32-bit signature (timestamp) as identified by an old-style record.
1309 // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h.
1310 //
1311 // Because DIA doesn't provide a way to directly determine whether a module
1312 // uses a GUID or a 32-bit signature, this code checks whether the first 32
1313 // bits of guid are the same as the signature, and if the rest of guid is
1314 // zero. If so, then with a pretty high degree of certainty, there's an
1315 // old-style CodeView record in use. This method will only falsely find an
1316 // an old-style CodeView record if a real 128-bit GUID has its first 32
1317 // bits set the same as the module's signature (timestamp) and the rest of
1318 // the GUID is set to 0. This is highly unlikely.
1319
1320 GUID signature_guid = {signature}; // 0-initializes other members
1321 *uses_guid = !IsEqualGUID(guid, signature_guid);
1322 return true;
1323 }
1324
1325 } // namespace google_breakpad
1326