| /* |
| * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #ifndef JDWP_UTIL_H |
| #define JDWP_UTIL_H |
| |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| |
| #ifdef DEBUG |
| /* Just to make sure these interfaces are not used here. */ |
| #undef free |
| #define free(p) Do not use this interface. |
| #undef malloc |
| #define malloc(p) Do not use this interface. |
| #undef calloc |
| #define calloc(p) Do not use this interface. |
| #undef realloc |
| #define realloc(p) Do not use this interface. |
| #undef strdup |
| #define strdup(p) Do not use this interface. |
| #endif |
| |
| #include "log_messages.h" |
| #include "vm_interface.h" |
| #include "JDWP.h" |
| #include "util_md.h" |
| #include "error_messages.h" |
| #include "debugInit.h" |
| |
| /* Get access to Native Platform Toolkit functions */ |
| #include "npt.h" |
| |
| /* Definition of a CommonRef tracked by the backend for the frontend */ |
| typedef struct RefNode { |
| jlong seqNum; /* ID of reference, also key for hash table */ |
| jobject ref; /* could be strong or weak */ |
| struct RefNode *next; /* next RefNode* in bucket chain */ |
| jint count; /* count of references */ |
| unsigned isStrong : 1; /* 1 means this is a string reference */ |
| } RefNode; |
| |
| /* Value of a NULL ID */ |
| #define NULL_OBJECT_ID ((jlong)0) |
| |
| /* |
| * Globals used throughout the back end |
| */ |
| |
| typedef jint FrameNumber; |
| |
| // ANDROID-CHANGED: support for DDMS extension apis. |
| typedef jvmtiError (*DdmProcessChunk)(jvmtiEnv* jvmti, |
| jint type_in, |
| jint length_in, |
| const jbyte* data_in, |
| jint* type_out, |
| jint* length_out, |
| jbyte** data_out); |
| |
| typedef struct { |
| jvmtiEnv *jvmti; |
| JavaVM *jvm; |
| volatile jboolean vmDead; /* Once VM is dead it stays that way - don't put in init */ |
| jboolean assertOn; |
| jboolean assertFatal; |
| jboolean doerrorexit; |
| jboolean modifiedUtf8; |
| jboolean quiet; |
| |
| /* Debug flags (bit mask) */ |
| int debugflags; |
| |
| /* Possible debug flags */ |
| #define USE_ITERATE_THROUGH_HEAP 0X001 |
| |
| char * options; |
| |
| jclass classClass; |
| jclass threadClass; |
| jclass threadGroupClass; |
| jclass classLoaderClass; |
| jclass stringClass; |
| jclass systemClass; |
| jmethodID threadConstructor; |
| jmethodID threadSetDaemon; |
| jmethodID threadResume; |
| jmethodID systemGetProperty; |
| jmethodID setProperty; |
| jthreadGroup systemThreadGroup; |
| jobject agent_properties; |
| |
| jint cachedJvmtiVersion; |
| jvmtiCapabilities cachedJvmtiCapabilities; |
| jboolean haveCachedJvmtiCapabilities; |
| jvmtiEventCallbacks callbacks; |
| |
| /* Various property values we should grab on initialization */ |
| char* property_java_version; /* UTF8 java.version */ |
| char* property_java_vm_name; /* UTF8 java.vm.name */ |
| char* property_java_vm_info; /* UTF8 java.vm.info */ |
| char* property_java_class_path; /* UTF8 java.class.path */ |
| char* property_sun_boot_class_path; /* UTF8 sun.boot.class.path */ |
| char* property_sun_boot_library_path; /* UTF8 sun.boot.library.path */ |
| char* property_path_separator; /* UTF8 path.separator */ |
| char* property_user_dir; /* UTF8 user.dir */ |
| |
| unsigned log_flags; |
| |
| /* The Native Platform Toolkit access */ |
| NptEnv *npt; |
| |
| /* Common References static data */ |
| jrawMonitorID refLock; |
| jlong nextSeqNum; |
| RefNode **objectsByID; |
| int objectsByIDsize; |
| int objectsByIDcount; |
| |
| /* Indication that the agent has been loaded */ |
| jboolean isLoaded; |
| |
| /* ANDROID-CHANGED: com.android.art.internal.ddm.process_chunk extension function */ |
| DdmProcessChunk ddm_process_chunk; |
| |
| /* ANDROID-CHANGED: Need to keep track of if ddm is initially active. */ |
| jboolean ddmInitiallyActive; |
| |
| } BackendGlobalData; |
| |
| extern BackendGlobalData * gdata; |
| |
| /* |
| * Event Index for handlers |
| */ |
| |
| typedef enum { |
| EI_min = 1, |
| |
| EI_SINGLE_STEP = 1, |
| EI_BREAKPOINT = 2, |
| EI_FRAME_POP = 3, |
| EI_EXCEPTION = 4, |
| EI_THREAD_START = 5, |
| EI_THREAD_END = 6, |
| EI_CLASS_PREPARE = 7, |
| EI_GC_FINISH = 8, |
| EI_CLASS_LOAD = 9, |
| EI_FIELD_ACCESS = 10, |
| EI_FIELD_MODIFICATION = 11, |
| EI_EXCEPTION_CATCH = 12, |
| EI_METHOD_ENTRY = 13, |
| EI_METHOD_EXIT = 14, |
| EI_MONITOR_CONTENDED_ENTER = 15, |
| EI_MONITOR_CONTENDED_ENTERED = 16, |
| EI_MONITOR_WAIT = 17, |
| EI_MONITOR_WAITED = 18, |
| EI_VM_INIT = 19, |
| EI_VM_DEATH = 20, |
| EI_max = 20 |
| } EventIndex; |
| |
| /* Agent errors that might be in a jvmtiError for JDWP or internal. |
| * (Done this way so that compiler allows it's use as a jvmtiError) |
| */ |
| #define _AGENT_ERROR(x) ((jvmtiError)(JVMTI_ERROR_MAX+64+x)) |
| #define AGENT_ERROR_INTERNAL _AGENT_ERROR(1) |
| #define AGENT_ERROR_VM_DEAD _AGENT_ERROR(2) |
| #define AGENT_ERROR_NO_JNI_ENV _AGENT_ERROR(3) |
| #define AGENT_ERROR_JNI_EXCEPTION _AGENT_ERROR(4) |
| #define AGENT_ERROR_JVMTI_INTERNAL _AGENT_ERROR(5) |
| #define AGENT_ERROR_JDWP_INTERNAL _AGENT_ERROR(6) |
| #define AGENT_ERROR_NOT_CURRENT_FRAME _AGENT_ERROR(7) |
| #define AGENT_ERROR_OUT_OF_MEMORY _AGENT_ERROR(8) |
| #define AGENT_ERROR_INVALID_TAG _AGENT_ERROR(9) |
| #define AGENT_ERROR_ALREADY_INVOKING _AGENT_ERROR(10) |
| #define AGENT_ERROR_INVALID_INDEX _AGENT_ERROR(11) |
| #define AGENT_ERROR_INVALID_LENGTH _AGENT_ERROR(12) |
| #define AGENT_ERROR_INVALID_STRING _AGENT_ERROR(13) |
| #define AGENT_ERROR_INVALID_CLASS_LOADER _AGENT_ERROR(14) |
| #define AGENT_ERROR_INVALID_ARRAY _AGENT_ERROR(15) |
| #define AGENT_ERROR_TRANSPORT_LOAD _AGENT_ERROR(16) |
| #define AGENT_ERROR_TRANSPORT_INIT _AGENT_ERROR(17) |
| #define AGENT_ERROR_NATIVE_METHOD _AGENT_ERROR(18) |
| #define AGENT_ERROR_INVALID_COUNT _AGENT_ERROR(19) |
| #define AGENT_ERROR_INVALID_FRAMEID _AGENT_ERROR(20) |
| #define AGENT_ERROR_NULL_POINTER _AGENT_ERROR(21) |
| #define AGENT_ERROR_ILLEGAL_ARGUMENT _AGENT_ERROR(22) |
| #define AGENT_ERROR_INVALID_THREAD _AGENT_ERROR(23) |
| #define AGENT_ERROR_INVALID_EVENT_TYPE _AGENT_ERROR(24) |
| #define AGENT_ERROR_INVALID_OBJECT _AGENT_ERROR(25) |
| #define AGENT_ERROR_NO_MORE_FRAMES _AGENT_ERROR(26) |
| |
| /* Combined event information */ |
| |
| typedef struct { |
| |
| EventIndex ei; |
| jthread thread; |
| jclass clazz; |
| jmethodID method; |
| jlocation location; |
| jobject object; /* possibly an exception or user object */ |
| |
| union { |
| |
| /* ei = EI_FIELD_ACCESS */ |
| struct { |
| jclass field_clazz; |
| jfieldID field; |
| } field_access; |
| |
| /* ei = EI_FIELD_MODIFICATION */ |
| struct { |
| jclass field_clazz; |
| jfieldID field; |
| char signature_type; |
| jvalue new_value; |
| } field_modification; |
| |
| /* ei = EI_EXCEPTION */ |
| struct { |
| jclass catch_clazz; |
| jmethodID catch_method; |
| jlocation catch_location; |
| } exception; |
| |
| /* ei = EI_METHOD_EXIT */ |
| struct { |
| jvalue return_value; |
| } method_exit; |
| |
| /* For monitor wait events */ |
| union { |
| /* ei = EI_MONITOR_WAIT */ |
| jlong timeout; |
| /* ei = EI_MONITOR_WAITED */ |
| jboolean timed_out; |
| } monitor; |
| } u; |
| |
| } EventInfo; |
| |
| /* Structure to hold dynamic array of objects */ |
| typedef struct ObjectBatch { |
| jobject *objects; |
| jint count; |
| } ObjectBatch; |
| |
| /* |
| * JNI signature constants, beyond those defined in JDWP_TAG(*) |
| */ |
| #define SIGNATURE_BEGIN_ARGS '(' |
| #define SIGNATURE_END_ARGS ')' |
| #define SIGNATURE_END_CLASS ';' |
| |
| /* |
| * Modifier flags for classes, fields, methods |
| */ |
| #define MOD_PUBLIC 0x0001 /* visible to everyone */ |
| #define MOD_PRIVATE 0x0002 /* visible only to the defining class */ |
| #define MOD_PROTECTED 0x0004 /* visible to subclasses */ |
| #define MOD_STATIC 0x0008 /* instance variable is static */ |
| #define MOD_FINAL 0x0010 /* no further subclassing, overriding */ |
| #define MOD_SYNCHRONIZED 0x0020 /* wrap method call in monitor lock */ |
| #define MOD_VOLATILE 0x0040 /* can cache in registers */ |
| #define MOD_TRANSIENT 0x0080 /* not persistant */ |
| #define MOD_NATIVE 0x0100 /* implemented in C */ |
| #define MOD_INTERFACE 0x0200 /* class is an interface */ |
| #define MOD_ABSTRACT 0x0400 /* no definition provided */ |
| /* |
| * Additional modifiers not defined as such in the JVM spec |
| */ |
| #define MOD_SYNTHETIC 0xf0000000 /* not in source code */ |
| |
| /* |
| * jlong conversion macros |
| */ |
| #define jlong_zero ((jlong) 0) |
| #define jlong_one ((jlong) 1) |
| |
| #define jlong_to_ptr(a) ((void*)(intptr_t)(a)) |
| #define ptr_to_jlong(a) ((jlong)(intptr_t)(a)) |
| #define jint_to_jlong(a) ((jlong)(a)) |
| #define jlong_to_jint(a) ((jint)(a)) |
| |
| |
| /* |
| * util funcs |
| */ |
| void util_initialize(JNIEnv *env); |
| void util_reset(void); |
| |
| struct PacketInputStream; |
| struct PacketOutputStream; |
| |
| jint uniqueID(void); |
| jbyte referenceTypeTag(jclass clazz); |
| jbyte specificTypeKey(JNIEnv *env, jobject object); |
| jboolean isObjectTag(jbyte tag); |
| jvmtiError spawnNewThread(jvmtiStartFunction func, void *arg, char *name); |
| void convertSignatureToClassname(char *convert); |
| void writeCodeLocation(struct PacketOutputStream *out, jclass clazz, |
| jmethodID method, jlocation location); |
| |
| jvmtiError classInstances(jclass klass, ObjectBatch *instances, int maxInstances); |
| jvmtiError classInstanceCounts(jint classCount, jclass *classes, jlong *counts); |
| jvmtiError objectReferrers(jobject obj, ObjectBatch *referrers, int maxObjects); |
| |
| // ANDROID-CHANGED: Helper function to get current time in milliseconds on CLOCK_MONOTONIC |
| jlong milliTime(void); |
| |
| /* |
| * Command handling helpers shared among multiple command sets |
| */ |
| int filterDebugThreads(jthread *threads, int count); |
| |
| |
| void sharedGetFieldValues(struct PacketInputStream *in, |
| struct PacketOutputStream *out, |
| jboolean isStatic); |
| jboolean sharedInvoke(struct PacketInputStream *in, |
| struct PacketOutputStream *out); |
| |
| jvmtiError fieldSignature(jclass, jfieldID, char **, char **, char **); |
| jvmtiError fieldModifiers(jclass, jfieldID, jint *); |
| jvmtiError methodSignature(jmethodID, char **, char **, char **); |
| jvmtiError methodReturnType(jmethodID, char *); |
| jvmtiError methodModifiers(jmethodID, jint *); |
| jvmtiError methodClass(jmethodID, jclass *); |
| jvmtiError methodLocation(jmethodID, jlocation*, jlocation*); |
| jvmtiError classLoader(jclass, jobject *); |
| |
| /* |
| * Thin wrappers on top of JNI |
| */ |
| JNIEnv *getEnv(void); |
| jboolean isClass(jobject object); |
| jboolean isThread(jobject object); |
| jboolean isThreadGroup(jobject object); |
| jboolean isString(jobject object); |
| jboolean isClassLoader(jobject object); |
| jboolean isArray(jobject object); |
| |
| /* |
| * Thin wrappers on top of JVMTI |
| */ |
| jvmtiError jvmtiGetCapabilities(jvmtiCapabilities *caps); |
| jint jvmtiMajorVersion(void); |
| jint jvmtiMinorVersion(void); |
| jint jvmtiMicroVersion(void); |
| jvmtiError getSourceDebugExtension(jclass clazz, char **extensionPtr); |
| jboolean canSuspendResumeThreadLists(void); |
| |
| jrawMonitorID debugMonitorCreate(char *name); |
| void debugMonitorEnter(jrawMonitorID theLock); |
| void debugMonitorExit(jrawMonitorID theLock); |
| void debugMonitorWait(jrawMonitorID theLock); |
| void debugMonitorTimedWait(jrawMonitorID theLock, jlong millis); |
| void debugMonitorNotify(jrawMonitorID theLock); |
| void debugMonitorNotifyAll(jrawMonitorID theLock); |
| void debugMonitorDestroy(jrawMonitorID theLock); |
| |
| jthread *allThreads(jint *count); |
| |
| void threadGroupInfo(jthreadGroup, jvmtiThreadGroupInfo *info); |
| |
| char *getClassname(jclass); |
| jvmtiError classSignature(jclass, char**, char**); |
| jint classStatus(jclass); |
| void writeGenericSignature(struct PacketOutputStream *, char *); |
| jboolean isMethodNative(jmethodID); |
| jboolean isMethodObsolete(jmethodID); |
| jvmtiError isMethodSynthetic(jmethodID, jboolean*); |
| jvmtiError isFieldSynthetic(jclass, jfieldID, jboolean*); |
| |
| jboolean isSameObject(JNIEnv *env, jobject o1, jobject o2); |
| |
| jint objectHashCode(jobject); |
| |
| jvmtiError allInterfaces(jclass clazz, jclass **ppinterfaces, jint *count); |
| jvmtiError allLoadedClasses(jclass **ppclasses, jint *count); |
| jvmtiError allClassLoaderClasses(jobject loader, jclass **ppclasses, jint *count); |
| jvmtiError allNestedClasses(jclass clazz, jclass **ppnested, jint *pcount); |
| |
| void setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue); |
| |
| void *jvmtiAllocate(jint numBytes); |
| void jvmtiDeallocate(void *buffer); |
| |
| void eventIndexInit(void); |
| jdwpEvent eventIndex2jdwp(EventIndex i); |
| jvmtiEvent eventIndex2jvmti(EventIndex i); |
| EventIndex jdwp2EventIndex(jdwpEvent eventType); |
| EventIndex jvmti2EventIndex(jvmtiEvent kind); |
| |
| jvmtiError map2jvmtiError(jdwpError); |
| jdwpError map2jdwpError(jvmtiError); |
| jdwpThreadStatus map2jdwpThreadStatus(jint state); |
| jint map2jdwpSuspendStatus(jint state); |
| jint map2jdwpClassStatus(jint); |
| |
| void log_debugee_location(const char *func, |
| jthread thread, jmethodID method, jlocation location); |
| |
| /* |
| * Local Reference management. The two macros below are used |
| * throughout the back end whenever space for JNI local references |
| * is needed in the current frame. |
| */ |
| |
| void createLocalRefSpace(JNIEnv *env, jint capacity); |
| |
| #define WITH_LOCAL_REFS(env, number) \ |
| createLocalRefSpace(env, number); \ |
| { /* BEGINNING OF WITH SCOPE */ |
| |
| #define END_WITH_LOCAL_REFS(env) \ |
| JNI_FUNC_PTR(env,PopLocalFrame)(env, NULL); \ |
| } /* END OF WITH SCOPE */ |
| |
| void saveGlobalRef(JNIEnv *env, jobject obj, jobject *pobj); |
| void tossGlobalRef(JNIEnv *env, jobject *pobj); |
| |
| /* ANDROID_CHANGED: Expose this method publicly. |
| * This returns a newly allocated jvmtiEnv* with the can_tag_objects capability. |
| */ |
| jvmtiEnv *getSpecialJvmti(void); |
| |
| #endif |