Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | // Copyright (c) 2006, Google Inc. |
michael@0 | 2 | // All rights reserved. |
michael@0 | 3 | // |
michael@0 | 4 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 5 | // modification, are permitted provided that the following conditions are |
michael@0 | 6 | // met: |
michael@0 | 7 | // |
michael@0 | 8 | // * Redistributions of source code must retain the above copyright |
michael@0 | 9 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | // * Redistributions in binary form must reproduce the above |
michael@0 | 11 | // copyright notice, this list of conditions and the following disclaimer |
michael@0 | 12 | // in the documentation and/or other materials provided with the |
michael@0 | 13 | // distribution. |
michael@0 | 14 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 15 | // contributors may be used to endorse or promote products derived from |
michael@0 | 16 | // this software without specific prior written permission. |
michael@0 | 17 | // |
michael@0 | 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 29 | |
michael@0 | 30 | #include "google_breakpad/processor/minidump_processor.h" |
michael@0 | 31 | |
michael@0 | 32 | #include <assert.h> |
michael@0 | 33 | #include <stdio.h> |
michael@0 | 34 | |
michael@0 | 35 | #include "common/scoped_ptr.h" |
michael@0 | 36 | #include "google_breakpad/processor/call_stack.h" |
michael@0 | 37 | #include "google_breakpad/processor/minidump.h" |
michael@0 | 38 | #include "google_breakpad/processor/process_state.h" |
michael@0 | 39 | #include "google_breakpad/processor/exploitability.h" |
michael@0 | 40 | #include "google_breakpad/processor/stack_frame_symbolizer.h" |
michael@0 | 41 | #include "processor/logging.h" |
michael@0 | 42 | #include "processor/stackwalker_x86.h" |
michael@0 | 43 | |
michael@0 | 44 | namespace google_breakpad { |
michael@0 | 45 | |
michael@0 | 46 | MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, |
michael@0 | 47 | SourceLineResolverInterface *resolver) |
michael@0 | 48 | : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), |
michael@0 | 49 | own_frame_symbolizer_(true), |
michael@0 | 50 | enable_exploitability_(false) { |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, |
michael@0 | 54 | SourceLineResolverInterface *resolver, |
michael@0 | 55 | bool enable_exploitability) |
michael@0 | 56 | : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), |
michael@0 | 57 | own_frame_symbolizer_(true), |
michael@0 | 58 | enable_exploitability_(enable_exploitability) { |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer *frame_symbolizer, |
michael@0 | 62 | bool enable_exploitability) |
michael@0 | 63 | : frame_symbolizer_(frame_symbolizer), |
michael@0 | 64 | own_frame_symbolizer_(false), |
michael@0 | 65 | enable_exploitability_(enable_exploitability) { |
michael@0 | 66 | assert(frame_symbolizer_); |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | MinidumpProcessor::~MinidumpProcessor() { |
michael@0 | 70 | if (own_frame_symbolizer_) delete frame_symbolizer_; |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | ProcessResult MinidumpProcessor::Process( |
michael@0 | 74 | Minidump *dump, ProcessState *process_state) { |
michael@0 | 75 | assert(dump); |
michael@0 | 76 | assert(process_state); |
michael@0 | 77 | |
michael@0 | 78 | process_state->Clear(); |
michael@0 | 79 | |
michael@0 | 80 | const MDRawHeader *header = dump->header(); |
michael@0 | 81 | if (!header) { |
michael@0 | 82 | BPLOG(ERROR) << "Minidump " << dump->path() << " has no header"; |
michael@0 | 83 | return PROCESS_ERROR_NO_MINIDUMP_HEADER; |
michael@0 | 84 | } |
michael@0 | 85 | process_state->time_date_stamp_ = header->time_date_stamp; |
michael@0 | 86 | |
michael@0 | 87 | bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_); |
michael@0 | 88 | bool has_os_info = GetOSInfo(dump, &process_state->system_info_); |
michael@0 | 89 | |
michael@0 | 90 | uint32_t dump_thread_id = 0; |
michael@0 | 91 | bool has_dump_thread = false; |
michael@0 | 92 | uint32_t requesting_thread_id = 0; |
michael@0 | 93 | bool has_requesting_thread = false; |
michael@0 | 94 | |
michael@0 | 95 | MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo(); |
michael@0 | 96 | if (breakpad_info) { |
michael@0 | 97 | has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id); |
michael@0 | 98 | has_requesting_thread = |
michael@0 | 99 | breakpad_info->GetRequestingThreadID(&requesting_thread_id); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | MinidumpException *exception = dump->GetException(); |
michael@0 | 103 | if (exception) { |
michael@0 | 104 | process_state->crashed_ = true; |
michael@0 | 105 | has_requesting_thread = exception->GetThreadID(&requesting_thread_id); |
michael@0 | 106 | |
michael@0 | 107 | process_state->crash_reason_ = GetCrashReason( |
michael@0 | 108 | dump, &process_state->crash_address_); |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | // This will just return an empty string if it doesn't exist. |
michael@0 | 112 | process_state->assertion_ = GetAssertion(dump); |
michael@0 | 113 | |
michael@0 | 114 | MinidumpModuleList *module_list = dump->GetModuleList(); |
michael@0 | 115 | |
michael@0 | 116 | // Put a copy of the module list into ProcessState object. This is not |
michael@0 | 117 | // necessarily a MinidumpModuleList, but it adheres to the CodeModules |
michael@0 | 118 | // interface, which is all that ProcessState needs to expose. |
michael@0 | 119 | if (module_list) |
michael@0 | 120 | process_state->modules_ = module_list->Copy(); |
michael@0 | 121 | |
michael@0 | 122 | MinidumpThreadList *threads = dump->GetThreadList(); |
michael@0 | 123 | if (!threads) { |
michael@0 | 124 | BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list"; |
michael@0 | 125 | return PROCESS_ERROR_NO_THREAD_LIST; |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | BPLOG(INFO) << "Minidump " << dump->path() << " has " << |
michael@0 | 129 | (has_cpu_info ? "" : "no ") << "CPU info, " << |
michael@0 | 130 | (has_os_info ? "" : "no ") << "OS info, " << |
michael@0 | 131 | (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " << |
michael@0 | 132 | (exception != NULL ? "" : "no ") << "exception, " << |
michael@0 | 133 | (module_list != NULL ? "" : "no ") << "module list, " << |
michael@0 | 134 | (threads != NULL ? "" : "no ") << "thread list, " << |
michael@0 | 135 | (has_dump_thread ? "" : "no ") << "dump thread, and " << |
michael@0 | 136 | (has_requesting_thread ? "" : "no ") << "requesting thread"; |
michael@0 | 137 | |
michael@0 | 138 | bool interrupted = false; |
michael@0 | 139 | bool found_requesting_thread = false; |
michael@0 | 140 | unsigned int thread_count = threads->thread_count(); |
michael@0 | 141 | |
michael@0 | 142 | // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump. |
michael@0 | 143 | frame_symbolizer_->Reset(); |
michael@0 | 144 | |
michael@0 | 145 | for (unsigned int thread_index = 0; |
michael@0 | 146 | thread_index < thread_count; |
michael@0 | 147 | ++thread_index) { |
michael@0 | 148 | char thread_string_buffer[64]; |
michael@0 | 149 | snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d", |
michael@0 | 150 | thread_index, thread_count); |
michael@0 | 151 | string thread_string = dump->path() + ":" + thread_string_buffer; |
michael@0 | 152 | |
michael@0 | 153 | MinidumpThread *thread = threads->GetThreadAtIndex(thread_index); |
michael@0 | 154 | if (!thread) { |
michael@0 | 155 | BPLOG(ERROR) << "Could not get thread for " << thread_string; |
michael@0 | 156 | return PROCESS_ERROR_GETTING_THREAD; |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | uint32_t thread_id; |
michael@0 | 160 | if (!thread->GetThreadID(&thread_id)) { |
michael@0 | 161 | BPLOG(ERROR) << "Could not get thread ID for " << thread_string; |
michael@0 | 162 | return PROCESS_ERROR_GETTING_THREAD_ID; |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | thread_string += " id " + HexString(thread_id); |
michael@0 | 166 | BPLOG(INFO) << "Looking at thread " << thread_string; |
michael@0 | 167 | |
michael@0 | 168 | // If this thread is the thread that produced the minidump, don't process |
michael@0 | 169 | // it. Because of the problems associated with a thread producing a |
michael@0 | 170 | // dump of itself (when both its context and its stack are in flux), |
michael@0 | 171 | // processing that stack wouldn't provide much useful data. |
michael@0 | 172 | if (has_dump_thread && thread_id == dump_thread_id) { |
michael@0 | 173 | continue; |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | MinidumpContext *context = thread->GetContext(); |
michael@0 | 177 | |
michael@0 | 178 | if (has_requesting_thread && thread_id == requesting_thread_id) { |
michael@0 | 179 | if (found_requesting_thread) { |
michael@0 | 180 | // There can't be more than one requesting thread. |
michael@0 | 181 | BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string; |
michael@0 | 182 | return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS; |
michael@0 | 183 | } |
michael@0 | 184 | |
michael@0 | 185 | // Use processed_state->threads_.size() instead of thread_index. |
michael@0 | 186 | // thread_index points to the thread index in the minidump, which |
michael@0 | 187 | // might be greater than the thread index in the threads vector if |
michael@0 | 188 | // any of the minidump's threads are skipped and not placed into the |
michael@0 | 189 | // processed threads vector. The thread vector's current size will |
michael@0 | 190 | // be the index of the current thread when it's pushed into the |
michael@0 | 191 | // vector. |
michael@0 | 192 | process_state->requesting_thread_ = process_state->threads_.size(); |
michael@0 | 193 | |
michael@0 | 194 | found_requesting_thread = true; |
michael@0 | 195 | |
michael@0 | 196 | if (process_state->crashed_) { |
michael@0 | 197 | // Use the exception record's context for the crashed thread, instead |
michael@0 | 198 | // of the thread's own context. For the crashed thread, the thread's |
michael@0 | 199 | // own context is the state inside the exception handler. Using it |
michael@0 | 200 | // would not result in the expected stack trace from the time of the |
michael@0 | 201 | // crash. If the exception context is invalid, however, we fall back |
michael@0 | 202 | // on the thread context. |
michael@0 | 203 | MinidumpContext *ctx = exception->GetContext(); |
michael@0 | 204 | context = ctx ? ctx : thread->GetContext(); |
michael@0 | 205 | } |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | MinidumpMemoryRegion *thread_memory = thread->GetMemory(); |
michael@0 | 209 | if (!thread_memory) { |
michael@0 | 210 | BPLOG(ERROR) << "No memory region for " << thread_string; |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | // Use process_state->modules_ instead of module_list, because the |
michael@0 | 214 | // |modules| argument will be used to populate the |module| fields in |
michael@0 | 215 | // the returned StackFrame objects, which will be placed into the |
michael@0 | 216 | // returned ProcessState object. module_list's lifetime is only as |
michael@0 | 217 | // long as the Minidump object: it will be deleted when this function |
michael@0 | 218 | // returns. process_state->modules_ is owned by the ProcessState object |
michael@0 | 219 | // (just like the StackFrame objects), and is much more suitable for this |
michael@0 | 220 | // task. |
michael@0 | 221 | scoped_ptr<Stackwalker> stackwalker( |
michael@0 | 222 | Stackwalker::StackwalkerForCPU(process_state->system_info(), |
michael@0 | 223 | context, |
michael@0 | 224 | thread_memory, |
michael@0 | 225 | process_state->modules_, |
michael@0 | 226 | frame_symbolizer_)); |
michael@0 | 227 | |
michael@0 | 228 | scoped_ptr<CallStack> stack(new CallStack()); |
michael@0 | 229 | if (stackwalker.get()) { |
michael@0 | 230 | if (!stackwalker->Walk(stack.get(), |
michael@0 | 231 | &process_state->modules_without_symbols_)) { |
michael@0 | 232 | BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at " |
michael@0 | 233 | << thread_string; |
michael@0 | 234 | interrupted = true; |
michael@0 | 235 | } |
michael@0 | 236 | } else { |
michael@0 | 237 | // Threads with missing CPU contexts will hit this, but |
michael@0 | 238 | // don't abort processing the rest of the dump just for |
michael@0 | 239 | // one bad thread. |
michael@0 | 240 | BPLOG(ERROR) << "No stackwalker for " << thread_string; |
michael@0 | 241 | } |
michael@0 | 242 | process_state->threads_.push_back(stack.release()); |
michael@0 | 243 | process_state->thread_memory_regions_.push_back(thread_memory); |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | if (interrupted) { |
michael@0 | 247 | BPLOG(INFO) << "Processing interrupted for " << dump->path(); |
michael@0 | 248 | return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED; |
michael@0 | 249 | } |
michael@0 | 250 | |
michael@0 | 251 | // If a requesting thread was indicated, it must be present. |
michael@0 | 252 | if (has_requesting_thread && !found_requesting_thread) { |
michael@0 | 253 | // Don't mark as an error, but invalidate the requesting thread |
michael@0 | 254 | BPLOG(ERROR) << "Minidump indicated requesting thread " << |
michael@0 | 255 | HexString(requesting_thread_id) << ", not found in " << |
michael@0 | 256 | dump->path(); |
michael@0 | 257 | process_state->requesting_thread_ = -1; |
michael@0 | 258 | } |
michael@0 | 259 | |
michael@0 | 260 | // Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED |
michael@0 | 261 | process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED; |
michael@0 | 262 | |
michael@0 | 263 | // If an exploitability run was requested we perform the platform specific |
michael@0 | 264 | // rating. |
michael@0 | 265 | if (enable_exploitability_) { |
michael@0 | 266 | scoped_ptr<Exploitability> exploitability( |
michael@0 | 267 | Exploitability::ExploitabilityForPlatform(dump, process_state)); |
michael@0 | 268 | // The engine will be null if the platform is not supported |
michael@0 | 269 | if (exploitability != NULL) { |
michael@0 | 270 | process_state->exploitability_ = exploitability->CheckExploitability(); |
michael@0 | 271 | } else { |
michael@0 | 272 | process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE; |
michael@0 | 273 | } |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | BPLOG(INFO) << "Processed " << dump->path(); |
michael@0 | 277 | return PROCESS_OK; |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | ProcessResult MinidumpProcessor::Process( |
michael@0 | 281 | const string &minidump_file, ProcessState *process_state) { |
michael@0 | 282 | BPLOG(INFO) << "Processing minidump in file " << minidump_file; |
michael@0 | 283 | |
michael@0 | 284 | Minidump dump(minidump_file); |
michael@0 | 285 | if (!dump.Read()) { |
michael@0 | 286 | BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read"; |
michael@0 | 287 | return PROCESS_ERROR_MINIDUMP_NOT_FOUND; |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | return Process(&dump, process_state); |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | // Returns the MDRawSystemInfo from a minidump, or NULL if system info is |
michael@0 | 294 | // not available from the minidump. If system_info is non-NULL, it is used |
michael@0 | 295 | // to pass back the MinidumpSystemInfo object. |
michael@0 | 296 | static const MDRawSystemInfo* GetSystemInfo(Minidump *dump, |
michael@0 | 297 | MinidumpSystemInfo **system_info) { |
michael@0 | 298 | MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo(); |
michael@0 | 299 | if (!minidump_system_info) |
michael@0 | 300 | return NULL; |
michael@0 | 301 | |
michael@0 | 302 | if (system_info) |
michael@0 | 303 | *system_info = minidump_system_info; |
michael@0 | 304 | |
michael@0 | 305 | return minidump_system_info->system_info(); |
michael@0 | 306 | } |
michael@0 | 307 | |
michael@0 | 308 | // static |
michael@0 | 309 | bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { |
michael@0 | 310 | assert(dump); |
michael@0 | 311 | assert(info); |
michael@0 | 312 | |
michael@0 | 313 | info->cpu.clear(); |
michael@0 | 314 | info->cpu_info.clear(); |
michael@0 | 315 | |
michael@0 | 316 | MinidumpSystemInfo *system_info; |
michael@0 | 317 | const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); |
michael@0 | 318 | if (!raw_system_info) |
michael@0 | 319 | return false; |
michael@0 | 320 | |
michael@0 | 321 | switch (raw_system_info->processor_architecture) { |
michael@0 | 322 | case MD_CPU_ARCHITECTURE_X86: |
michael@0 | 323 | case MD_CPU_ARCHITECTURE_AMD64: { |
michael@0 | 324 | if (raw_system_info->processor_architecture == |
michael@0 | 325 | MD_CPU_ARCHITECTURE_X86) |
michael@0 | 326 | info->cpu = "x86"; |
michael@0 | 327 | else |
michael@0 | 328 | info->cpu = "amd64"; |
michael@0 | 329 | |
michael@0 | 330 | const string *cpu_vendor = system_info->GetCPUVendor(); |
michael@0 | 331 | if (cpu_vendor) { |
michael@0 | 332 | info->cpu_info = *cpu_vendor; |
michael@0 | 333 | info->cpu_info.append(" "); |
michael@0 | 334 | } |
michael@0 | 335 | |
michael@0 | 336 | char x86_info[36]; |
michael@0 | 337 | snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u", |
michael@0 | 338 | raw_system_info->processor_level, |
michael@0 | 339 | raw_system_info->processor_revision >> 8, |
michael@0 | 340 | raw_system_info->processor_revision & 0xff); |
michael@0 | 341 | info->cpu_info.append(x86_info); |
michael@0 | 342 | break; |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | case MD_CPU_ARCHITECTURE_PPC: { |
michael@0 | 346 | info->cpu = "ppc"; |
michael@0 | 347 | break; |
michael@0 | 348 | } |
michael@0 | 349 | |
michael@0 | 350 | case MD_CPU_ARCHITECTURE_SPARC: { |
michael@0 | 351 | info->cpu = "sparc"; |
michael@0 | 352 | break; |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | case MD_CPU_ARCHITECTURE_ARM: { |
michael@0 | 356 | info->cpu = "arm"; |
michael@0 | 357 | break; |
michael@0 | 358 | } |
michael@0 | 359 | |
michael@0 | 360 | default: { |
michael@0 | 361 | // Assign the numeric architecture ID into the CPU string. |
michael@0 | 362 | char cpu_string[7]; |
michael@0 | 363 | snprintf(cpu_string, sizeof(cpu_string), "0x%04x", |
michael@0 | 364 | raw_system_info->processor_architecture); |
michael@0 | 365 | info->cpu = cpu_string; |
michael@0 | 366 | break; |
michael@0 | 367 | } |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | info->cpu_count = raw_system_info->number_of_processors; |
michael@0 | 371 | |
michael@0 | 372 | return true; |
michael@0 | 373 | } |
michael@0 | 374 | |
michael@0 | 375 | // static |
michael@0 | 376 | bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { |
michael@0 | 377 | assert(dump); |
michael@0 | 378 | assert(info); |
michael@0 | 379 | |
michael@0 | 380 | info->os.clear(); |
michael@0 | 381 | info->os_short.clear(); |
michael@0 | 382 | info->os_version.clear(); |
michael@0 | 383 | |
michael@0 | 384 | MinidumpSystemInfo *system_info; |
michael@0 | 385 | const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); |
michael@0 | 386 | if (!raw_system_info) |
michael@0 | 387 | return false; |
michael@0 | 388 | |
michael@0 | 389 | info->os_short = system_info->GetOS(); |
michael@0 | 390 | |
michael@0 | 391 | switch (raw_system_info->platform_id) { |
michael@0 | 392 | case MD_OS_WIN32_NT: { |
michael@0 | 393 | info->os = "Windows NT"; |
michael@0 | 394 | break; |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | case MD_OS_WIN32_WINDOWS: { |
michael@0 | 398 | info->os = "Windows"; |
michael@0 | 399 | break; |
michael@0 | 400 | } |
michael@0 | 401 | |
michael@0 | 402 | case MD_OS_MAC_OS_X: { |
michael@0 | 403 | info->os = "Mac OS X"; |
michael@0 | 404 | break; |
michael@0 | 405 | } |
michael@0 | 406 | |
michael@0 | 407 | case MD_OS_IOS: { |
michael@0 | 408 | info->os = "iOS"; |
michael@0 | 409 | break; |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | case MD_OS_LINUX: { |
michael@0 | 413 | info->os = "Linux"; |
michael@0 | 414 | break; |
michael@0 | 415 | } |
michael@0 | 416 | |
michael@0 | 417 | case MD_OS_SOLARIS: { |
michael@0 | 418 | info->os = "Solaris"; |
michael@0 | 419 | break; |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | case MD_OS_ANDROID: { |
michael@0 | 423 | info->os = "Android"; |
michael@0 | 424 | break; |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | default: { |
michael@0 | 428 | // Assign the numeric platform ID into the OS string. |
michael@0 | 429 | char os_string[11]; |
michael@0 | 430 | snprintf(os_string, sizeof(os_string), "0x%08x", |
michael@0 | 431 | raw_system_info->platform_id); |
michael@0 | 432 | info->os = os_string; |
michael@0 | 433 | break; |
michael@0 | 434 | } |
michael@0 | 435 | } |
michael@0 | 436 | |
michael@0 | 437 | char os_version_string[33]; |
michael@0 | 438 | snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u", |
michael@0 | 439 | raw_system_info->major_version, |
michael@0 | 440 | raw_system_info->minor_version, |
michael@0 | 441 | raw_system_info->build_number); |
michael@0 | 442 | info->os_version = os_version_string; |
michael@0 | 443 | |
michael@0 | 444 | const string *csd_version = system_info->GetCSDVersion(); |
michael@0 | 445 | if (csd_version) { |
michael@0 | 446 | info->os_version.append(" "); |
michael@0 | 447 | info->os_version.append(*csd_version); |
michael@0 | 448 | } |
michael@0 | 449 | |
michael@0 | 450 | return true; |
michael@0 | 451 | } |
michael@0 | 452 | |
michael@0 | 453 | // static |
michael@0 | 454 | string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { |
michael@0 | 455 | MinidumpException *exception = dump->GetException(); |
michael@0 | 456 | if (!exception) |
michael@0 | 457 | return ""; |
michael@0 | 458 | |
michael@0 | 459 | const MDRawExceptionStream *raw_exception = exception->exception(); |
michael@0 | 460 | if (!raw_exception) |
michael@0 | 461 | return ""; |
michael@0 | 462 | |
michael@0 | 463 | if (address) |
michael@0 | 464 | *address = raw_exception->exception_record.exception_address; |
michael@0 | 465 | |
michael@0 | 466 | // The reason value is OS-specific and possibly CPU-specific. Set up |
michael@0 | 467 | // sensible numeric defaults for the reason string in case we can't |
michael@0 | 468 | // map the codes to a string (because there's no system info, or because |
michael@0 | 469 | // it's an unrecognized platform, or because it's an unrecognized code.) |
michael@0 | 470 | char reason_string[24]; |
michael@0 | 471 | uint32_t exception_code = raw_exception->exception_record.exception_code; |
michael@0 | 472 | uint32_t exception_flags = raw_exception->exception_record.exception_flags; |
michael@0 | 473 | snprintf(reason_string, sizeof(reason_string), "0x%08x / 0x%08x", |
michael@0 | 474 | exception_code, exception_flags); |
michael@0 | 475 | string reason = reason_string; |
michael@0 | 476 | |
michael@0 | 477 | const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL); |
michael@0 | 478 | if (!raw_system_info) |
michael@0 | 479 | return reason; |
michael@0 | 480 | |
michael@0 | 481 | switch (raw_system_info->platform_id) { |
michael@0 | 482 | case MD_OS_MAC_OS_X: |
michael@0 | 483 | case MD_OS_IOS: { |
michael@0 | 484 | char flags_string[11]; |
michael@0 | 485 | snprintf(flags_string, sizeof(flags_string), "0x%08x", exception_flags); |
michael@0 | 486 | switch (exception_code) { |
michael@0 | 487 | case MD_EXCEPTION_MAC_BAD_ACCESS: |
michael@0 | 488 | reason = "EXC_BAD_ACCESS / "; |
michael@0 | 489 | switch (exception_flags) { |
michael@0 | 490 | case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS: |
michael@0 | 491 | reason.append("KERN_INVALID_ADDRESS"); |
michael@0 | 492 | break; |
michael@0 | 493 | case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE: |
michael@0 | 494 | reason.append("KERN_PROTECTION_FAILURE"); |
michael@0 | 495 | break; |
michael@0 | 496 | case MD_EXCEPTION_CODE_MAC_NO_ACCESS: |
michael@0 | 497 | reason.append("KERN_NO_ACCESS"); |
michael@0 | 498 | break; |
michael@0 | 499 | case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE: |
michael@0 | 500 | reason.append("KERN_MEMORY_FAILURE"); |
michael@0 | 501 | break; |
michael@0 | 502 | case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR: |
michael@0 | 503 | reason.append("KERN_MEMORY_ERROR"); |
michael@0 | 504 | break; |
michael@0 | 505 | default: |
michael@0 | 506 | // arm and ppc overlap |
michael@0 | 507 | if (raw_system_info->processor_architecture == |
michael@0 | 508 | MD_CPU_ARCHITECTURE_ARM) { |
michael@0 | 509 | switch (exception_flags) { |
michael@0 | 510 | case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: |
michael@0 | 511 | reason.append("EXC_ARM_DA_ALIGN"); |
michael@0 | 512 | break; |
michael@0 | 513 | case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: |
michael@0 | 514 | reason.append("EXC_ARM_DA_DEBUG"); |
michael@0 | 515 | break; |
michael@0 | 516 | default: |
michael@0 | 517 | reason.append(flags_string); |
michael@0 | 518 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 519 | break; |
michael@0 | 520 | } |
michael@0 | 521 | } else if (raw_system_info->processor_architecture == |
michael@0 | 522 | MD_CPU_ARCHITECTURE_PPC) { |
michael@0 | 523 | switch (exception_flags) { |
michael@0 | 524 | case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ: |
michael@0 | 525 | reason.append("EXC_PPC_VM_PROT_READ"); |
michael@0 | 526 | break; |
michael@0 | 527 | case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE: |
michael@0 | 528 | reason.append("EXC_PPC_BADSPACE"); |
michael@0 | 529 | break; |
michael@0 | 530 | case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED: |
michael@0 | 531 | reason.append("EXC_PPC_UNALIGNED"); |
michael@0 | 532 | break; |
michael@0 | 533 | default: |
michael@0 | 534 | reason.append(flags_string); |
michael@0 | 535 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 536 | break; |
michael@0 | 537 | } |
michael@0 | 538 | } else { |
michael@0 | 539 | reason.append(flags_string); |
michael@0 | 540 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 541 | } |
michael@0 | 542 | break; |
michael@0 | 543 | } |
michael@0 | 544 | break; |
michael@0 | 545 | case MD_EXCEPTION_MAC_BAD_INSTRUCTION: |
michael@0 | 546 | reason = "EXC_BAD_INSTRUCTION / "; |
michael@0 | 547 | switch (raw_system_info->processor_architecture) { |
michael@0 | 548 | case MD_CPU_ARCHITECTURE_ARM: { |
michael@0 | 549 | switch (exception_flags) { |
michael@0 | 550 | case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED: |
michael@0 | 551 | reason.append("EXC_ARM_UNDEFINED"); |
michael@0 | 552 | break; |
michael@0 | 553 | default: |
michael@0 | 554 | reason.append(flags_string); |
michael@0 | 555 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 556 | break; |
michael@0 | 557 | } |
michael@0 | 558 | break; |
michael@0 | 559 | } |
michael@0 | 560 | case MD_CPU_ARCHITECTURE_PPC: { |
michael@0 | 561 | switch (exception_flags) { |
michael@0 | 562 | case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL: |
michael@0 | 563 | reason.append("EXC_PPC_INVALID_SYSCALL"); |
michael@0 | 564 | break; |
michael@0 | 565 | case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION: |
michael@0 | 566 | reason.append("EXC_PPC_UNIPL_INST"); |
michael@0 | 567 | break; |
michael@0 | 568 | case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION: |
michael@0 | 569 | reason.append("EXC_PPC_PRIVINST"); |
michael@0 | 570 | break; |
michael@0 | 571 | case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER: |
michael@0 | 572 | reason.append("EXC_PPC_PRIVREG"); |
michael@0 | 573 | break; |
michael@0 | 574 | case MD_EXCEPTION_CODE_MAC_PPC_TRACE: |
michael@0 | 575 | reason.append("EXC_PPC_TRACE"); |
michael@0 | 576 | break; |
michael@0 | 577 | case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR: |
michael@0 | 578 | reason.append("EXC_PPC_PERFMON"); |
michael@0 | 579 | break; |
michael@0 | 580 | default: |
michael@0 | 581 | reason.append(flags_string); |
michael@0 | 582 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 583 | break; |
michael@0 | 584 | } |
michael@0 | 585 | break; |
michael@0 | 586 | } |
michael@0 | 587 | case MD_CPU_ARCHITECTURE_X86: { |
michael@0 | 588 | switch (exception_flags) { |
michael@0 | 589 | case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION: |
michael@0 | 590 | reason.append("EXC_I386_INVOP"); |
michael@0 | 591 | break; |
michael@0 | 592 | case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT: |
michael@0 | 593 | reason.append("EXC_INVTSSFLT"); |
michael@0 | 594 | break; |
michael@0 | 595 | case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT: |
michael@0 | 596 | reason.append("EXC_SEGNPFLT"); |
michael@0 | 597 | break; |
michael@0 | 598 | case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT: |
michael@0 | 599 | reason.append("EXC_STKFLT"); |
michael@0 | 600 | break; |
michael@0 | 601 | case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT: |
michael@0 | 602 | reason.append("EXC_GPFLT"); |
michael@0 | 603 | break; |
michael@0 | 604 | case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT: |
michael@0 | 605 | reason.append("EXC_ALIGNFLT"); |
michael@0 | 606 | break; |
michael@0 | 607 | default: |
michael@0 | 608 | reason.append(flags_string); |
michael@0 | 609 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 610 | break; |
michael@0 | 611 | } |
michael@0 | 612 | break; |
michael@0 | 613 | } |
michael@0 | 614 | default: |
michael@0 | 615 | reason.append(flags_string); |
michael@0 | 616 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 617 | break; |
michael@0 | 618 | } |
michael@0 | 619 | break; |
michael@0 | 620 | case MD_EXCEPTION_MAC_ARITHMETIC: |
michael@0 | 621 | reason = "EXC_ARITHMETIC / "; |
michael@0 | 622 | switch (raw_system_info->processor_architecture) { |
michael@0 | 623 | case MD_CPU_ARCHITECTURE_PPC: { |
michael@0 | 624 | switch (exception_flags) { |
michael@0 | 625 | case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW: |
michael@0 | 626 | reason.append("EXC_PPC_OVERFLOW"); |
michael@0 | 627 | break; |
michael@0 | 628 | case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE: |
michael@0 | 629 | reason.append("EXC_PPC_ZERO_DIVIDE"); |
michael@0 | 630 | break; |
michael@0 | 631 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT: |
michael@0 | 632 | reason.append("EXC_FLT_INEXACT"); |
michael@0 | 633 | break; |
michael@0 | 634 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE: |
michael@0 | 635 | reason.append("EXC_PPC_FLT_ZERO_DIVIDE"); |
michael@0 | 636 | break; |
michael@0 | 637 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW: |
michael@0 | 638 | reason.append("EXC_PPC_FLT_UNDERFLOW"); |
michael@0 | 639 | break; |
michael@0 | 640 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW: |
michael@0 | 641 | reason.append("EXC_PPC_FLT_OVERFLOW"); |
michael@0 | 642 | break; |
michael@0 | 643 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER: |
michael@0 | 644 | reason.append("EXC_PPC_FLT_NOT_A_NUMBER"); |
michael@0 | 645 | break; |
michael@0 | 646 | case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION: |
michael@0 | 647 | reason.append("EXC_PPC_NOEMULATION"); |
michael@0 | 648 | break; |
michael@0 | 649 | case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST: |
michael@0 | 650 | reason.append("EXC_PPC_ALTIVECASSIST"); |
michael@0 | 651 | default: |
michael@0 | 652 | reason.append(flags_string); |
michael@0 | 653 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 654 | break; |
michael@0 | 655 | } |
michael@0 | 656 | break; |
michael@0 | 657 | } |
michael@0 | 658 | case MD_CPU_ARCHITECTURE_X86: { |
michael@0 | 659 | switch (exception_flags) { |
michael@0 | 660 | case MD_EXCEPTION_CODE_MAC_X86_DIV: |
michael@0 | 661 | reason.append("EXC_I386_DIV"); |
michael@0 | 662 | break; |
michael@0 | 663 | case MD_EXCEPTION_CODE_MAC_X86_INTO: |
michael@0 | 664 | reason.append("EXC_I386_INTO"); |
michael@0 | 665 | break; |
michael@0 | 666 | case MD_EXCEPTION_CODE_MAC_X86_NOEXT: |
michael@0 | 667 | reason.append("EXC_I386_NOEXT"); |
michael@0 | 668 | break; |
michael@0 | 669 | case MD_EXCEPTION_CODE_MAC_X86_EXTOVR: |
michael@0 | 670 | reason.append("EXC_I386_EXTOVR"); |
michael@0 | 671 | break; |
michael@0 | 672 | case MD_EXCEPTION_CODE_MAC_X86_EXTERR: |
michael@0 | 673 | reason.append("EXC_I386_EXTERR"); |
michael@0 | 674 | break; |
michael@0 | 675 | case MD_EXCEPTION_CODE_MAC_X86_EMERR: |
michael@0 | 676 | reason.append("EXC_I386_EMERR"); |
michael@0 | 677 | break; |
michael@0 | 678 | case MD_EXCEPTION_CODE_MAC_X86_BOUND: |
michael@0 | 679 | reason.append("EXC_I386_BOUND"); |
michael@0 | 680 | break; |
michael@0 | 681 | case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR: |
michael@0 | 682 | reason.append("EXC_I386_SSEEXTERR"); |
michael@0 | 683 | break; |
michael@0 | 684 | default: |
michael@0 | 685 | reason.append(flags_string); |
michael@0 | 686 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 687 | break; |
michael@0 | 688 | } |
michael@0 | 689 | break; |
michael@0 | 690 | } |
michael@0 | 691 | default: |
michael@0 | 692 | reason.append(flags_string); |
michael@0 | 693 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 694 | break; |
michael@0 | 695 | } |
michael@0 | 696 | break; |
michael@0 | 697 | case MD_EXCEPTION_MAC_EMULATION: |
michael@0 | 698 | reason = "EXC_EMULATION / "; |
michael@0 | 699 | reason.append(flags_string); |
michael@0 | 700 | break; |
michael@0 | 701 | case MD_EXCEPTION_MAC_SOFTWARE: |
michael@0 | 702 | reason = "EXC_SOFTWARE / "; |
michael@0 | 703 | switch (exception_flags) { |
michael@0 | 704 | case MD_EXCEPTION_CODE_MAC_ABORT: |
michael@0 | 705 | reason.append("SIGABRT"); |
michael@0 | 706 | break; |
michael@0 | 707 | case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION: |
michael@0 | 708 | reason.append("UNCAUGHT_NS_EXCEPTION"); |
michael@0 | 709 | break; |
michael@0 | 710 | // These are ppc only but shouldn't be a problem as they're |
michael@0 | 711 | // unused on x86 |
michael@0 | 712 | case MD_EXCEPTION_CODE_MAC_PPC_TRAP: |
michael@0 | 713 | reason.append("EXC_PPC_TRAP"); |
michael@0 | 714 | break; |
michael@0 | 715 | case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE: |
michael@0 | 716 | reason.append("EXC_PPC_MIGRATE"); |
michael@0 | 717 | break; |
michael@0 | 718 | default: |
michael@0 | 719 | reason.append(flags_string); |
michael@0 | 720 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 721 | break; |
michael@0 | 722 | } |
michael@0 | 723 | break; |
michael@0 | 724 | case MD_EXCEPTION_MAC_BREAKPOINT: |
michael@0 | 725 | reason = "EXC_BREAKPOINT / "; |
michael@0 | 726 | switch (raw_system_info->processor_architecture) { |
michael@0 | 727 | case MD_CPU_ARCHITECTURE_ARM: { |
michael@0 | 728 | switch (exception_flags) { |
michael@0 | 729 | case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: |
michael@0 | 730 | reason.append("EXC_ARM_DA_ALIGN"); |
michael@0 | 731 | break; |
michael@0 | 732 | case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: |
michael@0 | 733 | reason.append("EXC_ARM_DA_DEBUG"); |
michael@0 | 734 | break; |
michael@0 | 735 | case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT: |
michael@0 | 736 | reason.append("EXC_ARM_BREAKPOINT"); |
michael@0 | 737 | break; |
michael@0 | 738 | default: |
michael@0 | 739 | reason.append(flags_string); |
michael@0 | 740 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 741 | break; |
michael@0 | 742 | } |
michael@0 | 743 | break; |
michael@0 | 744 | } |
michael@0 | 745 | case MD_CPU_ARCHITECTURE_PPC: { |
michael@0 | 746 | switch (exception_flags) { |
michael@0 | 747 | case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT: |
michael@0 | 748 | reason.append("EXC_PPC_BREAKPOINT"); |
michael@0 | 749 | break; |
michael@0 | 750 | default: |
michael@0 | 751 | reason.append(flags_string); |
michael@0 | 752 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 753 | break; |
michael@0 | 754 | } |
michael@0 | 755 | break; |
michael@0 | 756 | } |
michael@0 | 757 | case MD_CPU_ARCHITECTURE_X86: { |
michael@0 | 758 | switch (exception_flags) { |
michael@0 | 759 | case MD_EXCEPTION_CODE_MAC_X86_SGL: |
michael@0 | 760 | reason.append("EXC_I386_SGL"); |
michael@0 | 761 | break; |
michael@0 | 762 | case MD_EXCEPTION_CODE_MAC_X86_BPT: |
michael@0 | 763 | reason.append("EXC_I386_BPT"); |
michael@0 | 764 | break; |
michael@0 | 765 | default: |
michael@0 | 766 | reason.append(flags_string); |
michael@0 | 767 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 768 | break; |
michael@0 | 769 | } |
michael@0 | 770 | break; |
michael@0 | 771 | } |
michael@0 | 772 | default: |
michael@0 | 773 | reason.append(flags_string); |
michael@0 | 774 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 775 | break; |
michael@0 | 776 | } |
michael@0 | 777 | break; |
michael@0 | 778 | case MD_EXCEPTION_MAC_SYSCALL: |
michael@0 | 779 | reason = "EXC_SYSCALL / "; |
michael@0 | 780 | reason.append(flags_string); |
michael@0 | 781 | break; |
michael@0 | 782 | case MD_EXCEPTION_MAC_MACH_SYSCALL: |
michael@0 | 783 | reason = "EXC_MACH_SYSCALL / "; |
michael@0 | 784 | reason.append(flags_string); |
michael@0 | 785 | break; |
michael@0 | 786 | case MD_EXCEPTION_MAC_RPC_ALERT: |
michael@0 | 787 | reason = "EXC_RPC_ALERT / "; |
michael@0 | 788 | reason.append(flags_string); |
michael@0 | 789 | break; |
michael@0 | 790 | } |
michael@0 | 791 | break; |
michael@0 | 792 | } |
michael@0 | 793 | |
michael@0 | 794 | case MD_OS_WIN32_NT: |
michael@0 | 795 | case MD_OS_WIN32_WINDOWS: { |
michael@0 | 796 | switch (exception_code) { |
michael@0 | 797 | case MD_EXCEPTION_CODE_WIN_CONTROL_C: |
michael@0 | 798 | reason = "DBG_CONTROL_C"; |
michael@0 | 799 | break; |
michael@0 | 800 | case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: |
michael@0 | 801 | reason = "EXCEPTION_GUARD_PAGE"; |
michael@0 | 802 | break; |
michael@0 | 803 | case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT: |
michael@0 | 804 | reason = "EXCEPTION_DATATYPE_MISALIGNMENT"; |
michael@0 | 805 | break; |
michael@0 | 806 | case MD_EXCEPTION_CODE_WIN_BREAKPOINT: |
michael@0 | 807 | reason = "EXCEPTION_BREAKPOINT"; |
michael@0 | 808 | break; |
michael@0 | 809 | case MD_EXCEPTION_CODE_WIN_SINGLE_STEP: |
michael@0 | 810 | reason = "EXCEPTION_SINGLE_STEP"; |
michael@0 | 811 | break; |
michael@0 | 812 | case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION: |
michael@0 | 813 | // For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that |
michael@0 | 814 | // caused the fault in exception_information[1]. |
michael@0 | 815 | // exception_information[0] is 0 if the violation was caused by |
michael@0 | 816 | // an attempt to read data and 1 if it was an attempt to write |
michael@0 | 817 | // data. |
michael@0 | 818 | // This information is useful in addition to the code address, which |
michael@0 | 819 | // will be present in the crash thread's instruction field anyway. |
michael@0 | 820 | if (raw_exception->exception_record.number_parameters >= 1) { |
michael@0 | 821 | MDAccessViolationTypeWin av_type = |
michael@0 | 822 | static_cast<MDAccessViolationTypeWin> |
michael@0 | 823 | (raw_exception->exception_record.exception_information[0]); |
michael@0 | 824 | switch (av_type) { |
michael@0 | 825 | case MD_ACCESS_VIOLATION_WIN_READ: |
michael@0 | 826 | reason = "EXCEPTION_ACCESS_VIOLATION_READ"; |
michael@0 | 827 | break; |
michael@0 | 828 | case MD_ACCESS_VIOLATION_WIN_WRITE: |
michael@0 | 829 | reason = "EXCEPTION_ACCESS_VIOLATION_WRITE"; |
michael@0 | 830 | break; |
michael@0 | 831 | case MD_ACCESS_VIOLATION_WIN_EXEC: |
michael@0 | 832 | reason = "EXCEPTION_ACCESS_VIOLATION_EXEC"; |
michael@0 | 833 | break; |
michael@0 | 834 | default: |
michael@0 | 835 | reason = "EXCEPTION_ACCESS_VIOLATION"; |
michael@0 | 836 | break; |
michael@0 | 837 | } |
michael@0 | 838 | } else { |
michael@0 | 839 | reason = "EXCEPTION_ACCESS_VIOLATION"; |
michael@0 | 840 | } |
michael@0 | 841 | if (address && |
michael@0 | 842 | raw_exception->exception_record.number_parameters >= 2) { |
michael@0 | 843 | *address = |
michael@0 | 844 | raw_exception->exception_record.exception_information[1]; |
michael@0 | 845 | } |
michael@0 | 846 | break; |
michael@0 | 847 | case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR: |
michael@0 | 848 | reason = "EXCEPTION_IN_PAGE_ERROR"; |
michael@0 | 849 | break; |
michael@0 | 850 | case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE: |
michael@0 | 851 | reason = "EXCEPTION_INVALID_HANDLE"; |
michael@0 | 852 | break; |
michael@0 | 853 | case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION: |
michael@0 | 854 | reason = "EXCEPTION_ILLEGAL_INSTRUCTION"; |
michael@0 | 855 | break; |
michael@0 | 856 | case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: |
michael@0 | 857 | reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION"; |
michael@0 | 858 | break; |
michael@0 | 859 | case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: |
michael@0 | 860 | reason = "EXCEPTION_INVALID_DISPOSITION"; |
michael@0 | 861 | break; |
michael@0 | 862 | case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED: |
michael@0 | 863 | reason = "EXCEPTION_BOUNDS_EXCEEDED"; |
michael@0 | 864 | break; |
michael@0 | 865 | case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND: |
michael@0 | 866 | reason = "EXCEPTION_FLT_DENORMAL_OPERAND"; |
michael@0 | 867 | break; |
michael@0 | 868 | case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO: |
michael@0 | 869 | reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO"; |
michael@0 | 870 | break; |
michael@0 | 871 | case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT: |
michael@0 | 872 | reason = "EXCEPTION_FLT_INEXACT_RESULT"; |
michael@0 | 873 | break; |
michael@0 | 874 | case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION: |
michael@0 | 875 | reason = "EXCEPTION_FLT_INVALID_OPERATION"; |
michael@0 | 876 | break; |
michael@0 | 877 | case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW: |
michael@0 | 878 | reason = "EXCEPTION_FLT_OVERFLOW"; |
michael@0 | 879 | break; |
michael@0 | 880 | case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK: |
michael@0 | 881 | reason = "EXCEPTION_FLT_STACK_CHECK"; |
michael@0 | 882 | break; |
michael@0 | 883 | case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW: |
michael@0 | 884 | reason = "EXCEPTION_FLT_UNDERFLOW"; |
michael@0 | 885 | break; |
michael@0 | 886 | case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO: |
michael@0 | 887 | reason = "EXCEPTION_INT_DIVIDE_BY_ZERO"; |
michael@0 | 888 | break; |
michael@0 | 889 | case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW: |
michael@0 | 890 | reason = "EXCEPTION_INT_OVERFLOW"; |
michael@0 | 891 | break; |
michael@0 | 892 | case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION: |
michael@0 | 893 | reason = "EXCEPTION_PRIV_INSTRUCTION"; |
michael@0 | 894 | break; |
michael@0 | 895 | case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW: |
michael@0 | 896 | reason = "EXCEPTION_STACK_OVERFLOW"; |
michael@0 | 897 | break; |
michael@0 | 898 | case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK: |
michael@0 | 899 | reason = "EXCEPTION_POSSIBLE_DEADLOCK"; |
michael@0 | 900 | break; |
michael@0 | 901 | case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: |
michael@0 | 902 | reason = "EXCEPTION_STACK_BUFFER_OVERRUN"; |
michael@0 | 903 | break; |
michael@0 | 904 | case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: |
michael@0 | 905 | reason = "EXCEPTION_HEAP_CORRUPTION"; |
michael@0 | 906 | break; |
michael@0 | 907 | case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION: |
michael@0 | 908 | reason = "Unhandled C++ Exception"; |
michael@0 | 909 | break; |
michael@0 | 910 | default: |
michael@0 | 911 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 912 | break; |
michael@0 | 913 | } |
michael@0 | 914 | break; |
michael@0 | 915 | } |
michael@0 | 916 | |
michael@0 | 917 | case MD_OS_ANDROID: |
michael@0 | 918 | case MD_OS_LINUX: { |
michael@0 | 919 | switch (exception_code) { |
michael@0 | 920 | case MD_EXCEPTION_CODE_LIN_SIGHUP: |
michael@0 | 921 | reason = "SIGHUP"; |
michael@0 | 922 | break; |
michael@0 | 923 | case MD_EXCEPTION_CODE_LIN_SIGINT: |
michael@0 | 924 | reason = "SIGINT"; |
michael@0 | 925 | break; |
michael@0 | 926 | case MD_EXCEPTION_CODE_LIN_SIGQUIT: |
michael@0 | 927 | reason = "SIGQUIT"; |
michael@0 | 928 | break; |
michael@0 | 929 | case MD_EXCEPTION_CODE_LIN_SIGILL: |
michael@0 | 930 | reason = "SIGILL"; |
michael@0 | 931 | break; |
michael@0 | 932 | case MD_EXCEPTION_CODE_LIN_SIGTRAP: |
michael@0 | 933 | reason = "SIGTRAP"; |
michael@0 | 934 | break; |
michael@0 | 935 | case MD_EXCEPTION_CODE_LIN_SIGABRT: |
michael@0 | 936 | reason = "SIGABRT"; |
michael@0 | 937 | break; |
michael@0 | 938 | case MD_EXCEPTION_CODE_LIN_SIGBUS: |
michael@0 | 939 | reason = "SIGBUS"; |
michael@0 | 940 | break; |
michael@0 | 941 | case MD_EXCEPTION_CODE_LIN_SIGFPE: |
michael@0 | 942 | reason = "SIGFPE"; |
michael@0 | 943 | break; |
michael@0 | 944 | case MD_EXCEPTION_CODE_LIN_SIGKILL: |
michael@0 | 945 | reason = "SIGKILL"; |
michael@0 | 946 | break; |
michael@0 | 947 | case MD_EXCEPTION_CODE_LIN_SIGUSR1: |
michael@0 | 948 | reason = "SIGUSR1"; |
michael@0 | 949 | break; |
michael@0 | 950 | case MD_EXCEPTION_CODE_LIN_SIGSEGV: |
michael@0 | 951 | reason = "SIGSEGV"; |
michael@0 | 952 | break; |
michael@0 | 953 | case MD_EXCEPTION_CODE_LIN_SIGUSR2: |
michael@0 | 954 | reason = "SIGUSR2"; |
michael@0 | 955 | break; |
michael@0 | 956 | case MD_EXCEPTION_CODE_LIN_SIGPIPE: |
michael@0 | 957 | reason = "SIGPIPE"; |
michael@0 | 958 | break; |
michael@0 | 959 | case MD_EXCEPTION_CODE_LIN_SIGALRM: |
michael@0 | 960 | reason = "SIGALRM"; |
michael@0 | 961 | break; |
michael@0 | 962 | case MD_EXCEPTION_CODE_LIN_SIGTERM: |
michael@0 | 963 | reason = "SIGTERM"; |
michael@0 | 964 | break; |
michael@0 | 965 | case MD_EXCEPTION_CODE_LIN_SIGSTKFLT: |
michael@0 | 966 | reason = "SIGSTKFLT"; |
michael@0 | 967 | break; |
michael@0 | 968 | case MD_EXCEPTION_CODE_LIN_SIGCHLD: |
michael@0 | 969 | reason = "SIGCHLD"; |
michael@0 | 970 | break; |
michael@0 | 971 | case MD_EXCEPTION_CODE_LIN_SIGCONT: |
michael@0 | 972 | reason = "SIGCONT"; |
michael@0 | 973 | break; |
michael@0 | 974 | case MD_EXCEPTION_CODE_LIN_SIGSTOP: |
michael@0 | 975 | reason = "SIGSTOP"; |
michael@0 | 976 | break; |
michael@0 | 977 | case MD_EXCEPTION_CODE_LIN_SIGTSTP: |
michael@0 | 978 | reason = "SIGTSTP"; |
michael@0 | 979 | break; |
michael@0 | 980 | case MD_EXCEPTION_CODE_LIN_SIGTTIN: |
michael@0 | 981 | reason = "SIGTTIN"; |
michael@0 | 982 | break; |
michael@0 | 983 | case MD_EXCEPTION_CODE_LIN_SIGTTOU: |
michael@0 | 984 | reason = "SIGTTOU"; |
michael@0 | 985 | break; |
michael@0 | 986 | case MD_EXCEPTION_CODE_LIN_SIGURG: |
michael@0 | 987 | reason = "SIGURG"; |
michael@0 | 988 | break; |
michael@0 | 989 | case MD_EXCEPTION_CODE_LIN_SIGXCPU: |
michael@0 | 990 | reason = "SIGXCPU"; |
michael@0 | 991 | break; |
michael@0 | 992 | case MD_EXCEPTION_CODE_LIN_SIGXFSZ: |
michael@0 | 993 | reason = "SIGXFSZ"; |
michael@0 | 994 | break; |
michael@0 | 995 | case MD_EXCEPTION_CODE_LIN_SIGVTALRM: |
michael@0 | 996 | reason = "SIGVTALRM"; |
michael@0 | 997 | break; |
michael@0 | 998 | case MD_EXCEPTION_CODE_LIN_SIGPROF: |
michael@0 | 999 | reason = "SIGPROF"; |
michael@0 | 1000 | break; |
michael@0 | 1001 | case MD_EXCEPTION_CODE_LIN_SIGWINCH: |
michael@0 | 1002 | reason = "SIGWINCH"; |
michael@0 | 1003 | break; |
michael@0 | 1004 | case MD_EXCEPTION_CODE_LIN_SIGIO: |
michael@0 | 1005 | reason = "SIGIO"; |
michael@0 | 1006 | break; |
michael@0 | 1007 | case MD_EXCEPTION_CODE_LIN_SIGPWR: |
michael@0 | 1008 | reason = "SIGPWR"; |
michael@0 | 1009 | break; |
michael@0 | 1010 | case MD_EXCEPTION_CODE_LIN_SIGSYS: |
michael@0 | 1011 | reason = "SIGSYS"; |
michael@0 | 1012 | break; |
michael@0 | 1013 | case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: |
michael@0 | 1014 | reason = "DUMP_REQUESTED"; |
michael@0 | 1015 | break; |
michael@0 | 1016 | default: |
michael@0 | 1017 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 1018 | break; |
michael@0 | 1019 | } |
michael@0 | 1020 | break; |
michael@0 | 1021 | } |
michael@0 | 1022 | |
michael@0 | 1023 | case MD_OS_SOLARIS: { |
michael@0 | 1024 | switch (exception_code) { |
michael@0 | 1025 | case MD_EXCEPTION_CODE_SOL_SIGHUP: |
michael@0 | 1026 | reason = "SIGHUP"; |
michael@0 | 1027 | break; |
michael@0 | 1028 | case MD_EXCEPTION_CODE_SOL_SIGINT: |
michael@0 | 1029 | reason = "SIGINT"; |
michael@0 | 1030 | break; |
michael@0 | 1031 | case MD_EXCEPTION_CODE_SOL_SIGQUIT: |
michael@0 | 1032 | reason = "SIGQUIT"; |
michael@0 | 1033 | break; |
michael@0 | 1034 | case MD_EXCEPTION_CODE_SOL_SIGILL: |
michael@0 | 1035 | reason = "SIGILL"; |
michael@0 | 1036 | break; |
michael@0 | 1037 | case MD_EXCEPTION_CODE_SOL_SIGTRAP: |
michael@0 | 1038 | reason = "SIGTRAP"; |
michael@0 | 1039 | break; |
michael@0 | 1040 | case MD_EXCEPTION_CODE_SOL_SIGIOT: |
michael@0 | 1041 | reason = "SIGIOT | SIGABRT"; |
michael@0 | 1042 | break; |
michael@0 | 1043 | case MD_EXCEPTION_CODE_SOL_SIGEMT: |
michael@0 | 1044 | reason = "SIGEMT"; |
michael@0 | 1045 | break; |
michael@0 | 1046 | case MD_EXCEPTION_CODE_SOL_SIGFPE: |
michael@0 | 1047 | reason = "SIGFPE"; |
michael@0 | 1048 | break; |
michael@0 | 1049 | case MD_EXCEPTION_CODE_SOL_SIGKILL: |
michael@0 | 1050 | reason = "SIGKILL"; |
michael@0 | 1051 | break; |
michael@0 | 1052 | case MD_EXCEPTION_CODE_SOL_SIGBUS: |
michael@0 | 1053 | reason = "SIGBUS"; |
michael@0 | 1054 | break; |
michael@0 | 1055 | case MD_EXCEPTION_CODE_SOL_SIGSEGV: |
michael@0 | 1056 | reason = "SIGSEGV"; |
michael@0 | 1057 | break; |
michael@0 | 1058 | case MD_EXCEPTION_CODE_SOL_SIGSYS: |
michael@0 | 1059 | reason = "SIGSYS"; |
michael@0 | 1060 | break; |
michael@0 | 1061 | case MD_EXCEPTION_CODE_SOL_SIGPIPE: |
michael@0 | 1062 | reason = "SIGPIPE"; |
michael@0 | 1063 | break; |
michael@0 | 1064 | case MD_EXCEPTION_CODE_SOL_SIGALRM: |
michael@0 | 1065 | reason = "SIGALRM"; |
michael@0 | 1066 | break; |
michael@0 | 1067 | case MD_EXCEPTION_CODE_SOL_SIGTERM: |
michael@0 | 1068 | reason = "SIGTERM"; |
michael@0 | 1069 | break; |
michael@0 | 1070 | case MD_EXCEPTION_CODE_SOL_SIGUSR1: |
michael@0 | 1071 | reason = "SIGUSR1"; |
michael@0 | 1072 | break; |
michael@0 | 1073 | case MD_EXCEPTION_CODE_SOL_SIGUSR2: |
michael@0 | 1074 | reason = "SIGUSR2"; |
michael@0 | 1075 | break; |
michael@0 | 1076 | case MD_EXCEPTION_CODE_SOL_SIGCLD: |
michael@0 | 1077 | reason = "SIGCLD | SIGCHLD"; |
michael@0 | 1078 | break; |
michael@0 | 1079 | case MD_EXCEPTION_CODE_SOL_SIGPWR: |
michael@0 | 1080 | reason = "SIGPWR"; |
michael@0 | 1081 | break; |
michael@0 | 1082 | case MD_EXCEPTION_CODE_SOL_SIGWINCH: |
michael@0 | 1083 | reason = "SIGWINCH"; |
michael@0 | 1084 | break; |
michael@0 | 1085 | case MD_EXCEPTION_CODE_SOL_SIGURG: |
michael@0 | 1086 | reason = "SIGURG"; |
michael@0 | 1087 | break; |
michael@0 | 1088 | case MD_EXCEPTION_CODE_SOL_SIGPOLL: |
michael@0 | 1089 | reason = "SIGPOLL | SIGIO"; |
michael@0 | 1090 | break; |
michael@0 | 1091 | case MD_EXCEPTION_CODE_SOL_SIGSTOP: |
michael@0 | 1092 | reason = "SIGSTOP"; |
michael@0 | 1093 | break; |
michael@0 | 1094 | case MD_EXCEPTION_CODE_SOL_SIGTSTP: |
michael@0 | 1095 | reason = "SIGTSTP"; |
michael@0 | 1096 | break; |
michael@0 | 1097 | case MD_EXCEPTION_CODE_SOL_SIGCONT: |
michael@0 | 1098 | reason = "SIGCONT"; |
michael@0 | 1099 | break; |
michael@0 | 1100 | case MD_EXCEPTION_CODE_SOL_SIGTTIN: |
michael@0 | 1101 | reason = "SIGTTIN"; |
michael@0 | 1102 | break; |
michael@0 | 1103 | case MD_EXCEPTION_CODE_SOL_SIGTTOU: |
michael@0 | 1104 | reason = "SIGTTOU"; |
michael@0 | 1105 | break; |
michael@0 | 1106 | case MD_EXCEPTION_CODE_SOL_SIGVTALRM: |
michael@0 | 1107 | reason = "SIGVTALRM"; |
michael@0 | 1108 | break; |
michael@0 | 1109 | case MD_EXCEPTION_CODE_SOL_SIGPROF: |
michael@0 | 1110 | reason = "SIGPROF"; |
michael@0 | 1111 | break; |
michael@0 | 1112 | case MD_EXCEPTION_CODE_SOL_SIGXCPU: |
michael@0 | 1113 | reason = "SIGXCPU"; |
michael@0 | 1114 | break; |
michael@0 | 1115 | case MD_EXCEPTION_CODE_SOL_SIGXFSZ: |
michael@0 | 1116 | reason = "SIGXFSZ"; |
michael@0 | 1117 | break; |
michael@0 | 1118 | case MD_EXCEPTION_CODE_SOL_SIGWAITING: |
michael@0 | 1119 | reason = "SIGWAITING"; |
michael@0 | 1120 | break; |
michael@0 | 1121 | case MD_EXCEPTION_CODE_SOL_SIGLWP: |
michael@0 | 1122 | reason = "SIGLWP"; |
michael@0 | 1123 | break; |
michael@0 | 1124 | case MD_EXCEPTION_CODE_SOL_SIGFREEZE: |
michael@0 | 1125 | reason = "SIGFREEZE"; |
michael@0 | 1126 | break; |
michael@0 | 1127 | case MD_EXCEPTION_CODE_SOL_SIGTHAW: |
michael@0 | 1128 | reason = "SIGTHAW"; |
michael@0 | 1129 | break; |
michael@0 | 1130 | case MD_EXCEPTION_CODE_SOL_SIGCANCEL: |
michael@0 | 1131 | reason = "SIGCANCEL"; |
michael@0 | 1132 | break; |
michael@0 | 1133 | case MD_EXCEPTION_CODE_SOL_SIGLOST: |
michael@0 | 1134 | reason = "SIGLOST"; |
michael@0 | 1135 | break; |
michael@0 | 1136 | case MD_EXCEPTION_CODE_SOL_SIGXRES: |
michael@0 | 1137 | reason = "SIGXRES"; |
michael@0 | 1138 | break; |
michael@0 | 1139 | case MD_EXCEPTION_CODE_SOL_SIGJVM1: |
michael@0 | 1140 | reason = "SIGJVM1"; |
michael@0 | 1141 | break; |
michael@0 | 1142 | case MD_EXCEPTION_CODE_SOL_SIGJVM2: |
michael@0 | 1143 | reason = "SIGJVM2"; |
michael@0 | 1144 | break; |
michael@0 | 1145 | default: |
michael@0 | 1146 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 1147 | break; |
michael@0 | 1148 | } |
michael@0 | 1149 | break; |
michael@0 | 1150 | } |
michael@0 | 1151 | |
michael@0 | 1152 | default: { |
michael@0 | 1153 | BPLOG(INFO) << "Unknown exception reason " << reason; |
michael@0 | 1154 | break; |
michael@0 | 1155 | } |
michael@0 | 1156 | } |
michael@0 | 1157 | |
michael@0 | 1158 | return reason; |
michael@0 | 1159 | } |
michael@0 | 1160 | |
michael@0 | 1161 | // static |
michael@0 | 1162 | string MinidumpProcessor::GetAssertion(Minidump *dump) { |
michael@0 | 1163 | MinidumpAssertion *assertion = dump->GetAssertion(); |
michael@0 | 1164 | if (!assertion) |
michael@0 | 1165 | return ""; |
michael@0 | 1166 | |
michael@0 | 1167 | const MDRawAssertionInfo *raw_assertion = assertion->assertion(); |
michael@0 | 1168 | if (!raw_assertion) |
michael@0 | 1169 | return ""; |
michael@0 | 1170 | |
michael@0 | 1171 | string assertion_string; |
michael@0 | 1172 | switch (raw_assertion->type) { |
michael@0 | 1173 | case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER: |
michael@0 | 1174 | assertion_string = "Invalid parameter passed to library function"; |
michael@0 | 1175 | break; |
michael@0 | 1176 | case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL: |
michael@0 | 1177 | assertion_string = "Pure virtual function called"; |
michael@0 | 1178 | break; |
michael@0 | 1179 | default: { |
michael@0 | 1180 | char assertion_type[32]; |
michael@0 | 1181 | snprintf(assertion_type, sizeof(assertion_type), |
michael@0 | 1182 | "0x%08x", raw_assertion->type); |
michael@0 | 1183 | assertion_string = "Unknown assertion type "; |
michael@0 | 1184 | assertion_string += assertion_type; |
michael@0 | 1185 | break; |
michael@0 | 1186 | } |
michael@0 | 1187 | } |
michael@0 | 1188 | |
michael@0 | 1189 | string expression = assertion->expression(); |
michael@0 | 1190 | if (!expression.empty()) { |
michael@0 | 1191 | assertion_string.append(" " + expression); |
michael@0 | 1192 | } |
michael@0 | 1193 | |
michael@0 | 1194 | string function = assertion->function(); |
michael@0 | 1195 | if (!function.empty()) { |
michael@0 | 1196 | assertion_string.append(" in function " + function); |
michael@0 | 1197 | } |
michael@0 | 1198 | |
michael@0 | 1199 | string file = assertion->file(); |
michael@0 | 1200 | if (!file.empty()) { |
michael@0 | 1201 | assertion_string.append(", in file " + file); |
michael@0 | 1202 | } |
michael@0 | 1203 | |
michael@0 | 1204 | if (raw_assertion->line != 0) { |
michael@0 | 1205 | char assertion_line[32]; |
michael@0 | 1206 | snprintf(assertion_line, sizeof(assertion_line), "%u", raw_assertion->line); |
michael@0 | 1207 | assertion_string.append(" at line "); |
michael@0 | 1208 | assertion_string.append(assertion_line); |
michael@0 | 1209 | } |
michael@0 | 1210 | |
michael@0 | 1211 | return assertion_string; |
michael@0 | 1212 | } |
michael@0 | 1213 | |
michael@0 | 1214 | } // namespace google_breakpad |