1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,284 @@ 1.4 +// Copyright (c) 2006, Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// minidump_file_writer.cc: Minidump file writer implementation. 1.34 +// 1.35 +// See minidump_file_writer.h for documentation. 1.36 + 1.37 +#include <fcntl.h> 1.38 +#include <limits.h> 1.39 +#include <stdio.h> 1.40 +#include <string.h> 1.41 +#include <unistd.h> 1.42 + 1.43 +#include "client/minidump_file_writer-inl.h" 1.44 +#include "common/linux/linux_libc_support.h" 1.45 +#include "common/string_conversion.h" 1.46 +#if __linux__ 1.47 +#include "third_party/lss/linux_syscall_support.h" 1.48 +#endif 1.49 + 1.50 +namespace google_breakpad { 1.51 + 1.52 +const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1); 1.53 + 1.54 +MinidumpFileWriter::MinidumpFileWriter() 1.55 + : file_(-1), 1.56 + close_file_when_destroyed_(true), 1.57 + position_(0), 1.58 + size_(0) { 1.59 +} 1.60 + 1.61 +MinidumpFileWriter::~MinidumpFileWriter() { 1.62 + if (close_file_when_destroyed_) 1.63 + Close(); 1.64 +} 1.65 + 1.66 +bool MinidumpFileWriter::Open(const char *path) { 1.67 + assert(file_ == -1); 1.68 +#if __linux__ 1.69 + file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); 1.70 +#else 1.71 + file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); 1.72 +#endif 1.73 + 1.74 + return file_ != -1; 1.75 +} 1.76 + 1.77 +void MinidumpFileWriter::SetFile(const int file) { 1.78 + assert(file_ == -1); 1.79 + file_ = file; 1.80 + close_file_when_destroyed_ = false; 1.81 +} 1.82 + 1.83 +bool MinidumpFileWriter::Close() { 1.84 + bool result = true; 1.85 + 1.86 + if (file_ != -1) { 1.87 + if (-1 == ftruncate(file_, position_)) { 1.88 + return false; 1.89 + } 1.90 +#if __linux__ 1.91 + result = (sys_close(file_) == 0); 1.92 +#else 1.93 + result = (close(file_) == 0); 1.94 +#endif 1.95 + file_ = -1; 1.96 + } 1.97 + 1.98 + return result; 1.99 +} 1.100 + 1.101 +bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str, 1.102 + unsigned int length, 1.103 + TypedMDRVA<MDString> *mdstring) { 1.104 + bool result = true; 1.105 + if (sizeof(wchar_t) == sizeof(uint16_t)) { 1.106 + // Shortcut if wchar_t is the same size as MDString's buffer 1.107 + result = mdstring->Copy(str, mdstring->get()->length); 1.108 + } else { 1.109 + uint16_t out[2]; 1.110 + int out_idx = 0; 1.111 + 1.112 + // Copy the string character by character 1.113 + while (length && result) { 1.114 + UTF32ToUTF16Char(*str, out); 1.115 + if (!out[0]) 1.116 + return false; 1.117 + 1.118 + // Process one character at a time 1.119 + --length; 1.120 + ++str; 1.121 + 1.122 + // Append the one or two UTF-16 characters. The first one will be non- 1.123 + // zero, but the second one may be zero, depending on the conversion from 1.124 + // UTF-32. 1.125 + int out_count = out[1] ? 2 : 1; 1.126 + size_t out_size = sizeof(uint16_t) * out_count; 1.127 + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); 1.128 + out_idx += out_count; 1.129 + } 1.130 + } 1.131 + return result; 1.132 +} 1.133 + 1.134 +bool MinidumpFileWriter::CopyStringToMDString(const char *str, 1.135 + unsigned int length, 1.136 + TypedMDRVA<MDString> *mdstring) { 1.137 + bool result = true; 1.138 + uint16_t out[2]; 1.139 + int out_idx = 0; 1.140 + 1.141 + // Copy the string character by character 1.142 + while (length && result) { 1.143 + int conversion_count = UTF8ToUTF16Char(str, length, out); 1.144 + if (!conversion_count) 1.145 + return false; 1.146 + 1.147 + // Move the pointer along based on the nubmer of converted characters 1.148 + length -= conversion_count; 1.149 + str += conversion_count; 1.150 + 1.151 + // Append the one or two UTF-16 characters 1.152 + int out_count = out[1] ? 2 : 1; 1.153 + size_t out_size = sizeof(uint16_t) * out_count; 1.154 + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); 1.155 + out_idx += out_count; 1.156 + } 1.157 + return result; 1.158 +} 1.159 + 1.160 +template <typename CharType> 1.161 +bool MinidumpFileWriter::WriteStringCore(const CharType *str, 1.162 + unsigned int length, 1.163 + MDLocationDescriptor *location) { 1.164 + assert(str); 1.165 + assert(location); 1.166 + // Calculate the mdstring length by either limiting to |length| as passed in 1.167 + // or by finding the location of the NULL character. 1.168 + unsigned int mdstring_length = 0; 1.169 + if (!length) 1.170 + length = INT_MAX; 1.171 + for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length) 1.172 + ; 1.173 + 1.174 + // Allocate the string buffer 1.175 + TypedMDRVA<MDString> mdstring(this); 1.176 + if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t))) 1.177 + return false; 1.178 + 1.179 + // Set length excluding the NULL and copy the string 1.180 + mdstring.get()->length = 1.181 + static_cast<uint32_t>(mdstring_length * sizeof(uint16_t)); 1.182 + bool result = CopyStringToMDString(str, mdstring_length, &mdstring); 1.183 + 1.184 + // NULL terminate 1.185 + if (result) { 1.186 + uint16_t ch = 0; 1.187 + result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch)); 1.188 + 1.189 + if (result) 1.190 + *location = mdstring.location(); 1.191 + } 1.192 + 1.193 + return result; 1.194 +} 1.195 + 1.196 +bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length, 1.197 + MDLocationDescriptor *location) { 1.198 + return WriteStringCore(str, length, location); 1.199 +} 1.200 + 1.201 +bool MinidumpFileWriter::WriteString(const char *str, unsigned int length, 1.202 + MDLocationDescriptor *location) { 1.203 + return WriteStringCore(str, length, location); 1.204 +} 1.205 + 1.206 +bool MinidumpFileWriter::WriteMemory(const void *src, size_t size, 1.207 + MDMemoryDescriptor *output) { 1.208 + assert(src); 1.209 + assert(output); 1.210 + UntypedMDRVA mem(this); 1.211 + 1.212 + if (!mem.Allocate(size)) 1.213 + return false; 1.214 + if (!mem.Copy(src, mem.size())) 1.215 + return false; 1.216 + 1.217 + output->start_of_memory_range = reinterpret_cast<uint64_t>(src); 1.218 + output->memory = mem.location(); 1.219 + 1.220 + return true; 1.221 +} 1.222 + 1.223 +MDRVA MinidumpFileWriter::Allocate(size_t size) { 1.224 + assert(size); 1.225 + assert(file_ != -1); 1.226 + size_t aligned_size = (size + 7) & ~7; // 64-bit alignment 1.227 + 1.228 + if (position_ + aligned_size > size_) { 1.229 + size_t growth = aligned_size; 1.230 + size_t minimal_growth = getpagesize(); 1.231 + 1.232 + // Ensure that the file grows by at least the size of a memory page 1.233 + if (growth < minimal_growth) 1.234 + growth = minimal_growth; 1.235 + 1.236 + size_t new_size = size_ + growth; 1.237 + if (ftruncate(file_, new_size) != 0) 1.238 + return kInvalidMDRVA; 1.239 + 1.240 + size_ = new_size; 1.241 + } 1.242 + 1.243 + MDRVA current_position = position_; 1.244 + position_ += static_cast<MDRVA>(aligned_size); 1.245 + 1.246 + return current_position; 1.247 +} 1.248 + 1.249 +bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) { 1.250 + assert(src); 1.251 + assert(size); 1.252 + assert(file_ != -1); 1.253 + 1.254 + // Ensure that the data will fit in the allocated space 1.255 + if (static_cast<size_t>(size + position) > size_) 1.256 + return false; 1.257 + 1.258 + // Seek and write the data 1.259 +#if __linux__ 1.260 + if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) { 1.261 + if (sys_write(file_, src, size) == size) { 1.262 +#else 1.263 + if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) { 1.264 + if (write(file_, src, size) == size) { 1.265 +#endif 1.266 + return true; 1.267 + } 1.268 + } 1.269 + 1.270 + return false; 1.271 +} 1.272 + 1.273 +bool UntypedMDRVA::Allocate(size_t size) { 1.274 + assert(size_ == 0); 1.275 + size_ = size; 1.276 + position_ = writer_->Allocate(size_); 1.277 + return position_ != MinidumpFileWriter::kInvalidMDRVA; 1.278 +} 1.279 + 1.280 +bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) { 1.281 + assert(src); 1.282 + assert(size); 1.283 + assert(pos + size <= position_ + size_); 1.284 + return writer_->Copy(pos, src, size); 1.285 +} 1.286 + 1.287 +} // namespace google_breakpad