1 /*
2 * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include "util.h"
27 #include "StackFrameImpl.h"
28 #include "inStream.h"
29 #include "outStream.h"
30 #include "threadControl.h"
31 #include "FrameID.h"
32
33 static jdwpError
validateThreadFrame(jthread thread,FrameID frame)34 validateThreadFrame(jthread thread, FrameID frame)
35 {
36 jvmtiError error;
37 jdwpError serror;
38 jint count;
39 error = threadControl_suspendCount(thread, &count);
40 if ( error == JVMTI_ERROR_NONE ) {
41 if ( count > 0 ) {
42 serror = validateFrameID(thread, frame);
43 } else {
44 serror = JDWP_ERROR(THREAD_NOT_SUSPENDED);
45 }
46 } else {
47 serror = map2jdwpError(error);
48 }
49 return serror;
50 }
51
52 static jdwpError
writeVariableValue(JNIEnv * env,PacketOutputStream * out,jthread thread,FrameNumber fnum,jint slot,jbyte typeKey)53 writeVariableValue(JNIEnv *env, PacketOutputStream *out, jthread thread,
54 FrameNumber fnum, jint slot, jbyte typeKey)
55 {
56 jvmtiError error;
57 jvalue value;
58
59 if (isObjectTag(typeKey)) {
60
61 WITH_LOCAL_REFS(env, 1) {
62
63 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
64 (gdata->jvmti, thread, fnum, slot, &value.l);
65
66 if (error != JVMTI_ERROR_NONE) {
67 outStream_setError(out, map2jdwpError(error));
68 } else {
69 (void)outStream_writeByte(out, specificTypeKey(env, value.l));
70 (void)outStream_writeObjectRef(env, out, value.l);
71 }
72
73 } END_WITH_LOCAL_REFS(env);
74
75 } else {
76 /*
77 * For primitive types, the type key is bounced back as is.
78 */
79 (void)outStream_writeByte(out, typeKey);
80 switch (typeKey) {
81 case JDWP_TAG(BYTE): {
82 jint intValue;
83 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
84 (gdata->jvmti, thread, fnum, slot, &intValue);
85 (void)outStream_writeByte(out, (jbyte)intValue);
86 break;
87 }
88
89 case JDWP_TAG(CHAR): {
90 jint intValue;
91 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
92 (gdata->jvmti, thread, fnum, slot, &intValue);
93 (void)outStream_writeChar(out, (jchar)intValue);
94 break;
95 }
96
97 case JDWP_TAG(FLOAT):
98 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalFloat)
99 (gdata->jvmti, thread, fnum, slot, &value.f);
100 (void)outStream_writeFloat(out, value.f);
101 break;
102
103 case JDWP_TAG(DOUBLE):
104 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalDouble)
105 (gdata->jvmti, thread, fnum, slot, &value.d);
106 (void)outStream_writeDouble(out, value.d);
107 break;
108
109 case JDWP_TAG(INT):
110 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
111 (gdata->jvmti, thread, fnum, slot, &value.i);
112 (void)outStream_writeInt(out, value.i);
113 break;
114
115 case JDWP_TAG(LONG):
116 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalLong)
117 (gdata->jvmti, thread, fnum, slot, &value.j);
118 (void)outStream_writeLong(out, value.j);
119 break;
120
121 case JDWP_TAG(SHORT): {
122 jint intValue;
123 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
124 (gdata->jvmti, thread, fnum, slot, &intValue);
125 (void)outStream_writeShort(out, (jshort)intValue);
126 break;
127 }
128
129 case JDWP_TAG(BOOLEAN):{
130 jint intValue;
131 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
132 (gdata->jvmti, thread, fnum, slot, &intValue);
133 (void)outStream_writeBoolean(out, (jboolean)intValue);
134 break;
135 }
136
137 default:
138 return JDWP_ERROR(INVALID_TAG);
139 }
140 }
141
142 return map2jdwpError(error);
143 }
144
145 static jdwpError
readVariableValue(JNIEnv * env,PacketInputStream * in,jthread thread,FrameNumber fnum,jint slot,jbyte typeKey)146 readVariableValue(JNIEnv *env, PacketInputStream *in, jthread thread,
147 FrameNumber fnum, jint slot, jbyte typeKey)
148 {
149 jvmtiError error;
150 jvalue value;
151
152 if (isObjectTag(typeKey)) {
153
154 value.l = inStream_readObjectRef(env, in);
155
156 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalObject)
157 (gdata->jvmti, thread, fnum, slot, value.l);
158
159 } else {
160 switch (typeKey) {
161 case JDWP_TAG(BYTE):
162 value.b = inStream_readByte(in);
163 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
164 (gdata->jvmti, thread, fnum, slot, value.b);
165 break;
166
167 case JDWP_TAG(CHAR):
168 value.c = inStream_readChar(in);
169 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
170 (gdata->jvmti, thread, fnum, slot, value.c);
171 break;
172
173 case JDWP_TAG(FLOAT):
174 value.f = inStream_readFloat(in);
175 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalFloat)
176 (gdata->jvmti, thread, fnum, slot, value.f);
177 break;
178
179 case JDWP_TAG(DOUBLE):
180 value.d = inStream_readDouble(in);
181 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalDouble)
182 (gdata->jvmti, thread, fnum, slot, value.d);
183 break;
184
185 case JDWP_TAG(INT):
186 value.i = inStream_readInt(in);
187 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
188 (gdata->jvmti, thread, fnum, slot, value.i);
189 break;
190
191 case JDWP_TAG(LONG):
192 value.j = inStream_readLong(in);
193 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalLong)
194 (gdata->jvmti, thread, fnum, slot, value.j);
195 break;
196
197 case JDWP_TAG(SHORT):
198 value.s = inStream_readShort(in);
199 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
200 (gdata->jvmti, thread, fnum, slot, value.s);
201 break;
202
203 case JDWP_TAG(BOOLEAN):
204 value.z = inStream_readBoolean(in);
205 error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
206 (gdata->jvmti, thread, fnum, slot, value.z);
207 break;
208
209 default:
210 return JDWP_ERROR(INVALID_TAG);
211 }
212 }
213
214 return map2jdwpError(error);
215 }
216
217 static jboolean
getValues(PacketInputStream * in,PacketOutputStream * out)218 getValues(PacketInputStream *in, PacketOutputStream *out)
219 {
220 JNIEnv *env;
221 int i;
222 jdwpError serror;
223 jthread thread;
224 FrameID frame;
225 jint variableCount;
226
227 env = getEnv();
228
229 thread = inStream_readThreadRef(env, in);
230 if (inStream_error(in)) {
231 return JNI_TRUE;
232 }
233 frame = inStream_readFrameID(in);
234 if (inStream_error(in)) {
235 return JNI_TRUE;
236 }
237 variableCount = inStream_readInt(in);
238 if (inStream_error(in)) {
239 return JNI_TRUE;
240 }
241
242 /*
243 * Validate the frame id
244 */
245 serror = validateThreadFrame(thread, frame);
246 if (serror != JDWP_ERROR(NONE)) {
247 outStream_setError(out, serror);
248 return JNI_TRUE;
249 }
250
251 (void)outStream_writeInt(out, variableCount);
252 for (i = 0; (i < variableCount) && !outStream_error(out); i++) {
253 jint slot;
254 jbyte typeKey;
255 FrameNumber fnum;
256
257 slot = inStream_readInt(in);
258 if (inStream_error(in))
259 break;
260 typeKey = inStream_readByte(in);
261 if (inStream_error(in))
262 break;
263
264 fnum = getFrameNumber(frame);
265 serror = writeVariableValue(env, out, thread, fnum, slot, typeKey);
266 if (serror != JDWP_ERROR(NONE)) {
267 outStream_setError(out, serror);
268 break;
269 }
270 }
271
272 return JNI_TRUE;
273 }
274
275 static jboolean
setValues(PacketInputStream * in,PacketOutputStream * out)276 setValues(PacketInputStream *in, PacketOutputStream *out)
277 {
278 JNIEnv *env;
279 jint i;
280 jdwpError serror;
281 jthread thread;
282 FrameID frame;
283 jint variableCount;
284
285 env = getEnv();
286
287 thread = inStream_readThreadRef(env, in);
288 if (inStream_error(in)) {
289 return JNI_TRUE;
290 }
291 frame = inStream_readFrameID(in);
292 if (inStream_error(in)) {
293 return JNI_TRUE;
294 }
295 variableCount = inStream_readInt(in);
296 if (inStream_error(in)) {
297 return JNI_TRUE;
298 }
299
300 /*
301 * Validate the frame id
302 */
303 serror = validateThreadFrame(thread, frame);
304 if (serror != JDWP_ERROR(NONE)) {
305 outStream_setError(out, serror);
306 return JNI_TRUE;
307 }
308
309 for (i = 0; (i < variableCount) && !inStream_error(in); i++) {
310
311 jint slot;
312 jbyte typeKey;
313 FrameNumber fnum;
314
315 slot = inStream_readInt(in);
316 if (inStream_error(in)) {
317 return JNI_TRUE;
318 }
319 typeKey = inStream_readByte(in);
320 if (inStream_error(in)) {
321 return JNI_TRUE;
322 }
323
324 fnum = getFrameNumber(frame);
325 serror = readVariableValue(env, in, thread, fnum, slot, typeKey);
326 if (serror != JDWP_ERROR(NONE))
327 break;
328 }
329
330 if (serror != JDWP_ERROR(NONE)) {
331 outStream_setError(out, serror);
332 }
333
334 return JNI_TRUE;
335 }
336
337 static jboolean
thisObject(PacketInputStream * in,PacketOutputStream * out)338 thisObject(PacketInputStream *in, PacketOutputStream *out)
339 {
340 JNIEnv *env;
341 jdwpError serror;
342 jthread thread;
343 FrameID frame;
344
345 env = getEnv();
346
347 thread = inStream_readThreadRef(env, in);
348 if (inStream_error(in)) {
349 return JNI_TRUE;
350 }
351
352 frame = inStream_readFrameID(in);
353 if (inStream_error(in)) {
354 return JNI_TRUE;
355 }
356
357 /*
358 * Validate the frame id
359 */
360 serror = validateThreadFrame(thread, frame);
361 if (serror != JDWP_ERROR(NONE)) {
362 outStream_setError(out, serror);
363 return JNI_TRUE;
364 }
365
366 WITH_LOCAL_REFS(env, 2) {
367
368 jvmtiError error;
369 jmethodID method;
370 jlocation location;
371 FrameNumber fnum;
372
373 /*
374 * Find out if the given frame is for a static or native method.
375 */
376 fnum = getFrameNumber(frame);
377 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation)
378 (gdata->jvmti, thread, fnum, &method, &location);
379 if (error == JVMTI_ERROR_NONE) {
380
381 jint modifiers;
382
383 error = methodModifiers(method, &modifiers);
384 if (error == JVMTI_ERROR_NONE) {
385
386 jobject this_object;
387
388 /*
389 * Return null for static or native methods; otherwise, the JVM
390 * spec guarantees that "this" is in slot 0
391 */
392 if (modifiers & (MOD_STATIC | MOD_NATIVE)) {
393 this_object = NULL;
394 (void)outStream_writeByte(out, specificTypeKey(env, this_object));
395 (void)outStream_writeObjectRef(env, out, this_object);
396 } else {
397 // ANDROID-CHANGED: On ART 'this' is not always in register 0. We just use
398 // GetLocalInstance in all cases.
399 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInstance)
400 (gdata->jvmti, thread, fnum, &this_object);
401 if (error == JVMTI_ERROR_NONE) {
402 (void)outStream_writeByte(out, specificTypeKey(env, this_object));
403 (void)outStream_writeObjectRef(env, out, this_object);
404 }
405 }
406
407 }
408 }
409 serror = map2jdwpError(error);
410
411 } END_WITH_LOCAL_REFS(env);
412
413 if (serror != JDWP_ERROR(NONE))
414 outStream_setError(out, serror);
415
416 return JNI_TRUE;
417 }
418
419 static jboolean
popFrames(PacketInputStream * in,PacketOutputStream * out)420 popFrames(PacketInputStream *in, PacketOutputStream *out)
421 {
422 jvmtiError error;
423 jdwpError serror;
424 jthread thread;
425 FrameID frame;
426 FrameNumber fnum;
427
428 thread = inStream_readThreadRef(getEnv(), in);
429 if (inStream_error(in)) {
430 return JNI_TRUE;
431 }
432
433 frame = inStream_readFrameID(in);
434 if (inStream_error(in)) {
435 return JNI_TRUE;
436 }
437
438 /*
439 * Validate the frame id
440 */
441 serror = validateThreadFrame(thread, frame);
442 if (serror != JDWP_ERROR(NONE)) {
443 outStream_setError(out, serror);
444 return JNI_TRUE;
445 }
446
447 if (threadControl_isDebugThread(thread)) {
448 outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
449 return JNI_TRUE;
450 }
451
452 fnum = getFrameNumber(frame);
453 error = threadControl_popFrames(thread, fnum);
454 if (error != JVMTI_ERROR_NONE) {
455 serror = map2jdwpError(error);
456 outStream_setError(out, serror);
457 }
458 return JNI_TRUE;
459 }
460
461 void *StackFrame_Cmds[] = { (void *)0x4
462 ,(void *)getValues
463 ,(void *)setValues
464 ,(void *)thisObject
465 ,(void *)popFrames
466 };
467