/thirdparty/breakpad/client/minidump_file_writer.cc

http://github.com/tomahawk-player/tomahawk · C++ · 273 lines · 179 code · 46 blank · 48 comment · 42 complexity · 9abd413df2b276b518d8e8a2ec97aa31 MD5 · raw file

  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. // minidump_file_writer.cc: Minidump file writer implementation.
  30. //
  31. // See minidump_file_writer.h for documentation.
  32. #include <fcntl.h>
  33. #include <limits.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <unistd.h>
  37. #include "client/minidump_file_writer-inl.h"
  38. #include "common/linux/linux_libc_support.h"
  39. #include "common/string_conversion.h"
  40. #if __linux__
  41. #include "third_party/lss/linux_syscall_support.h"
  42. #endif
  43. namespace google_breakpad {
  44. const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
  45. MinidumpFileWriter::MinidumpFileWriter() : file_(-1), position_(0), size_(0) {
  46. }
  47. MinidumpFileWriter::~MinidumpFileWriter() {
  48. Close();
  49. }
  50. bool MinidumpFileWriter::Open(const char *path) {
  51. assert(file_ == -1);
  52. #if __linux__
  53. file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
  54. #else
  55. file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
  56. #endif
  57. return file_ != -1;
  58. }
  59. bool MinidumpFileWriter::Close() {
  60. bool result = true;
  61. if (file_ != -1) {
  62. if (-1 == ftruncate(file_, position_)) {
  63. return false;
  64. }
  65. #if __linux__
  66. result = (sys_close(file_) == 0);
  67. #else
  68. result = (close(file_) == 0);
  69. #endif
  70. file_ = -1;
  71. }
  72. return result;
  73. }
  74. bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
  75. unsigned int length,
  76. TypedMDRVA<MDString> *mdstring) {
  77. bool result = true;
  78. if (sizeof(wchar_t) == sizeof(u_int16_t)) {
  79. // Shortcut if wchar_t is the same size as MDString's buffer
  80. result = mdstring->Copy(str, mdstring->get()->length);
  81. } else {
  82. u_int16_t out[2];
  83. int out_idx = 0;
  84. // Copy the string character by character
  85. while (length && result) {
  86. UTF32ToUTF16Char(*str, out);
  87. if (!out[0])
  88. return false;
  89. // Process one character at a time
  90. --length;
  91. ++str;
  92. // Append the one or two UTF-16 characters. The first one will be non-
  93. // zero, but the second one may be zero, depending on the conversion from
  94. // UTF-32.
  95. int out_count = out[1] ? 2 : 1;
  96. size_t out_size = sizeof(u_int16_t) * out_count;
  97. result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
  98. out_idx += out_count;
  99. }
  100. }
  101. return result;
  102. }
  103. bool MinidumpFileWriter::CopyStringToMDString(const char *str,
  104. unsigned int length,
  105. TypedMDRVA<MDString> *mdstring) {
  106. bool result = true;
  107. u_int16_t out[2];
  108. int out_idx = 0;
  109. // Copy the string character by character
  110. while (length && result) {
  111. int conversion_count = UTF8ToUTF16Char(str, length, out);
  112. if (!conversion_count)
  113. return false;
  114. // Move the pointer along based on the nubmer of converted characters
  115. length -= conversion_count;
  116. str += conversion_count;
  117. // Append the one or two UTF-16 characters
  118. int out_count = out[1] ? 2 : 1;
  119. size_t out_size = sizeof(u_int16_t) * out_count;
  120. result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
  121. out_idx += out_count;
  122. }
  123. return result;
  124. }
  125. template <typename CharType>
  126. bool MinidumpFileWriter::WriteStringCore(const CharType *str,
  127. unsigned int length,
  128. MDLocationDescriptor *location) {
  129. assert(str);
  130. assert(location);
  131. // Calculate the mdstring length by either limiting to |length| as passed in
  132. // or by finding the location of the NULL character.
  133. unsigned int mdstring_length = 0;
  134. if (!length)
  135. length = INT_MAX;
  136. for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length)
  137. ;
  138. // Allocate the string buffer
  139. TypedMDRVA<MDString> mdstring(this);
  140. if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(u_int16_t)))
  141. return false;
  142. // Set length excluding the NULL and copy the string
  143. mdstring.get()->length =
  144. static_cast<u_int32_t>(mdstring_length * sizeof(u_int16_t));
  145. bool result = CopyStringToMDString(str, mdstring_length, &mdstring);
  146. // NULL terminate
  147. if (result) {
  148. u_int16_t ch = 0;
  149. result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
  150. if (result)
  151. *location = mdstring.location();
  152. }
  153. return result;
  154. }
  155. bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length,
  156. MDLocationDescriptor *location) {
  157. return WriteStringCore(str, length, location);
  158. }
  159. bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
  160. MDLocationDescriptor *location) {
  161. return WriteStringCore(str, length, location);
  162. }
  163. bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
  164. MDMemoryDescriptor *output) {
  165. assert(src);
  166. assert(output);
  167. UntypedMDRVA mem(this);
  168. if (!mem.Allocate(size))
  169. return false;
  170. if (!mem.Copy(src, mem.size()))
  171. return false;
  172. output->start_of_memory_range = reinterpret_cast<u_int64_t>(src);
  173. output->memory = mem.location();
  174. return true;
  175. }
  176. MDRVA MinidumpFileWriter::Allocate(size_t size) {
  177. assert(size);
  178. assert(file_ != -1);
  179. size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
  180. if (position_ + aligned_size > size_) {
  181. size_t growth = aligned_size;
  182. size_t minimal_growth = getpagesize();
  183. // Ensure that the file grows by at least the size of a memory page
  184. if (growth < minimal_growth)
  185. growth = minimal_growth;
  186. size_t new_size = size_ + growth;
  187. if (ftruncate(file_, new_size) != 0)
  188. return kInvalidMDRVA;
  189. size_ = new_size;
  190. }
  191. MDRVA current_position = position_;
  192. position_ += static_cast<MDRVA>(aligned_size);
  193. return current_position;
  194. }
  195. bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
  196. assert(src);
  197. assert(size);
  198. assert(file_ != -1);
  199. // Ensure that the data will fit in the allocated space
  200. if (static_cast<size_t>(size + position) > size_)
  201. return false;
  202. // Seek and write the data
  203. #if __linux__
  204. if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
  205. if (sys_write(file_, src, size) == size) {
  206. #else
  207. if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
  208. if (write(file_, src, size) == size) {
  209. #endif
  210. return true;
  211. }
  212. }
  213. return false;
  214. }
  215. bool UntypedMDRVA::Allocate(size_t size) {
  216. assert(size_ == 0);
  217. size_ = size;
  218. position_ = writer_->Allocate(size_);
  219. return position_ != MinidumpFileWriter::kInvalidMDRVA;
  220. }
  221. bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) {
  222. assert(src);
  223. assert(size);
  224. assert(pos + size <= position_ + size_);
  225. return writer_->Copy(pos, src, size);
  226. }
  227. } // namespace google_breakpad