17daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// Copyright (c) 2006, Google Inc.
27daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// All rights reserved.
3cb91a2f879250f2ef5f74321b5d08807247d41a7bryner//
47daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// Redistribution and use in source and binary forms, with or without
57daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// modification, are permitted provided that the following conditions are
67daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// met:
7cb91a2f879250f2ef5f74321b5d08807247d41a7bryner//
87daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai//     * Redistributions of source code must retain the above copyright
97daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// notice, this list of conditions and the following disclaimer.
107daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai//     * Redistributions in binary form must reproduce the above
117daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// copyright notice, this list of conditions and the following disclaimer
127daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// in the documentation and/or other materials provided with the
137daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// distribution.
147daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai//     * Neither the name of Google Inc. nor the names of its
157daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// contributors may be used to endorse or promote products derived from
167daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// this software without specific prior written permission.
17cb91a2f879250f2ef5f74321b5d08807247d41a7bryner//
187daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
197daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
207daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
217daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
227daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
237daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
247daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
257daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
267daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
277daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
287daf246e4baf0837e25429668cc23e92b6afe3b3mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
3085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org#include "common/windows/pdb_source_line_writer.h"
3185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
3285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org#include <windows.h>
3385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org#include <winnt.h>
34cb91a2f879250f2ef5f74321b5d08807247d41a7bryner#include <atlbase.h>
3529401d2457120b6d581affdb440017433ca93e77mmentovai#include <dia2.h>
36d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek#include <ImageHlp.h>
3729401d2457120b6d581affdb440017433ca93e77mmentovai#include <stdio.h>
3829401d2457120b6d581affdb440017433ca93e77mmentovai
396e3d661e0d84c4b75e0b1e9c320f7f61aad19bf0thestig@chromium.org#include <limits>
40d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org#include <set>
416e3d661e0d84c4b75e0b1e9c320f7f61aad19bf0thestig@chromium.org
4285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org#include "common/windows/dia_util.h"
4329401d2457120b6d581affdb440017433ca93e77mmentovai#include "common/windows/guid_string.h"
4485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org#include "common/windows/string_utils-inl.h"
45cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
46246f4068280b5b191303ff13671e43a0522987demmentovai// This constant may be missing from DbgHelp.h.  See the documentation for
47246f4068280b5b191303ff13671e43a0522987demmentovai// IDiaSymbol::get_undecoratedNameEx.
48246f4068280b5b191303ff13671e43a0522987demmentovai#ifndef UNDNAME_NO_ECSU
49246f4068280b5b191303ff13671e43a0522987demmentovai#define UNDNAME_NO_ECSU 0x8000  // Suppresses enum/class/struct/union.
50246f4068280b5b191303ff13671e43a0522987demmentovai#endif  // UNDNAME_NO_ECSU
51246f4068280b5b191303ff13671e43a0522987demmentovai
52dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org/*
53dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org * Not defined in WinNT.h for some reason. Definitions taken from:
54dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org * http://uninformed.org/index.cgi?v=4&a=1&p=13
55dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org *
56dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org */
57dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.orgtypedef unsigned char UBYTE;
58d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
59d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org#if !defined(_WIN64)
60dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org#define UNW_FLAG_EHANDLER  0x01
61dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org#define UNW_FLAG_UHANDLER  0x02
62dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org#define UNW_FLAG_CHAININFO 0x04
63d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org#endif
64dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
65dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.orgunion UnwindCode {
66dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  struct {
67dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    UBYTE offset_in_prolog;
68dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    UBYTE unwind_operation_code : 4;
69dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    UBYTE operation_info        : 4;
70dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  };
71dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  USHORT frame_offset;
72dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org};
73dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
74dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.orgenum UnwindOperationCodes {
75dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_PUSH_NONVOL = 0, /* info == register number */
76dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_ALLOC_LARGE,     /* no info, alloc size in next 2 slots */
77dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_ALLOC_SMALL,     /* info == size of allocation / 8 - 1 */
78dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_SET_FPREG,       /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
79dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_SAVE_NONVOL,     /* info == register number, offset in next slot */
80dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
810a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // XXX: these are missing from MSDN!
82dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
83dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_SAVE_XMM,
84dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_SAVE_XMM_FAR,
85dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_SAVE_XMM128,     /* info == XMM reg number, offset in next slot */
86dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
87dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UWOP_PUSH_MACHFRAME   /* info == 0: no error-code, 1: error-code */
88dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org};
89dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
90dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
91dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org// Note: some fields removed as we don't use them.
92dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.orgstruct UnwindInfo {
93dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UBYTE version       : 3;
94dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UBYTE flags         : 5;
95dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UBYTE size_of_prolog;
96dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UBYTE count_of_codes;
97dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UBYTE frame_register : 4;
98dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UBYTE frame_offset   : 4;
99dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  UnwindCode unwind_code[1];
100dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org};
101dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
102e5dc60822e5938fea2ae892ccddb906641ba174emmentovainamespace google_breakpad {
103cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
10485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.orgnamespace {
10585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
106d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarekusing std::vector;
107d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
108d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek// A helper class to scope a PLOADED_IMAGE.
109d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarekclass AutoImage {
110d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek public:
111d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
112d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  ~AutoImage() {
113d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    if (img_)
114d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek      ImageUnload(img_);
115d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
116d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
117d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  operator PLOADED_IMAGE() { return img_; }
118d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  PLOADED_IMAGE operator->() { return img_; }
119d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
120d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek private:
121d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  PLOADED_IMAGE img_;
122d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek};
123d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
12485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org}  // namespace
12585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
126cb91a2f879250f2ef5f74321b5d08807247d41a7brynerPDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
127cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
128cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
129cb91a2f879250f2ef5f74321b5d08807247d41a7brynerPDBSourceLineWriter::~PDBSourceLineWriter() {
130cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
131cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
1320a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.combool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
1330a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  if (code_file_.empty()) {
1340a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    code_file_ = exe_file;
1350a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    return true;
1360a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  }
1370a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // Setting a different code file path is an error.  It is success only if the
1380a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // file paths are the same.
1390a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  return exe_file == code_file_;
1400a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com}
1410a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
1428b1645d8cdb34035c0b132fe8b574bc5ee48fb62brynerbool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
143cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  Close();
1440a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  code_file_.clear();
145cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
146cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  if (FAILED(CoInitialize(NULL))) {
147cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    fprintf(stderr, "CoInitialize failed\n");
148cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
149cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
150cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
151cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  CComPtr<IDiaDataSource> data_source;
152cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  if (FAILED(data_source.CoCreateInstance(CLSID_DiaSource))) {
15304023b1f6a249a01c0a392db2cf5964dfa4067e2vitalybuka@chromium.org    const int kGuidSize = 64;
15404023b1f6a249a01c0a392db2cf5964dfa4067e2vitalybuka@chromium.org    wchar_t classid[kGuidSize] = {0};
15504023b1f6a249a01c0a392db2cf5964dfa4067e2vitalybuka@chromium.org    StringFromGUID2(CLSID_DiaSource, classid, kGuidSize);
15604023b1f6a249a01c0a392db2cf5964dfa4067e2vitalybuka@chromium.org    // vc80 uses bce36434-2c24-499e-bf49-8bd99b0eeb68.
15704023b1f6a249a01c0a392db2cf5964dfa4067e2vitalybuka@chromium.org    // vc90 uses 4C41678E-887B-4365-A09E-925D28DB33C2.
1580a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    // vc100 uses B86AE24D-BF2F-4AC9-B5A2-34B14E4CE11D.
15904023b1f6a249a01c0a392db2cf5964dfa4067e2vitalybuka@chromium.org    fprintf(stderr, "CoCreateInstance CLSID_DiaSource %S failed "
16004023b1f6a249a01c0a392db2cf5964dfa4067e2vitalybuka@chromium.org            "(msdia*.dll unregistered?)\n", classid);
161cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
162cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
163cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
1648b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner  switch (format) {
1658b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner    case PDB_FILE:
1668b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
167bce1bcc55e0363b9f22e862baf3626af667d5a72ted.mielczarek        fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str());
1688b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner        return false;
1698b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      }
1708b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      break;
1718b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner    case EXE_FILE:
1728b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
173bce1bcc55e0363b9f22e862baf3626af667d5a72ted.mielczarek        fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str());
1748b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner        return false;
1758b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      }
176d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek      code_file_ = file;
1778b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      break;
17880866e79454cefc5570b01dbb0a723185eae653cmmentovai    case ANY_FILE:
17980866e79454cefc5570b01dbb0a723185eae653cmmentovai      if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
18080866e79454cefc5570b01dbb0a723185eae653cmmentovai        if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
1810a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com          fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n",
1820a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                  file.c_str());
18380866e79454cefc5570b01dbb0a723185eae653cmmentovai          return false;
18480866e79454cefc5570b01dbb0a723185eae653cmmentovai        }
18585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        code_file_ = file;
18680866e79454cefc5570b01dbb0a723185eae653cmmentovai      }
18780866e79454cefc5570b01dbb0a723185eae653cmmentovai      break;
1888b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner    default:
1898b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      fprintf(stderr, "Unknown file format\n");
1908b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner      return false;
191cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
192cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
193cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  if (FAILED(data_source->openSession(&session_))) {
194cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    fprintf(stderr, "openSession failed\n");
195cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
196cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
197cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  return true;
198cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
199cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
200cb91a2f879250f2ef5f74321b5d08807247d41a7brynerbool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) {
201cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  // The line number format is:
202cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  // <rva> <line number> <source file id>
203cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  CComPtr<IDiaLineNumber> line;
204cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  ULONG count;
205cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
206cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
207cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    DWORD rva;
208cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    if (FAILED(line->get_relativeVirtualAddress(&rva))) {
209cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      fprintf(stderr, "failed to get line rva\n");
210cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      return false;
211cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    }
212cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
213cb9fd5b773b25473770b5ddda53b0a2e9f4c7703mmentovai    DWORD length;
214cb9fd5b773b25473770b5ddda53b0a2e9f4c7703mmentovai    if (FAILED(line->get_length(&length))) {
215cb9fd5b773b25473770b5ddda53b0a2e9f4c7703mmentovai      fprintf(stderr, "failed to get line code length\n");
216cb9fd5b773b25473770b5ddda53b0a2e9f4c7703mmentovai      return false;
217cb9fd5b773b25473770b5ddda53b0a2e9f4c7703mmentovai    }
218cb9fd5b773b25473770b5ddda53b0a2e9f4c7703mmentovai
219873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek    DWORD dia_source_id;
220873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek    if (FAILED(line->get_sourceFileId(&dia_source_id))) {
221cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      fprintf(stderr, "failed to get line source file id\n");
222cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      return false;
223cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    }
224873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek    // duplicate file names are coalesced to share one ID
225873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek    DWORD source_id = GetRealFileID(dia_source_id);
226cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
227cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    DWORD line_num;
228cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    if (FAILED(line->get_lineNumber(&line_num))) {
229cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      fprintf(stderr, "failed to get line number\n");
230cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      return false;
231cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    }
232cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
23385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org    AddressRangeVector ranges;
23485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org    MapAddressRange(image_map_, AddressRange(rva, length), &ranges);
23585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org    for (size_t i = 0; i < ranges.size(); ++i) {
23685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      fprintf(output_, "%x %x %d %d\n", ranges[i].rva, ranges[i].length,
23785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org              line_num, source_id);
23885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org    }
239cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    line.Release();
240cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
241cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  return true;
242cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
243cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
244927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarekbool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
245927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek                                        IDiaSymbol *block) {
246cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  // The function format is:
247246f4068280b5b191303ff13671e43a0522987demmentovai  // FUNC <address> <length> <param_stack_size> <function>
248246f4068280b5b191303ff13671e43a0522987demmentovai  DWORD rva;
249927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  if (FAILED(block->get_relativeVirtualAddress(&rva))) {
250246f4068280b5b191303ff13671e43a0522987demmentovai    fprintf(stderr, "couldn't get rva\n");
251cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
252cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
253cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
254cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  ULONGLONG length;
255927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  if (FAILED(block->get_length(&length))) {
256cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    fprintf(stderr, "failed to get function length\n");
257cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
258cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
259cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
2606bc866cc82cdf0ca37f6467f970413c2d2577d45mmentovai  if (length == 0) {
2616bc866cc82cdf0ca37f6467f970413c2d2577d45mmentovai    // Silently ignore zero-length functions, which can infrequently pop up.
2626bc866cc82cdf0ca37f6467f970413c2d2577d45mmentovai    return true;
2636bc866cc82cdf0ca37f6467f970413c2d2577d45mmentovai  }
2646bc866cc82cdf0ca37f6467f970413c2d2577d45mmentovai
265246f4068280b5b191303ff13671e43a0522987demmentovai  CComBSTR name;
266246f4068280b5b191303ff13671e43a0522987demmentovai  int stack_param_size;
267246f4068280b5b191303ff13671e43a0522987demmentovai  if (!GetSymbolFunctionName(function, &name, &stack_param_size)) {
268cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
269cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
270cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
271246f4068280b5b191303ff13671e43a0522987demmentovai  // If the decorated name didn't give the parameter size, try to
272246f4068280b5b191303ff13671e43a0522987demmentovai  // calculate it.
273246f4068280b5b191303ff13671e43a0522987demmentovai  if (stack_param_size < 0) {
274246f4068280b5b191303ff13671e43a0522987demmentovai    stack_param_size = GetFunctionStackParamSize(function);
275246f4068280b5b191303ff13671e43a0522987demmentovai  }
276246f4068280b5b191303ff13671e43a0522987demmentovai
27785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  AddressRangeVector ranges;
27885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  MapAddressRange(image_map_, AddressRange(rva, static_cast<DWORD>(length)),
27985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                  &ranges);
28085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  for (size_t i = 0; i < ranges.size(); ++i) {
28185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org    fprintf(output_, "FUNC %x %x %x %ws\n",
28285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org            ranges[i].rva, ranges[i].length, stack_param_size, name);
28385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  }
284246f4068280b5b191303ff13671e43a0522987demmentovai
285cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  CComPtr<IDiaEnumLineNumbers> lines;
286cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) {
287cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
288cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
289cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
290cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  if (!PrintLines(lines)) {
291cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
292cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
293cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  return true;
294cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
295cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
296cb91a2f879250f2ef5f74321b5d08807247d41a7brynerbool PDBSourceLineWriter::PrintSourceFiles() {
297cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  CComPtr<IDiaSymbol> global;
298cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  if (FAILED(session_->get_globalScope(&global))) {
299cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    fprintf(stderr, "get_globalScope failed\n");
300cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
301cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
302cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
303cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  CComPtr<IDiaEnumSymbols> compilands;
304cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  if (FAILED(global->findChildren(SymTagCompiland, NULL,
305cb91a2f879250f2ef5f74321b5d08807247d41a7bryner                                  nsNone, &compilands))) {
306cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    fprintf(stderr, "findChildren failed\n");
307cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
308cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
309cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
310cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  CComPtr<IDiaSymbol> compiland;
311cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  ULONG count;
312cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
313cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    CComPtr<IDiaEnumSourceFiles> source_files;
314cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) {
315cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      return false;
316cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    }
317cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    CComPtr<IDiaSourceFile> file;
318cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) {
319cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      DWORD file_id;
320cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      if (FAILED(file->get_uniqueId(&file_id))) {
321cb91a2f879250f2ef5f74321b5d08807247d41a7bryner        return false;
322cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      }
323cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
324cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      CComBSTR file_name;
325cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      if (FAILED(file->get_fileName(&file_name))) {
326cb91a2f879250f2ef5f74321b5d08807247d41a7bryner        return false;
327cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      }
328cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
329873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek      wstring file_name_string(file_name);
330873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek      if (!FileIDIsCached(file_name_string)) {
331873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek        // this is a new file name, cache it and output a FILE line.
332873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek        CacheFileID(file_name_string, file_id);
333873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek        fwprintf(output_, L"FILE %d %s\n", file_id, file_name);
334873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek      } else {
335873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek        // this file name has already been seen, just save this
336873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek        // ID for later lookup.
337873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek        StoreDuplicateFileID(file_name_string, file_id);
338873064894b391181b8e7afb503ffc65b6b28a423ted.mielczarek      }
339cb91a2f879250f2ef5f74321b5d08807247d41a7bryner      file.Release();
340cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    }
341cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    compiland.Release();
342cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
343cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  return true;
344cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
345cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
346cb91a2f879250f2ef5f74321b5d08807247d41a7brynerbool PDBSourceLineWriter::PrintFunctions() {
347d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  ULONG count = 0;
348d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  DWORD rva = 0;
349d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  CComPtr<IDiaSymbol> global;
350d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  HRESULT hr;
351cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
352d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  if (FAILED(session_->get_globalScope(&global))) {
353d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    fprintf(stderr, "get_globalScope failed\n");
354cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    return false;
355cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  }
356cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
357d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  CComPtr<IDiaEnumSymbols> symbols = NULL;
358cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
359e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  // Find all function symbols first.
360e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  std::set<DWORD> rvas;
361e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols);
362246f4068280b5b191303ff13671e43a0522987demmentovai
363d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  if (SUCCEEDED(hr)) {
364d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    CComPtr<IDiaSymbol> symbol = NULL;
365d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
366d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
367e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
368e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        // To maintain existing behavior of one symbol per address, place the
369e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        // rva onto a set here to uniquify them.
370e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        rvas.insert(rva);
371e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      } else {
372e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
373cb91a2f879250f2ef5f74321b5d08807247d41a7bryner        return false;
374e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      }
375e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org
376d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org      symbol.Release();
377d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    }
378d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
379d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    symbols.Release();
380d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  }
381d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
382e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  // Find all public symbols.  Store public symbols that are not also private
383e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  // symbols for later.
384e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  std::set<DWORD> public_only_rvas;
385e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  hr = global->findChildren(SymTagPublicSymbol, NULL, nsNone, &symbols);
386d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
387d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  if (SUCCEEDED(hr)) {
388d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    CComPtr<IDiaSymbol> symbol = NULL;
389d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
390d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
391d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org      if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
392d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org        if (rvas.count(rva) == 0) {
393e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org          rvas.insert(rva); // Keep symbols in rva order.
394e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org          public_only_rvas.insert(rva);
395d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org        }
396d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org      } else {
397d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org        fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
398246f4068280b5b191303ff13671e43a0522987demmentovai        return false;
399246f4068280b5b191303ff13671e43a0522987demmentovai      }
400d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
401d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org      symbol.Release();
402cb91a2f879250f2ef5f74321b5d08807247d41a7bryner    }
403d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org
404d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org    symbols.Release();
405d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  }
406cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
407e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  std::set<DWORD>::iterator it;
408e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org
409e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  // For each rva, dump the first symbol DIA knows about at the address.
410e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  for (it = rvas.begin(); it != rvas.end(); ++it) {
411e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    CComPtr<IDiaSymbol> symbol = NULL;
412e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    // If the symbol is not in the public list, look for SymTagFunction. This is
413e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    // a workaround to a bug where DIA will hang if searching for a private
414e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    // symbol at an address where only a public symbol exists.
415e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    // See http://connect.microsoft.com/VisualStudio/feedback/details/722366
416e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    if (public_only_rvas.count(*it) == 0) {
417e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      if (SUCCEEDED(session_->findSymbolByRVA(*it, SymTagFunction, &symbol))) {
418e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        // Sometimes findSymbolByRVA returns S_OK, but NULL.
419e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        if (symbol) {
420e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org          if (!PrintFunction(symbol, symbol))
421e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org            return false;
422e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org          symbol.Release();
423e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        }
424e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      } else {
425e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        fprintf(stderr, "findSymbolByRVA SymTagFunction failed\n");
426e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        return false;
427e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      }
428e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    } else if (SUCCEEDED(session_->findSymbolByRVA(*it,
429e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org                                                   SymTagPublicSymbol,
430e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org                                                   &symbol))) {
431e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      // Sometimes findSymbolByRVA returns S_OK, but NULL.
432e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      if (symbol) {
433e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        if (!PrintCodePublicSymbol(symbol))
434e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org          return false;
435e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org        symbol.Release();
436e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      }
437e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    } else {
438e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      fprintf(stderr, "findSymbolByRVA SymTagPublicSymbol failed\n");
439e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org      return false;
440e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org    }
441e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org  }
442e39b745b13ccf0b9e0619da2d599a5018a2f531awfh@chromium.org
443927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  // When building with PGO, the compiler can split functions into
444927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  // "hot" and "cold" blocks, and move the "cold" blocks out to separate
445927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  // pages, so the function can be noncontiguous. To find these blocks,
446927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  // we have to iterate over all the compilands, and then find blocks
447927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  // that are children of them. We can then find the lexical parents
448927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  // of those blocks and print out an extra FUNC line for blocks
449927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  // that are not contained in their parent functions.
450927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  CComPtr<IDiaEnumSymbols> compilands;
451927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  if (FAILED(global->findChildren(SymTagCompiland, NULL,
452927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek                                  nsNone, &compilands))) {
453927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    fprintf(stderr, "findChildren failed on the global\n");
454927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    return false;
455927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  }
456927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek
457927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  CComPtr<IDiaSymbol> compiland;
458927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
459927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    CComPtr<IDiaEnumSymbols> blocks;
460927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    if (FAILED(compiland->findChildren(SymTagBlock, NULL,
461927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek                                       nsNone, &blocks))) {
462927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      fprintf(stderr, "findChildren failed on a compiland\n");
463927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      return false;
464927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    }
465927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek
466927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    CComPtr<IDiaSymbol> block;
467927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) {
468927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      // find this block's lexical parent function
469927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      CComPtr<IDiaSymbol> parent;
470927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      DWORD tag;
471927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      if (SUCCEEDED(block->get_lexicalParent(&parent)) &&
472927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek          SUCCEEDED(parent->get_symTag(&tag)) &&
473927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek          tag == SymTagFunction) {
474927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek        // now get the block's offset and the function's offset and size,
475927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek        // and determine if the block is outside of the function
476927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek        DWORD func_rva, block_rva;
477927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek        ULONGLONG func_length;
478927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek        if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) &&
479927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek            SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) &&
480927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek            SUCCEEDED(parent->get_length(&func_length))) {
481927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek          if (block_rva < func_rva || block_rva > (func_rva + func_length)) {
482927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek            if (!PrintFunction(parent, block)) {
483927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek              return false;
484927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek            }
485927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek          }
486927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek        }
487927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      }
488927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      parent.Release();
489927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek      block.Release();
490927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    }
491927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    blocks.Release();
492927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek    compiland.Release();
493927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek  }
494927cc8fa2a8300ba96e624d66bb93e6026c76512ted.mielczarek
495d8b5964d62186c00ea958ebb0eab84a3924c3546wfh@chromium.org  global.Release();
496cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  return true;
497cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
498cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
499c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#undef max
500c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org
501dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.orgbool PDBSourceLineWriter::PrintFrameDataUsingPDB() {
502fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  // It would be nice if it were possible to output frame data alongside the
503fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  // associated function, as is done with line numbers, but the DIA API
504fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  // doesn't make it possible to get the frame data in that way.
505fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
506fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  CComPtr<IDiaEnumFrameData> frame_data_enum;
50785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  if (!FindTable(session_, &frame_data_enum))
508fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    return false;
509fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
5105bfd952ff6a4b595e90ea0d2d4f5e163af330dbathestig@chromium.org  DWORD last_type = std::numeric_limits<DWORD>::max();
5115bfd952ff6a4b595e90ea0d2d4f5e163af330dbathestig@chromium.org  DWORD last_rva = std::numeric_limits<DWORD>::max();
5124365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  DWORD last_code_size = 0;
5135bfd952ff6a4b595e90ea0d2d4f5e163af330dbathestig@chromium.org  DWORD last_prolog_size = std::numeric_limits<DWORD>::max();
5144365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
515fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  CComPtr<IDiaFrameData> frame_data;
51685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  ULONG count = 0;
517fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) &&
518fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai         count == 1) {
519fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    DWORD type;
520fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_type(&type)))
521fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
522fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
523fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    DWORD rva;
524fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_relativeVirtualAddress(&rva)))
525fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
526fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
527fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    DWORD code_size;
528fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_lengthBlock(&code_size)))
529fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
530fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
531fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    DWORD prolog_size;
532fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_lengthProlog(&prolog_size)))
533fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
534fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
535246f4068280b5b191303ff13671e43a0522987demmentovai    // parameter_size is the size of parameters passed on the stack.  If any
536246f4068280b5b191303ff13671e43a0522987demmentovai    // parameters are not passed on the stack (such as in registers), their
537246f4068280b5b191303ff13671e43a0522987demmentovai    // sizes will not be included in parameter_size.
538fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    DWORD parameter_size;
539fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_lengthParams(&parameter_size)))
540fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
541fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
542fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    DWORD saved_register_size;
543fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size)))
544fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
545fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
546fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    DWORD local_size;
547fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_lengthLocals(&local_size)))
548fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
549fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
550246f4068280b5b191303ff13671e43a0522987demmentovai    // get_maxStack can return S_FALSE, just use 0 in that case.
551246f4068280b5b191303ff13671e43a0522987demmentovai    DWORD max_stack_size = 0;
552fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    if (FAILED(frame_data->get_maxStack(&max_stack_size)))
553fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
554fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
555246f4068280b5b191303ff13671e43a0522987demmentovai    // get_programString can return S_FALSE, indicating that there is no
556246f4068280b5b191303ff13671e43a0522987demmentovai    // program string.  In that case, check whether %ebp is used.
557246f4068280b5b191303ff13671e43a0522987demmentovai    HRESULT program_string_result;
558246f4068280b5b191303ff13671e43a0522987demmentovai    CComBSTR program_string;
559246f4068280b5b191303ff13671e43a0522987demmentovai    if (FAILED(program_string_result = frame_data->get_program(
560246f4068280b5b191303ff13671e43a0522987demmentovai        &program_string))) {
561fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai      return false;
562246f4068280b5b191303ff13671e43a0522987demmentovai    }
563246f4068280b5b191303ff13671e43a0522987demmentovai
564246f4068280b5b191303ff13671e43a0522987demmentovai    // get_allocatesBasePointer can return S_FALSE, treat that as though
565246f4068280b5b191303ff13671e43a0522987demmentovai    // %ebp is not used.
566246f4068280b5b191303ff13671e43a0522987demmentovai    BOOL allocates_base_pointer = FALSE;
567246f4068280b5b191303ff13671e43a0522987demmentovai    if (program_string_result != S_OK) {
568246f4068280b5b191303ff13671e43a0522987demmentovai      if (FAILED(frame_data->get_allocatesBasePointer(
569246f4068280b5b191303ff13671e43a0522987demmentovai          &allocates_base_pointer))) {
570246f4068280b5b191303ff13671e43a0522987demmentovai        return false;
571246f4068280b5b191303ff13671e43a0522987demmentovai      }
572246f4068280b5b191303ff13671e43a0522987demmentovai    }
573fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
5744365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    // Only print out a line if type, rva, code_size, or prolog_size have
5754365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    // changed from the last line.  It is surprisingly common (especially in
5764365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    // system library PDBs) for DIA to return a series of identical
5774365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    // IDiaFrameData objects.  For kernel32.pdb from Windows XP SP2 on x86,
5784365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    // this check reduces the size of the dumped symbol file by a third.
5794365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    if (type != last_type || rva != last_rva || code_size != last_code_size ||
5804365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai        prolog_size != last_prolog_size) {
58185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // The prolog and the code portions of the frame have to be treated
58285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // independently as they may have independently changed in size, or may
58385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // even have been split.
58485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // NOTE: If epilog size is ever non-zero, we have to do something
58585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      //     similar with it.
58685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
58785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // Figure out where the prolog bytes have landed.
58885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      AddressRangeVector prolog_ranges;
58985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      if (prolog_size > 0) {
59085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        MapAddressRange(image_map_, AddressRange(rva, prolog_size),
59185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                        &prolog_ranges);
59285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      }
59385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
59485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // And figure out where the code bytes have landed.
59585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      AddressRangeVector code_ranges;
59685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      MapAddressRange(image_map_,
59785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                      AddressRange(rva + prolog_size,
59885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                                   code_size - prolog_size),
59985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                      &code_ranges);
60085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
60185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      struct FrameInfo {
60285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        DWORD rva;
60385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        DWORD code_size;
60485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        DWORD prolog_size;
60585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      };
60685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      std::vector<FrameInfo> frame_infos;
60785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
60885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // Special case: The prolog and the code bytes remain contiguous. This is
60985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // only done for compactness of the symbol file, and we could actually
61085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      // be outputting independent frame info for the prolog and code portions.
61185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      if (prolog_ranges.size() == 1 && code_ranges.size() == 1 &&
61285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          prolog_ranges[0].end() == code_ranges[0].rva) {
61385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        FrameInfo fi = { prolog_ranges[0].rva,
61485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                         prolog_ranges[0].length + code_ranges[0].length,
61585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                         prolog_ranges[0].length };
61685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        frame_infos.push_back(fi);
6174365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      } else {
61885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        // Otherwise we output the prolog and code frame info independently.
61985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        for (size_t i = 0; i < prolog_ranges.size(); ++i) {
62085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          FrameInfo fi = { prolog_ranges[i].rva,
62185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                           prolog_ranges[i].length,
62285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                           prolog_ranges[i].length };
62385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          frame_infos.push_back(fi);
62485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        }
62585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        for (size_t i = 0; i < code_ranges.size(); ++i) {
62685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          FrameInfo fi = { code_ranges[i].rva, code_ranges[i].length, 0 };
62785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          frame_infos.push_back(fi);
62885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        }
62985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      }
63085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
63185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      for (size_t i = 0; i < frame_infos.size(); ++i) {
63285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        const FrameInfo& fi(frame_infos[i]);
63385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ",
63485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                type, fi.rva, fi.code_size, fi.prolog_size,
63585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                0 /* epilog_size */, parameter_size, saved_register_size,
63685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org                local_size, max_stack_size, program_string_result == S_OK);
63785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        if (program_string_result == S_OK) {
63885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          fprintf(output_, "%ws\n", program_string);
63985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        } else {
64085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          fprintf(output_, "%d\n", allocates_base_pointer);
64185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        }
6424365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      }
6434365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
6444365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      last_type = type;
6454365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      last_rva = rva;
6464365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      last_code_size = code_size;
6474365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      last_prolog_size = prolog_size;
648246f4068280b5b191303ff13671e43a0522987demmentovai    }
649fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
650fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai    frame_data.Release();
651fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  }
652fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
653fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai  return true;
654fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai}
655fc1c78e60e9b305386f4c3fc811463f3b24cf6d4mmentovai
656dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.orgbool PDBSourceLineWriter::PrintFrameDataUsingEXE() {
657dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  if (code_file_.empty() && !FindPEFile()) {
658dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    fprintf(stderr, "Couldn't locate EXE or DLL file.\n");
659dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    return false;
660dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  }
661dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
662dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  // Convert wchar to native charset because ImageLoad only takes
663dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  // a PSTR as input.
664dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  string code_file;
665dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
666dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    return false;
667dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  }
668dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
669dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
670dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  if (!img) {
671dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    fprintf(stderr, "Failed to load %s\n", code_file.c_str());
672dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    return false;
673dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  }
674dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  PIMAGE_OPTIONAL_HEADER64 optional_header =
675dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
676dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
677dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    fprintf(stderr, "Not a PE32+ image\n");
678dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    return false;
679dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  }
680dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
681dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  // Read Exception Directory
682dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  DWORD exception_rva = optional_header->
683dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
684dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  DWORD exception_size = optional_header->
685dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
686dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
687dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
688dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        ImageRvaToVa(img->FileHeader,
689dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                     img->MappedAddress,
690dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                     exception_rva,
691dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                     &img->LastRvaSection));
692dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
693dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    DWORD unwind_rva = funcs[i].UnwindInfoAddress;
694dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    // handle chaining
695dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    while (unwind_rva & 0x1) {
696dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      unwind_rva ^= 0x1;
697dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
698dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
699dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            ImageRvaToVa(img->FileHeader,
700dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                         img->MappedAddress,
701dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                         unwind_rva,
702dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                         &img->LastRvaSection));
703dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      unwind_rva = chained_func->UnwindInfoAddress;
704dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    }
705dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
706dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    UnwindInfo *unwind_info = static_cast<UnwindInfo *>(
707dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        ImageRvaToVa(img->FileHeader,
708dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                     img->MappedAddress,
709dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                     unwind_rva,
710dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                     &img->LastRvaSection));
711dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
7120a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    DWORD stack_size = 8;  // minimal stack size is 8 for RIP
713dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    DWORD rip_offset = 8;
714dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    do {
715dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
716dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        UnwindCode *unwind_code = &unwind_info->unwind_code[c];
717dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        switch (unwind_code->unwind_operation_code) {
718dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_PUSH_NONVOL: {
719dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            stack_size += 8;
720dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            break;
721dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          }
722dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_ALLOC_LARGE: {
723dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            if (unwind_code->operation_info == 0) {
724dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              c++;
725dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              if (c < unwind_info->count_of_codes)
726dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                stack_size += (unwind_code + 1)->frame_offset * 8;
727dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            } else {
728dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              c += 2;
729dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              if (c < unwind_info->count_of_codes)
730dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                stack_size += (unwind_code + 1)->frame_offset |
731dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                              ((unwind_code + 2)->frame_offset << 16);
732dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            }
733dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            break;
734dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          }
735dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_ALLOC_SMALL: {
736dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            stack_size += unwind_code->operation_info * 8 + 8;
737dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            break;
738dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          }
739dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_SET_FPREG:
740dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_SAVE_XMM:
741dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_SAVE_XMM_FAR:
742dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            break;
743dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_SAVE_NONVOL:
744dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_SAVE_XMM128: {
7450a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            c++;  // skip slot with offset
746dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            break;
747dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          }
748dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_SAVE_NONVOL_FAR:
749dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_SAVE_XMM128_FAR: {
7500a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            c += 2;  // skip 2 slots with offset
751dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            break;
752dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          }
753dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          case UWOP_PUSH_MACHFRAME: {
754dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            if (unwind_code->operation_info) {
755dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              stack_size += 88;
756dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            } else {
757dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              stack_size += 80;
758dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            }
759dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            rip_offset += 80;
760dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            break;
761dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          }
762dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        }
763dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      }
764dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      if (unwind_info->flags & UNW_FLAG_CHAININFO) {
765dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
766dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org          reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
767dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              (unwind_info->unwind_code +
768dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org              ((unwind_info->count_of_codes + 1) & ~1)));
769dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
770dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        unwind_info = static_cast<UnwindInfo *>(
771dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            ImageRvaToVa(img->FileHeader,
772dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                         img->MappedAddress,
773dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                         chained_func->UnwindInfoAddress,
774dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org                         &img->LastRvaSection));
775dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      } else {
776dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org        unwind_info = NULL;
777dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org      }
778dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    } while (unwind_info);
779dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    fprintf(output_, "STACK CFI INIT %x %x .cfa: $rsp .ra: .cfa %d - ^\n",
780dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            funcs[i].BeginAddress,
781dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
782dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    fprintf(output_, "STACK CFI %x .cfa: $rsp %d +\n",
783dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org            funcs[i].BeginAddress, stack_size);
784dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  }
785dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
786dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  return true;
787dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org}
788dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
789dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.orgbool PDBSourceLineWriter::PrintFrameData() {
790dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  PDBModuleInfo info;
791dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  if (GetModuleInfo(&info) && info.cpu == L"x86_64") {
792dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    return PrintFrameDataUsingEXE();
793dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  } else {
794dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org    return PrintFrameDataUsingPDB();
795dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  }
796dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org  return false;
797dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org}
798dce69229eedf55783eae13d1782ebd0f39ca1ee6wfh@chromium.org
799246f4068280b5b191303ff13671e43a0522987demmentovaibool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
800246f4068280b5b191303ff13671e43a0522987demmentovai  BOOL is_code;
801246f4068280b5b191303ff13671e43a0522987demmentovai  if (FAILED(symbol->get_code(&is_code))) {
802246f4068280b5b191303ff13671e43a0522987demmentovai    return false;
803246f4068280b5b191303ff13671e43a0522987demmentovai  }
804246f4068280b5b191303ff13671e43a0522987demmentovai  if (!is_code) {
805246f4068280b5b191303ff13671e43a0522987demmentovai    return true;
806246f4068280b5b191303ff13671e43a0522987demmentovai  }
807246f4068280b5b191303ff13671e43a0522987demmentovai
808246f4068280b5b191303ff13671e43a0522987demmentovai  DWORD rva;
809246f4068280b5b191303ff13671e43a0522987demmentovai  if (FAILED(symbol->get_relativeVirtualAddress(&rva))) {
810246f4068280b5b191303ff13671e43a0522987demmentovai    return false;
811246f4068280b5b191303ff13671e43a0522987demmentovai  }
812246f4068280b5b191303ff13671e43a0522987demmentovai
813246f4068280b5b191303ff13671e43a0522987demmentovai  CComBSTR name;
814246f4068280b5b191303ff13671e43a0522987demmentovai  int stack_param_size;
815246f4068280b5b191303ff13671e43a0522987demmentovai  if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) {
816246f4068280b5b191303ff13671e43a0522987demmentovai    return false;
817246f4068280b5b191303ff13671e43a0522987demmentovai  }
818246f4068280b5b191303ff13671e43a0522987demmentovai
81985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  AddressRangeVector ranges;
82085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  MapAddressRange(image_map_, AddressRange(rva, 1), &ranges);
82185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  for (size_t i = 0; i < ranges.size(); ++i) {
82285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org    fprintf(output_, "PUBLIC %x %x %ws\n", ranges[i].rva,
82385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org            stack_param_size > 0 ? stack_param_size : 0, name);
82485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  }
825246f4068280b5b191303ff13671e43a0522987demmentovai  return true;
826246f4068280b5b191303ff13671e43a0522987demmentovai}
827246f4068280b5b191303ff13671e43a0522987demmentovai
82880866e79454cefc5570b01dbb0a723185eae653cmmentovaibool PDBSourceLineWriter::PrintPDBInfo() {
82993fa375b580a647904925cb741266f2d679cb448mmentovai  PDBModuleInfo info;
83093fa375b580a647904925cb741266f2d679cb448mmentovai  if (!GetModuleInfo(&info)) {
83180866e79454cefc5570b01dbb0a723185eae653cmmentovai    return false;
83280866e79454cefc5570b01dbb0a723185eae653cmmentovai  }
83380866e79454cefc5570b01dbb0a723185eae653cmmentovai
8344365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // Hard-code "windows" for the OS because that's the only thing that makes
8354365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // sense for PDB files.  (This might not be strictly correct for Windows CE
8364365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // support, but we don't care about that at the moment.)
83793fa375b580a647904925cb741266f2d679cb448mmentovai  fprintf(output_, "MODULE windows %ws %ws %ws\n",
83893fa375b580a647904925cb741266f2d679cb448mmentovai          info.cpu.c_str(), info.debug_identifier.c_str(),
83993fa375b580a647904925cb741266f2d679cb448mmentovai          info.debug_file.c_str());
84080866e79454cefc5570b01dbb0a723185eae653cmmentovai
84180866e79454cefc5570b01dbb0a723185eae653cmmentovai  return true;
84280866e79454cefc5570b01dbb0a723185eae653cmmentovai}
84380866e79454cefc5570b01dbb0a723185eae653cmmentovai
844d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarekbool PDBSourceLineWriter::PrintPEInfo() {
845d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  PEModuleInfo info;
846d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (!GetPEInfo(&info)) {
847d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    return false;
848d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
849d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
850d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  fprintf(output_, "INFO CODE_ID %ws %ws\n",
85185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          info.code_identifier.c_str(),
85285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          info.code_file.c_str());
853d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  return true;
854d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek}
855d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
856246f4068280b5b191303ff13671e43a0522987demmentovai// wcstol_positive_strict is sort of like wcstol, but much stricter.  string
857246f4068280b5b191303ff13671e43a0522987demmentovai// should be a buffer pointing to a null-terminated string containing only
858246f4068280b5b191303ff13671e43a0522987demmentovai// decimal digits.  If the entire string can be converted to an integer
859246f4068280b5b191303ff13671e43a0522987demmentovai// without overflowing, and there are no non-digit characters before the
860246f4068280b5b191303ff13671e43a0522987demmentovai// result is set to the value and this function returns true.  Otherwise,
861246f4068280b5b191303ff13671e43a0522987demmentovai// this function returns false.  This is an alternative to the strtol, atoi,
862246f4068280b5b191303ff13671e43a0522987demmentovai// and scanf families, which are not as strict about input and in some cases
863246f4068280b5b191303ff13671e43a0522987demmentovai// don't provide a good way for the caller to determine if a conversion was
864246f4068280b5b191303ff13671e43a0522987demmentovai// successful.
865246f4068280b5b191303ff13671e43a0522987demmentovaistatic bool wcstol_positive_strict(wchar_t *string, int *result) {
866246f4068280b5b191303ff13671e43a0522987demmentovai  int value = 0;
867246f4068280b5b191303ff13671e43a0522987demmentovai  for (wchar_t *c = string; *c != '\0'; ++c) {
868246f4068280b5b191303ff13671e43a0522987demmentovai    int last_value = value;
869246f4068280b5b191303ff13671e43a0522987demmentovai    value *= 10;
870246f4068280b5b191303ff13671e43a0522987demmentovai    // Detect overflow.
871246f4068280b5b191303ff13671e43a0522987demmentovai    if (value / 10 != last_value || value < 0) {
872246f4068280b5b191303ff13671e43a0522987demmentovai      return false;
873246f4068280b5b191303ff13671e43a0522987demmentovai    }
874246f4068280b5b191303ff13671e43a0522987demmentovai    if (*c < '0' || *c > '9') {
875246f4068280b5b191303ff13671e43a0522987demmentovai      return false;
876246f4068280b5b191303ff13671e43a0522987demmentovai    }
877246f4068280b5b191303ff13671e43a0522987demmentovai    unsigned int c_value = *c - '0';
878246f4068280b5b191303ff13671e43a0522987demmentovai    last_value = value;
879246f4068280b5b191303ff13671e43a0522987demmentovai    value += c_value;
880246f4068280b5b191303ff13671e43a0522987demmentovai    // Detect overflow.
881246f4068280b5b191303ff13671e43a0522987demmentovai    if (value < last_value) {
882246f4068280b5b191303ff13671e43a0522987demmentovai      return false;
883246f4068280b5b191303ff13671e43a0522987demmentovai    }
884246f4068280b5b191303ff13671e43a0522987demmentovai    // Forbid leading zeroes unless the string is just "0".
885246f4068280b5b191303ff13671e43a0522987demmentovai    if (value == 0 && *(c+1) != '\0') {
886246f4068280b5b191303ff13671e43a0522987demmentovai      return false;
887246f4068280b5b191303ff13671e43a0522987demmentovai    }
888246f4068280b5b191303ff13671e43a0522987demmentovai  }
889246f4068280b5b191303ff13671e43a0522987demmentovai  *result = value;
890246f4068280b5b191303ff13671e43a0522987demmentovai  return true;
891246f4068280b5b191303ff13671e43a0522987demmentovai}
892246f4068280b5b191303ff13671e43a0522987demmentovai
893d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarekbool PDBSourceLineWriter::FindPEFile() {
894d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  CComPtr<IDiaSymbol> global;
895d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (FAILED(session_->get_globalScope(&global))) {
896d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    fprintf(stderr, "get_globalScope failed\n");
897d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    return false;
898d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
899d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
900d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  CComBSTR symbols_file;
901d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) {
902d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    wstring file(symbols_file);
9030a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
904d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    // Look for an EXE or DLL file.
905d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    const wchar_t *extensions[] = { L"exe", L"dll" };
906d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) {
907d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek      size_t dot_pos = file.find_last_of(L".");
908d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek      if (dot_pos != wstring::npos) {
90985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        file.replace(dot_pos + 1, wstring::npos, extensions[i]);
91085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        // Check if this file exists.
91185be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) {
91285be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          code_file_ = file;
91385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org          return true;
91485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org        }
915d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek      }
916d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    }
917d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
918d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
919d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  return false;
920d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek}
921d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
922246f4068280b5b191303ff13671e43a0522987demmentovai// static
923246f4068280b5b191303ff13671e43a0522987demmentovaibool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
924246f4068280b5b191303ff13671e43a0522987demmentovai                                                BSTR *name,
925246f4068280b5b191303ff13671e43a0522987demmentovai                                                int *stack_param_size) {
926246f4068280b5b191303ff13671e43a0522987demmentovai  *stack_param_size = -1;
927246f4068280b5b191303ff13671e43a0522987demmentovai  const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS |
928246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_FUNCTION_RETURNS |
929246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_ALLOCATION_MODEL |
930246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_ALLOCATION_LANGUAGE |
931246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_THISTYPE |
932246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_ACCESS_SPECIFIERS |
933246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_THROW_SIGNATURES |
934246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_MEMBER_TYPE |
935246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_RETURN_UDT_MODEL |
936246f4068280b5b191303ff13671e43a0522987demmentovai                                   UNDNAME_NO_ECSU;
937246f4068280b5b191303ff13671e43a0522987demmentovai
938246f4068280b5b191303ff13671e43a0522987demmentovai  // Use get_undecoratedNameEx to get readable C++ names with arguments.
939246f4068280b5b191303ff13671e43a0522987demmentovai  if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) {
940246f4068280b5b191303ff13671e43a0522987demmentovai    if (function->get_name(name) != S_OK) {
941246f4068280b5b191303ff13671e43a0522987demmentovai      fprintf(stderr, "failed to get function name\n");
942246f4068280b5b191303ff13671e43a0522987demmentovai      return false;
943246f4068280b5b191303ff13671e43a0522987demmentovai    }
944246f4068280b5b191303ff13671e43a0522987demmentovai    // If a name comes from get_name because no undecorated form existed,
945246f4068280b5b191303ff13671e43a0522987demmentovai    // it's already formatted properly to be used as output.  Don't do any
946246f4068280b5b191303ff13671e43a0522987demmentovai    // additional processing.
94773cd14b4af906e77f3d8b019962fb9979ff12620mmentovai    //
94873cd14b4af906e77f3d8b019962fb9979ff12620mmentovai    // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's.
94973cd14b4af906e77f3d8b019962fb9979ff12620mmentovai    // This will result in calling get_name for some C++ symbols, so
95073cd14b4af906e77f3d8b019962fb9979ff12620mmentovai    // all of the parameter and return type information may not be included in
95173cd14b4af906e77f3d8b019962fb9979ff12620mmentovai    // the name string.
952246f4068280b5b191303ff13671e43a0522987demmentovai  } else {
953246f4068280b5b191303ff13671e43a0522987demmentovai    // C++ uses a bogus "void" argument for functions and methods that don't
954246f4068280b5b191303ff13671e43a0522987demmentovai    // take any parameters.  Take it out of the undecorated name because it's
955246f4068280b5b191303ff13671e43a0522987demmentovai    // ugly and unnecessary.
956246f4068280b5b191303ff13671e43a0522987demmentovai    const wchar_t *replace_string = L"(void)";
957246f4068280b5b191303ff13671e43a0522987demmentovai    const size_t replace_length = wcslen(replace_string);
958246f4068280b5b191303ff13671e43a0522987demmentovai    const wchar_t *replacement_string = L"()";
959246f4068280b5b191303ff13671e43a0522987demmentovai    size_t length = wcslen(*name);
960246f4068280b5b191303ff13671e43a0522987demmentovai    if (length >= replace_length) {
961246f4068280b5b191303ff13671e43a0522987demmentovai      wchar_t *name_end = *name + length - replace_length;
962246f4068280b5b191303ff13671e43a0522987demmentovai      if (wcscmp(name_end, replace_string) == 0) {
96373cd14b4af906e77f3d8b019962fb9979ff12620mmentovai        WindowsStringUtils::safe_wcscpy(name_end, replace_length,
96473cd14b4af906e77f3d8b019962fb9979ff12620mmentovai                                        replacement_string);
965246f4068280b5b191303ff13671e43a0522987demmentovai        length = wcslen(*name);
966246f4068280b5b191303ff13671e43a0522987demmentovai      }
967246f4068280b5b191303ff13671e43a0522987demmentovai    }
968246f4068280b5b191303ff13671e43a0522987demmentovai
969246f4068280b5b191303ff13671e43a0522987demmentovai    // Undecorate names used for stdcall and fastcall.  These names prefix
970246f4068280b5b191303ff13671e43a0522987demmentovai    // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it
971246f4068280b5b191303ff13671e43a0522987demmentovai    // with '@' followed by the number of bytes of parameters, in decimal.
972246f4068280b5b191303ff13671e43a0522987demmentovai    // If such a name is found, take note of the size and undecorate it.
973246f4068280b5b191303ff13671e43a0522987demmentovai    // Only do this for names that aren't C++, which is determined based on
974246f4068280b5b191303ff13671e43a0522987demmentovai    // whether the undecorated name contains any ':' or '(' characters.
975246f4068280b5b191303ff13671e43a0522987demmentovai    if (!wcschr(*name, ':') && !wcschr(*name, '(') &&
976246f4068280b5b191303ff13671e43a0522987demmentovai        (*name[0] == '_' || *name[0] == '@')) {
977246f4068280b5b191303ff13671e43a0522987demmentovai      wchar_t *last_at = wcsrchr(*name + 1, '@');
978246f4068280b5b191303ff13671e43a0522987demmentovai      if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) {
979246f4068280b5b191303ff13671e43a0522987demmentovai        // If this function adheres to the fastcall convention, it accepts up
980246f4068280b5b191303ff13671e43a0522987demmentovai        // to the first 8 bytes of parameters in registers (%ecx and %edx).
981246f4068280b5b191303ff13671e43a0522987demmentovai        // We're only interested in the stack space used for parameters, so
982246f4068280b5b191303ff13671e43a0522987demmentovai        // so subtract 8 and don't let the size go below 0.
983246f4068280b5b191303ff13671e43a0522987demmentovai        if (*name[0] == '@') {
984246f4068280b5b191303ff13671e43a0522987demmentovai          if (*stack_param_size > 8) {
985246f4068280b5b191303ff13671e43a0522987demmentovai            *stack_param_size -= 8;
986246f4068280b5b191303ff13671e43a0522987demmentovai          } else {
987246f4068280b5b191303ff13671e43a0522987demmentovai            *stack_param_size = 0;
988246f4068280b5b191303ff13671e43a0522987demmentovai          }
989246f4068280b5b191303ff13671e43a0522987demmentovai        }
990246f4068280b5b191303ff13671e43a0522987demmentovai
991246f4068280b5b191303ff13671e43a0522987demmentovai        // Undecorate the name by moving it one character to the left in its
992246f4068280b5b191303ff13671e43a0522987demmentovai        // buffer, and terminating it where the last '@' had been.
99373cd14b4af906e77f3d8b019962fb9979ff12620mmentovai        WindowsStringUtils::safe_wcsncpy(*name, length,
99473cd14b4af906e77f3d8b019962fb9979ff12620mmentovai                                         *name + 1, last_at - *name - 1);
99573cd14b4af906e77f3d8b019962fb9979ff12620mmentovai     } else if (*name[0] == '_') {
996246f4068280b5b191303ff13671e43a0522987demmentovai        // This symbol's name is encoded according to the cdecl rules.  The
997246f4068280b5b191303ff13671e43a0522987demmentovai        // name doesn't end in a '@' character followed by a decimal positive
9982fc823f5794737391e231c1dce6c2b0793213e53mmentovai        // integer, so it's not a stdcall name.  Strip off the leading
999246f4068280b5b191303ff13671e43a0522987demmentovai        // underscore.
100073cd14b4af906e77f3d8b019962fb9979ff12620mmentovai        WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length);
1001246f4068280b5b191303ff13671e43a0522987demmentovai      }
1002246f4068280b5b191303ff13671e43a0522987demmentovai    }
1003246f4068280b5b191303ff13671e43a0522987demmentovai  }
1004246f4068280b5b191303ff13671e43a0522987demmentovai
1005246f4068280b5b191303ff13671e43a0522987demmentovai  return true;
1006246f4068280b5b191303ff13671e43a0522987demmentovai}
1007246f4068280b5b191303ff13671e43a0522987demmentovai
1008246f4068280b5b191303ff13671e43a0522987demmentovai// static
1009246f4068280b5b191303ff13671e43a0522987demmentovaiint PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) {
1010246f4068280b5b191303ff13671e43a0522987demmentovai  // This implementation is highly x86-specific.
1011246f4068280b5b191303ff13671e43a0522987demmentovai
1012246f4068280b5b191303ff13671e43a0522987demmentovai  // Gather the symbols corresponding to data.
1013246f4068280b5b191303ff13671e43a0522987demmentovai  CComPtr<IDiaEnumSymbols> data_children;
1014246f4068280b5b191303ff13671e43a0522987demmentovai  if (FAILED(function->findChildren(SymTagData, NULL, nsNone,
1015246f4068280b5b191303ff13671e43a0522987demmentovai                                    &data_children))) {
1016246f4068280b5b191303ff13671e43a0522987demmentovai    return 0;
1017246f4068280b5b191303ff13671e43a0522987demmentovai  }
1018246f4068280b5b191303ff13671e43a0522987demmentovai
1019246f4068280b5b191303ff13671e43a0522987demmentovai  // lowest_base is the lowest %ebp-relative byte offset used for a parameter.
1020246f4068280b5b191303ff13671e43a0522987demmentovai  // highest_end is one greater than the highest offset (i.e. base + length).
1021246f4068280b5b191303ff13671e43a0522987demmentovai  // Stack parameters are assumed to be contiguous, because in reality, they
1022246f4068280b5b191303ff13671e43a0522987demmentovai  // are.
1023246f4068280b5b191303ff13671e43a0522987demmentovai  int lowest_base = INT_MAX;
1024246f4068280b5b191303ff13671e43a0522987demmentovai  int highest_end = INT_MIN;
1025246f4068280b5b191303ff13671e43a0522987demmentovai
1026246f4068280b5b191303ff13671e43a0522987demmentovai  CComPtr<IDiaSymbol> child;
1027246f4068280b5b191303ff13671e43a0522987demmentovai  DWORD count;
1028246f4068280b5b191303ff13671e43a0522987demmentovai  while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) {
1029246f4068280b5b191303ff13671e43a0522987demmentovai    // If any operation fails at this point, just proceed to the next child.
1030246f4068280b5b191303ff13671e43a0522987demmentovai    // Use the next_child label instead of continue because child needs to
1031246f4068280b5b191303ff13671e43a0522987demmentovai    // be released before it's reused.  Declare constructable/destructable
1032246f4068280b5b191303ff13671e43a0522987demmentovai    // types early to avoid gotos that cross initializations.
1033246f4068280b5b191303ff13671e43a0522987demmentovai    CComPtr<IDiaSymbol> child_type;
1034246f4068280b5b191303ff13671e43a0522987demmentovai
1035246f4068280b5b191303ff13671e43a0522987demmentovai    // DataIsObjectPtr is only used for |this|.  Because |this| can be passed
1036246f4068280b5b191303ff13671e43a0522987demmentovai    // as a stack parameter, look for it in addition to traditional
1037246f4068280b5b191303ff13671e43a0522987demmentovai    // parameters.
1038246f4068280b5b191303ff13671e43a0522987demmentovai    DWORD child_kind;
1039246f4068280b5b191303ff13671e43a0522987demmentovai    if (FAILED(child->get_dataKind(&child_kind)) ||
1040246f4068280b5b191303ff13671e43a0522987demmentovai        (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) {
1041246f4068280b5b191303ff13671e43a0522987demmentovai      goto next_child;
1042246f4068280b5b191303ff13671e43a0522987demmentovai    }
1043246f4068280b5b191303ff13671e43a0522987demmentovai
1044246f4068280b5b191303ff13671e43a0522987demmentovai    // Only concentrate on register-relative parameters.  Parameters may also
1045246f4068280b5b191303ff13671e43a0522987demmentovai    // be enregistered (passed directly in a register), but those don't
1046246f4068280b5b191303ff13671e43a0522987demmentovai    // consume any stack space, so they're not of interest.
1047246f4068280b5b191303ff13671e43a0522987demmentovai    DWORD child_location_type;
1048246f4068280b5b191303ff13671e43a0522987demmentovai    if (FAILED(child->get_locationType(&child_location_type)) ||
1049246f4068280b5b191303ff13671e43a0522987demmentovai        child_location_type != LocIsRegRel) {
1050246f4068280b5b191303ff13671e43a0522987demmentovai      goto next_child;
1051246f4068280b5b191303ff13671e43a0522987demmentovai    }
1052246f4068280b5b191303ff13671e43a0522987demmentovai
1053246f4068280b5b191303ff13671e43a0522987demmentovai    // Of register-relative parameters, the only ones that make any sense are
1054246f4068280b5b191303ff13671e43a0522987demmentovai    // %ebp- or %esp-relative.  Note that MSVC's debugging information always
1055246f4068280b5b191303ff13671e43a0522987demmentovai    // gives parameters as %ebp-relative even when a function doesn't use a
1056246f4068280b5b191303ff13671e43a0522987demmentovai    // traditional frame pointer and stack parameters are accessed relative to
1057246f4068280b5b191303ff13671e43a0522987demmentovai    // %esp, so just look for %ebp-relative parameters.  If you wanted to
1058246f4068280b5b191303ff13671e43a0522987demmentovai    // access parameters, you'd probably want to treat these %ebp-relative
1059246f4068280b5b191303ff13671e43a0522987demmentovai    // offsets as if they were relative to %esp before a function's prolog
1060246f4068280b5b191303ff13671e43a0522987demmentovai    // executed.
1061246f4068280b5b191303ff13671e43a0522987demmentovai    DWORD child_register;
1062246f4068280b5b191303ff13671e43a0522987demmentovai    if (FAILED(child->get_registerId(&child_register)) ||
1063246f4068280b5b191303ff13671e43a0522987demmentovai        child_register != CV_REG_EBP) {
1064246f4068280b5b191303ff13671e43a0522987demmentovai      goto next_child;
1065246f4068280b5b191303ff13671e43a0522987demmentovai    }
1066246f4068280b5b191303ff13671e43a0522987demmentovai
1067246f4068280b5b191303ff13671e43a0522987demmentovai    LONG child_register_offset;
1068246f4068280b5b191303ff13671e43a0522987demmentovai    if (FAILED(child->get_offset(&child_register_offset))) {
1069246f4068280b5b191303ff13671e43a0522987demmentovai      goto next_child;
1070246f4068280b5b191303ff13671e43a0522987demmentovai    }
1071246f4068280b5b191303ff13671e43a0522987demmentovai
1072329e6a963043bf3cc687d1b0f5740d5bf9cd77e0mmentovai    // IDiaSymbol::get_type can succeed but still pass back a NULL value.
1073329e6a963043bf3cc687d1b0f5740d5bf9cd77e0mmentovai    if (FAILED(child->get_type(&child_type)) || !child_type) {
1074246f4068280b5b191303ff13671e43a0522987demmentovai      goto next_child;
1075246f4068280b5b191303ff13671e43a0522987demmentovai    }
1076246f4068280b5b191303ff13671e43a0522987demmentovai
1077246f4068280b5b191303ff13671e43a0522987demmentovai    ULONGLONG child_length;
1078246f4068280b5b191303ff13671e43a0522987demmentovai    if (FAILED(child_type->get_length(&child_length))) {
1079246f4068280b5b191303ff13671e43a0522987demmentovai      goto next_child;
1080246f4068280b5b191303ff13671e43a0522987demmentovai    }
1081246f4068280b5b191303ff13671e43a0522987demmentovai
1082246f4068280b5b191303ff13671e43a0522987demmentovai    int child_end = child_register_offset + static_cast<ULONG>(child_length);
1083246f4068280b5b191303ff13671e43a0522987demmentovai    if (child_register_offset < lowest_base) {
1084246f4068280b5b191303ff13671e43a0522987demmentovai      lowest_base = child_register_offset;
1085246f4068280b5b191303ff13671e43a0522987demmentovai    }
1086246f4068280b5b191303ff13671e43a0522987demmentovai    if (child_end > highest_end) {
1087246f4068280b5b191303ff13671e43a0522987demmentovai      highest_end = child_end;
1088246f4068280b5b191303ff13671e43a0522987demmentovai    }
1089246f4068280b5b191303ff13671e43a0522987demmentovai
1090246f4068280b5b191303ff13671e43a0522987demmentovainext_child:
1091246f4068280b5b191303ff13671e43a0522987demmentovai    child.Release();
1092246f4068280b5b191303ff13671e43a0522987demmentovai  }
1093246f4068280b5b191303ff13671e43a0522987demmentovai
1094246f4068280b5b191303ff13671e43a0522987demmentovai  int param_size = 0;
1095246f4068280b5b191303ff13671e43a0522987demmentovai  // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest
1096246f4068280b5b191303ff13671e43a0522987demmentovai  // possible address to find a stack parameter before executing a function's
1097246f4068280b5b191303ff13671e43a0522987demmentovai  // prolog (see above).  Some optimizations cause parameter offsets to be
1098246f4068280b5b191303ff13671e43a0522987demmentovai  // lower than 4, but we're not concerned with those because we're only
1099246f4068280b5b191303ff13671e43a0522987demmentovai  // looking for parameters contained in addresses higher than where the
1100246f4068280b5b191303ff13671e43a0522987demmentovai  // return address is stored.
1101246f4068280b5b191303ff13671e43a0522987demmentovai  if (lowest_base < 4) {
1102246f4068280b5b191303ff13671e43a0522987demmentovai    lowest_base = 4;
1103246f4068280b5b191303ff13671e43a0522987demmentovai  }
1104246f4068280b5b191303ff13671e43a0522987demmentovai  if (highest_end > lowest_base) {
1105246f4068280b5b191303ff13671e43a0522987demmentovai    // All stack parameters are pushed as at least 4-byte quantities.  If the
1106246f4068280b5b191303ff13671e43a0522987demmentovai    // last type was narrower than 4 bytes, promote it.  This assumes that all
1107246f4068280b5b191303ff13671e43a0522987demmentovai    // parameters' offsets are 4-byte-aligned, which is always the case.  Only
1108246f4068280b5b191303ff13671e43a0522987demmentovai    // worry about the last type, because we're not summing the type sizes,
1109246f4068280b5b191303ff13671e43a0522987demmentovai    // just looking at the lowest and highest offsets.
1110246f4068280b5b191303ff13671e43a0522987demmentovai    int remainder = highest_end % 4;
1111246f4068280b5b191303ff13671e43a0522987demmentovai    if (remainder) {
1112246f4068280b5b191303ff13671e43a0522987demmentovai      highest_end += 4 - remainder;
1113246f4068280b5b191303ff13671e43a0522987demmentovai    }
1114246f4068280b5b191303ff13671e43a0522987demmentovai
1115246f4068280b5b191303ff13671e43a0522987demmentovai    param_size = highest_end - lowest_base;
1116246f4068280b5b191303ff13671e43a0522987demmentovai  }
1117246f4068280b5b191303ff13671e43a0522987demmentovai
1118246f4068280b5b191303ff13671e43a0522987demmentovai  return param_size;
1119246f4068280b5b191303ff13671e43a0522987demmentovai}
1120246f4068280b5b191303ff13671e43a0522987demmentovai
1121cb91a2f879250f2ef5f74321b5d08807247d41a7brynerbool PDBSourceLineWriter::WriteMap(FILE *map_file) {
1122cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  output_ = map_file;
112380866e79454cefc5570b01dbb0a723185eae653cmmentovai
112485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  // Load the OMAP information, and disable auto-translation of addresses in
112585be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  // preference of doing it ourselves.
112685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  OmapData omap_data;
112785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  if (!GetOmapDataAndDisableTranslation(session_, &omap_data))
112885be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org    return false;
112985be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org  BuildImageMap(omap_data, &image_map_);
113085be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org
1131d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  bool ret = PrintPDBInfo();
1132d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  // This is not a critical piece of the symbol file.
1133cff9fdbd945d3f40c8c10d3eb36f7680ecaa3e2eted.mielczarek  PrintPEInfo();
1134d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  ret = ret &&
11350a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com      PrintSourceFiles() &&
113685be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      PrintFunctions() &&
113785be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      PrintFrameData();
1138cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
1139cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  output_ = NULL;
1140cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  return ret;
1141cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
1142cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
1143cb91a2f879250f2ef5f74321b5d08807247d41a7brynervoid PDBSourceLineWriter::Close() {
1144cb91a2f879250f2ef5f74321b5d08807247d41a7bryner  session_.Release();
1145cb91a2f879250f2ef5f74321b5d08807247d41a7bryner}
1146cb91a2f879250f2ef5f74321b5d08807247d41a7bryner
114793fa375b580a647904925cb741266f2d679cb448mmentovaibool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
114893fa375b580a647904925cb741266f2d679cb448mmentovai  if (!info) {
114993fa375b580a647904925cb741266f2d679cb448mmentovai    return false;
115080866e79454cefc5570b01dbb0a723185eae653cmmentovai  }
115180866e79454cefc5570b01dbb0a723185eae653cmmentovai
115293fa375b580a647904925cb741266f2d679cb448mmentovai  info->debug_file.clear();
115393fa375b580a647904925cb741266f2d679cb448mmentovai  info->debug_identifier.clear();
115493fa375b580a647904925cb741266f2d679cb448mmentovai  info->cpu.clear();
115580866e79454cefc5570b01dbb0a723185eae653cmmentovai
11568b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner  CComPtr<IDiaSymbol> global;
11578b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner  if (FAILED(session_->get_globalScope(&global))) {
115880866e79454cefc5570b01dbb0a723185eae653cmmentovai    return false;
11598b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner  }
11608b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner
11616c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek  DWORD machine_type;
11626c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek  // get_machineType can return S_FALSE.
11636c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek  if (global->get_machineType(&machine_type) == S_OK) {
11646c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek    // The documentation claims that get_machineType returns a value from
11656c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek    // the CV_CPU_TYPE_e enumeration, but that's not the case.
11666c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek    // Instead, it returns one of the IMAGE_FILE_MACHINE values as
11676c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek    // defined here:
11686c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek    // http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx
11696c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek    switch (machine_type) {
11706c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek      case IMAGE_FILE_MACHINE_I386:
11716c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek        info->cpu = L"x86";
11726c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek        break;
11736c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek      case IMAGE_FILE_MACHINE_AMD64:
11746c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek        info->cpu = L"x86_64";
11756c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek        break;
11766c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek      default:
11776c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek        info->cpu = L"unknown";
11786c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek        break;
11796c7d641dc9052fa1fe731bf04388fa1a2eb34fc9ted.mielczarek    }
118093fa375b580a647904925cb741266f2d679cb448mmentovai  } else {
118193fa375b580a647904925cb741266f2d679cb448mmentovai    // Unexpected, but handle gracefully.
118293fa375b580a647904925cb741266f2d679cb448mmentovai    info->cpu = L"unknown";
118393fa375b580a647904925cb741266f2d679cb448mmentovai  }
118493fa375b580a647904925cb741266f2d679cb448mmentovai
118593fa375b580a647904925cb741266f2d679cb448mmentovai  // DWORD* and int* are not compatible.  This is clean and avoids a cast.
118693fa375b580a647904925cb741266f2d679cb448mmentovai  DWORD age;
118793fa375b580a647904925cb741266f2d679cb448mmentovai  if (FAILED(global->get_age(&age))) {
118893fa375b580a647904925cb741266f2d679cb448mmentovai    return false;
11894365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  }
11904365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
11914365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  bool uses_guid;
11924365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  if (!UsesGUID(&uses_guid)) {
119380866e79454cefc5570b01dbb0a723185eae653cmmentovai    return false;
11948b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner  }
11954365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
11964365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  if (uses_guid) {
119793fa375b580a647904925cb741266f2d679cb448mmentovai    GUID guid;
119893fa375b580a647904925cb741266f2d679cb448mmentovai    if (FAILED(global->get_guid(&guid))) {
11994365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      return false;
12004365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    }
12014365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
1202c7b6c11f3287ec4fe52e6ad915ed9c906ed8d301mmentovai    // Use the same format that the MS symbol server uses in filesystem
1203c7b6c11f3287ec4fe52e6ad915ed9c906ed8d301mmentovai    // hierarchies.
120493fa375b580a647904925cb741266f2d679cb448mmentovai    wchar_t age_string[9];
1205aec44489da7da17b5babd9343850257558741fa2mmentovai    swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
1206aec44489da7da17b5babd9343850257558741fa2mmentovai             L"%x", age);
120730fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai
120830fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai    // remove when VC++7.1 is no longer supported
120930fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai    age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
121093fa375b580a647904925cb741266f2d679cb448mmentovai
121193fa375b580a647904925cb741266f2d679cb448mmentovai    info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid);
121293fa375b580a647904925cb741266f2d679cb448mmentovai    info->debug_identifier.append(age_string);
12134365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  } else {
12144365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    DWORD signature;
12154365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    if (FAILED(global->get_signature(&signature))) {
12164365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai      return false;
12174365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    }
12184365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
1219c7b6c11f3287ec4fe52e6ad915ed9c906ed8d301mmentovai    // Use the same format that the MS symbol server uses in filesystem
1220c7b6c11f3287ec4fe52e6ad915ed9c906ed8d301mmentovai    // hierarchies.
122193fa375b580a647904925cb741266f2d679cb448mmentovai    wchar_t identifier_string[17];
1222aec44489da7da17b5babd9343850257558741fa2mmentovai    swprintf(identifier_string,
1223aec44489da7da17b5babd9343850257558741fa2mmentovai             sizeof(identifier_string) / sizeof(identifier_string[0]),
1224aec44489da7da17b5babd9343850257558741fa2mmentovai             L"%08X%x", signature, age);
122530fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai
122630fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai    // remove when VC++7.1 is no longer supported
122730fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai    identifier_string[sizeof(identifier_string) /
122830fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai                      sizeof(identifier_string[0]) - 1] = L'\0';
122930fc9ce1c0e671d7a4234ea70f7ed3906c627659mmentovai
123093fa375b580a647904925cb741266f2d679cb448mmentovai    info->debug_identifier = identifier_string;
123180866e79454cefc5570b01dbb0a723185eae653cmmentovai  }
123280866e79454cefc5570b01dbb0a723185eae653cmmentovai
123393fa375b580a647904925cb741266f2d679cb448mmentovai  CComBSTR debug_file_string;
123493fa375b580a647904925cb741266f2d679cb448mmentovai  if (FAILED(global->get_symbolsFileName(&debug_file_string))) {
123580866e79454cefc5570b01dbb0a723185eae653cmmentovai    return false;
123680866e79454cefc5570b01dbb0a723185eae653cmmentovai  }
123793fa375b580a647904925cb741266f2d679cb448mmentovai  info->debug_file =
123893fa375b580a647904925cb741266f2d679cb448mmentovai      WindowsStringUtils::GetBaseName(wstring(debug_file_string));
123980866e79454cefc5570b01dbb0a723185eae653cmmentovai
124080866e79454cefc5570b01dbb0a723185eae653cmmentovai  return true;
12418b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner}
12428b1645d8cdb34035c0b132fe8b574bc5ee48fb62bryner
1243d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarekbool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
1244d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (!info) {
1245d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    return false;
1246d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
1247d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
1248d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (code_file_.empty() && !FindPEFile()) {
1249d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    fprintf(stderr, "Couldn't locate EXE or DLL file.\n");
1250d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    return false;
1251d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
1252d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
1253d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  // Convert wchar to native charset because ImageLoad only takes
1254d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  // a PSTR as input.
1255d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  string code_file;
1256d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
1257d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    return false;
1258d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
1259d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
1260d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
1261d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (!img) {
1262d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str());
1263d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    return false;
1264d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
1265d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
1266d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  info->code_file = WindowsStringUtils::GetBaseName(code_file_);
1267d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
1268d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  // The date and time that the file was created by the linker.
1269d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
1270d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  // The size of the file in bytes, including all headers.
1271d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  DWORD SizeOfImage = 0;
1272d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  PIMAGE_OPTIONAL_HEADER64 opt =
1273d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
1274d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1275d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    // 64-bit PE file.
1276d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    SizeOfImage = opt->SizeOfImage;
12770a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  } else {
1278d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    // 32-bit PE file.
1279d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek    SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
1280d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  }
1281d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  wchar_t code_identifier[32];
1282d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  swprintf(code_identifier,
128385be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      sizeof(code_identifier) / sizeof(code_identifier[0]),
128485be25b17ef145142197007edb785f236f5844d9chrisha@chromium.org      L"%08X%X", TimeDateStamp, SizeOfImage);
1285d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  info->code_identifier = code_identifier;
1286d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
1287d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek  return true;
1288d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek}
1289d35f113d020aa1cb4f18aace03eca4eb8705dad2ted.mielczarek
12904365e2fe41e2d7246a71b364147dd6e7787028f9mmentovaibool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
12914365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  if (!uses_guid)
12924365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    return false;
12934365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
12944365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  CComPtr<IDiaSymbol> global;
12954365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  if (FAILED(session_->get_globalScope(&global)))
12964365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    return false;
12974365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
12984365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  GUID guid;
12994365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  if (FAILED(global->get_guid(&guid)))
13004365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    return false;
13014365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
13024365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  DWORD signature;
13034365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  if (FAILED(global->get_signature(&signature)))
13044365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai    return false;
13054365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
13064365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // There are two possibilities for guid: either it's a real 128-bit GUID
13074365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // as identified in a code module by a new-style CodeView record, or it's
13084365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // a 32-bit signature (timestamp) as identified by an old-style record.
13094365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h.
13104365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  //
13114365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // Because DIA doesn't provide a way to directly determine whether a module
13124365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // uses a GUID or a 32-bit signature, this code checks whether the first 32
13134365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // bits of guid are the same as the signature, and if the rest of guid is
13144365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // zero.  If so, then with a pretty high degree of certainty, there's an
13154365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // old-style CodeView record in use.  This method will only falsely find an
13164365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // an old-style CodeView record if a real 128-bit GUID has its first 32
13174365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // bits set the same as the module's signature (timestamp) and the rest of
13184365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  // the GUID is set to 0.  This is highly unlikely.
13194365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
13204365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  GUID signature_guid = {signature};  // 0-initializes other members
13214365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  *uses_guid = !IsEqualGUID(guid, signature_guid);
13224365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai  return true;
13234365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai}
13244365e2fe41e2d7246a71b364147dd6e7787028f9mmentovai
1325e5dc60822e5938fea2ae892ccddb906641ba174emmentovai}  // namespace google_breakpad
1326