1 // Copyright 2006 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // minidump_file_writer.h: Implements file-based minidump generation. It's 30 // intended to be used with the Google Breakpad open source crash handling 31 // project. 32 33 #ifndef CLIENT_MINIDUMP_FILE_WRITER_H__ 34 #define CLIENT_MINIDUMP_FILE_WRITER_H__ 35 36 #include <string> 37 38 #include "google_breakpad/common/minidump_format.h" 39 40 namespace google_breakpad { 41 42 class UntypedMDRVA; 43 template<typename MDType> class TypedMDRVA; 44 45 // The user of this class can Open() a file and add minidump streams, data, and 46 // strings using the definitions in minidump_format.h. Since this class is 47 // expected to be used in a situation where the current process may be 48 // damaged, it will not allocate heap memory. 49 // Sample usage: 50 // MinidumpFileWriter writer; 51 // writer.Open("/tmp/minidump.dmp"); 52 // TypedMDRVA<MDRawHeader> header(&writer_); 53 // header.Allocate(); 54 // header->get()->signature = MD_HEADER_SIGNATURE; 55 // : 56 // writer.Close(); 57 // 58 // An alternative is to use SetFile and provide a file descriptor: 59 // MinidumpFileWriter writer; 60 // writer.SetFile(minidump_fd); 61 // TypedMDRVA<MDRawHeader> header(&writer_); 62 // header.Allocate(); 63 // header->get()->signature = MD_HEADER_SIGNATURE; 64 // : 65 // writer.Close(); 66 67 class MinidumpFileWriter { 68 public: 69 // Invalid MDRVA (Minidump Relative Virtual Address) 70 // returned on failed allocation 71 static const MDRVA kInvalidMDRVA; 72 73 MinidumpFileWriter(); 74 ~MinidumpFileWriter(); 75 76 // Open |path| as the destination of the minidump data. If |path| already 77 // exists, then Open() will fail. 78 // Return true on success, or false on failure. 79 bool Open(const char* path); 80 81 // Sets the file descriptor |file| as the destination of the minidump data. 82 // Can be used as an alternative to Open() when a file descriptor is 83 // available. 84 // Note that |fd| is not closed when the instance of MinidumpFileWriter is 85 // destroyed. 86 void SetFile(const int file); 87 88 // Close the current file (that was either created when Open was called, or 89 // specified with SetFile). 90 // Return true on success, or false on failure. 91 bool Close(); 92 93 // Copy the contents of |str| to a MDString and write it to the file. 94 // |str| is expected to be either UTF-16 or UTF-32 depending on the size 95 // of wchar_t. 96 // Maximum |length| of characters to copy from |str|, or specify 0 to use the 97 // entire NULL terminated string. Copying will stop at the first NULL. 98 // |location| the allocated location 99 // Return true on success, or false on failure 100 bool WriteString(const wchar_t* str, unsigned int length, 101 MDLocationDescriptor* location); 102 103 // Same as above, except with |str| as a UTF-8 string 104 bool WriteString(const char* str, unsigned int length, 105 MDLocationDescriptor* location); 106 107 // Write |size| bytes starting at |src| into the current position. 108 // Return true on success and set |output| to position, or false on failure 109 bool WriteMemory(const void* src, size_t size, MDMemoryDescriptor* output); 110 111 // Copies |size| bytes from |src| to |position| 112 // Return true on success, or false on failure 113 bool Copy(MDRVA position, const void* src, ssize_t size); 114 115 // Return the current position for writing to the minidump position()116 inline MDRVA position() const { return position_; } 117 118 private: 119 friend class UntypedMDRVA; 120 121 // Allocates an area of |size| bytes. 122 // Returns the position of the allocation, or kInvalidMDRVA if it was 123 // unable to allocate the bytes. 124 MDRVA Allocate(size_t size); 125 126 // The file descriptor for the output file. 127 int file_; 128 129 // Whether |file_| should be closed when the instance is destroyed. 130 bool close_file_when_destroyed_; 131 132 // Current position in buffer 133 MDRVA position_; 134 135 // Current allocated size 136 size_t size_; 137 138 // Copy |length| characters from |str| to |mdstring|. These are distinct 139 // because the underlying MDString is a UTF-16 based string. The wchar_t 140 // variant may need to create a MDString that has more characters than the 141 // source |str|, whereas the UTF-8 variant may coalesce characters to form 142 // a single UTF-16 character. 143 bool CopyStringToMDString(const wchar_t* str, unsigned int length, 144 TypedMDRVA<MDString>* mdstring); 145 bool CopyStringToMDString(const char* str, unsigned int length, 146 TypedMDRVA<MDString>* mdstring); 147 148 // The common templated code for writing a string 149 template <typename CharType> 150 bool WriteStringCore(const CharType* str, unsigned int length, 151 MDLocationDescriptor* location); 152 }; 153 154 // Represents an untyped allocated chunk 155 class UntypedMDRVA { 156 public: UntypedMDRVA(MinidumpFileWriter * writer)157 explicit UntypedMDRVA(MinidumpFileWriter* writer) 158 : writer_(writer), 159 position_(writer->position()), 160 size_(0) {} 161 162 // Allocates |size| bytes. Must not call more than once. 163 // Return true on success, or false on failure 164 bool Allocate(size_t size); 165 166 // Returns the current position or kInvalidMDRVA if allocation failed position()167 inline MDRVA position() const { return position_; } 168 169 // Number of bytes allocated size()170 inline size_t size() const { return size_; } 171 172 // Return size and position location()173 inline MDLocationDescriptor location() const { 174 MDLocationDescriptor location = { static_cast<uint32_t>(size_), 175 position_ }; 176 return location; 177 } 178 179 // Copy |size| bytes starting at |src| into the minidump at |position| 180 // Return true on success, or false on failure 181 bool Copy(MDRVA position, const void* src, size_t size); 182 183 // Copy |size| bytes from |src| to the current position Copy(const void * src,size_t size)184 inline bool Copy(const void* src, size_t size) { 185 return Copy(position_, src, size); 186 } 187 188 protected: 189 // Writer we associate with 190 MinidumpFileWriter* writer_; 191 192 // Position of the start of the data 193 MDRVA position_; 194 195 // Allocated size 196 size_t size_; 197 }; 198 199 // Represents a Minidump object chunk. Additional memory can be allocated at 200 // the end of the object as a: 201 // - single allocation 202 // - Array of MDType objects 203 // - A MDType object followed by an array 204 template<typename MDType> 205 class TypedMDRVA : public UntypedMDRVA { 206 public: 207 // Constructs an unallocated MDRVA TypedMDRVA(MinidumpFileWriter * writer)208 explicit TypedMDRVA(MinidumpFileWriter* writer) 209 : UntypedMDRVA(writer), 210 data_(), 211 allocation_state_(UNALLOCATED) {} 212 ~TypedMDRVA()213 inline ~TypedMDRVA() { 214 // Ensure that the data_ object is written out 215 if (allocation_state_ != ARRAY) 216 Flush(); 217 } 218 219 // Address of object data_ of MDType. This is not declared const as the 220 // typical usage will be to access the underlying |data_| object as to 221 // alter its contents. get()222 MDType* get() { return &data_; } 223 224 // Allocates minidump_size<MDType>::size() bytes. 225 // Must not call more than once. 226 // Return true on success, or false on failure 227 bool Allocate(); 228 229 // Allocates minidump_size<MDType>::size() + |additional| bytes. 230 // Must not call more than once. 231 // Return true on success, or false on failure 232 bool Allocate(size_t additional); 233 234 // Allocate an array of |count| elements of MDType. 235 // Must not call more than once. 236 // Return true on success, or false on failure 237 bool AllocateArray(size_t count); 238 239 // Allocate an array of |count| elements of |size| after object of MDType 240 // Must not call more than once. 241 // Return true on success, or false on failure 242 bool AllocateObjectAndArray(size_t count, size_t size); 243 244 // Copy |item| to |index| 245 // Must have been allocated using AllocateArray(). 246 // Return true on success, or false on failure 247 bool CopyIndex(unsigned int index, MDType* item); 248 249 // Copy |size| bytes starting at |str| to |index| 250 // Must have been allocated using AllocateObjectAndArray(). 251 // Return true on success, or false on failure 252 bool CopyIndexAfterObject(unsigned int index, const void* src, size_t size); 253 254 // Write data_ 255 bool Flush(); 256 257 private: 258 enum AllocationState { 259 UNALLOCATED = 0, 260 SINGLE_OBJECT, 261 ARRAY, 262 SINGLE_OBJECT_WITH_ARRAY 263 }; 264 265 MDType data_; 266 AllocationState allocation_state_; 267 }; 268 269 } // namespace google_breakpad 270 271 #endif // CLIENT_MINIDUMP_FILE_WRITER_H__ 272