1 // Copyright (c) 2010, 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 // This code writes out minidump files: 31 // http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx 32 // 33 // Minidumps are a Microsoft format which Breakpad uses for recording crash 34 // dumps. This code has to run in a compromised environment (the address space 35 // may have received SIGSEGV), thus the following rules apply: 36 // * You may not enter the dynamic linker. This means that we cannot call 37 // any symbols in a shared library (inc libc). Because of this we replace 38 // libc functions in linux_libc_support.h. 39 // * You may not call syscalls via the libc wrappers. This rule is a subset 40 // of the first rule but it bears repeating. We have direct wrappers 41 // around the system calls in linux_syscall_support.h. 42 // * You may not malloc. There's an alternative allocator in memory.h and 43 // a canonical instance in the LinuxDumper object. We use the placement 44 // new form to allocate objects and we don't delete them. 45 46 #include "client/linux/handler/minidump_descriptor.h" 47 #include "client/linux/minidump_writer/minidump_writer.h" 48 #include "client/minidump_file_writer-inl.h" 49 50 #include <ctype.h> 51 #include <errno.h> 52 #include <fcntl.h> 53 #include <link.h> 54 #include <stdio.h> 55 #if defined(__ANDROID__) 56 #include <sys/system_properties.h> 57 #endif 58 #include <sys/types.h> 59 #include <sys/ucontext.h> 60 #include <sys/user.h> 61 #include <sys/utsname.h> 62 #include <time.h> 63 #include <unistd.h> 64 65 #include <algorithm> 66 67 #include "client/linux/dump_writer_common/seccomp_unwinder.h" 68 #include "client/linux/dump_writer_common/thread_info.h" 69 #include "client/linux/dump_writer_common/ucontext_reader.h" 70 #include "client/linux/handler/exception_handler.h" 71 #include "client/linux/minidump_writer/cpu_set.h" 72 #include "client/linux/minidump_writer/line_reader.h" 73 #include "client/linux/minidump_writer/linux_dumper.h" 74 #include "client/linux/minidump_writer/linux_ptrace_dumper.h" 75 #include "client/linux/minidump_writer/proc_cpuinfo_reader.h" 76 #include "client/minidump_file_writer.h" 77 #include "common/linux/linux_libc_support.h" 78 #include "common/minidump_type_helper.h" 79 #include "google_breakpad/common/minidump_format.h" 80 #include "third_party/lss/linux_syscall_support.h" 81 82 namespace { 83 84 using google_breakpad::AppMemoryList; 85 using google_breakpad::ExceptionHandler; 86 using google_breakpad::CpuSet; 87 using google_breakpad::LineReader; 88 using google_breakpad::LinuxDumper; 89 using google_breakpad::LinuxPtraceDumper; 90 using google_breakpad::MDTypeHelper; 91 using google_breakpad::MappingEntry; 92 using google_breakpad::MappingInfo; 93 using google_breakpad::MappingList; 94 using google_breakpad::MinidumpFileWriter; 95 using google_breakpad::PageAllocator; 96 using google_breakpad::ProcCpuInfoReader; 97 using google_breakpad::RawContextCPU; 98 using google_breakpad::SeccompUnwinder; 99 using google_breakpad::ThreadInfo; 100 using google_breakpad::TypedMDRVA; 101 using google_breakpad::UContextReader; 102 using google_breakpad::UntypedMDRVA; 103 using google_breakpad::wasteful_vector; 104 105 typedef MDTypeHelper<sizeof(void*)>::MDRawDebug MDRawDebug; 106 typedef MDTypeHelper<sizeof(void*)>::MDRawLinkMap MDRawLinkMap; 107 108 class MinidumpWriter { 109 public: 110 // The following kLimit* constants are for when minidump_size_limit_ is set 111 // and the minidump size might exceed it. 112 // 113 // Estimate for how big each thread's stack will be (in bytes). 114 static const unsigned kLimitAverageThreadStackLength = 8 * 1024; 115 // Number of threads whose stack size we don't want to limit. These base 116 // threads will simply be the first N threads returned by the dumper (although 117 // the crashing thread will never be limited). Threads beyond this count are 118 // the extra threads. 119 static const unsigned kLimitBaseThreadCount = 20; 120 // Maximum stack size to dump for any extra thread (in bytes). 121 static const unsigned kLimitMaxExtraThreadStackLen = 2 * 1024; 122 // Make sure this number of additional bytes can fit in the minidump 123 // (exclude the stack data). 124 static const unsigned kLimitMinidumpFudgeFactor = 64 * 1024; 125 126 MinidumpWriter(const char* minidump_path, 127 int minidump_fd, 128 const ExceptionHandler::CrashContext* context, 129 const MappingList& mappings, 130 const AppMemoryList& appmem, 131 LinuxDumper* dumper) 132 : fd_(minidump_fd), 133 path_(minidump_path), 134 ucontext_(context ? &context->context : NULL), 135 #if !defined(__ARM_EABI__) && !defined(__mips__) 136 float_state_(context ? &context->float_state : NULL), 137 #endif 138 dumper_(dumper), 139 minidump_size_limit_(-1), 140 memory_blocks_(dumper_->allocator()), 141 mapping_list_(mappings), 142 app_memory_list_(appmem) { 143 // Assert there should be either a valid fd or a valid path, not both. 144 assert(fd_ != -1 || minidump_path); 145 assert(fd_ == -1 || !minidump_path); 146 } 147 148 bool Init() { 149 if (!dumper_->Init()) 150 return false; 151 152 if (fd_ != -1) 153 minidump_writer_.SetFile(fd_); 154 else if (!minidump_writer_.Open(path_)) 155 return false; 156 157 return dumper_->ThreadsSuspend(); 158 } 159 160 ~MinidumpWriter() { 161 // Don't close the file descriptor when it's been provided explicitly. 162 // Callers might still need to use it. 163 if (fd_ == -1) 164 minidump_writer_.Close(); 165 dumper_->ThreadsResume(); 166 } 167 168 bool Dump() { 169 // A minidump file contains a number of tagged streams. This is the number 170 // of stream which we write. 171 unsigned kNumWriters = 13; 172 173 TypedMDRVA<MDRawHeader> header(&minidump_writer_); 174 TypedMDRVA<MDRawDirectory> dir(&minidump_writer_); 175 if (!header.Allocate()) 176 return false; 177 if (!dir.AllocateArray(kNumWriters)) 178 return false; 179 my_memset(header.get(), 0, sizeof(MDRawHeader)); 180 181 header.get()->signature = MD_HEADER_SIGNATURE; 182 header.get()->version = MD_HEADER_VERSION; 183 header.get()->time_date_stamp = time(NULL); 184 header.get()->stream_count = kNumWriters; 185 header.get()->stream_directory_rva = dir.position(); 186 187 unsigned dir_index = 0; 188 MDRawDirectory dirent; 189 190 if (!WriteThreadListStream(&dirent)) 191 return false; 192 dir.CopyIndex(dir_index++, &dirent); 193 194 if (!WriteMappings(&dirent)) 195 return false; 196 dir.CopyIndex(dir_index++, &dirent); 197 198 if (!WriteAppMemory()) 199 return false; 200 201 if (!WriteMemoryListStream(&dirent)) 202 return false; 203 dir.CopyIndex(dir_index++, &dirent); 204 205 if (!WriteExceptionStream(&dirent)) 206 return false; 207 dir.CopyIndex(dir_index++, &dirent); 208 209 if (!WriteSystemInfoStream(&dirent)) 210 return false; 211 dir.CopyIndex(dir_index++, &dirent); 212 213 dirent.stream_type = MD_LINUX_CPU_INFO; 214 if (!WriteFile(&dirent.location, "/proc/cpuinfo")) 215 NullifyDirectoryEntry(&dirent); 216 dir.CopyIndex(dir_index++, &dirent); 217 218 dirent.stream_type = MD_LINUX_PROC_STATUS; 219 if (!WriteProcFile(&dirent.location, GetCrashThread(), "status")) 220 NullifyDirectoryEntry(&dirent); 221 dir.CopyIndex(dir_index++, &dirent); 222 223 dirent.stream_type = MD_LINUX_LSB_RELEASE; 224 if (!WriteFile(&dirent.location, "/etc/lsb-release")) 225 NullifyDirectoryEntry(&dirent); 226 dir.CopyIndex(dir_index++, &dirent); 227 228 dirent.stream_type = MD_LINUX_CMD_LINE; 229 if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline")) 230 NullifyDirectoryEntry(&dirent); 231 dir.CopyIndex(dir_index++, &dirent); 232 233 dirent.stream_type = MD_LINUX_ENVIRON; 234 if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ")) 235 NullifyDirectoryEntry(&dirent); 236 dir.CopyIndex(dir_index++, &dirent); 237 238 dirent.stream_type = MD_LINUX_AUXV; 239 if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv")) 240 NullifyDirectoryEntry(&dirent); 241 dir.CopyIndex(dir_index++, &dirent); 242 243 dirent.stream_type = MD_LINUX_MAPS; 244 if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps")) 245 NullifyDirectoryEntry(&dirent); 246 dir.CopyIndex(dir_index++, &dirent); 247 248 dirent.stream_type = MD_LINUX_DSO_DEBUG; 249 if (!WriteDSODebugStream(&dirent)) 250 NullifyDirectoryEntry(&dirent); 251 dir.CopyIndex(dir_index++, &dirent); 252 253 // If you add more directory entries, don't forget to update kNumWriters, 254 // above. 255 256 dumper_->ThreadsResume(); 257 return true; 258 } 259 260 bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, 261 int max_stack_len, uint8_t** stack_copy) { 262 *stack_copy = NULL; 263 const void* stack; 264 size_t stack_len; 265 if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { 266 UntypedMDRVA memory(&minidump_writer_); 267 if (max_stack_len >= 0 && 268 stack_len > static_cast<unsigned int>(max_stack_len)) { 269 stack_len = max_stack_len; 270 } 271 if (!memory.Allocate(stack_len)) 272 return false; 273 *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len)); 274 dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack, 275 stack_len); 276 memory.Copy(*stack_copy, stack_len); 277 thread->stack.start_of_memory_range = 278 reinterpret_cast<uintptr_t>(stack); 279 thread->stack.memory = memory.location(); 280 memory_blocks_.push_back(thread->stack); 281 } else { 282 thread->stack.start_of_memory_range = stack_pointer; 283 thread->stack.memory.data_size = 0; 284 thread->stack.memory.rva = minidump_writer_.position(); 285 } 286 return true; 287 } 288 289 // Write information about the threads. 290 bool WriteThreadListStream(MDRawDirectory* dirent) { 291 const unsigned num_threads = dumper_->threads().size(); 292 293 TypedMDRVA<uint32_t> list(&minidump_writer_); 294 if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread))) 295 return false; 296 297 dirent->stream_type = MD_THREAD_LIST_STREAM; 298 dirent->location = list.location(); 299 300 *list.get() = num_threads; 301 302 // If there's a minidump size limit, check if it might be exceeded. Since 303 // most of the space is filled with stack data, just check against that. 304 // If this expects to exceed the limit, set extra_thread_stack_len such 305 // that any thread beyond the first kLimitBaseThreadCount threads will 306 // have only kLimitMaxExtraThreadStackLen bytes dumped. 307 int extra_thread_stack_len = -1; // default to no maximum 308 if (minidump_size_limit_ >= 0) { 309 const unsigned estimated_total_stack_size = num_threads * 310 kLimitAverageThreadStackLength; 311 const off_t estimated_minidump_size = minidump_writer_.position() + 312 estimated_total_stack_size + kLimitMinidumpFudgeFactor; 313 if (estimated_minidump_size > minidump_size_limit_) 314 extra_thread_stack_len = kLimitMaxExtraThreadStackLen; 315 } 316 317 for (unsigned i = 0; i < num_threads; ++i) { 318 MDRawThread thread; 319 my_memset(&thread, 0, sizeof(thread)); 320 thread.thread_id = dumper_->threads()[i]; 321 322 // We have a different source of information for the crashing thread. If 323 // we used the actual state of the thread we would find it running in the 324 // signal handler with the alternative stack, which would be deeply 325 // unhelpful. 326 if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() && 327 ucontext_ && 328 !dumper_->IsPostMortem()) { 329 uint8_t* stack_copy; 330 const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); 331 if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy)) 332 return false; 333 334 // Copy 256 bytes around crashing instruction pointer to minidump. 335 const size_t kIPMemorySize = 256; 336 uint64_t ip = UContextReader::GetInstructionPointer(ucontext_); 337 // Bound it to the upper and lower bounds of the memory map 338 // it's contained within. If it's not in mapped memory, 339 // don't bother trying to write it. 340 bool ip_is_mapped = false; 341 MDMemoryDescriptor ip_memory_d; 342 for (unsigned j = 0; j < dumper_->mappings().size(); ++j) { 343 const MappingInfo& mapping = *dumper_->mappings()[j]; 344 if (ip >= mapping.start_addr && 345 ip < mapping.start_addr + mapping.size) { 346 ip_is_mapped = true; 347 // Try to get 128 bytes before and after the IP, but 348 // settle for whatever's available. 349 ip_memory_d.start_of_memory_range = 350 std::max(mapping.start_addr, 351 uintptr_t(ip - (kIPMemorySize / 2))); 352 uintptr_t end_of_range = 353 std::min(uintptr_t(ip + (kIPMemorySize / 2)), 354 uintptr_t(mapping.start_addr + mapping.size)); 355 ip_memory_d.memory.data_size = 356 end_of_range - ip_memory_d.start_of_memory_range; 357 break; 358 } 359 } 360 361 if (ip_is_mapped) { 362 UntypedMDRVA ip_memory(&minidump_writer_); 363 if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) 364 return false; 365 uint8_t* memory_copy = 366 reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size)); 367 dumper_->CopyFromProcess( 368 memory_copy, 369 thread.thread_id, 370 reinterpret_cast<void*>(ip_memory_d.start_of_memory_range), 371 ip_memory_d.memory.data_size); 372 ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size); 373 ip_memory_d.memory = ip_memory.location(); 374 memory_blocks_.push_back(ip_memory_d); 375 } 376 377 TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); 378 if (!cpu.Allocate()) 379 return false; 380 my_memset(cpu.get(), 0, sizeof(RawContextCPU)); 381 #if !defined(__ARM_EABI__) && !defined(__mips__) 382 UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); 383 #else 384 UContextReader::FillCPUContext(cpu.get(), ucontext_); 385 #endif 386 if (stack_copy) 387 SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); 388 thread.thread_context = cpu.location(); 389 crashing_thread_context_ = cpu.location(); 390 } else { 391 ThreadInfo info; 392 if (!dumper_->GetThreadInfoByIndex(i, &info)) 393 return false; 394 395 uint8_t* stack_copy; 396 int max_stack_len = -1; // default to no maximum for this thread 397 if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount) 398 max_stack_len = extra_thread_stack_len; 399 if (!FillThreadStack(&thread, info.stack_pointer, max_stack_len, 400 &stack_copy)) 401 return false; 402 403 TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); 404 if (!cpu.Allocate()) 405 return false; 406 my_memset(cpu.get(), 0, sizeof(RawContextCPU)); 407 info.FillCPUContext(cpu.get()); 408 if (stack_copy) 409 SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); 410 thread.thread_context = cpu.location(); 411 if (dumper_->threads()[i] == GetCrashThread()) { 412 crashing_thread_context_ = cpu.location(); 413 if (!dumper_->IsPostMortem()) { 414 // This is the crashing thread of a live process, but 415 // no context was provided, so set the crash address 416 // while the instruction pointer is already here. 417 dumper_->set_crash_address(info.GetInstructionPointer()); 418 } 419 } 420 } 421 422 list.CopyIndexAfterObject(i, &thread, sizeof(thread)); 423 } 424 425 return true; 426 } 427 428 // Write application-provided memory regions. 429 bool WriteAppMemory() { 430 for (AppMemoryList::const_iterator iter = app_memory_list_.begin(); 431 iter != app_memory_list_.end(); 432 ++iter) { 433 uint8_t* data_copy = 434 reinterpret_cast<uint8_t*>(dumper_->allocator()->Alloc(iter->length)); 435 dumper_->CopyFromProcess(data_copy, GetCrashThread(), iter->ptr, 436 iter->length); 437 438 UntypedMDRVA memory(&minidump_writer_); 439 if (!memory.Allocate(iter->length)) { 440 return false; 441 } 442 memory.Copy(data_copy, iter->length); 443 MDMemoryDescriptor desc; 444 desc.start_of_memory_range = reinterpret_cast<uintptr_t>(iter->ptr); 445 desc.memory = memory.location(); 446 memory_blocks_.push_back(desc); 447 } 448 449 return true; 450 } 451 452 static bool ShouldIncludeMapping(const MappingInfo& mapping) { 453 if (mapping.name[0] == 0 || // only want modules with filenames. 454 // Only want to include one mapping per shared lib. 455 // Avoid filtering executable mappings. 456 (mapping.offset != 0 && !mapping.exec) || 457 mapping.size < 4096) { // too small to get a signature for. 458 return false; 459 } 460 461 return true; 462 } 463 464 // If there is caller-provided information about this mapping 465 // in the mapping_list_ list, return true. Otherwise, return false. 466 bool HaveMappingInfo(const MappingInfo& mapping) { 467 for (MappingList::const_iterator iter = mapping_list_.begin(); 468 iter != mapping_list_.end(); 469 ++iter) { 470 // Ignore any mappings that are wholly contained within 471 // mappings in the mapping_info_ list. 472 if (mapping.start_addr >= iter->first.start_addr && 473 (mapping.start_addr + mapping.size) <= 474 (iter->first.start_addr + iter->first.size)) { 475 return true; 476 } 477 } 478 return false; 479 } 480 481 // Write information about the mappings in effect. Because we are using the 482 // minidump format, the information about the mappings is pretty limited. 483 // Because of this, we also include the full, unparsed, /proc/$x/maps file in 484 // another stream in the file. 485 bool WriteMappings(MDRawDirectory* dirent) { 486 const unsigned num_mappings = dumper_->mappings().size(); 487 unsigned num_output_mappings = mapping_list_.size(); 488 489 for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { 490 const MappingInfo& mapping = *dumper_->mappings()[i]; 491 if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping)) 492 num_output_mappings++; 493 } 494 495 TypedMDRVA<uint32_t> list(&minidump_writer_); 496 if (num_output_mappings) { 497 if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE)) 498 return false; 499 } else { 500 // Still create the module list stream, although it will have zero 501 // modules. 502 if (!list.Allocate()) 503 return false; 504 } 505 506 dirent->stream_type = MD_MODULE_LIST_STREAM; 507 dirent->location = list.location(); 508 *list.get() = num_output_mappings; 509 510 // First write all the mappings from the dumper 511 unsigned int j = 0; 512 for (unsigned i = 0; i < num_mappings; ++i) { 513 const MappingInfo& mapping = *dumper_->mappings()[i]; 514 if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping)) 515 continue; 516 517 MDRawModule mod; 518 if (!FillRawModule(mapping, true, i, mod, NULL)) 519 return false; 520 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); 521 } 522 // Next write all the mappings provided by the caller 523 for (MappingList::const_iterator iter = mapping_list_.begin(); 524 iter != mapping_list_.end(); 525 ++iter) { 526 MDRawModule mod; 527 if (!FillRawModule(iter->first, false, 0, mod, iter->second)) 528 return false; 529 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); 530 } 531 532 return true; 533 } 534 535 // Fill the MDRawModule |mod| with information about the provided 536 // |mapping|. If |identifier| is non-NULL, use it instead of calculating 537 // a file ID from the mapping. 538 bool FillRawModule(const MappingInfo& mapping, 539 bool member, 540 unsigned int mapping_id, 541 MDRawModule& mod, 542 const uint8_t* identifier) { 543 my_memset(&mod, 0, MD_MODULE_SIZE); 544 545 mod.base_of_image = mapping.start_addr; 546 mod.size_of_image = mapping.size; 547 548 uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; 549 uint8_t* cv_ptr = cv_buf; 550 551 const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; 552 my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); 553 cv_ptr += sizeof(cv_signature); 554 uint8_t* signature = cv_ptr; 555 cv_ptr += sizeof(MDGUID); 556 if (identifier) { 557 // GUID was provided by caller. 558 my_memcpy(signature, identifier, sizeof(MDGUID)); 559 } else { 560 // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|. 561 dumper_->ElfFileIdentifierForMapping(mapping, member, 562 mapping_id, signature); 563 } 564 my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. 565 cv_ptr += sizeof(uint32_t); 566 567 char file_name[NAME_MAX]; 568 char file_path[NAME_MAX]; 569 LinuxDumper::GetMappingEffectiveNameAndPath( 570 mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); 571 572 const size_t file_name_len = my_strlen(file_name); 573 UntypedMDRVA cv(&minidump_writer_); 574 if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1)) 575 return false; 576 577 // Write pdb_file_name 578 my_memcpy(cv_ptr, file_name, file_name_len + 1); 579 cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1); 580 581 mod.cv_record = cv.location(); 582 583 MDLocationDescriptor ld; 584 if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) 585 return false; 586 mod.module_name_rva = ld.rva; 587 return true; 588 } 589 590 bool WriteMemoryListStream(MDRawDirectory* dirent) { 591 TypedMDRVA<uint32_t> list(&minidump_writer_); 592 if (memory_blocks_.size()) { 593 if (!list.AllocateObjectAndArray(memory_blocks_.size(), 594 sizeof(MDMemoryDescriptor))) 595 return false; 596 } else { 597 // Still create the memory list stream, although it will have zero 598 // memory blocks. 599 if (!list.Allocate()) 600 return false; 601 } 602 603 dirent->stream_type = MD_MEMORY_LIST_STREAM; 604 dirent->location = list.location(); 605 606 *list.get() = memory_blocks_.size(); 607 608 for (size_t i = 0; i < memory_blocks_.size(); ++i) { 609 list.CopyIndexAfterObject(i, &memory_blocks_[i], 610 sizeof(MDMemoryDescriptor)); 611 } 612 return true; 613 } 614 615 bool WriteExceptionStream(MDRawDirectory* dirent) { 616 TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_); 617 if (!exc.Allocate()) 618 return false; 619 my_memset(exc.get(), 0, sizeof(MDRawExceptionStream)); 620 621 dirent->stream_type = MD_EXCEPTION_STREAM; 622 dirent->location = exc.location(); 623 624 exc.get()->thread_id = GetCrashThread(); 625 exc.get()->exception_record.exception_code = dumper_->crash_signal(); 626 exc.get()->exception_record.exception_address = dumper_->crash_address(); 627 exc.get()->thread_context = crashing_thread_context_; 628 629 return true; 630 } 631 632 bool WriteSystemInfoStream(MDRawDirectory* dirent) { 633 TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_); 634 if (!si.Allocate()) 635 return false; 636 my_memset(si.get(), 0, sizeof(MDRawSystemInfo)); 637 638 dirent->stream_type = MD_SYSTEM_INFO_STREAM; 639 dirent->location = si.location(); 640 641 WriteCPUInformation(si.get()); 642 WriteOSInformation(si.get()); 643 644 return true; 645 } 646 647 bool WriteDSODebugStream(MDRawDirectory* dirent) { 648 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]); 649 char* base; 650 int phnum = dumper_->auxv()[AT_PHNUM]; 651 if (!phnum || !phdr) 652 return false; 653 654 // Assume the program base is at the beginning of the same page as the PHDR 655 base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff); 656 657 // Search for the program PT_DYNAMIC segment 658 ElfW(Addr) dyn_addr = 0; 659 for (; phnum >= 0; phnum--, phdr++) { 660 ElfW(Phdr) ph; 661 if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph))) 662 return false; 663 664 // Adjust base address with the virtual address of the PT_LOAD segment 665 // corresponding to offset 0 666 if (ph.p_type == PT_LOAD && ph.p_offset == 0) { 667 base -= ph.p_vaddr; 668 } 669 if (ph.p_type == PT_DYNAMIC) { 670 dyn_addr = ph.p_vaddr; 671 } 672 } 673 if (!dyn_addr) 674 return false; 675 676 ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base); 677 678 // The dynamic linker makes information available that helps gdb find all 679 // DSOs loaded into the program. If this information is indeed available, 680 // dump it to a MD_LINUX_DSO_DEBUG stream. 681 struct r_debug* r_debug = NULL; 682 uint32_t dynamic_length = 0; 683 684 for (int i = 0; ; ++i) { 685 ElfW(Dyn) dyn; 686 dynamic_length += sizeof(dyn); 687 if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i, 688 sizeof(dyn))) { 689 return false; 690 } 691 692 #ifdef __mips__ 693 if (dyn.d_tag == DT_MIPS_RLD_MAP) { 694 r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr); 695 continue; 696 } 697 #else 698 if (dyn.d_tag == DT_DEBUG) { 699 r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr); 700 continue; 701 } 702 #endif 703 else if (dyn.d_tag == DT_NULL) { 704 break; 705 } 706 } 707 708 // The "r_map" field of that r_debug struct contains a linked list of all 709 // loaded DSOs. 710 // Our list of DSOs potentially is different from the ones in the crashing 711 // process. So, we have to be careful to never dereference pointers 712 // directly. Instead, we use CopyFromProcess() everywhere. 713 // See <link.h> for a more detailed discussion of the how the dynamic 714 // loader communicates with debuggers. 715 716 // Count the number of loaded DSOs 717 int dso_count = 0; 718 struct r_debug debug_entry; 719 if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug, 720 sizeof(debug_entry))) { 721 return false; 722 } 723 for (struct link_map* ptr = debug_entry.r_map; ptr; ) { 724 struct link_map map; 725 if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map))) 726 return false; 727 728 ptr = map.l_next; 729 dso_count++; 730 } 731 732 MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA; 733 if (dso_count > 0) { 734 // If we have at least one DSO, create an array of MDRawLinkMap 735 // entries in the minidump file. 736 TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_); 737 if (!linkmap.AllocateArray(dso_count)) 738 return false; 739 linkmap_rva = linkmap.location().rva; 740 int idx = 0; 741 742 // Iterate over DSOs and write their information to mini dump 743 for (struct link_map* ptr = debug_entry.r_map; ptr; ) { 744 struct link_map map; 745 if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map))) 746 return false; 747 748 ptr = map.l_next; 749 char filename[257] = { 0 }; 750 if (map.l_name) { 751 dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name, 752 sizeof(filename) - 1); 753 } 754 MDLocationDescriptor location; 755 if (!minidump_writer_.WriteString(filename, 0, &location)) 756 return false; 757 MDRawLinkMap entry; 758 entry.name = location.rva; 759 entry.addr = map.l_addr; 760 entry.ld = reinterpret_cast<uintptr_t>(map.l_ld); 761 linkmap.CopyIndex(idx++, &entry); 762 } 763 } 764 765 // Write MD_LINUX_DSO_DEBUG record 766 TypedMDRVA<MDRawDebug> debug(&minidump_writer_); 767 if (!debug.AllocateObjectAndArray(1, dynamic_length)) 768 return false; 769 my_memset(debug.get(), 0, sizeof(MDRawDebug)); 770 dirent->stream_type = MD_LINUX_DSO_DEBUG; 771 dirent->location = debug.location(); 772 773 debug.get()->version = debug_entry.r_version; 774 debug.get()->map = linkmap_rva; 775 debug.get()->dso_count = dso_count; 776 debug.get()->brk = debug_entry.r_brk; 777 debug.get()->ldbase = debug_entry.r_ldbase; 778 debug.get()->dynamic = reinterpret_cast<uintptr_t>(dynamic); 779 780 wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length); 781 // The passed-in size to the constructor (above) is only a hint. 782 // Must call .resize() to do actual initialization of the elements. 783 dso_debug_data.resize(dynamic_length); 784 dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic, 785 dynamic_length); 786 debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length); 787 788 return true; 789 } 790 791 void set_minidump_size_limit(off_t limit) { minidump_size_limit_ = limit; } 792 793 private: 794 void* Alloc(unsigned bytes) { 795 return dumper_->allocator()->Alloc(bytes); 796 } 797 798 pid_t GetCrashThread() const { 799 return dumper_->crash_thread(); 800 } 801 802 void NullifyDirectoryEntry(MDRawDirectory* dirent) { 803 dirent->stream_type = 0; 804 dirent->location.data_size = 0; 805 dirent->location.rva = 0; 806 } 807 808 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) 809 bool WriteCPUInformation(MDRawSystemInfo* sys_info) { 810 char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; 811 static const char vendor_id_name[] = "vendor_id"; 812 813 struct CpuInfoEntry { 814 const char* info_name; 815 int value; 816 bool found; 817 } cpu_info_table[] = { 818 { "processor", -1, false }, 819 #if defined(__i386__) || defined(__x86_64__) 820 { "model", 0, false }, 821 { "stepping", 0, false }, 822 { "cpu family", 0, false }, 823 #endif 824 }; 825 826 // processor_architecture should always be set, do this first 827 sys_info->processor_architecture = 828 #if defined(__mips__) 829 MD_CPU_ARCHITECTURE_MIPS; 830 #elif defined(__i386__) 831 MD_CPU_ARCHITECTURE_X86; 832 #else 833 MD_CPU_ARCHITECTURE_AMD64; 834 #endif 835 836 const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); 837 if (fd < 0) 838 return false; 839 840 { 841 PageAllocator allocator; 842 ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd); 843 const char* field; 844 while (reader->GetNextField(&field)) { 845 for (size_t i = 0; 846 i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); 847 i++) { 848 CpuInfoEntry* entry = &cpu_info_table[i]; 849 if (i > 0 && entry->found) { 850 // except for the 'processor' field, ignore repeated values. 851 continue; 852 } 853 if (!my_strcmp(field, entry->info_name)) { 854 size_t value_len; 855 const char* value = reader->GetValueAndLen(&value_len); 856 if (value_len == 0) 857 continue; 858 859 uintptr_t val; 860 if (my_read_decimal_ptr(&val, value) == value) 861 continue; 862 863 entry->value = static_cast<int>(val); 864 entry->found = true; 865 } 866 } 867 868 // special case for vendor_id 869 if (!my_strcmp(field, vendor_id_name)) { 870 size_t value_len; 871 const char* value = reader->GetValueAndLen(&value_len); 872 if (value_len > 0) 873 my_strlcpy(vendor_id, value, sizeof(vendor_id)); 874 } 875 } 876 sys_close(fd); 877 } 878 879 // make sure we got everything we wanted 880 for (size_t i = 0; 881 i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); 882 i++) { 883 if (!cpu_info_table[i].found) { 884 return false; 885 } 886 } 887 // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo, 888 // assuming this is the highest id, change it to the number of CPUs 889 // by adding one. 890 cpu_info_table[0].value++; 891 892 sys_info->number_of_processors = cpu_info_table[0].value; 893 #if defined(__i386__) || defined(__x86_64__) 894 sys_info->processor_level = cpu_info_table[3].value; 895 sys_info->processor_revision = cpu_info_table[1].value << 8 | 896 cpu_info_table[2].value; 897 #endif 898 899 if (vendor_id[0] != '\0') { 900 my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id, 901 sizeof(sys_info->cpu.x86_cpu_info.vendor_id)); 902 } 903 return true; 904 } 905 #elif defined(__arm__) || defined(__aarch64__) 906 bool WriteCPUInformation(MDRawSystemInfo* sys_info) { 907 // The CPUID value is broken up in several entries in /proc/cpuinfo. 908 // This table is used to rebuild it from the entries. 909 const struct CpuIdEntry { 910 const char* field; 911 char format; 912 char bit_lshift; 913 char bit_length; 914 } cpu_id_entries[] = { 915 { "CPU implementer", 'x', 24, 8 }, 916 { "CPU variant", 'x', 20, 4 }, 917 { "CPU part", 'x', 4, 12 }, 918 { "CPU revision", 'd', 0, 4 }, 919 }; 920 921 // The ELF hwcaps are listed in the "Features" entry as textual tags. 922 // This table is used to rebuild them. 923 const struct CpuFeaturesEntry { 924 const char* tag; 925 uint32_t hwcaps; 926 } cpu_features_entries[] = { 927 #if defined(__arm__) 928 { "swp", MD_CPU_ARM_ELF_HWCAP_SWP }, 929 { "half", MD_CPU_ARM_ELF_HWCAP_HALF }, 930 { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB }, 931 { "26bit", MD_CPU_ARM_ELF_HWCAP_26BIT }, 932 { "fastmult", MD_CPU_ARM_ELF_HWCAP_FAST_MULT }, 933 { "fpa", MD_CPU_ARM_ELF_HWCAP_FPA }, 934 { "vfp", MD_CPU_ARM_ELF_HWCAP_VFP }, 935 { "edsp", MD_CPU_ARM_ELF_HWCAP_EDSP }, 936 { "java", MD_CPU_ARM_ELF_HWCAP_JAVA }, 937 { "iwmmxt", MD_CPU_ARM_ELF_HWCAP_IWMMXT }, 938 { "crunch", MD_CPU_ARM_ELF_HWCAP_CRUNCH }, 939 { "thumbee", MD_CPU_ARM_ELF_HWCAP_THUMBEE }, 940 { "neon", MD_CPU_ARM_ELF_HWCAP_NEON }, 941 { "vfpv3", MD_CPU_ARM_ELF_HWCAP_VFPv3 }, 942 { "vfpv3d16", MD_CPU_ARM_ELF_HWCAP_VFPv3D16 }, 943 { "tls", MD_CPU_ARM_ELF_HWCAP_TLS }, 944 { "vfpv4", MD_CPU_ARM_ELF_HWCAP_VFPv4 }, 945 { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA }, 946 { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT }, 947 { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT }, 948 #elif defined(__aarch64__) 949 // No hwcaps on aarch64. 950 #endif 951 }; 952 953 // processor_architecture should always be set, do this first 954 sys_info->processor_architecture = 955 #if defined(__aarch64__) 956 MD_CPU_ARCHITECTURE_ARM64; 957 #else 958 MD_CPU_ARCHITECTURE_ARM; 959 #endif 960 961 // /proc/cpuinfo is not readable under various sandboxed environments 962 // (e.g. Android services with the android:isolatedProcess attribute) 963 // prepare for this by setting default values now, which will be 964 // returned when this happens. 965 // 966 // Note: Bogus values are used to distinguish between failures (to 967 // read /sys and /proc files) and really badly configured kernels. 968 sys_info->number_of_processors = 0; 969 sys_info->processor_level = 1U; // There is no ARMv1 970 sys_info->processor_revision = 42; 971 sys_info->cpu.arm_cpu_info.cpuid = 0; 972 sys_info->cpu.arm_cpu_info.elf_hwcaps = 0; 973 974 // Counting the number of CPUs involves parsing two sysfs files, 975 // because the content of /proc/cpuinfo will only mirror the number 976 // of 'online' cores, and thus will vary with time. 977 // See http://www.kernel.org/doc/Documentation/cputopology.txt 978 { 979 CpuSet cpus_present; 980 CpuSet cpus_possible; 981 982 int fd = sys_open("/sys/devices/system/cpu/present", O_RDONLY, 0); 983 if (fd >= 0) { 984 cpus_present.ParseSysFile(fd); 985 sys_close(fd); 986 987 fd = sys_open("/sys/devices/system/cpu/possible", O_RDONLY, 0); 988 if (fd >= 0) { 989 cpus_possible.ParseSysFile(fd); 990 sys_close(fd); 991 992 cpus_present.IntersectWith(cpus_possible); 993 int cpu_count = cpus_present.GetCount(); 994 if (cpu_count > 255) 995 cpu_count = 255; 996 sys_info->number_of_processors = static_cast<uint8_t>(cpu_count); 997 } 998 } 999 } 1000 1001 // Parse /proc/cpuinfo to reconstruct the CPUID value, as well 1002 // as the ELF hwcaps field. For the latter, it would be easier to 1003 // read /proc/self/auxv but unfortunately, this file is not always 1004 // readable from regular Android applications on later versions 1005 // (>= 4.1) of the Android platform. 1006 const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); 1007 if (fd < 0) { 1008 // Do not return false here to allow the minidump generation 1009 // to happen properly. 1010 return true; 1011 } 1012 1013 { 1014 PageAllocator allocator; 1015 ProcCpuInfoReader* const reader = 1016 new(allocator) ProcCpuInfoReader(fd); 1017 const char* field; 1018 while (reader->GetNextField(&field)) { 1019 for (size_t i = 0; 1020 i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]); 1021 ++i) { 1022 const CpuIdEntry* entry = &cpu_id_entries[i]; 1023 if (my_strcmp(entry->field, field) != 0) 1024 continue; 1025 uintptr_t result = 0; 1026 const char* value = reader->GetValue(); 1027 const char* p = value; 1028 if (value[0] == '0' && value[1] == 'x') { 1029 p = my_read_hex_ptr(&result, value+2); 1030 } else if (entry->format == 'x') { 1031 p = my_read_hex_ptr(&result, value); 1032 } else { 1033 p = my_read_decimal_ptr(&result, value); 1034 } 1035 if (p == value) 1036 continue; 1037 1038 result &= (1U << entry->bit_length)-1; 1039 result <<= entry->bit_lshift; 1040 sys_info->cpu.arm_cpu_info.cpuid |= 1041 static_cast<uint32_t>(result); 1042 } 1043 #if defined(__arm__) 1044 // Get the architecture version from the "Processor" field. 1045 // Note that it is also available in the "CPU architecture" field, 1046 // however, some existing kernels are misconfigured and will report 1047 // invalid values here (e.g. 6, while the CPU is ARMv7-A based). 1048 // The "Processor" field doesn't have this issue. 1049 if (!my_strcmp(field, "Processor")) { 1050 size_t value_len; 1051 const char* value = reader->GetValueAndLen(&value_len); 1052 // Expected format: <text> (v<level><endian>) 1053 // Where <text> is some text like "ARMv7 Processor rev 2" 1054 // and <level> is a decimal corresponding to the ARM 1055 // architecture number. <endian> is either 'l' or 'b' 1056 // and corresponds to the endianess, it is ignored here. 1057 while (value_len > 0 && my_isspace(value[value_len-1])) 1058 value_len--; 1059 1060 size_t nn = value_len; 1061 while (nn > 0 && value[nn-1] != '(') 1062 nn--; 1063 if (nn > 0 && value[nn] == 'v') { 1064 uintptr_t arch_level = 5; 1065 my_read_decimal_ptr(&arch_level, value + nn + 1); 1066 sys_info->processor_level = static_cast<uint16_t>(arch_level); 1067 } 1068 } 1069 #elif defined(__aarch64__) 1070 // The aarch64 architecture does not provide the architecture level 1071 // in the Processor field, so we instead check the "CPU architecture" 1072 // field. 1073 if (!my_strcmp(field, "CPU architecture")) { 1074 uintptr_t arch_level = 0; 1075 const char* value = reader->GetValue(); 1076 const char* p = value; 1077 p = my_read_decimal_ptr(&arch_level, value); 1078 if (p == value) 1079 continue; 1080 sys_info->processor_level = static_cast<uint16_t>(arch_level); 1081 } 1082 #endif 1083 // Rebuild the ELF hwcaps from the 'Features' field. 1084 if (!my_strcmp(field, "Features")) { 1085 size_t value_len; 1086 const char* value = reader->GetValueAndLen(&value_len); 1087 1088 // Parse each space-separated tag. 1089 while (value_len > 0) { 1090 const char* tag = value; 1091 size_t tag_len = value_len; 1092 const char* p = my_strchr(tag, ' '); 1093 if (p != NULL) { 1094 tag_len = static_cast<size_t>(p - tag); 1095 value += tag_len + 1; 1096 value_len -= tag_len + 1; 1097 } else { 1098 tag_len = strlen(tag); 1099 value_len = 0; 1100 } 1101 for (size_t i = 0; 1102 i < sizeof(cpu_features_entries)/ 1103 sizeof(cpu_features_entries[0]); 1104 ++i) { 1105 const CpuFeaturesEntry* entry = &cpu_features_entries[i]; 1106 if (tag_len == strlen(entry->tag) && 1107 !memcmp(tag, entry->tag, tag_len)) { 1108 sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry->hwcaps; 1109 break; 1110 } 1111 } 1112 } 1113 } 1114 } 1115 sys_close(fd); 1116 } 1117 1118 return true; 1119 } 1120 #else 1121 # error "Unsupported CPU" 1122 #endif 1123 1124 bool WriteFile(MDLocationDescriptor* result, const char* filename) { 1125 const int fd = sys_open(filename, O_RDONLY, 0); 1126 if (fd < 0) 1127 return false; 1128 1129 // We can't stat the files because several of the files that we want to 1130 // read are kernel seqfiles, which always have a length of zero. So we have 1131 // to read as much as we can into a buffer. 1132 static const unsigned kBufSize = 1024 - 2*sizeof(void*); 1133 struct Buffers { 1134 Buffers* next; 1135 size_t len; 1136 uint8_t data[kBufSize]; 1137 } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers))); 1138 buffers->next = NULL; 1139 buffers->len = 0; 1140 1141 size_t total = 0; 1142 for (Buffers* bufptr = buffers;;) { 1143 ssize_t r; 1144 do { 1145 r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len); 1146 } while (r == -1 && errno == EINTR); 1147 1148 if (r < 1) 1149 break; 1150 1151 total += r; 1152 bufptr->len += r; 1153 if (bufptr->len == kBufSize) { 1154 bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers))); 1155 bufptr = bufptr->next; 1156 bufptr->next = NULL; 1157 bufptr->len = 0; 1158 } 1159 } 1160 sys_close(fd); 1161 1162 if (!total) 1163 return false; 1164 1165 UntypedMDRVA memory(&minidump_writer_); 1166 if (!memory.Allocate(total)) 1167 return false; 1168 for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) { 1169 // Check for special case of a zero-length buffer. This should only 1170 // occur if a file's size happens to be a multiple of the buffer's 1171 // size, in which case the final sys_read() will have resulted in 1172 // zero bytes being read after the final buffer was just allocated. 1173 if (buffers->len == 0) { 1174 // This can only occur with final buffer. 1175 assert(buffers->next == NULL); 1176 continue; 1177 } 1178 memory.Copy(pos, &buffers->data, buffers->len); 1179 pos += buffers->len; 1180 } 1181 *result = memory.location(); 1182 return true; 1183 } 1184 1185 bool WriteOSInformation(MDRawSystemInfo* sys_info) { 1186 #if defined(__ANDROID__) 1187 sys_info->platform_id = MD_OS_ANDROID; 1188 #else 1189 sys_info->platform_id = MD_OS_LINUX; 1190 #endif 1191 1192 struct utsname uts; 1193 if (uname(&uts)) 1194 return false; 1195 1196 static const size_t buf_len = 512; 1197 char buf[buf_len] = {0}; 1198 size_t space_left = buf_len - 1; 1199 const char* info_table[] = { 1200 uts.sysname, 1201 uts.release, 1202 uts.version, 1203 uts.machine, 1204 NULL 1205 }; 1206 bool first_item = true; 1207 for (const char** cur_info = info_table; *cur_info; cur_info++) { 1208 static const char separator[] = " "; 1209 size_t separator_len = sizeof(separator) - 1; 1210 size_t info_len = my_strlen(*cur_info); 1211 if (info_len == 0) 1212 continue; 1213 1214 if (space_left < info_len + (first_item ? 0 : separator_len)) 1215 break; 1216 1217 if (!first_item) { 1218 my_strlcat(buf, separator, sizeof(buf)); 1219 space_left -= separator_len; 1220 } 1221 1222 first_item = false; 1223 my_strlcat(buf, *cur_info, sizeof(buf)); 1224 space_left -= info_len; 1225 } 1226 1227 MDLocationDescriptor location; 1228 if (!minidump_writer_.WriteString(buf, 0, &location)) 1229 return false; 1230 sys_info->csd_version_rva = location.rva; 1231 1232 return true; 1233 } 1234 1235 bool WriteProcFile(MDLocationDescriptor* result, pid_t pid, 1236 const char* filename) { 1237 char buf[NAME_MAX]; 1238 if (!dumper_->BuildProcPath(buf, pid, filename)) 1239 return false; 1240 return WriteFile(result, buf); 1241 } 1242 1243 // Only one of the 2 member variables below should be set to a valid value. 1244 const int fd_; // File descriptor where the minidum should be written. 1245 const char* path_; // Path to the file where the minidum should be written. 1246 1247 const struct ucontext* const ucontext_; // also from the signal handler 1248 #if !defined(__ARM_EABI__) && !defined(__mips__) 1249 const google_breakpad::fpstate_t* const float_state_; // ditto 1250 #endif 1251 LinuxDumper* dumper_; 1252 MinidumpFileWriter minidump_writer_; 1253 off_t minidump_size_limit_; 1254 MDLocationDescriptor crashing_thread_context_; 1255 // Blocks of memory written to the dump. These are all currently 1256 // written while writing the thread list stream, but saved here 1257 // so a memory list stream can be written afterwards. 1258 wasteful_vector<MDMemoryDescriptor> memory_blocks_; 1259 // Additional information about some mappings provided by the caller. 1260 const MappingList& mapping_list_; 1261 // Additional memory regions to be included in the dump, 1262 // provided by the caller. 1263 const AppMemoryList& app_memory_list_; 1264 }; 1265 1266 1267 bool WriteMinidumpImpl(const char* minidump_path, 1268 int minidump_fd, 1269 off_t minidump_size_limit, 1270 pid_t crashing_process, 1271 const void* blob, size_t blob_size, 1272 const MappingList& mappings, 1273 const AppMemoryList& appmem) { 1274 LinuxPtraceDumper dumper(crashing_process); 1275 const ExceptionHandler::CrashContext* context = NULL; 1276 if (blob) { 1277 if (blob_size != sizeof(ExceptionHandler::CrashContext)) 1278 return false; 1279 context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); 1280 dumper.set_crash_address( 1281 reinterpret_cast<uintptr_t>(context->siginfo.si_addr)); 1282 dumper.set_crash_signal(context->siginfo.si_signo); 1283 dumper.set_crash_thread(context->tid); 1284 } 1285 MinidumpWriter writer(minidump_path, minidump_fd, context, mappings, 1286 appmem, &dumper); 1287 // Set desired limit for file size of minidump (-1 means no limit). 1288 writer.set_minidump_size_limit(minidump_size_limit); 1289 if (!writer.Init()) 1290 return false; 1291 return writer.Dump(); 1292 } 1293 1294 } // namespace 1295 1296 namespace google_breakpad { 1297 1298 bool WriteMinidump(const char* minidump_path, pid_t crashing_process, 1299 const void* blob, size_t blob_size) { 1300 return WriteMinidumpImpl(minidump_path, -1, -1, 1301 crashing_process, blob, blob_size, 1302 MappingList(), AppMemoryList()); 1303 } 1304 1305 bool WriteMinidump(int minidump_fd, pid_t crashing_process, 1306 const void* blob, size_t blob_size) { 1307 return WriteMinidumpImpl(NULL, minidump_fd, -1, 1308 crashing_process, blob, blob_size, 1309 MappingList(), AppMemoryList()); 1310 } 1311 1312 bool WriteMinidump(const char* minidump_path, pid_t process, 1313 pid_t process_blamed_thread) { 1314 LinuxPtraceDumper dumper(process); 1315 // MinidumpWriter will set crash address 1316 dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED); 1317 dumper.set_crash_thread(process_blamed_thread); 1318 MinidumpWriter writer(minidump_path, -1, NULL, MappingList(), 1319 AppMemoryList(), &dumper); 1320 if (!writer.Init()) 1321 return false; 1322 return writer.Dump(); 1323 } 1324 1325 bool WriteMinidump(const char* minidump_path, pid_t crashing_process, 1326 const void* blob, size_t blob_size, 1327 const MappingList& mappings, 1328 const AppMemoryList& appmem) { 1329 return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process, 1330 blob, blob_size, 1331 mappings, appmem); 1332 } 1333 1334 bool WriteMinidump(int minidump_fd, pid_t crashing_process, 1335 const void* blob, size_t blob_size, 1336 const MappingList& mappings, 1337 const AppMemoryList& appmem) { 1338 return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process, 1339 blob, blob_size, 1340 mappings, appmem); 1341 } 1342 1343 bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit, 1344 pid_t crashing_process, 1345 const void* blob, size_t blob_size, 1346 const MappingList& mappings, 1347 const AppMemoryList& appmem) { 1348 return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit, 1349 crashing_process, blob, blob_size, 1350 mappings, appmem); 1351 } 1352 1353 bool WriteMinidump(int minidump_fd, off_t minidump_size_limit, 1354 pid_t crashing_process, 1355 const void* blob, size_t blob_size, 1356 const MappingList& mappings, 1357 const AppMemoryList& appmem) { 1358 return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit, 1359 crashing_process, blob, blob_size, 1360 mappings, appmem); 1361 } 1362 1363 bool WriteMinidump(const char* filename, 1364 const MappingList& mappings, 1365 const AppMemoryList& appmem, 1366 LinuxDumper* dumper) { 1367 MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper); 1368 if (!writer.Init()) 1369 return false; 1370 return writer.Dump(); 1371 } 1372 1373 } // namespace google_breakpad 1374