/ src / processor / synth_minidump.h
synth_minidump.h
  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 <jimb@mozilla.com> <jimb@red-bean.com>
 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.
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.
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:
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.
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:
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.
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.
309    bool Empty() { return count_ == 0; }
310  
311    // Finish up the contents of this section, mark it as having been
312    // placed at 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.
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_