Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: obsolete/breakpad/common/windows/pdb_source_line_writer.cc

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <atlbase.h>
31 #include <DbgHelp.h>
32 #include <dia2.h>
33 #include <stdio.h>
34
35 #include "common/windows/string_utils-inl.h"
36
37 #include "common/windows/pdb_source_line_writer.h"
38 #include "common/windows/guid_string.h"
39
40 // This constant may be missing from DbgHelp.h. See the documentation for
41 // IDiaSymbol::get_undecoratedNameEx.
42 #ifndef UNDNAME_NO_ECSU
43 #define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union.
44 #endif // UNDNAME_NO_ECSU
45
46 namespace google_breakpad {
47
48 PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
49 }
50
51 PDBSourceLineWriter::~PDBSourceLineWriter() {
52 }
53
54 bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
55 Close();
56
57 if (FAILED(CoInitialize(NULL))) {
58 fprintf(stderr, "CoInitialize failed\n");
59 return false;
60 }
61
62 CComPtr<IDiaDataSource> data_source;
63 if (FAILED(data_source.CoCreateInstance(CLSID_DiaSource))) {
64 fprintf(stderr, "CoCreateInstance CLSID_DiaSource failed "
65 "(msdia80.dll unregistered?)\n");
66 return false;
67 }
68
69 switch (format) {
70 case PDB_FILE:
71 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
72 fprintf(stderr, "loadDataFromPdb failed\n");
73 return false;
74 }
75 break;
76 case EXE_FILE:
77 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
78 fprintf(stderr, "loadDataForExe failed\n");
79 return false;
80 }
81 break;
82 case ANY_FILE:
83 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
84 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
85 fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n");
86 return false;
87 }
88 }
89 break;
90 default:
91 fprintf(stderr, "Unknown file format\n");
92 return false;
93 }
94
95 if (FAILED(data_source->openSession(&session_))) {
96 fprintf(stderr, "openSession failed\n");
97 }
98
99 return true;
100 }
101
102 bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) {
103 // The line number format is:
104 // <rva> <line number> <source file id>
105 CComPtr<IDiaLineNumber> line;
106 ULONG count;
107
108 while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
109 DWORD rva;
110 if (FAILED(line->get_relativeVirtualAddress(&rva))) {
111 fprintf(stderr, "failed to get line rva\n");
112 return false;
113 }
114
115 DWORD length;
116 if (FAILED(line->get_length(&length))) {
117 fprintf(stderr, "failed to get line code length\n");
118 return false;
119 }
120
121 DWORD dia_source_id;
122 if (FAILED(line->get_sourceFileId(&dia_source_id))) {
123 fprintf(stderr, "failed to get line source file id\n");
124 return false;
125 }
126 // duplicate file names are coalesced to share one ID
127 DWORD source_id = GetRealFileID(dia_source_id);
128
129 DWORD line_num;
130 if (FAILED(line->get_lineNumber(&line_num))) {
131 fprintf(stderr, "failed to get line number\n");
132 return false;
133 }
134
135 fprintf(output_, "%x %x %d %d\n", rva, length, line_num, source_id);
136 line.Release();
137 }
138 return true;
139 }
140
141 bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
142 IDiaSymbol *block) {
143 // The function format is:
144 // FUNC <address> <length> <param_stack_size> <function>
145 DWORD rva;
146 if (FAILED(block->get_relativeVirtualAddress(&rva))) {
147 fprintf(stderr, "couldn't get rva\n");
148 return false;
149 }
150
151 ULONGLONG length;
152 if (FAILED(block->get_length(&length))) {
153 fprintf(stderr, "failed to get function length\n");
154 return false;
155 }
156
157 if (length == 0) {
158 // Silently ignore zero-length functions, which can infrequently pop up.
159 return true;
160 }
161
162 CComBSTR name;
163 int stack_param_size;
164 if (!GetSymbolFunctionName(function, &name, &stack_param_size)) {
165 return false;
166 }
167
168 // If the decorated name didn't give the parameter size, try to
169 // calculate it.
170 if (stack_param_size < 0) {
171 stack_param_size = GetFunctionStackParamSize(function);
172 }
173
174 fprintf(output_, "FUNC %x %" WIN_STRING_FORMAT_LL "x %x %ws\n",
175 rva, length, stack_param_size, name);
176
177 CComPtr<IDiaEnumLineNumbers> lines;
178 if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) {
179 return false;
180 }
181
182 if (!PrintLines(lines)) {
183 return false;
184 }
185 return true;
186 }
187
188 bool PDBSourceLineWriter::PrintSourceFiles() {
189 CComPtr<IDiaSymbol> global;
190 if (FAILED(session_->get_globalScope(&global))) {
191 fprintf(stderr, "get_globalScope failed\n");
192 return false;
193 }
194
195 CComPtr<IDiaEnumSymbols> compilands;
196 if (FAILED(global->findChildren(SymTagCompiland, NULL,
197 nsNone, &compilands))) {
198 fprintf(stderr, "findChildren failed\n");
199 return false;
200 }
201
202 CComPtr<IDiaSymbol> compiland;
203 ULONG count;
204 while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
205 CComPtr<IDiaEnumSourceFiles> source_files;
206 if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) {
207 return false;
208 }
209 CComPtr<IDiaSourceFile> file;
210 while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) {
211 DWORD file_id;
212 if (FAILED(file->get_uniqueId(&file_id))) {
213 return false;
214 }
215
216 CComBSTR file_name;
217 if (FAILED(file->get_fileName(&file_name))) {
218 return false;
219 }
220
221 wstring file_name_string(file_name);
222 if (!FileIDIsCached(file_name_string)) {
223 // this is a new file name, cache it and output a FILE line.
224 CacheFileID(file_name_string, file_id);
225 fwprintf(output_, L"FILE %d %s\n", file_id, file_name);
226 } else {
227 // this file name has already been seen, just save this
228 // ID for later lookup.
229 StoreDuplicateFileID(file_name_string, file_id);
230 }
231 file.Release();
232 }
233 compiland.Release();
234 }
235 return true;
236 }
237
238 bool PDBSourceLineWriter::PrintFunctions() {
239 CComPtr<IDiaEnumSymbolsByAddr> symbols;
240 if (FAILED(session_->getSymbolsByAddr(&symbols))) {
241 fprintf(stderr, "failed to get symbol enumerator\n");
242 return false;
243 }
244
245 CComPtr<IDiaSymbol> symbol;
246 if (FAILED(symbols->symbolByAddr(1, 0, &symbol))) {
247 fprintf(stderr, "failed to enumerate symbols\n");
248 return false;
249 }
250
251 DWORD rva_last = 0;
252 if (FAILED(symbol->get_relativeVirtualAddress(&rva_last))) {
253 fprintf(stderr, "failed to get symbol rva\n");
254 return false;
255 }
256
257 ULONG count;
258 do {
259 DWORD tag;
260 if (FAILED(symbol->get_symTag(&tag))) {
261 fprintf(stderr, "failed to get symbol tag\n");
262 return false;
263 }
264
265 // For a given function, DIA seems to give either a symbol with
266 // SymTagFunction or SymTagPublicSymbol, but not both. This means
267 // that PDBSourceLineWriter will output either a FUNC or PUBLIC line,
268 // but not both.
269 if (tag == SymTagFunction) {
270 if (!PrintFunction(symbol, symbol)) {
271 return false;
272 }
273 } else if (tag == SymTagPublicSymbol) {
274 if (!PrintCodePublicSymbol(symbol)) {
275 return false;
276 }
277 }
278 symbol.Release();
279 } while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1);
280
281 // When building with PGO, the compiler can split functions into
282 // "hot" and "cold" blocks, and move the "cold" blocks out to separate
283 // pages, so the function can be noncontiguous. To find these blocks,
284 // we have to iterate over all the compilands, and then find blocks
285 // that are children of them. We can then find the lexical parents
286 // of those blocks and print out an extra FUNC line for blocks
287 // that are not contained in their parent functions.
288 CComPtr<IDiaSymbol> global;
289 if (FAILED(session_->get_globalScope(&global))) {
290 fprintf(stderr, "get_globalScope failed\n");
291 return false;
292 }
293
294 CComPtr<IDiaEnumSymbols> compilands;
295 if (FAILED(global->findChildren(SymTagCompiland, NULL,
296 nsNone, &compilands))) {
297 fprintf(stderr, "findChildren failed on the global\n");
298 return false;
299 }
300
301 CComPtr<IDiaSymbol> compiland;
302 while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
303 CComPtr<IDiaEnumSymbols> blocks;
304 if (FAILED(compiland->findChildren(SymTagBlock, NULL,
305 nsNone, &blocks))) {
306 fprintf(stderr, "findChildren failed on a compiland\n");
307 return false;
308 }
309
310 CComPtr<IDiaSymbol> block;
311 while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) {
312 // find this block's lexical parent function
313 CComPtr<IDiaSymbol> parent;
314 DWORD tag;
315 if (SUCCEEDED(block->get_lexicalParent(&parent)) &&
316 SUCCEEDED(parent->get_symTag(&tag)) &&
317 tag == SymTagFunction) {
318 // now get the block's offset and the function's offset and size,
319 // and determine if the block is outside of the function
320 DWORD func_rva, block_rva;
321 ULONGLONG func_length;
322 if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) &&
323 SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) &&
324 SUCCEEDED(parent->get_length(&func_length))) {
325 if (block_rva < func_rva || block_rva > (func_rva + func_length)) {
326 if (!PrintFunction(parent, block)) {
327 return false;
328 }
329 }
330 }
331 }
332 parent.Release();
333 block.Release();
334 }
335 blocks.Release();
336 compiland.Release();
337 }
338
339 return true;
340 }
341
342 bool PDBSourceLineWriter::PrintFrameData() {
343 // It would be nice if it were possible to output frame data alongside the
344 // associated function, as is done with line numbers, but the DIA API
345 // doesn't make it possible to get the frame data in that way.
346
347 CComPtr<IDiaEnumTables> tables;
348 if (FAILED(session_->getEnumTables(&tables)))
349 return false;
350
351 // Pick up the first table that supports IDiaEnumFrameData.
352 CComPtr<IDiaEnumFrameData> frame_data_enum;
353 CComPtr<IDiaTable> table;
354 ULONG count;
355 while (!frame_data_enum &&
356 SUCCEEDED(tables->Next(1, &table, &count)) &&
357 count == 1) {
358 table->QueryInterface(_uuidof(IDiaEnumFrameData),
359 reinterpret_cast<void**>(&frame_data_enum));
360 table.Release();
361 }
362 if (!frame_data_enum)
363 return false;
364
365 DWORD last_type = -1;
366 DWORD last_rva = -1;
367 DWORD last_code_size = 0;
368 DWORD last_prolog_size = -1;
369
370 CComPtr<IDiaFrameData> frame_data;
371 while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) &&
372 count == 1) {
373 DWORD type;
374 if (FAILED(frame_data->get_type(&type)))
375 return false;
376
377 DWORD rva;
378 if (FAILED(frame_data->get_relativeVirtualAddress(&rva)))
379 return false;
380
381 DWORD code_size;
382 if (FAILED(frame_data->get_lengthBlock(&code_size)))
383 return false;
384
385 DWORD prolog_size;
386 if (FAILED(frame_data->get_lengthProlog(&prolog_size)))
387 return false;
388
389 // epliog_size is always 0.
390 DWORD epilog_size = 0;
391
392 // parameter_size is the size of parameters passed on the stack. If any
393 // parameters are not passed on the stack (such as in registers), their
394 // sizes will not be included in parameter_size.
395 DWORD parameter_size;
396 if (FAILED(frame_data->get_lengthParams(&parameter_size)))
397 return false;
398
399 DWORD saved_register_size;
400 if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size)))
401 return false;
402
403 DWORD local_size;
404 if (FAILED(frame_data->get_lengthLocals(&local_size)))
405 return false;
406
407 // get_maxStack can return S_FALSE, just use 0 in that case.
408 DWORD max_stack_size = 0;
409 if (FAILED(frame_data->get_maxStack(&max_stack_size)))
410 return false;
411
412 // get_programString can return S_FALSE, indicating that there is no
413 // program string. In that case, check whether %ebp is used.
414 HRESULT program_string_result;
415 CComBSTR program_string;
416 if (FAILED(program_string_result = frame_data->get_program(
417 &program_string))) {
418 return false;
419 }
420
421 // get_allocatesBasePointer can return S_FALSE, treat that as though
422 // %ebp is not used.
423 BOOL allocates_base_pointer = FALSE;
424 if (program_string_result != S_OK) {
425 if (FAILED(frame_data->get_allocatesBasePointer(
426 &allocates_base_pointer))) {
427 return false;
428 }
429 }
430
431 // Only print out a line if type, rva, code_size, or prolog_size have
432 // changed from the last line. It is surprisingly common (especially in
433 // system library PDBs) for DIA to return a series of identical
434 // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86,
435 // this check reduces the size of the dumped symbol file by a third.
436 if (type != last_type || rva != last_rva || code_size != last_code_size ||
437 prolog_size != last_prolog_size) {
438 fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ",
439 type, rva, code_size, prolog_size, epilog_size,
440 parameter_size, saved_register_size, local_size, max_stack_size,
441 program_string_result == S_OK);
442 if (program_string_result == S_OK) {
443 fprintf(output_, "%ws\n", program_string);
444 } else {
445 fprintf(output_, "%d\n", allocates_base_pointer);
446 }
447
448 last_type = type;
449 last_rva = rva;
450 last_code_size = code_size;
451 last_prolog_size = prolog_size;
452 }
453
454 frame_data.Release();
455 }
456
457 return true;
458 }
459
460 bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
461 BOOL is_code;
462 if (FAILED(symbol->get_code(&is_code))) {
463 return false;
464 }
465 if (!is_code) {
466 return true;
467 }
468
469 DWORD rva;
470 if (FAILED(symbol->get_relativeVirtualAddress(&rva))) {
471 return false;
472 }
473
474 CComBSTR name;
475 int stack_param_size;
476 if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) {
477 return false;
478 }
479
480 fprintf(output_, "PUBLIC %x %x %ws\n", rva,
481 stack_param_size > 0 ? stack_param_size : 0, name);
482 return true;
483 }
484
485 bool PDBSourceLineWriter::PrintPDBInfo() {
486 PDBModuleInfo info;
487 if (!GetModuleInfo(&info)) {
488 return false;
489 }
490
491 // Hard-code "windows" for the OS because that's the only thing that makes
492 // sense for PDB files. (This might not be strictly correct for Windows CE
493 // support, but we don't care about that at the moment.)
494 fprintf(output_, "MODULE windows %ws %ws %ws\n",
495 info.cpu.c_str(), info.debug_identifier.c_str(),
496 info.debug_file.c_str());
497
498 return true;
499 }
500
501 // wcstol_positive_strict is sort of like wcstol, but much stricter. string
502 // should be a buffer pointing to a null-terminated string containing only
503 // decimal digits. If the entire string can be converted to an integer
504 // without overflowing, and there are no non-digit characters before the
505 // result is set to the value and this function returns true. Otherwise,
506 // this function returns false. This is an alternative to the strtol, atoi,
507 // and scanf families, which are not as strict about input and in some cases
508 // don't provide a good way for the caller to determine if a conversion was
509 // successful.
510 static bool wcstol_positive_strict(wchar_t *string, int *result) {
511 int value = 0;
512 for (wchar_t *c = string; *c != '\0'; ++c) {
513 int last_value = value;
514 value *= 10;
515 // Detect overflow.
516 if (value / 10 != last_value || value < 0) {
517 return false;
518 }
519 if (*c < '0' || *c > '9') {
520 return false;
521 }
522 unsigned int c_value = *c - '0';
523 last_value = value;
524 value += c_value;
525 // Detect overflow.
526 if (value < last_value) {
527 return false;
528 }
529 // Forbid leading zeroes unless the string is just "0".
530 if (value == 0 && *(c+1) != '\0') {
531 return false;
532 }
533 }
534 *result = value;
535 return true;
536 }
537
538 // static
539 bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
540 BSTR *name,
541 int *stack_param_size) {
542 *stack_param_size = -1;
543 const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS |
544 UNDNAME_NO_FUNCTION_RETURNS |
545 UNDNAME_NO_ALLOCATION_MODEL |
546 UNDNAME_NO_ALLOCATION_LANGUAGE |
547 UNDNAME_NO_THISTYPE |
548 UNDNAME_NO_ACCESS_SPECIFIERS |
549 UNDNAME_NO_THROW_SIGNATURES |
550 UNDNAME_NO_MEMBER_TYPE |
551 UNDNAME_NO_RETURN_UDT_MODEL |
552 UNDNAME_NO_ECSU;
553
554 // Use get_undecoratedNameEx to get readable C++ names with arguments.
555 if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) {
556 if (function->get_name(name) != S_OK) {
557 fprintf(stderr, "failed to get function name\n");
558 return false;
559 }
560 // If a name comes from get_name because no undecorated form existed,
561 // it's already formatted properly to be used as output. Don't do any
562 // additional processing.
563 //
564 // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's.
565 // This will result in calling get_name for some C++ symbols, so
566 // all of the parameter and return type information may not be included in
567 // the name string.
568 } else {
569 // C++ uses a bogus "void" argument for functions and methods that don't
570 // take any parameters. Take it out of the undecorated name because it's
571 // ugly and unnecessary.
572 const wchar_t *replace_string = L"(void)";
573 const size_t replace_length = wcslen(replace_string);
574 const wchar_t *replacement_string = L"()";
575 size_t length = wcslen(*name);
576 if (length >= replace_length) {
577 wchar_t *name_end = *name + length - replace_length;
578 if (wcscmp(name_end, replace_string) == 0) {
579 WindowsStringUtils::safe_wcscpy(name_end, replace_length,
580 replacement_string);
581 length = wcslen(*name);
582 }
583 }
584
585 // Undecorate names used for stdcall and fastcall. These names prefix
586 // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it
587 // with '@' followed by the number of bytes of parameters, in decimal.
588 // If such a name is found, take note of the size and undecorate it.
589 // Only do this for names that aren't C++, which is determined based on
590 // whether the undecorated name contains any ':' or '(' characters.
591 if (!wcschr(*name, ':') && !wcschr(*name, '(') &&
592 (*name[0] == '_' || *name[0] == '@')) {
593 wchar_t *last_at = wcsrchr(*name + 1, '@');
594 if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) {
595 // If this function adheres to the fastcall convention, it accepts up
596 // to the first 8 bytes of parameters in registers (%ecx and %edx).
597 // We're only interested in the stack space used for parameters, so
598 // so subtract 8 and don't let the size go below 0.
599 if (*name[0] == '@') {
600 if (*stack_param_size > 8) {
601 *stack_param_size -= 8;
602 } else {
603 *stack_param_size = 0;
604 }
605 }
606
607 // Undecorate the name by moving it one character to the left in its
608 // buffer, and terminating it where the last '@' had been.
609 WindowsStringUtils::safe_wcsncpy(*name, length,
610 *name + 1, last_at - *name - 1);
611 } else if (*name[0] == '_') {
612 // This symbol's name is encoded according to the cdecl rules. The
613 // name doesn't end in a '@' character followed by a decimal positive
614 // integer, so it's not a stdcall name. Strip off the leading
615 // underscore.
616 WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length);
617 }
618 }
619 }
620
621 return true;
622 }
623
624 // static
625 int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) {
626 // This implementation is highly x86-specific.
627
628 // Gather the symbols corresponding to data.
629 CComPtr<IDiaEnumSymbols> data_children;
630 if (FAILED(function->findChildren(SymTagData, NULL, nsNone,
631 &data_children))) {
632 return 0;
633 }
634
635 // lowest_base is the lowest %ebp-relative byte offset used for a parameter.
636 // highest_end is one greater than the highest offset (i.e. base + length).
637 // Stack parameters are assumed to be contiguous, because in reality, they
638 // are.
639 int lowest_base = INT_MAX;
640 int highest_end = INT_MIN;
641
642 CComPtr<IDiaSymbol> child;
643 DWORD count;
644 while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) {
645 // If any operation fails at this point, just proceed to the next child.
646 // Use the next_child label instead of continue because child needs to
647 // be released before it's reused. Declare constructable/destructable
648 // types early to avoid gotos that cross initializations.
649 CComPtr<IDiaSymbol> child_type;
650
651 // DataIsObjectPtr is only used for |this|. Because |this| can be passed
652 // as a stack parameter, look for it in addition to traditional
653 // parameters.
654 DWORD child_kind;
655 if (FAILED(child->get_dataKind(&child_kind)) ||
656 (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) {
657 goto next_child;
658 }
659
660 // Only concentrate on register-relative parameters. Parameters may also
661 // be enregistered (passed directly in a register), but those don't
662 // consume any stack space, so they're not of interest.
663 DWORD child_location_type;
664 if (FAILED(child->get_locationType(&child_location_type)) ||
665 child_location_type != LocIsRegRel) {
666 goto next_child;
667 }
668
669 // Of register-relative parameters, the only ones that make any sense are
670 // %ebp- or %esp-relative. Note that MSVC's debugging information always
671 // gives parameters as %ebp-relative even when a function doesn't use a
672 // traditional frame pointer and stack parameters are accessed relative to
673 // %esp, so just look for %ebp-relative parameters. If you wanted to
674 // access parameters, you'd probably want to treat these %ebp-relative
675 // offsets as if they were relative to %esp before a function's prolog
676 // executed.
677 DWORD child_register;
678 if (FAILED(child->get_registerId(&child_register)) ||
679 child_register != CV_REG_EBP) {
680 goto next_child;
681 }
682
683 LONG child_register_offset;
684 if (FAILED(child->get_offset(&child_register_offset))) {
685 goto next_child;
686 }
687
688 // IDiaSymbol::get_type can succeed but still pass back a NULL value.
689 if (FAILED(child->get_type(&child_type)) || !child_type) {
690 goto next_child;
691 }
692
693 ULONGLONG child_length;
694 if (FAILED(child_type->get_length(&child_length))) {
695 goto next_child;
696 }
697
698 int child_end = child_register_offset + static_cast<ULONG>(child_length);
699 if (child_register_offset < lowest_base) {
700 lowest_base = child_register_offset;
701 }
702 if (child_end > highest_end) {
703 highest_end = child_end;
704 }
705
706 next_child:
707 child.Release();
708 }
709
710 int param_size = 0;
711 // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest
712 // possible address to find a stack parameter before executing a function's
713 // prolog (see above). Some optimizations cause parameter offsets to be
714 // lower than 4, but we're not concerned with those because we're only
715 // looking for parameters contained in addresses higher than where the
716 // return address is stored.
717 if (lowest_base < 4) {
718 lowest_base = 4;
719 }
720 if (highest_end > lowest_base) {
721 // All stack parameters are pushed as at least 4-byte quantities. If the
722 // last type was narrower than 4 bytes, promote it. This assumes that all
723 // parameters' offsets are 4-byte-aligned, which is always the case. Only
724 // worry about the last type, because we're not summing the type sizes,
725 // just looking at the lowest and highest offsets.
726 int remainder = highest_end % 4;
727 if (remainder) {
728 highest_end += 4 - remainder;
729 }
730
731 param_size = highest_end - lowest_base;
732 }
733
734 return param_size;
735 }
736
737 bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
738 output_ = map_file;
739
740 bool ret = PrintPDBInfo() &&
741 PrintSourceFiles() &&
742 PrintFunctions() &&
743 PrintFrameData();
744
745 output_ = NULL;
746 return ret;
747 }
748
749 void PDBSourceLineWriter::Close() {
750 session_.Release();
751 }
752
753 bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
754 if (!info) {
755 return false;
756 }
757
758 info->debug_file.clear();
759 info->debug_identifier.clear();
760 info->cpu.clear();
761
762 CComPtr<IDiaSymbol> global;
763 if (FAILED(session_->get_globalScope(&global))) {
764 return false;
765 }
766
767 // All CPUs in CV_CPU_TYPE_e (cvconst.h) below 0x10 are x86. There's no
768 // single specific constant to use.
769 DWORD platform;
770 if (SUCCEEDED(global->get_platform(&platform)) && platform < 0x10) {
771 info->cpu = L"x86";
772 } else {
773 // Unexpected, but handle gracefully.
774 info->cpu = L"unknown";
775 }
776
777 // DWORD* and int* are not compatible. This is clean and avoids a cast.
778 DWORD age;
779 if (FAILED(global->get_age(&age))) {
780 return false;
781 }
782
783 bool uses_guid;
784 if (!UsesGUID(&uses_guid)) {
785 return false;
786 }
787
788 if (uses_guid) {
789 GUID guid;
790 if (FAILED(global->get_guid(&guid))) {
791 return false;
792 }
793
794 // Use the same format that the MS symbol server uses in filesystem
795 // hierarchies.
796 wchar_t age_string[9];
797 swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
798 L"%x", age);
799
800 // remove when VC++7.1 is no longer supported
801 age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
802
803 info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid);
804 info->debug_identifier.append(age_string);
805 } else {
806 DWORD signature;
807 if (FAILED(global->get_signature(&signature))) {
808 return false;
809 }
810
811 // Use the same format that the MS symbol server uses in filesystem
812 // hierarchies.
813 wchar_t identifier_string[17];
814 swprintf(identifier_string,
815 sizeof(identifier_string) / sizeof(identifier_string[0]),
816 L"%08X%x", signature, age);
817
818 // remove when VC++7.1 is no longer supported
819 identifier_string[sizeof(identifier_string) /
820 sizeof(identifier_string[0]) - 1] = L'\0';
821
822 info->debug_identifier = identifier_string;
823 }
824
825 CComBSTR debug_file_string;
826 if (FAILED(global->get_symbolsFileName(&debug_file_string))) {
827 return false;
828 }
829 info->debug_file =
830 WindowsStringUtils::GetBaseName(wstring(debug_file_string));
831
832 return true;
833 }
834
835 bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
836 if (!uses_guid)
837 return false;
838
839 CComPtr<IDiaSymbol> global;
840 if (FAILED(session_->get_globalScope(&global)))
841 return false;
842
843 GUID guid;
844 if (FAILED(global->get_guid(&guid)))
845 return false;
846
847 DWORD signature;
848 if (FAILED(global->get_signature(&signature)))
849 return false;
850
851 // There are two possibilities for guid: either it's a real 128-bit GUID
852 // as identified in a code module by a new-style CodeView record, or it's
853 // a 32-bit signature (timestamp) as identified by an old-style record.
854 // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h.
855 //
856 // Because DIA doesn't provide a way to directly determine whether a module
857 // uses a GUID or a 32-bit signature, this code checks whether the first 32
858 // bits of guid are the same as the signature, and if the rest of guid is
859 // zero. If so, then with a pretty high degree of certainty, there's an
860 // old-style CodeView record in use. This method will only falsely find an
861 // an old-style CodeView record if a real 128-bit GUID has its first 32
862 // bits set the same as the module's signature (timestamp) and the rest of
863 // the GUID is set to 0. This is highly unlikely.
864
865 GUID signature_guid = {signature}; // 0-initializes other members
866 *uses_guid = !IsEqualGUID(guid, signature_guid);
867 return true;
868 }
869
870 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « obsolete/breakpad/common/windows/pdb_source_line_writer.h ('k') | obsolete/breakpad/common/windows/string_utils.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698