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

          Line data    Source code
       1             : // Copyright (c) 2014, 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 translation unit generates microdumps into the console (logcat on
      31             : // Android). See crbug.com/410294 for more info and design docs.
      32             : 
      33             : #include "linux/microdump_writer/microdump_writer.h"
      34             : 
      35             : #include <limits>
      36             : 
      37             : #include <sys/utsname.h>
      38             : 
      39             : #include "linux/dump_writer_common/thread_info.h"
      40             : #include "linux/dump_writer_common/ucontext_reader.h"
      41             : #include "linux/handler/exception_handler.h"
      42             : #include "linux/handler/microdump_extra_info.h"
      43             : #include "linux/log/log.h"
      44             : #include "linux/minidump_writer/linux_ptrace_dumper.h"
      45             : #include "common/linux/file_id.h"
      46             : #include "common/linux/linux_libc_support.h"
      47             : #include "common/memory.h"
      48             : 
      49             : namespace {
      50             : 
      51             : using google_breakpad::auto_wasteful_vector;
      52             : using google_breakpad::ExceptionHandler;
      53             : using google_breakpad::kDefaultBuildIdSize;
      54             : using google_breakpad::LinuxDumper;
      55             : using google_breakpad::LinuxPtraceDumper;
      56             : using google_breakpad::MappingInfo;
      57             : using google_breakpad::MappingList;
      58             : using google_breakpad::MicrodumpExtraInfo;
      59             : using google_breakpad::RawContextCPU;
      60             : using google_breakpad::ThreadInfo;
      61             : using google_breakpad::UContextReader;
      62             : 
      63             : const size_t kLineBufferSize = 2048;
      64             : 
      65             : #if !defined(__LP64__)
      66             : // The following are only used by DumpFreeSpace, so need to be compiled
      67             : // in conditionally in the same way.
      68             : 
      69             : template <typename Dst, typename Src>
      70             : Dst saturated_cast(Src src) {
      71             :   if (src >= std::numeric_limits<Dst>::max())
      72             :     return std::numeric_limits<Dst>::max();
      73             :   if (src <= std::numeric_limits<Dst>::min())
      74             :     return std::numeric_limits<Dst>::min();
      75             :   return static_cast<Dst>(src);
      76             : }
      77             : 
      78             : int Log2Floor(uint64_t n) {
      79             :   // Copied from chromium src/base/bits.h
      80             :   if (n == 0)
      81             :     return -1;
      82             :   int log = 0;
      83             :   uint64_t value = n;
      84             :   for (int i = 5; i >= 0; --i) {
      85             :     int shift = (1 << i);
      86             :     uint64_t x = value >> shift;
      87             :     if (x != 0) {
      88             :       value = x;
      89             :       log += shift;
      90             :     }
      91             :   }
      92             :   assert(value == 1u);
      93             :   return log;
      94             : }
      95             : 
      96             : bool MappingsAreAdjacent(const MappingInfo& a, const MappingInfo& b) {
      97             :   // Because of load biasing, we can end up with a situation where two
      98             :   // mappings actually overlap. So we will define adjacency to also include a
      99             :   // b start address that lies within a's address range (including starting
     100             :   // immediately after a).
     101             :   // Because load biasing only ever moves the start address backwards, the end
     102             :   // address should still increase.
     103             :   return a.start_addr <= b.start_addr && a.start_addr + a.size >= b.start_addr;
     104             : }
     105             : 
     106             : bool MappingLessThan(const MappingInfo* a, const MappingInfo* b) {
     107             :   // Return true if mapping a is before mapping b.
     108             :   // For the same reason (load biasing) we compare end addresses, which - unlike
     109             :   // start addresses - will not have been modified.
     110             :   return a->start_addr + a->size < b->start_addr + b->size;
     111             : }
     112             : 
     113             : size_t NextOrderedMapping(
     114             :     const google_breakpad::wasteful_vector<MappingInfo*>& mappings,
     115             :     size_t curr) {
     116             :   // Find the mapping that directly follows mappings[curr].
     117             :   // If no such mapping exists, return |invalid| to indicate this.
     118             :   const size_t invalid = std::numeric_limits<size_t>::max();
     119             :   size_t best = invalid;
     120             :   for (size_t next = 0; next < mappings.size(); ++next) {
     121             :     if (MappingLessThan(mappings[curr], mappings[next]) &&
     122             :         (best == invalid || MappingLessThan(mappings[next], mappings[best]))) {
     123             :       best = next;
     124             :     }
     125             :   }
     126             :   return best;
     127             : }
     128             : 
     129             : #endif  // !__LP64__
     130             : 
     131             : class MicrodumpWriter {
     132             :  public:
     133           0 :   MicrodumpWriter(const ExceptionHandler::CrashContext* context,
     134             :                   const MappingList& mappings,
     135             :                   const MicrodumpExtraInfo& microdump_extra_info,
     136             :                   LinuxDumper* dumper)
     137           0 :       : ucontext_(context ? &context->context : NULL),
     138             : #if !defined(__ARM_EABI__) && !defined(__mips__)
     139           0 :         float_state_(context ? &context->float_state : NULL),
     140             : #endif
     141             :         dumper_(dumper),
     142             :         mapping_list_(mappings),
     143             :         microdump_extra_info_(microdump_extra_info),
     144           0 :         log_line_(NULL) {
     145           0 :     log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
     146           0 :     if (log_line_)
     147           0 :       log_line_[0] = '\0';  // Clear out the log line buffer.
     148           0 :   }
     149             : 
     150           0 :   ~MicrodumpWriter() { dumper_->ThreadsResume(); }
     151             : 
     152           0 :   bool Init() {
     153             :     // In the exceptional case where the system was out of memory and there
     154             :     // wasn't even room to allocate the line buffer, bail out. There is nothing
     155             :     // useful we can possibly achieve without the ability to Log. At least let's
     156             :     // try to not crash.
     157           0 :     if (!dumper_->Init() || !log_line_)
     158           0 :       return false;
     159           0 :     return dumper_->ThreadsSuspend() && dumper_->LateInit();
     160             :   }
     161             : 
     162           0 :   bool Dump() {
     163             :     bool success;
     164           0 :     LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
     165           0 :     DumpProductInformation();
     166           0 :     DumpOSInformation();
     167           0 :     DumpProcessType();
     168           0 :     DumpGPUInformation();
     169             : #if !defined(__LP64__)
     170             :     DumpFreeSpace();
     171             : #endif
     172           0 :     success = DumpCrashingThread();
     173           0 :     if (success)
     174           0 :       success = DumpMappings();
     175           0 :     LogLine("-----END BREAKPAD MICRODUMP-----");
     176           0 :     dumper_->ThreadsResume();
     177           0 :     return success;
     178             :   }
     179             : 
     180             :  private:
     181             :   // Writes one line to the system log.
     182           0 :   void LogLine(const char* msg) {
     183             : #if defined(__ANDROID__)
     184             :     logger::writeToCrashLog(msg);
     185             : #else
     186           0 :     logger::write(msg, my_strlen(msg));
     187           0 :     logger::write("\n", 1);
     188             : #endif
     189           0 :   }
     190             : 
     191             :   // Stages the given string in the current line buffer.
     192           0 :   void LogAppend(const char* str) {
     193           0 :     my_strlcat(log_line_, str, kLineBufferSize);
     194           0 :   }
     195             : 
     196             :   // As above (required to take precedence over template specialization below).
     197           0 :   void LogAppend(char* str) {
     198           0 :     LogAppend(const_cast<const char*>(str));
     199           0 :   }
     200             : 
     201             :   // Stages the hex repr. of the given int type in the current line buffer.
     202             :   template<typename T>
     203           0 :   void LogAppend(T value) {
     204             :     // Make enough room to hex encode the largest int type + NUL.
     205             :     static const char HEX[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
     206             :                                'A', 'B', 'C', 'D', 'E', 'F'};
     207             :     char hexstr[sizeof(T) * 2 + 1];
     208           0 :     for (int i = sizeof(T) * 2 - 1; i >= 0; --i, value >>= 4)
     209           0 :       hexstr[i] = HEX[static_cast<uint8_t>(value) & 0x0F];
     210           0 :     hexstr[sizeof(T) * 2] = '\0';
     211           0 :     LogAppend(hexstr);
     212           0 :   }
     213             : 
     214             :   // Stages the buffer content hex-encoded in the current line buffer.
     215           0 :   void LogAppend(const void* buf, size_t length) {
     216           0 :     const uint8_t* ptr = reinterpret_cast<const uint8_t*>(buf);
     217           0 :     for (size_t i = 0; i < length; ++i, ++ptr)
     218           0 :       LogAppend(*ptr);
     219           0 :   }
     220             : 
     221             :   // Writes out the current line buffer on the system log.
     222           0 :   void LogCommitLine() {
     223           0 :     LogLine(log_line_);
     224           0 :     my_strlcpy(log_line_, "", kLineBufferSize);
     225           0 :   }
     226             : 
     227           0 :   void DumpProductInformation() {
     228           0 :     LogAppend("V ");
     229           0 :     if (microdump_extra_info_.product_info) {
     230           0 :       LogAppend(microdump_extra_info_.product_info);
     231             :     } else {
     232           0 :       LogAppend("UNKNOWN:0.0.0.0");
     233             :     }
     234           0 :     LogCommitLine();
     235           0 :   }
     236             : 
     237           0 :   void DumpProcessType() {
     238           0 :     LogAppend("P ");
     239           0 :     if (microdump_extra_info_.process_type) {
     240           0 :       LogAppend(microdump_extra_info_.process_type);
     241             :     } else {
     242           0 :       LogAppend("UNKNOWN");
     243             :     }
     244           0 :     LogCommitLine();
     245           0 :   }
     246             : 
     247           0 :   void DumpOSInformation() {
     248           0 :     const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
     249             : 
     250             : #if defined(__ANDROID__)
     251             :     const char kOSId[] = "A";
     252             : #else
     253           0 :     const char kOSId[] = "L";
     254             : #endif
     255             : 
     256             : // Dump the runtime architecture. On multiarch devices it might not match the
     257             : // hw architecture (the one returned by uname()), for instance in the case of
     258             : // a 32-bit app running on a aarch64 device.
     259             : #if defined(__aarch64__)
     260             :     const char kArch[] = "arm64";
     261             : #elif defined(__ARMEL__)
     262             :     const char kArch[] = "arm";
     263             : #elif defined(__x86_64__)
     264           0 :     const char kArch[] = "x86_64";
     265             : #elif defined(__i386__)
     266             :     const char kArch[] = "x86";
     267             : #elif defined(__mips__)
     268             : # if _MIPS_SIM == _ABIO32
     269             :     const char kArch[] = "mips";
     270             : # elif _MIPS_SIM == _ABI64
     271             :     const char kArch[] = "mips64";
     272             : # else
     273             : #  error "This mips ABI is currently not supported (n32)"
     274             : #endif
     275             : #else
     276             : #error "This code has not been ported to your platform yet"
     277             : #endif
     278             : 
     279           0 :     LogAppend("O ");
     280           0 :     LogAppend(kOSId);
     281           0 :     LogAppend(" ");
     282           0 :     LogAppend(kArch);
     283           0 :     LogAppend(" ");
     284           0 :     LogAppend(n_cpus);
     285           0 :     LogAppend(" ");
     286             : 
     287             :     // Dump the HW architecture (e.g., armv7l, aarch64).
     288             :     struct utsname uts;
     289           0 :     const bool has_uts_info = (uname(&uts) == 0);
     290           0 :     const char* hwArch = has_uts_info ? uts.machine : "unknown_hw_arch";
     291           0 :     LogAppend(hwArch);
     292           0 :     LogAppend(" ");
     293             : 
     294             :     // If the client has attached a build fingerprint to the MinidumpDescriptor
     295             :     // use that one. Otherwise try to get some basic info from uname().
     296           0 :     if (microdump_extra_info_.build_fingerprint) {
     297           0 :       LogAppend(microdump_extra_info_.build_fingerprint);
     298           0 :     } else if (has_uts_info) {
     299           0 :       LogAppend(uts.release);
     300           0 :       LogAppend(" ");
     301           0 :       LogAppend(uts.version);
     302             :     } else {
     303           0 :       LogAppend("no build fingerprint available");
     304             :     }
     305           0 :     LogCommitLine();
     306           0 :   }
     307             : 
     308           0 :   void DumpGPUInformation() {
     309           0 :     LogAppend("G ");
     310           0 :     if (microdump_extra_info_.gpu_fingerprint) {
     311           0 :       LogAppend(microdump_extra_info_.gpu_fingerprint);
     312             :     } else {
     313           0 :       LogAppend("UNKNOWN");
     314             :     }
     315           0 :     LogCommitLine();
     316           0 :   }
     317             : 
     318           0 :   bool DumpThreadStack(uint32_t thread_id,
     319             :                        uintptr_t stack_pointer,
     320             :                        int max_stack_len,
     321             :                        uint8_t** stack_copy) {
     322           0 :     *stack_copy = NULL;
     323             :     const void* stack;
     324             :     size_t stack_len;
     325             : 
     326           0 :     if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
     327             :       // The stack pointer might not be available. In this case we don't hard
     328             :       // fail, just produce a (almost useless) microdump w/o a stack section.
     329           0 :       return true;
     330             :     }
     331             : 
     332           0 :     LogAppend("S 0 ");
     333           0 :     LogAppend(stack_pointer);
     334           0 :     LogAppend(" ");
     335           0 :     LogAppend(reinterpret_cast<uintptr_t>(stack));
     336           0 :     LogAppend(" ");
     337           0 :     LogAppend(stack_len);
     338           0 :     LogCommitLine();
     339             : 
     340           0 :     if (max_stack_len >= 0 &&
     341           0 :         stack_len > static_cast<unsigned int>(max_stack_len)) {
     342           0 :       stack_len = max_stack_len;
     343             :     }
     344             : 
     345           0 :     *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
     346           0 :     dumper_->CopyFromProcess(*stack_copy, thread_id, stack, stack_len);
     347             : 
     348             :     // Dump the content of the stack, splicing it into chunks which size is
     349             :     // compatible with the max logcat line size (see LOGGER_ENTRY_MAX_PAYLOAD).
     350           0 :     const size_t STACK_DUMP_CHUNK_SIZE = 384;
     351           0 :     for (size_t stack_off = 0; stack_off < stack_len;
     352           0 :          stack_off += STACK_DUMP_CHUNK_SIZE) {
     353           0 :       LogAppend("S ");
     354           0 :       LogAppend(reinterpret_cast<uintptr_t>(stack) + stack_off);
     355           0 :       LogAppend(" ");
     356           0 :       LogAppend(*stack_copy + stack_off,
     357           0 :                 std::min(STACK_DUMP_CHUNK_SIZE, stack_len - stack_off));
     358           0 :       LogCommitLine();
     359             :     }
     360           0 :     return true;
     361             :   }
     362             : 
     363             :   // Write information about the crashing thread.
     364           0 :   bool DumpCrashingThread() {
     365           0 :     const unsigned num_threads = dumper_->threads().size();
     366             : 
     367           0 :     for (unsigned i = 0; i < num_threads; ++i) {
     368             :       MDRawThread thread;
     369           0 :       my_memset(&thread, 0, sizeof(thread));
     370           0 :       thread.thread_id = dumper_->threads()[i];
     371             : 
     372             :       // Dump only the crashing thread.
     373           0 :       if (static_cast<pid_t>(thread.thread_id) != dumper_->crash_thread())
     374           0 :         continue;
     375             : 
     376           0 :       assert(ucontext_);
     377           0 :       assert(!dumper_->IsPostMortem());
     378             : 
     379             :       uint8_t* stack_copy;
     380           0 :       const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
     381           0 :       if (!DumpThreadStack(thread.thread_id, stack_ptr, -1, &stack_copy))
     382           0 :         return false;
     383             : 
     384             :       RawContextCPU cpu;
     385           0 :       my_memset(&cpu, 0, sizeof(RawContextCPU));
     386             : #if !defined(__ARM_EABI__) && !defined(__mips__)
     387           0 :       UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
     388             : #else
     389             :       UContextReader::FillCPUContext(&cpu, ucontext_);
     390             : #endif
     391           0 :       DumpCPUState(&cpu);
     392             :     }
     393           0 :     return true;
     394             :   }
     395             : 
     396           0 :   void DumpCPUState(RawContextCPU* cpu) {
     397           0 :     LogAppend("C ");
     398           0 :     LogAppend(cpu, sizeof(*cpu));
     399           0 :     LogCommitLine();
     400           0 :   }
     401             : 
     402             :   // If there is caller-provided information about this mapping
     403             :   // in the mapping_list_ list, return true. Otherwise, return false.
     404           0 :   bool HaveMappingInfo(const MappingInfo& mapping) {
     405           0 :     for (MappingList::const_iterator iter = mapping_list_.begin();
     406           0 :          iter != mapping_list_.end();
     407             :          ++iter) {
     408             :       // Ignore any mappings that are wholly contained within
     409             :       // mappings in the mapping_info_ list.
     410           0 :       if (mapping.start_addr >= iter->first.start_addr &&
     411           0 :           (mapping.start_addr + mapping.size) <=
     412           0 :               (iter->first.start_addr + iter->first.size)) {
     413           0 :         return true;
     414             :       }
     415             :     }
     416           0 :     return false;
     417             :   }
     418             : 
     419             :   // Dump information about the provided |mapping|. If |identifier| is non-NULL,
     420             :   // use it instead of calculating a file ID from the mapping.
     421           0 :   void DumpModule(const MappingInfo& mapping,
     422             :                   bool member,
     423             :                   unsigned int mapping_id,
     424             :                   const uint8_t* identifier) {
     425             : 
     426             :     auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
     427           0 :         dumper_->allocator());
     428             : 
     429           0 :     if (identifier) {
     430             :       // GUID was provided by caller.
     431           0 :       identifier_bytes.insert(identifier_bytes.end(),
     432             :                               identifier,
     433           0 :                               identifier + sizeof(MDGUID));
     434             :     } else {
     435           0 :       dumper_->ElfFileIdentifierForMapping(
     436             :           mapping,
     437             :           member,
     438             :           mapping_id,
     439           0 :           identifier_bytes);
     440             :     }
     441             : 
     442             :     // Copy as many bytes of |identifier| as will fit into a MDGUID
     443           0 :     MDGUID module_identifier = {0};
     444           0 :     memcpy(&module_identifier, &identifier_bytes[0],
     445           0 :            std::min(sizeof(MDGUID), identifier_bytes.size()));
     446             : 
     447             :     char file_name[NAME_MAX];
     448             :     char file_path[NAME_MAX];
     449           0 :     dumper_->GetMappingEffectiveNameAndPath(
     450           0 :         mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
     451             : 
     452           0 :     LogAppend("M ");
     453           0 :     LogAppend(static_cast<uintptr_t>(mapping.start_addr));
     454           0 :     LogAppend(" ");
     455           0 :     LogAppend(mapping.offset);
     456           0 :     LogAppend(" ");
     457           0 :     LogAppend(mapping.size);
     458           0 :     LogAppend(" ");
     459           0 :     LogAppend(module_identifier.data1);
     460           0 :     LogAppend(module_identifier.data2);
     461           0 :     LogAppend(module_identifier.data3);
     462           0 :     LogAppend(module_identifier.data4[0]);
     463           0 :     LogAppend(module_identifier.data4[1]);
     464           0 :     LogAppend(module_identifier.data4[2]);
     465           0 :     LogAppend(module_identifier.data4[3]);
     466           0 :     LogAppend(module_identifier.data4[4]);
     467           0 :     LogAppend(module_identifier.data4[5]);
     468           0 :     LogAppend(module_identifier.data4[6]);
     469           0 :     LogAppend(module_identifier.data4[7]);
     470           0 :     LogAppend("0 ");  // Age is always 0 on Linux.
     471           0 :     LogAppend(file_name);
     472           0 :     LogCommitLine();
     473           0 :   }
     474             : 
     475             : #if !defined(__LP64__)
     476             :   void DumpFreeSpace() {
     477             :     const google_breakpad::wasteful_vector<MappingInfo*>& mappings =
     478             :         dumper_->mappings();
     479             :     if (mappings.size() == 0) return;
     480             : 
     481             :     // This is complicated by the fact that mappings is not in order. It should
     482             :     // be mostly in order, however the mapping that contains the entry point for
     483             :     // the process is always at the front of the vector.
     484             : 
     485             :     static const int HBITS = sizeof(size_t) * 8;
     486             :     size_t hole_histogram[HBITS];
     487             :     my_memset(hole_histogram, 0, sizeof(hole_histogram));
     488             : 
     489             :     // Find the lowest address mapping.
     490             :     size_t curr = 0;
     491             :     for (size_t i = 1; i < mappings.size(); ++i) {
     492             :       if (mappings[i]->start_addr < mappings[curr]->start_addr) curr = i;
     493             :     }
     494             : 
     495             :     uintptr_t lo_addr = mappings[curr]->start_addr;
     496             : 
     497             :     size_t hole_cnt = 0;
     498             :     size_t hole_max = 0;
     499             :     size_t hole_sum = 0;
     500             : 
     501             :     while (true) {
     502             :       // Skip to the end of an adjacent run of mappings. This is an optimization
     503             :       // for the fact that mappings is mostly sorted.
     504             :       while (curr != mappings.size() - 1 &&
     505             :              MappingsAreAdjacent(*mappings[curr], *mappings[curr + 1])) {
     506             :         ++curr;
     507             :       }
     508             : 
     509             :       size_t next = NextOrderedMapping(mappings, curr);
     510             :       if (next == std::numeric_limits<size_t>::max())
     511             :         break;
     512             : 
     513             :       uintptr_t hole_lo = mappings[curr]->start_addr + mappings[curr]->size;
     514             :       uintptr_t hole_hi = mappings[next]->start_addr;
     515             : 
     516             :       if (hole_hi > hole_lo) {
     517             :         size_t hole_sz = hole_hi - hole_lo;
     518             :         hole_sum += hole_sz;
     519             :         hole_max = std::max(hole_sz, hole_max);
     520             :         ++hole_cnt;
     521             :         ++hole_histogram[Log2Floor(hole_sz)];
     522             :       }
     523             :       curr = next;
     524             :     }
     525             : 
     526             :     uintptr_t hi_addr = mappings[curr]->start_addr + mappings[curr]->size;
     527             : 
     528             :     LogAppend("H ");
     529             :     LogAppend(lo_addr);
     530             :     LogAppend(" ");
     531             :     LogAppend(hi_addr);
     532             :     LogAppend(" ");
     533             :     LogAppend(saturated_cast<uint16_t>(hole_cnt));
     534             :     LogAppend(" ");
     535             :     LogAppend(hole_max);
     536             :     LogAppend(" ");
     537             :     LogAppend(hole_sum);
     538             :     for (unsigned int i = 0; i < HBITS; ++i) {
     539             :       if (!hole_histogram[i]) continue;
     540             :       LogAppend(" ");
     541             :       LogAppend(saturated_cast<uint8_t>(i));
     542             :       LogAppend(":");
     543             :       LogAppend(saturated_cast<uint8_t>(hole_histogram[i]));
     544             :     }
     545             :     LogCommitLine();
     546             :   }
     547             : #endif
     548             : 
     549             :   // Write information about the mappings in effect.
     550           0 :   bool DumpMappings() {
     551             :     // First write all the mappings from the dumper
     552           0 :     for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
     553           0 :       const MappingInfo& mapping = *dumper_->mappings()[i];
     554           0 :       if (mapping.name[0] == 0 ||  // only want modules with filenames.
     555           0 :           !mapping.exec ||  // only want executable mappings.
     556           0 :           mapping.size < 4096 || // too small to get a signature for.
     557           0 :           HaveMappingInfo(mapping)) {
     558           0 :         continue;
     559             :       }
     560             : 
     561           0 :       DumpModule(mapping, true, i, NULL);
     562             :     }
     563             :     // Next write all the mappings provided by the caller
     564           0 :     for (MappingList::const_iterator iter = mapping_list_.begin();
     565           0 :          iter != mapping_list_.end();
     566             :          ++iter) {
     567           0 :       DumpModule(iter->first, false, 0, iter->second);
     568             :     }
     569           0 :     return true;
     570             :   }
     571             : 
     572           0 :   void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
     573             : 
     574             :   const struct ucontext* const ucontext_;
     575             : #if !defined(__ARM_EABI__) && !defined(__mips__)
     576             :   const google_breakpad::fpstate_t* const float_state_;
     577             : #endif
     578             :   LinuxDumper* dumper_;
     579             :   const MappingList& mapping_list_;
     580             :   const MicrodumpExtraInfo microdump_extra_info_;
     581             :   char* log_line_;
     582             : };
     583             : }  // namespace
     584             : 
     585             : namespace google_breakpad {
     586             : 
     587           0 : bool WriteMicrodump(pid_t crashing_process,
     588             :                     const void* blob,
     589             :                     size_t blob_size,
     590             :                     const MappingList& mappings,
     591             :                     const MicrodumpExtraInfo& microdump_extra_info) {
     592           0 :   LinuxPtraceDumper dumper(crashing_process);
     593           0 :   const ExceptionHandler::CrashContext* context = NULL;
     594           0 :   if (blob) {
     595           0 :     if (blob_size != sizeof(ExceptionHandler::CrashContext))
     596           0 :       return false;
     597           0 :     context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
     598           0 :     dumper.set_crash_address(
     599           0 :         reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
     600           0 :     dumper.set_crash_signal(context->siginfo.si_signo);
     601           0 :     dumper.set_crash_thread(context->tid);
     602             :   }
     603           0 :   MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper);
     604           0 :   if (!writer.Init())
     605           0 :     return false;
     606           0 :   return writer.Dump();
     607             : }
     608             : 
     609             : }  // namespace google_breakpad

Generated by: LCOV version 1.13