xref: /haiku/src/kits/debugger/jobs/GetStackTraceJob.cpp (revision fce4895d1884da5ae6fb299d23c735c598e690b1)
1*fce4895dSRene Gollent /*
2*fce4895dSRene Gollent  * Copyright 2012-2016, 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 "ImageDebugInfo.h"
15*fce4895dSRene Gollent #include "StackTrace.h"
16*fce4895dSRene Gollent #include "Thread.h"
17*fce4895dSRene Gollent #include "Team.h"
18*fce4895dSRene Gollent 
19*fce4895dSRene Gollent 
GetStackTraceJob(DebuggerInterface * debuggerInterface,JobListener * listener,Architecture * architecture,::Thread * thread)20*fce4895dSRene Gollent GetStackTraceJob::GetStackTraceJob(DebuggerInterface* debuggerInterface,
21*fce4895dSRene Gollent 	JobListener* listener, Architecture* architecture, ::Thread* thread)
22*fce4895dSRene Gollent 	:
23*fce4895dSRene Gollent 	fKey(thread, JOB_TYPE_GET_STACK_TRACE),
24*fce4895dSRene Gollent 	fDebuggerInterface(debuggerInterface),
25*fce4895dSRene Gollent 	fJobListener(listener),
26*fce4895dSRene Gollent 	fArchitecture(architecture),
27*fce4895dSRene Gollent 	fThread(thread)
28*fce4895dSRene Gollent {
29*fce4895dSRene Gollent 	fThread->AcquireReference();
30*fce4895dSRene Gollent 
31*fce4895dSRene Gollent 	fCpuState = fThread->GetCpuState();
32*fce4895dSRene Gollent 	if (fCpuState != NULL)
33*fce4895dSRene Gollent 		fCpuState->AcquireReference();
34*fce4895dSRene Gollent 
35*fce4895dSRene Gollent 
36*fce4895dSRene Gollent 	SetDescription("Retrieving stack trace for thread %" B_PRId32, fThread->ID());
37*fce4895dSRene Gollent }
38*fce4895dSRene Gollent 
39*fce4895dSRene Gollent 
~GetStackTraceJob()40*fce4895dSRene Gollent GetStackTraceJob::~GetStackTraceJob()
41*fce4895dSRene Gollent {
42*fce4895dSRene Gollent 	if (fCpuState != NULL)
43*fce4895dSRene Gollent 		fCpuState->ReleaseReference();
44*fce4895dSRene Gollent 
45*fce4895dSRene Gollent 	fThread->ReleaseReference();
46*fce4895dSRene Gollent }
47*fce4895dSRene Gollent 
48*fce4895dSRene Gollent 
49*fce4895dSRene Gollent const JobKey&
Key() const50*fce4895dSRene Gollent GetStackTraceJob::Key() const
51*fce4895dSRene Gollent {
52*fce4895dSRene Gollent 	return fKey;
53*fce4895dSRene Gollent }
54*fce4895dSRene Gollent 
55*fce4895dSRene Gollent 
56*fce4895dSRene Gollent status_t
Do()57*fce4895dSRene Gollent GetStackTraceJob::Do()
58*fce4895dSRene Gollent {
59*fce4895dSRene Gollent 	if (fCpuState == NULL)
60*fce4895dSRene Gollent 		return B_BAD_VALUE;
61*fce4895dSRene Gollent 
62*fce4895dSRene Gollent 	// get the stack trace
63*fce4895dSRene Gollent 	StackTrace* stackTrace;
64*fce4895dSRene Gollent 	status_t error = fArchitecture->CreateStackTrace(fThread->GetTeam(), this,
65*fce4895dSRene Gollent 		fCpuState, stackTrace, fThread->ReturnValueInfos());
66*fce4895dSRene Gollent 	if (error != B_OK)
67*fce4895dSRene Gollent 		return error;
68*fce4895dSRene Gollent 	BReference<StackTrace> stackTraceReference(stackTrace, true);
69*fce4895dSRene Gollent 
70*fce4895dSRene Gollent 	// set the stack trace, unless something has changed
71*fce4895dSRene Gollent 	AutoLocker<Team> locker(fThread->GetTeam());
72*fce4895dSRene Gollent 
73*fce4895dSRene Gollent 	if (fThread->GetCpuState() == fCpuState)
74*fce4895dSRene Gollent 		fThread->SetStackTrace(stackTrace);
75*fce4895dSRene Gollent 
76*fce4895dSRene Gollent 	return B_OK;
77*fce4895dSRene Gollent }
78*fce4895dSRene Gollent 
79*fce4895dSRene Gollent 
80*fce4895dSRene Gollent status_t
GetImageDebugInfo(Image * image,ImageDebugInfo * & _info)81*fce4895dSRene Gollent GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
82*fce4895dSRene Gollent {
83*fce4895dSRene Gollent 	AutoLocker<Team> teamLocker(fThread->GetTeam());
84*fce4895dSRene Gollent 
85*fce4895dSRene Gollent 	while (image->GetImageDebugInfo() == NULL) {
86*fce4895dSRene Gollent 		// schedule a job, if not loaded
87*fce4895dSRene Gollent 		ImageDebugInfo* info;
88*fce4895dSRene Gollent 		status_t error = LoadImageDebugInfoJob::ScheduleIfNecessary(GetWorker(),
89*fce4895dSRene Gollent 			image, fJobListener, &info);
90*fce4895dSRene Gollent 		if (error != B_OK)
91*fce4895dSRene Gollent 			return error;
92*fce4895dSRene Gollent 
93*fce4895dSRene Gollent 		if (info != NULL) {
94*fce4895dSRene Gollent 			_info = info;
95*fce4895dSRene Gollent 			return B_OK;
96*fce4895dSRene Gollent 		}
97*fce4895dSRene Gollent 
98*fce4895dSRene Gollent 		teamLocker.Unlock();
99*fce4895dSRene Gollent 
100*fce4895dSRene Gollent 		// wait for the job to finish
101*fce4895dSRene Gollent 		switch (WaitFor(SimpleJobKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO))) {
102*fce4895dSRene Gollent 			case JOB_DEPENDENCY_SUCCEEDED:
103*fce4895dSRene Gollent 			case JOB_DEPENDENCY_NOT_FOUND:
104*fce4895dSRene Gollent 				// "Not found" can happen due to a race condition between
105*fce4895dSRene Gollent 				// unlocking the worker and starting to wait.
106*fce4895dSRene Gollent 				break;
107*fce4895dSRene Gollent 			case JOB_DEPENDENCY_FAILED:
108*fce4895dSRene Gollent 			case JOB_DEPENDENCY_ABORTED:
109*fce4895dSRene Gollent 			default:
110*fce4895dSRene Gollent 				return B_ERROR;
111*fce4895dSRene Gollent 		}
112*fce4895dSRene Gollent 
113*fce4895dSRene Gollent 		teamLocker.Lock();
114*fce4895dSRene Gollent 	}
115*fce4895dSRene Gollent 
116*fce4895dSRene Gollent 	_info = image->GetImageDebugInfo();
117*fce4895dSRene Gollent 	_info->AcquireReference();
118*fce4895dSRene Gollent 
119*fce4895dSRene Gollent 	return B_OK;
120*fce4895dSRene Gollent }
121