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

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

Coverage information generated Thu Jan 14 17:40:38 2016.