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
GetStackTraceJob(DebuggerInterface * debuggerInterface,JobListener * listener,Architecture * architecture,::Thread * thread)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
~GetStackTraceJob()40 GetStackTraceJob::~GetStackTraceJob()
41 {
42 if (fCpuState != NULL)
43 fCpuState->ReleaseReference();
44
45 fThread->ReleaseReference();
46 }
47
48
49 const JobKey&
Key() const50 GetStackTraceJob::Key() const
51 {
52 return fKey;
53 }
54
55
56 status_t
Do()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
GetImageDebugInfo(Image * image,ImageDebugInfo * & _info)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