// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This translation unit generates microdumps into the console (logcat on // Android). See crbug.com/410294 for more info and design docs. #ifdef HAVE_CONFIG_H #include <config.h> // Must come first #endif #include "client/linux/microdump_writer/microdump_writer.h" #include <limits> #include <sys/utsname.h> #include "client/linux/dump_writer_common/thread_info.h" #include "client/linux/dump_writer_common/ucontext_reader.h" #include "client/linux/handler/exception_handler.h" #include "client/linux/handler/microdump_extra_info.h" #include "client/linux/log/log.h" #include "client/linux/minidump_writer/linux_ptrace_dumper.h" #include "common/linux/file_id.h" #include "common/linux/linux_libc_support.h" #include "common/memory_allocator.h" namespace { auto_wasteful_vector; kDefaultBuildIdSize; ExceptionHandler; LinuxDumper; LinuxPtraceDumper; MappingInfo; MappingList; MicrodumpExtraInfo; RawContextCPU; ThreadInfo; UContextReader; const size_t kLineBufferSize = …; #if !defined(__LP64__) // The following are only used by DumpFreeSpace, so need to be compiled // in conditionally in the same way. template <typename Dst, typename Src> Dst saturated_cast(Src src) { if (src >= std::numeric_limits<Dst>::max()) return std::numeric_limits<Dst>::max(); if (src <= std::numeric_limits<Dst>::min()) return std::numeric_limits<Dst>::min(); return static_cast<Dst>(src); } int Log2Floor(uint64_t n) { // Copied from chromium src/base/bits.h if (n == 0) return -1; int log = 0; uint64_t value = n; for (int i = 5; i >= 0; --i) { int shift = (1 << i); uint64_t x = value >> shift; if (x != 0) { value = x; log += shift; } } assert(value == 1u); return log; } bool MappingsAreAdjacent(const MappingInfo& a, const MappingInfo& b) { // Because of load biasing, we can end up with a situation where two // mappings actually overlap. So we will define adjacency to also include a // b start address that lies within a's address range (including starting // immediately after a). // Because load biasing only ever moves the start address backwards, the end // address should still increase. return a.start_addr <= b.start_addr && a.start_addr + a.size >= b.start_addr; } bool MappingLessThan(const MappingInfo* a, const MappingInfo* b) { // Return true if mapping a is before mapping b. // For the same reason (load biasing) we compare end addresses, which - unlike // start addresses - will not have been modified. return a->start_addr + a->size < b->start_addr + b->size; } size_t NextOrderedMapping( const google_breakpad::wasteful_vector<MappingInfo*>& mappings, size_t curr) { // Find the mapping that directly follows mappings[curr]. // If no such mapping exists, return |invalid| to indicate this. const size_t invalid = std::numeric_limits<size_t>::max(); size_t best = invalid; for (size_t next = 0; next < mappings.size(); ++next) { if (MappingLessThan(mappings[curr], mappings[next]) && (best == invalid || MappingLessThan(mappings[next], mappings[best]))) { best = next; } } return best; } #endif // !__LP64__ class MicrodumpWriter { … }; } // namespace namespace google_breakpad { bool WriteMicrodump(pid_t crashing_process, const void* blob, size_t blob_size, const MappingList& mappings, bool skip_dump_if_principal_mapping_not_referenced, uintptr_t address_within_principal_mapping, bool sanitize_stack, const MicrodumpExtraInfo& microdump_extra_info) { … } } // namespace google_breakpad