1f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org// Copyright (c) 2010, Google Inc. 2b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// All rights reserved. 3b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// 4b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// Redistribution and use in source and binary forms, with or without 5b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// modification, are permitted provided that the following conditions are 6b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// met: 7b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// 8b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// * Redistributions of source code must retain the above copyright 9b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// notice, this list of conditions and the following disclaimer. 10b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// * Redistributions in binary form must reproduce the above 11b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// copyright notice, this list of conditions and the following disclaimer 12b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// in the documentation and/or other materials provided with the 13b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// distribution. 14b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// * Neither the name of Google Inc. nor the names of its 15b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// contributors may be used to endorse or promote products derived from 16b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// this software without specific prior written permission. 17b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// 18b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 30b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// This code writes out minidump files: 31b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx 32b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// 33b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// Minidumps are a Microsoft format which Breakpad uses for recording crash 34b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// dumps. This code has to run in a compromised environment (the address space 35b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// may have received SIGSEGV), thus the following rules apply: 36b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// * You may not enter the dynamic linker. This means that we cannot call 37b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// any symbols in a shared library (inc libc). Because of this we replace 38b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// libc functions in linux_libc_support.h. 39b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// * You may not call syscalls via the libc wrappers. This rule is a subset 40b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// of the first rule but it bears repeating. We have direct wrappers 41b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// around the system calls in linux_syscall_support.h. 42b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// * You may not malloc. There's an alternative allocator in memory.h and 43b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// a canonical instance in the LinuxDumper object. We use the placement 44b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid// new form to allocate objects and we don't delete them. 45b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 46e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org#include "client/linux/handler/minidump_descriptor.h" 47b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/linux/minidump_writer/minidump_writer.h" 48b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/minidump_file_writer-inl.h" 49b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 50aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include <ctype.h> 51b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <errno.h> 52b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <fcntl.h> 53f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org#include <link.h> 54b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <stdio.h> 555187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#if defined(__ANDROID__) 565187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#include <sys/system_properties.h> 575187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#endif 5829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org#include <sys/types.h> 59b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <sys/ucontext.h> 60b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <sys/user.h> 61b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include <sys/utsname.h> 627b8a8fc5575624c97ff6659040e99ecf9d84e371thestig@chromium.org#include <time.h> 63aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include <unistd.h> 64b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 65f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org#include <algorithm> 66f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org 6730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org#include "client/linux/dump_writer_common/seccomp_unwinder.h" 6830f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org#include "client/linux/dump_writer_common/thread_info.h" 6930f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org#include "client/linux/dump_writer_common/ucontext_reader.h" 70b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/linux/handler/exception_handler.h" 71972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#include "client/linux/minidump_writer/cpu_set.h" 72b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "client/linux/minidump_writer/line_reader.h" 73de545c09d0363e6964822ec92529a80feaca152dnealsid#include "client/linux/minidump_writer/linux_dumper.h" 744fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org#include "client/linux/minidump_writer/linux_ptrace_dumper.h" 75972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#include "client/linux/minidump_writer/proc_cpuinfo_reader.h" 76aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include "client/minidump_file_writer.h" 77b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#include "common/linux/linux_libc_support.h" 78e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org#include "common/minidump_type_helper.h" 79aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org#include "google_breakpad/common/minidump_format.h" 800e3b7020b8f679259acfcfdbea4d39e1c13e6f19thestig@chromium.org#include "third_party/lss/linux_syscall_support.h" 81b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 82e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgnamespace { 83e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 8486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.comusing google_breakpad::AppMemoryList; 85e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::ExceptionHandler; 86972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.orgusing google_breakpad::CpuSet; 87e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::LineReader; 88e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::LinuxDumper; 89e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::LinuxPtraceDumper; 90e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.orgusing google_breakpad::MDTypeHelper; 91e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MappingEntry; 92e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MappingInfo; 93e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MappingList; 94e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::MinidumpFileWriter; 95e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::PageAllocator; 96972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.orgusing google_breakpad::ProcCpuInfoReader; 9730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.orgusing google_breakpad::RawContextCPU; 9830f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.orgusing google_breakpad::SeccompUnwinder; 99e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::ThreadInfo; 100e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::TypedMDRVA; 10130f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.orgusing google_breakpad::UContextReader; 102e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::UntypedMDRVA; 103e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgusing google_breakpad::wasteful_vector; 104e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 105e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.orgtypedef MDTypeHelper<sizeof(void*)>::MDRawDebug MDRawDebug; 106e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.orgtypedef MDTypeHelper<sizeof(void*)>::MDRawLinkMap MDRawLinkMap; 107b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 108b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsidclass MinidumpWriter { 109b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid public: 11029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // The following kLimit* constants are for when minidump_size_limit_ is set 11129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // and the minidump size might exceed it. 11229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // 11329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // Estimate for how big each thread's stack will be (in bytes). 11429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org static const unsigned kLimitAverageThreadStackLength = 8 * 1024; 11529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // Number of threads whose stack size we don't want to limit. These base 11629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // threads will simply be the first N threads returned by the dumper (although 11729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // the crashing thread will never be limited). Threads beyond this count are 11829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // the extra threads. 11929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org static const unsigned kLimitBaseThreadCount = 20; 12029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // Maximum stack size to dump for any extra thread (in bytes). 12129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org static const unsigned kLimitMaxExtraThreadStackLen = 2 * 1024; 12229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // Make sure this number of additional bytes can fit in the minidump 12329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // (exclude the stack data). 12429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org static const unsigned kLimitMinidumpFudgeFactor = 64 * 1024; 12529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org 126e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org MinidumpWriter(const char* minidump_path, 127e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org int minidump_fd, 128ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek const ExceptionHandler::CrashContext* context, 129e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org const MappingList& mappings, 13086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const AppMemoryList& appmem, 131e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org LinuxDumper* dumper) 132e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org : fd_(minidump_fd), 133e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org path_(minidump_path), 1344fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org ucontext_(context ? &context->context : NULL), 135b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#if !defined(__ARM_EABI__) && !defined(__mips__) 1364fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org float_state_(context ? &context->float_state : NULL), 137de545c09d0363e6964822ec92529a80feaca152dnealsid#endif 138e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org dumper_(dumper), 13929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org minidump_size_limit_(-1), 140e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org memory_blocks_(dumper_->allocator()), 14186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com mapping_list_(mappings), 14286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com app_memory_list_(appmem) { 143e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org // Assert there should be either a valid fd or a valid path, not both. 144e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org assert(fd_ != -1 || minidump_path); 145e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org assert(fd_ == -1 || !minidump_path); 146b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 147b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 148b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool Init() { 149e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org if (!dumper_->Init()) 150e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org return false; 151e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 152e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org if (fd_ != -1) 153e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org minidump_writer_.SetFile(fd_); 154e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org else if (!minidump_writer_.Open(path_)) 155e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org return false; 156e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 157e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org return dumper_->ThreadsSuspend(); 158b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 159b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 160b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid ~MinidumpWriter() { 161e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org // Don't close the file descriptor when it's been provided explicitly. 162e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org // Callers might still need to use it. 163e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org if (fd_ == -1) 164e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org minidump_writer_.Close(); 165e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org dumper_->ThreadsResume(); 166b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 167b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 168b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool Dump() { 169b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // A minidump file contains a number of tagged streams. This is the number 170b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // of stream which we write. 171693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com unsigned kNumWriters = 13; 172b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 173b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<MDRawHeader> header(&minidump_writer_); 174b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<MDRawDirectory> dir(&minidump_writer_); 175b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!header.Allocate()) 176b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 177b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!dir.AllocateArray(kNumWriters)) 178b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 179ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org my_memset(header.get(), 0, sizeof(MDRawHeader)); 180b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 181b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid header.get()->signature = MD_HEADER_SIGNATURE; 182b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid header.get()->version = MD_HEADER_VERSION; 183b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid header.get()->time_date_stamp = time(NULL); 184b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid header.get()->stream_count = kNumWriters; 185b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid header.get()->stream_directory_rva = dir.position(); 186b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 187b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid unsigned dir_index = 0; 188b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid MDRawDirectory dirent; 189b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 190b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!WriteThreadListStream(&dirent)) 191b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 192b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 193b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 194b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!WriteMappings(&dirent)) 195b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 196b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 197b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 19886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com if (!WriteAppMemory()) 19986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com return false; 20086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com 201efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek if (!WriteMemoryListStream(&dirent)) 202efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek return false; 203efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek dir.CopyIndex(dir_index++, &dirent); 204efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 205b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!WriteExceptionStream(&dirent)) 206b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 207b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 208b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 209b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!WriteSystemInfoStream(&dirent)) 210b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 211b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 212b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 213b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent.stream_type = MD_LINUX_CPU_INFO; 214b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!WriteFile(&dirent.location, "/proc/cpuinfo")) 215b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NullifyDirectoryEntry(&dirent); 216b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 217b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 218b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent.stream_type = MD_LINUX_PROC_STATUS; 219e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org if (!WriteProcFile(&dirent.location, GetCrashThread(), "status")) 220b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NullifyDirectoryEntry(&dirent); 221b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 222b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 223b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent.stream_type = MD_LINUX_LSB_RELEASE; 224b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!WriteFile(&dirent.location, "/etc/lsb-release")) 225b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NullifyDirectoryEntry(&dirent); 226b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 227b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 228b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent.stream_type = MD_LINUX_CMD_LINE; 229e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline")) 230b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NullifyDirectoryEntry(&dirent); 231b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 232b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 233b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent.stream_type = MD_LINUX_ENVIRON; 234e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ")) 235b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NullifyDirectoryEntry(&dirent); 236b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 237b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 238b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent.stream_type = MD_LINUX_AUXV; 239e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv")) 240b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NullifyDirectoryEntry(&dirent); 241b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 242b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 243f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org dirent.stream_type = MD_LINUX_MAPS; 244e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps")) 245b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NullifyDirectoryEntry(&dirent); 246b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dir.CopyIndex(dir_index++, &dirent); 247b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 248693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com dirent.stream_type = MD_LINUX_DSO_DEBUG; 249693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com if (!WriteDSODebugStream(&dirent)) 250693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com NullifyDirectoryEntry(&dirent); 251693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com dir.CopyIndex(dir_index++, &dirent); 252f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 253b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // If you add more directory entries, don't forget to update kNumWriters, 254b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // above. 255b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 256e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org dumper_->ThreadsResume(); 257b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 258b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 259b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 260a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, 26129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org int max_stack_len, uint8_t** stack_copy) { 262a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org *stack_copy = NULL; 263a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org const void* stack; 264a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org size_t stack_len; 265a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { 266a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org UntypedMDRVA memory(&minidump_writer_); 2672971a050754f48aaa807db47a29e0d0beddbdcf7ivan.penkov@gmail.com if (max_stack_len >= 0 && 2682971a050754f48aaa807db47a29e0d0beddbdcf7ivan.penkov@gmail.com stack_len > static_cast<unsigned int>(max_stack_len)) { 26929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org stack_len = max_stack_len; 2702971a050754f48aaa807db47a29e0d0beddbdcf7ivan.penkov@gmail.com } 271a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org if (!memory.Allocate(stack_len)) 272a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org return false; 273a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len)); 274a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack, 275a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org stack_len); 276a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org memory.Copy(*stack_copy, stack_len); 277a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org thread->stack.start_of_memory_range = 278a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org reinterpret_cast<uintptr_t>(stack); 279a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org thread->stack.memory = memory.location(); 280a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org memory_blocks_.push_back(thread->stack); 281a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org } else { 282a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org thread->stack.start_of_memory_range = stack_pointer; 283a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org thread->stack.memory.data_size = 0; 284a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org thread->stack.memory.rva = minidump_writer_.position(); 285a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org } 286a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org return true; 287a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org } 288a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org 289b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // Write information about the threads. 290b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteThreadListStream(MDRawDirectory* dirent) { 291e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org const unsigned num_threads = dumper_->threads().size(); 292b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 293b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<uint32_t> list(&minidump_writer_); 294b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread))) 295b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 296b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 297b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->stream_type = MD_THREAD_LIST_STREAM; 298b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->location = list.location(); 299b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 300b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid *list.get() = num_threads; 301b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 30229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // If there's a minidump size limit, check if it might be exceeded. Since 30329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // most of the space is filled with stack data, just check against that. 30429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // If this expects to exceed the limit, set extra_thread_stack_len such 30529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // that any thread beyond the first kLimitBaseThreadCount threads will 30629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // have only kLimitMaxExtraThreadStackLen bytes dumped. 30729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org int extra_thread_stack_len = -1; // default to no maximum 30829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org if (minidump_size_limit_ >= 0) { 30929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const unsigned estimated_total_stack_size = num_threads * 31029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org kLimitAverageThreadStackLength; 31129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const off_t estimated_minidump_size = minidump_writer_.position() + 31229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org estimated_total_stack_size + kLimitMinidumpFudgeFactor; 31329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org if (estimated_minidump_size > minidump_size_limit_) 31429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org extra_thread_stack_len = kLimitMaxExtraThreadStackLen; 31529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org } 31629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org 317b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid for (unsigned i = 0; i < num_threads; ++i) { 318b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid MDRawThread thread; 319b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid my_memset(&thread, 0, sizeof(thread)); 320e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org thread.thread_id = dumper_->threads()[i]; 321a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org 322b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // We have a different source of information for the crashing thread. If 323b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // we used the actual state of the thread we would find it running in the 324b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // signal handler with the alternative stack, which would be deeply 325b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // unhelpful. 3264fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() && 327f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com ucontext_ && 3284fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org !dumper_->IsPostMortem()) { 329a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org uint8_t* stack_copy; 33030f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); 33130f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy)) 332b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 333efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 334efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // Copy 256 bytes around crashing instruction pointer to minidump. 335efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek const size_t kIPMemorySize = 256; 33630f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org uint64_t ip = UContextReader::GetInstructionPointer(ucontext_); 337efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // Bound it to the upper and lower bounds of the memory map 338efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // it's contained within. If it's not in mapped memory, 339efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // don't bother trying to write it. 340efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek bool ip_is_mapped = false; 341efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek MDMemoryDescriptor ip_memory_d; 342e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org for (unsigned j = 0; j < dumper_->mappings().size(); ++j) { 343e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org const MappingInfo& mapping = *dumper_->mappings()[j]; 344efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek if (ip >= mapping.start_addr && 345efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek ip < mapping.start_addr + mapping.size) { 346efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek ip_is_mapped = true; 347efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // Try to get 128 bytes before and after the IP, but 348efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // settle for whatever's available. 349efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek ip_memory_d.start_of_memory_range = 3504621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek std::max(mapping.start_addr, 351efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek uintptr_t(ip - (kIPMemorySize / 2))); 352f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org uintptr_t end_of_range = 3534621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek std::min(uintptr_t(ip + (kIPMemorySize / 2)), 3544621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek uintptr_t(mapping.start_addr + mapping.size)); 355efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek ip_memory_d.memory.data_size = 3564621ee06914b2ebe963c93ea78fabf982cf670dfted.mielczarek end_of_range - ip_memory_d.start_of_memory_range; 357efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek break; 358efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek } 359efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek } 360efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 361efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek if (ip_is_mapped) { 362efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek UntypedMDRVA ip_memory(&minidump_writer_); 363efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) 364efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek return false; 365efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek uint8_t* memory_copy = 366e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size)); 367e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org dumper_->CopyFromProcess( 368e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org memory_copy, 369e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org thread.thread_id, 370e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org reinterpret_cast<void*>(ip_memory_d.start_of_memory_range), 371e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org ip_memory_d.memory.data_size); 372efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size); 373efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek ip_memory_d.memory = ip_memory.location(); 374efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek memory_blocks_.push_back(ip_memory_d); 375efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek } 376efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 377b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); 378b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!cpu.Allocate()) 379b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 380b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid my_memset(cpu.get(), 0, sizeof(RawContextCPU)); 381b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#if !defined(__ARM_EABI__) && !defined(__mips__) 38230f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); 383b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#else 38430f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org UContextReader::FillCPUContext(cpu.get(), ucontext_); 385b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#endif 386a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org if (stack_copy) 38730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); 388b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid thread.thread_context = cpu.location(); 389b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid crashing_thread_context_ = cpu.location(); 390b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } else { 391b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid ThreadInfo info; 392e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org if (!dumper_->GetThreadInfoByIndex(i, &info)) 393b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 394a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org 395a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org uint8_t* stack_copy; 39629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org int max_stack_len = -1; // default to no maximum for this thread 39729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount) 39829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org max_stack_len = extra_thread_stack_len; 39929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org if (!FillThreadStack(&thread, info.stack_pointer, max_stack_len, 40029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org &stack_copy)) 401b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 402efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 403b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); 404b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!cpu.Allocate()) 405b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 406b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid my_memset(cpu.get(), 0, sizeof(RawContextCPU)); 40730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org info.FillCPUContext(cpu.get()); 408a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org if (stack_copy) 40930f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); 410b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid thread.thread_context = cpu.location(); 4114fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org if (dumper_->threads()[i] == GetCrashThread()) { 4124fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org crashing_thread_context_ = cpu.location(); 413f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com if (!dumper_->IsPostMortem()) { 414f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com // This is the crashing thread of a live process, but 415f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com // no context was provided, so set the crash address 416f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com // while the instruction pointer is already here. 41730f1b7fb16cdc906078f031bf12c1ffb2cb5ea3eprimiano@chromium.org dumper_->set_crash_address(info.GetInstructionPointer()); 418f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com } 4194fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org } 420b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 421b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 422b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid list.CopyIndexAfterObject(i, &thread, sizeof(thread)); 423b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 424b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 425b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 426b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 427b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 42886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com // Write application-provided memory regions. 42986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com bool WriteAppMemory() { 43086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com for (AppMemoryList::const_iterator iter = app_memory_list_.begin(); 43186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com iter != app_memory_list_.end(); 43286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com ++iter) { 43386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com uint8_t* data_copy = 43486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com reinterpret_cast<uint8_t*>(dumper_->allocator()->Alloc(iter->length)); 43586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com dumper_->CopyFromProcess(data_copy, GetCrashThread(), iter->ptr, 43686f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com iter->length); 43786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com 43886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com UntypedMDRVA memory(&minidump_writer_); 43986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com if (!memory.Allocate(iter->length)) { 44086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com return false; 44186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com } 44286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com memory.Copy(data_copy, iter->length); 44386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com MDMemoryDescriptor desc; 44486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com desc.start_of_memory_range = reinterpret_cast<uintptr_t>(iter->ptr); 44586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com desc.memory = memory.location(); 44686f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com memory_blocks_.push_back(desc); 44786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com } 44886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com 44986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com return true; 45086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com } 45186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com 452b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid static bool ShouldIncludeMapping(const MappingInfo& mapping) { 453f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org if (mapping.name[0] == 0 || // only want modules with filenames. 454dd5dd85f3795609723082a2b34f81e19b4f1679frmcilroy@chromium.org // Only want to include one mapping per shared lib. 455dd5dd85f3795609723082a2b34f81e19b4f1679frmcilroy@chromium.org // Avoid filtering executable mappings. 456dd5dd85f3795609723082a2b34f81e19b4f1679frmcilroy@chromium.org (mapping.offset != 0 && !mapping.exec) || 457b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid mapping.size < 4096) { // too small to get a signature for. 458b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 459b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 460b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 461b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 462b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 463b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 464ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // If there is caller-provided information about this mapping 465ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // in the mapping_list_ list, return true. Otherwise, return false. 466ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek bool HaveMappingInfo(const MappingInfo& mapping) { 467ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek for (MappingList::const_iterator iter = mapping_list_.begin(); 468ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek iter != mapping_list_.end(); 469ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek ++iter) { 470ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // Ignore any mappings that are wholly contained within 471ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // mappings in the mapping_info_ list. 472ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek if (mapping.start_addr >= iter->first.start_addr && 473ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek (mapping.start_addr + mapping.size) <= 474ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek (iter->first.start_addr + iter->first.size)) { 475ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek return true; 476ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek } 477ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek } 478ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek return false; 479ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek } 480ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek 481b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // Write information about the mappings in effect. Because we are using the 482b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // minidump format, the information about the mappings is pretty limited. 483b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // Because of this, we also include the full, unparsed, /proc/$x/maps file in 484b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // another stream in the file. 485b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteMappings(MDRawDirectory* dirent) { 486e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org const unsigned num_mappings = dumper_->mappings().size(); 487ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek unsigned num_output_mappings = mapping_list_.size(); 488b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 489e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { 490e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org const MappingInfo& mapping = *dumper_->mappings()[i]; 491ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping)) 492b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid num_output_mappings++; 493b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 494b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 495b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<uint32_t> list(&minidump_writer_); 496362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org if (num_output_mappings) { 497362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE)) 498362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org return false; 499362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org } else { 500362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org // Still create the module list stream, although it will have zero 501362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org // modules. 502362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org if (!list.Allocate()) 503362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org return false; 504362167fa1af90ed3b1cda0cbcac8d15011a28a12mkrebs@chromium.org } 505b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 506b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->stream_type = MD_MODULE_LIST_STREAM; 507b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->location = list.location(); 508b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid *list.get() = num_output_mappings; 509b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 510ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // First write all the mappings from the dumper 511ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek unsigned int j = 0; 512ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek for (unsigned i = 0; i < num_mappings; ++i) { 513e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org const MappingInfo& mapping = *dumper_->mappings()[i]; 514ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping)) 515b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid continue; 516b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 517b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid MDRawModule mod; 51823c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com if (!FillRawModule(mapping, true, i, mod, NULL)) 519b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 520ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); 521ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek } 522ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // Next write all the mappings provided by the caller 523ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek for (MappingList::const_iterator iter = mapping_list_.begin(); 524ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek iter != mapping_list_.end(); 525ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek ++iter) { 526ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek MDRawModule mod; 52723c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com if (!FillRawModule(iter->first, false, 0, mod, iter->second)) 528ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek return false; 529ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); 530ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek } 531b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 532ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek return true; 533ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek } 534b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 535ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // Fill the MDRawModule |mod| with information about the provided 536ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // |mapping|. If |identifier| is non-NULL, use it instead of calculating 53723c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com // a file ID from the mapping. 538ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek bool FillRawModule(const MappingInfo& mapping, 53923c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com bool member, 54023c82999a8a8a6761133a7a8e88b5349bcff211ajessicag.feedback@gmail.com unsigned int mapping_id, 541ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek MDRawModule& mod, 5426162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com const uint8_t* identifier) { 543ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek my_memset(&mod, 0, MD_MODULE_SIZE); 544ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek 545ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek mod.base_of_image = mapping.start_addr; 546ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek mod.size_of_image = mapping.size; 547b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 548ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; 549ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek uint8_t* cv_ptr = cv_buf; 550b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 551ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; 552ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); 553ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek cv_ptr += sizeof(cv_signature); 554ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek uint8_t* signature = cv_ptr; 555ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek cv_ptr += sizeof(MDGUID); 556ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek if (identifier) { 557ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // GUID was provided by caller. 558ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org my_memcpy(signature, identifier, sizeof(MDGUID)); 559ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek } else { 56084c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|. 561e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org dumper_->ElfFileIdentifierForMapping(mapping, member, 562e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org mapping_id, signature); 563b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 564ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. 565ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek cv_ptr += sizeof(uint32_t); 566b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 56784c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org char file_name[NAME_MAX]; 56884c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org char file_path[NAME_MAX]; 56984c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org LinuxDumper::GetMappingEffectiveNameAndPath( 57084c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); 57184c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org 57284c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org const size_t file_name_len = my_strlen(file_name); 57384c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org UntypedMDRVA cv(&minidump_writer_); 57484c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1)) 57584c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org return false; 57684c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org 577ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // Write pdb_file_name 57884c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org my_memcpy(cv_ptr, file_name, file_name_len + 1); 57984c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1); 580ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek 581ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek mod.cv_record = cv.location(); 582ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek 583ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek MDLocationDescriptor ld; 58484c92677474d91cdc1585a9d663eae30272b807aprimiano@chromium.org if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) 585ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek return false; 586ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek mod.module_name_rva = ld.rva; 587b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 588b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 589b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 590efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek bool WriteMemoryListStream(MDRawDirectory* dirent) { 591efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek TypedMDRVA<uint32_t> list(&minidump_writer_); 592a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org if (memory_blocks_.size()) { 593a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org if (!list.AllocateObjectAndArray(memory_blocks_.size(), 594a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org sizeof(MDMemoryDescriptor))) 595a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org return false; 596a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org } else { 597a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org // Still create the memory list stream, although it will have zero 598a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org // memory blocks. 599a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org if (!list.Allocate()) 600a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org return false; 601a576a63122315d8675b8ef6b43c848e627354afbmkrebs@chromium.org } 602efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 603efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek dirent->stream_type = MD_MEMORY_LIST_STREAM; 604efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek dirent->location = list.location(); 605efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 606efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek *list.get() = memory_blocks_.size(); 607efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 608efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek for (size_t i = 0; i < memory_blocks_.size(); ++i) { 609efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek list.CopyIndexAfterObject(i, &memory_blocks_[i], 610efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek sizeof(MDMemoryDescriptor)); 611efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek } 612efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek return true; 613efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek } 614efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek 615b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteExceptionStream(MDRawDirectory* dirent) { 616b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_); 617b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!exc.Allocate()) 618b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 619b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid my_memset(exc.get(), 0, sizeof(MDRawExceptionStream)); 620b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 621b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->stream_type = MD_EXCEPTION_STREAM; 622b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->location = exc.location(); 623b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 624e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org exc.get()->thread_id = GetCrashThread(); 625e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org exc.get()->exception_record.exception_code = dumper_->crash_signal(); 626e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org exc.get()->exception_record.exception_address = dumper_->crash_address(); 627b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid exc.get()->thread_context = crashing_thread_context_; 628b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 629b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 630b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 631b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 632b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteSystemInfoStream(MDRawDirectory* dirent) { 633b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_); 634b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!si.Allocate()) 635b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 636b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid my_memset(si.get(), 0, sizeof(MDRawSystemInfo)); 637b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 638b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->stream_type = MD_SYSTEM_INFO_STREAM; 639b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->location = si.location(); 640b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 641b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid WriteCPUInformation(si.get()); 642b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid WriteOSInformation(si.get()); 643b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 644b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 645b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 646b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 647693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com bool WriteDSODebugStream(MDRawDirectory* dirent) { 648693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]); 649693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com char* base; 650693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com int phnum = dumper_->auxv()[AT_PHNUM]; 651693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com if (!phnum || !phdr) 652693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com return false; 653693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com 654693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // Assume the program base is at the beginning of the same page as the PHDR 655693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff); 656693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com 657693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // Search for the program PT_DYNAMIC segment 658693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com ElfW(Addr) dyn_addr = 0; 659693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com for (; phnum >= 0; phnum--, phdr++) { 660693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com ElfW(Phdr) ph; 661e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph))) 662e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org return false; 663e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org 664693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // Adjust base address with the virtual address of the PT_LOAD segment 665693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // corresponding to offset 0 666693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com if (ph.p_type == PT_LOAD && ph.p_offset == 0) { 667693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com base -= ph.p_vaddr; 668693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com } 669693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com if (ph.p_type == PT_DYNAMIC) { 670693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com dyn_addr = ph.p_vaddr; 671693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com } 672693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com } 673693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com if (!dyn_addr) 674693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com return false; 675693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com 676693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base); 677693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com 678693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // The dynamic linker makes information available that helps gdb find all 679693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // DSOs loaded into the program. If this information is indeed available, 680693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // dump it to a MD_LINUX_DSO_DEBUG stream. 681693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com struct r_debug* r_debug = NULL; 682693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com uint32_t dynamic_length = 0; 683693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com 684e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org for (int i = 0; ; ++i) { 685693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com ElfW(Dyn) dyn; 686693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com dynamic_length += sizeof(dyn); 687e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i, 688e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org sizeof(dyn))) { 689e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org return false; 690e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org } 691e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org 692693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com if (dyn.d_tag == DT_DEBUG) { 693693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr); 694693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com continue; 695693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com } else if (dyn.d_tag == DT_NULL) { 696693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com break; 697693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com } 698693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com } 699693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com 700693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // The "r_map" field of that r_debug struct contains a linked list of all 701693d4caa50791a40a8b9734054603dde2b05e0fbted.mielczarek@gmail.com // loaded DSOs. 702f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // Our list of DSOs potentially is different from the ones in the crashing 703f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // process. So, we have to be careful to never dereference pointers 704f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // directly. Instead, we use CopyFromProcess() everywhere. 705f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // See <link.h> for a more detailed discussion of the how the dynamic 706f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // loader communicates with debuggers. 707f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 708f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // Count the number of loaded DSOs 709f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org int dso_count = 0; 710f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org struct r_debug debug_entry; 711e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug, 712e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org sizeof(debug_entry))) { 713e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org return false; 714e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org } 715f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org for (struct link_map* ptr = debug_entry.r_map; ptr; ) { 716f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org struct link_map map; 717e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map))) 718e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org return false; 719e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org 720f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org ptr = map.l_next; 721f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org dso_count++; 722f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org } 723f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 724f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA; 725f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (dso_count > 0) { 726f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // If we have at least one DSO, create an array of MDRawLinkMap 727f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // entries in the minidump file. 728f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_); 729f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (!linkmap.AllocateArray(dso_count)) 730f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org return false; 731f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org linkmap_rva = linkmap.location().rva; 732f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org int idx = 0; 733f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 734f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // Iterate over DSOs and write their information to mini dump 735f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org for (struct link_map* ptr = debug_entry.r_map; ptr; ) { 736f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org struct link_map map; 737e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map))) 738e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org return false; 739e0aa94bfb6682a04f824b64d064fbb58ac5343c7benchan@chromium.org 740f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org ptr = map.l_next; 741f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org char filename[257] = { 0 }; 742f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (map.l_name) { 743e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name, 744e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org sizeof(filename) - 1); 745f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org } 746f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org MDLocationDescriptor location; 747f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (!minidump_writer_.WriteString(filename, 0, &location)) 748f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org return false; 749f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org MDRawLinkMap entry; 750f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org entry.name = location.rva; 751e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org entry.addr = map.l_addr; 752e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org entry.ld = reinterpret_cast<uintptr_t>(map.l_ld); 753f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org linkmap.CopyIndex(idx++, &entry); 754f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org } 755f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org } 756f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 757f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org // Write MD_LINUX_DSO_DEBUG record 758f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org TypedMDRVA<MDRawDebug> debug(&minidump_writer_); 759f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (!debug.AllocateObjectAndArray(1, dynamic_length)) 760f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org return false; 761f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org my_memset(debug.get(), 0, sizeof(MDRawDebug)); 762f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org dirent->stream_type = MD_LINUX_DSO_DEBUG; 763f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org dirent->location = debug.location(); 764f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 765f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org debug.get()->version = debug_entry.r_version; 766f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org debug.get()->map = linkmap_rva; 767f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org debug.get()->dso_count = dso_count; 768e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org debug.get()->brk = debug_entry.r_brk; 769e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org debug.get()->ldbase = debug_entry.r_ldbase; 770e2f4be928865f991e7177248bc4daadb0bd4aed0mdempsky@chromium.org debug.get()->dynamic = reinterpret_cast<uintptr_t>(dynamic); 771f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 7725eb7c9279928a6c65dc76949bd518e9167ca678eted.mielczarek@gmail.com wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length); 773447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com // The passed-in size to the constructor (above) is only a hint. 774447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com // Must call .resize() to do actual initialization of the elements. 775447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com dso_debug_data.resize(dynamic_length); 7765eb7c9279928a6c65dc76949bd518e9167ca678eted.mielczarek@gmail.com dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic, 777e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org dynamic_length); 7785eb7c9279928a6c65dc76949bd518e9167ca678eted.mielczarek@gmail.com debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length); 779f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 780f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org return true; 781f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org } 782f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 78329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org void set_minidump_size_limit(off_t limit) { minidump_size_limit_ = limit; } 78429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org 785b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid private: 786e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org void* Alloc(unsigned bytes) { 787e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org return dumper_->allocator()->Alloc(bytes); 788e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org } 789e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org 790e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org pid_t GetCrashThread() const { 791e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org return dumper_->crash_thread(); 792e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org } 793e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org 794b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid void NullifyDirectoryEntry(MDRawDirectory* dirent) { 795b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->stream_type = 0; 796b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->location.data_size = 0; 797b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid dirent->location.rva = 0; 798b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 799b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 8005f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) 801b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteCPUInformation(MDRawSystemInfo* sys_info) { 802b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; 803b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid static const char vendor_id_name[] = "vendor_id"; 804b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 805b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid struct CpuInfoEntry { 806b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid const char* info_name; 807b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid int value; 808b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool found; 809b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } cpu_info_table[] = { 810b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid { "processor", -1, false }, 811952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__i386__) || defined(__x86_64__) 812b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid { "model", 0, false }, 813b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid { "stepping", 0, false }, 814096992fac73756cfa0974a94754329f30fd4e786nealsid { "cpu family", 0, false }, 8155f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#endif 816b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid }; 817b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 818b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // processor_architecture should always be set, do this first 819b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_info->processor_architecture = 8205f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#if defined(__mips__) 8215f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com MD_CPU_ARCHITECTURE_MIPS; 8225f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#elif defined(__i386__) 823b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid MD_CPU_ARCHITECTURE_X86; 824b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#else 825972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org MD_CPU_ARCHITECTURE_AMD64; 826b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid#endif 827b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 828b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); 829b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (fd < 0) 830b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 831b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 832b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid { 833b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid PageAllocator allocator; 834972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd); 835972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* field; 836972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org while (reader->GetNextField(&field)) { 837b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid for (size_t i = 0; 838b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); 839b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid i++) { 840b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid CpuInfoEntry* entry = &cpu_info_table[i]; 841972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (i > 0 && entry->found) { 842972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // except for the 'processor' field, ignore repeated values. 843b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid continue; 844972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 845972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (!my_strcmp(field, entry->info_name)) { 846972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org size_t value_len; 847972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* value = reader->GetValueAndLen(&value_len); 848972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (value_len == 0) 849b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid continue; 850b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 851ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org uintptr_t val; 852d8511da723115e5e39117129ea518b6e9c0e09b4thestig@chromium.org if (my_read_decimal_ptr(&val, value) == value) 853d8511da723115e5e39117129ea518b6e9c0e09b4thestig@chromium.org continue; 854972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 855ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org entry->value = static_cast<int>(val); 856b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid entry->found = true; 857b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 858b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 859b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 860b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // special case for vendor_id 861972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (!my_strcmp(field, vendor_id_name)) { 862972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org size_t value_len; 863972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* value = reader->GetValueAndLen(&value_len); 864972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (value_len > 0) 865f1e81b3b4a9b31a56c669950a97b71e9e7acaf4cthestig@chromium.org my_strlcpy(vendor_id, value, sizeof(vendor_id)); 866b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 867b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 868b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_close(fd); 869b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 870b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 871b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // make sure we got everything we wanted 872b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid for (size_t i = 0; 873b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); 874b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid i++) { 875b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!cpu_info_table[i].found) { 876b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 877b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 878b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 879972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo, 880972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // assuming this is the highest id, change it to the number of CPUs 881972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // by adding one. 882b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid cpu_info_table[0].value++; 883b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 884b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_info->number_of_processors = cpu_info_table[0].value; 885952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__i386__) || defined(__x86_64__) 886b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_info->processor_level = cpu_info_table[3].value; 887b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_info->processor_revision = cpu_info_table[1].value << 8 | 888b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid cpu_info_table[2].value; 8895f22d6a7f471f2352d394c188560fd06830e14f3gordana.cmiljanovic@imgtec.com#endif 890b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 891b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (vendor_id[0] != '\0') { 892ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id, 893ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org sizeof(sys_info->cpu.x86_cpu_info.vendor_id)); 894b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 895b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 896b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 897952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#elif defined(__arm__) || defined(__aarch64__) 898972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org bool WriteCPUInformation(MDRawSystemInfo* sys_info) { 899972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // The CPUID value is broken up in several entries in /proc/cpuinfo. 900972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // This table is used to rebuild it from the entries. 901972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const struct CpuIdEntry { 902972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* field; 903972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org char format; 904972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org char bit_lshift; 905972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org char bit_length; 906972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } cpu_id_entries[] = { 907972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "CPU implementer", 'x', 24, 8 }, 908972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "CPU variant", 'x', 20, 4 }, 909972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "CPU part", 'x', 4, 12 }, 910972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "CPU revision", 'd', 0, 4 }, 911972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org }; 912972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 913972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // The ELF hwcaps are listed in the "Features" entry as textual tags. 914972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // This table is used to rebuild them. 915972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const struct CpuFeaturesEntry { 916972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* tag; 917972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org uint32_t hwcaps; 918972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } cpu_features_entries[] = { 919952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__arm__) 920972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "swp", MD_CPU_ARM_ELF_HWCAP_SWP }, 921972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "half", MD_CPU_ARM_ELF_HWCAP_HALF }, 922972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB }, 923972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "26bit", MD_CPU_ARM_ELF_HWCAP_26BIT }, 924972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "fastmult", MD_CPU_ARM_ELF_HWCAP_FAST_MULT }, 925972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "fpa", MD_CPU_ARM_ELF_HWCAP_FPA }, 926972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "vfp", MD_CPU_ARM_ELF_HWCAP_VFP }, 927972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "edsp", MD_CPU_ARM_ELF_HWCAP_EDSP }, 928972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "java", MD_CPU_ARM_ELF_HWCAP_JAVA }, 929972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "iwmmxt", MD_CPU_ARM_ELF_HWCAP_IWMMXT }, 930972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "crunch", MD_CPU_ARM_ELF_HWCAP_CRUNCH }, 931972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "thumbee", MD_CPU_ARM_ELF_HWCAP_THUMBEE }, 932972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "neon", MD_CPU_ARM_ELF_HWCAP_NEON }, 933972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "vfpv3", MD_CPU_ARM_ELF_HWCAP_VFPv3 }, 934972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "vfpv3d16", MD_CPU_ARM_ELF_HWCAP_VFPv3D16 }, 935972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "tls", MD_CPU_ARM_ELF_HWCAP_TLS }, 936972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "vfpv4", MD_CPU_ARM_ELF_HWCAP_VFPv4 }, 937972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA }, 938972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT }, 939972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT }, 940952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#elif defined(__aarch64__) 941952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org // No hwcaps on aarch64. 942952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#endif 943972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org }; 944972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 945972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // processor_architecture should always be set, do this first 946952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org sys_info->processor_architecture = 947952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__aarch64__) 948952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org MD_CPU_ARCHITECTURE_ARM64; 949952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#else 950952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org MD_CPU_ARCHITECTURE_ARM; 951952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#endif 952972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 953972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // /proc/cpuinfo is not readable under various sandboxed environments 954972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // (e.g. Android services with the android:isolatedProcess attribute) 955972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // prepare for this by setting default values now, which will be 956972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // returned when this happens. 957972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // 958972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Note: Bogus values are used to distinguish between failures (to 959972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // read /sys and /proc files) and really badly configured kernels. 960972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->number_of_processors = 0; 961972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->processor_level = 1U; // There is no ARMv1 962972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->processor_revision = 42; 963972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->cpu.arm_cpu_info.cpuid = 0; 964972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->cpu.arm_cpu_info.elf_hwcaps = 0; 965972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 966972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Counting the number of CPUs involves parsing two sysfs files, 967972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // because the content of /proc/cpuinfo will only mirror the number 968972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // of 'online' cores, and thus will vary with time. 969972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // See http://www.kernel.org/doc/Documentation/cputopology.txt 970972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { 971972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org CpuSet cpus_present; 972972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org CpuSet cpus_possible; 973972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 974972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org int fd = sys_open("/sys/devices/system/cpu/present", O_RDONLY, 0); 975972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (fd >= 0) { 976972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org cpus_present.ParseSysFile(fd); 977972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_close(fd); 978972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 979972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org fd = sys_open("/sys/devices/system/cpu/possible", O_RDONLY, 0); 980972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (fd >= 0) { 981972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org cpus_possible.ParseSysFile(fd); 982972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_close(fd); 983972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 984972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org cpus_present.IntersectWith(cpus_possible); 985972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org int cpu_count = cpus_present.GetCount(); 986972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (cpu_count > 255) 987972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org cpu_count = 255; 988972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->number_of_processors = static_cast<uint8_t>(cpu_count); 989972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 990972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 991972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 992972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 993972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Parse /proc/cpuinfo to reconstruct the CPUID value, as well 994972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // as the ELF hwcaps field. For the latter, it would be easier to 995972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // read /proc/self/auxv but unfortunately, this file is not always 996972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // readable from regular Android applications on later versions 997972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // (>= 4.1) of the Android platform. 998972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); 999972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (fd < 0) { 1000972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Do not return false here to allow the minidump generation 1001972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // to happen properly. 1002972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org return true; 1003972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1004972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 1005972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org { 1006972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org PageAllocator allocator; 1007972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org ProcCpuInfoReader* const reader = 1008972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org new(allocator) ProcCpuInfoReader(fd); 1009972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* field; 1010972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org while (reader->GetNextField(&field)) { 1011972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org for (size_t i = 0; 1012972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]); 1013972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org ++i) { 1014972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const CpuIdEntry* entry = &cpu_id_entries[i]; 1015972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (my_strcmp(entry->field, field) != 0) 1016972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org continue; 1017972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org uintptr_t result = 0; 1018972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* value = reader->GetValue(); 1019972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* p = value; 1020972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (value[0] == '0' && value[1] == 'x') { 1021972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org p = my_read_hex_ptr(&result, value+2); 1022447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com } else if (entry->format == 'x') { 1023972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org p = my_read_hex_ptr(&result, value); 1024447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com } else { 1025972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org p = my_read_decimal_ptr(&result, value); 1026447a1149385a9f5a5641a281e4075a38dba51a5eivan.penkov@gmail.com } 1027972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (p == value) 1028972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org continue; 1029972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 1030972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org result &= (1U << entry->bit_length)-1; 1031972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org result <<= entry->bit_lshift; 1032972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->cpu.arm_cpu_info.cpuid |= 1033972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org static_cast<uint32_t>(result); 1034972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1035952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#if defined(__arm__) 1036972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Get the architecture version from the "Processor" field. 1037972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Note that it is also available in the "CPU architecture" field, 1038972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // however, some existing kernels are misconfigured and will report 1039972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // invalid values here (e.g. 6, while the CPU is ARMv7-A based). 1040972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // The "Processor" field doesn't have this issue. 1041972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (!my_strcmp(field, "Processor")) { 1042952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org size_t value_len; 1043972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* value = reader->GetValueAndLen(&value_len); 1044972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Expected format: <text> (v<level><endian>) 1045972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Where <text> is some text like "ARMv7 Processor rev 2" 1046972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // and <level> is a decimal corresponding to the ARM 1047972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // architecture number. <endian> is either 'l' or 'b' 1048972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // and corresponds to the endianess, it is ignored here. 1049972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org while (value_len > 0 && my_isspace(value[value_len-1])) 1050972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org value_len--; 1051972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 1052972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org size_t nn = value_len; 1053972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org while (nn > 0 && value[nn-1] != '(') 1054972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org nn--; 1055972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (nn > 0 && value[nn] == 'v') { 1056972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org uintptr_t arch_level = 5; 1057972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org my_read_decimal_ptr(&arch_level, value + nn + 1); 1058972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->processor_level = static_cast<uint16_t>(arch_level); 1059972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1060972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1061952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#elif defined(__aarch64__) 1062952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org // The aarch64 architecture does not provide the architecture level 1063952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org // in the Processor field, so we instead check the "CPU architecture" 1064952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org // field. 1065952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org if (!my_strcmp(field, "CPU architecture")) { 1066952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org uintptr_t arch_level = 0; 1067952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org const char* value = reader->GetValue(); 1068952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org const char* p = value; 1069952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org p = my_read_decimal_ptr(&arch_level, value); 1070952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org if (p == value) 1071952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org continue; 1072952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org sys_info->processor_level = static_cast<uint16_t>(arch_level); 1073952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org } 1074952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org#endif 1075972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Rebuild the ELF hwcaps from the 'Features' field. 1076972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (!my_strcmp(field, "Features")) { 1077952aa862b163ea4d1c7b7eaf34ef8d1b764fd37crmcilroy@chromium.org size_t value_len; 1078972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* value = reader->GetValueAndLen(&value_len); 1079972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 1080972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org // Parse each space-separated tag. 1081972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org while (value_len > 0) { 1082972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* tag = value; 1083972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org size_t tag_len = value_len; 1084972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const char* p = my_strchr(tag, ' '); 1085972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (p != NULL) { 1086972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org tag_len = static_cast<size_t>(p - tag); 1087972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org value += tag_len + 1; 1088972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org value_len -= tag_len + 1; 1089972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } else { 1090972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org tag_len = strlen(tag); 1091972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org value_len = 0; 1092972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1093972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org for (size_t i = 0; 1094972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org i < sizeof(cpu_features_entries)/ 1095972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sizeof(cpu_features_entries[0]); 1096972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org ++i) { 1097972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org const CpuFeaturesEntry* entry = &cpu_features_entries[i]; 1098972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org if (tag_len == strlen(entry->tag) && 1099972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org !memcmp(tag, entry->tag, tag_len)) { 1100972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry->hwcaps; 1101972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org break; 1102972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1103972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1104972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1105972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1106972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1107972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org sys_close(fd); 1108972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1109972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org 1110972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org return true; 1111972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org } 1112972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#else 1113972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org# error "Unsupported CPU" 1114972816ca0a2c53907b4a75c8351bed0802c9e91bdigit@chromium.org#endif 1115b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1116b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteFile(MDLocationDescriptor* result, const char* filename) { 1117b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid const int fd = sys_open(filename, O_RDONLY, 0); 1118b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (fd < 0) 1119b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 1120b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1121b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // We can't stat the files because several of the files that we want to 1122b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // read are kernel seqfiles, which always have a length of zero. So we have 1123b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid // to read as much as we can into a buffer. 1124f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org static const unsigned kBufSize = 1024 - 2*sizeof(void*); 1125f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org struct Buffers { 1126e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org Buffers* next; 1127f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org size_t len; 1128f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org uint8_t data[kBufSize]; 1129e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers))); 1130f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org buffers->next = NULL; 1131f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org buffers->len = 0; 1132f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org 1133f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org size_t total = 0; 1134e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org for (Buffers* bufptr = buffers;;) { 1135b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid ssize_t r; 1136b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid do { 1137f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len); 1138b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } while (r == -1 && errno == EINTR); 1139b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1140b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (r < 1) 1141b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid break; 1142f66ff1afd2e0f7f16ac2f8d40984cf799f3f099bthestig@chromium.org 1143f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org total += r; 1144f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org bufptr->len += r; 1145f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (bufptr->len == kBufSize) { 1146e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers))); 1147f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org bufptr = bufptr->next; 1148f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org bufptr->next = NULL; 1149f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org bufptr->len = 0; 1150f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org } 1151b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 1152b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_close(fd); 1153b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1154f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (!total) 1155b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 1156b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1157b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid UntypedMDRVA memory(&minidump_writer_); 1158f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org if (!memory.Allocate(total)) 1159b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 1160f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) { 1161be55cc8cf05aace5e8769230e02b5948a0079496mmentovai // Check for special case of a zero-length buffer. This should only 1162be55cc8cf05aace5e8769230e02b5948a0079496mmentovai // occur if a file's size happens to be a multiple of the buffer's 1163be55cc8cf05aace5e8769230e02b5948a0079496mmentovai // size, in which case the final sys_read() will have resulted in 1164be55cc8cf05aace5e8769230e02b5948a0079496mmentovai // zero bytes being read after the final buffer was just allocated. 1165be55cc8cf05aace5e8769230e02b5948a0079496mmentovai if (buffers->len == 0) { 1166be55cc8cf05aace5e8769230e02b5948a0079496mmentovai // This can only occur with final buffer. 1167be55cc8cf05aace5e8769230e02b5948a0079496mmentovai assert(buffers->next == NULL); 1168be55cc8cf05aace5e8769230e02b5948a0079496mmentovai continue; 1169be55cc8cf05aace5e8769230e02b5948a0079496mmentovai } 1170f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org memory.Copy(pos, &buffers->data, buffers->len); 1171f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org pos += buffers->len; 1172f5c8f6fb61ce609452361ee9b61a343570f62d12thestig@chromium.org } 1173b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid *result = memory.location(); 1174b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 1175b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 1176b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1177b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteOSInformation(MDRawSystemInfo* sys_info) { 11785187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#if defined(__ANDROID__) 11795187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org sys_info->platform_id = MD_OS_ANDROID; 11805187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#else 1181b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_info->platform_id = MD_OS_LINUX; 11825187de1ae5cb7df2343b650416aa805084bdf8dadigit@chromium.org#endif 1183b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1184b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid struct utsname uts; 1185b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (uname(&uts)) 1186b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 1187b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1188b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid static const size_t buf_len = 512; 1189b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid char buf[buf_len] = {0}; 1190b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid size_t space_left = buf_len - 1; 1191b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid const char* info_table[] = { 1192b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid uts.sysname, 1193b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid uts.release, 1194b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid uts.version, 1195b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid uts.machine, 1196b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid NULL 1197b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid }; 1198b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool first_item = true; 1199b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid for (const char** cur_info = info_table; *cur_info; cur_info++) { 1200ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org static const char separator[] = " "; 1201ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org size_t separator_len = sizeof(separator) - 1; 1202ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org size_t info_len = my_strlen(*cur_info); 1203b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (info_len == 0) 1204b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid continue; 1205b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1206b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (space_left < info_len + (first_item ? 0 : separator_len)) 1207b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid break; 1208b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1209b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!first_item) { 1210ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org my_strlcat(buf, separator, sizeof(buf)); 1211b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid space_left -= separator_len; 1212b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 1213b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1214b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid first_item = false; 1215ef3ecf7e00698724f49b38c2183e313dcdc17b19digit@chromium.org my_strlcat(buf, *cur_info, sizeof(buf)); 1216b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid space_left -= info_len; 1217b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 1218b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1219b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid MDLocationDescriptor location; 1220b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!minidump_writer_.WriteString(buf, 0, &location)) 1221b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 1222b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid sys_info->csd_version_rva = location.rva; 1223b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1224b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return true; 1225b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 1226b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1227b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid bool WriteProcFile(MDLocationDescriptor* result, pid_t pid, 1228b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid const char* filename) { 1229b5dfa2834d37a669cce3ca62cb7a56b713d368a2kmixter@chromium.org char buf[NAME_MAX]; 12304fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org if (!dumper_->BuildProcPath(buf, pid, filename)) 12314fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org return false; 1232b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return WriteFile(result, buf); 1233b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid } 1234b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1235e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org // Only one of the 2 member variables below should be set to a valid value. 1236e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org const int fd_; // File descriptor where the minidum should be written. 1237e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org const char* path_; // Path to the file where the minidum should be written. 1238e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 1239b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid const struct ucontext* const ucontext_; // also from the signal handler 1240b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#if !defined(__ARM_EABI__) && !defined(__mips__) 1241b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org const google_breakpad::fpstate_t* const float_state_; // ditto 1242b8c5896ddca70d6926083bba0aebf860e5a3b291rmcilroy@chromium.org#endif 1243e8bbceddb1bef18462c3504d10c60a7936a2f530benchan@chromium.org LinuxDumper* dumper_; 1244b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid MinidumpFileWriter minidump_writer_; 124529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org off_t minidump_size_limit_; 1246b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid MDLocationDescriptor crashing_thread_context_; 1247efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // Blocks of memory written to the dump. These are all currently 1248efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // written while writing the thread list stream, but saved here 1249efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek // so a memory list stream can be written afterwards. 1250efa30c13f2e0bf2cb60a9d00010e8cdc162c872ated.mielczarek wasteful_vector<MDMemoryDescriptor> memory_blocks_; 1251ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek // Additional information about some mappings provided by the caller. 1252ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek const MappingList& mapping_list_; 125386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com // Additional memory regions to be included in the dump, 125486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com // provided by the caller. 125586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const AppMemoryList& app_memory_list_; 1256b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid}; 1257b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1258ef7262d4775bf6de750bc2a26dbf98368d7ec0c3ted.mielczarek 1259e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidumpImpl(const char* minidump_path, 1260e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org int minidump_fd, 126129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org off_t minidump_size_limit, 1262e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org pid_t crashing_process, 1263e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org const void* blob, size_t blob_size, 126486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const MappingList& mappings, 126586f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const AppMemoryList& appmem) { 12664fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org LinuxPtraceDumper dumper(crashing_process); 126729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const ExceptionHandler::CrashContext* context = NULL; 126829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org if (blob) { 126929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org if (blob_size != sizeof(ExceptionHandler::CrashContext)) 127029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org return false; 127129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); 127229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org dumper.set_crash_address( 127329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org reinterpret_cast<uintptr_t>(context->siginfo.si_addr)); 127429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org dumper.set_crash_signal(context->siginfo.si_signo); 127529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org dumper.set_crash_thread(context->tid); 127629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org } 127786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com MinidumpWriter writer(minidump_path, minidump_fd, context, mappings, 127886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com appmem, &dumper); 127929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org // Set desired limit for file size of minidump (-1 means no limit). 128029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org writer.set_minidump_size_limit(minidump_size_limit); 1281b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid if (!writer.Init()) 1282b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return false; 1283b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid return writer.Dump(); 1284b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid} 1285b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid 1286e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org} // namespace 1287e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 1288e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgnamespace google_breakpad { 1289e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 1290e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(const char* minidump_path, pid_t crashing_process, 1291e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org const void* blob, size_t blob_size) { 129229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org return WriteMinidumpImpl(minidump_path, -1, -1, 129329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org crashing_process, blob, blob_size, 129486f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com MappingList(), AppMemoryList()); 1295e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org} 1296e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 1297e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(int minidump_fd, pid_t crashing_process, 1298e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org const void* blob, size_t blob_size) { 129929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org return WriteMinidumpImpl(NULL, minidump_fd, -1, 130029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org crashing_process, blob, blob_size, 130186f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com MappingList(), AppMemoryList()); 1302e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org} 1303e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 1304f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.combool WriteMinidump(const char* minidump_path, pid_t process, 1305f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com pid_t process_blamed_thread) { 1306f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com LinuxPtraceDumper dumper(process); 1307f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com // MinidumpWriter will set crash address 1308f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED); 1309f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com dumper.set_crash_thread(process_blamed_thread); 1310f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com MinidumpWriter writer(minidump_path, -1, NULL, MappingList(), 1311f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com AppMemoryList(), &dumper); 1312f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com if (!writer.Init()) 1313f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com return false; 1314f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com return writer.Dump(); 1315f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com} 1316f092d39bfc1090285476784307a10881702179fbted.mielczarek@gmail.com 1317e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(const char* minidump_path, pid_t crashing_process, 1318e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org const void* blob, size_t blob_size, 131986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const MappingList& mappings, 132086f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const AppMemoryList& appmem) { 132129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process, 132229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org blob, blob_size, 132386f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com mappings, appmem); 1324e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org} 1325e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 1326e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.orgbool WriteMinidump(int minidump_fd, pid_t crashing_process, 1327e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org const void* blob, size_t blob_size, 132886f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const MappingList& mappings, 132986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const AppMemoryList& appmem) { 133029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process, 133129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org blob, blob_size, 133229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org mappings, appmem); 133329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org} 133429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org 133529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.orgbool WriteMinidump(const char* minidump_path, off_t minidump_size_limit, 133629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org pid_t crashing_process, 133729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const void* blob, size_t blob_size, 133829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const MappingList& mappings, 133929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const AppMemoryList& appmem) { 134029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit, 134129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org crashing_process, blob, blob_size, 134229a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org mappings, appmem); 134329a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org} 134429a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org 134529a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.orgbool WriteMinidump(int minidump_fd, off_t minidump_size_limit, 134629a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org pid_t crashing_process, 134729a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const void* blob, size_t blob_size, 134829a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const MappingList& mappings, 134929a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org const AppMemoryList& appmem) { 135029a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit, 135129a383cd82d220d95ccdb9fc6a3bd9246ebfa7f8mkrebs@chromium.org crashing_process, blob, blob_size, 135286f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com mappings, appmem); 1353e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org} 1354e751dcaed67b71fa950d1f2c54cd0ddc365248f8jcivelli@chromium.org 1355aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.orgbool WriteMinidump(const char* filename, 1356aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org const MappingList& mappings, 135786f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com const AppMemoryList& appmem, 1358aa52a01f8a977bdb8a1f79ccabab963131574301mark@chromium.org LinuxDumper* dumper) { 135986f79a00ae0829dae0136f758eafbe7c220e0c0dted.mielczarek@gmail.com MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper); 13604fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org if (!writer.Init()) 13614fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org return false; 13624fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org return writer.Dump(); 13634fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org} 13644fa638a7ecb6ab042664300767614308dbc147bbbenchan@chromium.org 1365b0baafc4da1f3ffb84e267dd19d176db3de1c14enealsid} // namespace google_breakpad 1366