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