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