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

          Line data    Source code
       1             : // Copyright (c) 2006, 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             : // minidump_file_writer.cc: Minidump file writer implementation.
      31             : //
      32             : // See minidump_file_writer.h for documentation.
      33             : 
      34             : #include <fcntl.h>
      35             : #include <limits.h>
      36             : #include <stdio.h>
      37             : #include <string.h>
      38             : #include <unistd.h>
      39             : 
      40             : #include "minidump_file_writer-inl.h"
      41             : #include "common/linux/linux_libc_support.h"
      42             : #include "common/string_conversion.h"
      43             : #if defined(__linux__) && __linux__
      44             : #include "third_party/lss/linux_syscall_support.h"
      45             : #endif
      46             : 
      47             : #if defined(__ANDROID__)
      48             : #include <errno.h>
      49             : 
      50             : namespace {
      51             : 
      52             : bool g_need_ftruncate_workaround = false;
      53             : bool g_checked_need_ftruncate_workaround = false;
      54             : 
      55             : void CheckNeedsFTruncateWorkAround(int file) {
      56             :   if (g_checked_need_ftruncate_workaround) {
      57             :     return;
      58             :   }
      59             :   g_checked_need_ftruncate_workaround = true;
      60             : 
      61             :   // Attempt an idempotent truncate that chops off nothing and see if we
      62             :   // run into any sort of errors.
      63             :   off_t offset = sys_lseek(file, 0, SEEK_END);
      64             :   if (offset == -1) {
      65             :     // lseek failed. Don't apply work around. It's unlikely that we can write
      66             :     // to a minidump with either method.
      67             :     return;
      68             :   }
      69             : 
      70             :   int result = ftruncate(file, offset);
      71             :   if (result == -1 && errno == EACCES) {
      72             :     // It very likely that we are running into the kernel bug in M devices.
      73             :     // We are going to deploy the workaround for writing minidump files
      74             :     // without uses of ftruncate(). This workaround should be fine even
      75             :     // for kernels without the bug.
      76             :     // See http://crbug.com/542840 for more details.
      77             :     g_need_ftruncate_workaround = true;
      78             :   }
      79             : }
      80             : 
      81             : bool NeedsFTruncateWorkAround() {
      82             :   return g_need_ftruncate_workaround;
      83             : }
      84             : 
      85             : }  // namespace
      86             : #endif  // defined(__ANDROID__)
      87             : 
      88             : namespace google_breakpad {
      89             : 
      90             : const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
      91             : 
      92           0 : MinidumpFileWriter::MinidumpFileWriter()
      93             :     : file_(-1),
      94             :       close_file_when_destroyed_(true),
      95             :       position_(0),
      96           0 :       size_(0) {
      97           0 : }
      98             : 
      99           0 : MinidumpFileWriter::~MinidumpFileWriter() {
     100           0 :   if (close_file_when_destroyed_)
     101           0 :     Close();
     102           0 : }
     103             : 
     104           0 : bool MinidumpFileWriter::Open(const char *path) {
     105           0 :   assert(file_ == -1);
     106             : #if defined(__linux__) && __linux__
     107           0 :   file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
     108             : #else
     109             :   file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
     110             : #endif
     111             : 
     112           0 :   return file_ != -1;
     113             : }
     114             : 
     115           0 : void MinidumpFileWriter::SetFile(const int file) {
     116           0 :   assert(file_ == -1);
     117           0 :   file_ = file;
     118           0 :   close_file_when_destroyed_ = false;
     119             : #if defined(__ANDROID__)
     120             :   CheckNeedsFTruncateWorkAround(file);
     121             : #endif
     122           0 : }
     123             : 
     124           0 : bool MinidumpFileWriter::Close() {
     125           0 :   bool result = true;
     126             : 
     127           0 :   if (file_ != -1) {
     128             : #if defined(__ANDROID__)
     129             :     if (!NeedsFTruncateWorkAround() && ftruncate(file_, position_)) {
     130             :        return false;
     131             :     }
     132             : #else
     133           0 :     if (ftruncate(file_, position_)) {
     134           0 :        return false;
     135             :     }
     136             : #endif
     137             : #if defined(__linux__) && __linux__
     138           0 :     result = (sys_close(file_) == 0);
     139             : #else
     140             :     result = (close(file_) == 0);
     141             : #endif
     142           0 :     file_ = -1;
     143             :   }
     144             : 
     145           0 :   return result;
     146             : }
     147             : 
     148           0 : bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
     149             :                                               unsigned int length,
     150             :                                               TypedMDRVA<MDString> *mdstring) {
     151           0 :   bool result = true;
     152             :   if (sizeof(wchar_t) == sizeof(uint16_t)) {
     153             :     // Shortcut if wchar_t is the same size as MDString's buffer
     154             :     result = mdstring->Copy(str, mdstring->get()->length);
     155             :   } else {
     156             :     uint16_t out[2];
     157           0 :     int out_idx = 0;
     158             : 
     159             :     // Copy the string character by character
     160           0 :     while (length && result) {
     161           0 :       UTF32ToUTF16Char(*str, out);
     162           0 :       if (!out[0])
     163           0 :         return false;
     164             : 
     165             :       // Process one character at a time
     166           0 :       --length;
     167           0 :       ++str;
     168             : 
     169             :       // Append the one or two UTF-16 characters.  The first one will be non-
     170             :       // zero, but the second one may be zero, depending on the conversion from
     171             :       // UTF-32.
     172           0 :       int out_count = out[1] ? 2 : 1;
     173           0 :       size_t out_size = sizeof(uint16_t) * out_count;
     174           0 :       result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
     175           0 :       out_idx += out_count;
     176             :     }
     177             :   }
     178           0 :   return result;
     179             : }
     180             : 
     181           0 : bool MinidumpFileWriter::CopyStringToMDString(const char *str,
     182             :                                               unsigned int length,
     183             :                                               TypedMDRVA<MDString> *mdstring) {
     184           0 :   bool result = true;
     185             :   uint16_t out[2];
     186           0 :   int out_idx = 0;
     187             : 
     188             :   // Copy the string character by character
     189           0 :   while (length && result) {
     190           0 :     int conversion_count = UTF8ToUTF16Char(str, length, out);
     191           0 :     if (!conversion_count)
     192           0 :       return false;
     193             : 
     194             :     // Move the pointer along based on the nubmer of converted characters
     195           0 :     length -= conversion_count;
     196           0 :     str += conversion_count;
     197             : 
     198             :     // Append the one or two UTF-16 characters
     199           0 :     int out_count = out[1] ? 2 : 1;
     200           0 :     size_t out_size = sizeof(uint16_t) * out_count;
     201           0 :     result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
     202           0 :     out_idx += out_count;
     203             :   }
     204           0 :   return result;
     205             : }
     206             : 
     207             : template <typename CharType>
     208           0 : bool MinidumpFileWriter::WriteStringCore(const CharType *str,
     209             :                                          unsigned int length,
     210             :                                          MDLocationDescriptor *location) {
     211           0 :   assert(str);
     212           0 :   assert(location);
     213             :   // Calculate the mdstring length by either limiting to |length| as passed in
     214             :   // or by finding the location of the NULL character.
     215           0 :   unsigned int mdstring_length = 0;
     216           0 :   if (!length)
     217           0 :     length = INT_MAX;
     218           0 :   for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length)
     219             :     ;
     220             : 
     221             :   // Allocate the string buffer
     222           0 :   TypedMDRVA<MDString> mdstring(this);
     223           0 :   if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t)))
     224           0 :     return false;
     225             : 
     226             :   // Set length excluding the NULL and copy the string
     227           0 :   mdstring.get()->length =
     228           0 :       static_cast<uint32_t>(mdstring_length * sizeof(uint16_t));
     229           0 :   bool result = CopyStringToMDString(str, mdstring_length, &mdstring);
     230             : 
     231             :   // NULL terminate
     232           0 :   if (result) {
     233           0 :     uint16_t ch = 0;
     234           0 :     result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
     235             : 
     236           0 :     if (result)
     237           0 :       *location = mdstring.location();
     238             :   }
     239             : 
     240           0 :   return result;
     241             : }
     242             : 
     243           0 : bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length,
     244             :                  MDLocationDescriptor *location) {
     245           0 :   return WriteStringCore(str, length, location);
     246             : }
     247             : 
     248           0 : bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
     249             :                  MDLocationDescriptor *location) {
     250           0 :   return WriteStringCore(str, length, location);
     251             : }
     252             : 
     253           0 : bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
     254             :                                      MDMemoryDescriptor *output) {
     255           0 :   assert(src);
     256           0 :   assert(output);
     257           0 :   UntypedMDRVA mem(this);
     258             : 
     259           0 :   if (!mem.Allocate(size))
     260           0 :     return false;
     261           0 :   if (!mem.Copy(src, mem.size()))
     262           0 :     return false;
     263             : 
     264           0 :   output->start_of_memory_range = reinterpret_cast<uint64_t>(src);
     265           0 :   output->memory = mem.location();
     266             : 
     267           0 :   return true;
     268             : }
     269             : 
     270           0 : MDRVA MinidumpFileWriter::Allocate(size_t size) {
     271           0 :   assert(size);
     272           0 :   assert(file_ != -1);
     273             : #if defined(__ANDROID__)
     274             :   if (NeedsFTruncateWorkAround()) {
     275             :     // If ftruncate() is not available. We simply increase the size beyond the
     276             :     // current file size. sys_write() will expand the file when data is written
     277             :     // to it. Because we did not over allocate to fit memory pages, we also
     278             :     // do not need to ftruncate() the file once we are done.
     279             :     size_ += size;
     280             : 
     281             :     // We don't need to seek since the file is unchanged.
     282             :     MDRVA current_position = position_;
     283             :     position_ += static_cast<MDRVA>(size);
     284             :     return current_position;
     285             :   }
     286             : #endif
     287           0 :   size_t aligned_size = (size + 7) & ~7;  // 64-bit alignment
     288             : 
     289           0 :   if (position_ + aligned_size > size_) {
     290           0 :     size_t growth = aligned_size;
     291           0 :     size_t minimal_growth = getpagesize();
     292             : 
     293             :     // Ensure that the file grows by at least the size of a memory page
     294           0 :     if (growth < minimal_growth)
     295           0 :       growth = minimal_growth;
     296             : 
     297           0 :     size_t new_size = size_ + growth;
     298           0 :     if (ftruncate(file_, new_size) != 0)
     299           0 :       return kInvalidMDRVA;
     300             : 
     301           0 :     size_ = new_size;
     302             :   }
     303             : 
     304           0 :   MDRVA current_position = position_;
     305           0 :   position_ += static_cast<MDRVA>(aligned_size);
     306             : 
     307           0 :   return current_position;
     308             : }
     309             : 
     310           0 : bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
     311           0 :   assert(src);
     312           0 :   assert(size);
     313           0 :   assert(file_ != -1);
     314             : 
     315             :   // Ensure that the data will fit in the allocated space
     316           0 :   if (static_cast<size_t>(size + position) > size_)
     317           0 :     return false;
     318             : 
     319             :   // Seek and write the data
     320             : #if defined(__linux__) && __linux__
     321           0 :   if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
     322           0 :     if (sys_write(file_, src, size) == size) {
     323           0 :       return true;
     324             :     }
     325             :   }
     326             : #else
     327             :   if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
     328             :     if (write(file_, src, size) == size) {
     329             :       return true;
     330             :     }
     331             :   }
     332             : #endif
     333           0 :   return false;
     334             : }
     335             : 
     336           0 : bool UntypedMDRVA::Allocate(size_t size) {
     337           0 :   assert(size_ == 0);
     338           0 :   size_ = size;
     339           0 :   position_ = writer_->Allocate(size_);
     340           0 :   return position_ != MinidumpFileWriter::kInvalidMDRVA;
     341             : }
     342             : 
     343           0 : bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) {
     344           0 :   assert(src);
     345           0 :   assert(size);
     346           0 :   assert(pos + size <= position_ + size_);
     347           0 :   return writer_->Copy(pos, src, size);
     348             : }
     349             : 
     350             : }  // namespace google_breakpad

Generated by: LCOV version 1.13