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
20GetStackTraceJob::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
40GetStackTraceJob::~GetStackTraceJob()
41{
42	if (fCpuState != NULL)
43		fCpuState->ReleaseReference();
44
45	fThread->ReleaseReference();
46}
47
48
49const JobKey&
50GetStackTraceJob::Key() const
51{
52	return fKey;
53}
54
55
56status_t
57GetStackTraceJob::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
80status_t
81GetStackTraceJob::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