blob: 098cedbffa7e57a4b01f090621413ee854ef4476 [file] [log] [blame]
Andreas Gampeb5eb94a2016-10-27 19:23:09 -07001/* Copyright (C) 2016 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
32#include "ti_stack.h"
33
Andreas Gampea1a27c62017-01-11 16:37:16 -080034#include <list>
35#include <unordered_map>
36#include <vector>
37
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070038#include "art_jvmti.h"
39#include "art_method-inl.h"
Andreas Gampea1a27c62017-01-11 16:37:16 -080040#include "base/bit_utils.h"
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070041#include "base/enums.h"
Andreas Gampea1a27c62017-01-11 16:37:16 -080042#include "base/mutex.h"
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070043#include "dex_file.h"
44#include "dex_file_annotations.h"
45#include "jni_env_ext.h"
Andreas Gampe13b27842016-11-07 16:48:23 -080046#include "jni_internal.h"
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070047#include "mirror/class.h"
48#include "mirror/dex_cache.h"
49#include "scoped_thread_state_change-inl.h"
Andreas Gampea1a27c62017-01-11 16:37:16 -080050#include "ScopedLocalRef.h"
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070051#include "stack.h"
Andreas Gampea1a27c62017-01-11 16:37:16 -080052#include "thread-inl.h"
53#include "thread_list.h"
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070054#include "thread_pool.h"
55
56namespace openjdkjvmti {
57
58struct GetStackTraceVisitor : public art::StackVisitor {
59 GetStackTraceVisitor(art::Thread* thread_in,
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070060 size_t start_,
61 size_t stop_)
62 : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070063 start(start_),
64 stop(stop_) {}
65
66 bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
67 art::ArtMethod* m = GetMethod();
68 if (m->IsRuntimeMethod()) {
69 return true;
70 }
71
72 if (start == 0) {
73 m = m->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
Andreas Gampe13b27842016-11-07 16:48:23 -080074 jmethodID id = art::jni::EncodeArtMethod(m);
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070075
Andreas Gampe2340e3f2016-12-12 19:37:19 -080076 uint32_t dex_pc = GetDexPc(false);
77 jlong dex_location = (dex_pc == art::DexFile::kDexNoIndex) ? -1 : static_cast<jlong>(dex_pc);
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070078
Andreas Gampe2340e3f2016-12-12 19:37:19 -080079 jvmtiFrameInfo info = { id, dex_location };
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070080 frames.push_back(info);
81
82 if (stop == 1) {
83 return false; // We're done.
84 } else if (stop > 0) {
85 stop--;
86 }
87 } else {
88 start--;
89 }
90
91 return true;
92 }
93
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070094 std::vector<jvmtiFrameInfo> frames;
95 size_t start;
96 size_t stop;
97};
98
99struct GetStackTraceClosure : public art::Closure {
100 public:
101 GetStackTraceClosure(size_t start, size_t stop)
102 : start_input(start),
103 stop_input(stop),
104 start_result(0),
105 stop_result(0) {}
106
Andreas Gampea1a27c62017-01-11 16:37:16 -0800107 void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
108 GetStackTraceVisitor visitor(self, start_input, stop_input);
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700109 visitor.WalkStack(false);
110
111 frames.swap(visitor.frames);
112 start_result = visitor.start;
113 stop_result = visitor.stop;
114 }
115
116 const size_t start_input;
117 const size_t stop_input;
118
119 std::vector<jvmtiFrameInfo> frames;
120 size_t start_result;
121 size_t stop_result;
122};
123
Andreas Gampea1a27c62017-01-11 16:37:16 -0800124static jvmtiError TranslateFrameVector(const std::vector<jvmtiFrameInfo>& frames,
125 jint start_depth,
126 size_t start_result,
127 jint max_frame_count,
128 jvmtiFrameInfo* frame_buffer,
129 jint* count_ptr) {
130 size_t collected_frames = frames.size();
131
132 // Assume we're here having collected something.
133 DCHECK_GT(max_frame_count, 0);
134
135 // Frames from the top.
136 if (start_depth >= 0) {
137 if (start_result != 0) {
138 // Not enough frames.
139 return ERR(ILLEGAL_ARGUMENT);
140 }
141 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
142 if (frames.size() > 0) {
143 memcpy(frame_buffer, frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
144 }
145 *count_ptr = static_cast<jint>(frames.size());
146 return ERR(NONE);
147 }
148
149 // Frames from the bottom.
150 if (collected_frames < static_cast<size_t>(-start_depth)) {
151 return ERR(ILLEGAL_ARGUMENT);
152 }
153
154 size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
155 memcpy(frame_buffer,
156 &frames.data()[collected_frames + start_depth],
157 count * sizeof(jvmtiFrameInfo));
158 *count_ptr = static_cast<jint>(count);
159 return ERR(NONE);
160}
161
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700162jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
163 jthread java_thread,
164 jint start_depth,
165 jint max_frame_count,
166 jvmtiFrameInfo* frame_buffer,
167 jint* count_ptr) {
168 if (java_thread == nullptr) {
169 return ERR(INVALID_THREAD);
170 }
171
172 art::Thread* thread;
173 {
174 // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
175 art::ScopedObjectAccess soa(art::Thread::Current());
176 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
177 thread = art::Thread::FromManagedThread(soa, java_thread);
178 DCHECK(thread != nullptr);
179 }
180
181 art::ThreadState state = thread->GetState();
182 if (state == art::ThreadState::kStarting ||
183 state == art::ThreadState::kTerminated ||
184 thread->IsStillStarting()) {
185 return ERR(THREAD_NOT_ALIVE);
186 }
187
188 if (max_frame_count < 0) {
189 return ERR(ILLEGAL_ARGUMENT);
190 }
191 if (frame_buffer == nullptr || count_ptr == nullptr) {
192 return ERR(NULL_POINTER);
193 }
194
195 if (max_frame_count == 0) {
196 *count_ptr = 0;
197 return ERR(NONE);
198 }
199
200 GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0,
Andreas Gampea1a27c62017-01-11 16:37:16 -0800201 start_depth >= 0 ? static_cast<size_t>(max_frame_count) : 0);
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700202 thread->RequestSynchronousCheckpoint(&closure);
203
Andreas Gampea1a27c62017-01-11 16:37:16 -0800204 return TranslateFrameVector(closure.frames,
205 start_depth,
206 closure.start_result,
207 max_frame_count,
208 frame_buffer,
209 count_ptr);
210}
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700211
Andreas Gampea1a27c62017-01-11 16:37:16 -0800212struct GetAllStackTraceClosure : public art::Closure {
213 public:
214 explicit GetAllStackTraceClosure(size_t stop)
215 : start_input(0),
216 stop_input(stop),
217 frames_lock("GetAllStackTraceGuard", art::LockLevel::kAbortLock),
218 start_result(0),
219 stop_result(0) {}
220
221 void Run(art::Thread* self)
222 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!frames_lock) {
223 // self should be live here (so it could be suspended). No need to filter.
224
225 art::Thread* current = art::Thread::Current();
226 std::vector<jvmtiFrameInfo> self_frames;
227
228 GetStackTraceVisitor visitor(self, start_input, stop_input);
229 visitor.WalkStack(false);
230
231 self_frames.swap(visitor.frames);
232
233 art::MutexLock mu(current, frames_lock);
234 frames.emplace(self, self_frames);
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700235 }
236
Andreas Gampea1a27c62017-01-11 16:37:16 -0800237 const size_t start_input;
238 const size_t stop_input;
239
240 art::Mutex frames_lock;
241 std::unordered_map<art::Thread*, std::vector<jvmtiFrameInfo>> frames GUARDED_BY(frames_lock);
242 size_t start_result;
243 size_t stop_result;
244};
245
246
247
248jvmtiError StackUtil::GetAllStackTraces(jvmtiEnv* env,
249 jint max_frame_count,
250 jvmtiStackInfo** stack_info_ptr,
251 jint* thread_count_ptr) {
252 if (max_frame_count < 0) {
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700253 return ERR(ILLEGAL_ARGUMENT);
254 }
Andreas Gampea1a27c62017-01-11 16:37:16 -0800255 if (stack_info_ptr == nullptr || thread_count_ptr == nullptr) {
256 return ERR(NULL_POINTER);
257 }
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700258
Andreas Gampea1a27c62017-01-11 16:37:16 -0800259
260 art::Thread* current = art::Thread::Current();
261 art::ScopedObjectAccess soa(current); // Now we know we have the shared lock.
262 art::ScopedThreadSuspension sts(current, art::kWaitingForDebuggerSuspension);
263 art::ScopedSuspendAll ssa("GetAllStackTraces");
264
265 std::vector<art::Thread*> threads;
266 std::vector<std::vector<jvmtiFrameInfo>> frames;
267 {
268 std::list<art::Thread*> thread_list;
269 {
270 art::MutexLock mu(current, *art::Locks::thread_list_lock_);
271 thread_list = art::Runtime::Current()->GetThreadList()->GetList();
272 }
273
274 for (art::Thread* thread : thread_list) {
Andreas Gampe984efb52017-01-12 17:43:13 -0800275 // Skip threads that are still starting.
276 if (thread->IsStillStarting()) {
277 continue;
278 }
279
Andreas Gampea1a27c62017-01-11 16:37:16 -0800280 GetStackTraceClosure closure(0u, static_cast<size_t>(max_frame_count));
281 thread->RequestSynchronousCheckpoint(&closure);
282
283 threads.push_back(thread);
284 frames.emplace_back();
285 frames.back().swap(closure.frames);
286 }
287 }
288
289 // Convert the data into our output format. Note: we need to keep the threads suspended,
290 // as we need to access them for their peers.
291
292 // Note: we use an array of jvmtiStackInfo for convenience. The spec says we need to
293 // allocate one big chunk for this and the actual frames, which means we need
294 // to either be conservative or rearrange things later (the latter is implemented).
295 std::unique_ptr<jvmtiStackInfo[]> stack_info_array(new jvmtiStackInfo[frames.size()]);
296 std::vector<std::unique_ptr<jvmtiFrameInfo[]>> frame_infos;
297 frame_infos.reserve(frames.size());
298
299 // Now run through and add data for each thread.
300 size_t sum_frames = 0;
301 for (size_t index = 0; index < frames.size(); ++index) {
302 jvmtiStackInfo& stack_info = stack_info_array.get()[index];
303 memset(&stack_info, 0, sizeof(jvmtiStackInfo));
304
305 art::Thread* self = threads[index];
306 const std::vector<jvmtiFrameInfo>& thread_frames = frames[index];
307
308 // For the time being, set the thread to null. We don't have good ScopedLocalRef
309 // infrastructure.
310 DCHECK(self->GetPeer() != nullptr);
311 stack_info.thread = nullptr;
312 stack_info.state = JVMTI_THREAD_STATE_SUSPENDED;
313
314 size_t collected_frames = thread_frames.size();
315 if (max_frame_count == 0 || collected_frames == 0) {
316 stack_info.frame_count = 0;
317 stack_info.frame_buffer = nullptr;
318 continue;
319 }
320 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
321
322 jvmtiFrameInfo* frame_info = new jvmtiFrameInfo[collected_frames];
323 frame_infos.emplace_back(frame_info);
324
325 jint count;
326 jvmtiError translate_result = TranslateFrameVector(thread_frames,
327 0,
328 0,
329 static_cast<jint>(collected_frames),
330 frame_info,
331 &count);
332 DCHECK(translate_result == JVMTI_ERROR_NONE);
333 stack_info.frame_count = static_cast<jint>(collected_frames);
334 stack_info.frame_buffer = frame_info;
335 sum_frames += static_cast<size_t>(count);
336 }
337
338 // No errors, yet. Now put it all into an output buffer.
339 size_t rounded_stack_info_size = art::RoundUp(sizeof(jvmtiStackInfo) * frames.size(),
340 alignof(jvmtiFrameInfo));
341 size_t chunk_size = rounded_stack_info_size + sum_frames * sizeof(jvmtiFrameInfo);
342 unsigned char* chunk_data;
343 jvmtiError alloc_result = env->Allocate(chunk_size, &chunk_data);
344 if (alloc_result != ERR(NONE)) {
345 return alloc_result;
346 }
347
348 jvmtiStackInfo* stack_info = reinterpret_cast<jvmtiStackInfo*>(chunk_data);
349 // First copy in all the basic data.
350 memcpy(stack_info, stack_info_array.get(), sizeof(jvmtiStackInfo) * frames.size());
351
352 // Now copy the frames and fix up the pointers.
353 jvmtiFrameInfo* frame_info = reinterpret_cast<jvmtiFrameInfo*>(
354 chunk_data + rounded_stack_info_size);
355 for (size_t i = 0; i < frames.size(); ++i) {
356 jvmtiStackInfo& old_stack_info = stack_info_array.get()[i];
357 jvmtiStackInfo& new_stack_info = stack_info[i];
358
359 jthread thread_peer = current->GetJniEnv()->AddLocalReference<jthread>(threads[i]->GetPeer());
360 new_stack_info.thread = thread_peer;
361
362 if (old_stack_info.frame_count > 0) {
363 // Only copy when there's data - leave the nullptr alone.
364 size_t frames_size = static_cast<size_t>(old_stack_info.frame_count) * sizeof(jvmtiFrameInfo);
365 memcpy(frame_info, old_stack_info.frame_buffer, frames_size);
366 new_stack_info.frame_buffer = frame_info;
367 frame_info += old_stack_info.frame_count;
368 }
369 }
370
371 *stack_info_ptr = stack_info;
372 *thread_count_ptr = static_cast<jint>(frames.size());
373
Andreas Gampeb5eb94a2016-10-27 19:23:09 -0700374 return ERR(NONE);
375}
376
377} // namespace openjdkjvmti