• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&parameter_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