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