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_
|