vfs: check userland buffers before reading them.
[haiku.git] / src / kits / debugger / jobs / ResolveValueNodeJob.cpp
blobef30d85c156ca9b62d6fd3e9383c2d59429e52e1
1 /*
2 * Copyright 2012-2015, Rene Gollent, rene@gollent.com.
3 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
7 #include "Jobs.h"
9 #include <AutoLocker.h>
11 #include "Architecture.h"
12 #include "CpuState.h"
13 #include "DebuggerInterface.h"
14 #include "TeamTypeInformation.h"
15 #include "Tracing.h"
16 #include "Value.h"
17 #include "ValueLoader.h"
18 #include "ValueLocation.h"
19 #include "ValueNode.h"
20 #include "ValueNodeContainer.h"
21 #include "Variable.h"
22 #include "VariableValueNodeChild.h"
25 ResolveValueNodeValueJob::ResolveValueNodeValueJob(
26 DebuggerInterface* debuggerInterface, Architecture* architecture,
27 CpuState* cpuState, TeamTypeInformation* typeInformation,
28 ValueNodeContainer* container, ValueNode* valueNode)
30 fKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE),
31 fDebuggerInterface(debuggerInterface),
32 fArchitecture(architecture),
33 fCpuState(cpuState),
34 fTypeInformation(typeInformation),
35 fContainer(container),
36 fValueNode(valueNode)
38 if (fCpuState != NULL)
39 fCpuState->AcquireReference();
40 fContainer->AcquireReference();
41 fValueNode->AcquireReference();
45 ResolveValueNodeValueJob::~ResolveValueNodeValueJob()
47 if (fCpuState != NULL)
48 fCpuState->ReleaseReference();
49 fContainer->ReleaseReference();
50 fValueNode->ReleaseReference();
54 const JobKey&
55 ResolveValueNodeValueJob::Key() const
57 return fKey;
61 status_t
62 ResolveValueNodeValueJob::Do()
64 // check whether the node still belongs to the container
65 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
66 if (fValueNode->Container() != fContainer)
67 return B_BAD_VALUE;
69 // if already resolved, we're done
70 status_t nodeResolutionState
71 = fValueNode->LocationAndValueResolutionState();
72 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
73 return nodeResolutionState;
75 containerLocker.Unlock();
77 // resolve
78 status_t error = _ResolveNodeValue();
79 if (error != B_OK) {
80 nodeResolutionState = fValueNode->LocationAndValueResolutionState();
81 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
82 return nodeResolutionState;
84 containerLocker.Lock();
85 fValueNode->SetLocationAndValue(NULL, NULL, error);
86 containerLocker.Unlock();
89 return error;
93 status_t
94 ResolveValueNodeValueJob::_ResolveNodeValue()
96 // get the node child and parent node
97 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
98 ValueNodeChild* nodeChild = fValueNode->NodeChild();
99 BReference<ValueNodeChild> nodeChildReference(nodeChild);
101 ValueNode* parentNode = nodeChild->Parent();
102 BReference<ValueNode> parentNodeReference(parentNode);
104 // Check whether the node child location has been resolved already
105 // (successfully).
106 status_t nodeChildResolutionState = nodeChild->LocationResolutionState();
107 bool nodeChildDone = nodeChildResolutionState != VALUE_NODE_UNRESOLVED;
108 if (nodeChildDone && nodeChildResolutionState != B_OK)
109 return nodeChildResolutionState;
111 // If the child node location has not been resolved yet, check whether the
112 // parent node location and value have been resolved already (successfully).
113 bool parentDone = true;
114 if (!nodeChildDone && parentNode != NULL) {
115 status_t parentResolutionState
116 = parentNode->LocationAndValueResolutionState();
117 parentDone = parentResolutionState != VALUE_NODE_UNRESOLVED;
118 if (parentDone && parentResolutionState != B_OK)
119 return parentResolutionState;
122 containerLocker.Unlock();
124 // resolve the parent node location and value, if necessary
125 if (!parentDone) {
126 status_t error = _ResolveParentNodeValue(parentNode);
127 if (error != B_OK) {
128 TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
129 "node: %p (\"%s\"): _ResolveParentNodeValue(%p) failed\n",
130 fValueNode, fValueNode->Name().String(), parentNode);
131 return error;
134 if (State() == JOB_STATE_WAITING)
135 return B_OK;
138 // resolve the node child location, if necessary
139 if (!nodeChildDone) {
140 status_t error = _ResolveNodeChildLocation(nodeChild);
141 if (error != B_OK) {
142 TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
143 "node: %p (\"%s\"): _ResolveNodeChildLocation(%p) failed\n",
144 fValueNode, fValueNode->Name().String(), nodeChild);
145 return error;
149 CpuState* variableCpuState = NULL;
150 VariableValueNodeChild* variableChild = dynamic_cast<
151 VariableValueNodeChild*>(nodeChild);
152 if (variableChild != NULL)
153 variableCpuState = variableChild->GetVariable()->GetCpuState();
155 // resolve the node location and value
156 ValueLoader valueLoader(fArchitecture, fDebuggerInterface,
157 variableCpuState != NULL ? variableCpuState : fCpuState);
158 ValueLocation* location;
159 Value* value;
160 status_t error = fValueNode->ResolvedLocationAndValue(&valueLoader,
161 location, value);
162 if (error != B_OK) {
163 TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
164 "node: %p (\"%s\"): fValueNode->ResolvedLocationAndValue() "
165 "failed\n", fValueNode, fValueNode->Name().String());
166 return error;
168 BReference<ValueLocation> locationReference(location, true);
169 BReference<Value> valueReference(value, true);
171 // set location and value on the node
172 containerLocker.Lock();
173 status_t nodeResolutionState
174 = fValueNode->LocationAndValueResolutionState();
175 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
176 return nodeResolutionState;
177 fValueNode->SetLocationAndValue(location, value, B_OK);
178 containerLocker.Unlock();
180 return B_OK;
184 status_t
185 ResolveValueNodeValueJob::_ResolveNodeChildLocation(ValueNodeChild* nodeChild)
187 // resolve the location
188 ValueLoader valueLoader(fArchitecture, fDebuggerInterface, fCpuState);
189 ValueLocation* location = NULL;
190 status_t error = nodeChild->ResolveLocation(&valueLoader, location);
191 BReference<ValueLocation> locationReference(location, true);
193 // set the location on the node child
194 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
195 status_t nodeChildResolutionState = nodeChild->LocationResolutionState();
196 if (nodeChildResolutionState == VALUE_NODE_UNRESOLVED)
197 nodeChild->SetLocation(location, error);
198 else
199 error = nodeChildResolutionState;
201 return error;
205 status_t
206 ResolveValueNodeValueJob::_ResolveParentNodeValue(ValueNode* parentNode)
208 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
210 if (parentNode->Container() != fContainer)
211 return B_BAD_VALUE;
213 // if the parent node already has a value, we're done
214 status_t nodeResolutionState
215 = parentNode->LocationAndValueResolutionState();
216 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
217 return nodeResolutionState;
219 // check whether a job is already in progress
220 AutoLocker<Worker> workerLocker(GetWorker());
221 SimpleJobKey jobKey(parentNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
222 if (GetWorker()->GetJob(jobKey) == NULL) {
223 workerLocker.Unlock();
225 // schedule the job
226 status_t error = GetWorker()->ScheduleJob(
227 new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
228 fArchitecture, fCpuState, fTypeInformation, fContainer,
229 parentNode));
230 if (error != B_OK) {
231 // scheduling failed -- set the value to invalid
232 parentNode->SetLocationAndValue(NULL, NULL, error);
233 return error;
237 // wait for the job to finish
238 workerLocker.Unlock();
239 containerLocker.Unlock();
241 switch (WaitFor(jobKey)) {
242 case JOB_DEPENDENCY_SUCCEEDED:
243 case JOB_DEPENDENCY_NOT_FOUND:
244 // "Not found" can happen due to a race condition between
245 // unlocking the worker and starting to wait.
246 break;
247 case JOB_DEPENDENCY_ACTIVE:
248 return B_OK;
249 case JOB_DEPENDENCY_FAILED:
250 case JOB_DEPENDENCY_ABORTED:
251 default:
252 return B_ERROR;
255 containerLocker.Lock();
257 // now there should be a value for the node
258 nodeResolutionState = parentNode->LocationAndValueResolutionState();
259 return nodeResolutionState != VALUE_NODE_UNRESOLVED
260 ? nodeResolutionState : B_ERROR;