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 */
57typedef 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
65union 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
74enum 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.
92struct 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
102namespace google_breakpad {
103
104namespace {
105
106using std::vector;
107
108// A helper class to scope a PLOADED_IMAGE.
109class AutoImage {
110 public:
111  explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
112  ~AutoImage() {
113    if (img_)
114      ImageUnload(img_);
115  }
116
117  operator PLOADED_IMAGE() { return img_; }
118  PLOADED_IMAGE operator->() { return img_; }
119
120 private:
121  PLOADED_IMAGE img_;
122};
123
124}  // namespace
125
126PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
127}
128
129PDBSourceLineWriter::~PDBSourceLineWriter() {
130}
131
132bool 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
142bool 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
200bool 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
244bool 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
296bool 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
346bool 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
501bool 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
656bool 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
789bool 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
799bool 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
828bool 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
844bool 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.
865static 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
893bool 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
923bool 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
1009int 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
1090next_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
1121bool 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
1143void PDBSourceLineWriter::Close() {
1144  session_.Release();
1145}
1146
1147bool 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
1243bool 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
1290bool 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