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