blob: 6f8976f03d4277910b20659c710046b02023f579 [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
70 art::mirror::DexCache* dex_cache = m->GetDexCache();
71 int32_t line_number = -1;
72 if (dex_cache != nullptr) { // be tolerant of bad input
73 const art::DexFile* dex_file = dex_cache->GetDexFile();
74 line_number = art::annotations::GetLineNumFromPC(dex_file, m, GetDexPc(false));
75 }
76
77 jvmtiFrameInfo info = { id, static_cast<jlong>(line_number) };
78 frames.push_back(info);
79
80 if (stop == 1) {
81 return false; // We're done.
82 } else if (stop > 0) {
83 stop--;
84 }
85 } else {
86 start--;
87 }
88
89 return true;
90 }
91
92 art::ScopedObjectAccessAlreadyRunnable& soa;
93 std::vector<jvmtiFrameInfo> frames;
94 size_t start;
95 size_t stop;
96};
97
98struct GetStackTraceClosure : public art::Closure {
99 public:
100 GetStackTraceClosure(size_t start, size_t stop)
101 : start_input(start),
102 stop_input(stop),
103 start_result(0),
104 stop_result(0) {}
105
106 void Run(art::Thread* self) OVERRIDE {
107 art::ScopedObjectAccess soa(art::Thread::Current());
108
109 GetStackTraceVisitor visitor(self, soa, start_input, stop_input);
110 visitor.WalkStack(false);
111
112 frames.swap(visitor.frames);
113 start_result = visitor.start;
114 stop_result = visitor.stop;
115 }
116
117 const size_t start_input;
118 const size_t stop_input;
119
120 std::vector<jvmtiFrameInfo> frames;
121 size_t start_result;
122 size_t stop_result;
123};
124
125jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
126 jthread java_thread,
127 jint start_depth,
128 jint max_frame_count,
129 jvmtiFrameInfo* frame_buffer,
130 jint* count_ptr) {
131 if (java_thread == nullptr) {
132 return ERR(INVALID_THREAD);
133 }
134
135 art::Thread* thread;
136 {
137 // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
138 art::ScopedObjectAccess soa(art::Thread::Current());
139 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
140 thread = art::Thread::FromManagedThread(soa, java_thread);
141 DCHECK(thread != nullptr);
142 }
143
144 art::ThreadState state = thread->GetState();
145 if (state == art::ThreadState::kStarting ||
146 state == art::ThreadState::kTerminated ||
147 thread->IsStillStarting()) {
148 return ERR(THREAD_NOT_ALIVE);
149 }
150
151 if (max_frame_count < 0) {
152 return ERR(ILLEGAL_ARGUMENT);
153 }
154 if (frame_buffer == nullptr || count_ptr == nullptr) {
155 return ERR(NULL_POINTER);
156 }
157
158 if (max_frame_count == 0) {
159 *count_ptr = 0;
160 return ERR(NONE);
161 }
162
163 GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0,
164 start_depth >= 0 ?static_cast<size_t>(max_frame_count) : 0);
165 thread->RequestSynchronousCheckpoint(&closure);
166
167 size_t collected_frames = closure.frames.size();
168
169 // Frames from the top.
170 if (start_depth >= 0) {
171 if (closure.start_result != 0) {
172 // Not enough frames.
173 return ERR(ILLEGAL_ARGUMENT);
174 }
175 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
176 if (closure.frames.size() > 0) {
177 memcpy(frame_buffer, closure.frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
178 }
179 *count_ptr = static_cast<jint>(closure.frames.size());
180 return ERR(NONE);
181 }
182
183 // Frames from the bottom.
184 if (collected_frames < static_cast<size_t>(-start_depth)) {
185 return ERR(ILLEGAL_ARGUMENT);
186 }
187
188 size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
189 memcpy(frame_buffer,
190 &closure.frames.data()[collected_frames + start_depth],
191 count * sizeof(jvmtiFrameInfo));
192 *count_ptr = static_cast<jint>(count);
193 return ERR(NONE);
194}
195
196} // namespace openjdkjvmti