blob: 579fb50ecc22bee42a256fc3cdfc6c12edb4fd02 [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
34#include "art_jvmti.h"
35#include "art_method-inl.h"
36#include "base/enums.h"
37#include "dex_file.h"
38#include "dex_file_annotations.h"
39#include "jni_env_ext.h"
Andreas Gampe13b27842016-11-07 16:48:23 -080040#include "jni_internal.h"
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070041#include "mirror/class.h"
42#include "mirror/dex_cache.h"
43#include "scoped_thread_state_change-inl.h"
44#include "stack.h"
45#include "thread.h"
46#include "thread_pool.h"
47
48namespace openjdkjvmti {
49
50struct GetStackTraceVisitor : public art::StackVisitor {
51 GetStackTraceVisitor(art::Thread* thread_in,
52 art::ScopedObjectAccessAlreadyRunnable& soa_,
53 size_t start_,
54 size_t stop_)
55 : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
56 soa(soa_),
57 start(start_),
58 stop(stop_) {}
59
60 bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
61 art::ArtMethod* m = GetMethod();
62 if (m->IsRuntimeMethod()) {
63 return true;
64 }
65
66 if (start == 0) {
67 m = m->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
Andreas Gampe13b27842016-11-07 16:48:23 -080068 jmethodID id = art::jni::EncodeArtMethod(m);
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070069
Andreas Gampe2340e3f2016-12-12 19:37:19 -080070 uint32_t dex_pc = GetDexPc(false);
71 jlong dex_location = (dex_pc == art::DexFile::kDexNoIndex) ? -1 : static_cast<jlong>(dex_pc);
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070072
Andreas Gampe2340e3f2016-12-12 19:37:19 -080073 jvmtiFrameInfo info = { id, dex_location };
Andreas Gampeb5eb94a2016-10-27 19:23:09 -070074 frames.push_back(info);
75
76 if (stop == 1) {
77 return false; // We're done.
78 } else if (stop > 0) {
79 stop--;
80 }
81 } else {
82 start--;
83 }
84
85 return true;
86 }
87
88 art::ScopedObjectAccessAlreadyRunnable& soa;
89 std::vector<jvmtiFrameInfo> frames;
90 size_t start;
91 size_t stop;
92};
93
94struct GetStackTraceClosure : public art::Closure {
95 public:
96 GetStackTraceClosure(size_t start, size_t stop)
97 : start_input(start),
98 stop_input(stop),
99 start_result(0),
100 stop_result(0) {}
101
102 void Run(art::Thread* self) OVERRIDE {
103 art::ScopedObjectAccess soa(art::Thread::Current());
104
105 GetStackTraceVisitor visitor(self, soa, start_input, stop_input);
106 visitor.WalkStack(false);
107
108 frames.swap(visitor.frames);
109 start_result = visitor.start;
110 stop_result = visitor.stop;
111 }
112
113 const size_t start_input;
114 const size_t stop_input;
115
116 std::vector<jvmtiFrameInfo> frames;
117 size_t start_result;
118 size_t stop_result;
119};
120
121jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
122 jthread java_thread,
123 jint start_depth,
124 jint max_frame_count,
125 jvmtiFrameInfo* frame_buffer,
126 jint* count_ptr) {
127 if (java_thread == nullptr) {
128 return ERR(INVALID_THREAD);
129 }
130
131 art::Thread* thread;
132 {
133 // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
134 art::ScopedObjectAccess soa(art::Thread::Current());
135 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
136 thread = art::Thread::FromManagedThread(soa, java_thread);
137 DCHECK(thread != nullptr);
138 }
139
140 art::ThreadState state = thread->GetState();
141 if (state == art::ThreadState::kStarting ||
142 state == art::ThreadState::kTerminated ||
143 thread->IsStillStarting()) {
144 return ERR(THREAD_NOT_ALIVE);
145 }
146
147 if (max_frame_count < 0) {
148 return ERR(ILLEGAL_ARGUMENT);
149 }
150 if (frame_buffer == nullptr || count_ptr == nullptr) {
151 return ERR(NULL_POINTER);
152 }
153
154 if (max_frame_count == 0) {
155 *count_ptr = 0;
156 return ERR(NONE);
157 }
158
159 GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0,
160 start_depth >= 0 ?static_cast<size_t>(max_frame_count) : 0);
161 thread->RequestSynchronousCheckpoint(&closure);
162
163 size_t collected_frames = closure.frames.size();
164
165 // Frames from the top.
166 if (start_depth >= 0) {
167 if (closure.start_result != 0) {
168 // Not enough frames.
169 return ERR(ILLEGAL_ARGUMENT);
170 }
171 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
172 if (closure.frames.size() > 0) {
173 memcpy(frame_buffer, closure.frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
174 }
175 *count_ptr = static_cast<jint>(closure.frames.size());
176 return ERR(NONE);
177 }
178
179 // Frames from the bottom.
180 if (collected_frames < static_cast<size_t>(-start_depth)) {
181 return ERR(ILLEGAL_ARGUMENT);
182 }
183
184 size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
185 memcpy(frame_buffer,
186 &closure.frames.data()[collected_frames + start_depth],
187 count * sizeof(jvmtiFrameInfo));
188 *count_ptr = static_cast<jint>(count);
189 return ERR(NONE);
190}
191
192} // namespace openjdkjvmti