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