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 "client/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 namespace google_breakpad { 48 49 const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1); 50 51 MinidumpFileWriter::MinidumpFileWriter() 52 : file_(-1), 53 close_file_when_destroyed_(true), 54 position_(0), 55 size_(0) { 56 } 57 58 MinidumpFileWriter::~MinidumpFileWriter() { 59 if (close_file_when_destroyed_) 60 Close(); 61 } 62 63 bool MinidumpFileWriter::Open(const char *path) { 64 assert(file_ == -1); 65 #if defined(__linux__) && __linux__ 66 file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); 67 #else 68 file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); 69 #endif 70 71 return file_ != -1; 72 } 73 74 void MinidumpFileWriter::SetFile(const int file) { 75 assert(file_ == -1); 76 file_ = file; 77 close_file_when_destroyed_ = false; 78 } 79 80 bool MinidumpFileWriter::Close() { 81 bool result = true; 82 83 if (file_ != -1) { 84 if (-1 == ftruncate(file_, position_)) { 85 return false; 86 } 87 #if defined(__linux__) && __linux__ 88 result = (sys_close(file_) == 0); 89 #else 90 result = (close(file_) == 0); 91 #endif 92 file_ = -1; 93 } 94 95 return result; 96 } 97 98 bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str, 99 unsigned int length, 100 TypedMDRVA<MDString> *mdstring) { 101 bool result = true; 102 if (sizeof(wchar_t) == sizeof(uint16_t)) { 103 // Shortcut if wchar_t is the same size as MDString's buffer 104 result = mdstring->Copy(str, mdstring->get()->length); 105 } else { 106 uint16_t out[2]; 107 int out_idx = 0; 108 109 // Copy the string character by character 110 while (length && result) { 111 UTF32ToUTF16Char(*str, out); 112 if (!out[0]) 113 return false; 114 115 // Process one character at a time 116 --length; 117 ++str; 118 119 // Append the one or two UTF-16 characters. The first one will be non- 120 // zero, but the second one may be zero, depending on the conversion from 121 // UTF-32. 122 int out_count = out[1] ? 2 : 1; 123 size_t out_size = sizeof(uint16_t) * out_count; 124 result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); 125 out_idx += out_count; 126 } 127 } 128 return result; 129 } 130 131 bool MinidumpFileWriter::CopyStringToMDString(const char *str, 132 unsigned int length, 133 TypedMDRVA<MDString> *mdstring) { 134 bool result = true; 135 uint16_t out[2]; 136 int out_idx = 0; 137 138 // Copy the string character by character 139 while (length && result) { 140 int conversion_count = UTF8ToUTF16Char(str, length, out); 141 if (!conversion_count) 142 return false; 143 144 // Move the pointer along based on the nubmer of converted characters 145 length -= conversion_count; 146 str += conversion_count; 147 148 // Append the one or two UTF-16 characters 149 int out_count = out[1] ? 2 : 1; 150 size_t out_size = sizeof(uint16_t) * out_count; 151 result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); 152 out_idx += out_count; 153 } 154 return result; 155 } 156 157 template <typename CharType> 158 bool MinidumpFileWriter::WriteStringCore(const CharType *str, 159 unsigned int length, 160 MDLocationDescriptor *location) { 161 assert(str); 162 assert(location); 163 // Calculate the mdstring length by either limiting to |length| as passed in 164 // or by finding the location of the NULL character. 165 unsigned int mdstring_length = 0; 166 if (!length) 167 length = INT_MAX; 168 for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length) 169 ; 170 171 // Allocate the string buffer 172 TypedMDRVA<MDString> mdstring(this); 173 if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t))) 174 return false; 175 176 // Set length excluding the NULL and copy the string 177 mdstring.get()->length = 178 static_cast<uint32_t>(mdstring_length * sizeof(uint16_t)); 179 bool result = CopyStringToMDString(str, mdstring_length, &mdstring); 180 181 // NULL terminate 182 if (result) { 183 uint16_t ch = 0; 184 result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch)); 185 186 if (result) 187 *location = mdstring.location(); 188 } 189 190 return result; 191 } 192 193 bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length, 194 MDLocationDescriptor *location) { 195 return WriteStringCore(str, length, location); 196 } 197 198 bool MinidumpFileWriter::WriteString(const char *str, unsigned int length, 199 MDLocationDescriptor *location) { 200 return WriteStringCore(str, length, location); 201 } 202 203 bool MinidumpFileWriter::WriteMemory(const void *src, size_t size, 204 MDMemoryDescriptor *output) { 205 assert(src); 206 assert(output); 207 UntypedMDRVA mem(this); 208 209 if (!mem.Allocate(size)) 210 return false; 211 if (!mem.Copy(src, mem.size())) 212 return false; 213 214 output->start_of_memory_range = reinterpret_cast<uint64_t>(src); 215 output->memory = mem.location(); 216 217 return true; 218 } 219 220 MDRVA MinidumpFileWriter::Allocate(size_t size) { 221 assert(size); 222 assert(file_ != -1); 223 size_t aligned_size = (size + 7) & ~7; // 64-bit alignment 224 225 if (position_ + aligned_size > size_) { 226 size_t growth = aligned_size; 227 size_t minimal_growth = getpagesize(); 228 229 // Ensure that the file grows by at least the size of a memory page 230 if (growth < minimal_growth) 231 growth = minimal_growth; 232 233 size_t new_size = size_ + growth; 234 if (ftruncate(file_, new_size) != 0) 235 return kInvalidMDRVA; 236 237 size_ = new_size; 238 } 239 240 MDRVA current_position = position_; 241 position_ += static_cast<MDRVA>(aligned_size); 242 243 return current_position; 244 } 245 246 bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) { 247 assert(src); 248 assert(size); 249 assert(file_ != -1); 250 251 // Ensure that the data will fit in the allocated space 252 if (static_cast<size_t>(size + position) > size_) 253 return false; 254 255 // Seek and write the data 256 #if defined(__linux__) && __linux__ 257 if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) { 258 if (sys_write(file_, src, size) == size) { 259 #else 260 if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) { 261 if (write(file_, src, size) == size) { 262 #endif 263 return true; 264 } 265 } 266 267 return false; 268 } 269 270 bool UntypedMDRVA::Allocate(size_t size) { 271 assert(size_ == 0); 272 size_ = size; 273 position_ = writer_->Allocate(size_); 274 return position_ != MinidumpFileWriter::kInvalidMDRVA; 275 } 276 277 bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) { 278 assert(src); 279 assert(size); 280 assert(pos + size <= position_ + size_); 281 return writer_->Copy(pos, src, size); 282 } 283 284 } // namespace google_breakpad 285