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