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