1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Stacks and their uses (e.g. native --> interpreted method calls). 19 * 20 * See the majestic ASCII art in Stack.h. 21 */ 22 #include "Dalvik.h" 23 #include "jni.h" 24 25 #include <stdlib.h> 26 #include <stdarg.h> 27 28 /* 29 * Initialize the interpreter stack in a new thread. 30 * 31 * Currently this doesn't do much, since we don't need to zero out the 32 * stack (and we really don't want to if it was created with mmap). 33 */ 34 bool dvmInitInterpStack(Thread* thread, int stackSize) 35 { 36 assert(thread->interpStackStart != NULL); 37 38 assert(thread->interpSave.curFrame == NULL); 39 40 return true; 41 } 42 43 /* 44 * We're calling an interpreted method from an internal VM function or 45 * via reflection. 46 * 47 * Push a frame for an interpreted method onto the stack. This is only 48 * used when calling into interpreted code from native code. (The 49 * interpreter does its own stack frame manipulation for interp-->interp 50 * calls.) 51 * 52 * The size we need to reserve is the sum of parameters, local variables, 53 * saved goodies, and outbound parameters. 54 * 55 * We start by inserting a "break" frame, which ensures that the interpreter 56 * hands control back to us after the function we call returns or an 57 * uncaught exception is thrown. 58 */ 59 static bool dvmPushInterpFrame(Thread* self, const Method* method) 60 { 61 StackSaveArea* saveBlock; 62 StackSaveArea* breakSaveBlock; 63 int stackReq; 64 u1* stackPtr; 65 66 assert(!dvmIsNativeMethod(method)); 67 assert(!dvmIsAbstractMethod(method)); 68 69 stackReq = method->registersSize * 4 // params + locals 70 + sizeof(StackSaveArea) * 2 // break frame + regular frame 71 + method->outsSize * 4; // args to other methods 72 73 if (self->interpSave.curFrame != NULL) 74 stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame); 75 else 76 stackPtr = self->interpStackStart; 77 78 if (stackPtr - stackReq < self->interpStackEnd) { 79 /* not enough space */ 80 LOGW("Stack overflow on call to interp " 81 "(req=%d top=%p cur=%p size=%d %s.%s)", 82 stackReq, self->interpStackStart, self->interpSave.curFrame, 83 self->interpStackSize, method->clazz->descriptor, method->name); 84 dvmHandleStackOverflow(self, method); 85 assert(dvmCheckException(self)); 86 return false; 87 } 88 89 /* 90 * Shift the stack pointer down, leaving space for the function's 91 * args/registers and save area. 92 */ 93 stackPtr -= sizeof(StackSaveArea); 94 breakSaveBlock = (StackSaveArea*)stackPtr; 95 stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea); 96 saveBlock = (StackSaveArea*) stackPtr; 97 98 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) 99 /* debug -- memset the new stack, unless we want valgrind's help */ 100 memset(stackPtr - (method->outsSize*4), 0xaf, stackReq); 101 #endif 102 #ifdef EASY_GDB 103 breakSaveBlock->prevSave = 104 (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame); 105 saveBlock->prevSave = breakSaveBlock; 106 #endif 107 108 breakSaveBlock->prevFrame = self->interpSave.curFrame; 109 breakSaveBlock->savedPc = NULL; // not required 110 breakSaveBlock->xtra.localRefCookie = 0; // not required 111 breakSaveBlock->method = NULL; 112 saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock); 113 saveBlock->savedPc = NULL; // not required 114 saveBlock->xtra.currentPc = NULL; // not required? 115 saveBlock->method = method; 116 117 LOGVV("PUSH frame: old=%p new=%p (size=%d)", 118 self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock), 119 (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); 120 121 self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock); 122 123 return true; 124 } 125 126 /* 127 * We're calling a JNI native method from an internal VM fuction or 128 * via reflection. This is also used to create the "fake" native-method 129 * frames at the top of the interpreted stack. 130 * 131 * This actually pushes two frames; the first is a "break" frame. 132 * 133 * The top frame has additional space for JNI local reference tracking. 134 */ 135 bool dvmPushJNIFrame(Thread* self, const Method* method) 136 { 137 StackSaveArea* saveBlock; 138 StackSaveArea* breakSaveBlock; 139 int stackReq; 140 u1* stackPtr; 141 142 assert(dvmIsNativeMethod(method)); 143 144 stackReq = method->registersSize * 4 // params only 145 + sizeof(StackSaveArea) * 2; // break frame + regular frame 146 147 if (self->interpSave.curFrame != NULL) 148 stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame); 149 else 150 stackPtr = self->interpStackStart; 151 152 if (stackPtr - stackReq < self->interpStackEnd) { 153 /* not enough space */ 154 LOGW("Stack overflow on call to native " 155 "(req=%d top=%p cur=%p size=%d '%s')", 156 stackReq, self->interpStackStart, self->interpSave.curFrame, 157 self->interpStackSize, method->name); 158 dvmHandleStackOverflow(self, method); 159 assert(dvmCheckException(self)); 160 return false; 161 } 162 163 /* 164 * Shift the stack pointer down, leaving space for just the stack save 165 * area for the break frame, then shift down farther for the full frame. 166 * We leave space for the method args, which are copied in later. 167 */ 168 stackPtr -= sizeof(StackSaveArea); 169 breakSaveBlock = (StackSaveArea*)stackPtr; 170 stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea); 171 saveBlock = (StackSaveArea*) stackPtr; 172 173 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) 174 /* debug -- memset the new stack */ 175 memset(stackPtr, 0xaf, stackReq); 176 #endif 177 #ifdef EASY_GDB 178 if (self->interpSave.curFrame == NULL) 179 breakSaveBlock->prevSave = NULL; 180 else { 181 void* fp = FP_FROM_SAVEAREA(self->interpSave.curFrame); 182 breakSaveBlock->prevSave = (StackSaveArea*)fp; 183 } 184 saveBlock->prevSave = breakSaveBlock; 185 #endif 186 187 breakSaveBlock->prevFrame = self->interpSave.curFrame; 188 breakSaveBlock->savedPc = NULL; // not required 189 breakSaveBlock->xtra.localRefCookie = 0; // not required 190 breakSaveBlock->method = NULL; 191 saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock); 192 saveBlock->savedPc = NULL; // not required 193 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all; 194 saveBlock->method = method; 195 196 LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)", 197 self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock), 198 (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); 199 200 self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock); 201 202 return true; 203 } 204 205 /* 206 * This is used by the JNI PushLocalFrame call. We push a new frame onto 207 * the stack that has no ins, outs, or locals, and no break frame above it. 208 * It's strictly used for tracking JNI local refs, and will be popped off 209 * by dvmPopFrame if it's not removed explicitly. 210 */ 211 bool dvmPushLocalFrame(Thread* self, const Method* method) 212 { 213 StackSaveArea* saveBlock; 214 int stackReq; 215 u1* stackPtr; 216 217 assert(dvmIsNativeMethod(method)); 218 219 stackReq = sizeof(StackSaveArea); // regular frame 220 221 assert(self->interpSave.curFrame != NULL); 222 stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame); 223 224 if (stackPtr - stackReq < self->interpStackEnd) { 225 /* not enough space; let JNI throw the exception */ 226 LOGW("Stack overflow on PushLocal " 227 "(req=%d top=%p cur=%p size=%d '%s')", 228 stackReq, self->interpStackStart, self->interpSave.curFrame, 229 self->interpStackSize, method->name); 230 dvmHandleStackOverflow(self, method); 231 assert(dvmCheckException(self)); 232 return false; 233 } 234 235 /* 236 * Shift the stack pointer down, leaving space for just the stack save 237 * area for the break frame, then shift down farther for the full frame. 238 */ 239 stackPtr -= sizeof(StackSaveArea); 240 saveBlock = (StackSaveArea*) stackPtr; 241 242 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) 243 /* debug -- memset the new stack */ 244 memset(stackPtr, 0xaf, stackReq); 245 #endif 246 #ifdef EASY_GDB 247 saveBlock->prevSave = 248 (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame); 249 #endif 250 251 saveBlock->prevFrame = self->interpSave.curFrame; 252 saveBlock->savedPc = NULL; // not required 253 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all; 254 saveBlock->method = method; 255 256 LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)", 257 self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock), 258 (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); 259 260 self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock); 261 262 return true; 263 } 264 265 /* 266 * Pop one frame pushed on by JNI PushLocalFrame. 267 * 268 * If we've gone too far, the previous frame is either a break frame or 269 * an interpreted frame. Either way, the method pointer won't match. 270 */ 271 bool dvmPopLocalFrame(Thread* self) 272 { 273 StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame); 274 275 assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame)); 276 if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) { 277 /* 278 * The previous frame doesn't have the same method pointer -- we've 279 * been asked to pop too much. 280 */ 281 assert(dvmIsBreakFrame((u4*)saveBlock->prevFrame) || 282 !dvmIsNativeMethod( 283 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method)); 284 return false; 285 } 286 287 LOGVV("POP JNI local frame: removing %s, now %s", 288 saveBlock->method->name, 289 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name); 290 dvmPopJniLocals(self, saveBlock); 291 self->interpSave.curFrame = saveBlock->prevFrame; 292 293 return true; 294 } 295 296 /* 297 * Pop a frame we added. There should be one method frame and one break 298 * frame. 299 * 300 * If JNI Push/PopLocalFrame calls were mismatched, we might end up 301 * popping multiple method frames before we find the break. 302 * 303 * Returns "false" if there was no frame to pop. 304 */ 305 static bool dvmPopFrame(Thread* self) 306 { 307 StackSaveArea* saveBlock; 308 309 if (self->interpSave.curFrame == NULL) 310 return false; 311 312 saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame); 313 assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame)); 314 315 /* 316 * Remove everything up to the break frame. If this was a call into 317 * native code, pop the JNI local references table. 318 */ 319 while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) { 320 /* probably a native->native JNI call */ 321 322 if (dvmIsNativeMethod(saveBlock->method)) { 323 LOGVV("Popping JNI stack frame for %s.%s%s", 324 saveBlock->method->clazz->descriptor, 325 saveBlock->method->name, 326 (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ? 327 "" : " (JNI local)"); 328 dvmPopJniLocals(self, saveBlock); 329 } 330 331 saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame); 332 } 333 if (saveBlock->method != NULL) { 334 LOGE("PopFrame missed the break"); 335 assert(false); 336 dvmAbort(); // stack trashed -- nowhere to go in this thread 337 } 338 339 LOGVV("POP frame: cur=%p new=%p", 340 self->interpSave.curFrame, saveBlock->prevFrame); 341 342 self->interpSave.curFrame = saveBlock->prevFrame; 343 return true; 344 } 345 346 /* 347 * Common code for dvmCallMethodV/A and dvmInvokeMethod. 348 * 349 * Pushes a call frame on, advancing self->interpSave.curFrame. 350 */ 351 static ClassObject* callPrep(Thread* self, const Method* method, Object* obj, 352 bool checkAccess) 353 { 354 ClassObject* clazz; 355 356 #ifndef NDEBUG 357 if (self->status != THREAD_RUNNING) { 358 LOGW("threadid=%d: status=%d on call to %s.%s -", 359 self->threadId, self->status, 360 method->clazz->descriptor, method->name); 361 } 362 #endif 363 364 assert(self != NULL); 365 assert(method != NULL); 366 367 if (obj != NULL) 368 clazz = obj->clazz; 369 else 370 clazz = method->clazz; 371 372 IF_LOGVV() { 373 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 374 LOGVV("thread=%d native code calling %s.%s %s", self->threadId, 375 clazz->descriptor, method->name, desc); 376 free(desc); 377 } 378 379 if (checkAccess) { 380 /* needed for java.lang.reflect.Method.invoke */ 381 if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->interpSave.curFrame), 382 method)) 383 { 384 /* note this throws IAException, not IAError */ 385 dvmThrowIllegalAccessException("access to method denied"); 386 return NULL; 387 } 388 } 389 390 /* 391 * Push a call frame on. If there isn't enough room for ins, locals, 392 * outs, and the saved state, it will throw an exception. 393 * 394 * This updates self->interpSave.curFrame. 395 */ 396 if (dvmIsNativeMethod(method)) { 397 /* native code calling native code the hard way */ 398 if (!dvmPushJNIFrame(self, method)) { 399 assert(dvmCheckException(self)); 400 return NULL; 401 } 402 } else { 403 /* native code calling interpreted code */ 404 if (!dvmPushInterpFrame(self, method)) { 405 assert(dvmCheckException(self)); 406 return NULL; 407 } 408 } 409 410 return clazz; 411 } 412 413 /* 414 * Issue a method call. 415 * 416 * Pass in NULL for "obj" on calls to static methods. 417 * 418 * (Note this can't be inlined because it takes a variable number of args.) 419 */ 420 void dvmCallMethod(Thread* self, const Method* method, Object* obj, 421 JValue* pResult, ...) 422 { 423 va_list args; 424 va_start(args, pResult); 425 dvmCallMethodV(self, method, obj, false, pResult, args); 426 va_end(args); 427 } 428 429 /* 430 * Issue a method call with a variable number of arguments. We process 431 * the contents of "args" by scanning the method signature. 432 * 433 * Pass in NULL for "obj" on calls to static methods. 434 * 435 * We don't need to take the class as an argument because, in Dalvik, 436 * we don't need to worry about static synchronized methods. 437 */ 438 void dvmCallMethodV(Thread* self, const Method* method, Object* obj, 439 bool fromJni, JValue* pResult, va_list args) 440 { 441 const char* desc = &(method->shorty[1]); // [0] is the return type. 442 int verifyCount = 0; 443 ClassObject* clazz; 444 u4* ins; 445 446 clazz = callPrep(self, method, obj, false); 447 if (clazz == NULL) 448 return; 449 450 /* "ins" for new frame start at frame pointer plus locals */ 451 ins = ((u4*)self->interpSave.curFrame) + 452 (method->registersSize - method->insSize); 453 454 //LOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins); 455 456 /* put "this" pointer into in0 if appropriate */ 457 if (!dvmIsStaticMethod(method)) { 458 #ifdef WITH_EXTRA_OBJECT_VALIDATION 459 assert(obj != NULL && dvmIsHeapAddress(obj)); 460 #endif 461 *ins++ = (u4) obj; 462 verifyCount++; 463 } 464 465 JNIEnv* env = self->jniEnv; 466 while (*desc != '\0') { 467 switch (*(desc++)) { 468 case 'D': case 'J': { 469 u8 val = va_arg(args, u8); 470 memcpy(ins, &val, 8); // EABI prevents direct store 471 ins += 2; 472 verifyCount += 2; 473 break; 474 } 475 case 'F': { 476 /* floats were normalized to doubles; convert back */ 477 float f = (float) va_arg(args, double); 478 *ins++ = dvmFloatToU4(f); 479 verifyCount++; 480 break; 481 } 482 case 'L': { /* 'shorty' descr uses L for all refs, incl array */ 483 void* arg = va_arg(args, void*); 484 assert(obj == NULL || dvmIsHeapAddress(obj)); 485 jobject argObj = reinterpret_cast<jobject>(arg); 486 if (fromJni) 487 *ins++ = (u4) dvmDecodeIndirectRef(env, argObj); 488 else 489 *ins++ = (u4) argObj; 490 verifyCount++; 491 break; 492 } 493 default: { 494 /* Z B C S I -- all passed as 32-bit integers */ 495 *ins++ = va_arg(args, u4); 496 verifyCount++; 497 break; 498 } 499 } 500 } 501 502 #ifndef NDEBUG 503 if (verifyCount != method->insSize) { 504 LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, 505 method->insSize, clazz->descriptor, method->name); 506 assert(false); 507 goto bail; 508 } 509 #endif 510 511 //dvmDumpThreadStack(dvmThreadSelf()); 512 513 if (dvmIsNativeMethod(method)) { 514 TRACE_METHOD_ENTER(self, method); 515 /* 516 * Because we leave no space for local variables, "curFrame" points 517 * directly at the method arguments. 518 */ 519 (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, 520 method, self); 521 TRACE_METHOD_EXIT(self, method); 522 } else { 523 dvmInterpret(self, method, pResult); 524 } 525 526 #ifndef NDEBUG 527 bail: 528 #endif 529 dvmPopFrame(self); 530 } 531 532 /* 533 * Issue a method call with arguments provided in an array. We process 534 * the contents of "args" by scanning the method signature. 535 * 536 * The values were likely placed into an uninitialized jvalue array using 537 * the field specifiers, which means that sub-32-bit fields (e.g. short, 538 * boolean) may not have 32 or 64 bits of valid data. This is different 539 * from the varargs invocation where the C compiler does a widening 540 * conversion when calling a function. As a result, we have to be a 541 * little more precise when pulling stuff out. 542 * 543 * "args" may be NULL if the method has no arguments. 544 */ 545 void dvmCallMethodA(Thread* self, const Method* method, Object* obj, 546 bool fromJni, JValue* pResult, const jvalue* args) 547 { 548 const char* desc = &(method->shorty[1]); // [0] is the return type. 549 int verifyCount = 0; 550 ClassObject* clazz; 551 u4* ins; 552 553 clazz = callPrep(self, method, obj, false); 554 if (clazz == NULL) 555 return; 556 557 /* "ins" for new frame start at frame pointer plus locals */ 558 ins = ((u4*)self->interpSave.curFrame) + 559 (method->registersSize - method->insSize); 560 561 /* put "this" pointer into in0 if appropriate */ 562 if (!dvmIsStaticMethod(method)) { 563 assert(obj != NULL); 564 *ins++ = (u4) obj; /* obj is a "real" ref */ 565 verifyCount++; 566 } 567 568 JNIEnv* env = self->jniEnv; 569 while (*desc != '\0') { 570 switch (*desc++) { 571 case 'D': /* 64-bit quantity; have to use */ 572 case 'J': /* memcpy() in case of mis-alignment */ 573 memcpy(ins, &args->j, 8); 574 ins += 2; 575 verifyCount++; /* this needs an extra push */ 576 break; 577 case 'L': /* includes array refs */ 578 if (fromJni) 579 *ins++ = (u4) dvmDecodeIndirectRef(env, args->l); 580 else 581 *ins++ = (u4) args->l; 582 break; 583 case 'F': 584 case 'I': 585 *ins++ = args->i; /* full 32 bits */ 586 break; 587 case 'S': 588 *ins++ = args->s; /* 16 bits, sign-extended */ 589 break; 590 case 'C': 591 *ins++ = args->c; /* 16 bits, unsigned */ 592 break; 593 case 'B': 594 *ins++ = args->b; /* 8 bits, sign-extended */ 595 break; 596 case 'Z': 597 *ins++ = args->z; /* 8 bits, zero or non-zero */ 598 break; 599 default: 600 LOGE("Invalid char %c in short signature of %s.%s", 601 *(desc-1), clazz->descriptor, method->name); 602 assert(false); 603 goto bail; 604 } 605 606 verifyCount++; 607 args++; 608 } 609 610 #ifndef NDEBUG 611 if (verifyCount != method->insSize) { 612 LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, 613 method->insSize, clazz->descriptor, method->name); 614 assert(false); 615 goto bail; 616 } 617 #endif 618 619 if (dvmIsNativeMethod(method)) { 620 TRACE_METHOD_ENTER(self, method); 621 /* 622 * Because we leave no space for local variables, "curFrame" points 623 * directly at the method arguments. 624 */ 625 (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, 626 method, self); 627 TRACE_METHOD_EXIT(self, method); 628 } else { 629 dvmInterpret(self, method, pResult); 630 } 631 632 bail: 633 dvmPopFrame(self); 634 } 635 636 static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) { 637 std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor)); 638 std::string actualClassName = dvmHumanReadableType(arg); 639 dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s", 640 argIndex + 1, expectedClassName.c_str(), actualClassName.c_str()); 641 } 642 643 /* 644 * Invoke a method, using the specified arguments and return type, through 645 * one of the reflection interfaces. Could be a virtual or direct method 646 * (including constructors). Used for reflection. 647 * 648 * Deals with boxing/unboxing primitives and performs widening conversions. 649 * 650 * "invokeObj" will be null for a static method. 651 * 652 * If the invocation returns with an exception raised, we have to wrap it. 653 */ 654 Object* dvmInvokeMethod(Object* obj, const Method* method, 655 ArrayObject* argList, ArrayObject* params, ClassObject* returnType, 656 bool noAccessCheck) 657 { 658 ClassObject* clazz; 659 Object* retObj = NULL; 660 Thread* self = dvmThreadSelf(); 661 s4* ins; 662 int verifyCount, argListLength; 663 JValue retval; 664 bool needPop = false; 665 666 /* verify arg count */ 667 if (argList != NULL) 668 argListLength = argList->length; 669 else 670 argListLength = 0; 671 if (argListLength != (int) params->length) { 672 dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, 673 "wrong number of arguments; expected %d, got %d", 674 params->length, argListLength); 675 return NULL; 676 } 677 678 clazz = callPrep(self, method, obj, !noAccessCheck); 679 if (clazz == NULL) 680 return NULL; 681 needPop = true; 682 683 /* "ins" for new frame start at frame pointer plus locals */ 684 ins = ((s4*)self->interpSave.curFrame) + 685 (method->registersSize - method->insSize); 686 verifyCount = 0; 687 688 //LOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins); 689 690 /* put "this" pointer into in0 if appropriate */ 691 if (!dvmIsStaticMethod(method)) { 692 assert(obj != NULL); 693 *ins++ = (s4) obj; 694 verifyCount++; 695 } 696 697 /* 698 * Copy the args onto the stack. Primitive types are converted when 699 * necessary, and object types are verified. 700 */ 701 DataObject** args = (DataObject**)(void*)argList->contents; 702 ClassObject** types = (ClassObject**)(void*)params->contents; 703 for (int i = 0; i < argListLength; i++) { 704 int width = dvmConvertArgument(*args++, *types++, ins); 705 if (width < 0) { 706 dvmPopFrame(self); // throw wants to pull PC out of stack 707 needPop = false; 708 throwArgumentTypeMismatch(i, *(types-1), *(args-1)); 709 goto bail; 710 } 711 712 ins += width; 713 verifyCount += width; 714 } 715 716 #ifndef NDEBUG 717 if (verifyCount != method->insSize) { 718 LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, 719 method->insSize, clazz->descriptor, method->name); 720 assert(false); 721 goto bail; 722 } 723 #endif 724 725 if (dvmIsNativeMethod(method)) { 726 TRACE_METHOD_ENTER(self, method); 727 /* 728 * Because we leave no space for local variables, "curFrame" points 729 * directly at the method arguments. 730 */ 731 (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval, 732 method, self); 733 TRACE_METHOD_EXIT(self, method); 734 } else { 735 dvmInterpret(self, method, &retval); 736 } 737 738 /* 739 * Pop the frame immediately. The "wrap" calls below can cause 740 * allocations, and we don't want the GC to walk the now-dead frame. 741 */ 742 dvmPopFrame(self); 743 needPop = false; 744 745 /* 746 * If an exception is raised, wrap and replace. This is necessary 747 * because the invoked method could have thrown a checked exception 748 * that the caller wasn't prepared for. 749 * 750 * We might be able to do this up in the interpreted code, but that will 751 * leave us with a shortened stack trace in the top-level exception. 752 */ 753 if (dvmCheckException(self)) { 754 dvmWrapException("Ljava/lang/reflect/InvocationTargetException;"); 755 } else { 756 /* 757 * If this isn't a void method or constructor, convert the return type 758 * to an appropriate object. 759 * 760 * We don't do this when an exception is raised because the value 761 * in "retval" is undefined. 762 */ 763 if (returnType != NULL) { 764 retObj = (Object*)dvmBoxPrimitive(retval, returnType); 765 dvmReleaseTrackedAlloc(retObj, NULL); 766 } 767 } 768 769 bail: 770 if (needPop) { 771 dvmPopFrame(self); 772 } 773 return retObj; 774 } 775 776 struct LineNumFromPcContext { 777 u4 address; 778 u4 lineNum; 779 }; 780 781 static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum) 782 { 783 LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt; 784 785 // We know that this callback will be called in 786 // ascending address order, so keep going until we find 787 // a match or we've just gone past it. 788 789 if (address > pContext->address) { 790 // The line number from the previous positions callback 791 // wil be the final result. 792 return 1; 793 } 794 795 pContext->lineNum = lineNum; 796 797 return (address == pContext->address) ? 1 : 0; 798 } 799 800 /* 801 * Determine the source file line number based on the program counter. 802 * "pc" is an offset, in 16-bit units, from the start of the method's code. 803 * 804 * Returns -1 if no match was found (possibly because the source files were 805 * compiled without "-g", so no line number information is present). 806 * Returns -2 for native methods (as expected in exception traces). 807 */ 808 int dvmLineNumFromPC(const Method* method, u4 relPc) 809 { 810 const DexCode* pDexCode = dvmGetMethodCode(method); 811 812 if (pDexCode == NULL) { 813 if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method)) 814 return -2; 815 return -1; /* can happen for abstract method stub */ 816 } 817 818 LineNumFromPcContext context; 819 memset(&context, 0, sizeof(context)); 820 context.address = relPc; 821 // A method with no line number info should return -1 822 context.lineNum = -1; 823 824 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode, 825 method->clazz->descriptor, 826 method->prototype.protoIdx, 827 method->accessFlags, 828 lineNumForPcCb, NULL, &context); 829 830 return context.lineNum; 831 } 832 833 /* 834 * Compute the frame depth. 835 * 836 * Excludes "break" frames. 837 */ 838 int dvmComputeExactFrameDepth(const void* fp) 839 { 840 int count = 0; 841 842 for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) { 843 if (!dvmIsBreakFrame((u4*)fp)) 844 count++; 845 } 846 847 return count; 848 } 849 850 /* 851 * Compute the "vague" frame depth, which is just a pointer subtraction. 852 * The result is NOT an overly generous assessment of the number of 853 * frames; the only meaningful use is to compare against the result of 854 * an earlier invocation. 855 * 856 * Useful for implementing single-step debugger modes, which may need to 857 * call this for every instruction. 858 */ 859 int dvmComputeVagueFrameDepth(Thread* thread, const void* fp) 860 { 861 const u1* interpStackStart = thread->interpStackStart; 862 863 assert((u1*) fp >= interpStackStart - thread->interpStackSize); 864 assert((u1*) fp < interpStackStart); 865 return interpStackStart - (u1*) fp; 866 } 867 868 /* 869 * Get the calling frame. Pass in the current fp. 870 * 871 * Skip "break" frames and reflection invoke frames. 872 */ 873 void* dvmGetCallerFP(const void* curFrame) 874 { 875 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; 876 StackSaveArea* saveArea; 877 878 retry: 879 if (dvmIsBreakFrame((u4*)caller)) { 880 /* pop up one more */ 881 caller = SAVEAREA_FROM_FP(caller)->prevFrame; 882 if (caller == NULL) 883 return NULL; /* hit the top */ 884 885 /* 886 * If we got here by java.lang.reflect.Method.invoke(), we don't 887 * want to return Method's class loader. Shift up one and try 888 * again. 889 */ 890 saveArea = SAVEAREA_FROM_FP(caller); 891 if (dvmIsReflectionMethod(saveArea->method)) { 892 caller = saveArea->prevFrame; 893 assert(caller != NULL); 894 goto retry; 895 } 896 } 897 898 return caller; 899 } 900 901 /* 902 * Get the caller's class. Pass in the current fp. 903 * 904 * This is used by e.g. java.lang.Class. 905 */ 906 ClassObject* dvmGetCallerClass(const void* curFrame) 907 { 908 void* caller; 909 910 caller = dvmGetCallerFP(curFrame); 911 if (caller == NULL) 912 return NULL; 913 914 return SAVEAREA_FROM_FP(caller)->method->clazz; 915 } 916 917 /* 918 * Get the caller's caller's class. Pass in the current fp. 919 * 920 * This is used by e.g. java.lang.Class, which wants to know about the 921 * class loader of the method that called it. 922 */ 923 ClassObject* dvmGetCaller2Class(const void* curFrame) 924 { 925 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; 926 void* callerCaller; 927 928 /* at the top? */ 929 if (dvmIsBreakFrame((u4*)caller) && 930 SAVEAREA_FROM_FP(caller)->prevFrame == NULL) 931 return NULL; 932 933 /* go one more */ 934 callerCaller = dvmGetCallerFP(caller); 935 if (callerCaller == NULL) 936 return NULL; 937 938 return SAVEAREA_FROM_FP(callerCaller)->method->clazz; 939 } 940 941 /* 942 * Get the caller's caller's caller's class. Pass in the current fp. 943 * 944 * This is used by e.g. java.lang.Class, which wants to know about the 945 * class loader of the method that called it. 946 */ 947 ClassObject* dvmGetCaller3Class(const void* curFrame) 948 { 949 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; 950 int i; 951 952 /* at the top? */ 953 if (dvmIsBreakFrame((u4*)caller) && 954 SAVEAREA_FROM_FP(caller)->prevFrame == NULL) 955 return NULL; 956 957 /* Walk up two frames if possible. */ 958 for (i = 0; i < 2; i++) { 959 caller = dvmGetCallerFP(caller); 960 if (caller == NULL) 961 return NULL; 962 } 963 964 return SAVEAREA_FROM_FP(caller)->method->clazz; 965 } 966 967 /* 968 * Fill a flat array of methods that comprise the current interpreter 969 * stack trace. Pass in the current frame ptr. Break frames are 970 * skipped, but reflection invocations are not. 971 * 972 * The current frame will be in element 0. 973 */ 974 void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length) 975 { 976 assert(fp != NULL); 977 assert(array != NULL); 978 size_t i = 0; 979 while (fp != NULL) { 980 if (!dvmIsBreakFrame((u4*)fp)) { 981 assert(i < length); 982 array[i++] = SAVEAREA_FROM_FP(fp)->method; 983 } 984 fp = SAVEAREA_FROM_FP(fp)->prevFrame; 985 } 986 } 987 988 /* 989 * Open up the reserved area and throw an exception. The reserved area 990 * should only be needed to create and initialize the exception itself. 991 * 992 * If we already opened it and we're continuing to overflow, abort the VM. 993 * 994 * We have to leave the "reserved" area open until the "catch" handler has 995 * finished doing its processing. This is because the catch handler may 996 * need to resolve classes, which requires calling into the class loader if 997 * the classes aren't already in the "initiating loader" list. 998 */ 999 void dvmHandleStackOverflow(Thread* self, const Method* method) 1000 { 1001 /* 1002 * Can we make the reserved area available? 1003 */ 1004 if (self->stackOverflowed) { 1005 /* 1006 * Already did, nothing to do but bail. 1007 */ 1008 LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting", 1009 self->threadId); 1010 dvmDumpThread(self, false); 1011 dvmAbort(); 1012 } 1013 1014 /* open it up to the full range */ 1015 LOGI("threadid=%d: stack overflow on call to %s.%s:%s", 1016 self->threadId, 1017 method->clazz->descriptor, method->name, method->shorty); 1018 StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame); 1019 LOGI(" method requires %d+%d+%d=%d bytes, fp is %p (%d left)", 1020 method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4, 1021 (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea), 1022 saveArea, (u1*) saveArea - self->interpStackEnd); 1023 LOGI(" expanding stack end (%p to %p)", self->interpStackEnd, 1024 self->interpStackStart - self->interpStackSize); 1025 //dvmDumpThread(self, false); 1026 self->interpStackEnd = self->interpStackStart - self->interpStackSize; 1027 self->stackOverflowed = true; 1028 1029 /* 1030 * If we were trying to throw an exception when the stack overflowed, 1031 * we will blow up when doing the class lookup on StackOverflowError 1032 * because of the pending exception. So, we clear it and make it 1033 * the cause of the SOE. 1034 */ 1035 Object* excep = dvmGetException(self); 1036 if (excep != NULL) { 1037 LOGW("Stack overflow while throwing exception"); 1038 dvmClearException(self); 1039 } 1040 dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep); 1041 } 1042 1043 /* 1044 * Reduce the available stack size. By this point we should have finished 1045 * our overflow processing. 1046 */ 1047 void dvmCleanupStackOverflow(Thread* self, const Object* exception) 1048 { 1049 const u1* newStackEnd; 1050 1051 assert(self->stackOverflowed); 1052 1053 if (exception->clazz != gDvm.exStackOverflowError) { 1054 /* exception caused during SOE, not the SOE itself */ 1055 return; 1056 } 1057 1058 newStackEnd = (self->interpStackStart - self->interpStackSize) 1059 + STACK_OVERFLOW_RESERVE; 1060 if ((u1*)self->interpSave.curFrame <= newStackEnd) { 1061 LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)", 1062 self->interpStackEnd, self->interpSave.curFrame); 1063 dvmDumpThread(self, false); 1064 dvmAbort(); 1065 } 1066 1067 self->interpStackEnd = newStackEnd; 1068 self->stackOverflowed = false; 1069 1070 LOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd, 1071 self->interpSave.curFrame); 1072 } 1073 1074 1075 /* 1076 * Extract the object that is the target of a monitor-enter instruction 1077 * in the top stack frame of "thread". 1078 * 1079 * The other thread might be alive, so this has to work carefully. 1080 * 1081 * The thread list lock must be held. 1082 * 1083 * Returns "true" if we successfully recover the object. "*pOwner" will 1084 * be NULL if we can't determine the owner for some reason (e.g. race 1085 * condition on ownership transfer). 1086 */ 1087 static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj, 1088 Thread** pOwner) 1089 { 1090 void* framePtr = thread->interpSave.curFrame; 1091 1092 if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr)) 1093 return false; 1094 1095 const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr); 1096 const Method* method = saveArea->method; 1097 const u2* currentPc = saveArea->xtra.currentPc; 1098 1099 /* check Method* */ 1100 if (!dvmLinearAllocContains(method, sizeof(Method))) { 1101 LOGD("ExtrMon: method %p not valid", method); 1102 return false; 1103 } 1104 1105 /* check currentPc */ 1106 u4 insnsSize = dvmGetMethodInsnsSize(method); 1107 if (currentPc < method->insns || 1108 currentPc >= method->insns + insnsSize) 1109 { 1110 LOGD("ExtrMon: insns %p not valid (%p - %p)", 1111 currentPc, method->insns, method->insns + insnsSize); 1112 return false; 1113 } 1114 1115 /* check the instruction */ 1116 if ((*currentPc & 0xff) != OP_MONITOR_ENTER) { 1117 LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)", 1118 currentPc, *currentPc & 0xff); 1119 return false; 1120 } 1121 1122 /* get and check the register index */ 1123 unsigned int reg = *currentPc >> 8; 1124 if (reg >= method->registersSize) { 1125 LOGD("ExtrMon: invalid register %d (max %d)", 1126 reg, method->registersSize); 1127 return false; 1128 } 1129 1130 /* get and check the object in that register */ 1131 u4* fp = (u4*) framePtr; 1132 Object* obj = (Object*) fp[reg]; 1133 if (obj != NULL && !dvmIsHeapAddress(obj)) { 1134 LOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg); 1135 return false; 1136 } 1137 *pLockObj = obj; 1138 1139 /* 1140 * Try to determine the object's lock holder; it's okay if this fails. 1141 * 1142 * We're assuming the thread list lock is already held by this thread. 1143 * If it's not, we may be living dangerously if we have to scan through 1144 * the thread list to find a match. (The VM will generally be in a 1145 * suspended state when executing here, so this is a minor concern 1146 * unless we're dumping while threads are running, in which case there's 1147 * a good chance of stuff blowing up anyway.) 1148 */ 1149 *pOwner = dvmGetObjectLockHolder(obj); 1150 1151 return true; 1152 } 1153 1154 static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj, 1155 Thread* thread) 1156 { 1157 std::string msg(StringPrintf(" - waiting %s <%p> ", detail, obj)); 1158 1159 if (obj->clazz != gDvm.classJavaLangClass) { 1160 // I(16573) - waiting on <0xf5feda38> (a java.util.LinkedList) 1161 // I(16573) - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>) 1162 msg += "(a " + dvmHumanReadableType(obj) + ")"; 1163 } 1164 1165 if (thread != NULL) { 1166 std::string threadName(dvmGetThreadName(thread)); 1167 StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str()); 1168 } 1169 1170 dvmPrintDebugMessage(target, "%s\n", msg.c_str()); 1171 } 1172 1173 /* 1174 * Dump stack frames, starting from the specified frame and moving down. 1175 * 1176 * Each frame holds a pointer to the currently executing method, and the 1177 * saved program counter from the caller ("previous" frame). This means 1178 * we don't have the PC for the current method on the stack, which is 1179 * pretty reasonable since it's in the "PC register" for the VM. Because 1180 * exceptions need to show the correct line number we actually *do* have 1181 * an updated version in the fame's "xtra.currentPc", but it's unreliable. 1182 * 1183 * Note "framePtr" could be NULL in rare circumstances. 1184 */ 1185 static void dumpFrames(const DebugOutputTarget* target, void* framePtr, 1186 Thread* thread) 1187 { 1188 const StackSaveArea* saveArea; 1189 const Method* method; 1190 int checkCount = 0; 1191 const u2* currentPc = NULL; 1192 bool first = true; 1193 1194 /* 1195 * We call functions that require us to be holding the thread list lock. 1196 * It's probable that the caller has already done so, but it's not 1197 * guaranteed. If it's not locked, lock it now. 1198 */ 1199 bool needThreadUnlock = dvmTryLockThreadList(); 1200 1201 /* 1202 * The "currentPc" is updated whenever we execute an instruction that 1203 * might throw an exception. Show it here. 1204 */ 1205 if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) { 1206 saveArea = SAVEAREA_FROM_FP(framePtr); 1207 1208 if (saveArea->xtra.currentPc != NULL) 1209 currentPc = saveArea->xtra.currentPc; 1210 } 1211 1212 while (framePtr != NULL) { 1213 saveArea = SAVEAREA_FROM_FP(framePtr); 1214 method = saveArea->method; 1215 1216 if (dvmIsBreakFrame((u4*)framePtr)) { 1217 //dvmPrintDebugMessage(target, " (break frame)\n"); 1218 } else { 1219 int relPc; 1220 1221 if (currentPc != NULL) 1222 relPc = currentPc - saveArea->method->insns; 1223 else 1224 relPc = -1; 1225 1226 std::string methodName(dvmHumanReadableMethod(method, false)); 1227 if (dvmIsNativeMethod(method)) { 1228 dvmPrintDebugMessage(target, " at %s(Native Method)\n", 1229 methodName.c_str()); 1230 } else { 1231 dvmPrintDebugMessage(target, " at %s(%s:%s%d)\n", 1232 methodName.c_str(), dvmGetMethodSourceFile(method), 1233 (relPc >= 0 && first) ? "~" : "", 1234 relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc)); 1235 } 1236 1237 if (first) { 1238 /* 1239 * Decorate WAIT and MONITOR threads with some detail on 1240 * the first frame. 1241 * 1242 * warning: wait status not stable, even in suspend 1243 */ 1244 if (thread->status == THREAD_WAIT || 1245 thread->status == THREAD_TIMED_WAIT) 1246 { 1247 Monitor* mon = thread->waitMonitor; 1248 Object* obj = dvmGetMonitorObject(mon); 1249 if (obj != NULL) { 1250 Thread* joinThread = NULL; 1251 if (obj->clazz == gDvm.classJavaLangVMThread) { 1252 joinThread = dvmGetThreadFromThreadObject(obj); 1253 } 1254 printWaitMessage(target, "on", obj, joinThread); 1255 } 1256 } else if (thread->status == THREAD_MONITOR) { 1257 Object* obj; 1258 Thread* owner; 1259 if (extractMonitorEnterObject(thread, &obj, &owner)) { 1260 printWaitMessage(target, "to lock", obj, owner); 1261 } 1262 } 1263 } 1264 } 1265 1266 /* 1267 * Get saved PC for previous frame. There's no savedPc in a "break" 1268 * frame, because that represents native or interpreted code 1269 * invoked by the VM. The saved PC is sitting in the "PC register", 1270 * a local variable on the native stack. 1271 */ 1272 currentPc = saveArea->savedPc; 1273 1274 first = false; 1275 1276 if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) { 1277 LOGW("Warning: loop in stack trace at frame %d (%p -> %p)", 1278 checkCount, framePtr, saveArea->prevFrame); 1279 break; 1280 } 1281 framePtr = saveArea->prevFrame; 1282 1283 checkCount++; 1284 if (checkCount > 300) { 1285 dvmPrintDebugMessage(target, 1286 " ***** printed %d frames, not showing any more\n", 1287 checkCount); 1288 break; 1289 } 1290 } 1291 dvmPrintDebugMessage(target, "\n"); 1292 1293 if (needThreadUnlock) { 1294 dvmUnlockThreadList(); 1295 } 1296 } 1297 1298 1299 /* 1300 * Dump the stack for the specified thread. 1301 */ 1302 void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread) 1303 { 1304 dumpFrames(target, thread->interpSave.curFrame, thread); 1305 } 1306 1307 /* 1308 * Dump the stack for the specified thread, which is still running. 1309 * 1310 * This is very dangerous, because stack frames are being pushed on and 1311 * popped off, and if the thread exits we'll be looking at freed memory. 1312 * The plan here is to take a snapshot of the stack and then dump that 1313 * to try to minimize the chances of catching it mid-update. This should 1314 * work reasonably well on a single-CPU system. 1315 * 1316 * There is a small chance that calling here will crash the VM. 1317 */ 1318 void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread) 1319 { 1320 StackSaveArea* saveArea; 1321 const u1* origStack; 1322 u1* stackCopy = NULL; 1323 int origSize, fpOffset; 1324 void* fp; 1325 int depthLimit = 200; 1326 1327 if (thread == NULL || thread->interpSave.curFrame == NULL) { 1328 dvmPrintDebugMessage(target, 1329 "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n", 1330 thread, (thread != NULL) ? thread->threadId : 0); 1331 return; 1332 } 1333 1334 /* wait for a full quantum */ 1335 sched_yield(); 1336 1337 /* copy the info we need, then the stack itself */ 1338 origSize = thread->interpStackSize; 1339 origStack = (const u1*) thread->interpStackStart - origSize; 1340 stackCopy = (u1*) malloc(origSize); 1341 fpOffset = (u1*) thread->interpSave.curFrame - origStack; 1342 memcpy(stackCopy, origStack, origSize); 1343 1344 /* 1345 * Run through the stack and rewrite the "prev" pointers. 1346 */ 1347 //LOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack, 1348 // thread->interpSave.curFrame); 1349 fp = stackCopy + fpOffset; 1350 while (true) { 1351 int prevOffset; 1352 1353 if (depthLimit-- < 0) { 1354 /* we're probably screwed */ 1355 dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n"); 1356 dvmAbort(); 1357 } 1358 saveArea = SAVEAREA_FROM_FP(fp); 1359 if (saveArea->prevFrame == NULL) 1360 break; 1361 1362 prevOffset = (u1*) saveArea->prevFrame - origStack; 1363 if (prevOffset < 0 || prevOffset > origSize) { 1364 dvmPrintDebugMessage(target, 1365 "DumpRunning: bad offset found: %d (from %p %p)\n", 1366 prevOffset, origStack, saveArea->prevFrame); 1367 saveArea->prevFrame = NULL; 1368 break; 1369 } 1370 1371 saveArea->prevFrame = (u4*)(stackCopy + prevOffset); 1372 fp = saveArea->prevFrame; 1373 } 1374 1375 /* 1376 * We still need to pass the Thread for some monitor wait stuff. 1377 */ 1378 dumpFrames(target, stackCopy + fpOffset, thread); 1379 free(stackCopy); 1380 } 1381