OSDN Git Service

am 486ac3c0: Removing inaccurate and unmaintained docs.
[android-x86/dalvik.git] / vm / native / dalvik_system_VMDebug.c
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  * dalvik.system.VMDebug
19  */
20 #include "Dalvik.h"
21 #include "native/InternalNativePriv.h"
22 #include "hprof/Hprof.h"
23
24 #include <string.h>
25 #include <unistd.h>
26 #include <errno.h>
27
28
29 /*
30  * Extracts the fd from a FileDescriptor object.
31  *
32  * If an error is encountered, or the extracted descriptor is numerically
33  * invalid, this returns -1 with an exception raised.
34  */
35 static int getFileDescriptor(Object* obj)
36 {
37     assert(obj != NULL);
38     assert(strcmp(obj->clazz->descriptor, "Ljava/io/FileDescriptor;") == 0);
39
40     InstField* field = dvmFindInstanceField(obj->clazz, "descriptor", "I");
41     if (field == NULL) {
42         dvmThrowException("Ljava/lang/NoSuchFieldException;",
43             "No FileDescriptor.descriptor field");
44         return -1;
45     }
46
47     int fd = dvmGetFieldInt(obj, field->byteOffset);
48     if (fd < 0) {
49         dvmThrowExceptionFmt("Ljava/lang/RuntimeException;",
50             "Invalid file descriptor");
51         return -1;
52     }
53
54     return fd;
55 }
56
57 /*
58  * Convert an array of char* into a String[].
59  *
60  * Returns NULL on failure, with an exception raised.
61  */
62 static ArrayObject* convertStringArray(char** strings, size_t count)
63 {
64     Thread* self = dvmThreadSelf();
65
66     /*
67      * Allocate an array to hold the String objects.
68      */
69     ClassObject* stringArrayClass =
70         dvmFindArrayClass("[Ljava/lang/String;", NULL);
71     if (stringArrayClass == NULL) {
72         /* shouldn't happen */
73         LOGE("Unable to find [Ljava/lang/String;\n");
74         dvmAbort();
75     }
76
77     ArrayObject* stringArray =
78         dvmAllocArrayByClass(stringArrayClass, count, ALLOC_DEFAULT);
79     if (stringArray == NULL) {
80         /* probably OOM */
81         LOGD("Failed allocating array of %d strings\n", count);
82         assert(dvmCheckException(self));
83         return NULL;
84     }
85
86     /*
87      * Create the individual String objects and add them to the array.
88      */
89     size_t i;
90     for (i = 0; i < count; i++) {
91         Object *str =
92             (Object *)dvmCreateStringFromCstr(strings[i]);
93         if (str == NULL) {
94             /* probably OOM; drop out now */
95             assert(dvmCheckException(self));
96             dvmReleaseTrackedAlloc((Object*)stringArray, self);
97             return NULL;
98         }
99         dvmSetObjectArrayElement(stringArray, i, str);
100         /* stored in tracked array, okay to release */
101         dvmReleaseTrackedAlloc(str, self);
102     }
103
104     dvmReleaseTrackedAlloc((Object*)stringArray, self);
105     return stringArray;
106 }
107
108 /*
109  * static String[] getVmFeatureList()
110  *
111  * Return a set of strings describing available VM features (this is chiefly
112  * of interest to DDMS).  Some features may be controlled by compile-time
113  * or command-line flags.
114  */
115 static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args,
116     JValue* pResult)
117 {
118     static const int MAX_FEATURE_COUNT = 10;
119     char* features[MAX_FEATURE_COUNT];
120     int idx = 0;
121
122     /* VM responds to DDMS method profiling requests */
123     features[idx++] = "method-trace-profiling";
124     features[idx++] = "method-trace-profiling-streaming";
125     /* VM responds to DDMS heap dump requests */
126     features[idx++] = "hprof-heap-dump";
127     features[idx++] = "hprof-heap-dump-streaming";
128
129     assert(idx <= MAX_FEATURE_COUNT);
130
131     LOGV("+++ sending up %d features\n", idx);
132     ArrayObject* arrayObj = convertStringArray(features, idx);
133     RETURN_PTR(arrayObj);       /* will be null on OOM */
134 }
135
136
137 /* These must match the values in dalvik.system.VMDebug.
138  */
139 enum {
140     KIND_ALLOCATED_OBJECTS      = 1<<0,
141     KIND_ALLOCATED_BYTES        = 1<<1,
142     KIND_FREED_OBJECTS          = 1<<2,
143     KIND_FREED_BYTES            = 1<<3,
144     KIND_GC_INVOCATIONS         = 1<<4,
145     KIND_CLASS_INIT_COUNT       = 1<<5,
146     KIND_CLASS_INIT_TIME        = 1<<6,
147
148     /* These values exist for backward compatibility. */
149     KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
150     KIND_EXT_ALLOCATED_BYTES   = 1<<13,
151     KIND_EXT_FREED_OBJECTS     = 1<<14,
152     KIND_EXT_FREED_BYTES       = 1<<15,
153
154     KIND_GLOBAL_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS,
155     KIND_GLOBAL_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES,
156     KIND_GLOBAL_FREED_OBJECTS       = KIND_FREED_OBJECTS,
157     KIND_GLOBAL_FREED_BYTES         = KIND_FREED_BYTES,
158     KIND_GLOBAL_GC_INVOCATIONS      = KIND_GC_INVOCATIONS,
159     KIND_GLOBAL_CLASS_INIT_COUNT    = KIND_CLASS_INIT_COUNT,
160     KIND_GLOBAL_CLASS_INIT_TIME     = KIND_CLASS_INIT_TIME,
161
162     KIND_THREAD_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS << 16,
163     KIND_THREAD_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES << 16,
164     KIND_THREAD_FREED_OBJECTS       = KIND_FREED_OBJECTS << 16,
165     KIND_THREAD_FREED_BYTES         = KIND_FREED_BYTES << 16,
166
167     KIND_THREAD_GC_INVOCATIONS      = KIND_GC_INVOCATIONS << 16,
168
169     // TODO: failedAllocCount, failedAllocSize
170 };
171
172 #define KIND_ALL_COUNTS 0xffffffff
173
174 /*
175  * Zero out the specified fields.
176  */
177 static void clearAllocProfStateFields(AllocProfState *allocProf,
178     unsigned int kinds)
179 {
180     if (kinds & KIND_ALLOCATED_OBJECTS) {
181         allocProf->allocCount = 0;
182     }
183     if (kinds & KIND_ALLOCATED_BYTES) {
184         allocProf->allocSize = 0;
185     }
186     if (kinds & KIND_FREED_OBJECTS) {
187         allocProf->freeCount = 0;
188     }
189     if (kinds & KIND_FREED_BYTES) {
190         allocProf->freeSize = 0;
191     }
192     if (kinds & KIND_GC_INVOCATIONS) {
193         allocProf->gcCount = 0;
194     }
195     if (kinds & KIND_CLASS_INIT_COUNT) {
196         allocProf->classInitCount = 0;
197     }
198     if (kinds & KIND_CLASS_INIT_TIME) {
199         allocProf->classInitTime = 0;
200     }
201 }
202
203 /*
204  * static void startAllocCounting()
205  *
206  * Reset the counters and enable counting.
207  *
208  * TODO: this currently only resets the per-thread counters for the current
209  * thread.  If we actually start using the per-thread counters we'll
210  * probably want to fix this.
211  */
212 static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
213     JValue* pResult)
214 {
215     UNUSED_PARAMETER(args);
216
217     clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
218     clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
219     dvmStartAllocCounting();
220     RETURN_VOID();
221 }
222
223 /*
224  * public static void stopAllocCounting()
225  */
226 static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
227     JValue* pResult)
228 {
229     UNUSED_PARAMETER(args);
230
231     dvmStopAllocCounting();
232     RETURN_VOID();
233 }
234
235 /*
236  * private static int getAllocCount(int kind)
237  */
238 static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
239     JValue* pResult)
240 {
241     AllocProfState *allocProf;
242     unsigned int kind = args[0];
243     if (kind < (1<<16)) {
244         allocProf = &gDvm.allocProf;
245     } else {
246         allocProf = &dvmThreadSelf()->allocProf;
247         kind >>= 16;
248     }
249     switch (kind) {
250     case KIND_ALLOCATED_OBJECTS:
251         pResult->i = allocProf->allocCount;
252         break;
253     case KIND_ALLOCATED_BYTES:
254         pResult->i = allocProf->allocSize;
255         break;
256     case KIND_FREED_OBJECTS:
257         pResult->i = allocProf->freeCount;
258         break;
259     case KIND_FREED_BYTES:
260         pResult->i = allocProf->freeSize;
261         break;
262     case KIND_GC_INVOCATIONS:
263         pResult->i = allocProf->gcCount;
264         break;
265     case KIND_CLASS_INIT_COUNT:
266         pResult->i = allocProf->classInitCount;
267         break;
268     case KIND_CLASS_INIT_TIME:
269         /* convert nsec to usec, reduce to 32 bits */
270         pResult->i = (int) (allocProf->classInitTime / 1000);
271         break;
272     case KIND_EXT_ALLOCATED_OBJECTS:
273     case KIND_EXT_ALLOCATED_BYTES:
274     case KIND_EXT_FREED_OBJECTS:
275     case KIND_EXT_FREED_BYTES:
276         pResult->i = 0;  /* backward compatibility */
277         break;
278     default:
279         assert(false);
280         pResult->i = -1;
281     }
282 }
283
284 /*
285  * public static void resetAllocCount(int kinds)
286  */
287 static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
288     JValue* pResult)
289 {
290     unsigned int kinds = args[0];
291     clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
292     clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
293     RETURN_VOID();
294 }
295
296 /*
297  * static void startMethodTracingNative(String traceFileName,
298  *     FileDescriptor fd, int bufferSize, int flags)
299  *
300  * Start method trace profiling.
301  *
302  * If both "traceFileName" and "fd" are null, the result will be sent
303  * directly to DDMS.  (The non-DDMS versions of the calls are expected
304  * to enforce non-NULL filenames.)
305  */
306 static void Dalvik_dalvik_system_VMDebug_startMethodTracingNative(const u4* args,
307     JValue* pResult)
308 {
309     StringObject* traceFileStr = (StringObject*) args[0];
310     Object* traceFd = (Object*) args[1];
311     int bufferSize = args[2];
312     int flags = args[3];
313
314     if (bufferSize == 0) {
315         // Default to 8MB per the documentation.
316         bufferSize = 8 * 1024 * 1024;
317     }
318
319     if (bufferSize < 1024) {
320         dvmThrowException("Ljava/lang/IllegalArgumentException;", NULL);
321         RETURN_VOID();
322     }
323
324     char* traceFileName = NULL;
325     if (traceFileStr != NULL)
326         traceFileName = dvmCreateCstrFromString(traceFileStr);
327
328     int fd = -1;
329     if (traceFd != NULL) {
330         int origFd = getFileDescriptor(traceFd);
331         if (origFd < 0)
332             RETURN_VOID();
333
334         fd = dup(origFd);
335         if (fd < 0) {
336             dvmThrowExceptionFmt("Ljava/lang/RuntimeException;",
337                 "dup(%d) failed: %s", origFd, strerror(errno));
338             RETURN_VOID();
339         }
340     }
341
342     dvmMethodTraceStart(traceFileName != NULL ? traceFileName : "[DDMS]",
343         fd, bufferSize, flags, (traceFileName == NULL && fd == -1));
344     free(traceFileName);
345     RETURN_VOID();
346 }
347
348 /*
349  * static boolean isMethodTracingActive()
350  *
351  * Determine whether method tracing is currently active.
352  */
353 static void Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4* args,
354     JValue* pResult)
355 {
356     UNUSED_PARAMETER(args);
357
358     RETURN_BOOLEAN(dvmIsMethodTraceActive());
359 }
360
361 /*
362  * static void stopMethodTracing()
363  *
364  * Stop method tracing.
365  */
366 static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
367     JValue* pResult)
368 {
369     UNUSED_PARAMETER(args);
370
371     dvmMethodTraceStop();
372     RETURN_VOID();
373 }
374
375 /*
376  * static void startEmulatorTracing()
377  *
378  * Start sending method trace info to the emulator.
379  */
380 static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
381     JValue* pResult)
382 {
383     UNUSED_PARAMETER(args);
384
385     dvmEmulatorTraceStart();
386     RETURN_VOID();
387 }
388
389 /*
390  * static void stopEmulatorTracing()
391  *
392  * Start sending method trace info to the emulator.
393  */
394 static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
395     JValue* pResult)
396 {
397     UNUSED_PARAMETER(args);
398
399     dvmEmulatorTraceStop();
400     RETURN_VOID();
401 }
402
403 /*
404  * static boolean isDebuggerConnected()
405  *
406  * Returns "true" if a debugger is attached.
407  */
408 static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
409     JValue* pResult)
410 {
411     UNUSED_PARAMETER(args);
412
413     RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
414 }
415
416 /*
417  * static boolean isDebuggingEnabled()
418  *
419  * Returns "true" if debugging is enabled.
420  */
421 static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
422     JValue* pResult)
423 {
424     UNUSED_PARAMETER(args);
425
426     RETURN_BOOLEAN(gDvm.jdwpConfigured);
427 }
428
429 /*
430  * static long lastDebuggerActivity()
431  *
432  * Returns the time, in msec, since we last had an interaction with the
433  * debugger (send or receive).
434  */
435 static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
436     JValue* pResult)
437 {
438     UNUSED_PARAMETER(args);
439
440     RETURN_LONG(dvmDbgLastDebuggerActivity());
441 }
442
443 /*
444  * static void startInstructionCounting()
445  */
446 static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
447     JValue* pResult)
448 {
449     dvmStartInstructionCounting();
450     RETURN_VOID();
451 }
452
453 /*
454  * static void stopInstructionCounting()
455  */
456 static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
457     JValue* pResult)
458 {
459     dvmStopInstructionCounting();
460     RETURN_VOID();
461 }
462
463 /*
464  * static boolean getInstructionCount(int[] counts)
465  *
466  * Grab a copy of the global instruction count array.
467  *
468  * Since the instruction counts aren't synchronized, we use sched_yield
469  * to improve our chances of finishing without contention.  (Only makes
470  * sense on a uniprocessor.)
471  */
472 static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
473     JValue* pResult)
474 {
475     ArrayObject* countArray = (ArrayObject*) args[0];
476
477     if (countArray != NULL) {
478         int* storage = (int*) countArray->contents;
479         u4 length = countArray->length;
480
481         /*
482          * Ensure that we copy at most kNumPackedOpcodes
483          * elements, but no more than the length of the given array.
484          */
485         if (length > kNumPackedOpcodes) {
486             length = kNumPackedOpcodes;
487         }
488
489         sched_yield();
490         memcpy(storage, gDvm.executedInstrCounts, length * sizeof(int));
491     }
492
493     RETURN_VOID();
494 }
495
496 /*
497  * static boolean resetInstructionCount()
498  *
499  * Reset the instruction count array.
500  */
501 static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
502     JValue* pResult)
503 {
504     sched_yield();
505     memset(gDvm.executedInstrCounts, 0, kNumPackedOpcodes * sizeof(int));
506     RETURN_VOID();
507 }
508
509 /*
510  * static void printLoadedClasses(int flags)
511  *
512  * Dump the list of loaded classes.
513  */
514 static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
515     JValue* pResult)
516 {
517     int flags = args[0];
518
519     dvmDumpAllClasses(flags);
520
521     RETURN_VOID();
522 }
523
524 /*
525  * static int getLoadedClassCount()
526  *
527  * Return the number of loaded classes
528  */
529 static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
530     JValue* pResult)
531 {
532     int count;
533
534     UNUSED_PARAMETER(args);
535
536     count = dvmGetNumLoadedClasses();
537
538     RETURN_INT(count);
539 }
540
541 /*
542  * Returns the thread-specific CPU-time clock value for the current thread,
543  * or -1 if the feature isn't supported.
544  */
545 static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
546     JValue* pResult)
547 {
548     jlong result;
549
550 #ifdef HAVE_POSIX_CLOCKS
551     struct timespec now;
552     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
553     result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
554 #else
555     result = (jlong) -1;
556 #endif
557
558     RETURN_LONG(result);
559 }
560
561 /*
562  * static void dumpHprofData(String fileName, FileDescriptor fd)
563  *
564  * Cause "hprof" data to be dumped.  We can throw an IOException if an
565  * error occurs during file handling.
566  */
567 static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
568     JValue* pResult)
569 {
570     StringObject* fileNameStr = (StringObject*) args[0];
571     Object* fileDescriptor = (Object*) args[1];
572     char* fileName;
573     int result;
574
575     /*
576      * Only one of these may be NULL.
577      */
578     if (fileNameStr == NULL && fileDescriptor == NULL) {
579         dvmThrowException("Ljava/lang/NullPointerException;", NULL);
580         RETURN_VOID();
581     }
582
583     if (fileNameStr != NULL) {
584         fileName = dvmCreateCstrFromString(fileNameStr);
585         if (fileName == NULL) {
586             /* unexpected -- malloc failure? */
587             dvmThrowException("Ljava/lang/RuntimeException;", "malloc failure?");
588             RETURN_VOID();
589         }
590     } else {
591         fileName = strdup("[fd]");
592     }
593
594     int fd = -1;
595     if (fileDescriptor != NULL) {
596         fd = getFileDescriptor(fileDescriptor);
597         if (fd < 0) {
598             free(fileName);
599             RETURN_VOID();
600         }
601     }
602
603     result = hprofDumpHeap(fileName, fd, false);
604     free(fileName);
605
606     if (result != 0) {
607         /* ideally we'd throw something more specific based on actual failure */
608         dvmThrowException("Ljava/lang/RuntimeException;",
609             "Failure during heap dump -- check log output for details");
610         RETURN_VOID();
611     }
612
613     RETURN_VOID();
614 }
615
616 /*
617  * static void dumpHprofDataDdms()
618  *
619  * Cause "hprof" data to be computed and sent directly to DDMS.
620  */
621 static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
622     JValue* pResult)
623 {
624     int result;
625
626     result = hprofDumpHeap("[DDMS]", -1, true);
627
628     if (result != 0) {
629         /* ideally we'd throw something more specific based on actual failure */
630         dvmThrowException("Ljava/lang/RuntimeException;",
631             "Failure during heap dump -- check log output for details");
632         RETURN_VOID();
633     }
634
635     RETURN_VOID();
636 }
637
638 /*
639  * static boolean cacheRegisterMap(String classAndMethodDescr)
640  *
641  * If the specified class is loaded, and the named method exists, ensure
642  * that the method's register map is ready for use.  If the class/method
643  * cannot be found, nothing happens.
644  *
645  * This can improve the zygote's sharing of compressed register maps.  Do
646  * this after class preloading.
647  *
648  * Returns true if the register map is cached and ready, either as a result
649  * of this call or earlier activity.  Returns false if the class isn't loaded,
650  * if the method couldn't be found, or if the method has no register map.
651  *
652  * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
653  */
654 static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
655     JValue* pResult)
656 {
657     StringObject* classAndMethodDescStr = (StringObject*) args[0];
658     ClassObject* clazz;
659     bool result = false;
660
661     if (classAndMethodDescStr == NULL) {
662         dvmThrowException("Ljava/lang/NullPointerException;", NULL);
663         RETURN_VOID();
664     }
665
666     char* classAndMethodDesc = NULL;
667
668     /*
669      * Pick the string apart.  We have a local copy, so just modify it
670      * in place.
671      */
672     classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
673
674     char* methodName = strchr(classAndMethodDesc, '.');
675     if (methodName == NULL) {
676         dvmThrowException("Ljava/lang/RuntimeException;",
677             "method name not found in string");
678         RETURN_VOID();
679     }
680     *methodName++ = '\0';
681
682     char* methodDescr = strchr(methodName, ':');
683     if (methodDescr == NULL) {
684         dvmThrowException("Ljava/lang/RuntimeException;",
685             "method descriptor not found in string");
686         RETURN_VOID();
687     }
688     *methodDescr++ = '\0';
689
690     //LOGD("GOT: %s %s %s\n", classAndMethodDesc, methodName, methodDescr);
691
692     /*
693      * Find the class, but only if it's already loaded.
694      */
695     clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
696     if (clazz == NULL) {
697         LOGD("Class %s not found in bootstrap loader\n", classAndMethodDesc);
698         goto bail;
699     }
700
701     Method* method;
702
703     /*
704      * Find the method, which could be virtual or direct, defined directly
705      * or inherited.
706      */
707     if (methodName[0] == '<') {
708         /*
709          * Constructor or class initializer.  Only need to examine the
710          * "direct" list, and don't need to search up the class hierarchy.
711          */
712         method = dvmFindDirectMethodByDescriptor(clazz, methodName,
713                     methodDescr);
714     } else {
715         /*
716          * Try both lists, and scan up the tree.
717          */
718         method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
719                     methodDescr);
720         if (method == NULL) {
721             method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
722                         methodDescr);
723         }
724     }
725
726     if (method != NULL) {
727         /*
728          * Got it.  See if there's a register map here.
729          */
730         const RegisterMap* pMap;
731         pMap = dvmGetExpandedRegisterMap(method);
732         if (pMap == NULL) {
733             LOGV("No map for %s.%s %s\n",
734                 classAndMethodDesc, methodName, methodDescr);
735         } else {
736             LOGV("Found map %s.%s %s\n",
737                 classAndMethodDesc, methodName, methodDescr);
738             result = true;
739         }
740     } else {
741         LOGV("Unable to find %s.%s %s\n",
742             classAndMethodDesc, methodName, methodDescr);
743     }
744
745 bail:
746     free(classAndMethodDesc);
747     RETURN_BOOLEAN(result);
748 }
749
750 /*
751  * static void dumpReferenceTables()
752  */
753 static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
754     JValue* pResult)
755 {
756     UNUSED_PARAMETER(args);
757     UNUSED_PARAMETER(pResult);
758
759     LOGI("--- reference table dump ---\n");
760     dvmDumpJniReferenceTables();
761     // could dump thread's internalLocalRefTable, probably not useful
762     // ditto for thread's jniMonitorRefTable
763     LOGI("---\n");
764     RETURN_VOID();
765 }
766
767 /*
768  * static void crash()
769  *
770  * Dump the current thread's interpreted stack and abort the VM.  Useful
771  * for seeing both interpreted and native stack traces.
772  *
773  * (Might want to restrict this to debuggable processes as a security
774  * measure, or check SecurityManager.checkExit().)
775  */
776 static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
777     JValue* pResult)
778 {
779     UNUSED_PARAMETER(args);
780     UNUSED_PARAMETER(pResult);
781
782     LOGW("Crashing VM on request\n");
783     dvmDumpThread(dvmThreadSelf(), false);
784     dvmAbort();
785 }
786
787 /*
788  * static void infopoint(int id)
789  *
790  * Provide a hook for gdb to hang to so that the VM can be stopped when
791  * user-tagged source locations are being executed.
792  */
793 static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
794     JValue* pResult)
795 {
796     gDvm.nativeDebuggerActive = true;
797
798     LOGD("VMDebug infopoint %d hit", args[0]);
799
800     gDvm.nativeDebuggerActive = false;
801     RETURN_VOID();
802 }
803
804 static void Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4* args,
805     JValue* pResult)
806 {
807     ClassObject* clazz = (ClassObject*)args[0];
808     bool countAssignable = args[1];
809     if (clazz == NULL) {
810         RETURN_LONG(0);
811     }
812     if (countAssignable) {
813         size_t count = dvmCountAssignableInstancesOfClass(clazz);
814         RETURN_LONG((long long)count);
815     } else {
816         size_t count = dvmCountInstancesOfClass(clazz);
817         RETURN_LONG((long long)count);
818     }
819 }
820
821 const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
822     { "getVmFeatureList",           "()[Ljava/lang/String;",
823         Dalvik_dalvik_system_VMDebug_getVmFeatureList },
824     { "getAllocCount",              "(I)I",
825         Dalvik_dalvik_system_VMDebug_getAllocCount },
826     { "resetAllocCount",            "(I)V",
827         Dalvik_dalvik_system_VMDebug_resetAllocCount },
828     { "startAllocCounting",         "()V",
829         Dalvik_dalvik_system_VMDebug_startAllocCounting },
830     { "stopAllocCounting",          "()V",
831         Dalvik_dalvik_system_VMDebug_stopAllocCounting },
832     { "startMethodTracingNative",   "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
833         Dalvik_dalvik_system_VMDebug_startMethodTracingNative },
834     { "isMethodTracingActive",      "()Z",
835         Dalvik_dalvik_system_VMDebug_isMethodTracingActive },
836     { "stopMethodTracing",          "()V",
837         Dalvik_dalvik_system_VMDebug_stopMethodTracing },
838     { "startEmulatorTracing",       "()V",
839         Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
840     { "stopEmulatorTracing",        "()V",
841         Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
842     { "startInstructionCounting",   "()V",
843         Dalvik_dalvik_system_VMDebug_startInstructionCounting },
844     { "stopInstructionCounting",    "()V",
845         Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
846     { "resetInstructionCount",      "()V",
847         Dalvik_dalvik_system_VMDebug_resetInstructionCount },
848     { "getInstructionCount",        "([I)V",
849         Dalvik_dalvik_system_VMDebug_getInstructionCount },
850     { "isDebuggerConnected",        "()Z",
851         Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
852     { "isDebuggingEnabled",         "()Z",
853         Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
854     { "lastDebuggerActivity",       "()J",
855         Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
856     { "printLoadedClasses",         "(I)V",
857         Dalvik_dalvik_system_VMDebug_printLoadedClasses },
858     { "getLoadedClassCount",        "()I",
859         Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
860     { "threadCpuTimeNanos",         "()J",
861         Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
862     { "dumpHprofData",              "(Ljava/lang/String;Ljava/io/FileDescriptor;)V",
863         Dalvik_dalvik_system_VMDebug_dumpHprofData },
864     { "dumpHprofDataDdms",          "()V",
865         Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
866     { "cacheRegisterMap",           "(Ljava/lang/String;)Z",
867         Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
868     { "dumpReferenceTables",        "()V",
869         Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
870     { "crash",                      "()V",
871         Dalvik_dalvik_system_VMDebug_crash },
872     { "infopoint",                 "(I)V",
873         Dalvik_dalvik_system_VMDebug_infopoint },
874     { "countInstancesOfClass",     "(Ljava/lang/Class;Z)J",
875         Dalvik_dalvik_system_VMDebug_countInstancesOfClass },
876     { NULL, NULL, NULL },
877 };