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 while (*desc != '\0') { 466 switch (*(desc++)) { 467 case 'D': case 'J': { 468 u8 val = va_arg(args, u8); 469 memcpy(ins, &val, 8); // EABI prevents direct store 470 ins += 2; 471 verifyCount += 2; 472 break; 473 } 474 case 'F': { 475 /* floats were normalized to doubles; convert back */ 476 float f = (float) va_arg(args, double); 477 *ins++ = dvmFloatToU4(f); 478 verifyCount++; 479 break; 480 } 481 case 'L': { /* 'shorty' descr uses L for all refs, incl array */ 482 void* arg = va_arg(args, void*); 483 assert(obj == NULL || dvmIsHeapAddress(obj)); 484 jobject argObj = reinterpret_cast<jobject>(arg); 485 if (fromJni) 486 *ins++ = (u4) dvmDecodeIndirectRef(self, argObj); 487 else 488 *ins++ = (u4) argObj; 489 verifyCount++; 490 break; 491 } 492 default: { 493 /* Z B C S I -- all passed as 32-bit integers */ 494 *ins++ = va_arg(args, u4); 495 verifyCount++; 496 break; 497 } 498 } 499 } 500 501 #ifndef NDEBUG 502 if (verifyCount != method->insSize) { 503 LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, 504 method->insSize, clazz->descriptor, method->name); 505 assert(false); 506 goto bail; 507 } 508 #endif 509 510 //dvmDumpThreadStack(dvmThreadSelf()); 511 512 if (dvmIsNativeMethod(method)) { 513 TRACE_METHOD_ENTER(self, method); 514 /* 515 * Because we leave no space for local variables, "curFrame" points 516 * directly at the method arguments. 517 */ 518 (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, 519 method, self); 520 TRACE_METHOD_EXIT(self, method); 521 } else { 522 dvmInterpret(self, method, pResult); 523 } 524 525 #ifndef NDEBUG 526 bail: 527 #endif 528 dvmPopFrame(self); 529 } 530 531 /* 532 * Issue a method call with arguments provided in an array. We process 533 * the contents of "args" by scanning the method signature. 534 * 535 * The values were likely placed into an uninitialized jvalue array using 536 * the field specifiers, which means that sub-32-bit fields (e.g. short, 537 * boolean) may not have 32 or 64 bits of valid data. This is different 538 * from the varargs invocation where the C compiler does a widening 539 * conversion when calling a function. As a result, we have to be a 540 * little more precise when pulling stuff out. 541 * 542 * "args" may be NULL if the method has no arguments. 543 */ 544 void dvmCallMethodA(Thread* self, const Method* method, Object* obj, 545 bool fromJni, JValue* pResult, const jvalue* args) 546 { 547 const char* desc = &(method->shorty[1]); // [0] is the return type. 548 int verifyCount = 0; 549 ClassObject* clazz; 550 u4* ins; 551 552 clazz = callPrep(self, method, obj, false); 553 if (clazz == NULL) 554 return; 555 556 /* "ins" for new frame start at frame pointer plus locals */ 557 ins = ((u4*)self->interpSave.curFrame) + 558 (method->registersSize - method->insSize); 559 560 /* put "this" pointer into in0 if appropriate */ 561 if (!dvmIsStaticMethod(method)) { 562 assert(obj != NULL); 563 *ins++ = (u4) obj; /* obj is a "real" ref */ 564 verifyCount++; 565 } 566 567 while (*desc != '\0') { 568 switch (*desc++) { 569 case 'D': /* 64-bit quantity; have to use */ 570 case 'J': /* memcpy() in case of mis-alignment */ 571 memcpy(ins, &args->j, 8); 572 ins += 2; 573 verifyCount++; /* this needs an extra push */ 574 break; 575 case 'L': /* includes array refs */ 576 if (fromJni) 577 *ins++ = (u4) dvmDecodeIndirectRef(self, args->l); 578 else 579 *ins++ = (u4) args->l; 580 break; 581 case 'F': 582 case 'I': 583 *ins++ = args->i; /* full 32 bits */ 584 break; 585 case 'S': 586 *ins++ = args->s; /* 16 bits, sign-extended */ 587 break; 588 case 'C': 589 *ins++ = args->c; /* 16 bits, unsigned */ 590 break; 591 case 'B': 592 *ins++ = args->b; /* 8 bits, sign-extended */ 593 break; 594 case 'Z': 595 *ins++ = args->z; /* 8 bits, zero or non-zero */ 596 break; 597 default: 598 LOGE("Invalid char %c in short signature of %s.%s", 599 *(desc-1), clazz->descriptor, method->name); 600 assert(false); 601 goto bail; 602 } 603 604 verifyCount++; 605 args++; 606 } 607 608 #ifndef NDEBUG 609 if (verifyCount != method->insSize) { 610 LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, 611 method->insSize, clazz->descriptor, method->name); 612 assert(false); 613 goto bail; 614 } 615 #endif 616 617 if (dvmIsNativeMethod(method)) { 618 TRACE_METHOD_ENTER(self, method); 619 /* 620 * Because we leave no space for local variables, "curFrame" points 621 * directly at the method arguments. 622 */ 623 (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, 624 method, self); 625 TRACE_METHOD_EXIT(self, method); 626 } else { 627 dvmInterpret(self, method, pResult); 628 } 629 630 bail: 631 dvmPopFrame(self); 632 } 633 634 static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) { 635 std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor)); 636 std::string actualClassName = dvmHumanReadableType(arg); 637 dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s", 638 argIndex + 1, expectedClassName.c_str(), actualClassName.c_str()); 639 } 640 641 /* 642 * Invoke a method, using the specified arguments and return type, through 643 * one of the reflection interfaces. Could be a virtual or direct method 644 * (including constructors). Used for reflection. 645 * 646 * Deals with boxing/unboxing primitives and performs widening conversions. 647 * 648 * "invokeObj" will be null for a static method. 649 * 650 * If the invocation returns with an exception raised, we have to wrap it. 651 */ 652 Object* dvmInvokeMethod(Object* obj, const Method* method, 653 ArrayObject* argList, ArrayObject* params, ClassObject* returnType, 654 bool noAccessCheck) 655 { 656 ClassObject* clazz; 657 Object* retObj = NULL; 658 Thread* self = dvmThreadSelf(); 659 s4* ins; 660 int verifyCount, argListLength; 661 JValue retval; 662 bool needPop = false; 663 664 /* verify arg count */ 665 if (argList != NULL) 666 argListLength = argList->length; 667 else 668 argListLength = 0; 669 if (argListLength != (int) params->length) { 670 dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, 671 "wrong number of arguments; expected %d, got %d", 672 params->length, argListLength); 673 return NULL; 674 } 675 676 clazz = callPrep(self, method, obj, !noAccessCheck); 677 if (clazz == NULL) 678 return NULL; 679 needPop = true; 680 681 /* "ins" for new frame start at frame pointer plus locals */ 682 ins = ((s4*)self->interpSave.curFrame) + 683 (method->registersSize - method->insSize); 684 verifyCount = 0; 685 686 //LOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins); 687 688 /* put "this" pointer into in0 if appropriate */ 689 if (!dvmIsStaticMethod(method)) { 690 assert(obj != NULL); 691 *ins++ = (s4) obj; 692 verifyCount++; 693 } 694 695 /* 696 * Copy the args onto the stack. Primitive types are converted when 697 * necessary, and object types are verified. 698 */ 699 DataObject** args = (DataObject**)(void*)argList->contents; 700 ClassObject** types = (ClassObject**)(void*)params->contents; 701 for (int i = 0; i < argListLength; i++) { 702 int width = dvmConvertArgument(*args++, *types++, ins); 703 if (width < 0) { 704 dvmPopFrame(self); // throw wants to pull PC out of stack 705 needPop = false; 706 throwArgumentTypeMismatch(i, *(types-1), *(args-1)); 707 goto bail; 708 } 709 710 ins += width; 711 verifyCount += width; 712 } 713 714 #ifndef NDEBUG 715 if (verifyCount != method->insSize) { 716 LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, 717 method->insSize, clazz->descriptor, method->name); 718 assert(false); 719 goto bail; 720 } 721 #endif 722 723 if (dvmIsNativeMethod(method)) { 724 TRACE_METHOD_ENTER(self, method); 725 /* 726 * Because we leave no space for local variables, "curFrame" points 727 * directly at the method arguments. 728 */ 729 (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval, 730 method, self); 731 TRACE_METHOD_EXIT(self, method); 732 } else { 733 dvmInterpret(self, method, &retval); 734 } 735 736 /* 737 * Pop the frame immediately. The "wrap" calls below can cause 738 * allocations, and we don't want the GC to walk the now-dead frame. 739 */ 740 dvmPopFrame(self); 741 needPop = false; 742 743 /* 744 * If an exception is raised, wrap and replace. This is necessary 745 * because the invoked method could have thrown a checked exception 746 * that the caller wasn't prepared for. 747 * 748 * We might be able to do this up in the interpreted code, but that will 749 * leave us with a shortened stack trace in the top-level exception. 750 */ 751 if (dvmCheckException(self)) { 752 dvmWrapException("Ljava/lang/reflect/InvocationTargetException;"); 753 } else { 754 /* 755 * If this isn't a void method or constructor, convert the return type 756 * to an appropriate object. 757 * 758 * We don't do this when an exception is raised because the value 759 * in "retval" is undefined. 760 */ 761 if (returnType != NULL) { 762 retObj = (Object*)dvmBoxPrimitive(retval, returnType); 763 dvmReleaseTrackedAlloc(retObj, NULL); 764 } 765 } 766 767 bail: 768 if (needPop) { 769 dvmPopFrame(self); 770 } 771 return retObj; 772 } 773 774 struct LineNumFromPcContext { 775 u4 address; 776 u4 lineNum; 777 }; 778 779 static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum) 780 { 781 LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt; 782 783 // We know that this callback will be called in 784 // ascending address order, so keep going until we find 785 // a match or we've just gone past it. 786 787 if (address > pContext->address) { 788 // The line number from the previous positions callback 789 // wil be the final result. 790 return 1; 791 } 792 793 pContext->lineNum = lineNum; 794 795 return (address == pContext->address) ? 1 : 0; 796 } 797 798 /* 799 * Determine the source file line number based on the program counter. 800 * "pc" is an offset, in 16-bit units, from the start of the method's code. 801 * 802 * Returns -1 if no match was found (possibly because the source files were 803 * compiled without "-g", so no line number information is present). 804 * Returns -2 for native methods (as expected in exception traces). 805 */ 806 int dvmLineNumFromPC(const Method* method, u4 relPc) 807 { 808 const DexCode* pDexCode = dvmGetMethodCode(method); 809 810 if (pDexCode == NULL) { 811 if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method)) 812 return -2; 813 return -1; /* can happen for abstract method stub */ 814 } 815 816 LineNumFromPcContext context; 817 memset(&context, 0, sizeof(context)); 818 context.address = relPc; 819 // A method with no line number info should return -1 820 context.lineNum = -1; 821 822 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode, 823 method->clazz->descriptor, 824 method->prototype.protoIdx, 825 method->accessFlags, 826 lineNumForPcCb, NULL, &context); 827 828 return context.lineNum; 829 } 830 831 /* 832 * Compute the frame depth. 833 * 834 * Excludes "break" frames. 835 */ 836 int dvmComputeExactFrameDepth(const void* fp) 837 { 838 int count = 0; 839 840 for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) { 841 if (!dvmIsBreakFrame((u4*)fp)) 842 count++; 843 } 844 845 return count; 846 } 847 848 /* 849 * Compute the "vague" frame depth, which is just a pointer subtraction. 850 * The result is NOT an overly generous assessment of the number of 851 * frames; the only meaningful use is to compare against the result of 852 * an earlier invocation. 853 * 854 * Useful for implementing single-step debugger modes, which may need to 855 * call this for every instruction. 856 */ 857 int dvmComputeVagueFrameDepth(Thread* thread, const void* fp) 858 { 859 const u1* interpStackStart = thread->interpStackStart; 860 861 assert((u1*) fp >= interpStackStart - thread->interpStackSize); 862 assert((u1*) fp < interpStackStart); 863 return interpStackStart - (u1*) fp; 864 } 865 866 /* 867 * Get the calling frame. Pass in the current fp. 868 * 869 * Skip "break" frames and reflection invoke frames. 870 */ 871 void* dvmGetCallerFP(const void* curFrame) 872 { 873 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; 874 StackSaveArea* saveArea; 875 876 retry: 877 if (dvmIsBreakFrame((u4*)caller)) { 878 /* pop up one more */ 879 caller = SAVEAREA_FROM_FP(caller)->prevFrame; 880 if (caller == NULL) 881 return NULL; /* hit the top */ 882 883 /* 884 * If we got here by java.lang.reflect.Method.invoke(), we don't 885 * want to return Method's class loader. Shift up one and try 886 * again. 887 */ 888 saveArea = SAVEAREA_FROM_FP(caller); 889 if (dvmIsReflectionMethod(saveArea->method)) { 890 caller = saveArea->prevFrame; 891 assert(caller != NULL); 892 goto retry; 893 } 894 } 895 896 return caller; 897 } 898 899 /* 900 * Get the caller's class. Pass in the current fp. 901 * 902 * This is used by e.g. java.lang.Class. 903 */ 904 ClassObject* dvmGetCallerClass(const void* curFrame) 905 { 906 void* caller; 907 908 caller = dvmGetCallerFP(curFrame); 909 if (caller == NULL) 910 return NULL; 911 912 return SAVEAREA_FROM_FP(caller)->method->clazz; 913 } 914 915 /* 916 * Get the caller's caller's class. Pass in the current fp. 917 * 918 * This is used by e.g. java.lang.Class, which wants to know about the 919 * class loader of the method that called it. 920 */ 921 ClassObject* dvmGetCaller2Class(const void* curFrame) 922 { 923 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; 924 void* callerCaller; 925 926 /* at the top? */ 927 if (dvmIsBreakFrame((u4*)caller) && 928 SAVEAREA_FROM_FP(caller)->prevFrame == NULL) 929 return NULL; 930 931 /* go one more */ 932 callerCaller = dvmGetCallerFP(caller); 933 if (callerCaller == NULL) 934 return NULL; 935 936 return SAVEAREA_FROM_FP(callerCaller)->method->clazz; 937 } 938 939 /* 940 * Get the caller's caller's caller's class. Pass in the current fp. 941 * 942 * This is used by e.g. java.lang.Class, which wants to know about the 943 * class loader of the method that called it. 944 */ 945 ClassObject* dvmGetCaller3Class(const void* curFrame) 946 { 947 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; 948 int i; 949 950 /* at the top? */ 951 if (dvmIsBreakFrame((u4*)caller) && 952 SAVEAREA_FROM_FP(caller)->prevFrame == NULL) 953 return NULL; 954 955 /* Walk up two frames if possible. */ 956 for (i = 0; i < 2; i++) { 957 caller = dvmGetCallerFP(caller); 958 if (caller == NULL) 959 return NULL; 960 } 961 962 return SAVEAREA_FROM_FP(caller)->method->clazz; 963 } 964 965 /* 966 * Fill a flat array of methods that comprise the current interpreter 967 * stack trace. Pass in the current frame ptr. Break frames are 968 * skipped, but reflection invocations are not. 969 * 970 * The current frame will be in element 0. 971 */ 972 void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length) 973 { 974 assert(fp != NULL); 975 assert(array != NULL); 976 size_t i = 0; 977 while (fp != NULL) { 978 if (!dvmIsBreakFrame((u4*)fp)) { 979 assert(i < length); 980 array[i++] = SAVEAREA_FROM_FP(fp)->method; 981 } 982 fp = SAVEAREA_FROM_FP(fp)->prevFrame; 983 } 984 } 985 986 /* 987 * Open up the reserved area and throw an exception. The reserved area 988 * should only be needed to create and initialize the exception itself. 989 * 990 * If we already opened it and we're continuing to overflow, abort the VM. 991 * 992 * We have to leave the "reserved" area open until the "catch" handler has 993 * finished doing its processing. This is because the catch handler may 994 * need to resolve classes, which requires calling into the class loader if 995 * the classes aren't already in the "initiating loader" list. 996 */ 997 void dvmHandleStackOverflow(Thread* self, const Method* method) 998 { 999 /* 1000 * Can we make the reserved area available? 1001 */ 1002 if (self->stackOverflowed) { 1003 /* 1004 * Already did, nothing to do but bail. 1005 */ 1006 LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting", 1007 self->threadId); 1008 dvmDumpThread(self, false); 1009 dvmAbort(); 1010 } 1011 1012 /* open it up to the full range */ 1013 LOGI("threadid=%d: stack overflow on call to %s.%s:%s", 1014 self->threadId, 1015 method->clazz->descriptor, method->name, method->shorty); 1016 StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame); 1017 LOGI(" method requires %d+%d+%d=%d bytes, fp is %p (%d left)", 1018 method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4, 1019 (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea), 1020 saveArea, (u1*) saveArea - self->interpStackEnd); 1021 LOGI(" expanding stack end (%p to %p)", self->interpStackEnd, 1022 self->interpStackStart - self->interpStackSize); 1023 //dvmDumpThread(self, false); 1024 self->interpStackEnd = self->interpStackStart - self->interpStackSize; 1025 self->stackOverflowed = true; 1026 1027 /* 1028 * If we were trying to throw an exception when the stack overflowed, 1029 * we will blow up when doing the class lookup on StackOverflowError 1030 * because of the pending exception. So, we clear it and make it 1031 * the cause of the SOE. 1032 */ 1033 Object* excep = dvmGetException(self); 1034 if (excep != NULL) { 1035 LOGW("Stack overflow while throwing exception"); 1036 dvmClearException(self); 1037 } 1038 dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep); 1039 } 1040 1041 /* 1042 * Reduce the available stack size. By this point we should have finished 1043 * our overflow processing. 1044 */ 1045 void dvmCleanupStackOverflow(Thread* self, const Object* exception) 1046 { 1047 const u1* newStackEnd; 1048 1049 assert(self->stackOverflowed); 1050 1051 if (exception->clazz != gDvm.exStackOverflowError) { 1052 /* exception caused during SOE, not the SOE itself */ 1053 return; 1054 } 1055 1056 newStackEnd = (self->interpStackStart - self->interpStackSize) 1057 + STACK_OVERFLOW_RESERVE; 1058 if ((u1*)self->interpSave.curFrame <= newStackEnd) { 1059 LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)", 1060 self->interpStackEnd, self->interpSave.curFrame); 1061 dvmDumpThread(self, false); 1062 dvmAbort(); 1063 } 1064 1065 self->interpStackEnd = newStackEnd; 1066 self->stackOverflowed = false; 1067 1068 LOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd, 1069 self->interpSave.curFrame); 1070 } 1071 1072 1073 /* 1074 * Extract the object that is the target of a monitor-enter instruction 1075 * in the top stack frame of "thread". 1076 * 1077 * The other thread might be alive, so this has to work carefully. 1078 * 1079 * The thread list lock must be held. 1080 * 1081 * Returns "true" if we successfully recover the object. "*pOwner" will 1082 * be NULL if we can't determine the owner for some reason (e.g. race 1083 * condition on ownership transfer). 1084 */ 1085 static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj, 1086 Thread** pOwner) 1087 { 1088 void* framePtr = thread->interpSave.curFrame; 1089 1090 if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr)) 1091 return false; 1092 1093 const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr); 1094 const Method* method = saveArea->method; 1095 const u2* currentPc = saveArea->xtra.currentPc; 1096 1097 /* check Method* */ 1098 if (!dvmLinearAllocContains(method, sizeof(Method))) { 1099 LOGD("ExtrMon: method %p not valid", method); 1100 return false; 1101 } 1102 1103 /* check currentPc */ 1104 u4 insnsSize = dvmGetMethodInsnsSize(method); 1105 if (currentPc < method->insns || 1106 currentPc >= method->insns + insnsSize) 1107 { 1108 LOGD("ExtrMon: insns %p not valid (%p - %p)", 1109 currentPc, method->insns, method->insns + insnsSize); 1110 return false; 1111 } 1112 1113 /* check the instruction */ 1114 if ((*currentPc & 0xff) != OP_MONITOR_ENTER) { 1115 LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)", 1116 currentPc, *currentPc & 0xff); 1117 return false; 1118 } 1119 1120 /* get and check the register index */ 1121 unsigned int reg = *currentPc >> 8; 1122 if (reg >= method->registersSize) { 1123 LOGD("ExtrMon: invalid register %d (max %d)", 1124 reg, method->registersSize); 1125 return false; 1126 } 1127 1128 /* get and check the object in that register */ 1129 u4* fp = (u4*) framePtr; 1130 Object* obj = (Object*) fp[reg]; 1131 if (obj != NULL && !dvmIsHeapAddress(obj)) { 1132 LOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg); 1133 return false; 1134 } 1135 *pLockObj = obj; 1136 1137 /* 1138 * Try to determine the object's lock holder; it's okay if this fails. 1139 * 1140 * We're assuming the thread list lock is already held by this thread. 1141 * If it's not, we may be living dangerously if we have to scan through 1142 * the thread list to find a match. (The VM will generally be in a 1143 * suspended state when executing here, so this is a minor concern 1144 * unless we're dumping while threads are running, in which case there's 1145 * a good chance of stuff blowing up anyway.) 1146 */ 1147 *pOwner = dvmGetObjectLockHolder(obj); 1148 1149 return true; 1150 } 1151 1152 static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj, 1153 Thread* thread) 1154 { 1155 std::string msg(StringPrintf(" - waiting %s <%p> ", detail, obj)); 1156 1157 if (obj->clazz != gDvm.classJavaLangClass) { 1158 // I(16573) - waiting on <0xf5feda38> (a java.util.LinkedList) 1159 // I(16573) - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>) 1160 msg += "(a " + dvmHumanReadableType(obj) + ")"; 1161 } 1162 1163 if (thread != NULL) { 1164 std::string threadName(dvmGetThreadName(thread)); 1165 StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str()); 1166 } 1167 1168 dvmPrintDebugMessage(target, "%s\n", msg.c_str()); 1169 } 1170 1171 /* 1172 * Dump stack frames, starting from the specified frame and moving down. 1173 * 1174 * Each frame holds a pointer to the currently executing method, and the 1175 * saved program counter from the caller ("previous" frame). This means 1176 * we don't have the PC for the current method on the stack, which is 1177 * pretty reasonable since it's in the "PC register" for the VM. Because 1178 * exceptions need to show the correct line number we actually *do* have 1179 * an updated version in the fame's "xtra.currentPc", but it's unreliable. 1180 * 1181 * Note "framePtr" could be NULL in rare circumstances. 1182 */ 1183 static void dumpFrames(const DebugOutputTarget* target, void* framePtr, 1184 Thread* thread) 1185 { 1186 const StackSaveArea* saveArea; 1187 const Method* method; 1188 int checkCount = 0; 1189 const u2* currentPc = NULL; 1190 bool first = true; 1191 1192 /* 1193 * We call functions that require us to be holding the thread list lock. 1194 * It's probable that the caller has already done so, but it's not 1195 * guaranteed. If it's not locked, lock it now. 1196 */ 1197 bool needThreadUnlock = dvmTryLockThreadList(); 1198 1199 /* 1200 * The "currentPc" is updated whenever we execute an instruction that 1201 * might throw an exception. Show it here. 1202 */ 1203 if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) { 1204 saveArea = SAVEAREA_FROM_FP(framePtr); 1205 1206 if (saveArea->xtra.currentPc != NULL) 1207 currentPc = saveArea->xtra.currentPc; 1208 } 1209 1210 while (framePtr != NULL) { 1211 saveArea = SAVEAREA_FROM_FP(framePtr); 1212 method = saveArea->method; 1213 1214 if (dvmIsBreakFrame((u4*)framePtr)) { 1215 //dvmPrintDebugMessage(target, " (break frame)\n"); 1216 } else { 1217 int relPc; 1218 1219 if (currentPc != NULL) 1220 relPc = currentPc - saveArea->method->insns; 1221 else 1222 relPc = -1; 1223 1224 std::string methodName(dvmHumanReadableMethod(method, false)); 1225 if (dvmIsNativeMethod(method)) { 1226 dvmPrintDebugMessage(target, " at %s(Native Method)\n", 1227 methodName.c_str()); 1228 } else { 1229 dvmPrintDebugMessage(target, " at %s(%s:%s%d)\n", 1230 methodName.c_str(), dvmGetMethodSourceFile(method), 1231 (relPc >= 0 && first) ? "~" : "", 1232 relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc)); 1233 } 1234 1235 if (first) { 1236 /* 1237 * Decorate WAIT and MONITOR threads with some detail on 1238 * the first frame. 1239 * 1240 * warning: wait status not stable, even in suspend 1241 */ 1242 if (thread->status == THREAD_WAIT || 1243 thread->status == THREAD_TIMED_WAIT) 1244 { 1245 Monitor* mon = thread->waitMonitor; 1246 Object* obj = dvmGetMonitorObject(mon); 1247 if (obj != NULL) { 1248 Thread* joinThread = NULL; 1249 if (obj->clazz == gDvm.classJavaLangVMThread) { 1250 joinThread = dvmGetThreadFromThreadObject(obj); 1251 } 1252 printWaitMessage(target, "on", obj, joinThread); 1253 } 1254 } else if (thread->status == THREAD_MONITOR) { 1255 Object* obj; 1256 Thread* owner; 1257 if (extractMonitorEnterObject(thread, &obj, &owner)) { 1258 printWaitMessage(target, "to lock", obj, owner); 1259 } 1260 } 1261 } 1262 } 1263 1264 /* 1265 * Get saved PC for previous frame. There's no savedPc in a "break" 1266 * frame, because that represents native or interpreted code 1267 * invoked by the VM. The saved PC is sitting in the "PC register", 1268 * a local variable on the native stack. 1269 */ 1270 currentPc = saveArea->savedPc; 1271 1272 first = false; 1273 1274 if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) { 1275 LOGW("Warning: loop in stack trace at frame %d (%p -> %p)", 1276 checkCount, framePtr, saveArea->prevFrame); 1277 break; 1278 } 1279 framePtr = saveArea->prevFrame; 1280 1281 checkCount++; 1282 if (checkCount > 300) { 1283 dvmPrintDebugMessage(target, 1284 " ***** printed %d frames, not showing any more\n", 1285 checkCount); 1286 break; 1287 } 1288 } 1289 dvmPrintDebugMessage(target, "\n"); 1290 1291 if (needThreadUnlock) { 1292 dvmUnlockThreadList(); 1293 } 1294 } 1295 1296 1297 /* 1298 * Dump the stack for the specified thread. 1299 */ 1300 void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread) 1301 { 1302 dumpFrames(target, thread->interpSave.curFrame, thread); 1303 } 1304 1305 /* 1306 * Dump the stack for the specified thread, which is still running. 1307 * 1308 * This is very dangerous, because stack frames are being pushed on and 1309 * popped off, and if the thread exits we'll be looking at freed memory. 1310 * The plan here is to take a snapshot of the stack and then dump that 1311 * to try to minimize the chances of catching it mid-update. This should 1312 * work reasonably well on a single-CPU system. 1313 * 1314 * There is a small chance that calling here will crash the VM. 1315 */ 1316 void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread) 1317 { 1318 StackSaveArea* saveArea; 1319 const u1* origStack; 1320 u1* stackCopy = NULL; 1321 int origSize, fpOffset; 1322 void* fp; 1323 int depthLimit = 200; 1324 1325 if (thread == NULL || thread->interpSave.curFrame == NULL) { 1326 dvmPrintDebugMessage(target, 1327 "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n", 1328 thread, (thread != NULL) ? thread->threadId : 0); 1329 return; 1330 } 1331 1332 /* wait for a full quantum */ 1333 sched_yield(); 1334 1335 /* copy the info we need, then the stack itself */ 1336 origSize = thread->interpStackSize; 1337 origStack = (const u1*) thread->interpStackStart - origSize; 1338 stackCopy = (u1*) malloc(origSize); 1339 fpOffset = (u1*) thread->interpSave.curFrame - origStack; 1340 memcpy(stackCopy, origStack, origSize); 1341 1342 /* 1343 * Run through the stack and rewrite the "prev" pointers. 1344 */ 1345 //LOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack, 1346 // thread->interpSave.curFrame); 1347 fp = stackCopy + fpOffset; 1348 while (true) { 1349 int prevOffset; 1350 1351 if (depthLimit-- < 0) { 1352 /* we're probably screwed */ 1353 dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n"); 1354 dvmAbort(); 1355 } 1356 saveArea = SAVEAREA_FROM_FP(fp); 1357 if (saveArea->prevFrame == NULL) 1358 break; 1359 1360 prevOffset = (u1*) saveArea->prevFrame - origStack; 1361 if (prevOffset < 0 || prevOffset > origSize) { 1362 dvmPrintDebugMessage(target, 1363 "DumpRunning: bad offset found: %d (from %p %p)\n", 1364 prevOffset, origStack, saveArea->prevFrame); 1365 saveArea->prevFrame = NULL; 1366 break; 1367 } 1368 1369 saveArea->prevFrame = (u4*)(stackCopy + prevOffset); 1370 fp = saveArea->prevFrame; 1371 } 1372 1373 /* 1374 * We still need to pass the Thread for some monitor wait stuff. 1375 */ 1376 dumpFrames(target, stackCopy + fpOffset, thread); 1377 free(stackCopy); 1378 } 1379