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