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 : #include "syzygy/refinery/process_state/process_state.h"
16 :
17 : #include <algorithm>
18 :
19 : #include "syzygy/refinery/core/addressed_data.h"
20 : #include "syzygy/refinery/process_state/process_state_util.h"
21 :
22 : namespace refinery {
23 :
24 E : ProcessState::ProcessState() : has_exception(false), excepting_thread_id(0U) {
25 E : }
26 :
27 E : ProcessState::~ProcessState() {
28 E : }
29 :
30 : bool ProcessState::FindStackRecord(
31 : size_t thread_id,
32 E : scoped_refptr<Record<Stack>>* record) {
33 E : StackLayerPtr stack_layer;
34 E : if (!FindLayer(&stack_layer))
35 E : return false;
36 :
37 E : for (StackRecordPtr stack : *stack_layer) {
38 E : const Stack& stack_proto = stack->data();
39 E : DCHECK(stack_proto.has_thread_info());
40 E : DCHECK(stack_proto.thread_info().has_thread_id());
41 E : if (stack_proto.thread_info().thread_id() == thread_id) {
42 E : *record = stack;
43 E : return true;
44 : }
45 E : }
46 :
47 E : return false;
48 E : }
49 :
50 E : bool ProcessState::GetAll(const AddressRange& range, void* data_ptr) {
51 E : DCHECK(range.IsValid());
52 :
53 : // Get the bytes layer.
54 E : BytesLayerPtr bytes_layer;
55 E : if (!FindLayer(&bytes_layer))
56 i : return false;
57 :
58 : // Search for a single record that spans the desired range.
59 E : std::vector<BytesRecordPtr> matching_records;
60 E : bytes_layer->GetRecordsSpanning(range, &matching_records);
61 E : if (matching_records.empty())
62 E : return false;
63 E : DCHECK_EQ(1U, matching_records.size());
64 :
65 : // Copy the bytes.
66 E : BytesRecordPtr bytes_record = matching_records[0];
67 : AddressedData record_data(
68 : bytes_record->range(),
69 E : reinterpret_cast<const void*>(bytes_record->data().data().c_str()));
70 :
71 E : return record_data.GetAt(range, data_ptr);
72 E : }
73 :
74 : bool ProcessState::GetFrom(const AddressRange& range,
75 : size_t* data_cnt,
76 E : void* data_ptr) {
77 E : DCHECK(range.IsValid());
78 :
79 : // Find the single record that contains the head of the range.
80 E : BytesRecordPtr record;
81 E : if (!FindSingleRecord(range.start(), &record))
82 E : return false;
83 :
84 : // Determine the range that can be served.
85 E : Address available_end = std::min(range.end(), record->range().end());
86 E : AddressRange available_range(range.start(), available_end - range.start());
87 E : DCHECK(available_range.IsValid());
88 :
89 : // Serve request.
90 E : *data_cnt = available_range.size();
91 E : if (data_ptr == nullptr)
92 i : return true; // Actual bytes not requested.
93 :
94 : AddressedData record_data(
95 : record->range(),
96 E : reinterpret_cast<const void*>(record->data().data().c_str()));
97 E : if (!record_data.GetAt(available_range, reinterpret_cast<void*>(data_ptr)))
98 i : return false;
99 :
100 E : return true;
101 E : }
102 :
103 i : bool ProcessState::HasSome(const AddressRange& range) {
104 : // TODO(manzagop): implement.
105 i : return false;
106 i : }
107 :
108 E : bool ProcessState::SetException(const Exception& candidate) {
109 E : DCHECK(candidate.has_thread_id());
110 :
111 E : if (has_exception)
112 E : return false; // There's already an exception.
113 :
114 E : StackRecordPtr stack_record;
115 E : if (!FindStackRecord(candidate.thread_id(), &stack_record))
116 E : return false; // Thread isn't in the process state.
117 :
118 E : DCHECK(stack_record->mutable_data());
119 : ThreadInformation* thread_info =
120 E : stack_record->mutable_data()->mutable_thread_info();
121 E : DCHECK(!thread_info->has_exception());
122 E : Exception* exception = thread_info->mutable_exception();
123 E : *exception = candidate;
124 :
125 E : has_exception = true;
126 E : excepting_thread_id = exception->thread_id();
127 :
128 E : return true;
129 E : }
130 :
131 E : bool ProcessState::GetExceptingThreadId(size_t* thread_id) {
132 E : if (!has_exception)
133 E : return false;
134 :
135 E : *thread_id = excepting_thread_id;
136 E : return true;
137 E : }
138 :
139 : } // namespace refinery
|