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