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(¶meter_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