Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright (c) 2010 Google Inc. | 1 // Copyright (c) 2010 Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 29 matching lines...) Expand all Loading... | |
40 #include <string.h> | 40 #include <string.h> |
41 | 41 |
42 #include <string> | 42 #include <string> |
43 #include <vector> | 43 #include <vector> |
44 | 44 |
45 #include "common/using_std_string.h" | 45 #include "common/using_std_string.h" |
46 #include "google_breakpad/processor/call_stack.h" | 46 #include "google_breakpad/processor/call_stack.h" |
47 #include "google_breakpad/processor/code_module.h" | 47 #include "google_breakpad/processor/code_module.h" |
48 #include "google_breakpad/processor/code_modules.h" | 48 #include "google_breakpad/processor/code_modules.h" |
49 #include "google_breakpad/processor/process_state.h" | 49 #include "google_breakpad/processor/process_state.h" |
50 #include "google_breakpad/processor/source_line_resolver_interface.h" | |
50 #include "google_breakpad/processor/stack_frame_cpu.h" | 51 #include "google_breakpad/processor/stack_frame_cpu.h" |
51 #include "processor/logging.h" | 52 #include "processor/logging.h" |
52 #include "processor/pathname_stripper.h" | 53 #include "processor/pathname_stripper.h" |
53 | 54 |
54 namespace google_breakpad { | 55 namespace google_breakpad { |
55 | 56 |
56 namespace { | 57 namespace { |
57 | 58 |
58 using std::vector; | 59 using std::vector; |
59 | 60 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
103 while ((position = result.find(kOutputSeparator, position)) != string::npos) { | 104 while ((position = result.find(kOutputSeparator, position)) != string::npos) { |
104 result.erase(position, 1); | 105 result.erase(position, 1); |
105 } | 106 } |
106 position = 0; | 107 position = 0; |
107 while ((position = result.find('\n', position)) != string::npos) { | 108 while ((position = result.find('\n', position)) != string::npos) { |
108 result.erase(position, 1); | 109 result.erase(position, 1); |
109 } | 110 } |
110 return result; | 111 return result; |
111 } | 112 } |
112 | 113 |
114 // PrintStackContents prints the stack contents of the current frame to stdout. | |
115 static void PrintStackContents(const std::string &indent, | |
116 const StackFrame *frame, | |
117 const StackFrame *prev_frame, | |
118 const std::string &cpu, | |
119 const MemoryRegion *memory, | |
120 const CodeModules* modules, | |
121 SourceLineResolverInterface *resolver) { | |
122 // Find stack range. | |
123 int word_length = 0; | |
124 uint64_t stack_begin = 0, stack_end = 0; | |
125 if (cpu == "x86") { | |
126 word_length = 4; | |
127 const StackFrameX86 *frame_x86 = static_cast<const StackFrameX86*>(frame); | |
128 const StackFrameX86 *prev_frame_x86 = | |
129 static_cast<const StackFrameX86*>(prev_frame); | |
130 if ((frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) && | |
131 (prev_frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)) { | |
132 stack_begin = frame_x86->context.esp; | |
133 stack_end = prev_frame_x86->context.esp; | |
134 } | |
135 } else if (cpu == "amd64") { | |
136 word_length = 8; | |
137 const StackFrameAMD64 *frame_amd64 = | |
138 static_cast<const StackFrameAMD64*>(frame); | |
139 const StackFrameAMD64 *prev_frame_amd64 = | |
140 static_cast<const StackFrameAMD64*>(prev_frame); | |
141 if ((frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) && | |
142 (prev_frame_amd64->context_validity & | |
143 StackFrameAMD64::CONTEXT_VALID_RSP)) { | |
144 stack_begin = frame_amd64->context.rsp; | |
145 stack_end = prev_frame_amd64->context.rsp; | |
146 } | |
147 } else if (cpu == "arm") { | |
148 word_length = 4; | |
149 const StackFrameARM *frame_arm = static_cast<const StackFrameARM*>(frame); | |
150 const StackFrameARM *prev_frame_arm = | |
151 static_cast<const StackFrameARM*>(prev_frame); | |
152 if ((frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) && | |
153 (prev_frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { | |
154 stack_begin = frame_arm->context.iregs[13]; | |
155 stack_end = prev_frame_arm->context.iregs[13]; | |
156 } | |
157 } else if (cpu == "arm64") { | |
158 word_length = 8; | |
159 const StackFrameARM64 *frame_arm64 = | |
160 static_cast<const StackFrameARM64*>(frame); | |
161 const StackFrameARM64 *prev_frame_arm64 = | |
162 static_cast<const StackFrameARM64*>(prev_frame); | |
163 if ((frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) && | |
164 (prev_frame_arm64->context_validity & | |
165 StackFrameARM64::CONTEXT_VALID_SP)) { | |
166 stack_begin = frame_arm64->context.iregs[31]; | |
167 stack_end = prev_frame_arm64->context.iregs[31]; | |
168 } | |
169 } | |
170 if (!word_length || !stack_begin || !stack_end) | |
171 return; | |
172 | |
173 // Print stack contents. | |
174 printf("\n%sStack contents:", indent.c_str()); | |
175 for(uint64_t address = stack_begin; address < stack_end; ) { | |
176 // Print the start address of this row. | |
177 if (word_length == 4) | |
178 printf("\n%s %08x", indent.c_str(), static_cast<uint32_t>(address)); | |
179 else | |
180 printf("\n%s %016" PRIx64, indent.c_str(), address); | |
181 | |
182 // Print data in hex. | |
183 const int kBytesPerRow = 16; | |
184 std::string data_as_string; | |
185 for (int i = 0; i < kBytesPerRow; ++i, ++address) { | |
186 uint8_t value = 0; | |
187 if (address < stack_end && | |
188 memory->GetMemoryAtAddress(address, &value)) { | |
189 printf(" %02x", value); | |
190 data_as_string.push_back(isprint(value) ? value : '.'); | |
191 } else { | |
192 printf(" "); | |
193 data_as_string.push_back(' '); | |
194 } | |
195 } | |
196 // Print data as string. | |
197 printf(" %s", data_as_string.c_str()); | |
198 } | |
199 | |
200 // Try to find instruction pointers from stack. | |
201 printf("\n%sPossible instruction pointers:", indent.c_str()); | |
202 for (uint64_t address = stack_begin; address < stack_end; | |
203 address += word_length) { | |
204 StackFrame pointee_frame; | |
205 | |
206 // Read a word (possible instruction pointer) from stack. | |
207 if (word_length == 4) { | |
208 uint32_t data32 = 0; | |
209 memory->GetMemoryAtAddress(address, &data32); | |
210 pointee_frame.instruction = data32; | |
211 } else { | |
212 uint64_t data64 = 0; | |
213 memory->GetMemoryAtAddress(address, &data64); | |
214 pointee_frame.instruction = data64; | |
215 } | |
216 pointee_frame.module = | |
217 modules->GetModuleForAddress(pointee_frame.instruction); | |
218 | |
219 // Try to look up the function name. | |
220 if (pointee_frame.module) | |
221 resolver->FillSourceLineInfo(&pointee_frame); | |
222 | |
223 // Print function name. | |
224 if (!pointee_frame.function_name.empty()) { | |
225 if (word_length == 4) { | |
226 printf("\n%s *(0x%08x) = 0x%08x", indent.c_str(), | |
227 static_cast<uint32_t>(address), | |
228 static_cast<uint32_t>(pointee_frame.instruction)); | |
229 } else { | |
230 printf("\n%s *(0x%016" PRIx64 ") = 0x%016" PRIx64, | |
231 indent.c_str(), address, pointee_frame.instruction); | |
232 } | |
233 printf(" <%s> [%s : %d + 0x%" PRIx64 "]", | |
234 pointee_frame.function_name.c_str(), | |
235 PathnameStripper::File(pointee_frame.source_file_name).c_str(), | |
236 pointee_frame.source_line, | |
237 pointee_frame.instruction - pointee_frame.source_line_base); | |
238 } | |
239 } | |
240 } | |
241 | |
113 // PrintStack prints the call stack in |stack| to stdout, in a reasonably | 242 // PrintStack prints the call stack in |stack| to stdout, in a reasonably |
114 // useful form. Module, function, and source file names are displayed if | 243 // useful form. Module, function, and source file names are displayed if |
115 // they are available. The code offset to the base code address of the | 244 // they are available. The code offset to the base code address of the |
116 // source line, function, or module is printed, preferring them in that | 245 // source line, function, or module is printed, preferring them in that |
117 // order. If no source line, function, or module information is available, | 246 // order. If no source line, function, or module information is available, |
118 // an absolute code offset is printed. | 247 // an absolute code offset is printed. |
119 // | 248 // |
120 // If |cpu| is a recognized CPU name, relevant register state for each stack | 249 // If |cpu| is a recognized CPU name, relevant register state for each stack |
121 // frame printed is also output, if available. | 250 // frame printed is also output, if available. |
122 static void PrintStack(const CallStack *stack, const string &cpu) { | 251 static void PrintStack(const CallStack *stack, |
252 const string &cpu, | |
253 bool output_stack_contents, | |
254 const MemoryRegion* memory, | |
255 const CodeModules* modules, | |
256 SourceLineResolverInterface* resolver) { | |
123 int frame_count = stack->frames()->size(); | 257 int frame_count = stack->frames()->size(); |
124 if (frame_count == 0) { | 258 if (frame_count == 0) { |
125 printf(" <no frames>\n"); | 259 printf(" <no frames>\n"); |
126 } | 260 } |
127 for (int frame_index = 0; frame_index < frame_count; ++frame_index) { | 261 for (int frame_index = 0; frame_index < frame_count; ++frame_index) { |
128 const StackFrame *frame = stack->frames()->at(frame_index); | 262 const StackFrame *frame = stack->frames()->at(frame_index); |
129 printf("%2d ", frame_index); | 263 printf("%2d ", frame_index); |
130 | 264 |
131 uint64_t instruction_address = frame->ReturnAddress(); | 265 uint64_t instruction_address = frame->ReturnAddress(); |
132 | 266 |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
461 sequence); | 595 sequence); |
462 if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6) | 596 if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6) |
463 sequence = PrintRegister64("s6", | 597 sequence = PrintRegister64("s6", |
464 frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6], | 598 frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6], |
465 sequence); | 599 sequence); |
466 if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7) | 600 if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7) |
467 sequence = PrintRegister64("s7", | 601 sequence = PrintRegister64("s7", |
468 frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7], | 602 frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7], |
469 sequence); | 603 sequence); |
470 } | 604 } |
605 // Print stack contents. | |
606 if (output_stack_contents && frame_index + 1 < frame_count) { | |
607 const std::string indent(" "); | |
608 PrintStackContents(indent, frame, stack->frames()->at(frame_index + 1), | |
609 cpu, memory, modules, resolver); | |
610 } | |
471 printf("\n Found by: %s\n", frame->trust_description().c_str()); | 611 printf("\n Found by: %s\n", frame->trust_description().c_str()); |
Mark Mentovai
2015/02/26 13:48:44
I would put this before the stack contents.
hashimoto
2015/02/27 04:52:08
Done.
| |
472 } | 612 } |
473 } | 613 } |
474 | 614 |
475 // PrintStackMachineReadable prints the call stack in |stack| to stdout, | 615 // PrintStackMachineReadable prints the call stack in |stack| to stdout, |
476 // in the following machine readable pipe-delimited text format: | 616 // in the following machine readable pipe-delimited text format: |
477 // thread number|frame number|module|function|source file|line|offset | 617 // thread number|frame number|module|function|source file|line|offset |
478 // | 618 // |
479 // Module, function, source file, and source line may all be empty | 619 // Module, function, source file, and source line may all be empty |
480 // depending on availability. The code offset follows the same rules as | 620 // depending on availability. The code offset follows the same rules as |
481 // PrintStack above. | 621 // PrintStack above. |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
635 StripSeparator(module->debug_identifier()).c_str(), | 775 StripSeparator(module->debug_identifier()).c_str(), |
636 kOutputSeparator, base_address, | 776 kOutputSeparator, base_address, |
637 kOutputSeparator, base_address + module->size() - 1, | 777 kOutputSeparator, base_address + module->size() - 1, |
638 kOutputSeparator, | 778 kOutputSeparator, |
639 main_module != NULL && base_address == main_address ? 1 : 0); | 779 main_module != NULL && base_address == main_address ? 1 : 0); |
640 } | 780 } |
641 } | 781 } |
642 | 782 |
643 } // namespace | 783 } // namespace |
644 | 784 |
645 void PrintProcessState(const ProcessState& process_state) { | 785 void PrintProcessState(const ProcessState& process_state, |
786 bool output_stack_contents, | |
787 SourceLineResolverInterface* resolver) { | |
646 // Print OS and CPU information. | 788 // Print OS and CPU information. |
647 string cpu = process_state.system_info()->cpu; | 789 string cpu = process_state.system_info()->cpu; |
648 string cpu_info = process_state.system_info()->cpu_info; | 790 string cpu_info = process_state.system_info()->cpu_info; |
649 printf("Operating system: %s\n", process_state.system_info()->os.c_str()); | 791 printf("Operating system: %s\n", process_state.system_info()->os.c_str()); |
650 printf(" %s\n", | 792 printf(" %s\n", |
651 process_state.system_info()->os_version.c_str()); | 793 process_state.system_info()->os_version.c_str()); |
652 printf("CPU: %s\n", cpu.c_str()); | 794 printf("CPU: %s\n", cpu.c_str()); |
653 if (!cpu_info.empty()) { | 795 if (!cpu_info.empty()) { |
654 // This field is optional. | 796 // This field is optional. |
655 printf(" %s\n", cpu_info.c_str()); | 797 printf(" %s\n", cpu_info.c_str()); |
(...skipping 29 matching lines...) Expand all Loading... | |
685 } | 827 } |
686 | 828 |
687 // If the thread that requested the dump is known, print it first. | 829 // If the thread that requested the dump is known, print it first. |
688 int requesting_thread = process_state.requesting_thread(); | 830 int requesting_thread = process_state.requesting_thread(); |
689 if (requesting_thread != -1) { | 831 if (requesting_thread != -1) { |
690 printf("\n"); | 832 printf("\n"); |
691 printf("Thread %d (%s)\n", | 833 printf("Thread %d (%s)\n", |
692 requesting_thread, | 834 requesting_thread, |
693 process_state.crashed() ? "crashed" : | 835 process_state.crashed() ? "crashed" : |
694 "requested dump, did not crash"); | 836 "requested dump, did not crash"); |
695 PrintStack(process_state.threads()->at(requesting_thread), cpu); | 837 PrintStack(process_state.threads()->at(requesting_thread), cpu, |
838 output_stack_contents, | |
839 process_state.thread_memory_regions()->at(requesting_thread), | |
840 process_state.modules(), resolver); | |
696 } | 841 } |
697 | 842 |
698 // Print all of the threads in the dump. | 843 // Print all of the threads in the dump. |
699 int thread_count = process_state.threads()->size(); | 844 int thread_count = process_state.threads()->size(); |
700 for (int thread_index = 0; thread_index < thread_count; ++thread_index) { | 845 for (int thread_index = 0; thread_index < thread_count; ++thread_index) { |
701 if (thread_index != requesting_thread) { | 846 if (thread_index != requesting_thread) { |
702 // Don't print the crash thread again, it was already printed. | 847 // Don't print the crash thread again, it was already printed. |
703 printf("\n"); | 848 printf("\n"); |
704 printf("Thread %d\n", thread_index); | 849 printf("Thread %d\n", thread_index); |
705 PrintStack(process_state.threads()->at(thread_index), cpu); | 850 PrintStack(process_state.threads()->at(thread_index), cpu, |
851 output_stack_contents, | |
852 process_state.thread_memory_regions()->at(thread_index), | |
853 process_state.modules(), resolver); | |
706 } | 854 } |
707 } | 855 } |
708 | 856 |
709 PrintModules(process_state.modules(), | 857 PrintModules(process_state.modules(), |
710 process_state.modules_without_symbols(), | 858 process_state.modules_without_symbols(), |
711 process_state.modules_with_corrupt_symbols()); | 859 process_state.modules_with_corrupt_symbols()); |
712 } | 860 } |
713 | 861 |
714 void PrintProcessStateMachineReadable(const ProcessState& process_state) { | 862 void PrintProcessStateMachineReadable(const ProcessState& process_state) { |
715 // Print OS and CPU information. | 863 // Print OS and CPU information. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
770 for (int thread_index = 0; thread_index < thread_count; ++thread_index) { | 918 for (int thread_index = 0; thread_index < thread_count; ++thread_index) { |
771 if (thread_index != requesting_thread) { | 919 if (thread_index != requesting_thread) { |
772 // Don't print the crash thread again, it was already printed. | 920 // Don't print the crash thread again, it was already printed. |
773 PrintStackMachineReadable(thread_index, | 921 PrintStackMachineReadable(thread_index, |
774 process_state.threads()->at(thread_index)); | 922 process_state.threads()->at(thread_index)); |
775 } | 923 } |
776 } | 924 } |
777 } | 925 } |
778 | 926 |
779 } // namespace google_breakpad | 927 } // namespace google_breakpad |
OLD | NEW |