blob: 33e677f4b130fb0e203bdb95d952139c30bec10c [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"
40#include "mirror/class.h"
41#include "mirror/dex_cache.h"
42#include "scoped_thread_state_change-inl.h"
43#include "stack.h"
44#include "thread.h"
45#include "thread_pool.h"
46
47namespace openjdkjvmti {
48
49struct GetStackTraceVisitor : public art::StackVisitor {
50 GetStackTraceVisitor(art::Thread* thread_in,
51 art::ScopedObjectAccessAlreadyRunnable& soa_,
52 size_t start_,
53 size_t stop_)
54 : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
55 soa(soa_),
56 start(start_),
57 stop(stop_) {}
58
59 bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
60 art::ArtMethod* m = GetMethod();
61 if (m->IsRuntimeMethod()) {
62 return true;
63 }
64
65 if (start == 0) {
66 m = m->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
67 jmethodID id = soa.EncodeMethod(m);
68
69 art::mirror::DexCache* dex_cache = m->GetDexCache();
70 int32_t line_number = -1;
71 if (dex_cache != nullptr) { // be tolerant of bad input
72 const art::DexFile* dex_file = dex_cache->GetDexFile();
73 line_number = art::annotations::GetLineNumFromPC(dex_file, m, GetDexPc(false));
74 }
75
76 jvmtiFrameInfo info = { id, static_cast<jlong>(line_number) };
77 frames.push_back(info);
78
79 if (stop == 1) {
80 return false; // We're done.
81 } else if (stop > 0) {
82 stop--;
83 }
84 } else {
85 start--;
86 }
87
88 return true;
89 }
90
91 art::ScopedObjectAccessAlreadyRunnable& soa;
92 std::vector<jvmtiFrameInfo> frames;
93 size_t start;
94 size_t stop;
95};
96
97struct GetStackTraceClosure : public art::Closure {
98 public:
99 GetStackTraceClosure(size_t start, size_t stop)
100 : start_input(start),
101 stop_input(stop),
102 start_result(0),
103 stop_result(0) {}
104
105 void Run(art::Thread* self) OVERRIDE {
106 art::ScopedObjectAccess soa(art::Thread::Current());
107
108 GetStackTraceVisitor visitor(self, soa, start_input, stop_input);
109 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
124jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
125 jthread java_thread,
126 jint start_depth,
127 jint max_frame_count,
128 jvmtiFrameInfo* frame_buffer,
129 jint* count_ptr) {
130 if (java_thread == nullptr) {
131 return ERR(INVALID_THREAD);
132 }
133
134 art::Thread* thread;
135 {
136 // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
137 art::ScopedObjectAccess soa(art::Thread::Current());
138 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
139 thread = art::Thread::FromManagedThread(soa, java_thread);
140 DCHECK(thread != nullptr);
141 }
142
143 art::ThreadState state = thread->GetState();
144 if (state == art::ThreadState::kStarting ||
145 state == art::ThreadState::kTerminated ||
146 thread->IsStillStarting()) {
147 return ERR(THREAD_NOT_ALIVE);
148 }
149
150 if (max_frame_count < 0) {
151 return ERR(ILLEGAL_ARGUMENT);
152 }
153 if (frame_buffer == nullptr || count_ptr == nullptr) {
154 return ERR(NULL_POINTER);
155 }
156
157 if (max_frame_count == 0) {
158 *count_ptr = 0;
159 return ERR(NONE);
160 }
161
162 GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0,
163 start_depth >= 0 ?static_cast<size_t>(max_frame_count) : 0);
164 thread->RequestSynchronousCheckpoint(&closure);
165
166 size_t collected_frames = closure.frames.size();
167
168 // Frames from the top.
169 if (start_depth >= 0) {
170 if (closure.start_result != 0) {
171 // Not enough frames.
172 return ERR(ILLEGAL_ARGUMENT);
173 }
174 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
175 if (closure.frames.size() > 0) {
176 memcpy(frame_buffer, closure.frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
177 }
178 *count_ptr = static_cast<jint>(closure.frames.size());
179 return ERR(NONE);
180 }
181
182 // Frames from the bottom.
183 if (collected_frames < static_cast<size_t>(-start_depth)) {
184 return ERR(ILLEGAL_ARGUMENT);
185 }
186
187 size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
188 memcpy(frame_buffer,
189 &closure.frames.data()[collected_frames + start_depth],
190 count * sizeof(jvmtiFrameInfo));
191 *count_ptr = static_cast<jint>(count);
192 return ERR(NONE);
193}
194
195} // namespace openjdkjvmti