LCOV - code coverage report
Current view: top level - toolkit/crashreporter/breakpad-client/linux/minidump_writer - minidump_writer.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 547 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13