|
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 __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 __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 __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 __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 |