Coverage for /Syzygy/minidump/minidump.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
93.0%53570.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  // A utility class for reading minidumps.
  16    :  
  17    :  #ifndef SYZYGY_MINIDUMP_MINIDUMP_H_
  18    :  #define SYZYGY_MINIDUMP_MINIDUMP_H_
  19    :  
  20    :  #include <windows.h>  // NOLINT
  21    :  #include <dbghelp.h>
  22    :  
  23    :  #include <stdint.h>
  24    :  #include <string>
  25    :  #include <vector>
  26    :  
  27    :  #include "base/macros.h"
  28    :  #include "base/files/file_path.h"
  29    :  #include "base/files/scoped_file.h"
  30    :  
  31    :  namespace minidump {
  32    :  
  33    :  namespace internal {
  34    :  
  35    :  // Provides the default header parsing for the TypedMinidumpStream class.
  36    :  class DefaultHeaderParser {
  37    :   public:
  38    :    static size_t Parse(const MINIDUMP_MEMORY_LIST& header);
  39    :    static size_t Parse(const MINIDUMP_MODULE_LIST& header);
  40    :    static size_t Parse(const MINIDUMP_THREAD_LIST& header);
  41    :    static size_t Parse(const MINIDUMP_THREAD_EX_LIST& header);
  42    :  };
  43    :  
  44    :  }  // namespace internal
  45    :  
  46    :  // fwd.
  47    :  template <typename HeaderType,
  48    :            typename ElementType,
  49    :            size_t (*ParseHeaderFunction)(const HeaderType& hdr) =
  50    :                internal::DefaultHeaderParser::Parse>
  51    :  class TypedMinidumpStream;
  52    :  
  53    :  template <typename ElementType>
  54    :  class TypedMinidumpStreamIterator;
  55    :  
  56    :  class Minidump {
  57    :   public:
  58    :    using TypedMemoryList =
  59    :        TypedMinidumpStream<MINIDUMP_MEMORY_LIST, MINIDUMP_MEMORY_DESCRIPTOR>;
  60    :    using TypedModuleList =
  61    :        TypedMinidumpStream<MINIDUMP_MODULE_LIST, MINIDUMP_MODULE>;
  62    :    using TypedThreadList =
  63    :        TypedMinidumpStream<MINIDUMP_THREAD_LIST, MINIDUMP_THREAD>;
  64    :    using TypedThreadExList =
  65    :        TypedMinidumpStream<MINIDUMP_THREAD_EX_LIST, MINIDUMP_THREAD_EX>;
  66    :  
  67    :    static const size_t kNoStreamId = static_cast<size_t>(-1);
  68    :  
  69    :    class Stream;
  70    :  
  71    :    Minidump();
  72    :    ~Minidump();
  73    :  
  74    :    // @name Typed stream accessors.
  75    :    // These functions retrieve typed stream accessors to particular well-known
  76    :    // streams in the mindump directory.
  77    :    // @{
  78    :    TypedMemoryList GetMemoryList() const;
  79    :    TypedModuleList GetModuleList() const;
  80    :    TypedThreadList GetThreadList() const;
  81    :    TypedThreadExList GetThreadExList() const;
  82    :    // @}
  83    :  
  84    :    // Returns a stream for @p location.
  85    :    // @param location defines the offset and length of the returned stream.
  86    :    Stream GetStreamFor(const MINIDUMP_LOCATION_DESCRIPTOR& location) const;
  87    :  
  88    :    // Returns a stream for the file's @p stream_id.
  89    :    // @param stream_id the stream id to return, must be a valid stream id.
  90    :    Stream GetStream(size_t stream_id) const;
  91    :  
  92    :    // Find the next stream of type @p stream_type.
  93    :    // @param prev the previous stream of this type or nullptr.
  94    :    // @param stream_type the stream type to look for.
  95    :    // @returns a valid stream if one can be found, otherwise an invalid stream.
  96    :    Stream FindNextStream(const Stream* prev, size_t stream_type) const;
  97    :  
  98    :    // Accessors.
  99  E :    const std::vector<MINIDUMP_DIRECTORY>& directory() const {
 100  E :      return directory_;
 101  E :    }
 102    :  
 103    :   protected:
 104    :    friend class Stream;
 105    :  
 106    :    // @name Data accessors.
 107    :    // Reads file contents.
 108    :    // @param offset the file offset to read from.
 109    :    // @param data_size the amount of data to read.
 110    :    // @param data where to write the data, must be of size @p data_data size or
 111    :    //     larger.
 112    :    // @returns true on success, false on failure, including a short read.
 113    :    virtual bool ReadBytes(size_t offset, size_t data_size, void* data) const = 0;
 114    :  
 115    :    bool ReadDirectory();
 116    :  
 117    :    std::vector<MINIDUMP_DIRECTORY> directory_;
 118    :  
 119    :   private:
 120    :    DISALLOW_COPY_AND_ASSIGN(Minidump);
 121    :  };
 122    :  
 123    :  // Allows parsing a minidump from a file.
 124    :  class FileMinidump : public Minidump {
 125    :   public:
 126    :    // Opens the minidump file at @p path and verifies its header structure.
 127    :    // @param path the minidump file to open.
 128    :    // @return true on success, false on failure.
 129    :    bool Open(const base::FilePath& path);
 130    :  
 131    :   protected:
 132    :    bool ReadBytes(size_t offset, size_t data_size, void* data) const override;
 133    :  
 134    :   private:
 135    :    base::ScopedFILE file_;
 136    :  };
 137    :  
 138    :  // Allows parsing a minidump from an in-memory buffer.
 139    :  class BufferMinidump : public Minidump {
 140    :   public:
 141    :    BufferMinidump();
 142    :  
 143    :    // Initializes the minidump to the contents of @p buf[0.. @p buf_len].
 144    :    // Note that @p buf must outlive this instance, as it does not take ownership
 145    :    // of the buffer, nor copy it.
 146    :    // @param buf pointer to the buffer containing the minidump.
 147    :    // @param buf_len the size of the @p buf buffer.
 148    :    // @returns true on success, false on failure.
 149    :    bool Initialize(const uint8_t* buf, size_t buf_len);
 150    :  
 151    :   protected:
 152    :    bool ReadBytes(size_t offset, size_t data_size, void* data) const override;
 153    :  
 154    :   private:
 155    :    // Not owned.
 156    :    const uint8_t* buf_;
 157    :    size_t buf_len_;
 158    :  };
 159    :  
 160    :  // A forward-only reading class that bounds reads to streams that make it safe
 161    :  // and easy to parse minidump streams. Streams are lightweight objects that
 162    :  // can be freely copied.
 163    :  // Note that a stream has a current position and a remaining length, and no
 164    :  // independent start position. It's therefore not possible to "rewind" a
 165    :  // stream.
 166    :  class Minidump::Stream {
 167    :   public:
 168    :    Stream();
 169    :    Stream(const Minidump* minidump, size_t offset, size_t length,
 170    :           size_t stream_id);
 171    :  
 172  E :    bool IsValid() const { return minidump_ != nullptr; }
 173    :  
 174    :    // @name Functions that read and advance over the read data.
 175    :    // @{
 176    :    bool ReadAndAdvanceBytes(size_t data_len, void* data);
 177    :    bool ReadAndAdvanceBytes(size_t data_len, std::string* data);
 178    :  
 179    :    template <class DataType>
 180    :    bool ReadAndAdvanceElement(DataType* element);
 181    :    bool ReadAndAdvanceString(std::wstring* data);
 182    :    // @}
 183    :  
 184    :    // @name Functions that will separately read and advance by a number of bytes.
 185    :    // @{
 186    :    bool ReadBytes(size_t data_len, void* data);
 187    :    bool AdvanceBytes(size_t data_len);
 188    :    // @}
 189    :  
 190    :    // Accessors.
 191  E :    size_t current_offset() const { return current_offset_; }
 192  E :    size_t remaining_length() const { return remaining_length_; }
 193  E :    size_t stream_id() const { return stream_id_; }
 194  E :    const Minidump* minidump() const { return minidump_; }
 195    :  
 196    :   private:
 197    :    const Minidump* minidump_;
 198    :  
 199    :    size_t current_offset_;
 200    :    size_t remaining_length_;
 201    :    size_t stream_id_;
 202    :  };
 203    :  
 204    :  // A forward only-iterator for Minidump Streams that yields elements of a
 205    :  // given, fixed type.
 206    :  template <typename ElementType>
 207    :  class TypedMinidumpStreamIterator {
 208    :   public:
 209    :    // Creates a new iterator on @p stream. This iterator will yield
 210    :    // @p stream.GetBytesRemaining() / sizeof(ElementType) elements.
 211  E :    explicit TypedMinidumpStreamIterator(const minidump::Minidump::Stream& stream)
 212  E :        : stream_(stream) {
 213    :      // Make sure the stream contains a range that covers whole elements.
 214  E :      DCHECK(!stream_.IsValid() ||
 215    :             (stream.remaining_length() % sizeof(ElementType) == 0));
 216  E :      if (stream.remaining_length() != 0) {
 217    :        // It's fatal if we can't pre-read the element that should be there.
 218  E :        CHECK(stream_.ReadBytes(sizeof(element_), &element_));
 219    :      }
 220  E :    }
 221    :    TypedMinidumpStreamIterator(const TypedMinidumpStreamIterator& o)
 222    :        : stream_(o.stream), element_(o.element_) {}
 223    :  
 224  E :    void operator++() {
 225    :      // It's invalid to advance the end iterator.
 226  E :      DCHECK_NE(0u, stream_.remaining_length());
 227    :  
 228    :      // It's fatal if we can't advance over the current element.
 229  E :      CHECK(stream_.AdvanceBytes(sizeof(element_)));
 230    :  
 231  E :      if (stream_.remaining_length()) {
 232    :        // Not yet at end, read the current element. Fatal if this fails.
 233  E :        CHECK(stream_.ReadBytes(sizeof(element_), &element_));
 234    :      }
 235  E :    }
 236    :  
 237  E :    bool operator!=(const TypedMinidumpStreamIterator& o) const {
 238    :      // Only iterators on the same minidump can be compared.
 239  E :      DCHECK_EQ(stream_.minidump(), o.stream_.minidump());
 240    :  
 241  E :      return stream_.current_offset() != o.stream_.current_offset();
 242  E :    }
 243    :  
 244  E :    const ElementType& operator*() const {
 245  E :      DCHECK_NE(0u, stream_.remaining_length());
 246  E :      return element_;
 247  E :    }
 248    :  
 249    :   private:
 250    :    // Disallow default construction.
 251    :    TypedMinidumpStreamIterator() {}
 252    :  
 253    :    minidump::Minidump::Stream stream_;
 254    :    ElementType element_;
 255    :  };
 256    :  
 257    :  // A typed minidump stream allows reading a stream header and iterating over
 258    :  // the elements of the stream.
 259    :  template <typename HeaderType,
 260    :            typename ElementType,
 261    :            size_t (*ParseHeaderFunction)(const HeaderType& hdr)>
 262    :  class TypedMinidumpStream {
 263    :   public:
 264    :    using Iterator = TypedMinidumpStreamIterator<ElementType>;
 265    :  
 266    :    // Initializes this instance to a stream of type @p stream_type in
 267    :    // @p minidump.
 268    :    TypedMinidumpStream(const Minidump& minidump, size_t stream_type);
 269    :    TypedMinidumpStream(const TypedMinidumpStream& other) = default;
 270    :  
 271  E :    bool IsValid() const { return element_stream_.IsValid(); }
 272    :  
 273  E :    const HeaderType& header() const {
 274  E :      return *reinterpret_cast<const HeaderType*>(header_storage_);
 275  E :    }
 276    :  
 277  E :    Iterator begin() const { return Iterator(element_stream_); }
 278  E :    Iterator end() const {
 279  E :      return Iterator(Minidump::Stream(
 280    :          element_stream_.minidump(),
 281    :          element_stream_.current_offset() + element_stream_.remaining_length(),
 282    :          0, element_stream_.stream_id()));
 283  E :    }
 284    :  
 285    :   private:
 286    :    // Initializes this instance to a stream of type @p stream_type in
 287    :    // @p minidump.
 288    :    // @returns true on success, false if the stream doesn't exist, is not
 289    :    //     unique, or the stream header can't be read.
 290    :    bool Initialize(const Minidump& minidump, size_t stream_type);
 291    :  
 292    :    // The stream we read elements from, this must be constrained to the
 293    :    // range elements occupy, e.g. positioned at the start of the first element
 294    :    // and span a multiple of sizeof(ElementType) bytes.
 295    :    Minidump::Stream element_stream_;
 296    :  
 297    :    // Some of the MINIDUMP_* headers declare a zero element array as placeholder
 298    :    // for the elements. Since such structures can't be directly instantiated,
 299    :    // we read them into a byte array instead.
 300    :    uint8_t header_storage_[sizeof(HeaderType)];
 301    :  };
 302    :  
 303    :  template <typename HeaderType,
 304    :            typename ElementType,
 305    :            size_t (*ParseHeaderFunction)(const HeaderType& hdr)>
 306    :  TypedMinidumpStream<HeaderType, ElementType, ParseHeaderFunction>::
 307  E :      TypedMinidumpStream(const Minidump& minidump, size_t stream_type) {
 308  E :    memset(header_storage_, 0, sizeof(header_storage_));
 309  E :    Initialize(minidump, stream_type);
 310  E :  }
 311    :  
 312    :  template <typename HeaderType,
 313    :            typename ElementType,
 314    :            size_t (*ParseHeaderFunction)(const HeaderType& hdr)>
 315    :  bool TypedMinidumpStream<HeaderType, ElementType, ParseHeaderFunction>::
 316  E :      Initialize(const Minidump& minidump, size_t stream_type) {
 317    :    // Find the first stream of the requested type.
 318  E :    Minidump::Stream stream = minidump.FindNextStream(nullptr, stream_type);
 319  E :    if (!stream.IsValid())
 320  i :      return false;
 321    :  
 322    :    // Make sure the stream is unique.
 323  E :    if (minidump.FindNextStream(&stream, stream_type).IsValid())
 324  i :      return false;
 325    :  
 326    :    // Read and advance over the header.
 327  E :    if (!stream.ReadAndAdvanceBytes(sizeof(header_storage_), header_storage_))
 328  i :      return false;
 329    :  
 330  E :    size_t number_of_elements = ParseHeaderFunction(header());
 331    :    // Make sure the stream has appropriate byte length.
 332  E :    if (stream.remaining_length() != number_of_elements * sizeof(ElementType))
 333  i :      return false;
 334    :  
 335  E :    element_stream_ = stream;
 336    :  
 337  E :    return true;
 338  E :  }
 339    :  
 340    :  template <typename DataType>
 341  E :  bool Minidump::Stream::ReadAndAdvanceElement(DataType* element) {
 342  E :    return ReadAndAdvanceBytes(sizeof(DataType), element);
 343  E :  }
 344    :  
 345    :  }  // namespace minidump
 346    :  
 347    :  #endif  // SYZYGY_MINIDUMP_MINIDUMP_H_

Coverage information generated Fri Jul 29 11:00:21 2016.