Coverage for /Syzygy/refinery/process_state/process_state.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%00226.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    :  #ifndef SYZYGY_REFINERY_PROCESS_STATE_PROCESS_STATE_H_
  16    :  #define SYZYGY_REFINERY_PROCESS_STATE_PROCESS_STATE_H_
  17    :  
  18    :  #include <iterator>
  19    :  #include <map>
  20    :  #include <vector>
  21    :  
  22    :  #include "base/logging.h"
  23    :  #include "base/macros.h"
  24    :  #include "base/memory/ref_counted.h"
  25    :  #include "syzygy/refinery/core/address.h"
  26    :  #include "syzygy/refinery/core/bit_source.h"
  27    :  #include "syzygy/refinery/process_state/layer_traits.h"
  28    :  #include "syzygy/refinery/process_state/record_traits.h"
  29    :  #include "syzygy/refinery/process_state/refinery.pb.h"
  30    :  
  31  m :  namespace refinery {
  32    :  
  33    :  // Declares the layers a process state knows of.
  34    :  #define PROCESS_STATE_LAYERS(DECL) \
  35  m :    DECL(Bytes)                      \
  36  m :    DECL(Stack)                      \
  37  m :    DECL(StackFrame)                 \
  38  m :    DECL(TypedBlock)                 \
  39  m :    DECL(Module)                     \
  40  m :    DECL(HeapMetadata)               \
  41  m :    DECL(HeapAllocation)
  42    :  
  43    :  // A process state is a cross-platform representation of the memory contents
  44    :  // and other state of a process, typically obtained obtained from a post-mortem
  45    :  // crash minidump. A process state typically contains only a partial state of
  46    :  // the process.
  47    :  // It is comprised of a number of layers, each representing some aspect of the
  48    :  // process (eg raw bytes, stack, stack frames, heap snippets, typed blocks,
  49    :  // loaded libraries, etc.).
  50    :  // Each layer is a bag of records, where each record covers part of the
  51    :  // process' virtual memory space, and contains data specific to that layer and
  52    :  // range. Each layer and the data associated with a record is a protobuf of
  53    :  // a type appropriate to the layer.
  54  m :  class ProcessState : public BitSource {
  55  m :   public:
  56  m :    template <typename RecordType> class Layer;
  57  m :    template <typename RecordType> class Record;
  58    :  
  59    :    // Layers can be named with this enum.
  60  m :    enum LayerEnum {
  61    :  #define DECL_LAYER_ENUM(name) name##Layer,
  62    :      // A sentinel value for errors.
  63  m :      UnknownLayer = -1,
  64    :  
  65  m :      PROCESS_STATE_LAYERS(DECL_LAYER_ENUM)
  66    :  
  67    :  #undef DECL_LAYER_ENUM
  68  m :    };
  69    :  
  70  m :    ProcessState();
  71  m :    ~ProcessState();
  72    :  
  73    :    // Gets the name of @p layer.
  74    :    // @returns the name or nullptr on failure.
  75  m :    static const char* LayerName(LayerEnum layer);
  76    :  
  77    :    // Gets the enum value for the layer named @p name.
  78    :    // @returns the enum associated with @p name or UnknownLayer if no
  79  m :    static LayerEnum LayerFromName(const base::StringPiece& name);
  80    :  
  81    :    // Finds layer of type @p RecordType if one exists.
  82    :    // @param layer on success, the returned layer.
  83    :    // @returns true on success, false if layer doesn't exist.
  84  m :    template<typename RecordType>
  85  m :    bool FindLayer(scoped_refptr<Layer<RecordType>>* layer);
  86    :  
  87    :    // Finds or creates a layer of type @p RecordType.
  88    :    // @param layer the returned layer.
  89  m :    template<typename RecordType>
  90  m :    void FindOrCreateLayer(scoped_refptr<Layer<RecordType>>* layer);
  91    :  
  92    :    // Finds the single record that contains @p addr.
  93    :    // @param addr the address the desired record contains.
  94    :    // @param record on success, the returned record.
  95    :    // @returns true on success, false if there is no single record containing @p
  96    :    //     addr.
  97  m :    template <typename RecordType>
  98  m :    bool FindSingleRecord(Address addr,
  99  m :                          scoped_refptr<Record<RecordType>>* record);
 100    :  
 101    :    // Finds the stack record of the thread of id @p thread_id.
 102    :    // @param thread_id the id of the thread.
 103    :    // @param record on success, the returned stack record.
 104    :    // @returns true on success, false if record doesn't exist.
 105  m :    bool FindStackRecord(size_t thread_id,
 106  m :                         scoped_refptr<Record<Stack>>* record);
 107    :  
 108    :    // @name BitSource implementation.
 109    :    // @{
 110  m :    bool GetAll(const AddressRange& range, void* data_ptr) override;
 111  m :    bool GetFrom(const AddressRange& range,
 112  m :                 size_t* data_cnt,
 113  m :                 void* data_ptr) override;
 114  m :    bool HasSome(const AddressRange& range) override;
 115    :    // @}
 116    :  
 117    :    // Sets an exception. A process state can have a single exception.
 118    :    // @pre @p exception must have a thread id set.
 119    :    // @param exception the exception
 120    :    // @returns true on success, false if the excepting thread doesn't exist or if
 121    :    //     an exception is already set.
 122  m :    bool SetException(const Exception& exception);
 123    :  
 124    :    // Returns the id of the excepting thread.
 125    :    // @param thread_id on success, the id of the excepting thread.
 126    :    // @returns true on success, false if there is no exception.
 127  m :    bool GetExceptingThreadId(size_t* thread_id);
 128    :  
 129  m :   private:
 130  m :    class LayerBase;
 131    :  
 132  m :    template<typename RecordType>
 133  m :    void CreateLayer(scoped_refptr<Layer<RecordType>>* layer);
 134    :  
 135  m :    std::map<RecordId, scoped_refptr<LayerBase>> layers_;
 136    :  
 137  m :    bool has_exception;
 138  m :    size_t excepting_thread_id;
 139    :  
 140  m :    DISALLOW_COPY_AND_ASSIGN(ProcessState);
 141  m :  };
 142    :  
 143    :  // A layer is one view on a process (eg raw bytes, stack, stack frames,
 144    :  // typed blocks). It's a bag of records that span some part of the process'
 145    :  // address space.
 146  m :  class ProcessState::LayerBase : public base::RefCounted<LayerBase> {
 147  m :   public:
 148  m :    LayerBase() {}
 149    :  
 150  m :   protected:
 151  m :    friend class base::RefCounted<LayerBase>;
 152  m :    virtual ~LayerBase() {}
 153    :  
 154  m :   private:
 155  m :    DISALLOW_COPY_AND_ASSIGN(LayerBase);
 156  m :  };
 157    :  
 158    :  // An individual record of a layer. Contains the data associated with the
 159    :  // record as a protobuffer.
 160  m :  template <typename RecordType>
 161  m :  class ProcessState::Record : public base::RefCounted<Record<RecordType>> {
 162  m :   public:
 163    :    // @pre @p range must be a valid range.
 164  m :    explicit Record(AddressRange range) : range_(range) {
 165  m :      DCHECK(range.IsValid());
 166  m :    }
 167    :  
 168    :    // @name Accessors.
 169    :    // @{
 170  m :    AddressRange range() const { return range_; }
 171  m :    RecordType* mutable_data() { return &data_; }
 172  m :    const RecordType& data() { return data_; }
 173    :    // @}
 174    :  
 175  m :   private:
 176  m :    friend class base::RefCounted<Record<RecordType>>;
 177  m :    ~Record() {}
 178    :  
 179  m :    AddressRange range_;
 180  m :    RecordType data_;
 181    :  
 182  m :    DISALLOW_COPY_AND_ASSIGN(Record);
 183  m :  };
 184    :  
 185  m :  template <typename RecordType> class Iterator;
 186    :  
 187  m :  template <typename RecordType>
 188  m :  class ProcessState::Layer : public ProcessState::LayerBase {
 189  m :   public:
 190  m :    typedef scoped_refptr<Record<RecordType>> RecordPtr;
 191  m :    typedef Iterator<RecordType> Iterator;
 192    :  
 193    :    // @pre @p range must be a valid.
 194  m :    void CreateRecord(AddressRange range, RecordPtr* record);
 195    :  
 196    :    // Gets records located at |addr|.
 197    :    // @param addr the address records should must be located at.
 198    :    // @param records contains the matching records.
 199  m :    void GetRecordsAt(Address addr, std::vector<RecordPtr>* records) const;
 200    :  
 201    :    // Gets records that fully span |range|.
 202    :    // @pre @p range must be a valid.
 203    :    // @param range the address range the region records should span.
 204    :    // @param records contains the matching records.
 205  m :    void GetRecordsSpanning(const AddressRange& range,
 206  m :                            std::vector<RecordPtr>* records) const;
 207    :  
 208    :    // Gets records that intersect |range|.
 209    :    // @pre @p range must be a valid.
 210    :    // @param range the address range the region records should intersect.
 211    :    // @param records contains the matching records.
 212  m :    void GetRecordsIntersecting(const AddressRange& range,
 213  m :                                std::vector<RecordPtr>* records) const;
 214    :  
 215    :    // Removes |record| from the layer.
 216    :    // @param record the record to remove.
 217    :    // @returns true on success, false otherwise.
 218  m :    bool RemoveRecord(const RecordPtr& record);
 219    :  
 220    :    // Iterators for range-based for loop.
 221  m :    Iterator begin() { return Iterator(records_.begin()); }
 222  m :    Iterator end() { return Iterator(records_.end()); }
 223    :  
 224  m :    size_t size() const { return records_.size(); }
 225    :  
 226  m :    typename const LayerTraits<RecordType>::DataType& data() { return data_; }
 227  m :    typename LayerTraits<RecordType>::DataType* mutable_data() { return &data_; }
 228    :  
 229  m :   private:
 230  m :    typename LayerTraits<RecordType>::DataType data_;
 231  m :    std::multimap<Address, RecordPtr> records_;
 232  m :  };
 233    :  
 234    :  #define DECL_LAYER_TYPES(layer_name)                                           \
 235  m :    using layer_name##LayerPtr = scoped_refptr<ProcessState::Layer<layer_name>>; \
 236  m :    using layer_name##RecordPtr = ProcessState::Layer<layer_name>::RecordPtr;
 237    :  
 238    :  // Declares types named XXLayerPtr and XXRecordPtr for each layer XX.
 239  m :  PROCESS_STATE_LAYERS(DECL_LAYER_TYPES)
 240    :  
 241    :  #undef DECL_LAYER_TYPES
 242    :  
 243  m :  template <typename RecordType>
 244  m :  class Iterator : public std::iterator<
 245  m :      std::input_iterator_tag,
 246  m :      typename ProcessState::Layer<RecordType>::RecordPtr> {
 247  m :   public:
 248  m :    typedef typename ProcessState::Layer<RecordType>::RecordPtr RecordPtr;
 249    :  
 250  m :    Iterator() {}
 251  m :    const RecordPtr& operator*() const { return it_->second; }
 252  m :    Iterator& operator=(const Iterator&) {
 253  m :      it_ = other.it_;
 254  m :      return *this;
 255  m :    }
 256  m :    const Iterator& operator++() {
 257  m :      ++it_;
 258  m :      return *this;
 259  m :    }
 260  m :    bool operator==(const Iterator& other) const {
 261  m :      return it_ == other.it_;
 262  m :    }
 263  m :    bool operator!=(const Iterator& other) const {
 264  m :      return it_ != other.it_;
 265  m :    }
 266    :  
 267  m :   private:
 268  m :    friend ProcessState::Layer<RecordType>;
 269  m :    explicit Iterator(typename std::multimap<Address, RecordPtr>::iterator it)
 270  m :        : it_(it) {}
 271    :  
 272  m :    typename std::multimap<Address, RecordPtr>::iterator it_;
 273  m :  };
 274    :  
 275    :  // ProcessState
 276  m :  template<typename RecordType>
 277  m :  bool ProcessState::FindLayer(scoped_refptr<Layer<RecordType>>* layer) {
 278  m :    DCHECK(layer != nullptr);
 279    :  
 280  m :    RecordId id = RecordTraits<RecordType>::ID;
 281  m :    auto it = layers_.find(id);
 282  m :    if (it != layers_.end()) {
 283  m :      *layer = static_cast<Layer<RecordType>*>(it->second.get());
 284  m :      return true;
 285  m :    }
 286    :  
 287  m :    return false;
 288  m :  }
 289    :  
 290  m :  template <typename RecordType>
 291  m :  void ProcessState::FindOrCreateLayer(
 292  m :      scoped_refptr<Layer<RecordType>>* layer) {
 293  m :    DCHECK(layer != nullptr);
 294    :  
 295  m :    if (FindLayer(layer))
 296  m :      return;
 297    :  
 298  m :    CreateLayer(layer);
 299  m :  }
 300    :  
 301  m :  template <typename RecordType>
 302  m :  bool ProcessState::FindSingleRecord(Address addr,
 303  m :                                      scoped_refptr<Record<RecordType>>* record) {
 304    :    // Get layer.
 305  m :    scoped_refptr<Layer<RecordType>> layer;
 306  m :    if (!FindLayer(&layer))
 307  m :      return false;
 308    :  
 309    :    // Get the single record containing the address.
 310  m :    std::vector<scoped_refptr<Record<RecordType>>> matching_records;
 311  m :    layer->GetRecordsSpanning(AddressRange(addr, 1U), &matching_records);
 312  m :    if (matching_records.size() != 1U)
 313  m :      return false;
 314    :  
 315  m :    *record = matching_records[0];
 316  m :    return true;
 317  m :  }
 318    :  
 319  m :  template<typename RecordType>
 320  m :  void ProcessState::CreateLayer(scoped_refptr<Layer<RecordType>>* layer) {
 321  m :    DCHECK(layer != nullptr);
 322    :  
 323  m :    scoped_refptr<Layer<RecordType>> new_layer = new Layer<RecordType>();
 324  m :    DCHECK(new_layer.get() != nullptr);
 325    :  
 326  m :    RecordId id = RecordTraits<RecordType>::ID;
 327  m :    auto ib = layers_.insert(
 328  m :        std::make_pair(id, scoped_refptr<LayerBase>(new_layer.get())));
 329  m :    DCHECK(ib.second);
 330    :  
 331  m :    layer->swap(new_layer);
 332  m :  }
 333    :  
 334    :  // ProcessState::Layer
 335  m :  template <typename RecordType>
 336  m :  void ProcessState::Layer<RecordType>::CreateRecord(
 337  m :      AddressRange range, RecordPtr* record) {
 338  m :    DCHECK(range.IsValid());
 339  m :    DCHECK(record != nullptr);
 340    :  
 341  m :    RecordPtr new_record = new Record<RecordType>(range);
 342  m :    records_.insert(std::make_pair(range.start(), new_record));
 343    :  
 344  m :    record->swap(new_record);
 345  m :  }
 346    :  
 347  m :  template <typename RecordType>
 348  m :  void ProcessState::Layer<RecordType>::GetRecordsAt(
 349  m :      Address addr, std::vector<RecordPtr>* records) const {
 350  m :    DCHECK(records != nullptr);
 351    :  
 352  m :    records->clear();
 353    :  
 354  m :    auto match = records_.equal_range(addr);
 355  m :    for (auto it = match.first; it != match.second; ++it) {
 356  m :      records->push_back(it->second);
 357  m :    }
 358  m :  }
 359    :  
 360  m :  template <typename RecordType>
 361  m :  void ProcessState::Layer<RecordType>::GetRecordsSpanning(
 362  m :      const AddressRange& range, std::vector<RecordPtr>* records) const {
 363  m :    DCHECK(range.IsValid());
 364  m :    DCHECK(records != nullptr);
 365    :  
 366  m :    records->clear();
 367    :  
 368  m :    for (const auto& entry : records_) {
 369  m :      AddressRange record_range = entry.second->range();
 370  m :      DCHECK(record_range.IsValid());
 371  m :      if (record_range.Contains(range))
 372  m :        records->push_back(entry.second);
 373    :  
 374  m :      if (record_range.start() > range.start())
 375    :        // Records that start after the range, or any after, cannot span it.
 376  m :        return;
 377  m :    }
 378  m :  }
 379    :  
 380  m :  template <typename RecordType>
 381  m :  void ProcessState::Layer<RecordType>::GetRecordsIntersecting(
 382  m :      const AddressRange& range, std::vector<RecordPtr>* records) const {
 383  m :    DCHECK(range.IsValid());
 384  m :    DCHECK(records != nullptr);
 385    :  
 386  m :    records->clear();
 387    :  
 388  m :    for (const auto& entry : records_) {
 389  m :      AddressRange record_range = entry.second->range();
 390  m :      DCHECK(record_range.IsValid());
 391  m :      if (record_range.Intersects(range))
 392  m :        records->push_back(entry.second);
 393  m :    }
 394  m :  }
 395    :  
 396  m :  template <typename RecordType>
 397  m :  bool ProcessState::Layer<RecordType>::RemoveRecord(const RecordPtr& record) {
 398  m :    DCHECK(record.get() != nullptr);
 399    :  
 400    :    // Note: a record can only appear once, as per API (CreateRecord is the only
 401    :    // mechanism to add a record).
 402  m :    auto matches = records_.equal_range(record->range().start());
 403  m :    for (auto it = matches.first; it != matches.second; ++it) {
 404  m :      if (it->second.get() == record.get()) {
 405  m :        records_.erase(it);
 406  m :        return true;
 407  m :      }
 408  m :    }
 409    :  
 410  m :    return false;
 411  m :  }
 412    :  
 413  m :  }  // namespace refinery
 414    :  
 415    :  #endif  // SYZYGY_REFINERY_PROCESS_STATE_PROCESS_STATE_H_

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