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.h: Implements file-based minidump generation. It's |
31 | // intended to be used with the Google Breakpad open source crash handling |
32 | // project. |
33 | |
34 | #ifndef CLIENT_MINIDUMP_FILE_WRITER_H__ |
35 | #define CLIENT_MINIDUMP_FILE_WRITER_H__ |
36 | |
37 | #include <string> |
38 | |
39 | #include "google_breakpad/common/minidump_format.h" |
40 | |
41 | namespace google_breakpad { |
42 | |
43 | class UntypedMDRVA; |
44 | template<typename MDType> class TypedMDRVA; |
45 | |
46 | // The user of this class can Open() a file and add minidump streams, data, and |
47 | // strings using the definitions in minidump_format.h. Since this class is |
48 | // expected to be used in a situation where the current process may be |
49 | // damaged, it will not allocate heap memory. |
50 | // Sample usage: |
51 | // MinidumpFileWriter writer; |
52 | // writer.Open("/tmp/minidump.dmp"); |
53 | // TypedMDRVA<MDRawHeader> header(&writer_); |
54 | // header.Allocate(); |
55 | // header->get()->signature = MD_HEADER_SIGNATURE; |
56 | // : |
57 | // writer.Close(); |
58 | // |
59 | // An alternative is to use SetFile and provide a file descriptor: |
60 | // MinidumpFileWriter writer; |
61 | // writer.SetFile(minidump_fd); |
62 | // TypedMDRVA<MDRawHeader> header(&writer_); |
63 | // header.Allocate(); |
64 | // header->get()->signature = MD_HEADER_SIGNATURE; |
65 | // : |
66 | // writer.Close(); |
67 | |
68 | class MinidumpFileWriter { |
69 | public: |
70 | // Invalid MDRVA (Minidump Relative Virtual Address) |
71 | // returned on failed allocation |
72 | static const MDRVA kInvalidMDRVA; |
73 | |
74 | MinidumpFileWriter(); |
75 | ~MinidumpFileWriter(); |
76 | |
77 | // Open |path| as the destination of the minidump data. If |path| already |
78 | // exists, then Open() will fail. |
79 | // Return true on success, or false on failure. |
80 | bool Open(const char* path); |
81 | |
82 | // Sets the file descriptor |file| as the destination of the minidump data. |
83 | // Can be used as an alternative to Open() when a file descriptor is |
84 | // available. |
85 | // Note that |fd| is not closed when the instance of MinidumpFileWriter is |
86 | // destroyed. |
87 | void SetFile(const int file); |
88 | |
89 | // Close the current file (that was either created when Open was called, or |
90 | // specified with SetFile). |
91 | // Return true on success, or false on failure. |
92 | bool Close(); |
93 | |
94 | // Copy the contents of |str| to a MDString and write it to the file. |
95 | // |str| is expected to be either UTF-16 or UTF-32 depending on the size |
96 | // of wchar_t. |
97 | // Maximum |length| of characters to copy from |str|, or specify 0 to use the |
98 | // entire NULL terminated string. Copying will stop at the first NULL. |
99 | // |location| the allocated location |
100 | // Return true on success, or false on failure |
101 | bool WriteString(const wchar_t* str, unsigned int length, |
102 | MDLocationDescriptor* location); |
103 | |
104 | // Same as above, except with |str| as a UTF-8 string |
105 | bool WriteString(const char* str, unsigned int length, |
106 | MDLocationDescriptor* location); |
107 | |
108 | // Write |size| bytes starting at |src| into the current position. |
109 | // Return true on success and set |output| to position, or false on failure |
110 | bool WriteMemory(const void* src, size_t size, MDMemoryDescriptor* output); |
111 | |
112 | // Copies |size| bytes from |src| to |position| |
113 | // Return true on success, or false on failure |
114 | bool Copy(MDRVA position, const void* src, ssize_t size); |
115 | |
116 | // Return the current position for writing to the minidump |
117 | inline MDRVA position() const { return position_; } |
118 | |
119 | private: |
120 | friend class UntypedMDRVA; |
121 | |
122 | // Allocates an area of |size| bytes. |
123 | // Returns the position of the allocation, or kInvalidMDRVA if it was |
124 | // unable to allocate the bytes. |
125 | MDRVA Allocate(size_t size); |
126 | |
127 | // The file descriptor for the output file. |
128 | int file_; |
129 | |
130 | // Whether |file_| should be closed when the instance is destroyed. |
131 | bool close_file_when_destroyed_; |
132 | |
133 | // Current position in buffer |
134 | MDRVA position_; |
135 | |
136 | // Current allocated size |
137 | size_t size_; |
138 | |
139 | // Copy |length| characters from |str| to |mdstring|. These are distinct |
140 | // because the underlying MDString is a UTF-16 based string. The wchar_t |
141 | // variant may need to create a MDString that has more characters than the |
142 | // source |str|, whereas the UTF-8 variant may coalesce characters to form |
143 | // a single UTF-16 character. |
144 | bool CopyStringToMDString(const wchar_t* str, unsigned int length, |
145 | TypedMDRVA<MDString>* mdstring); |
146 | bool CopyStringToMDString(const char* str, unsigned int length, |
147 | TypedMDRVA<MDString>* mdstring); |
148 | |
149 | // The common templated code for writing a string |
150 | template <typename CharType> |
151 | bool WriteStringCore(const CharType* str, unsigned int length, |
152 | MDLocationDescriptor* location); |
153 | }; |
154 | |
155 | // Represents an untyped allocated chunk |
156 | class UntypedMDRVA { |
157 | public: |
158 | explicit UntypedMDRVA(MinidumpFileWriter* writer) |
159 | : writer_(writer), |
160 | position_(writer->position()), |
161 | size_(0) {} |
162 | |
163 | // Allocates |size| bytes. Must not call more than once. |
164 | // Return true on success, or false on failure |
165 | bool Allocate(size_t size); |
166 | |
167 | // Returns the current position or kInvalidMDRVA if allocation failed |
168 | inline MDRVA position() const { return position_; } |
169 | |
170 | // Number of bytes allocated |
171 | inline size_t size() const { return size_; } |
172 | |
173 | // Return size and position |
174 | inline MDLocationDescriptor location() const { |
175 | MDLocationDescriptor location = { static_cast<uint32_t>(size_), |
176 | position_ }; |
177 | return location; |
178 | } |
179 | |
180 | // Copy |size| bytes starting at |src| into the minidump at |position| |
181 | // Return true on success, or false on failure |
182 | bool Copy(MDRVA position, const void* src, size_t size); |
183 | |
184 | // Copy |size| bytes from |src| to the current position |
185 | inline bool Copy(const void* src, size_t size) { |
186 | return Copy(position_, src, size); |
187 | } |
188 | |
189 | protected: |
190 | // Writer we associate with |
191 | MinidumpFileWriter* writer_; |
192 | |
193 | // Position of the start of the data |
194 | MDRVA position_; |
195 | |
196 | // Allocated size |
197 | size_t size_; |
198 | }; |
199 | |
200 | // Represents a Minidump object chunk. Additional memory can be allocated at |
201 | // the end of the object as a: |
202 | // - single allocation |
203 | // - Array of MDType objects |
204 | // - A MDType object followed by an array |
205 | template<typename MDType> |
206 | class TypedMDRVA : public UntypedMDRVA { |
207 | public: |
208 | // Constructs an unallocated MDRVA |
209 | explicit TypedMDRVA(MinidumpFileWriter* writer) |
210 | : UntypedMDRVA(writer), |
211 | data_(), |
212 | allocation_state_(UNALLOCATED) {} |
213 | |
214 | inline ~TypedMDRVA() { |
215 | // Ensure that the data_ object is written out |
216 | if (allocation_state_ != ARRAY) |
217 | Flush(); |
218 | } |
219 | |
220 | // Address of object data_ of MDType. This is not declared const as the |
221 | // typical usage will be to access the underlying |data_| object as to |
222 | // alter its contents. |
223 | MDType* get() { return &data_; } |
224 | |
225 | // Allocates minidump_size<MDType>::size() bytes. |
226 | // Must not call more than once. |
227 | // Return true on success, or false on failure |
228 | bool Allocate(); |
229 | |
230 | // Allocates minidump_size<MDType>::size() + |additional| bytes. |
231 | // Must not call more than once. |
232 | // Return true on success, or false on failure |
233 | bool Allocate(size_t additional); |
234 | |
235 | // Allocate an array of |count| elements of MDType. |
236 | // Must not call more than once. |
237 | // Return true on success, or false on failure |
238 | bool AllocateArray(size_t count); |
239 | |
240 | // Allocate an array of |count| elements of |size| after object of MDType |
241 | // Must not call more than once. |
242 | // Return true on success, or false on failure |
243 | bool AllocateObjectAndArray(size_t count, size_t size); |
244 | |
245 | // Copy |item| to |index| |
246 | // Must have been allocated using AllocateArray(). |
247 | // Return true on success, or false on failure |
248 | bool CopyIndex(unsigned int index, MDType* item); |
249 | |
250 | // Copy |size| bytes starting at |str| to |index| |
251 | // Must have been allocated using AllocateObjectAndArray(). |
252 | // Return true on success, or false on failure |
253 | bool CopyIndexAfterObject(unsigned int index, const void* src, size_t size); |
254 | |
255 | // Write data_ |
256 | bool Flush(); |
257 | |
258 | private: |
259 | enum AllocationState { |
260 | UNALLOCATED = 0, |
261 | SINGLE_OBJECT, |
262 | ARRAY, |
263 | SINGLE_OBJECT_WITH_ARRAY |
264 | }; |
265 | |
266 | MDType data_; |
267 | AllocationState allocation_state_; |
268 | }; |
269 | |
270 | } // namespace google_breakpad |
271 | |
272 | #endif // CLIENT_MINIDUMP_FILE_WRITER_H__ |
273 | |