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