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