1 // -*- mode: C++ -*- 2 3 // Copyright 2010 Google LLC 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google LLC nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // Original author: Jim Blandy <[email protected]> <[email protected]> 32 33 // synth_minidump.h: Interface to SynthMinidump: fake minidump generator. 34 // 35 // We treat a minidump file as the concatenation of a bunch of 36 // test_assembler::Sections. The file header, stream directory, 37 // streams, memory regions, strings, and so on --- each is a Section 38 // that eventually gets appended to the minidump. Dump, Memory, 39 // Context, Thread, and so on all inherit from test_assembler::Section. 40 // For example: 41 // 42 // using google_breakpad::test_assembler::kLittleEndian; 43 // using google_breakpad::SynthMinidump::Context; 44 // using google_breakpad::SynthMinidump::Dump; 45 // using google_breakpad::SynthMinidump::Memory; 46 // using google_breakpad::SynthMinidump::Thread; 47 // 48 // Dump minidump(MD_NORMAL, kLittleEndian); 49 // 50 // Memory stack1(minidump, 0x569eb0a9); 51 // ... build contents of stack1 with test_assembler::Section functions ... 52 // 53 // MDRawContextX86 x86_context1; 54 // x86_context1.context_flags = MD_CONTEXT_X86; 55 // x86_context1.eip = 0x7c90eb94; 56 // x86_context1.esp = 0x569eb0a9; 57 // x86_context1.ebp = x86_context1.esp + something appropriate; 58 // Context context1(minidump, x86_context1); 59 // 60 // Thread thread1(minidump, 0xe4a4821d, stack1, context1); 61 // 62 // minidump.Add(&stack1); 63 // minidump.Add(&context1); 64 // minidump.Add(&thread1); 65 // minidump.Finish(); 66 // 67 // string contents; 68 // EXPECT_TRUE(minidump.GetContents(&contents)); 69 // // contents now holds the bytes of a minidump file 70 // 71 // Because the test_assembler classes let us write Label references to 72 // sections before the Labels' values are known, this gives us 73 // flexibility in how we put the dump together: minidump pieces can 74 // hold the file offsets of other minidump pieces before the 75 // referents' positions have been decided. As long as everything has 76 // been placed by the time we call dump.GetContents to obtain the 77 // bytes, all the Labels' values will be known, and everything will 78 // get patched up appropriately. 79 // 80 // The dump.Add(thing) functions append THINGS's contents to the 81 // minidump, but they also do two other things: 82 // 83 // - dump.Add(thing) invokes thing->Finish, which tells *thing the 84 // offset within the file at which it was placed, and allows *thing 85 // to do any final content generation. 86 // 87 // - If THING is something which should receive an entry in some sort 88 // of list or directory, then dump.Add(THING) automatically creates 89 // the appropriate directory or list entry. Streams must appear in 90 // the stream directory; memory ranges should be listed in the 91 // memory list; threads should be placed in the thread list; and so 92 // on. 93 // 94 // By convention, Section subclass constructors that take references 95 // to other Sections do not take care of 'Add'ing their arguments to 96 // the dump. For example, although the Thread constructor takes 97 // references to a Memory and a Context, it does not add them to the 98 // dump on the caller's behalf. Rather, the caller is responsible for 99 // 'Add'ing every section they create. This allows Sections to be 100 // cited from more than one place; for example, Memory ranges are 101 // cited both from Thread objects (as their stack contents) and by the 102 // memory list stream. 103 // 104 // If you forget to Add some Section, the Dump::GetContents call will 105 // fail, as the test_assembler::Labels used to cite the Section's 106 // contents from elsewhere will still be undefined. 107 #ifndef PROCESSOR_SYNTH_MINIDUMP_H_ 108 #define PROCESSOR_SYNTH_MINIDUMP_H_ 109 110 #include <assert.h> 111 112 #include <iostream> 113 #include <string> 114 115 #include "common/test_assembler.h" 116 #include "common/using_std_string.h" 117 #include "google_breakpad/common/breakpad_types.h" 118 #include "google_breakpad/common/minidump_format.h" 119 120 namespace google_breakpad { 121 122 namespace SynthMinidump { 123 124 using test_assembler::Endianness; 125 using test_assembler::kBigEndian; 126 using test_assembler::kLittleEndian; 127 using test_assembler::kUnsetEndian; 128 using test_assembler::Label; 129 130 class Dump; 131 class Memory; 132 class String; 133 134 // A test_assembler::Section which will be appended to a minidump. 135 class Section: public test_assembler::Section { 136 public: 137 explicit Section(const Dump& dump); 138 139 // Append an MDLocationDescriptor referring to this section to SECTION. 140 // If 'this' is NULL, append a descriptor with a zero length and MDRVA. 141 // 142 // (I couldn't find the language in the C++ standard that says that 143 // invoking member functions of a NULL pointer to a class type is 144 // bad, if such language exists. Having this function handle NULL 145 // 'this' is convenient, but if it causes trouble, it's not hard to 146 // do differently.) 147 void CiteLocationIn(test_assembler::Section* section) const; 148 149 // Note that this section's contents are complete, and that it has 150 // been placed in the minidump file at OFFSET. The 'Add' member 151 // functions call the Finish member function of the object being 152 // added for you; if you are 'Add'ing this section, you needn't Finish it. Finish(const Label & offset)153 virtual void Finish(const Label& offset) { 154 file_offset_ = offset; size_ = Size(); 155 } 156 157 protected: 158 // This section's size and offset within the minidump file. 159 Label file_offset_, size_; 160 }; 161 162 // A stream within a minidump file. 'Add'ing a stream to a minidump 163 // creates an entry for it in the minidump's stream directory. 164 class Stream: public Section { 165 public: 166 // Create a stream of type TYPE. You can append whatever contents 167 // you like to this stream using the test_assembler::Section methods. Stream(const Dump & dump,uint32_t type)168 Stream(const Dump& dump, uint32_t type) : Section(dump), type_(type) { } 169 170 // Append an MDRawDirectory referring to this stream to SECTION. 171 void CiteStreamIn(test_assembler::Section* section) const; 172 173 private: 174 // The type of this stream. 175 uint32_t type_; 176 }; 177 178 class SystemInfo: public Stream { 179 public: 180 // Create an MD_SYSTEM_INFO_STREAM stream belonging to DUMP holding 181 // an MDRawSystem info structure initialized with the values from 182 // SYSTEM_INFO, except that the csd_version field is replaced with 183 // the file offset of the string CSD_VERSION, which can be 'Add'ed 184 // to the dump at the desired location. 185 // 186 // Remember that you are still responsible for 'Add'ing CSD_VERSION 187 // to the dump yourself. 188 SystemInfo(const Dump& dump, 189 const MDRawSystemInfo& system_info, 190 const String& csd_version); 191 192 // Stock MDRawSystemInfo information and associated strings, for 193 // writing tests. 194 static const MDRawSystemInfo windows_x86; 195 static const string windows_x86_csd_version; 196 }; 197 198 // An MDString: a string preceded by a 32-bit length. 199 class String: public Section { 200 public: 201 String(const Dump& dump, const string& value); 202 203 // Append an MDRVA referring to this string to SECTION. 204 void CiteStringIn(test_assembler::Section* section) const; 205 }; 206 207 // A range of memory contents. 'Add'ing a memory range to a minidump 208 // creates n entry for it in the minidump's memory list. By 209 // convention, the 'start', 'Here', and 'Mark' member functions refer 210 // to memory addresses. 211 class Memory: public Section { 212 public: Memory(const Dump & dump,uint64_t address)213 Memory(const Dump& dump, uint64_t address) 214 : Section(dump), address_(address) { start() = address; } 215 216 // Append an MDMemoryDescriptor referring to this memory range to SECTION. 217 void CiteMemoryIn(test_assembler::Section* section) const; 218 219 private: 220 // The process address from which these memory contents were taken. 221 // Shouldn't this be a Label? 222 uint64_t address_; 223 }; 224 225 class Context: public Section { 226 public: 227 // Create a context belonging to DUMP whose contents are a copy of CONTEXT. 228 Context(const Dump& dump, const MDRawContextX86& context); 229 Context(const Dump& dump, const MDRawContextARM& context); 230 Context(const Dump& dump, const MDRawContextMIPS& context); 231 // Add an empty context to the dump. Context(const Dump & dump)232 Context(const Dump& dump) : Section(dump) {} 233 // Add constructors for other architectures here. Remember to byteswap. 234 }; 235 236 class Thread: public Section { 237 public: 238 // Create a thread belonging to DUMP with the given values, citing 239 // STACK and CONTEXT (which you must Add to the dump separately). 240 Thread(const Dump& dump, 241 uint32_t thread_id, 242 const Memory& stack, 243 const Context& context, 244 uint32_t suspend_count = 0, 245 uint32_t priority_class = 0, 246 uint32_t priority = 0, 247 uint64_t teb = 0); 248 }; 249 250 class Module: public Section { 251 public: 252 // Create a module with the given values. Note that CV_RECORD and 253 // MISC_RECORD can be NULL, in which case the corresponding location 254 // descriptior in the minidump will have a length of zero. 255 Module(const Dump& dump, 256 uint64_t base_of_image, 257 uint32_t size_of_image, 258 const String& name, 259 uint32_t time_date_stamp = 1262805309, 260 uint32_t checksum = 0, 261 const MDVSFixedFileInfo& version_info = Module::stock_version_info, 262 const Section* cv_record = NULL, 263 const Section* misc_record = NULL); 264 265 private: 266 // A standard MDVSFixedFileInfo structure to use as a default for 267 // minidumps. There's no reason to make users write out all this crap 268 // over and over. 269 static const MDVSFixedFileInfo stock_version_info; 270 }; 271 272 class UnloadedModule: public Section { 273 public: 274 UnloadedModule(const Dump& dump, 275 uint64_t base_of_image, 276 uint32_t size_of_image, 277 const String& name, 278 uint32_t checksum = 0, 279 uint32_t time_date_stamp = 1262805309); 280 }; 281 282 class Exception : public Stream { 283 public: 284 Exception(const Dump& dump, 285 const Context& context, 286 uint32_t thread_id = 0, 287 uint32_t exception_code = 0, 288 uint32_t exception_flags = 0, 289 uint64_t exception_address = 0); 290 }; 291 292 // A list of entries starting with a 32-bit count, like a memory list 293 // or a thread list. 294 template<typename Element> 295 class List: public Stream { 296 public: List(const Dump & dump,uint32_t type)297 List(const Dump& dump, uint32_t type) : Stream(dump, type), count_(0) { 298 D32(count_label_); 299 } 300 301 // Add ELEMENT to this list. Add(Element * element)302 void Add(Element* element) { 303 element->Finish(file_offset_ + Size()); 304 Append(*element); 305 count_++; 306 } 307 308 // Return true if this List is empty, false otherwise. Empty()309 bool Empty() { return count_ == 0; } 310 311 // Finish up the contents of this section, mark it as having been 312 // placed at OFFSET. Finish(const Label & offset)313 virtual void Finish(const Label& offset) { 314 Stream::Finish(offset); 315 count_label_ = count_; 316 } 317 318 private: 319 size_t count_; 320 321 protected: 322 // This constructor allows derived lists to specify their own layout 323 // rather than starting with count as specified in the public constructor. List(const Dump & dump,uint32_t type,bool)324 List(const Dump& dump, uint32_t type, bool) : Stream(dump, type), count_(0) {} 325 326 Label count_label_; 327 }; 328 329 class UnloadedModuleList : public List<UnloadedModule> { 330 public: 331 UnloadedModuleList(const Dump& dump, uint32_t type); 332 }; 333 334 class Dump: public test_assembler::Section { 335 public: 336 337 // Create a test_assembler::Section containing a minidump file whose 338 // header uses the given values. ENDIANNESS determines the 339 // endianness of the signature; we set this section's default 340 // endianness by this. 341 Dump(uint64_t flags, 342 Endianness endianness = kLittleEndian, 343 uint32_t version = MD_HEADER_VERSION, 344 uint32_t date_time_stamp = 1262805309); 345 346 // The following functions call OBJECT->Finish(), and append the 347 // contents of OBJECT to this minidump. They also record OBJECT in 348 // whatever directory or list is appropriate for its type. The 349 // stream directory, memory list, thread list, and module list are 350 // accumulated this way. 351 Dump& Add(SynthMinidump::Section* object); // simply append data 352 Dump& Add(Stream* object); // append, record in stream directory 353 Dump& Add(Memory* object); // append, record in memory list 354 Dump& Add(Thread* object); // append, record in thread list 355 Dump& Add(Module* object); // append, record in module list 356 Dump& Add(UnloadedModule* object); // append, record in unloaded module list 357 358 // Complete the construction of the minidump, given the Add calls 359 // we've seen up to this point. After this call, this Dump's 360 // contents are complete, all labels should be defined if everything 361 // Cited has been Added, and you may call GetContents on it. 362 void Finish(); 363 364 private: 365 // A label representing the start of the minidump file. 366 Label file_start_; 367 368 // The stream directory. We construct this incrementally from 369 // Add(Stream*) calls. 370 SynthMinidump::Section stream_directory_; // The directory's contents. 371 size_t stream_count_; // The number of streams so far. 372 Label stream_count_label_; // Cited in file header. 373 Label stream_directory_rva_; // The directory's file offset. 374 375 // This minidump's thread list. We construct this incrementally from 376 // Add(Thread*) calls. 377 List<Thread> thread_list_; 378 379 // This minidump's module list. We construct this incrementally from 380 // Add(Module*) calls. 381 List<Module> module_list_; 382 383 // This minidump's unloaded module list. We construct this incrementally from 384 // Add(UnloadedModule*) calls. 385 UnloadedModuleList unloaded_module_list_; 386 387 // This minidump's memory list. We construct this incrementally from 388 // Add(Memory*) calls. This is actually a list of MDMemoryDescriptors, 389 // not memory ranges --- thus the odd type. 390 List<SynthMinidump::Section> memory_list_; 391 }; 392 393 } // namespace SynthMinidump 394 395 } // namespace google_breakpad 396 397 #endif // PROCESSOR_SYNTH_MINIDUMP_H_ 398