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 */
getFileDescriptor(Object * obj)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 */
Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4 * args,JValue * pResult)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 */
clearAllocProfStateFields(AllocProfState * allocProf,unsigned int kinds)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 */
Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_getAllocCount(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_startMethodTracingNative(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4 * args,JValue * pResult)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 //ALOGD("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 ALOGD("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 ALOGV("No map for %s.%s %s",
661 classAndMethodDesc, methodName, methodDescr);
662 } else {
663 ALOGV("Found map %s.%s %s",
664 classAndMethodDesc, methodName, methodDescr);
665 result = true;
666 }
667 } else {
668 ALOGV("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 */
Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4 * args,JValue * pResult)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 ALOGI("--- reference table dump ---");
687 dvmDumpJniReferenceTables();
688 // could dump thread's internalLocalRefTable, probably not useful
689 // ditto for thread's jniMonitorRefTable
690 ALOGI("---");
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 */
Dalvik_dalvik_system_VMDebug_crash(const u4 * args,JValue * pResult)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 ALOGW("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 */
Dalvik_dalvik_system_VMDebug_infopoint(const u4 * args,JValue * pResult)720 static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
721 JValue* pResult)
722 {
723 gDvm.nativeDebuggerActive = true;
724
725 ALOGD("VMDebug infopoint %d hit", args[0]);
726
727 gDvm.nativeDebuggerActive = false;
728 RETURN_VOID();
729 }
730
Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4 * args,JValue * pResult)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