toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006, Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // minidump_file_writer.cc: Minidump file writer implementation.
michael@0 31 //
michael@0 32 // See minidump_file_writer.h for documentation.
michael@0 33
michael@0 34 #include <fcntl.h>
michael@0 35 #include <limits.h>
michael@0 36 #include <stdio.h>
michael@0 37 #include <string.h>
michael@0 38 #include <unistd.h>
michael@0 39
michael@0 40 #include "client/minidump_file_writer-inl.h"
michael@0 41 #include "common/linux/linux_libc_support.h"
michael@0 42 #include "common/string_conversion.h"
michael@0 43 #if __linux__
michael@0 44 #include "third_party/lss/linux_syscall_support.h"
michael@0 45 #endif
michael@0 46
michael@0 47 namespace google_breakpad {
michael@0 48
michael@0 49 const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
michael@0 50
michael@0 51 MinidumpFileWriter::MinidumpFileWriter()
michael@0 52 : file_(-1),
michael@0 53 close_file_when_destroyed_(true),
michael@0 54 position_(0),
michael@0 55 size_(0) {
michael@0 56 }
michael@0 57
michael@0 58 MinidumpFileWriter::~MinidumpFileWriter() {
michael@0 59 if (close_file_when_destroyed_)
michael@0 60 Close();
michael@0 61 }
michael@0 62
michael@0 63 bool MinidumpFileWriter::Open(const char *path) {
michael@0 64 assert(file_ == -1);
michael@0 65 #if __linux__
michael@0 66 file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
michael@0 67 #else
michael@0 68 file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
michael@0 69 #endif
michael@0 70
michael@0 71 return file_ != -1;
michael@0 72 }
michael@0 73
michael@0 74 void MinidumpFileWriter::SetFile(const int file) {
michael@0 75 assert(file_ == -1);
michael@0 76 file_ = file;
michael@0 77 close_file_when_destroyed_ = false;
michael@0 78 }
michael@0 79
michael@0 80 bool MinidumpFileWriter::Close() {
michael@0 81 bool result = true;
michael@0 82
michael@0 83 if (file_ != -1) {
michael@0 84 if (-1 == ftruncate(file_, position_)) {
michael@0 85 return false;
michael@0 86 }
michael@0 87 #if __linux__
michael@0 88 result = (sys_close(file_) == 0);
michael@0 89 #else
michael@0 90 result = (close(file_) == 0);
michael@0 91 #endif
michael@0 92 file_ = -1;
michael@0 93 }
michael@0 94
michael@0 95 return result;
michael@0 96 }
michael@0 97
michael@0 98 bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
michael@0 99 unsigned int length,
michael@0 100 TypedMDRVA<MDString> *mdstring) {
michael@0 101 bool result = true;
michael@0 102 if (sizeof(wchar_t) == sizeof(uint16_t)) {
michael@0 103 // Shortcut if wchar_t is the same size as MDString's buffer
michael@0 104 result = mdstring->Copy(str, mdstring->get()->length);
michael@0 105 } else {
michael@0 106 uint16_t out[2];
michael@0 107 int out_idx = 0;
michael@0 108
michael@0 109 // Copy the string character by character
michael@0 110 while (length && result) {
michael@0 111 UTF32ToUTF16Char(*str, out);
michael@0 112 if (!out[0])
michael@0 113 return false;
michael@0 114
michael@0 115 // Process one character at a time
michael@0 116 --length;
michael@0 117 ++str;
michael@0 118
michael@0 119 // Append the one or two UTF-16 characters. The first one will be non-
michael@0 120 // zero, but the second one may be zero, depending on the conversion from
michael@0 121 // UTF-32.
michael@0 122 int out_count = out[1] ? 2 : 1;
michael@0 123 size_t out_size = sizeof(uint16_t) * out_count;
michael@0 124 result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
michael@0 125 out_idx += out_count;
michael@0 126 }
michael@0 127 }
michael@0 128 return result;
michael@0 129 }
michael@0 130
michael@0 131 bool MinidumpFileWriter::CopyStringToMDString(const char *str,
michael@0 132 unsigned int length,
michael@0 133 TypedMDRVA<MDString> *mdstring) {
michael@0 134 bool result = true;
michael@0 135 uint16_t out[2];
michael@0 136 int out_idx = 0;
michael@0 137
michael@0 138 // Copy the string character by character
michael@0 139 while (length && result) {
michael@0 140 int conversion_count = UTF8ToUTF16Char(str, length, out);
michael@0 141 if (!conversion_count)
michael@0 142 return false;
michael@0 143
michael@0 144 // Move the pointer along based on the nubmer of converted characters
michael@0 145 length -= conversion_count;
michael@0 146 str += conversion_count;
michael@0 147
michael@0 148 // Append the one or two UTF-16 characters
michael@0 149 int out_count = out[1] ? 2 : 1;
michael@0 150 size_t out_size = sizeof(uint16_t) * out_count;
michael@0 151 result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
michael@0 152 out_idx += out_count;
michael@0 153 }
michael@0 154 return result;
michael@0 155 }
michael@0 156
michael@0 157 template <typename CharType>
michael@0 158 bool MinidumpFileWriter::WriteStringCore(const CharType *str,
michael@0 159 unsigned int length,
michael@0 160 MDLocationDescriptor *location) {
michael@0 161 assert(str);
michael@0 162 assert(location);
michael@0 163 // Calculate the mdstring length by either limiting to |length| as passed in
michael@0 164 // or by finding the location of the NULL character.
michael@0 165 unsigned int mdstring_length = 0;
michael@0 166 if (!length)
michael@0 167 length = INT_MAX;
michael@0 168 for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length)
michael@0 169 ;
michael@0 170
michael@0 171 // Allocate the string buffer
michael@0 172 TypedMDRVA<MDString> mdstring(this);
michael@0 173 if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t)))
michael@0 174 return false;
michael@0 175
michael@0 176 // Set length excluding the NULL and copy the string
michael@0 177 mdstring.get()->length =
michael@0 178 static_cast<uint32_t>(mdstring_length * sizeof(uint16_t));
michael@0 179 bool result = CopyStringToMDString(str, mdstring_length, &mdstring);
michael@0 180
michael@0 181 // NULL terminate
michael@0 182 if (result) {
michael@0 183 uint16_t ch = 0;
michael@0 184 result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
michael@0 185
michael@0 186 if (result)
michael@0 187 *location = mdstring.location();
michael@0 188 }
michael@0 189
michael@0 190 return result;
michael@0 191 }
michael@0 192
michael@0 193 bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length,
michael@0 194 MDLocationDescriptor *location) {
michael@0 195 return WriteStringCore(str, length, location);
michael@0 196 }
michael@0 197
michael@0 198 bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
michael@0 199 MDLocationDescriptor *location) {
michael@0 200 return WriteStringCore(str, length, location);
michael@0 201 }
michael@0 202
michael@0 203 bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
michael@0 204 MDMemoryDescriptor *output) {
michael@0 205 assert(src);
michael@0 206 assert(output);
michael@0 207 UntypedMDRVA mem(this);
michael@0 208
michael@0 209 if (!mem.Allocate(size))
michael@0 210 return false;
michael@0 211 if (!mem.Copy(src, mem.size()))
michael@0 212 return false;
michael@0 213
michael@0 214 output->start_of_memory_range = reinterpret_cast<uint64_t>(src);
michael@0 215 output->memory = mem.location();
michael@0 216
michael@0 217 return true;
michael@0 218 }
michael@0 219
michael@0 220 MDRVA MinidumpFileWriter::Allocate(size_t size) {
michael@0 221 assert(size);
michael@0 222 assert(file_ != -1);
michael@0 223 size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
michael@0 224
michael@0 225 if (position_ + aligned_size > size_) {
michael@0 226 size_t growth = aligned_size;
michael@0 227 size_t minimal_growth = getpagesize();
michael@0 228
michael@0 229 // Ensure that the file grows by at least the size of a memory page
michael@0 230 if (growth < minimal_growth)
michael@0 231 growth = minimal_growth;
michael@0 232
michael@0 233 size_t new_size = size_ + growth;
michael@0 234 if (ftruncate(file_, new_size) != 0)
michael@0 235 return kInvalidMDRVA;
michael@0 236
michael@0 237 size_ = new_size;
michael@0 238 }
michael@0 239
michael@0 240 MDRVA current_position = position_;
michael@0 241 position_ += static_cast<MDRVA>(aligned_size);
michael@0 242
michael@0 243 return current_position;
michael@0 244 }
michael@0 245
michael@0 246 bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
michael@0 247 assert(src);
michael@0 248 assert(size);
michael@0 249 assert(file_ != -1);
michael@0 250
michael@0 251 // Ensure that the data will fit in the allocated space
michael@0 252 if (static_cast<size_t>(size + position) > size_)
michael@0 253 return false;
michael@0 254
michael@0 255 // Seek and write the data
michael@0 256 #if __linux__
michael@0 257 if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
michael@0 258 if (sys_write(file_, src, size) == size) {
michael@0 259 #else
michael@0 260 if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
michael@0 261 if (write(file_, src, size) == size) {
michael@0 262 #endif
michael@0 263 return true;
michael@0 264 }
michael@0 265 }
michael@0 266
michael@0 267 return false;
michael@0 268 }
michael@0 269
michael@0 270 bool UntypedMDRVA::Allocate(size_t size) {
michael@0 271 assert(size_ == 0);
michael@0 272 size_ = size;
michael@0 273 position_ = writer_->Allocate(size_);
michael@0 274 return position_ != MinidumpFileWriter::kInvalidMDRVA;
michael@0 275 }
michael@0 276
michael@0 277 bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) {
michael@0 278 assert(src);
michael@0 279 assert(size);
michael@0 280 assert(pos + size <= position_ + size_);
michael@0 281 return writer_->Copy(pos, src, size);
michael@0 282 }
michael@0 283
michael@0 284 } // namespace google_breakpad

mercurial