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 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 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 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 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 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 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 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