Merge
This commit is contained in:
commit
c7e37d5eaf
@ -128,3 +128,4 @@ f42e3d9394b40a423d345b8da22687b5462e5f25 jdk8-b01
|
||||
0b66a233bfb9ba2ebda1e5cdfdb0373d6c1e3c69 jdk8-b04
|
||||
b910aac18c772b823b1f7da03e2c6528725cc6de jdk8-b05
|
||||
28cf2aec4dd7c3c75efc1c15078522467c781a6d jdk8-b06
|
||||
0db7ae9f2b1017124c779bccd016c976928859a0 jdk8-b07
|
||||
|
@ -128,3 +128,4 @@ cd0da00694fbce642db9be936d3e4909a71d911d jdk8-b03
|
||||
60a68d688e24473cf84dedd1e60901a61ab82555 jdk8-b04
|
||||
cc1b599b986a37cb57de4584c5e58169766ca535 jdk8-b05
|
||||
45c43dde7ba7f176333a51a98f086275478836fa jdk8-b06
|
||||
3d61f0856f349e2163bf98146465dab3b7437f63 jdk8-b07
|
||||
|
@ -180,3 +180,11 @@ c149193c768b8b7233da4c3a3fdc0756b975848e jdk7-b143
|
||||
0fa3ace511fe98fe948e751531f3e2b7c60c8376 jdk8-b04
|
||||
dce7d24674f4d0bed00de24f00119057fdce7cfb jdk8-b05
|
||||
0db80d8e77fccddf5e6fa49963226b54ac7d0f62 jdk8-b06
|
||||
3f0cf875af83f55ec5e1a5cea80455315f9322a2 jdk8-b07
|
||||
3a2fb61165dfc72e6de2adab1f2649a408f5e577 hs22-b01
|
||||
7c29742c41b44fb0cd5a13c7ac8834f3f2ca649e hs22-b02
|
||||
3a2fb61165dfc72e398179a2796d740c8da5b8c0 hs22-b03
|
||||
ce9bde819dcba4a5d2822229d9183e69c74326ca hs22-b04
|
||||
513a84dd0f8b56dc0836b4e0bdd5dd0a778fc634 hs22-b05
|
||||
650d15d8f37255d3b805aa00c5bd1c30984b203d hs22-b06
|
||||
da883b9e6d3788057f9577e72712998ed82c9b7e hs23-b01
|
||||
|
@ -48,17 +48,18 @@ sun.jvm.hotspot.asm.x86 \
|
||||
sun.jvm.hotspot.bugspot \
|
||||
sun.jvm.hotspot.bugspot.tree \
|
||||
sun.jvm.hotspot.c1 \
|
||||
sun.jvm.hotspot.ci \
|
||||
sun.jvm.hotspot.code \
|
||||
sun.jvm.hotspot.compiler \
|
||||
sun.jvm.hotspot.debugger \
|
||||
sun.jvm.hotspot.debugger.amd64 \
|
||||
sun.jvm.hotspot.debugger.bsd \
|
||||
sun.jvm.hotspot.debugger.bsd.amd64 \
|
||||
sun.jvm.hotspot.debugger.bsd.x86 \
|
||||
sun.jvm.hotspot.debugger.cdbg \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic.amd64 \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic.x86 \
|
||||
sun.jvm.hotspot.debugger.dbx \
|
||||
sun.jvm.hotspot.debugger.dbx.sparc \
|
||||
sun.jvm.hotspot.debugger.dbx.x86 \
|
||||
sun.jvm.hotspot.debugger.dummy \
|
||||
sun.jvm.hotspot.debugger.ia64 \
|
||||
sun.jvm.hotspot.debugger.linux \
|
||||
@ -76,7 +77,6 @@ sun.jvm.hotspot.debugger.remote.amd64 \
|
||||
sun.jvm.hotspot.debugger.remote.sparc \
|
||||
sun.jvm.hotspot.debugger.remote.x86 \
|
||||
sun.jvm.hotspot.debugger.sparc \
|
||||
sun.jvm.hotspot.debugger.win32 \
|
||||
sun.jvm.hotspot.debugger.win32.coff \
|
||||
sun.jvm.hotspot.debugger.windbg \
|
||||
sun.jvm.hotspot.debugger.windbg.amd64 \
|
||||
@ -91,9 +91,14 @@ sun.jvm.hotspot.interpreter \
|
||||
sun.jvm.hotspot.jdi \
|
||||
sun.jvm.hotspot.livejvm \
|
||||
sun.jvm.hotspot.memory \
|
||||
sun.jvm.hotspot.opto \
|
||||
sun.jvm.hotspot.oops \
|
||||
sun.jvm.hotspot.prims \
|
||||
sun.jvm.hotspot.runtime \
|
||||
sun.jvm.hotspot.runtime.amd64 \
|
||||
sun.jvm.hotspot.runtime.bsd \
|
||||
sun.jvm.hotspot.runtime.bsd_amd64 \
|
||||
sun.jvm.hotspot.runtime.bsd_x86 \
|
||||
sun.jvm.hotspot.runtime.ia64 \
|
||||
sun.jvm.hotspot.runtime.linux \
|
||||
sun.jvm.hotspot.runtime.linux_amd64 \
|
||||
@ -139,17 +144,18 @@ sun/jvm/hotspot/asm/x86/*.java \
|
||||
sun/jvm/hotspot/bugspot/*.java \
|
||||
sun/jvm/hotspot/bugspot/tree/*.java \
|
||||
sun/jvm/hotspot/c1/*.java \
|
||||
sun/jvm/hotspot/ci/*.java \
|
||||
sun/jvm/hotspot/code/*.java \
|
||||
sun/jvm/hotspot/compiler/*.java \
|
||||
sun/jvm/hotspot/debugger/*.java \
|
||||
sun/jvm/hotspot/debugger/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/bsd/*.java \
|
||||
sun/jvm/hotspot/debugger/bsd/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/bsd/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/dbx/*.java \
|
||||
sun/jvm/hotspot/debugger/dbx/sparc/*.java \
|
||||
sun/jvm/hotspot/debugger/dbx/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/dummy/*.java \
|
||||
sun/jvm/hotspot/debugger/ia64/*.java \
|
||||
sun/jvm/hotspot/debugger/linux/*.java \
|
||||
@ -165,7 +171,6 @@ sun/jvm/hotspot/debugger/remote/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/remote/sparc/*.java \
|
||||
sun/jvm/hotspot/debugger/remote/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/sparc/*.java \
|
||||
sun/jvm/hotspot/debugger/win32/*.java \
|
||||
sun/jvm/hotspot/debugger/win32/coff/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/ia64/*.java \
|
||||
@ -176,8 +181,13 @@ sun/jvm/hotspot/jdi/*.java \
|
||||
sun/jvm/hotspot/livejvm/*.java \
|
||||
sun/jvm/hotspot/memory/*.java \
|
||||
sun/jvm/hotspot/oops/*.java \
|
||||
sun/jvm/hotspot/opto/*.java \
|
||||
sun/jvm/hotspot/prims/*.java \
|
||||
sun/jvm/hotspot/runtime/*.java \
|
||||
sun/jvm/hotspot/runtime/amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd_amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd_x86/*.java \
|
||||
sun/jvm/hotspot/runtime/ia64/*.java \
|
||||
sun/jvm/hotspot/runtime/linux/*.java \
|
||||
sun/jvm/hotspot/runtime/linux_amd64/*.java \
|
||||
|
@ -70,6 +70,14 @@ fi
|
||||
|
||||
SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/js.jar
|
||||
|
||||
if [ ! -z "$SA_TYPEDB" ]; then
|
||||
if [ ! -f $SA_TYPEDB ]; then
|
||||
echo "$SA_TYPEDB is unreadable"
|
||||
exit 1
|
||||
fi
|
||||
OPTIONS="-Dsun.jvm.hotspot.typedb=$SA_TYPEDB ${OPTIONS}"
|
||||
fi
|
||||
|
||||
OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}"
|
||||
|
||||
SA_JAVA_CMD="$SA_PREFIX_CMD $SA_JAVA -showversion ${OPTIONS} -cp $SA_CLASSPATH $SA_OPTIONS"
|
||||
|
@ -67,6 +67,14 @@ fi
|
||||
|
||||
SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar::$STARTDIR/lib/js.jar
|
||||
|
||||
if [ ! -z "$SA_TYPEDB" ]; then
|
||||
if [ ! -f $SA_TYPEDB ]; then
|
||||
echo "$SA_TYPEDB is unreadable"
|
||||
exit 1
|
||||
fi
|
||||
OPTIONS="-Dsun.jvm.hotspot.typedb=$SA_TYPEDB ${OPTIONS}"
|
||||
fi
|
||||
|
||||
OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}"
|
||||
|
||||
SA_JAVA_CMD="$SA_PREFIX_CMD $SA_JAVA -d64 -showversion ${OPTIONS} -cp $SA_CLASSPATH $SA_OPTIONS"
|
||||
|
413
hotspot/agent/src/os/bsd/BsdDebuggerLocal.c
Normal file
413
hotspot/agent/src/os/bsd/BsdDebuggerLocal.c
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <jni.h>
|
||||
#include "libproc.h"
|
||||
|
||||
#if defined(x86_64) && !defined(amd64)
|
||||
#define amd64 1
|
||||
#endif
|
||||
|
||||
#ifdef i386
|
||||
#include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h"
|
||||
#endif
|
||||
|
||||
#ifdef amd64
|
||||
#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
|
||||
#endif
|
||||
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
#include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h"
|
||||
#endif
|
||||
|
||||
static jfieldID p_ps_prochandle_ID = 0;
|
||||
static jfieldID threadList_ID = 0;
|
||||
static jfieldID loadObjectList_ID = 0;
|
||||
|
||||
static jmethodID createClosestSymbol_ID = 0;
|
||||
static jmethodID createLoadObject_ID = 0;
|
||||
static jmethodID getThreadForThreadId_ID = 0;
|
||||
static jmethodID listAdd_ID = 0;
|
||||
|
||||
#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }
|
||||
#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
|
||||
|
||||
static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
||||
}
|
||||
|
||||
static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {
|
||||
jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);
|
||||
return (struct ps_prochandle*)(intptr_t)ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: init0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0
|
||||
(JNIEnv *env, jclass cls) {
|
||||
jclass listClass;
|
||||
|
||||
if (init_libproc(getenv("LIBSAPROC_DEBUG") != NULL) != true) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("can't initialize libproc");
|
||||
}
|
||||
|
||||
// fields we use
|
||||
p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");
|
||||
CHECK_EXCEPTION;
|
||||
threadList_ID = (*env)->GetFieldID(env, cls, "threadList", "Ljava/util/List;");
|
||||
CHECK_EXCEPTION;
|
||||
loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");
|
||||
CHECK_EXCEPTION;
|
||||
|
||||
// methods we use
|
||||
createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",
|
||||
"(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
|
||||
CHECK_EXCEPTION;
|
||||
createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",
|
||||
"(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
|
||||
CHECK_EXCEPTION;
|
||||
getThreadForThreadId_ID = (*env)->GetMethodID(env, cls, "getThreadForThreadId",
|
||||
"(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");
|
||||
CHECK_EXCEPTION;
|
||||
// java.util.List method we call
|
||||
listClass = (*env)->FindClass(env, "java/util/List");
|
||||
CHECK_EXCEPTION;
|
||||
listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");
|
||||
CHECK_EXCEPTION;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
#ifdef _LP64
|
||||
return 8;
|
||||
#else
|
||||
return 4;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void fillThreadsAndLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
|
||||
int n = 0, i = 0;
|
||||
|
||||
// add threads
|
||||
n = get_num_threads(ph);
|
||||
for (i = 0; i < n; i++) {
|
||||
jobject thread;
|
||||
jobject threadList;
|
||||
lwpid_t lwpid;
|
||||
|
||||
lwpid = get_lwp_id(ph, i);
|
||||
thread = (*env)->CallObjectMethod(env, this_obj, getThreadForThreadId_ID,
|
||||
(jlong)lwpid);
|
||||
CHECK_EXCEPTION;
|
||||
threadList = (*env)->GetObjectField(env, this_obj, threadList_ID);
|
||||
CHECK_EXCEPTION;
|
||||
(*env)->CallBooleanMethod(env, threadList, listAdd_ID, thread);
|
||||
CHECK_EXCEPTION;
|
||||
}
|
||||
|
||||
// add load objects
|
||||
n = get_num_libs(ph);
|
||||
for (i = 0; i < n; i++) {
|
||||
uintptr_t base;
|
||||
const char* name;
|
||||
jobject loadObject;
|
||||
jobject loadObjectList;
|
||||
|
||||
base = get_lib_base(ph, i);
|
||||
name = get_lib_name(ph, i);
|
||||
loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,
|
||||
(*env)->NewStringUTF(env, name), (jlong)0, (jlong)base);
|
||||
CHECK_EXCEPTION;
|
||||
loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);
|
||||
CHECK_EXCEPTION;
|
||||
(*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);
|
||||
CHECK_EXCEPTION;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I
|
||||
(JNIEnv *env, jobject this_obj, jint jpid) {
|
||||
|
||||
struct ps_prochandle* ph;
|
||||
if ( (ph = Pgrab(jpid)) == NULL) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
|
||||
}
|
||||
(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
|
||||
fillThreadsAndLoadObjects(env, this_obj, ph);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
|
||||
(JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) {
|
||||
const char *execName_cstr;
|
||||
const char *coreName_cstr;
|
||||
jboolean isCopy;
|
||||
struct ps_prochandle* ph;
|
||||
|
||||
execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);
|
||||
CHECK_EXCEPTION;
|
||||
coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);
|
||||
CHECK_EXCEPTION;
|
||||
|
||||
if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
|
||||
(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");
|
||||
}
|
||||
(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
|
||||
(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
|
||||
(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
|
||||
fillThreadsAndLoadObjects(env, this_obj, ph);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: detach0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
if (ph != NULL) {
|
||||
Prelease(ph);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByName0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0
|
||||
(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
|
||||
const char *objectName_cstr, *symbolName_cstr;
|
||||
jlong addr;
|
||||
jboolean isCopy;
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
|
||||
objectName_cstr = NULL;
|
||||
if (objectName != NULL) {
|
||||
objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);
|
||||
CHECK_EXCEPTION_(0);
|
||||
}
|
||||
symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);
|
||||
CHECK_EXCEPTION_(0);
|
||||
|
||||
addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);
|
||||
|
||||
if (objectName_cstr != NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByAddress0
|
||||
* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr) {
|
||||
uintptr_t offset;
|
||||
const char* sym = NULL;
|
||||
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
|
||||
if (sym == NULL) return 0;
|
||||
return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
|
||||
(*env)->NewStringUTF(env, sym), (jlong)offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: readBytesFromProcess0
|
||||
* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {
|
||||
|
||||
jboolean isCopy;
|
||||
jbyteArray array;
|
||||
jbyte *bufPtr;
|
||||
ps_err_e err;
|
||||
|
||||
array = (*env)->NewByteArray(env, numBytes);
|
||||
CHECK_EXCEPTION_(0);
|
||||
bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);
|
||||
CHECK_EXCEPTION_(0);
|
||||
|
||||
err = ps_pread(get_proc_handle(env, this_obj), (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);
|
||||
(*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);
|
||||
return (err == PS_OK)? array : 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
|
||||
(JNIEnv *env, jobject this_obj, jint lwp_id) {
|
||||
|
||||
struct reg gregs;
|
||||
jboolean isCopy;
|
||||
jlongArray array;
|
||||
jlong *regs;
|
||||
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);
|
||||
}
|
||||
|
||||
#undef NPRGREG
|
||||
#ifdef i386
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG
|
||||
#endif
|
||||
#ifdef ia64
|
||||
#define NPRGREG IA64_REG_COUNT
|
||||
#endif
|
||||
#ifdef amd64
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
|
||||
#endif
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
|
||||
#endif
|
||||
|
||||
array = (*env)->NewLongArray(env, NPRGREG);
|
||||
CHECK_EXCEPTION_(0);
|
||||
regs = (*env)->GetLongArrayElements(env, array, &isCopy);
|
||||
|
||||
#undef REG_INDEX
|
||||
|
||||
#ifdef i386
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##reg
|
||||
|
||||
regs[REG_INDEX(GS)] = (uintptr_t) gregs.r_gs;
|
||||
regs[REG_INDEX(FS)] = (uintptr_t) gregs.r_fs;
|
||||
regs[REG_INDEX(ES)] = (uintptr_t) gregs.r_es;
|
||||
regs[REG_INDEX(DS)] = (uintptr_t) gregs.r_ds;
|
||||
regs[REG_INDEX(EDI)] = (uintptr_t) gregs.r_edi;
|
||||
regs[REG_INDEX(ESI)] = (uintptr_t) gregs.r_esi;
|
||||
regs[REG_INDEX(FP)] = (uintptr_t) gregs.r_ebp;
|
||||
regs[REG_INDEX(SP)] = (uintptr_t) gregs.r_isp;
|
||||
regs[REG_INDEX(EBX)] = (uintptr_t) gregs.r_ebx;
|
||||
regs[REG_INDEX(EDX)] = (uintptr_t) gregs.r_edx;
|
||||
regs[REG_INDEX(ECX)] = (uintptr_t) gregs.r_ecx;
|
||||
regs[REG_INDEX(EAX)] = (uintptr_t) gregs.r_eax;
|
||||
regs[REG_INDEX(PC)] = (uintptr_t) gregs.r_eip;
|
||||
regs[REG_INDEX(CS)] = (uintptr_t) gregs.r_cs;
|
||||
regs[REG_INDEX(SS)] = (uintptr_t) gregs.r_ss;
|
||||
|
||||
#endif /* i386 */
|
||||
|
||||
#if ia64
|
||||
regs = (*env)->GetLongArrayElements(env, array, &isCopy);
|
||||
int i;
|
||||
for (i = 0; i < NPRGREG; i++ ) {
|
||||
regs[i] = 0xDEADDEAD;
|
||||
}
|
||||
#endif /* ia64 */
|
||||
|
||||
#ifdef amd64
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
|
||||
|
||||
regs[REG_INDEX(R15)] = gregs.r_r15;
|
||||
regs[REG_INDEX(R14)] = gregs.r_r14;
|
||||
regs[REG_INDEX(R13)] = gregs.r_r13;
|
||||
regs[REG_INDEX(R12)] = gregs.r_r12;
|
||||
regs[REG_INDEX(RBP)] = gregs.r_rbp;
|
||||
regs[REG_INDEX(RBX)] = gregs.r_rbx;
|
||||
regs[REG_INDEX(R11)] = gregs.r_r11;
|
||||
regs[REG_INDEX(R10)] = gregs.r_r10;
|
||||
regs[REG_INDEX(R9)] = gregs.r_r9;
|
||||
regs[REG_INDEX(R8)] = gregs.r_r8;
|
||||
regs[REG_INDEX(RAX)] = gregs.r_rax;
|
||||
regs[REG_INDEX(RCX)] = gregs.r_rcx;
|
||||
regs[REG_INDEX(RDX)] = gregs.r_rdx;
|
||||
regs[REG_INDEX(RSI)] = gregs.r_rsi;
|
||||
regs[REG_INDEX(RDI)] = gregs.r_rdi;
|
||||
regs[REG_INDEX(RIP)] = gregs.r_rip;
|
||||
regs[REG_INDEX(CS)] = gregs.r_cs;
|
||||
regs[REG_INDEX(RSP)] = gregs.r_rsp;
|
||||
regs[REG_INDEX(SS)] = gregs.r_ss;
|
||||
// regs[REG_INDEX(FSBASE)] = gregs.fs_base;
|
||||
// regs[REG_INDEX(GSBASE)] = gregs.gs_base;
|
||||
// regs[REG_INDEX(DS)] = gregs.ds;
|
||||
// regs[REG_INDEX(ES)] = gregs.es;
|
||||
// regs[REG_INDEX(FS)] = gregs.fs;
|
||||
// regs[REG_INDEX(GS)] = gregs.gs;
|
||||
|
||||
#endif /* amd64 */
|
||||
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_##reg
|
||||
|
||||
#ifdef _LP64
|
||||
regs[REG_INDEX(R_PSR)] = gregs.tstate;
|
||||
regs[REG_INDEX(R_PC)] = gregs.tpc;
|
||||
regs[REG_INDEX(R_nPC)] = gregs.tnpc;
|
||||
regs[REG_INDEX(R_Y)] = gregs.y;
|
||||
#else
|
||||
regs[REG_INDEX(R_PSR)] = gregs.psr;
|
||||
regs[REG_INDEX(R_PC)] = gregs.pc;
|
||||
regs[REG_INDEX(R_nPC)] = gregs.npc;
|
||||
regs[REG_INDEX(R_Y)] = gregs.y;
|
||||
#endif
|
||||
regs[REG_INDEX(R_G0)] = 0 ;
|
||||
regs[REG_INDEX(R_G1)] = gregs.u_regs[0];
|
||||
regs[REG_INDEX(R_G2)] = gregs.u_regs[1];
|
||||
regs[REG_INDEX(R_G3)] = gregs.u_regs[2];
|
||||
regs[REG_INDEX(R_G4)] = gregs.u_regs[3];
|
||||
regs[REG_INDEX(R_G5)] = gregs.u_regs[4];
|
||||
regs[REG_INDEX(R_G6)] = gregs.u_regs[5];
|
||||
regs[REG_INDEX(R_G7)] = gregs.u_regs[6];
|
||||
regs[REG_INDEX(R_O0)] = gregs.u_regs[7];
|
||||
regs[REG_INDEX(R_O1)] = gregs.u_regs[8];
|
||||
regs[REG_INDEX(R_O2)] = gregs.u_regs[ 9];
|
||||
regs[REG_INDEX(R_O3)] = gregs.u_regs[10];
|
||||
regs[REG_INDEX(R_O4)] = gregs.u_regs[11];
|
||||
regs[REG_INDEX(R_O5)] = gregs.u_regs[12];
|
||||
regs[REG_INDEX(R_O6)] = gregs.u_regs[13];
|
||||
regs[REG_INDEX(R_O7)] = gregs.u_regs[14];
|
||||
#endif /* sparc */
|
||||
|
||||
|
||||
(*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);
|
||||
return array;
|
||||
}
|
78
hotspot/agent/src/os/bsd/Makefile
Normal file
78
hotspot/agent/src/os/bsd/Makefile
Normal file
@ -0,0 +1,78 @@
|
||||
#
|
||||
# Copyright (c) 2002, 2009, 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi )
|
||||
GCC = gcc
|
||||
|
||||
JAVAH = ${JAVA_HOME}/bin/javah
|
||||
|
||||
SOURCES = salibelf.c \
|
||||
symtab.c \
|
||||
libproc_impl.c \
|
||||
ps_proc.c \
|
||||
ps_core.c \
|
||||
hsearch_r.c \
|
||||
BsdDebuggerLocal.c
|
||||
|
||||
INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]")
|
||||
|
||||
OBJS = $(SOURCES:.c=.o)
|
||||
|
||||
LIBS = -lutil -lthread_db
|
||||
|
||||
CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES)
|
||||
|
||||
LIBSA = $(ARCH)/libsaproc.so
|
||||
|
||||
all: $(LIBSA)
|
||||
|
||||
BsdDebuggerLocal.o: BsdDebuggerLocal.c
|
||||
$(JAVAH) -jni -classpath ../../../../../build/bsd-i586/hotspot/outputdir/bsd_i486_compiler2/generated/saclasses \
|
||||
sun.jvm.hotspot.debugger.x86.X86ThreadContext \
|
||||
sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
|
||||
$(GCC) $(CFLAGS) $<
|
||||
|
||||
.c.obj:
|
||||
$(GCC) $(CFLAGS)
|
||||
|
||||
ifndef LDNOMAP
|
||||
LFLAGS_LIBSA = -Xlinker --version-script=mapfile
|
||||
endif
|
||||
|
||||
$(LIBSA): $(OBJS) mapfile
|
||||
if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi
|
||||
$(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS)
|
||||
|
||||
test.o: $(LIBSA) test.c
|
||||
$(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c
|
||||
|
||||
test: test.o
|
||||
$(GCC) -o test test.o -L$(ARCH) -lsaproc $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(LIBSA)
|
||||
rm -f $(OBJS)
|
||||
rm -f test.o
|
||||
-rmdir $(ARCH)
|
||||
|
120
hotspot/agent/src/os/bsd/StubDebuggerLocal.c
Normal file
120
hotspot/agent/src/os/bsd/StubDebuggerLocal.c
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <jni.h>
|
||||
|
||||
#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }
|
||||
#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
|
||||
|
||||
static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: init0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0
|
||||
(JNIEnv *env, jclass cls) {
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
#ifdef _LP64
|
||||
return 8;
|
||||
#else
|
||||
return 4;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I
|
||||
(JNIEnv *env, jobject this_obj, jint jpid) {
|
||||
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
|
||||
(JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: detach0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByName0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0
|
||||
(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByAddress0
|
||||
* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: readBytesFromProcess0
|
||||
* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
|
||||
(JNIEnv *env, jobject this_obj, jint lwp_id) {
|
||||
return 0;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2006, 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
|
||||
@ -22,34 +22,37 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PROCLIST_
|
||||
#define _PROCLIST_
|
||||
#ifndef _ELFMACROS_H_
|
||||
#define _ELFMACROS_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
#define ELF_NHDR Elf_Note
|
||||
|
||||
class ProcEntry {
|
||||
public:
|
||||
/** name may not be NULL */
|
||||
ProcEntry(ULONG pid, USHORT nameLength, wchar_t* name);
|
||||
ProcEntry(ULONG pid, USHORT nameLength, char* name);
|
||||
~ProcEntry();
|
||||
ProcEntry(const ProcEntry& arg);
|
||||
ProcEntry& operator=(const ProcEntry& arg);
|
||||
#if defined(_LP64)
|
||||
#define ELF_EHDR Elf64_Ehdr
|
||||
#define ELF_SHDR Elf64_Shdr
|
||||
#define ELF_PHDR Elf64_Phdr
|
||||
#define ELF_SYM Elf64_Sym
|
||||
#define ELF_DYN Elf64_Dyn
|
||||
#define ELF_ADDR Elf64_Addr
|
||||
|
||||
ULONG getPid();
|
||||
/** Returns number of WCHAR characters in getName() */
|
||||
USHORT getNameLength();
|
||||
WCHAR* getName();
|
||||
#ifndef ELF_ST_TYPE
|
||||
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
#endif
|
||||
|
||||
private:
|
||||
ULONG pid;
|
||||
USHORT nameLength;
|
||||
WCHAR* name;
|
||||
void copyFrom(const ProcEntry& arg);
|
||||
};
|
||||
#else
|
||||
|
||||
typedef std::vector<ProcEntry> ProcEntryList;
|
||||
void procList(ProcEntryList& processes);
|
||||
#define ELF_EHDR Elf32_Ehdr
|
||||
#define ELF_SHDR Elf32_Shdr
|
||||
#define ELF_PHDR Elf32_Phdr
|
||||
#define ELF_SYM Elf32_Sym
|
||||
#define ELF_DYN Elf32_Dyn
|
||||
#define ELF_ADDR Elf32_Addr
|
||||
|
||||
#endif // #defined _PROCLIST_
|
||||
#ifndef ELF_ST_TYPE
|
||||
#define ELF_ST_TYPE ELF32_ST_TYPE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _ELFMACROS_H_ */
|
127
hotspot/agent/src/os/bsd/libproc.h
Normal file
127
hotspot/agent/src/os/bsd/libproc.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2007, 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.
|
||||
*
|
||||
* 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 _LIBPROC_H_
|
||||
#define _LIBPROC_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <machine/reg.h>
|
||||
#include <proc_service.h>
|
||||
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
/*
|
||||
If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64
|
||||
otherwise it should be from /usr/include/asm-sparc
|
||||
These two files define pt_regs structure differently
|
||||
*/
|
||||
#ifdef _LP64
|
||||
#include "asm-sparc64/ptrace.h"
|
||||
#else
|
||||
#include "asm-sparc/ptrace.h"
|
||||
#endif
|
||||
|
||||
#endif //sparc or sparcv9
|
||||
|
||||
/************************************************************************************
|
||||
|
||||
0. This is very minimal subset of Solaris libproc just enough for current application.
|
||||
Please note that the bulk of the functionality is from proc_service interface. This
|
||||
adds Pgrab__ and some missing stuff. We hide the difference b/w live process and core
|
||||
file by this interface.
|
||||
|
||||
1. pthread_id is unique. We store this in OSThread::_pthread_id in JVM code.
|
||||
|
||||
2. All threads see the same pid when they call getpid().
|
||||
We used to save the result of ::getpid() call in OSThread::_thread_id.
|
||||
Because gettid returns actual pid of thread (lwp id), this is
|
||||
unique again. We therefore use OSThread::_thread_id as unique identifier.
|
||||
|
||||
3. There is a unique LWP id under both thread libraries. libthread_db maps pthread_id
|
||||
to its underlying lwp_id under both the thread libraries. thread_info.lwp_id stores
|
||||
lwp_id of the thread. The lwp id is nothing but the actual pid of clone'd processes. But
|
||||
unfortunately libthread_db does not work very well for core dumps. So, we get pthread_id
|
||||
only for processes. For core dumps, we don't use libthread_db at all (like gdb).
|
||||
|
||||
4. ptrace operates on this LWP id under both the thread libraries. When we say 'pid' for
|
||||
ptrace call, we refer to lwp_id of the thread.
|
||||
|
||||
5. for core file, we parse ELF files and read data from them. For processes we use
|
||||
combination of ptrace and /proc calls.
|
||||
|
||||
*************************************************************************************/
|
||||
|
||||
// This C bool type must be int for compatibility with BSD calls and
|
||||
// it would be a mistake to equivalence it to C++ bool on many platforms
|
||||
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
struct ps_prochandle;
|
||||
|
||||
// attach to a process
|
||||
struct ps_prochandle* Pgrab(pid_t pid);
|
||||
|
||||
// attach to a core dump
|
||||
struct ps_prochandle* Pgrab_core(const char* execfile, const char* corefile);
|
||||
|
||||
// release a process or core
|
||||
void Prelease(struct ps_prochandle* ph);
|
||||
|
||||
// functions not directly available in Solaris libproc
|
||||
|
||||
// initialize libproc (call this only once per app)
|
||||
// pass true to make library verbose
|
||||
bool init_libproc(bool verbose);
|
||||
|
||||
// get number of threads
|
||||
int get_num_threads(struct ps_prochandle* ph);
|
||||
|
||||
// get lwp_id of n'th thread
|
||||
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index);
|
||||
|
||||
// get regs for a given lwp
|
||||
bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lid, struct reg* regs);
|
||||
|
||||
// get number of shared objects
|
||||
int get_num_libs(struct ps_prochandle* ph);
|
||||
|
||||
// get name of n'th lib
|
||||
const char* get_lib_name(struct ps_prochandle* ph, int index);
|
||||
|
||||
// get base of lib
|
||||
uintptr_t get_lib_base(struct ps_prochandle* ph, int index);
|
||||
|
||||
// returns true if given library is found in lib list
|
||||
bool find_lib(struct ps_prochandle* ph, const char *lib_name);
|
||||
|
||||
// symbol lookup
|
||||
uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
|
||||
const char* sym_name);
|
||||
|
||||
// address->nearest symbol lookup. return NULL for no symbol
|
||||
const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset);
|
||||
|
||||
#endif //__LIBPROC_H_
|
452
hotspot/agent/src/os/bsd/libproc_impl.c
Normal file
452
hotspot/agent/src/os/bsd/libproc_impl.c
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <thread_db.h>
|
||||
#include "libproc_impl.h"
|
||||
|
||||
static const char* alt_root = NULL;
|
||||
static int alt_root_len = -1;
|
||||
|
||||
#define SA_ALTROOT "SA_ALTROOT"
|
||||
|
||||
static void init_alt_root() {
|
||||
if (alt_root_len == -1) {
|
||||
alt_root = getenv(SA_ALTROOT);
|
||||
if (alt_root) {
|
||||
alt_root_len = strlen(alt_root);
|
||||
} else {
|
||||
alt_root_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pathmap_open(const char* name) {
|
||||
int fd;
|
||||
char alt_path[PATH_MAX + 1];
|
||||
|
||||
init_alt_root();
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (alt_root_len > 0) {
|
||||
strcpy(alt_path, alt_root);
|
||||
strcat(alt_path, name);
|
||||
fd = open(alt_path, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
print_debug("path %s substituted for %s\n", alt_path, name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (strrchr(name, '/')) {
|
||||
strcpy(alt_path, alt_root);
|
||||
strcat(alt_path, strrchr(name, '/'));
|
||||
fd = open(alt_path, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
print_debug("path %s substituted for %s\n", alt_path, name);
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool _libsaproc_debug;
|
||||
|
||||
void print_debug(const char* format,...) {
|
||||
if (_libsaproc_debug) {
|
||||
va_list alist;
|
||||
|
||||
va_start(alist, format);
|
||||
fputs("libsaproc DEBUG: ", stderr);
|
||||
vfprintf(stderr, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_debug() {
|
||||
return _libsaproc_debug;
|
||||
}
|
||||
|
||||
// initialize libproc
|
||||
bool init_libproc(bool debug) {
|
||||
// init debug mode
|
||||
_libsaproc_debug = debug;
|
||||
|
||||
// initialize the thread_db library
|
||||
if (td_init() != TD_OK) {
|
||||
print_debug("libthread_db's td_init failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void destroy_lib_info(struct ps_prochandle* ph) {
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
lib_info *next = lib->next;
|
||||
if (lib->symtab) {
|
||||
destroy_symtab(lib->symtab);
|
||||
}
|
||||
free(lib);
|
||||
lib = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_thread_info(struct ps_prochandle* ph) {
|
||||
thread_info* thr = ph->threads;
|
||||
while (thr) {
|
||||
thread_info *next = thr->next;
|
||||
free(thr);
|
||||
thr = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ps_prochandle cleanup
|
||||
|
||||
// ps_prochandle cleanup
|
||||
void Prelease(struct ps_prochandle* ph) {
|
||||
// do the "derived class" clean-up first
|
||||
ph->ops->release(ph);
|
||||
destroy_lib_info(ph);
|
||||
destroy_thread_info(ph);
|
||||
free(ph);
|
||||
}
|
||||
|
||||
lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {
|
||||
return add_lib_info_fd(ph, libname, -1, base);
|
||||
}
|
||||
|
||||
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {
|
||||
lib_info* newlib;
|
||||
|
||||
if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
|
||||
print_debug("can't allocate memory for lib_info\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(newlib->name, libname, sizeof(newlib->name));
|
||||
newlib->base = base;
|
||||
|
||||
if (fd == -1) {
|
||||
if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
|
||||
print_debug("can't open shared object %s\n", newlib->name);
|
||||
free(newlib);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
newlib->fd = fd;
|
||||
}
|
||||
|
||||
// check whether we have got an ELF file. /proc/<pid>/map
|
||||
// gives out all file mappings and not just shared objects
|
||||
if (is_elf_file(newlib->fd) == false) {
|
||||
close(newlib->fd);
|
||||
free(newlib);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newlib->symtab = build_symtab(newlib->fd);
|
||||
if (newlib->symtab == NULL) {
|
||||
print_debug("symbol table build failed for %s\n", newlib->name);
|
||||
}
|
||||
else {
|
||||
print_debug("built symbol table for %s\n", newlib->name);
|
||||
}
|
||||
|
||||
// even if symbol table building fails, we add the lib_info.
|
||||
// This is because we may need to read from the ELF file for core file
|
||||
// address read functionality. lookup_symbol checks for NULL symtab.
|
||||
if (ph->libs) {
|
||||
ph->lib_tail->next = newlib;
|
||||
ph->lib_tail = newlib;
|
||||
} else {
|
||||
ph->libs = ph->lib_tail = newlib;
|
||||
}
|
||||
ph->num_libs++;
|
||||
|
||||
return newlib;
|
||||
}
|
||||
|
||||
// lookup for a specific symbol
|
||||
uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
|
||||
const char* sym_name) {
|
||||
// ignore object_name. search in all libraries
|
||||
// FIXME: what should we do with object_name?? The library names are obtained
|
||||
// by parsing /proc/<pid>/maps, which may not be the same as object_name.
|
||||
// What we need is a utility to map object_name to real file name, something
|
||||
// dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For
|
||||
// now, we just ignore object_name and do a global search for the symbol.
|
||||
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (lib->symtab) {
|
||||
uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);
|
||||
if (res) return res;
|
||||
}
|
||||
lib = lib->next;
|
||||
}
|
||||
|
||||
print_debug("lookup failed for symbol '%s' in obj '%s'\n",
|
||||
sym_name, object_name);
|
||||
return (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
|
||||
const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) {
|
||||
const char* res = NULL;
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (lib->symtab && addr >= lib->base) {
|
||||
res = nearest_symbol(lib->symtab, addr - lib->base, poffset);
|
||||
if (res) return res;
|
||||
}
|
||||
lib = lib->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// add a thread to ps_prochandle
|
||||
thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
|
||||
thread_info* newthr;
|
||||
if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) {
|
||||
print_debug("can't allocate memory for thread_info\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// initialize thread info
|
||||
newthr->pthread_id = pthread_id;
|
||||
newthr->lwp_id = lwp_id;
|
||||
|
||||
// add new thread to the list
|
||||
newthr->next = ph->threads;
|
||||
ph->threads = newthr;
|
||||
ph->num_threads++;
|
||||
return newthr;
|
||||
}
|
||||
|
||||
|
||||
// struct used for client data from thread_db callback
|
||||
struct thread_db_client_data {
|
||||
struct ps_prochandle* ph;
|
||||
thread_info_callback callback;
|
||||
};
|
||||
|
||||
// callback function for libthread_db
|
||||
static int thread_db_callback(const td_thrhandle_t *th_p, void *data) {
|
||||
struct thread_db_client_data* ptr = (struct thread_db_client_data*) data;
|
||||
td_thrinfo_t ti;
|
||||
td_err_e err;
|
||||
|
||||
memset(&ti, 0, sizeof(ti));
|
||||
err = td_thr_get_info(th_p, &ti);
|
||||
if (err != TD_OK) {
|
||||
print_debug("libthread_db : td_thr_get_info failed, can't get thread info\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid);
|
||||
|
||||
if (ptr->callback(ptr->ph, (pthread_t)ti.ti_tid, ti.ti_lid) != true)
|
||||
return TD_ERR;
|
||||
|
||||
return TD_OK;
|
||||
}
|
||||
|
||||
// read thread_info using libthread_db
|
||||
bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) {
|
||||
struct thread_db_client_data mydata;
|
||||
td_thragent_t* thread_agent = NULL;
|
||||
if (td_ta_new(ph, &thread_agent) != TD_OK) {
|
||||
print_debug("can't create libthread_db agent\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
mydata.ph = ph;
|
||||
mydata.callback = cb;
|
||||
|
||||
// we use libthread_db iterator to iterate thru list of threads.
|
||||
if (td_ta_thr_iter(thread_agent, thread_db_callback, &mydata,
|
||||
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
|
||||
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS) != TD_OK) {
|
||||
td_ta_delete(thread_agent);
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete thread agent
|
||||
td_ta_delete(thread_agent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// get number of threads
|
||||
int get_num_threads(struct ps_prochandle* ph) {
|
||||
return ph->num_threads;
|
||||
}
|
||||
|
||||
// get lwp_id of n'th thread
|
||||
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) {
|
||||
int count = 0;
|
||||
thread_info* thr = ph->threads;
|
||||
while (thr) {
|
||||
if (count == index) {
|
||||
return thr->lwp_id;
|
||||
}
|
||||
count++;
|
||||
thr = thr->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get regs for a given lwp
|
||||
bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) {
|
||||
return ph->ops->get_lwp_regs(ph, lwp_id, regs);
|
||||
}
|
||||
|
||||
// get number of shared objects
|
||||
int get_num_libs(struct ps_prochandle* ph) {
|
||||
return ph->num_libs;
|
||||
}
|
||||
|
||||
// get name of n'th solib
|
||||
const char* get_lib_name(struct ps_prochandle* ph, int index) {
|
||||
int count = 0;
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (count == index) {
|
||||
return lib->name;
|
||||
}
|
||||
count++;
|
||||
lib = lib->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get base address of a lib
|
||||
uintptr_t get_lib_base(struct ps_prochandle* ph, int index) {
|
||||
int count = 0;
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (count == index) {
|
||||
return lib->base;
|
||||
}
|
||||
count++;
|
||||
lib = lib->next;
|
||||
}
|
||||
return (uintptr_t)NULL;
|
||||
}
|
||||
|
||||
bool find_lib(struct ps_prochandle* ph, const char *lib_name) {
|
||||
lib_info *p = ph->libs;
|
||||
while (p) {
|
||||
if (strcmp(p->name, lib_name) == 0) {
|
||||
return true;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// proc service functions
|
||||
|
||||
// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table
|
||||
// of the load object object_name in the target process identified by ph.
|
||||
// It returns the symbol's value as an address in the target process in
|
||||
// *sym_addr.
|
||||
|
||||
ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
|
||||
const char *sym_name, psaddr_t *sym_addr) {
|
||||
*sym_addr = (psaddr_t) lookup_symbol(ph, object_name, sym_name);
|
||||
return (*sym_addr ? PS_OK : PS_NOSYM);
|
||||
}
|
||||
|
||||
// read "size" bytes info "buf" from address "addr"
|
||||
ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr,
|
||||
void *buf, size_t size) {
|
||||
return ph->ops->p_pread(ph, (uintptr_t) addr, buf, size)? PS_OK: PS_ERR;
|
||||
}
|
||||
|
||||
// write "size" bytes of data to debuggee at address "addr"
|
||||
ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr,
|
||||
const void *buf, size_t size) {
|
||||
return ph->ops->p_pwrite(ph, (uintptr_t)addr, buf, size)? PS_OK: PS_ERR;
|
||||
}
|
||||
|
||||
// fill in ptrace_lwpinfo for lid
|
||||
ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) {
|
||||
return ph->ops->get_lwp_info(ph, lwp_id, linfo)? PS_OK: PS_ERR;
|
||||
}
|
||||
|
||||
// needed for when libthread_db is compiled with TD_DEBUG defined
|
||||
void
|
||||
ps_plog (const char *format, ...)
|
||||
{
|
||||
va_list alist;
|
||||
|
||||
va_start(alist, format);
|
||||
vfprintf(stderr, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Functions below this point are not yet implemented. They are here only
|
||||
// to make the linker happy.
|
||||
|
||||
ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) {
|
||||
print_debug("ps_lsetfpregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lid, const prgregset_t gregset) {
|
||||
print_debug("ps_lsetregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lid, prfpregset_t *fpregs) {
|
||||
print_debug("ps_lgetfpregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) {
|
||||
print_debug("ps_lgetfpregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lstop(struct ps_prochandle *ph, lwpid_t lid) {
|
||||
print_debug("ps_lstop not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_pcontinue(struct ps_prochandle *ph) {
|
||||
print_debug("ps_pcontinue not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
130
hotspot/agent/src/os/bsd/libproc_impl.h
Normal file
130
hotspot/agent/src/os/bsd/libproc_impl.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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.
|
||||
*
|
||||
* 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 _LIBPROC_IMPL_H_
|
||||
#define _LIBPROC_IMPL_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include "libproc.h"
|
||||
#include "symtab.h"
|
||||
|
||||
// data structures in this file mimic those of Solaris 8.0 - libproc's Pcontrol.h
|
||||
|
||||
#define BUF_SIZE (PATH_MAX + NAME_MAX + 1)
|
||||
|
||||
// list of shared objects
|
||||
typedef struct lib_info {
|
||||
char name[BUF_SIZE];
|
||||
uintptr_t base;
|
||||
struct symtab* symtab;
|
||||
int fd; // file descriptor for lib
|
||||
struct lib_info* next;
|
||||
} lib_info;
|
||||
|
||||
// list of threads
|
||||
typedef struct thread_info {
|
||||
lwpid_t lwp_id;
|
||||
pthread_t pthread_id; // not used cores, always -1
|
||||
struct reg regs; // not for process, core uses for caching regset
|
||||
struct thread_info* next;
|
||||
} thread_info;
|
||||
|
||||
// list of virtual memory maps
|
||||
typedef struct map_info {
|
||||
int fd; // file descriptor
|
||||
off_t offset; // file offset of this mapping
|
||||
uintptr_t vaddr; // starting virtual address
|
||||
size_t memsz; // size of the mapping
|
||||
struct map_info* next;
|
||||
} map_info;
|
||||
|
||||
// vtable for ps_prochandle
|
||||
typedef struct ps_prochandle_ops {
|
||||
// "derived class" clean-up
|
||||
void (*release)(struct ps_prochandle* ph);
|
||||
// read from debuggee
|
||||
bool (*p_pread)(struct ps_prochandle *ph,
|
||||
uintptr_t addr, char *buf, size_t size);
|
||||
// write into debuggee
|
||||
bool (*p_pwrite)(struct ps_prochandle *ph,
|
||||
uintptr_t addr, const char *buf , size_t size);
|
||||
// get integer regset of a thread
|
||||
bool (*get_lwp_regs)(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs);
|
||||
// get info on thread
|
||||
bool (*get_lwp_info)(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo);
|
||||
} ps_prochandle_ops;
|
||||
|
||||
// the ps_prochandle
|
||||
|
||||
struct core_data {
|
||||
int core_fd; // file descriptor of core file
|
||||
int exec_fd; // file descriptor of exec file
|
||||
int interp_fd; // file descriptor of interpreter (ld-elf.so.1)
|
||||
// part of the class sharing workaround
|
||||
int classes_jsa_fd; // file descriptor of class share archive
|
||||
uintptr_t dynamic_addr; // address of dynamic section of a.out
|
||||
uintptr_t ld_base_addr; // base address of ld.so
|
||||
size_t num_maps; // number of maps.
|
||||
map_info* maps; // maps in a linked list
|
||||
// part of the class sharing workaround
|
||||
map_info* class_share_maps;// class share maps in a linked list
|
||||
map_info** map_array; // sorted (by vaddr) array of map_info pointers
|
||||
};
|
||||
|
||||
struct ps_prochandle {
|
||||
ps_prochandle_ops* ops; // vtable ptr
|
||||
pid_t pid;
|
||||
int num_libs;
|
||||
lib_info* libs; // head of lib list
|
||||
lib_info* lib_tail; // tail of lib list - to append at the end
|
||||
int num_threads;
|
||||
thread_info* threads; // head of thread list
|
||||
struct core_data* core; // data only used for core dumps, NULL for process
|
||||
};
|
||||
|
||||
int pathmap_open(const char* name);
|
||||
|
||||
void print_debug(const char* format,...);
|
||||
bool is_debug();
|
||||
|
||||
typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid);
|
||||
|
||||
// reads thread info using libthread_db and calls above callback for each thread
|
||||
bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb);
|
||||
|
||||
// adds a new shared object to lib list, returns NULL on failure
|
||||
lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base);
|
||||
|
||||
// adds a new shared object to lib list, supply open lib file descriptor as well
|
||||
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
|
||||
uintptr_t base);
|
||||
|
||||
// adds a new thread to threads list, returns NULL on failure
|
||||
thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id);
|
||||
|
||||
// a test for ELF signature without using libelf
|
||||
bool is_elf_file(int fd);
|
||||
|
||||
#endif //_LIBPROC_IMPL_H_
|
66
hotspot/agent/src/os/bsd/mapfile
Normal file
66
hotspot/agent/src/os/bsd/mapfile
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2003, 2006, 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
# Define public interface.
|
||||
|
||||
SUNWprivate_1.1 {
|
||||
global:
|
||||
|
||||
# native methods of BsdDebuggerLocal class
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0;
|
||||
|
||||
# proc_service.h functions - to be used by libthread_db
|
||||
ps_getpid;
|
||||
ps_pglobal_lookup;
|
||||
ps_pread;
|
||||
ps_pwrite;
|
||||
ps_lsetfpregs;
|
||||
ps_lsetregs;
|
||||
ps_lgetfpregs;
|
||||
ps_lgetregs;
|
||||
ps_lcontinue;
|
||||
ps_lgetxmmregs;
|
||||
ps_lsetxmmregs;
|
||||
ps_lstop;
|
||||
ps_linfo;
|
||||
|
||||
# used by attach test program
|
||||
init_libproc;
|
||||
Pgrab;
|
||||
Pgrab_core;
|
||||
Prelease;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
1023
hotspot/agent/src/os/bsd/ps_core.c
Normal file
1023
hotspot/agent/src/os/bsd/ps_core.c
Normal file
File diff suppressed because it is too large
Load Diff
444
hotspot/agent/src/os/bsd/ps_proc.c
Normal file
444
hotspot/agent/src/os/bsd/ps_proc.c
Normal file
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/user.h>
|
||||
#include <elf.h>
|
||||
#include <sys/elf_common.h>
|
||||
#include <sys/link_elf.h>
|
||||
#include <libutil.h>
|
||||
#include "libproc_impl.h"
|
||||
#include "elfmacros.h"
|
||||
|
||||
// This file has the libproc implementation specific to live process
|
||||
// For core files, refer to ps_core.c
|
||||
|
||||
static inline uintptr_t align(uintptr_t ptr, size_t size) {
|
||||
return (ptr & ~(size - 1));
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// ptrace functions
|
||||
// ---------------------------------------------
|
||||
|
||||
// read "size" bytes of data from "addr" within the target process.
|
||||
// unlike the standard ptrace() function, process_read_data() can handle
|
||||
// unaligned address - alignment check, if required, should be done
|
||||
// before calling process_read_data.
|
||||
|
||||
static bool process_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) {
|
||||
int rslt;
|
||||
size_t i, words;
|
||||
uintptr_t end_addr = addr + size;
|
||||
uintptr_t aligned_addr = align(addr, sizeof(int));
|
||||
|
||||
if (aligned_addr != addr) {
|
||||
char *ptr = (char *)&rslt;
|
||||
errno = 0;
|
||||
rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0);
|
||||
if (errno) {
|
||||
print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr);
|
||||
return false;
|
||||
}
|
||||
for (; aligned_addr != addr; aligned_addr++, ptr++);
|
||||
for (; ((intptr_t)aligned_addr % sizeof(int)) && aligned_addr < end_addr;
|
||||
aligned_addr++)
|
||||
*(buf++) = *(ptr++);
|
||||
}
|
||||
|
||||
words = (end_addr - aligned_addr) / sizeof(int);
|
||||
|
||||
// assert((intptr_t)aligned_addr % sizeof(int) == 0);
|
||||
for (i = 0; i < words; i++) {
|
||||
errno = 0;
|
||||
rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0);
|
||||
if (errno) {
|
||||
print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr);
|
||||
return false;
|
||||
}
|
||||
*(int *)buf = rslt;
|
||||
buf += sizeof(int);
|
||||
aligned_addr += sizeof(int);
|
||||
}
|
||||
|
||||
if (aligned_addr != end_addr) {
|
||||
char *ptr = (char *)&rslt;
|
||||
errno = 0;
|
||||
rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0);
|
||||
if (errno) {
|
||||
print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr);
|
||||
return false;
|
||||
}
|
||||
for (; aligned_addr != end_addr; aligned_addr++)
|
||||
*(buf++) = *(ptr++);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// null implementation for write
|
||||
static bool process_write_data(struct ps_prochandle* ph,
|
||||
uintptr_t addr, const char *buf , size_t size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// "user" should be a pointer to a reg
|
||||
static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct reg *user) {
|
||||
// we have already attached to all thread 'pid's, just use ptrace call
|
||||
// to get regset now. Note that we don't cache regset upfront for processes.
|
||||
if (ptrace(PT_GETREGS, pid, (caddr_t) user, 0) < 0) {
|
||||
print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// fill in ptrace_lwpinfo for lid
|
||||
static bool process_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) {
|
||||
errno = 0;
|
||||
ptrace(PT_LWPINFO, lwp_id, linfo, sizeof(struct ptrace_lwpinfo));
|
||||
|
||||
return (errno == 0)? true: false;
|
||||
}
|
||||
|
||||
// attach to a process/thread specified by "pid"
|
||||
static bool ptrace_attach(pid_t pid) {
|
||||
if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) {
|
||||
print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
|
||||
return false;
|
||||
} else {
|
||||
int ret;
|
||||
int status;
|
||||
do {
|
||||
// Wait for debuggee to stop.
|
||||
ret = waitpid(pid, &status, 0);
|
||||
if (ret >= 0) {
|
||||
if (WIFSTOPPED(status)) {
|
||||
// Debuggee stopped.
|
||||
return true;
|
||||
} else {
|
||||
print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
break;
|
||||
case ECHILD:
|
||||
print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
|
||||
break;
|
||||
case EINVAL:
|
||||
print_debug("waitpid() failed. Invalid options argument.\n");
|
||||
break;
|
||||
default:
|
||||
print_debug("waitpid() failed. Unexpected error %d\n",errno);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
// functions for obtaining library information
|
||||
// -------------------------------------------------------
|
||||
|
||||
// callback for read_thread_info
|
||||
static bool add_new_thread(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
|
||||
return add_thread_info(ph, pthread_id, lwp_id) != NULL;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__) && __FreeBSD_version < 701000
|
||||
/*
|
||||
* TEXT_START_ADDR from binutils/ld/emulparams/<arch_spec>.sh
|
||||
* Not the most robust but good enough.
|
||||
*/
|
||||
|
||||
#if defined(amd64) || defined(x86_64)
|
||||
#define TEXT_START_ADDR 0x400000
|
||||
#elif defined(i386)
|
||||
#define TEXT_START_ADDR 0x8048000
|
||||
#else
|
||||
#error TEXT_START_ADDR not defined
|
||||
#endif
|
||||
|
||||
#define BUF_SIZE (PATH_MAX + NAME_MAX + 1)
|
||||
|
||||
uintptr_t linkmap_addr(struct ps_prochandle *ph) {
|
||||
uintptr_t ehdr_addr, phdr_addr, dyn_addr, dmap_addr, lmap_addr;
|
||||
ELF_EHDR ehdr;
|
||||
ELF_PHDR *phdrs, *phdr;
|
||||
ELF_DYN *dyns, *dyn;
|
||||
struct r_debug dmap;
|
||||
unsigned long hdrs_size;
|
||||
unsigned int i;
|
||||
|
||||
/* read ELF_EHDR at TEXT_START_ADDR and validate */
|
||||
|
||||
ehdr_addr = (uintptr_t)TEXT_START_ADDR;
|
||||
|
||||
if (process_read_data(ph, ehdr_addr, (char *)&ehdr, sizeof(ehdr)) != true) {
|
||||
print_debug("process_read_data failed for ehdr_addr %p\n", ehdr_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!IS_ELF(ehdr) ||
|
||||
ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
|
||||
ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
|
||||
ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
|
||||
ehdr.e_phentsize != sizeof(ELF_PHDR) ||
|
||||
ehdr.e_version != ELF_TARG_VER ||
|
||||
ehdr.e_machine != ELF_TARG_MACH) {
|
||||
print_debug("not an ELF_EHDR at %p\n", ehdr_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* allocate space for all ELF_PHDR's and read */
|
||||
|
||||
phdr_addr = ehdr_addr + ehdr.e_phoff;
|
||||
hdrs_size = ehdr.e_phnum * sizeof(ELF_PHDR);
|
||||
|
||||
if ((phdrs = malloc(hdrs_size)) == NULL)
|
||||
return (0);
|
||||
|
||||
if (process_read_data(ph, phdr_addr, (char *)phdrs, hdrs_size) != true) {
|
||||
print_debug("process_read_data failed for phdr_addr %p\n", phdr_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* find PT_DYNAMIC section */
|
||||
|
||||
for (i = 0, phdr = phdrs; i < ehdr.e_phnum; i++, phdr++) {
|
||||
if (phdr->p_type == PT_DYNAMIC)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= ehdr.e_phnum) {
|
||||
print_debug("PT_DYNAMIC section not found!\n");
|
||||
free(phdrs);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* allocate space and read in ELF_DYN headers */
|
||||
|
||||
dyn_addr = phdr->p_vaddr;
|
||||
hdrs_size = phdr->p_memsz;
|
||||
free(phdrs);
|
||||
|
||||
if ((dyns = malloc(hdrs_size)) == NULL)
|
||||
return (0);
|
||||
|
||||
if (process_read_data(ph, dyn_addr, (char *)dyns, hdrs_size) != true) {
|
||||
print_debug("process_read_data failed for dyn_addr %p\n", dyn_addr);
|
||||
free(dyns);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* find DT_DEBUG */
|
||||
|
||||
dyn = dyns;
|
||||
while (dyn->d_tag != DT_DEBUG && dyn->d_tag != DT_NULL) {
|
||||
dyn++;
|
||||
}
|
||||
|
||||
if (dyn->d_tag != DT_DEBUG) {
|
||||
print_debug("failed to find DT_DEBUG\n");
|
||||
free(dyns);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* read struct r_debug into dmap */
|
||||
|
||||
dmap_addr = (uintptr_t)dyn->d_un.d_ptr;
|
||||
free(dyns);
|
||||
|
||||
if (process_read_data(ph, dmap_addr, (char *)&dmap, sizeof(dmap)) != true) {
|
||||
print_debug("process_read_data failed for dmap_addr %p\n", dmap_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
lmap_addr = (uintptr_t)dmap.r_map;
|
||||
|
||||
return (lmap_addr);
|
||||
}
|
||||
#endif // __FreeBSD__ && __FreeBSD_version < 701000
|
||||
|
||||
static bool read_lib_info(struct ps_prochandle* ph) {
|
||||
#if defined(__FreeBSD__) && __FreeBSD_version >= 701000
|
||||
struct kinfo_vmentry *freep, *kve;
|
||||
int i, cnt;
|
||||
|
||||
freep = kinfo_getvmmap(ph->pid, &cnt);
|
||||
if (freep == NULL) {
|
||||
print_debug("can't get vm map for pid\n", ph->pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
kve = &freep[i];
|
||||
if ((kve->kve_flags & KVME_FLAG_COW) &&
|
||||
kve->kve_path != NULL &&
|
||||
strlen(kve->kve_path) > 0) {
|
||||
|
||||
if (find_lib(ph, kve->kve_path) == false) {
|
||||
lib_info* lib;
|
||||
if ((lib = add_lib_info(ph, kve->kve_path,
|
||||
(uintptr_t) kve->kve_start)) == NULL)
|
||||
continue; // ignore, add_lib_info prints error
|
||||
|
||||
// we don't need to keep the library open, symtab is already
|
||||
// built. Only for core dump we need to keep the fd open.
|
||||
close(lib->fd);
|
||||
lib->fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(freep);
|
||||
|
||||
return true;
|
||||
#else
|
||||
char *l_name;
|
||||
struct link_map *lmap;
|
||||
uintptr_t lmap_addr;
|
||||
|
||||
if ((l_name = malloc(BUF_SIZE)) == NULL)
|
||||
return false;
|
||||
|
||||
if ((lmap = malloc(sizeof(*lmap))) == NULL) {
|
||||
free(l_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
lmap_addr = linkmap_addr(ph);
|
||||
|
||||
if (lmap_addr == 0) {
|
||||
free(l_name);
|
||||
free(lmap);
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
if (process_read_data(ph, lmap_addr, (char *)lmap, sizeof(*lmap)) != true) {
|
||||
print_debug("process_read_data failed for lmap_addr %p\n", lmap_addr);
|
||||
free (l_name);
|
||||
free (lmap);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (process_read_data(ph, (uintptr_t)lmap->l_name, l_name,
|
||||
BUF_SIZE) != true) {
|
||||
print_debug("process_read_data failed for lmap->l_name %p\n",
|
||||
lmap->l_name);
|
||||
free (l_name);
|
||||
free (lmap);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (find_lib(ph, l_name) == false) {
|
||||
lib_info* lib;
|
||||
if ((lib = add_lib_info(ph, l_name,
|
||||
(uintptr_t) lmap->l_addr)) == NULL)
|
||||
continue; // ignore, add_lib_info prints error
|
||||
|
||||
// we don't need to keep the library open, symtab is already
|
||||
// built. Only for core dump we need to keep the fd open.
|
||||
close(lib->fd);
|
||||
lib->fd = -1;
|
||||
}
|
||||
lmap_addr = (uintptr_t)lmap->l_next;
|
||||
} while (lmap->l_next != NULL);
|
||||
|
||||
free (l_name);
|
||||
free (lmap);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// detach a given pid
|
||||
static bool ptrace_detach(pid_t pid) {
|
||||
if (pid && ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) {
|
||||
print_debug("ptrace(PTRACE_DETACH, ..) failed for %d\n", pid);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_cleanup(struct ps_prochandle* ph) {
|
||||
ptrace_detach(ph->pid);
|
||||
}
|
||||
|
||||
static ps_prochandle_ops process_ops = {
|
||||
.release= process_cleanup,
|
||||
.p_pread= process_read_data,
|
||||
.p_pwrite= process_write_data,
|
||||
.get_lwp_regs= process_get_lwp_regs,
|
||||
.get_lwp_info= process_get_lwp_info
|
||||
};
|
||||
|
||||
// attach to the process. One and only one exposed stuff
|
||||
struct ps_prochandle* Pgrab(pid_t pid) {
|
||||
struct ps_prochandle* ph = NULL;
|
||||
thread_info* thr = NULL;
|
||||
|
||||
if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {
|
||||
print_debug("can't allocate memory for ps_prochandle\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ptrace_attach(pid) != true) {
|
||||
free(ph);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// initialize ps_prochandle
|
||||
ph->pid = pid;
|
||||
|
||||
// initialize vtable
|
||||
ph->ops = &process_ops;
|
||||
|
||||
// read library info and symbol tables, must do this before attaching threads,
|
||||
// as the symbols in the pthread library will be used to figure out
|
||||
// the list of threads within the same process.
|
||||
if (read_lib_info(ph) != true) {
|
||||
ptrace_detach(pid);
|
||||
free(ph);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read thread info
|
||||
read_thread_info(ph, add_new_thread);
|
||||
|
||||
return ph;
|
||||
}
|
126
hotspot/agent/src/os/bsd/salibelf.c
Normal file
126
hotspot/agent/src/os/bsd/salibelf.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2006, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "salibelf.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void print_debug(const char*,...);
|
||||
|
||||
// ELF file parsing helpers. Note that we do *not* use libelf here.
|
||||
int read_elf_header(int fd, ELF_EHDR* ehdr) {
|
||||
if (pread(fd, ehdr, sizeof (ELF_EHDR), 0) != sizeof (ELF_EHDR) ||
|
||||
memcmp(&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 ||
|
||||
ehdr->e_version != EV_CURRENT) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool is_elf_file(int fd) {
|
||||
ELF_EHDR ehdr;
|
||||
return read_elf_header(fd, &ehdr);
|
||||
}
|
||||
|
||||
// read program header table of an ELF file
|
||||
ELF_PHDR* read_program_header_table(int fd, ELF_EHDR* hdr) {
|
||||
ELF_PHDR* phbuf = 0;
|
||||
// allocate memory for program header table
|
||||
size_t nbytes = hdr->e_phnum * hdr->e_phentsize;
|
||||
|
||||
if ((phbuf = (ELF_PHDR*) malloc(nbytes)) == NULL) {
|
||||
print_debug("can't allocate memory for reading program header table\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pread(fd, phbuf, nbytes, hdr->e_phoff) != nbytes) {
|
||||
print_debug("ELF file is truncated! can't read program header table\n");
|
||||
free(phbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return phbuf;
|
||||
}
|
||||
|
||||
// read section header table of an ELF file
|
||||
ELF_SHDR* read_section_header_table(int fd, ELF_EHDR* hdr) {
|
||||
ELF_SHDR* shbuf = 0;
|
||||
// allocate memory for section header table
|
||||
size_t nbytes = hdr->e_shnum * hdr->e_shentsize;
|
||||
|
||||
if ((shbuf = (ELF_SHDR*) malloc(nbytes)) == NULL) {
|
||||
print_debug("can't allocate memory for reading section header table\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pread(fd, shbuf, nbytes, hdr->e_shoff) != nbytes) {
|
||||
print_debug("ELF file is truncated! can't read section header table\n");
|
||||
free(shbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return shbuf;
|
||||
}
|
||||
|
||||
// read a particular section's data
|
||||
void* read_section_data(int fd, ELF_EHDR* ehdr, ELF_SHDR* shdr) {
|
||||
void *buf = NULL;
|
||||
if (shdr->sh_type == SHT_NOBITS || shdr->sh_size == 0) {
|
||||
return buf;
|
||||
}
|
||||
if ((buf = calloc(shdr->sh_size, 1)) == NULL) {
|
||||
print_debug("can't allocate memory for reading section data\n");
|
||||
return NULL;
|
||||
}
|
||||
if (pread(fd, buf, shdr->sh_size, shdr->sh_offset) != shdr->sh_size) {
|
||||
free(buf);
|
||||
print_debug("section data read failed\n");
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
uintptr_t find_base_address(int fd, ELF_EHDR* ehdr) {
|
||||
uintptr_t baseaddr = (uintptr_t)-1;
|
||||
int cnt;
|
||||
ELF_PHDR *phbuf, *phdr;
|
||||
|
||||
// read program header table
|
||||
if ((phbuf = read_program_header_table(fd, ehdr)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
// the base address of a shared object is the lowest vaddr of
|
||||
// its loadable segments (PT_LOAD)
|
||||
for (phdr = phbuf, cnt = 0; cnt < ehdr->e_phnum; cnt++, phdr++) {
|
||||
if (phdr->p_type == PT_LOAD && phdr->p_vaddr < baseaddr) {
|
||||
baseaddr = phdr->p_vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
quit:
|
||||
if (phbuf) free(phbuf);
|
||||
return baseaddr;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -22,54 +22,31 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nt4internals.hpp"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#ifndef _SALIBELF_H_
|
||||
#define _SALIBELF_H_
|
||||
|
||||
namespace NT4 {
|
||||
#include <elf.h>
|
||||
#include "elfmacros.h"
|
||||
#include "libproc_impl.h"
|
||||
|
||||
static HMODULE ntDLL = NULL;
|
||||
// read ELF file header.
|
||||
int read_elf_header(int fd, ELF_EHDR* ehdr);
|
||||
|
||||
HMODULE loadNTDLL() {
|
||||
if (ntDLL == NULL) {
|
||||
ntDLL = LoadLibrary("NTDLL.DLL");
|
||||
}
|
||||
// is given file descriptor corresponds to an ELF file?
|
||||
bool is_elf_file(int fd);
|
||||
|
||||
assert(ntDLL != NULL);
|
||||
return ntDLL;
|
||||
}
|
||||
// read program header table of an ELF file. caller has to
|
||||
// free the result pointer after use. NULL on failure.
|
||||
ELF_PHDR* read_program_header_table(int fd, ELF_EHDR* hdr);
|
||||
|
||||
void unloadNTDLL() {
|
||||
if (ntDLL != NULL) {
|
||||
FreeLibrary(ntDLL);
|
||||
ntDLL = NULL;
|
||||
}
|
||||
}
|
||||
// read section header table of an ELF file. caller has to
|
||||
// free the result pointer after use. NULL on failure.
|
||||
ELF_SHDR* read_section_header_table(int fd, ELF_EHDR* hdr);
|
||||
|
||||
} // namespace NT4
|
||||
// read a particular section's data. caller has to free the
|
||||
// result pointer after use. NULL on failure.
|
||||
void* read_section_data(int fd, ELF_EHDR* ehdr, ELF_SHDR* shdr);
|
||||
|
||||
static HMODULE psapiDLL = NULL;
|
||||
|
||||
HMODULE
|
||||
loadPSAPIDLL() {
|
||||
if (psapiDLL == NULL) {
|
||||
psapiDLL = LoadLibrary("PSAPI.DLL");
|
||||
}
|
||||
|
||||
if (psapiDLL == NULL) {
|
||||
fprintf(stderr, "Simple Windows Debug Server requires PSAPI.DLL on Windows NT 4.0.\n");
|
||||
fprintf(stderr, "Please install this DLL from the SDK and restart the server.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return psapiDLL;
|
||||
}
|
||||
|
||||
void
|
||||
unloadPSAPIDLL() {
|
||||
if (psapiDLL != NULL) {
|
||||
FreeLibrary(psapiDLL);
|
||||
psapiDLL = NULL;
|
||||
}
|
||||
}
|
||||
// find the base address at which the library wants to load itself
|
||||
uintptr_t find_base_address(int fd, ELF_EHDR* ehdr);
|
||||
#endif /* _SALIBELF_H_ */
|
239
hotspot/agent/src/os/bsd/symtab.c
Normal file
239
hotspot/agent/src/os/bsd/symtab.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <search.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <db.h>
|
||||
#include <fcntl.h>
|
||||
#include "symtab.h"
|
||||
#include "salibelf.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
// functions for symbol lookups
|
||||
// ----------------------------------------------------
|
||||
|
||||
struct elf_section {
|
||||
ELF_SHDR *c_shdr;
|
||||
void *c_data;
|
||||
};
|
||||
|
||||
struct elf_symbol {
|
||||
char *name;
|
||||
uintptr_t offset;
|
||||
uintptr_t size;
|
||||
};
|
||||
|
||||
typedef struct symtab {
|
||||
char *strs;
|
||||
size_t num_symbols;
|
||||
struct elf_symbol *symbols;
|
||||
DB* hash_table;
|
||||
} symtab_t;
|
||||
|
||||
// read symbol table from given fd.
|
||||
struct symtab* build_symtab(int fd) {
|
||||
ELF_EHDR ehdr;
|
||||
struct symtab* symtab = NULL;
|
||||
|
||||
// Reading of elf header
|
||||
struct elf_section *scn_cache = NULL;
|
||||
int cnt = 0;
|
||||
ELF_SHDR* shbuf = NULL;
|
||||
ELF_SHDR* cursct = NULL;
|
||||
ELF_PHDR* phbuf = NULL;
|
||||
int symtab_found = 0;
|
||||
int dynsym_found = 0;
|
||||
uint32_t symsection = SHT_SYMTAB;
|
||||
|
||||
uintptr_t baseaddr = (uintptr_t)-1;
|
||||
|
||||
lseek(fd, (off_t)0L, SEEK_SET);
|
||||
if (! read_elf_header(fd, &ehdr)) {
|
||||
// not an elf
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read ELF header
|
||||
if ((shbuf = read_section_header_table(fd, &ehdr)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
baseaddr = find_base_address(fd, &ehdr);
|
||||
|
||||
scn_cache = calloc(ehdr.e_shnum, sizeof(*scn_cache));
|
||||
if (scn_cache == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) {
|
||||
scn_cache[cnt].c_shdr = cursct;
|
||||
if (cursct->sh_type == SHT_SYMTAB ||
|
||||
cursct->sh_type == SHT_STRTAB ||
|
||||
cursct->sh_type == SHT_DYNSYM) {
|
||||
if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursct->sh_type == SHT_SYMTAB)
|
||||
symtab_found++;
|
||||
|
||||
if (cursct->sh_type == SHT_DYNSYM)
|
||||
dynsym_found++;
|
||||
|
||||
cursct++;
|
||||
}
|
||||
|
||||
if (!symtab_found && dynsym_found)
|
||||
symsection = SHT_DYNSYM;
|
||||
|
||||
for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
|
||||
ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
|
||||
|
||||
if (shdr->sh_type == symsection) {
|
||||
ELF_SYM *syms;
|
||||
int j, n, rslt;
|
||||
size_t size;
|
||||
|
||||
// FIXME: there could be multiple data buffers associated with the
|
||||
// same ELF section. Here we can handle only one buffer. See man page
|
||||
// for elf_getdata on Solaris.
|
||||
|
||||
// guarantee(symtab == NULL, "multiple symtab");
|
||||
symtab = calloc(1, sizeof(*symtab));
|
||||
if (symtab == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
// the symbol table
|
||||
syms = (ELF_SYM *)scn_cache[cnt].c_data;
|
||||
|
||||
// number of symbols
|
||||
n = shdr->sh_size / shdr->sh_entsize;
|
||||
|
||||
// create hash table, we use berkeley db to
|
||||
// manipulate the hash table.
|
||||
symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);
|
||||
// guarantee(symtab->hash_table, "unexpected failure: dbopen");
|
||||
|
||||
// shdr->sh_link points to the section that contains the actual strings
|
||||
// for symbol names. the st_name field in ELF_SYM is just the
|
||||
// string table index. we make a copy of the string table so the
|
||||
// strings will not be destroyed by elf_end.
|
||||
size = scn_cache[shdr->sh_link].c_shdr->sh_size;
|
||||
symtab->strs = malloc(size);
|
||||
memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);
|
||||
|
||||
// allocate memory for storing symbol offset and size;
|
||||
symtab->num_symbols = n;
|
||||
symtab->symbols = calloc(n , sizeof(*symtab->symbols));
|
||||
|
||||
// copy symbols info our symtab and enter them info the hash table
|
||||
for (j = 0; j < n; j++, syms++) {
|
||||
DBT key, value;
|
||||
char *sym_name = symtab->strs + syms->st_name;
|
||||
|
||||
// skip non-object and non-function symbols
|
||||
int st_type = ELF_ST_TYPE(syms->st_info);
|
||||
if ( st_type != STT_FUNC && st_type != STT_OBJECT)
|
||||
continue;
|
||||
// skip empty strings and undefined symbols
|
||||
if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
|
||||
|
||||
symtab->symbols[j].name = sym_name;
|
||||
symtab->symbols[j].offset = syms->st_value - baseaddr;
|
||||
symtab->symbols[j].size = syms->st_size;
|
||||
|
||||
key.data = sym_name;
|
||||
key.size = strlen(sym_name) + 1;
|
||||
value.data = &(symtab->symbols[j]);
|
||||
value.size = sizeof(void *);
|
||||
(*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quit:
|
||||
if (shbuf) free(shbuf);
|
||||
if (phbuf) free(phbuf);
|
||||
if (scn_cache) {
|
||||
for (cnt = 0; cnt < ehdr.e_shnum; cnt++) {
|
||||
if (scn_cache[cnt].c_data != NULL) {
|
||||
free(scn_cache[cnt].c_data);
|
||||
}
|
||||
}
|
||||
free(scn_cache);
|
||||
}
|
||||
return symtab;
|
||||
}
|
||||
|
||||
void destroy_symtab(struct symtab* symtab) {
|
||||
if (!symtab) return;
|
||||
if (symtab->strs) free(symtab->strs);
|
||||
if (symtab->symbols) free(symtab->symbols);
|
||||
if (symtab->hash_table) {
|
||||
symtab->hash_table->close(symtab->hash_table);
|
||||
}
|
||||
free(symtab);
|
||||
}
|
||||
|
||||
uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
|
||||
const char *sym_name, int *sym_size) {
|
||||
DBT key, value;
|
||||
int ret;
|
||||
|
||||
// library does not have symbol table
|
||||
if (!symtab || !symtab->hash_table)
|
||||
return 0;
|
||||
|
||||
key.data = (char*)(uintptr_t)sym_name;
|
||||
key.size = strlen(sym_name) + 1;
|
||||
ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0);
|
||||
if (ret == 0) {
|
||||
struct elf_symbol *sym = value.data;
|
||||
uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
|
||||
if (sym_size) *sym_size = sym->size;
|
||||
return rslt;
|
||||
}
|
||||
|
||||
quit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
|
||||
uintptr_t* poffset) {
|
||||
int n = 0;
|
||||
if (!symtab) return NULL;
|
||||
for (; n < symtab->num_symbols; n++) {
|
||||
struct elf_symbol* sym = &(symtab->symbols[n]);
|
||||
if (sym->name != NULL &&
|
||||
offset >= sym->offset && offset < sym->offset + sym->size) {
|
||||
if (poffset) *poffset = (offset - sym->offset);
|
||||
return sym->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
50
hotspot/agent/src/os/bsd/symtab.h
Normal file
50
hotspot/agent/src/os/bsd/symtab.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, 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.
|
||||
*
|
||||
* 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 _SYMTAB_H_
|
||||
#define _SYMTAB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// interface to manage ELF symbol tables
|
||||
|
||||
struct symtab;
|
||||
|
||||
// build symbol table for a given ELF file descriptor
|
||||
struct symtab* build_symtab(int fd);
|
||||
|
||||
// destroy the symbol table
|
||||
void destroy_symtab(struct symtab* symtab);
|
||||
|
||||
// search for symbol in the given symbol table. Adds offset
|
||||
// to the base uintptr_t supplied. Returns NULL if not found.
|
||||
uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
|
||||
const char *sym_name, int *sym_size);
|
||||
|
||||
// look for nearest symbol for a given offset (not address - base
|
||||
// subtraction done by caller
|
||||
const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
|
||||
uintptr_t* poffset);
|
||||
|
||||
#endif /*_SYMTAB_H_*/
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -22,33 +22,38 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LOCKABLE_LIST_
|
||||
#define _LOCKABLE_LIST_
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "libproc.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "BasicList.hpp"
|
||||
int main(int argc, char** argv) {
|
||||
struct ps_prochandle* ph;
|
||||
|
||||
template<class T>
|
||||
class LockableList : public BasicList<T> {
|
||||
private:
|
||||
CRITICAL_SECTION crit;
|
||||
init_libproc(true);
|
||||
switch (argc) {
|
||||
case 2: {
|
||||
// process
|
||||
ph = Pgrab(atoi(argv[1]));
|
||||
break;
|
||||
}
|
||||
|
||||
public:
|
||||
LockableList() {
|
||||
InitializeCriticalSection(&crit);
|
||||
}
|
||||
case 3: {
|
||||
// core
|
||||
ph = Pgrab_core(argv[1], argv[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
~LockableList() {
|
||||
DeleteCriticalSection(&crit);
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "usage %s <pid> or %s <exec file> <core file>\n", argv[0], argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void lock() {
|
||||
EnterCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
LeaveCriticalSection(&crit);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // #defined _LOCKABLE_LIST_
|
||||
if (ph) {
|
||||
Prelease(ph);
|
||||
return 0;
|
||||
} else {
|
||||
printf("can't connect to debuggee\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -24,9 +24,7 @@
|
||||
|
||||
|
||||
all:
|
||||
cd dbx; $(MAKE) all
|
||||
cd proc; $(MAKE) all
|
||||
|
||||
clean:
|
||||
cd dbx; $(MAKE) clean
|
||||
cd proc; $(MAKE) clean
|
||||
|
@ -1,91 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2000, 2003, 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
# Targets are:
|
||||
# 32bit: Build the 32 bit version in ./32bit
|
||||
# 64bit: Build the 64 bit version in ./64bit
|
||||
# helloWorld: Build the helloWorld test program
|
||||
# all: Build all of the above. This is the default.
|
||||
#
|
||||
# NOTE: This makefile uses IOBuf.cpp, IOBuf.hpp, Buffer.cpp, and
|
||||
# Buffer.hpp from the src/os/win32/agent directory.
|
||||
|
||||
.PHONY: 32bit 64bit
|
||||
|
||||
ARCH_ORIG = $(shell uname -p)
|
||||
|
||||
# C++ := /java/devtools/$(ARCH_ORIG)/SUNWspro/SC6.1/bin/CC
|
||||
|
||||
C++ := CC
|
||||
RM := /usr/bin/rm
|
||||
MKDIRS := /usr/bin/mkdir -p
|
||||
|
||||
|
||||
WIN32_DIR := ../../win32
|
||||
ARCH := $(subst i386,i486,$(ARCH_ORIG))
|
||||
# INCLUDES := -I/net/sparcworks.eng/export/set/sparcworks5/dbx_62_intg/dev/src/dbx -I$(WIN32_DIR)
|
||||
INCLUDES := -I. -I$(WIN32_DIR)
|
||||
CFLAGS_32bit := -xarch=v8
|
||||
CFLAGS_64bit := -xarch=v9
|
||||
CFLAGS := -PIC -xO3 $(INCLUDES)
|
||||
LIBS := -lsocket -lnsl -lrtld_db
|
||||
LDFLAGS := -G
|
||||
|
||||
ifneq "$(ARCH)" "i486"
|
||||
CFLAGS += $(CFLAGS_$(VERSION))
|
||||
LDFLAGS += $(CFLAGS_$(VERSION))
|
||||
endif
|
||||
|
||||
# We use IOBuf.hpp, IOBuf.cpp, Buffer.hpp, and Buffer.cpp from the win32 dir.
|
||||
vpath %.cpp .:$(WIN32_DIR)
|
||||
vpath %.hpp .:$(WIN32_DIR)
|
||||
|
||||
OBJS = $(VERSION)/svc_agent_dbx.o $(VERSION)/IOBuf.o $(VERSION)/Buffer.o
|
||||
|
||||
|
||||
|
||||
# The default is to make both 32 bit and 64 bit versions.
|
||||
all:: 32bit 64bit
|
||||
|
||||
32bit 64bit::
|
||||
$(MKDIRS) $@
|
||||
$(MAKE) $@/libsvc_agent_dbx.so helloWorld VERSION=$@
|
||||
|
||||
$(VERSION)/IOBuf.o: IOBuf.hpp
|
||||
$(VERSION)/Buffer.o: Buffer.hpp
|
||||
$(VERSION)/svc_agent_dbx.o: svc_agent_dbx.hpp
|
||||
|
||||
$(VERSION)/%.o: %.cpp
|
||||
$(C++) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(VERSION)/libsvc_agent_dbx.so:: $(OBJS)
|
||||
$(C++) $(LDFLAGS) -o $(VERSION)/libsvc_agent_dbx.so $(OBJS) $(LIBS)
|
||||
|
||||
# Would be nice to move this into a shared directory
|
||||
helloWorld:: helloWorld.cpp
|
||||
$(C++) -g $< -o $@
|
||||
|
||||
clean::
|
||||
$(RM) -rf 32bit 64bit *.o helloWorld
|
@ -1,9 +0,0 @@
|
||||
shell_impl.h
|
||||
proc_service_2.h
|
||||
|
||||
The above files are captured from the dbx build environment.
|
||||
Rather then use a -I that points to stuff in .eng domain that
|
||||
may not be accessible in other domains these files are just
|
||||
copied here so local builds in other domains will work.
|
||||
These files rarely change so the fact that we might have to
|
||||
strobe in new ones on rare occasions is no big deal.
|
@ -1,82 +0,0 @@
|
||||
This import module uses a largely text-based protocol, except for
|
||||
certain bulk data transfer operations. All text is in single-byte
|
||||
US-ASCII.
|
||||
|
||||
Commands understood:
|
||||
|
||||
address_size ::= <int result>
|
||||
|
||||
Returns 32 if attached to 32-bit process, 64 if 64-bit.
|
||||
|
||||
peek_fail_fast <bool arg> ::=
|
||||
|
||||
Indicates whether "peek" requests should "fail fast"; that is, if
|
||||
any of the addresses in the requested range are unmapped, report
|
||||
the entire range as unmapped. This is substantially faster than
|
||||
the alternative, which is to read the entire range byte-by-byte.
|
||||
However, it should only be used when it is guaranteed by the
|
||||
client application that peeks come from at most one page. The
|
||||
default is that peek_fast_fail is not enabled.
|
||||
|
||||
peek <address addr> <unsigned int numBytes> ::=
|
||||
B<binary char success>
|
||||
[<binary unsigned int len> <binary char isMapped> [<binary char data>]...]...
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII letter 'B', allowing easier synchronization by
|
||||
clients. There is no data between the 'B' and the rest of the
|
||||
message.
|
||||
|
||||
May only be called once attached. Reads the address space of the
|
||||
target process starting at the given address (see below for format
|
||||
specifications) and extending the given number of bytes. Whether
|
||||
the read succeeded is indicated by a single byte containing a 1 or
|
||||
0 (success or failure). If successful, the return result is given
|
||||
in a sequence of ranges. _len_, the length of each range, is
|
||||
indicated by a 32-bit unsigned integer transmitted with big-endian
|
||||
byte ordering (i.e., most significant byte first). _isMapped_
|
||||
indicates whether the range is mapped or unmapped in the target
|
||||
process's address space, and will contain the value 1 or 0 for
|
||||
mapped or unmapped, respectively. If the range is mapped,
|
||||
_isMapped_ is followed by _data_, containing the raw binary data
|
||||
for the range. The sum of all ranges' lengths is guaranteed to be
|
||||
equivalent to the number of bytes requested.
|
||||
|
||||
poke <address addr> <int numBytes> B[<binary char data>]... ::= <bool result>
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII letter 'B', allowing easier synchronization by
|
||||
clients. There is no data between the 'B' and the rest of the
|
||||
message.
|
||||
|
||||
Writes the given data to the target process starting at the given
|
||||
address. Returns 1 on success, 0 on failure (i.e., one or more of
|
||||
target addresses were unmapped).
|
||||
|
||||
mapped <address addr> <int numBytes> ::= <bool result>
|
||||
|
||||
Returns 1 if entire address range [address...address + int arg) is
|
||||
mapped in target process's address space, 0 if not
|
||||
|
||||
lookup <symbol objName> <symbol sym> ::= <address addr>
|
||||
|
||||
First symbol is object name; second is symbol to be looked up.
|
||||
Looks up symbol in target process's symbol table and returns
|
||||
address. Returns NULL (0x0) if symbol is not found.
|
||||
|
||||
thr_gregs <int tid> ::= <int numAddresses> <address...>
|
||||
|
||||
Fetch the "general" (integer) register set for the given thread.
|
||||
Returned as a series of hexidecimal values. NOTE: the meaning of
|
||||
the return value is architecture-dependent. In general it is the
|
||||
contents of the prgregset_t.
|
||||
|
||||
exit ::=
|
||||
|
||||
Exits the serviceability agent dbx module, returning control to
|
||||
the dbx prompt.
|
||||
|
||||
// Data formats and example values:
|
||||
<address> ::= 0x12345678[9ABCDEF0] /* up to 64-bit hex value */
|
||||
<unsigned int> ::= 5 /* up to 32-bit integer number; no leading sign */
|
||||
<bool> ::= 1 /* ASCII '0' or '1' */
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
extern "C" {
|
||||
const char* helloWorldString = "Hello, world!";
|
||||
// Do not change these values without changing TestDebugger.java as well
|
||||
// FIXME: should make these jbyte, jshort, etc...
|
||||
volatile int8_t testByte = 132;
|
||||
volatile int16_t testShort = 27890;
|
||||
volatile int32_t testInt = 1020304050;
|
||||
volatile int64_t testLong = 102030405060708090LL;
|
||||
volatile float testFloat = 35.4F;
|
||||
volatile double testDouble = 1.23456789;
|
||||
|
||||
volatile int helloWorldTrigger = 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int, char**) {
|
||||
while (1) {
|
||||
while (helloWorldTrigger == 0) {
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\n", helloWorldString);
|
||||
fprintf(stderr, "testByte=%d\n", testByte);
|
||||
fprintf(stderr, "testShort=%d\n", testShort);
|
||||
fprintf(stderr, "testInt=%d\n", testInt);
|
||||
fprintf(stderr, "testLong=%d\n", testLong);
|
||||
fprintf(stderr, "testFloat=%d\n", testFloat);
|
||||
fprintf(stderr, "testDouble=%d\n", testDouble);
|
||||
|
||||
while (helloWorldTrigger != 0) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.
|
||||
*
|
||||
* 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 _PROC_SERVICE_2_H
|
||||
#define _PROC_SERVICE_2_H
|
||||
|
||||
/*
|
||||
* Types, function definitions for the provider of services beyond
|
||||
* proc_service. This interface will be used by import modules like
|
||||
* BAT/prex, NEO debugger etc.
|
||||
*/
|
||||
|
||||
/*
|
||||
CCR info
|
||||
|
||||
Version history:
|
||||
|
||||
1.0 - Initial CCR release
|
||||
|
||||
1.1 - Changes for GLUE/neo.
|
||||
New entry points ps_svnt_generic() and ps_svc_generic()
|
||||
- New entry point ps_getpid()
|
||||
|
||||
Release information for automatic CCR updates:
|
||||
BEGIN RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
1.2 - Changes to support Solaris 2.7
|
||||
|
||||
END RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
|
||||
Following is used for CCR version number:
|
||||
|
||||
#define CCR_PROC_SERVICE_2_VERSION 1.2
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <proc_service.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ps_loadobj {
|
||||
int objfd; /* fd of the load object or executable
|
||||
* -1 implies its not available.
|
||||
* This file decriptor is live only during the
|
||||
* particular call to ps_iter_f(). If you
|
||||
* need it beyond that you need to dup() it.
|
||||
*/
|
||||
psaddr_t
|
||||
text_base; /* address where text of loadobj was mapped */
|
||||
psaddr_t
|
||||
data_base; /* address where data of loadobj was mapped */
|
||||
const char *objname; /* loadobj name */
|
||||
};
|
||||
|
||||
typedef int ps_iter_f(const struct ps_prochandle *, const struct ps_loadobj *,
|
||||
void *cd);
|
||||
|
||||
/*
|
||||
* Returns the ps_prochandle for the current process under focus. Returns
|
||||
* NULL if there is none.
|
||||
*/
|
||||
|
||||
const struct ps_prochandle *
|
||||
ps_get_prochandle(void);
|
||||
|
||||
/*
|
||||
* Returns the ps_prochandle for the current process(allows core files to
|
||||
* be specified) under focus. Returns NULL if there is none.
|
||||
*/
|
||||
const struct ps_prochandle *
|
||||
ps_get_prochandle2(int cores_too);
|
||||
|
||||
/*
|
||||
* Returns the pid of the process referred to by the ps_prochandle.
|
||||
*
|
||||
* 0 is returned in case the ps_prochandle is not valid or refers to dead
|
||||
* process.
|
||||
*
|
||||
*/
|
||||
pid_t
|
||||
ps_getpid(const struct ps_prochandle *);
|
||||
|
||||
/*
|
||||
* Iteration function that iterates over all load objects *and the
|
||||
* executable*
|
||||
*
|
||||
* If the callback routine returns:
|
||||
* 0 - continue processing link objects
|
||||
* non zero - stop calling the callback function
|
||||
*
|
||||
*/
|
||||
|
||||
ps_err_e
|
||||
ps_loadobj_iter(const struct ps_prochandle *, ps_iter_f *, void *clnt_data);
|
||||
|
||||
/*
|
||||
* Address => function name mapping
|
||||
*
|
||||
* Given an address, returns a pointer to the function's
|
||||
* linker name (null terminated).
|
||||
*/
|
||||
|
||||
ps_err_e
|
||||
ps_find_fun_name(const struct ps_prochandle *, psaddr_t addr,
|
||||
const char **name);
|
||||
|
||||
/*
|
||||
* Interface to LD_PRELOAD. LD_PRELOAD given library across the
|
||||
* program 'exec'.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Append/Prepend the 'lib' (has to be library name as understood by LD_PRELOAD)
|
||||
* to the LD_PRELOAD variable setting to be used by the debugee
|
||||
* Returns a cookie (in id).
|
||||
*/
|
||||
ps_err_e
|
||||
ps_ld_preload_append(const char *lib, int *id);
|
||||
ps_err_e
|
||||
ps_ld_preload_prepend(const char *lib, int *id);
|
||||
|
||||
/*
|
||||
* Remove the library associated with 'id' from the LD_PRELOAD setting.
|
||||
*
|
||||
*/
|
||||
ps_err_e
|
||||
ps_ld_preload_remove(int id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following are C++ only interfaces
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
/*
|
||||
* classes ServiceDbx and ServantDbx and defined in "gp_dbx_svc.h" which is
|
||||
* accessed via CCR
|
||||
*/
|
||||
extern class ServantDbx *ps_svnt_generic();
|
||||
extern class ServiceDbx *ps_svc_generic();
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _PROC_SERVICE_2_H */
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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 SHELL_IMP_H
|
||||
#define SHELL_IMP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
CCR info
|
||||
|
||||
Vesrion history:
|
||||
|
||||
1.0 - Initial CCR release
|
||||
|
||||
Release information for automatic CCR updates:
|
||||
|
||||
BEGIN RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
1.1
|
||||
- Entry points for va_list style msgs; new shell_imp_vmsg()
|
||||
and shell_imp_verrmsg()
|
||||
- shell_imp_env_checker() is now shell_imp_var_checker().
|
||||
Also the var_checker callback gets passed interp.
|
||||
1.2 - interposition framework (used by jdbx)
|
||||
- access to input FILE pointer.
|
||||
|
||||
END RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
|
||||
Following is used as a CCR version number:
|
||||
#define CCR_SHELL_IMP_VERSION 1.1
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SHELL_IMP_MAJOR 1
|
||||
#define SHELL_IMP_MINOR 2
|
||||
#define SHELL_IMP_FLAG_GLOB 0x1
|
||||
#define SHELL_IMP_FLAG_ARGQ 0x2
|
||||
|
||||
typedef void *shell_imp_interp_t;
|
||||
typedef void *shell_imp_command_t;
|
||||
typedef int shell_imp_fun_t(shell_imp_interp_t, int, char **, void *);
|
||||
|
||||
int
|
||||
shell_imp_init(
|
||||
int, /* major version number */
|
||||
int, /* minor version number */
|
||||
shell_imp_interp_t, /* interpreter */
|
||||
int, /* argc */
|
||||
char *[] /* argv */
|
||||
);
|
||||
|
||||
int
|
||||
shell_imp_fini(shell_imp_interp_t);
|
||||
|
||||
shell_imp_command_t
|
||||
shell_imp_define_command(char *, /* command name e.g. "tnf" */
|
||||
shell_imp_fun_t *, /* callback function */
|
||||
int, /* SHELL_IMP_FLAG_* bit vector */
|
||||
void *, /* client_data Passed as last arg to
|
||||
/* callback function */
|
||||
char * /* help message, e.g. */
|
||||
/* "enable the specified tnf probes" */
|
||||
);
|
||||
|
||||
int
|
||||
shell_imp_undefine_command(shell_imp_command_t);
|
||||
|
||||
int
|
||||
shell_imp_var_checker(shell_imp_interp_t,
|
||||
const char *, /* var name */
|
||||
int (*)(shell_imp_interp_t, const char*) /* env checker */
|
||||
);
|
||||
|
||||
int
|
||||
shell_imp_execute(shell_imp_interp_t, const char *);
|
||||
|
||||
const char *
|
||||
shell_imp_get_var(shell_imp_interp_t, const char *);
|
||||
|
||||
void
|
||||
shell_imp_msg(shell_imp_interp_t, const char *, ...);
|
||||
|
||||
void
|
||||
shell_imp_errmsg(shell_imp_interp_t, const char *, ...);
|
||||
|
||||
void
|
||||
shell_imp_vmsg(shell_imp_interp_t, const char *, va_list);
|
||||
|
||||
void
|
||||
shell_imp_verrmsg(shell_imp_interp_t, const char *, va_list);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Stuff added for 1.2
|
||||
*/
|
||||
|
||||
struct shell_imp_interposition_info_t {
|
||||
shell_imp_fun_t *
|
||||
new_func;
|
||||
void * new_client_data;
|
||||
shell_imp_fun_t *
|
||||
original_func;
|
||||
void * original_client_data;
|
||||
int original_flags;
|
||||
};
|
||||
|
||||
typedef int shell_imp_dispatcher_t(shell_imp_interp_t, int, char **,
|
||||
shell_imp_interposition_info_t *);
|
||||
|
||||
shell_imp_command_t
|
||||
shell_imp_interpose(char *name,
|
||||
shell_imp_fun_t *new_func,
|
||||
int flags,
|
||||
void *client_data,
|
||||
char * description,
|
||||
shell_imp_dispatcher_t *);
|
||||
|
||||
int shell_imp_uninterpose(shell_imp_command_t);
|
||||
|
||||
int
|
||||
shell_imp_dispatch_interposition(shell_imp_interp_t,
|
||||
shell_imp_interposition_info_t *,
|
||||
int argc, char *argv[]);
|
||||
|
||||
int
|
||||
shell_imp_dispatch_original(shell_imp_interp_t,
|
||||
shell_imp_interposition_info_t *,
|
||||
int argc, char *argv[]);
|
||||
|
||||
FILE *
|
||||
shell_imp_cur_input(shell_imp_interp_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shell_imp.h"
|
||||
#include "IOBuf.hpp"
|
||||
#include <sys/time.h>
|
||||
#include <thread_db.h>
|
||||
|
||||
typedef td_err_e td_init_fn_t();
|
||||
typedef td_err_e td_ta_new_fn_t(struct ps_prochandle *, td_thragent_t **);
|
||||
typedef td_err_e td_ta_delete_fn_t(td_thragent_t *);
|
||||
typedef td_err_e td_ta_map_id2thr_fn_t(const td_thragent_t *, thread_t, td_thrhandle_t *);
|
||||
typedef td_err_e td_thr_getgregs_fn_t(const td_thrhandle_t *, prgregset_t);
|
||||
|
||||
class ServiceabilityAgentDbxModule {
|
||||
public:
|
||||
ServiceabilityAgentDbxModule(int major, int minor,
|
||||
shell_imp_interp_t interp, int argc, char *argv[]);
|
||||
~ServiceabilityAgentDbxModule();
|
||||
|
||||
bool install();
|
||||
bool uninstall();
|
||||
|
||||
/* This is invoked through the dbx command interpreter. It listens
|
||||
on a socket for commands and does not return until it receives an
|
||||
"exit" command. At that point control is returned to dbx's main
|
||||
loop, at which point if the user sends an exit command to dbx's
|
||||
shell the dbx process will exit. Returns true if completed
|
||||
successfully, false if an error occurred while running (for
|
||||
example, unable to bind listening socket). */
|
||||
bool run();
|
||||
|
||||
private:
|
||||
|
||||
// This must be shared between the Java and C layers
|
||||
static const int PORT = 21928;
|
||||
|
||||
// Command handlers
|
||||
bool handleAddressSize(char* data);
|
||||
bool handlePeekFailFast(char* data);
|
||||
bool handlePeek(char* data);
|
||||
bool handlePoke(char* data);
|
||||
bool handleMapped(char* data);
|
||||
bool handleLookup(char* data);
|
||||
bool handleThrGRegs(char* data);
|
||||
|
||||
// Input routines
|
||||
|
||||
// May mutate addr argument even if result is false
|
||||
bool scanAddress(char** data, psaddr_t* addr);
|
||||
// May mutate num argument even if result is false
|
||||
bool scanUnsignedInt(char** data, unsigned int* num);
|
||||
// Returns NULL if error occurred while scanning. Otherwise, returns
|
||||
// newly-allocated character array which must be freed with delete[].
|
||||
char* scanSymbol(char** data);
|
||||
// Helper routine: converts ASCII to 4-bit integer. Returns true if
|
||||
// character is in range, false otherwise.
|
||||
bool charToNibble(char ascii, int* value);
|
||||
|
||||
// Output routines
|
||||
|
||||
// Writes an int with no leading or trailing spaces
|
||||
bool writeInt(int val, int fd);
|
||||
// Writes an address in hex format with no leading or trailing
|
||||
// spaces
|
||||
bool writeAddress(psaddr_t addr, int fd);
|
||||
// Writes a register in hex format with no leading or trailing
|
||||
// spaces (addresses and registers might be of different size)
|
||||
bool writeRegister(prgreg_t reg, int fd);
|
||||
// Writes a space to given file descriptor
|
||||
bool writeSpace(int fd);
|
||||
// Writes carriage return to given file descriptor
|
||||
bool writeCR(int fd);
|
||||
// Writes a bool as [0|1]
|
||||
bool writeBoolAsInt(bool val, int fd);
|
||||
// Helper routine: converts low 4 bits to ASCII [0..9][A..F]
|
||||
char nibbleToChar(unsigned char nibble);
|
||||
|
||||
// Base routine called by most of the above
|
||||
bool writeString(const char* str, int fd);
|
||||
|
||||
// Writes a binary character
|
||||
bool writeBinChar(char val, int fd);
|
||||
// Writes a binary unsigned int in network (big-endian) byte order
|
||||
bool writeBinUnsignedInt(unsigned int val, int fd);
|
||||
// Writes a binary buffer
|
||||
bool writeBinBuf(char* buf, int size, int fd);
|
||||
|
||||
// Routine to flush the socket
|
||||
bool flush(int client_socket);
|
||||
|
||||
void cleanup(int client_socket);
|
||||
|
||||
// The shell interpreter on which we can invoke commands (?)
|
||||
shell_imp_interp_t _interp;
|
||||
|
||||
// The "command line" arguments passed to us by dbx (?)
|
||||
int _argc;
|
||||
char **_argv;
|
||||
|
||||
// The installed command in the dbx shell
|
||||
shell_imp_command_t _command;
|
||||
|
||||
// Access to libthread_db (dlsym'ed to be able to pick up the
|
||||
// version loaded by dbx)
|
||||
td_init_fn_t* td_init_fn;
|
||||
td_ta_new_fn_t* td_ta_new_fn;
|
||||
td_ta_delete_fn_t* td_ta_delete_fn;
|
||||
td_ta_map_id2thr_fn_t* td_ta_map_id2thr_fn;
|
||||
td_thr_getgregs_fn_t* td_thr_getgregs_fn;
|
||||
|
||||
// Our "thread agent" -- access to libthread_db
|
||||
td_thragent_t* _tdb_agent;
|
||||
|
||||
// Path to libthread.so in target process; free with delete[]
|
||||
char* libThreadName;
|
||||
|
||||
// Handle to dlopen'ed libthread_db.so
|
||||
void* libThreadDB;
|
||||
|
||||
// Helper callback for finding libthread_db.so
|
||||
friend int findLibThreadCB(const rd_loadobj_t* lo, void* data);
|
||||
|
||||
// Support for reading C strings out of the target process (so we
|
||||
// can find the correct libthread_db). Returns newly-allocated char*
|
||||
// which must be freed with delete[], or null if the read failed.
|
||||
char* readCStringFromProcess(psaddr_t addr);
|
||||
|
||||
IOBuf myComm;
|
||||
|
||||
// Output buffer support (used by writeString, writeChar, flush)
|
||||
char* output_buffer;
|
||||
int output_buffer_size;
|
||||
int output_buffer_pos;
|
||||
|
||||
// "Fail fast" flag
|
||||
bool peek_fail_fast;
|
||||
|
||||
// Commands
|
||||
static const char* CMD_ADDRESS_SIZE;
|
||||
static const char* CMD_PEEK_FAIL_FAST;
|
||||
static const char* CMD_PEEK;
|
||||
static const char* CMD_POKE;
|
||||
static const char* CMD_MAPPED;
|
||||
static const char* CMD_LOOKUP;
|
||||
static const char* CMD_THR_GREGS;
|
||||
static const char* CMD_EXIT;
|
||||
};
|
||||
|
||||
// For profiling. Times reported are in milliseconds.
|
||||
class Timer {
|
||||
public:
|
||||
Timer();
|
||||
~Timer();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
long total();
|
||||
long average();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
struct timeval startTime;
|
||||
long long totalMicroseconds; // stored internally in microseconds
|
||||
int counter;
|
||||
long long timevalDiff(struct timeval* startTime, struct timeval* endTime);
|
||||
};
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Buffer.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
Buffer::Buffer(int bufSize) {
|
||||
buf = new char[bufSize];
|
||||
sz = bufSize;
|
||||
fill = 0;
|
||||
drain = 0;
|
||||
}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
char*
|
||||
Buffer::fillPos() {
|
||||
return buf + fill;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::remaining() {
|
||||
return sz - fill;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::size() {
|
||||
return sz;
|
||||
}
|
||||
|
||||
bool
|
||||
Buffer::incrFillPos(int amt) {
|
||||
if (fill + amt >= sz) {
|
||||
return false;
|
||||
}
|
||||
fill += amt;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::readByte() {
|
||||
if (drain < fill) {
|
||||
return buf[drain++] & 0xFF;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::readBytes(char* data, int len) {
|
||||
int numRead = 0;
|
||||
while (numRead < len) {
|
||||
int c = readByte();
|
||||
if (c < 0) break;
|
||||
data[numRead++] = (char) c;
|
||||
}
|
||||
return numRead;
|
||||
}
|
||||
|
||||
char*
|
||||
Buffer::drainPos() {
|
||||
return buf + drain;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::drainRemaining() {
|
||||
return fill - drain;
|
||||
}
|
||||
|
||||
bool
|
||||
Buffer::incrDrainPos(int amt) {
|
||||
if (drainRemaining() < amt) {
|
||||
return false;
|
||||
}
|
||||
drain += amt;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Buffer::compact() {
|
||||
// Copy down data
|
||||
memmove(buf, buf + drain, fill - drain);
|
||||
// Adjust positions
|
||||
fill -= drain;
|
||||
drain = 0;
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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 _BUFFER_
|
||||
#define _BUFFER_
|
||||
|
||||
// A Buffer is the backing store for the IOBuf abstraction and
|
||||
// supports producer-consumer filling and draining.
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
Buffer(int bufSize);
|
||||
~Buffer();
|
||||
|
||||
char* fillPos(); // Position of the place where buffer should be filled
|
||||
int remaining(); // Number of bytes that can be placed starting at fillPos
|
||||
int size(); // Size of the buffer
|
||||
// Move up fill position by amount (decreases remaining()); returns
|
||||
// false if not enough space
|
||||
bool incrFillPos(int amt);
|
||||
|
||||
// Read single byte (0..255); returns -1 if no data available.
|
||||
int readByte();
|
||||
// Read multiple bytes, non-blocking (this buffer does not define a
|
||||
// fill mechanism), into provided buffer. Returns number of bytes read.
|
||||
int readBytes(char* buf, int len);
|
||||
|
||||
// Access to drain position. Be very careful using this.
|
||||
char* drainPos();
|
||||
int drainRemaining();
|
||||
bool incrDrainPos(int amt);
|
||||
|
||||
// Compact buffer, removing already-consumed input. This must be
|
||||
// called periodically to yield the illusion of an infinite buffer.
|
||||
void compact();
|
||||
|
||||
private:
|
||||
Buffer(const Buffer&);
|
||||
Buffer& operator=(const Buffer&);
|
||||
|
||||
char* buf;
|
||||
int sz;
|
||||
int fill;
|
||||
int drain;
|
||||
};
|
||||
|
||||
#endif // #defined _BUFFER_
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dispatcher.hpp"
|
||||
|
||||
const char* CMD_ASCII = "ascii";
|
||||
const char* CMD_UNICODE = "unicode";
|
||||
const char* CMD_PROCLIST = "proclist";
|
||||
const char* CMD_ATTACH = "attach";
|
||||
const char* CMD_DETACH = "detach";
|
||||
const char* CMD_LIBINFO = "libinfo";
|
||||
const char* CMD_PEEK = "peek";
|
||||
const char* CMD_POKE = "poke";
|
||||
const char* CMD_THREADLIST = "threadlist";
|
||||
const char* CMD_DUPHANDLE = "duphandle";
|
||||
const char* CMD_CLOSEHANDLE = "closehandle";
|
||||
const char* CMD_GETCONTEXT = "getcontext";
|
||||
const char* CMD_SETCONTEXT = "setcontext";
|
||||
const char* CMD_SELECTORENTRY = "selectorentry";
|
||||
const char* CMD_SUSPEND = "suspend";
|
||||
const char* CMD_RESUME = "resume";
|
||||
const char* CMD_POLLEVENT = "pollevent";
|
||||
const char* CMD_CONTINUEEVENT = "continueevent";
|
||||
const char* CMD_EXIT = "exit";
|
||||
|
||||
// Uncomment the #define below to get messages on stderr
|
||||
// #define DEBUGGING
|
||||
|
||||
void
|
||||
Dispatcher::dispatch(char* cmd, Handler* handler) {
|
||||
if (!strncmp(cmd, CMD_ASCII, strlen(CMD_ASCII))) {
|
||||
handler->ascii(cmd + strlen(CMD_ASCII));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_UNICODE, strlen(CMD_UNICODE))) {
|
||||
handler->unicode(cmd + strlen(CMD_UNICODE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_PROCLIST, strlen(CMD_PROCLIST))) {
|
||||
handler->procList(cmd + strlen(CMD_PROCLIST));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_ATTACH, strlen(CMD_ATTACH))) {
|
||||
handler->attach(cmd + strlen(CMD_ATTACH));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_DETACH, strlen(CMD_DETACH))) {
|
||||
handler->detach(cmd + strlen(CMD_DETACH));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_LIBINFO, strlen(CMD_LIBINFO))) {
|
||||
handler->libInfo(cmd + strlen(CMD_LIBINFO));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_PEEK, strlen(CMD_PEEK))) {
|
||||
handler->peek(cmd + strlen(CMD_PEEK));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_POKE, strlen(CMD_POKE))) {
|
||||
handler->poke(cmd + strlen(CMD_POKE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_THREADLIST, strlen(CMD_THREADLIST))) {
|
||||
handler->threadList(cmd + strlen(CMD_THREADLIST));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_DUPHANDLE, strlen(CMD_DUPHANDLE))) {
|
||||
handler->dupHandle(cmd + strlen(CMD_DUPHANDLE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_CLOSEHANDLE, strlen(CMD_CLOSEHANDLE))) {
|
||||
handler->closeHandle(cmd + strlen(CMD_CLOSEHANDLE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_GETCONTEXT, strlen(CMD_GETCONTEXT))) {
|
||||
handler->getContext(cmd + strlen(CMD_GETCONTEXT));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_SETCONTEXT, strlen(CMD_SETCONTEXT))) {
|
||||
handler->setContext(cmd + strlen(CMD_SETCONTEXT));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_SELECTORENTRY, strlen(CMD_SELECTORENTRY))) {
|
||||
handler->selectorEntry(cmd + strlen(CMD_SELECTORENTRY));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_SUSPEND, strlen(CMD_SUSPEND))) {
|
||||
handler->suspend(cmd + strlen(CMD_SUSPEND));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_RESUME, strlen(CMD_RESUME))) {
|
||||
handler->resume(cmd + strlen(CMD_RESUME));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_POLLEVENT, strlen(CMD_POLLEVENT))) {
|
||||
handler->pollEvent(cmd + strlen(CMD_POLLEVENT));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_CONTINUEEVENT, strlen(CMD_CONTINUEEVENT))) {
|
||||
handler->continueEvent(cmd + strlen(CMD_CONTINUEEVENT));
|
||||
|
||||
} else if (!strcmp(cmd, CMD_EXIT)) {
|
||||
handler->exit(cmd + strlen(CMD_EXIT));
|
||||
}
|
||||
|
||||
#ifdef DEBUGGING
|
||||
else fprintf(stderr, "Ignoring illegal command \"%s\"\n", cmd);
|
||||
#endif
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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.
|
||||
*
|
||||
* 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 _HANDLER_
|
||||
#define _HANDLER_
|
||||
|
||||
/** An abstract base class encapsulating the handlers for all commands
|
||||
understood by the system. */
|
||||
class Handler {
|
||||
public:
|
||||
virtual void ascii(char* arg) = 0;
|
||||
virtual void unicode(char* arg) = 0;
|
||||
virtual void procList(char* arg) = 0;
|
||||
virtual void attach(char* arg) = 0;
|
||||
virtual void detach(char* arg) = 0;
|
||||
virtual void libInfo(char* arg) = 0;
|
||||
virtual void peek(char* arg) = 0;
|
||||
virtual void poke(char* arg) = 0;
|
||||
virtual void threadList(char* arg) = 0;
|
||||
virtual void dupHandle(char* arg) = 0;
|
||||
virtual void closeHandle(char* arg) = 0;
|
||||
virtual void getContext(char* arg) = 0;
|
||||
virtual void setContext(char* arg) = 0;
|
||||
virtual void selectorEntry(char* arg) = 0;
|
||||
virtual void suspend(char* arg) = 0;
|
||||
virtual void resume(char* arg) = 0;
|
||||
virtual void pollEvent(char* arg) = 0;
|
||||
virtual void continueEvent(char* arg) = 0;
|
||||
virtual void exit(char* arg) = 0;
|
||||
};
|
||||
|
||||
#endif // #defined _HANDLER_
|
@ -1,490 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2003, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// This file is currently used for os/solaris/agent too. At some point in time
|
||||
// the source will be reorganized to avoid these ifdefs.
|
||||
|
||||
#ifdef __sun
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/byteorder.h>
|
||||
#endif
|
||||
|
||||
#include "IOBuf.hpp"
|
||||
|
||||
// Formats for printing pointers
|
||||
#ifdef _LP64
|
||||
# define INTPTR_FORMAT "0x%016lx"
|
||||
#else /* ! _LP64 */
|
||||
# define INTPTR_FORMAT "0x%08lx"
|
||||
#endif /* _LP64 */
|
||||
|
||||
// Uncomment the #define below to get messages on stderr
|
||||
// #define DEBUGGING
|
||||
|
||||
IOBuf::IOBuf(int inLen, int outLen) {
|
||||
inBuf = new Buffer(inLen);
|
||||
outBuf = new Buffer(outLen);
|
||||
fd = INVALID_SOCKET;
|
||||
outHandle = NULL;
|
||||
usingSocket = true;
|
||||
reset();
|
||||
}
|
||||
|
||||
IOBuf::~IOBuf() {
|
||||
delete inBuf;
|
||||
delete outBuf;
|
||||
}
|
||||
|
||||
void
|
||||
IOBuf::setSocket(SOCKET sock) {
|
||||
fd = sock;
|
||||
usingSocket = true;
|
||||
}
|
||||
|
||||
// Reading/writing files is only needed and used on windows.
|
||||
#ifdef WIN32
|
||||
void
|
||||
IOBuf::setOutputFileHandle(HANDLE handle) {
|
||||
outHandle = handle;
|
||||
usingSocket = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
IOBuf::reset() {
|
||||
gotDataLastTime = false;
|
||||
state = TEXT_STATE;
|
||||
binPos = 0;
|
||||
binLength = 0;
|
||||
}
|
||||
|
||||
IOBuf::ReadLineResult
|
||||
IOBuf::tryReadLine() {
|
||||
return doReadLine(false);
|
||||
}
|
||||
|
||||
char*
|
||||
IOBuf::readLine() {
|
||||
ReadLineResult rr = doReadLine(true);
|
||||
if (rr != RL_GOT_DATA) {
|
||||
return NULL;
|
||||
}
|
||||
return getLine();
|
||||
}
|
||||
|
||||
IOBuf::ReadLineResult
|
||||
IOBuf::doReadLine(bool shouldWait) {
|
||||
|
||||
if (!usingSocket) {
|
||||
return IOBuf::RL_ERROR;
|
||||
}
|
||||
|
||||
if (gotDataLastTime) {
|
||||
curLine.clear();
|
||||
}
|
||||
|
||||
int c;
|
||||
do {
|
||||
c = readChar(shouldWait);
|
||||
if (c >= 0) {
|
||||
Action act = processChar((char) c);
|
||||
if (act == GOT_LINE) {
|
||||
curLine.push_back('\0');
|
||||
gotDataLastTime = true;
|
||||
return IOBuf::RL_GOT_DATA;
|
||||
} else if (act == SKIP_EOL_CHAR) {
|
||||
// Do nothing
|
||||
} else {
|
||||
curLine.push_back((char) c);
|
||||
}
|
||||
}
|
||||
} while (shouldWait || c >= 0);
|
||||
|
||||
gotDataLastTime = false;
|
||||
return IOBuf::RL_NO_DATA;
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::flushImpl(bool moreDataToCome) {
|
||||
int numWritten = 0;
|
||||
|
||||
#ifdef WIN32
|
||||
// When running on Windows and using IOBufs for inter-process
|
||||
// communication, we need to write metadata into the stream
|
||||
// indicating how many bytes are coming down. Five bytes are written
|
||||
// per flush() call, four containing the integer number of bytes
|
||||
// coming (not including the five-byte header) and one (a 0 or 1)
|
||||
// indicating whether there is more data coming.
|
||||
if (!usingSocket) {
|
||||
int numToWrite = outBuf->drainRemaining();
|
||||
char moreToCome = (moreDataToCome ? 1 : 0);
|
||||
DWORD numBytesWritten;
|
||||
if (!WriteFile(outHandle, &numToWrite, sizeof(int), &numBytesWritten, NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (numBytesWritten != sizeof(int)) {
|
||||
return false;
|
||||
}
|
||||
if (!WriteFile(outHandle, &moreToCome, 1, &numBytesWritten, NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (numBytesWritten != 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while (outBuf->drainRemaining() != 0) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Flushing %d bytes\n", outBuf->drainRemaining());
|
||||
#endif
|
||||
if (usingSocket) {
|
||||
numWritten = send(fd, outBuf->drainPos(), outBuf->drainRemaining(), 0);
|
||||
} else {
|
||||
#ifdef WIN32
|
||||
DWORD numBytesWritten;
|
||||
if (!WriteFile(outHandle, outBuf->drainPos(), outBuf->drainRemaining(), &numBytesWritten, NULL)) {
|
||||
numWritten = -1;
|
||||
} else {
|
||||
numWritten = numBytesWritten;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (numWritten != -1) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Flushed %d bytes\n", numWritten);
|
||||
#endif
|
||||
outBuf->incrDrainPos(numWritten);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
outBuf->compact();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
IOBuf::readChar(bool block) {
|
||||
do {
|
||||
int c = inBuf->readByte();
|
||||
if (c >= 0) {
|
||||
return c;
|
||||
}
|
||||
// See whether we need to compact the input buffer
|
||||
if (inBuf->remaining() < inBuf->size() / 2) {
|
||||
inBuf->compact();
|
||||
}
|
||||
// See whether socket is ready
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
if (block || select(1 + fd, &fds, NULL, NULL, &timeout) > 0) {
|
||||
if (block || FD_ISSET(fd, &fds)) {
|
||||
#ifdef DEBUGGING
|
||||
int b = (block ? 1 : 0);
|
||||
fprintf(stderr, "calling recv: block = %d\n", b);
|
||||
#endif
|
||||
// Read data from socket
|
||||
int numRead = recv(fd, inBuf->fillPos(), inBuf->remaining(), 0);
|
||||
if (numRead < 0) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "recv failed\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
inBuf->incrFillPos(numRead);
|
||||
}
|
||||
}
|
||||
} while (block);
|
||||
|
||||
return inBuf->readByte();
|
||||
}
|
||||
|
||||
char*
|
||||
IOBuf::getLine() {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Returning (first 10 chars) \"%.10s\"\n", curLine.begin());
|
||||
#endif
|
||||
return curLine.begin();
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::flush() {
|
||||
return flushImpl(false);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeString(const char* str) {
|
||||
int len = strlen(str);
|
||||
|
||||
if (len > outBuf->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len > outBuf->remaining()) {
|
||||
if (!flushImpl(true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE we do not copy the null terminator of the string.
|
||||
|
||||
strncpy(outBuf->fillPos(), str, len);
|
||||
outBuf->incrFillPos(len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeInt(int val) {
|
||||
char buf[128];
|
||||
sprintf(buf, "%d", val);
|
||||
return writeString(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeUnsignedInt(unsigned int val) {
|
||||
char buf[128];
|
||||
sprintf(buf, "%u", val);
|
||||
return writeString(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBoolAsInt(bool val) {
|
||||
if (val) {
|
||||
return writeString("1");
|
||||
} else {
|
||||
return writeString("0");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeAddress(void* val) {
|
||||
char buf[128];
|
||||
sprintf(buf, INTPTR_FORMAT, val);
|
||||
return writeString(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeSpace() {
|
||||
return writeString(" ");
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeEOL() {
|
||||
return writeString("\n\r");
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinChar(char c) {
|
||||
return writeBinBuf((char*) &c, sizeof(c));
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinUnsignedShort(unsigned short i) {
|
||||
i = htons(i);
|
||||
return writeBinBuf((char*) &i, sizeof(i));
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinUnsignedInt(unsigned int i) {
|
||||
i = htonl(i);
|
||||
return writeBinBuf((char*) &i, sizeof(i));
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinBuf(char* buf, int size) {
|
||||
while (size > 0) {
|
||||
int spaceRemaining = outBuf->remaining();
|
||||
if (spaceRemaining == 0) {
|
||||
if (!flushImpl(true)) {
|
||||
return false;
|
||||
}
|
||||
spaceRemaining = outBuf->remaining();
|
||||
}
|
||||
int toCopy = (size > spaceRemaining) ? spaceRemaining : size;
|
||||
memcpy(outBuf->fillPos(), buf, toCopy);
|
||||
outBuf->incrFillPos(toCopy);
|
||||
buf += toCopy;
|
||||
size -= toCopy;
|
||||
if (size > 0) {
|
||||
if (!flushImpl(true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
IOBuf::FillState
|
||||
IOBuf::fillFromFileHandle(HANDLE fh, DWORD* numBytesRead) {
|
||||
int totalToRead;
|
||||
char moreToCome;
|
||||
|
||||
outBuf->compact();
|
||||
|
||||
DWORD numRead;
|
||||
if (!ReadFile(fh, &totalToRead, sizeof(int), &numRead, NULL)) {
|
||||
return FAILED;
|
||||
}
|
||||
if (numRead != sizeof(int)) {
|
||||
return FAILED;
|
||||
}
|
||||
if (!ReadFile(fh, &moreToCome, 1, &numRead, NULL)) {
|
||||
return FAILED;
|
||||
}
|
||||
if (numRead != 1) {
|
||||
return FAILED;
|
||||
}
|
||||
if (outBuf->remaining() < totalToRead) {
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
int tmp = totalToRead;
|
||||
|
||||
while (totalToRead > 0) {
|
||||
if (!ReadFile(fh, outBuf->fillPos(), totalToRead, &numRead, NULL)) {
|
||||
return FAILED;
|
||||
}
|
||||
outBuf->incrFillPos((int) numRead);
|
||||
totalToRead -= numRead;
|
||||
}
|
||||
|
||||
*numBytesRead = tmp;
|
||||
return ((moreToCome == 0) ? DONE : MORE_DATA_PENDING);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
IOBuf::isBinEscapeChar(char c) {
|
||||
return (c == '|');
|
||||
}
|
||||
|
||||
IOBuf::Action
|
||||
IOBuf::processChar(char c) {
|
||||
Action action = NO_ACTION;
|
||||
switch (state) {
|
||||
case TEXT_STATE: {
|
||||
// Looking for text char, bin escape char, or EOL
|
||||
if (isBinEscapeChar(c)) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[a: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
binPos = 0;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[b: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
binLength = 0;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[c: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
state = BIN_STATE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[d: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "\nSwitching to BIN_STATE\n");
|
||||
#endif
|
||||
} else if (isEOL(c)) {
|
||||
state = EOL_STATE;
|
||||
action = GOT_LINE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "\nSwitching to EOL_STATE (GOT_LINE)\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUGGING
|
||||
else {
|
||||
fprintf(stderr, "'%c' ", c);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case BIN_STATE: {
|
||||
// Seeking to finish read of input
|
||||
if (binPos < 4) {
|
||||
int cur = c & 0xFF;
|
||||
binLength <<= 8;
|
||||
binLength |= cur;
|
||||
++binPos;
|
||||
} else {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Reading binary byte %d of %d\n",
|
||||
binPos - 4, binLength);
|
||||
#endif
|
||||
++binPos;
|
||||
if (binPos == 4 + binLength) {
|
||||
state = TEXT_STATE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Switching to TEXT_STATE\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EOL_STATE: {
|
||||
// More EOL characters just cause us to re-enter this state
|
||||
if (isEOL(c)) {
|
||||
action = SKIP_EOL_CHAR;
|
||||
} else if (isBinEscapeChar(c)) {
|
||||
binPos = 0;
|
||||
binLength = 0;
|
||||
state = BIN_STATE;
|
||||
} else {
|
||||
state = TEXT_STATE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "'%c' ", c);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} // switch
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IOBuf::isEOL(char c) {
|
||||
#ifdef WIN32
|
||||
return ((c == '\n') || (c == '\r'));
|
||||
#elif defined(__sun)
|
||||
return c == '\n';
|
||||
#else
|
||||
#error Please port isEOL() to your platform
|
||||
return false;
|
||||
#endif
|
||||
}
|
@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2003, 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.
|
||||
*
|
||||
* 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 _IO_BUF_
|
||||
#define _IO_BUF_
|
||||
|
||||
// This file is currently used for os/solaris/agent/ too. At some point in time
|
||||
// the source will be reorganized to avoid these ifdefs.
|
||||
// Note that this class can read/write from a file as well as a socket. This
|
||||
// file capability is only implemented on win32.
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
// These are from win32 winsock2.h
|
||||
typedef unsigned int SOCKET;
|
||||
typedef void * HANDLE;
|
||||
typedef unsigned long DWORD;
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include "Buffer.hpp"
|
||||
|
||||
/** Manages an input/output buffer pair for a socket or file handle. */
|
||||
class IOBuf {
|
||||
public:
|
||||
IOBuf(int inBufLen, int outBufLen);
|
||||
~IOBuf();
|
||||
|
||||
enum ReadLineResult {
|
||||
RL_GOT_DATA,
|
||||
RL_NO_DATA,
|
||||
RL_ERROR
|
||||
};
|
||||
|
||||
/** Change the socket with which this buffer is associated */
|
||||
void setSocket(SOCKET sock);
|
||||
|
||||
// Reading/writing files is only supported on windows.
|
||||
#ifdef WIN32
|
||||
/** Change the output file handle with which this buffer is
|
||||
associated. Currently IOBufs can not be used to read from a file
|
||||
handle. */
|
||||
void setOutputFileHandle(HANDLE handle);
|
||||
#endif
|
||||
|
||||
/** Reset the input and output buffers, without flushing the output
|
||||
data to the socket */
|
||||
void reset();
|
||||
|
||||
/** Try to read a line of data from the given socket without
|
||||
blocking. If was able to read a complete line of data, returns a
|
||||
character pointer to the beginning of the (null-terminated)
|
||||
string. If not, returns NULL, but maintains enough state that
|
||||
subsequent calls to tryReadLine() will not ignore the data
|
||||
already read. NOTE: this skips end-of-line characters (typically
|
||||
CR/LF) as defined by "isEOL()". When switching back and forth
|
||||
between binary and text modes, to be sure no data is lost, pad
|
||||
the beginning and end of the binary transmission with bytes
|
||||
which can not be confused with these characters. */
|
||||
ReadLineResult tryReadLine();
|
||||
|
||||
/** Read a line of data from the given socket, blocking until a
|
||||
line, including EOL, appears. Return the line, or NULL if
|
||||
something goes wrong. */
|
||||
char *readLine();
|
||||
|
||||
/** Get the pointer to the beginning of the (null-terminated) line.
|
||||
This should only be called if tryReadLine() has returned
|
||||
RL_GOT_DATA. This sets the "parsing cursor" to the beginning of
|
||||
the line. */
|
||||
char* getLine();
|
||||
|
||||
// NOTE: any further data-acquisition routines must ALWAYS call
|
||||
// fixupData() at the beginning!
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Output routines
|
||||
//
|
||||
|
||||
/** Flush the output buffer to the socket. Returns true if
|
||||
succeeded, false if write error occurred. */
|
||||
bool flush();
|
||||
|
||||
/** Write the given string to the output buffer. May flush if output
|
||||
buffer becomes too full to store the data. Not guaranteed to
|
||||
work if string is longer than the size of the output buffer.
|
||||
Does not include the null terminator of the string. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeString(const char* str);
|
||||
|
||||
/** Write the given int to the output buffer. May flush if output
|
||||
buffer becomes too full to store the data. Returns true if
|
||||
succeeded, false if write error occurred. */
|
||||
bool writeInt(int val);
|
||||
|
||||
/** Write the given unsigned int to the output buffer. May flush if
|
||||
output buffer becomes too full to store the data. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeUnsignedInt(unsigned int val);
|
||||
|
||||
/** Write the given boolean to the output buffer. May flush if
|
||||
output buffer becomes too full to store the data. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeBoolAsInt(bool val);
|
||||
|
||||
/** Write the given address to the output buffer. May flush if
|
||||
output buffer becomes too full to store the data. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeAddress(void* val);
|
||||
|
||||
/** Writes a space to the output buffer. May flush if output buffer
|
||||
becomes too full to store the data. Returns true if succeeded,
|
||||
false if write error occurred. */
|
||||
bool writeSpace();
|
||||
|
||||
/** Writes an end-of-line sequence to the output buffer. May flush
|
||||
if output buffer becomes too full to store the data. Returns
|
||||
true if succeeded, false if write error occurred. */
|
||||
bool writeEOL();
|
||||
|
||||
/** Writes a binary character to the output buffer. */
|
||||
bool writeBinChar(char c);
|
||||
|
||||
/** Writes a binary unsigned short in network (big-endian) byte
|
||||
order to the output buffer. */
|
||||
bool writeBinUnsignedShort(unsigned short i);
|
||||
|
||||
/** Writes a binary unsigned int in network (big-endian) byte order
|
||||
to the output buffer. */
|
||||
bool writeBinUnsignedInt(unsigned int i);
|
||||
|
||||
/** Writes a binary buffer to the output buffer. */
|
||||
bool writeBinBuf(char* buf, int size);
|
||||
|
||||
#ifdef WIN32
|
||||
enum FillState {
|
||||
DONE = 1,
|
||||
MORE_DATA_PENDING = 2,
|
||||
FAILED = 3
|
||||
};
|
||||
|
||||
/** Very specialized routine; fill the output buffer from the given
|
||||
file handle. Caller is responsible for ensuring that there is
|
||||
data to be read on the file handle. */
|
||||
FillState fillFromFileHandle(HANDLE fh, DWORD* numRead);
|
||||
#endif
|
||||
|
||||
/** Binary utility routine (for poke) */
|
||||
static bool isBinEscapeChar(char c);
|
||||
|
||||
private:
|
||||
IOBuf(const IOBuf&);
|
||||
IOBuf& operator=(const IOBuf&);
|
||||
|
||||
// Returns -1 if non-blocking and no data available
|
||||
int readChar(bool block);
|
||||
// Line-oriented reading
|
||||
std::vector<char> curLine;
|
||||
bool gotDataLastTime;
|
||||
|
||||
ReadLineResult doReadLine(bool);
|
||||
|
||||
bool flushImpl(bool moreDataToCome);
|
||||
|
||||
SOCKET fd;
|
||||
HANDLE outHandle;
|
||||
bool usingSocket;
|
||||
|
||||
// Buffers
|
||||
Buffer* inBuf;
|
||||
Buffer* outBuf;
|
||||
|
||||
// Simple finite-state machine to handle binary data
|
||||
enum State {
|
||||
TEXT_STATE,
|
||||
BIN_STATE,
|
||||
EOL_STATE
|
||||
};
|
||||
enum Action {
|
||||
NO_ACTION,
|
||||
GOT_LINE, // TEXT_STATE -> EOL_STATE transition
|
||||
SKIP_EOL_CHAR // EOL_STATE -> EOL_STATE transition
|
||||
};
|
||||
|
||||
State state;
|
||||
Action processChar(char c);
|
||||
|
||||
// Handling incoming binary buffers (poke command)
|
||||
int binPos; // Number of binary characters read so far;
|
||||
// total number to read is binLength + 4
|
||||
int binLength; // Number of binary characters in message;
|
||||
// not valid until binPos >= 4
|
||||
|
||||
bool isEOL(char c);
|
||||
};
|
||||
|
||||
#endif // #defined _IO_BUF_
|
@ -1,80 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2000, 2001, 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
SERVER=SwDbgSrv.exe
|
||||
SUBPROCESS=SwDbgSub.exe
|
||||
|
||||
SERVER_SOURCES = \
|
||||
Buffer.cpp \
|
||||
Dispatcher.cpp \
|
||||
initWinsock.cpp \
|
||||
IOBuf.cpp \
|
||||
ioUtils.cpp \
|
||||
isNT4.cpp \
|
||||
nt4internals.cpp \
|
||||
procList.cpp \
|
||||
Reaper.cpp \
|
||||
SwDbgSrv.cpp \
|
||||
serverLists.cpp \
|
||||
toolHelp.cpp
|
||||
|
||||
SUBPROCESS_SOURCES = \
|
||||
SwDbgSub.cpp \
|
||||
Buffer.cpp \
|
||||
IOBuf.cpp \
|
||||
isNT4.cpp \
|
||||
libInfo.cpp \
|
||||
Monitor.cpp \
|
||||
nt4internals.cpp \
|
||||
toolHelp.cpp
|
||||
|
||||
SERVER_OBJS = $(SERVER_SOURCES:.cpp=.obj)
|
||||
SUBPROCESS_OBJS = $(SUBPROCESS_SOURCES:.cpp=.obj)
|
||||
|
||||
CPP=cl.exe
|
||||
LINK32=link.exe
|
||||
|
||||
# These do not need to be optimized (don't run a lot of code) and it
|
||||
# will be useful to have the assertion checks in place
|
||||
|
||||
CFLAGS=/nologo /MD /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
|
||||
LIBS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib \
|
||||
ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib \
|
||||
winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib \
|
||||
odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386
|
||||
|
||||
default: $(SERVER) $(SUBPROCESS)
|
||||
|
||||
$(SERVER): $(SERVER_OBJS)
|
||||
$(LINK32) /out:$@ $(SERVER_OBJS) $(LIBS)
|
||||
|
||||
$(SUBPROCESS): $(SUBPROCESS_OBJS)
|
||||
$(LINK32) /out:$@ $(SUBPROCESS_OBJS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f *.obj *.idb *.pch *.pdb *.ncb *.opt *.plg *.exe *.ilk
|
||||
|
||||
.cpp.obj:
|
||||
@ $(CPP) $(CFLAGS) /o $@ $<
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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.
|
||||
*
|
||||
* 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 _MESSAGE_
|
||||
#define _MESSAGE_
|
||||
|
||||
// These are the commands sent from the server to the child processes
|
||||
// over the child processes' stdin pipes. A subset of the commands
|
||||
// understood by the overall system, these require responses from the
|
||||
// child process. Having a data structure rather than sending text
|
||||
// simplifies parsing on the child side. The child replies by sending
|
||||
// back fully-formatted replies which are copied by the server process
|
||||
// to the clients' sockets.
|
||||
|
||||
struct PeekArg {
|
||||
DWORD address;
|
||||
DWORD numBytes;
|
||||
};
|
||||
|
||||
// NOTE: when sending a PokeArg to the child process, we handle the
|
||||
// buffer specially
|
||||
struct PokeArg {
|
||||
DWORD address;
|
||||
DWORD numBytes;
|
||||
void* data;
|
||||
};
|
||||
|
||||
// Used for continueevent
|
||||
struct BoolArg {
|
||||
bool val;
|
||||
};
|
||||
|
||||
// Used for duphandle, closehandle, and getcontext
|
||||
struct HandleArg {
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
// Used for setcontext
|
||||
const int NUM_REGS_IN_CONTEXT = 22;
|
||||
struct SetContextArg {
|
||||
HANDLE handle;
|
||||
DWORD Eax;
|
||||
DWORD Ebx;
|
||||
DWORD Ecx;
|
||||
DWORD Edx;
|
||||
DWORD Esi;
|
||||
DWORD Edi;
|
||||
DWORD Ebp;
|
||||
DWORD Esp;
|
||||
DWORD Eip;
|
||||
DWORD Ds;
|
||||
DWORD Es;
|
||||
DWORD Fs;
|
||||
DWORD Gs;
|
||||
DWORD Cs;
|
||||
DWORD Ss;
|
||||
DWORD EFlags;
|
||||
DWORD Dr0;
|
||||
DWORD Dr1;
|
||||
DWORD Dr2;
|
||||
DWORD Dr3;
|
||||
DWORD Dr6;
|
||||
DWORD Dr7;
|
||||
};
|
||||
|
||||
// Used for selectorentry
|
||||
struct SelectorEntryArg {
|
||||
HANDLE handle;
|
||||
DWORD selector;
|
||||
};
|
||||
|
||||
struct Message {
|
||||
typedef enum {
|
||||
ATTACH,
|
||||
DETACH,
|
||||
LIBINFO,
|
||||
PEEK,
|
||||
POKE,
|
||||
THREADLIST,
|
||||
DUPHANDLE,
|
||||
CLOSEHANDLE,
|
||||
GETCONTEXT,
|
||||
SETCONTEXT,
|
||||
SELECTORENTRY,
|
||||
SUSPEND,
|
||||
RESUME,
|
||||
POLLEVENT,
|
||||
CONTINUEEVENT
|
||||
} Type;
|
||||
|
||||
Type type;
|
||||
union {
|
||||
PeekArg peekArg;
|
||||
PokeArg pokeArg;
|
||||
BoolArg boolArg;
|
||||
HandleArg handleArg;
|
||||
SetContextArg setContextArg;
|
||||
SelectorEntryArg selectorArg;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // #defined _MESSAGE_
|
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "Monitor.hpp"
|
||||
|
||||
Monitor::Monitor() {
|
||||
_lock_count = -1; // No threads have entered the critical section
|
||||
_owner = NULL;
|
||||
_lock_event = CreateEvent(NULL, false, false, NULL);
|
||||
_wait_event = CreateEvent(NULL, true, false, NULL);
|
||||
_counter = 0;
|
||||
_tickets = 0;
|
||||
_waiters = 0;
|
||||
}
|
||||
|
||||
Monitor::~Monitor() {
|
||||
assert(_owner == NULL); // Otherwise, owned monitor being deleted
|
||||
assert(_lock_count == -1); // Otherwise, monitor being deleted with non -1 lock count
|
||||
CloseHandle(_lock_event);
|
||||
CloseHandle(_wait_event);
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::lock() {
|
||||
if (InterlockedIncrement(&_lock_count) == 0) {
|
||||
// Success, we now own the lock
|
||||
} else {
|
||||
DWORD dwRet = WaitForSingleObject((HANDLE)_lock_event, INFINITE);
|
||||
assert(dwRet == WAIT_OBJECT_0); // Unexpected return value from WaitForSingleObject
|
||||
}
|
||||
assert(owner() == NULL); // Otherwise, lock count and owner are inconsistent
|
||||
setOwner(GetCurrentThread());
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::unlock() {
|
||||
setOwner(NULL);
|
||||
if (InterlockedDecrement(&_lock_count) >= 0) {
|
||||
// Wake a waiting thread up
|
||||
DWORD dwRet = SetEvent(_lock_event);
|
||||
assert(dwRet != 0); // Unexpected return value from SetEvent
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Monitor::wait(long timeout) {
|
||||
assert(owner() != NULL);
|
||||
assert(owner() == GetCurrentThread());
|
||||
|
||||
// 0 means forever. Convert to Windows specific code.
|
||||
DWORD timeout_value = (timeout == 0) ? INFINITE : timeout;
|
||||
DWORD which;
|
||||
|
||||
long c = _counter;
|
||||
bool retry = false;
|
||||
|
||||
_waiters++;
|
||||
// Loop until condition variable is signaled. The event object is
|
||||
// set whenever the condition variable is signaled, and tickets will
|
||||
// reflect the number of threads which have been notified. The counter
|
||||
// field is used to make sure we don't respond to notifications that
|
||||
// have occurred *before* we started waiting, and is incremented each
|
||||
// time the condition variable is signaled.
|
||||
|
||||
while (true) {
|
||||
|
||||
// Leave critical region
|
||||
unlock();
|
||||
|
||||
// If this is a retry, let other low-priority threads have a chance
|
||||
// to run. Make sure that we sleep outside of the critical section.
|
||||
if (retry) {
|
||||
Sleep(1);
|
||||
} else {
|
||||
retry = true;
|
||||
}
|
||||
|
||||
which = WaitForSingleObject(_wait_event, timeout_value);
|
||||
// Enter critical section
|
||||
lock();
|
||||
|
||||
if (_tickets != 0 && _counter != c) break;
|
||||
|
||||
if (which == WAIT_TIMEOUT) {
|
||||
--_waiters;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_waiters--;
|
||||
|
||||
// If this was the last thread to be notified, then we need to reset
|
||||
// the event object.
|
||||
if (--_tickets == 0) {
|
||||
ResetEvent(_wait_event);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Notify a single thread waiting on this monitor
|
||||
bool
|
||||
Monitor::notify() {
|
||||
assert(ownedBySelf()); // Otherwise, notify on unknown thread
|
||||
|
||||
if (_waiters > _tickets) {
|
||||
if (!SetEvent(_wait_event)) {
|
||||
return false;
|
||||
}
|
||||
_tickets++;
|
||||
_counter++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Notify all threads waiting on this monitor
|
||||
bool
|
||||
Monitor::notifyAll() {
|
||||
assert(ownedBySelf()); // Otherwise, notifyAll on unknown thread
|
||||
|
||||
if (_waiters > 0) {
|
||||
if (!SetEvent(_wait_event)) {
|
||||
return false;
|
||||
}
|
||||
_tickets = _waiters;
|
||||
_counter++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
Monitor::owner() {
|
||||
return _owner;
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::setOwner(HANDLE owner) {
|
||||
if (owner != NULL) {
|
||||
assert(_owner == NULL); // Setting owner thread of already owned monitor
|
||||
assert(owner == GetCurrentThread()); // Else should not be doing this
|
||||
} else {
|
||||
HANDLE oldOwner = _owner;
|
||||
assert(oldOwner != NULL); // Removing the owner thread of an unowned mutex
|
||||
assert(oldOwner == GetCurrentThread());
|
||||
}
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
bool
|
||||
Monitor::ownedBySelf() {
|
||||
return (_owner == GetCurrentThread());
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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 _MONITOR_
|
||||
#define _MONITOR_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
Monitor();
|
||||
~Monitor();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
// Default time is forever (i.e, zero). Returns true if it times-out, otherwise
|
||||
// false.
|
||||
bool wait(long timeout = 0);
|
||||
bool notify();
|
||||
bool notifyAll();
|
||||
|
||||
private:
|
||||
HANDLE owner();
|
||||
void setOwner(HANDLE owner);
|
||||
bool ownedBySelf();
|
||||
|
||||
HANDLE _owner;
|
||||
long _lock_count;
|
||||
HANDLE _lock_event; // Auto-reset event for blocking in lock()
|
||||
HANDLE _wait_event; // Manual-reset event for notifications
|
||||
long _counter; // Current number of notifications
|
||||
long _waiters; // Number of threads waiting for notification
|
||||
long _tickets; // Number of waiters to be notified
|
||||
};
|
||||
|
||||
|
||||
#endif // #defined _MONITOR_
|
@ -1,246 +0,0 @@
|
||||
This debug server uses a largely text-based protocol, except for
|
||||
certain bulk data transfer operations. All text is in single-byte
|
||||
US-ASCII except for the strings returned in "proclist".
|
||||
|
||||
NOTE that the character '|' (vertical bar) is used as an escape
|
||||
character to switch the incoming data stream to the debug server into
|
||||
binary mode, so no text command may contain that character.
|
||||
|
||||
Commands understood:
|
||||
|
||||
ascii <EOL> ::=
|
||||
|
||||
Changes to ASCII mode. This affects all outgoing strings. At
|
||||
startup the system is in unicode mode.
|
||||
|
||||
unicode <EOL> ::=
|
||||
|
||||
Changes to UNICODE mode. This affects all outgoing strings. This
|
||||
is the default mode upon startup.
|
||||
|
||||
proclist <EOL> ::=
|
||||
<int num> [<unsigned int pid> <int charSize> <int numChars> [<binary char_t name>]...]... <EOL>
|
||||
|
||||
Returns integer indicating number of processes to follow, followed
|
||||
by (pid, name) pairs. Names are given by (charSize, numChars,
|
||||
[char_t]...) tuples; charSize indicates the size of each character
|
||||
in bytes, numChars the number of characters in the string, and
|
||||
name the raw data for the string. Each individual character of the
|
||||
string, if multi-byte, is transmitted in network byte order.
|
||||
numChars and name are guaranteed to be separated by precisely one
|
||||
US-ASCII space. If process list is not available because of
|
||||
limitations of the underlying operating system, number of
|
||||
processes returned is 0.
|
||||
|
||||
attach <int pid> <EOL> ::= <bool result> <EOL>
|
||||
|
||||
Attempts to attach to the specified process. Returns 1 if
|
||||
successful, 0 if not. Will fail if already attached or if the
|
||||
process ID does not exist. Attaching to a process causes the
|
||||
process to be suspended.
|
||||
|
||||
detach <EOL> ::= <bool result> <EOL>
|
||||
|
||||
Detaches from the given process. Attaching and detaching multiple
|
||||
times during a debugging session is allowed. Detaching causes the
|
||||
process to resume execution.
|
||||
|
||||
libinfo <EOL> ::=
|
||||
<int numLibs> [<int charSize> <int numChars> [<binary char_t name>]... <address baseAddr>]... <EOL>
|
||||
|
||||
May only be called once attached and the target process must be
|
||||
suspended; otherwise, returns 0. Returns list of the full path
|
||||
names of all of the loaded modules (including the executable
|
||||
image) in the target process, as well as the base address at which
|
||||
each module was relocated. See proclist for format of strings, but
|
||||
NOTE that charSize is ALWAYS 1 for this particular routine,
|
||||
regardless of the setting of ASCII/UNICODE.
|
||||
|
||||
peek <address addr> <unsigned int numBytes> <EOL> ::=
|
||||
B<binary char success>
|
||||
[<binary unsigned int len> <binary char isMapped> [<binary char data>]...]...
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII letter 'B', allowing easier synchronization by
|
||||
clients. There is no data between the 'B' and the rest of the
|
||||
message.
|
||||
|
||||
May only be called once attached. Reads the address space of the
|
||||
target process starting at the given address (see below for format
|
||||
specifications) and extending the given number of bytes. Whether
|
||||
the read succeeded is indicated by a single byte containing a 1 or
|
||||
0 (success or failure). If successful, the return result is given
|
||||
in a sequence of ranges. _len_, the length of each range, is
|
||||
indicated by a 32-bit unsigned integer transmitted with big-endian
|
||||
byte ordering (i.e., most significant byte first). _isMapped_
|
||||
indicates whether the range is mapped or unmapped in the target
|
||||
process's address space, and will contain the value 1 or 0 for
|
||||
mapped or unmapped, respectively. If the range is mapped,
|
||||
_isMapped_ is followed by _data_, containing the raw binary data
|
||||
for the range. The sum of all ranges' lengths is guaranteed to be
|
||||
equivalent to the number of bytes requested.
|
||||
|
||||
poke <address addr> |[<binary unsigned int len> [<binary char data>]] <EOL> ::=
|
||||
<bool result> <EOL>
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII character '|' (vertical bar), allowing easier
|
||||
synchronization by the server. There is no data between the '|'
|
||||
and the rest of the message. ('B' is not used here because
|
||||
addresses can contain that letter; no alphanumeric characters are
|
||||
used because some of the parsing routines are used by the Solaris
|
||||
SA port, and in that port any alphanumeric character can show up
|
||||
as a part of a symbol being looked up.)
|
||||
|
||||
May only be called once attached. Writes the address space of the
|
||||
target process starting at the given address (see below for format
|
||||
specifications), extending the given number of bytes, and
|
||||
containing the given data. The number of bytes is a 32-bit
|
||||
unsigned integer transmitted with big-endian byte ordering (i.e.,
|
||||
most significant byte first). This is followed by the raw binary
|
||||
data to be placed at that address. The number of bytes of data
|
||||
must match the number of bytes specified in the message.
|
||||
|
||||
Returns true if the write succeeded; false if it failed, for
|
||||
example because a portion of the region was not mapped in the
|
||||
target address space.
|
||||
|
||||
threadlist <EOL> ::= <int numThreads> [<address threadHandle>...] <EOL>
|
||||
|
||||
May only be called once attached and the target process must be
|
||||
suspended; otherwise, returns 0. If available, returns handles for
|
||||
all of the threads in the target process. These handles may be
|
||||
used as arguments to the getcontext and selectorentry
|
||||
commands. They do not need to be (and should not be) duplicated
|
||||
via the duphandle command and must not be closed via the
|
||||
closehandle command.
|
||||
|
||||
duphandle <address handle> <EOL> ::=
|
||||
<bool success> [<address duplicate>] <EOL>
|
||||
|
||||
Duplicates a HANDLE read from the target process's address space.
|
||||
HANDLE is a Windows construct (typically typedef'd to void *).
|
||||
The returned handle should ultimately be closed via the
|
||||
closehandle command; failing to do so can cause resource leaks.
|
||||
|
||||
The purpose of this command is to allow the debugger to read the
|
||||
value of a thread handle from the target process and query its
|
||||
register set and thread selector entries via the getcontext and
|
||||
selectorentry commands, below; such use implies that the target
|
||||
program has its own notion of the thread list, and further, that
|
||||
the debugger has a way of locating that thread list.
|
||||
|
||||
closehandle <address handle> <EOL> ::=
|
||||
|
||||
Closes a handle retrieved via the duphandle command, above.
|
||||
|
||||
getcontext <address threadHandle> <EOL> ::= <bool success> [<context>] <EOL>
|
||||
|
||||
Returns the context for the given thread. The handle must either
|
||||
be one of the handles returned from the threadlist command or the
|
||||
result of duplicating a thread handle out of the target process
|
||||
via the duphandle command. The target process must be suspended.
|
||||
|
||||
The context is returned as a series of hex values which represent
|
||||
the following x86 registers in the following order:
|
||||
EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP, DS, ES, FS, GS,
|
||||
CS, SS, EFLAGS, DR0, DR1, DR2, DR3, DR6, DR7
|
||||
|
||||
FIXME: needs to be generalized and/or specified for other
|
||||
architectures.
|
||||
|
||||
setcontext <address threadHandle> <context> ::= <bool success> <EOL>
|
||||
|
||||
Sets the context of the given thread. The target process must be
|
||||
suspended. See the getcontext command for the ordering of the
|
||||
registers in the context.
|
||||
|
||||
Even if the setcontext command succeeds, some of the bits in some
|
||||
of the registers (like the global enable bits in the debug
|
||||
registers) may be overridden by the operating system. To ensure
|
||||
the debugger's notion of the register set is up to date, it is
|
||||
recommended to follow up a setcontext with a getcontext.
|
||||
|
||||
selectorentry <address threadHandle> <int selector> <EOL> ::=
|
||||
<bool success>
|
||||
[<address limitLow> <address baseLow>
|
||||
<address baseMid> <address flags1>
|
||||
<address flags2> <address baseHi>] <EOL>
|
||||
|
||||
Retrieves a descriptor table entry for the given thread and
|
||||
selector. This data structure allows conversion of a
|
||||
segment-relative address to a linear virtual address. It is most
|
||||
useful for locating the Thread Information Block for a given
|
||||
thread handle to be able to find that thread's ID, to be able to
|
||||
understand whether two different thread handles in fact refer to
|
||||
the same underlying thread.
|
||||
|
||||
This command will only work on the X86 architecture and will
|
||||
return false for the success flag (with no additional information
|
||||
sent) on other architectures.
|
||||
|
||||
suspend ::=
|
||||
|
||||
Suspends the target process. Must be attached to a target process.
|
||||
A process is suspended when attached to via the attach command. If
|
||||
the target process is already suspended then this command has no
|
||||
effect.
|
||||
|
||||
resume ::=
|
||||
|
||||
Resumes the target process without detaching from it. Must be
|
||||
attached to a target process. After resuming a target process, the
|
||||
debugger client must be prepared to poll for events from the
|
||||
target process fairly frequently in order for execution in the
|
||||
target process to proceed normally. If the target process is
|
||||
already resumed then this command has no effect.
|
||||
|
||||
pollevent ::=
|
||||
<bool eventPresent> [<address threadHandle> <unsigned int eventCode>]
|
||||
|
||||
Additional entries in result for given eventCode:
|
||||
|
||||
LOAD/UNLOAD_DLL_DEBUG_EVENT: <address baseOfDLL>
|
||||
EXCEPTION_DEBUG_EVENT: <unsigned int exceptionCode> <address faultingPC>
|
||||
|
||||
Additional entries for given exceptionCode:
|
||||
|
||||
EXCEPTION_ACCESS_VIOLATION: <bool wasWrite> <address faultingAddress>
|
||||
|
||||
<EOL>
|
||||
|
||||
Polls once to see whether a debug event has been generated by the
|
||||
target process. If none is present, returns 0 immediately.
|
||||
Otherwise, returns 1 along with a series of textual information
|
||||
about the event. The event is not cleared, and the thread resumed,
|
||||
until the continueevent command is sent, or the debugger client
|
||||
detaches from the target process.
|
||||
|
||||
Typically a debugger client will suspend the target process upon
|
||||
reception of a debug event. Otherwise, it is not guaranteed that
|
||||
all threads will be suspended upon reception of a debug event, and
|
||||
any operations requiring that threads be suspended (including
|
||||
fetching the context for the thread which generated the event)
|
||||
will fail.
|
||||
|
||||
continueevent <bool passEventToClient> ::= <bool success> <EOL>
|
||||
|
||||
Indicates that the current debug event has been used by the
|
||||
debugger client and that the target process should be resumed. The
|
||||
passEventToClient flag indicates whether the event should be
|
||||
propagated to the target process. Breakpoint and single-step
|
||||
events should not be propagated to the target. Returns false if
|
||||
there was no pending event, true otherwise.
|
||||
|
||||
exit <EOL>
|
||||
|
||||
Exits this debugger session.
|
||||
|
||||
Format specifications:
|
||||
|
||||
// Data formats and example values:
|
||||
<EOL> ::= end of line (typically \n on Unix platforms, or \n\r on Windows)
|
||||
<address> ::= 0x12345678[9ABCDEF0] /* up to 64-bit hex value */
|
||||
<unsigned int> ::= 5 /* up to 32-bit integer number; no leading sign */
|
||||
<bool> ::= 1 /* ASCII '0' or '1' */
|
||||
<context> ::= <address> ...
|
@ -1,64 +0,0 @@
|
||||
This is a "Simple Windows Debug Server" written for the purpose of
|
||||
enabling the Serviceability Agent on Win32. It has backends both for
|
||||
Windows NT 4.0 (using internal Windows APIs for a few routines) as
|
||||
well as for 95/98/ME/2000 via the Tool Help APIs.
|
||||
|
||||
The reason this debug server is necessary is that the Win32 debug APIs
|
||||
by design tear down the target process when the debugger exits (see
|
||||
knowledge base article Q164205 on msdn.microsoft.com). On Solaris, one
|
||||
can attach to and detach from a process with no effect; this is key to
|
||||
allowing dbx and gcore to work.
|
||||
|
||||
The Simple Windows Debug Server effectively implements attach/detach
|
||||
functionality for arbitrary debug clients. This allows the SA to
|
||||
attach non-destructively to a process, and will enable gcore for Win32
|
||||
to be written shortly. While the debugger (the "client" in all of the
|
||||
source code) is attached, the target process is suspended. (Note that
|
||||
the debug server could be extended to support resumption of the target
|
||||
process and transmission of debug events over to the debugger, but
|
||||
this has been left for the future.)
|
||||
|
||||
The makefile (type "nmake") builds two executables: SwDbgSrv.exe,
|
||||
which is the server process, and SwDbgSub.exe, which is forked by the
|
||||
server and should not be directly invoked by the user.
|
||||
|
||||
The intent is that these two executables can be installed into
|
||||
C:\WINNT\SYSTEM32 and SwDbgSrv installed to run as a service (on NT),
|
||||
for example using ServiceInstaller (http://www.kcmultimedia.com/smaster/).
|
||||
However, SwDbgSrv can also be run from the command line. It generates
|
||||
no text output unless the source code is changed to enable debugging
|
||||
printouts. As long as any processes which have been attached to by the
|
||||
SA are alive, the SwDbgSrv and any forked SwDbgSub processes must be
|
||||
left running. Terminating them will cause termination of the target
|
||||
processes.
|
||||
|
||||
The debug server opens port 27000 and accepts incoming connections
|
||||
from localhost only. The security model assumes that if one can run a
|
||||
process on the given machine then one basically has access to most or
|
||||
all of the machine's facilities; this seems to be in line with the
|
||||
standard Windows security model. The protocol used is text-based, so
|
||||
one can debug the debug server using telnet. See README-commands.txt
|
||||
for documentation on the supported commands.
|
||||
|
||||
Testing indicates that the performance impact of attaching to a
|
||||
process (and therefore permanently attaching a debugger) is minimal.
|
||||
Some serious performance problems had been seen which ultimately
|
||||
appeared to be a lack of physical memory on the machine running the
|
||||
system.
|
||||
|
||||
Bugs:
|
||||
|
||||
This debug server is fundamentally incompatible with the Visual C++
|
||||
debugger. Once the debug server is used to attach to a process, the
|
||||
Visual C++ IDE will not be able to attach to the same process (even if
|
||||
the debug server is "detached" from that process). Note that this
|
||||
system is designed to work with the same primitives that C and C++
|
||||
debuggers use (like "symbol lookup" and "read from process memory")
|
||||
and exposes these primitives to Java, so in the long term we could
|
||||
solve this problem by implementing platform-specific debug symbol
|
||||
parsing and a platform-independent C++ debugger in Java.
|
||||
|
||||
Note:
|
||||
|
||||
The files IOBuf.cpp and IOBuf.hpp are also used in
|
||||
building src/os/solaris/agent.
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "Reaper.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Reaper::Reaper(ReaperCB* cb) {
|
||||
InitializeCriticalSection(&crit);
|
||||
event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
this->cb = cb;
|
||||
|
||||
active = false;
|
||||
shouldShutDown = false;
|
||||
}
|
||||
|
||||
bool
|
||||
Reaper::start() {
|
||||
bool result = false;
|
||||
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
if (!active) {
|
||||
DWORD id;
|
||||
HANDLE reaper = CreateThread(NULL, 0, &Reaper::reaperThreadEntry,
|
||||
this, 0, &id);
|
||||
if (reaper != NULL) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
Reaper::stop() {
|
||||
bool result = false;
|
||||
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
if (active) {
|
||||
shouldShutDown = true;
|
||||
SetEvent(event);
|
||||
while (active) {
|
||||
Sleep(1);
|
||||
}
|
||||
shouldShutDown = false;
|
||||
result = true;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
Reaper::registerProcess(HANDLE processHandle, void* userData) {
|
||||
ProcessInfo info;
|
||||
|
||||
info.handle = processHandle;
|
||||
info.userData = userData;
|
||||
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
procInfo.push_back(info);
|
||||
SetEvent(event);
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void
|
||||
Reaper::reaperThread() {
|
||||
while (!shouldShutDown) {
|
||||
// Take atomic snapshot of the current process list and user data
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
int num = procInfo.size();
|
||||
HANDLE* handleList = new HANDLE[1 + num];
|
||||
void** dataList = new void*[num];
|
||||
for (int i = 0; i < num; i++) {
|
||||
handleList[i] = procInfo[i].handle;
|
||||
dataList[i] = procInfo[i].userData;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
|
||||
// Topmost handle becomes the event object, so other threads can
|
||||
// signal this one to notice differences in the above list (or
|
||||
// shut down)
|
||||
handleList[num] = event;
|
||||
|
||||
// Wait for these objects
|
||||
DWORD idx = WaitForMultipleObjects(1 + num, handleList,
|
||||
FALSE, INFINITE);
|
||||
if ((idx >= WAIT_OBJECT_0) && (idx <= WAIT_OBJECT_0 + num)) {
|
||||
idx -= WAIT_OBJECT_0;
|
||||
if (idx < num) {
|
||||
// A process exited (i.e., it wasn't that we were woken up
|
||||
// just because the event went off)
|
||||
(*cb)(dataList[idx]);
|
||||
// Remove this process from the list (NOTE: requires that
|
||||
// ordering does not change, i.e., that all additions are to
|
||||
// the back of the process list)
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
std::vector<ProcessInfo>::iterator iter = procInfo.begin();
|
||||
iter += idx;
|
||||
procInfo.erase(iter);
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
} else {
|
||||
// Notification from other thread
|
||||
ResetEvent(event);
|
||||
}
|
||||
} else {
|
||||
// Unexpected return value. For now, warn.
|
||||
cerr << "Reaper::reaperThread(): unexpected return value "
|
||||
<< idx << " from WaitForMultipleObjects" << endl;
|
||||
}
|
||||
|
||||
// Clean up these lists
|
||||
delete[] handleList;
|
||||
delete[] dataList;
|
||||
}
|
||||
|
||||
// Time to shut down
|
||||
active = false;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
Reaper::reaperThreadEntry(LPVOID data) {
|
||||
Reaper* reaper = (Reaper*) data;
|
||||
reaper->reaperThread();
|
||||
return 0;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.
|
||||
*
|
||||
* 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 _REAPER_
|
||||
#define _REAPER_
|
||||
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
typedef void ReaperCB(void* userData);
|
||||
|
||||
/** A Reaper maintains a thread which waits for child processes to
|
||||
terminate; upon termination it calls a user-specified ReaperCB to
|
||||
clean up resources associated with those child processes. */
|
||||
|
||||
class Reaper {
|
||||
private:
|
||||
Reaper& operator=(const Reaper&);
|
||||
Reaper(const Reaper&);
|
||||
|
||||
public:
|
||||
Reaper(ReaperCB*);
|
||||
~Reaper();
|
||||
|
||||
// Start the reaper thread.
|
||||
bool start();
|
||||
|
||||
// Stop the reaper thread. This is called automatically in the
|
||||
// reaper's destructor. It is not thread safe and should be called
|
||||
// by at most one thread at a time.
|
||||
bool stop();
|
||||
|
||||
// Register a given child process with the reaper. This should be
|
||||
// called by the application's main thread. When that process
|
||||
// terminates, the cleanup callback will be called with the
|
||||
// specified userData in the context of the reaper thread. Callbacks
|
||||
// are guaranteed to be called serially, so they can safely refer to
|
||||
// static data as well as the given user data.
|
||||
void registerProcess(HANDLE processHandle, void* userData);
|
||||
|
||||
private:
|
||||
// For thread safety of register()
|
||||
CRITICAL_SECTION crit;
|
||||
|
||||
ReaperCB* cb;
|
||||
|
||||
// State variables
|
||||
volatile bool active;
|
||||
volatile bool shouldShutDown;
|
||||
|
||||
struct ProcessInfo {
|
||||
HANDLE handle;
|
||||
void* userData;
|
||||
};
|
||||
|
||||
// Bookkeeping
|
||||
std::vector<ProcessInfo> procInfo;
|
||||
|
||||
// Synchronization between application thread and reaper thread
|
||||
HANDLE event;
|
||||
|
||||
// Entry point for reaper thread
|
||||
void reaperThread();
|
||||
|
||||
// Static function which is actual thread entry point
|
||||
static DWORD WINAPI reaperThreadEntry(LPVOID data);
|
||||
};
|
||||
|
||||
#endif // #defined _REAPER_
|
File diff suppressed because it is too large
Load Diff
@ -1,146 +0,0 @@
|
||||
# Microsoft Developer Studio Project File - Name="SwDbgSrv" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=SwDbgSrv - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSrv.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSrv.mak" CFG="SwDbgSrv - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "SwDbgSrv - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "SwDbgSrv - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "SwDbgSrv - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "SwDbgSrv - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "SwDbgSrv___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "SwDbgSrv___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "SwDbgSrv - Win32 Release"
|
||||
# Name "SwDbgSrv - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Buffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Dispatcher.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\initWinsock.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IOBuf.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ioUtils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\isNT4.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nt4internals.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\procList.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Reaper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\serverLists.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\SwDbgSrv.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\toolHelp.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
@ -1,41 +0,0 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "SwDbgSrv"=.\SwDbgSrv.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "SwDbgSub"=.\SwDbgSub.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
@ -1,883 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2003, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// This is the source code for the subprocess forked by the Simple
|
||||
// Windows Debug Server. It assumes most of the responsibility for the
|
||||
// debug session, and processes all of the commands sent by clients.
|
||||
|
||||
// Disable too-long symbol warnings
|
||||
#pragma warning ( disable : 4786 )
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
// Must come before windows.h
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include "IOBuf.hpp"
|
||||
#include "libInfo.hpp"
|
||||
#include "LockableList.hpp"
|
||||
#include "Message.hpp"
|
||||
#include "Monitor.hpp"
|
||||
#include "nt4internals.hpp"
|
||||
|
||||
// Uncomment the #define below to get messages on stderr
|
||||
// #define DEBUGGING
|
||||
|
||||
using namespace std;
|
||||
|
||||
DWORD pid;
|
||||
HANDLE procHandle;
|
||||
IOBuf* ioBuf;
|
||||
|
||||
// State flags indicating whether the attach to the remote process
|
||||
// definitively succeeded or failed
|
||||
volatile bool attachFailed = false;
|
||||
volatile bool attachSucceeded = false;
|
||||
|
||||
// State flag indicating whether the target process is suspended.
|
||||
// Modified by suspend()/resume(), viewed by debug thread, but only
|
||||
// under cover of the threads lock.
|
||||
volatile bool suspended = false;
|
||||
|
||||
// State flags indicating whether we are considered to be attached to
|
||||
// the target process and are therefore queuing up events to be sent
|
||||
// back to the debug server. These flags are only accessed and
|
||||
// modified under the cover of the eventLock.
|
||||
Monitor* eventLock;
|
||||
// The following is set to true when a client is attached to this process
|
||||
volatile bool generateDebugEvents = false;
|
||||
// Pointer to current debug event; non-NULL indicates a debug event is
|
||||
// waiting to be sent to the client. Main thread sets this to NULL to
|
||||
// indicate that the event has been consumed; also sets
|
||||
// passEventToClient, below.
|
||||
volatile DEBUG_EVENT* curDebugEvent = NULL;
|
||||
// Set by main thread to indicate whether the most recently posted
|
||||
// debug event should be passed on to the target process.
|
||||
volatile bool passEventToClient = true;
|
||||
|
||||
void conditionalPostDebugEvent(DEBUG_EVENT* ev, DWORD* continueOrNotHandledFlag) {
|
||||
// FIXME: make it possible for the client to enable and disable
|
||||
// certain types of events (have to do so in a platform-independent
|
||||
// manner)
|
||||
switch (ev->dwDebugEventCode) {
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
switch (ev->u.Exception.ExceptionRecord.ExceptionCode) {
|
||||
case EXCEPTION_BREAKPOINT: break;
|
||||
case EXCEPTION_SINGLE_STEP: break;
|
||||
case EXCEPTION_ACCESS_VIOLATION: break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
eventLock->lock();
|
||||
if (generateDebugEvents) {
|
||||
curDebugEvent = ev;
|
||||
while (curDebugEvent != NULL) {
|
||||
eventLock->wait();
|
||||
}
|
||||
if (passEventToClient) {
|
||||
*continueOrNotHandledFlag = DBG_EXCEPTION_NOT_HANDLED;
|
||||
} else {
|
||||
*continueOrNotHandledFlag = DBG_CONTINUE;
|
||||
}
|
||||
}
|
||||
eventLock->unlock();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Module list
|
||||
//
|
||||
|
||||
vector<LibInfo> libs;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Thread list
|
||||
//
|
||||
|
||||
struct ThreadInfo {
|
||||
DWORD tid;
|
||||
HANDLE thread;
|
||||
|
||||
ThreadInfo(DWORD tid, HANDLE thread) {
|
||||
this->tid = tid;
|
||||
this->thread = thread;
|
||||
}
|
||||
};
|
||||
|
||||
class ThreadList : public LockableList<ThreadInfo> {
|
||||
public:
|
||||
bool removeByThreadID(DWORD tid) {
|
||||
for (InternalListType::iterator iter = internalList.begin();
|
||||
iter != internalList.end(); iter++) {
|
||||
if ((*iter).tid == tid) {
|
||||
internalList.erase(iter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
HANDLE threadIDToHandle(DWORD tid) {
|
||||
for (InternalListType::iterator iter = internalList.begin();
|
||||
iter != internalList.end(); iter++) {
|
||||
if ((*iter).tid == tid) {
|
||||
return (*iter).thread;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
ThreadList threads;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// INITIALIZATION AND TERMINATION
|
||||
//
|
||||
|
||||
void
|
||||
printError(const char* prefix) {
|
||||
DWORD detail = GetLastError();
|
||||
LPTSTR message;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
0,
|
||||
detail,
|
||||
0,
|
||||
(LPTSTR) &message,
|
||||
1,
|
||||
NULL);
|
||||
// FIXME: This is signaling an error: "The handle is invalid." ?
|
||||
// Do I have to do all of my WaitForDebugEvent calls from the same thread?
|
||||
cerr << prefix << ": " << message << endl;
|
||||
LocalFree(message);
|
||||
}
|
||||
|
||||
void
|
||||
endProcess(bool waitForProcess = true) {
|
||||
NT4::unloadNTDLL();
|
||||
if (waitForProcess) {
|
||||
// Though we're exiting because of an error, do not tear down the
|
||||
// target process.
|
||||
WaitForSingleObject(procHandle, INFINITE);
|
||||
}
|
||||
CloseHandle(procHandle);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
debugThreadEntry(void*) {
|
||||
#ifdef DEBUGGING
|
||||
DWORD lastMsgId = 0;
|
||||
int count = 0;
|
||||
#endif
|
||||
|
||||
if (!DebugActiveProcess(pid)) {
|
||||
attachFailed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wait for debug events. We keep the information from some of these
|
||||
// on the side in anticipation of later queries by the client. NOTE
|
||||
// that we leave the process running. The main thread is responsible
|
||||
// for suspending and resuming all currently-active threads upon
|
||||
// client attach and detach.
|
||||
|
||||
while (true) {
|
||||
DEBUG_EVENT ev;
|
||||
if (!WaitForDebugEvent(&ev, INFINITE)) {
|
||||
#ifdef DEBUGGING
|
||||
if (++count < 10) {
|
||||
// FIXME: This is signaling an error: "The handle is invalid." ?
|
||||
// Do I have to do all of my WaitForDebugEvent calls from the same thread?
|
||||
printError("WaitForDebugEvent failed");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
|
||||
#ifdef DEBUGGING
|
||||
if (ev.dwDebugEventCode != lastMsgId) {
|
||||
lastMsgId = ev.dwDebugEventCode;
|
||||
count = 0;
|
||||
cerr << "Debug thread received event " << ev.dwDebugEventCode << endl;
|
||||
} else {
|
||||
if (++count < 10) {
|
||||
cerr << "Debug thread received event " << ev.dwDebugEventCode << endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD dbgContinueMode = DBG_CONTINUE;
|
||||
|
||||
switch (ev.dwDebugEventCode) {
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
conditionalPostDebugEvent(&ev, &dbgContinueMode);
|
||||
break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
conditionalPostDebugEvent(&ev, &dbgContinueMode);
|
||||
break;
|
||||
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
threads.lock();
|
||||
// FIXME: will this deal properly with child processes? If
|
||||
// not, is it possible to make it do so?
|
||||
#ifdef DEBUGGING
|
||||
cerr << "CREATE_PROCESS_DEBUG_EVENT " << ev.dwThreadId
|
||||
<< " " << ev.u.CreateProcessInfo.hThread << endl;
|
||||
#endif
|
||||
if (ev.u.CreateProcessInfo.hThread != NULL) {
|
||||
threads.add(ThreadInfo(ev.dwThreadId, ev.u.CreateProcessInfo.hThread));
|
||||
}
|
||||
threads.unlock();
|
||||
break;
|
||||
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
threads.lock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "CREATE_THREAD_DEBUG_EVENT " << ev.dwThreadId
|
||||
<< " " << ev.u.CreateThread.hThread << endl;
|
||||
#endif
|
||||
if (suspended) {
|
||||
// Suspend this thread before adding it to the thread list
|
||||
SuspendThread(ev.u.CreateThread.hThread);
|
||||
}
|
||||
threads.add(ThreadInfo(ev.dwThreadId, ev.u.CreateThread.hThread));
|
||||
threads.unlock();
|
||||
break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
threads.lock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "EXIT_THREAD_DEBUG_EVENT " << ev.dwThreadId << endl;
|
||||
#endif
|
||||
threads.removeByThreadID(ev.dwThreadId);
|
||||
threads.unlock();
|
||||
break;
|
||||
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
// cerr << "EXCEPTION_DEBUG_EVENT" << endl;
|
||||
switch (ev.u.Exception.ExceptionRecord.ExceptionCode) {
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
// cerr << "EXCEPTION_BREAKPOINT" << endl;
|
||||
if (!attachSucceeded && !attachFailed) {
|
||||
attachSucceeded = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dbgContinueMode = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
}
|
||||
conditionalPostDebugEvent(&ev, &dbgContinueMode);
|
||||
break;
|
||||
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
endProcess(false);
|
||||
// NOT REACHED
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Received debug event " << ev.dwDebugEventCode << endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, dbgContinueMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
attachToProcess() {
|
||||
// Create event lock
|
||||
eventLock = new Monitor();
|
||||
|
||||
// Get a process handle for later
|
||||
procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||
if (procHandle == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start up the debug thread
|
||||
DWORD debugThreadId;
|
||||
if (CreateThread(NULL, 0, &debugThreadEntry, NULL, 0, &debugThreadId) == NULL) {
|
||||
// Failed to make background debug thread. Fail.
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((!attachSucceeded) && (!attachFailed)) {
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (attachFailed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(attachSucceeded);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
readMessage(Message* msg) {
|
||||
DWORD numRead;
|
||||
if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE),
|
||||
msg,
|
||||
sizeof(Message),
|
||||
&numRead,
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (numRead != sizeof(Message)) {
|
||||
return false;
|
||||
}
|
||||
// For "poke" messages, must follow up by reading raw data
|
||||
if (msg->type == Message::POKE) {
|
||||
char* dataBuf = new char[msg->pokeArg.numBytes];
|
||||
if (dataBuf == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE),
|
||||
dataBuf,
|
||||
msg->pokeArg.numBytes,
|
||||
&numRead,
|
||||
NULL)) {
|
||||
delete[] dataBuf;
|
||||
return false;
|
||||
}
|
||||
if (numRead != msg->pokeArg.numBytes) {
|
||||
delete[] dataBuf;
|
||||
return false;
|
||||
}
|
||||
msg->pokeArg.data = (void *) dataBuf;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
handlePeek(Message* msg) {
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Entering handlePeek()" << endl;
|
||||
#endif
|
||||
|
||||
char* memBuf = new char[msg->peekArg.numBytes];
|
||||
if (memBuf == NULL) {
|
||||
ioBuf->writeString("B");
|
||||
ioBuf->writeBinChar(0);
|
||||
ioBuf->flush();
|
||||
delete[] memBuf;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try fast case first
|
||||
DWORD numRead;
|
||||
BOOL res = ReadProcessMemory(procHandle,
|
||||
(LPCVOID) msg->peekArg.address,
|
||||
memBuf,
|
||||
msg->peekArg.numBytes,
|
||||
&numRead);
|
||||
if (res && (numRead == msg->peekArg.numBytes)) {
|
||||
|
||||
// OK, complete success. Phew.
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Peek success case" << endl;
|
||||
#endif
|
||||
ioBuf->writeString("B");
|
||||
ioBuf->writeBinChar(1);
|
||||
ioBuf->writeBinUnsignedInt(numRead);
|
||||
ioBuf->writeBinChar(1);
|
||||
ioBuf->writeBinBuf(memBuf, numRead);
|
||||
} else {
|
||||
#ifdef DEBUGGING
|
||||
cerr << "*** Peek slow case ***" << endl;
|
||||
#endif
|
||||
|
||||
ioBuf->writeString("B");
|
||||
ioBuf->writeBinChar(1);
|
||||
|
||||
// Use VirtualQuery to speed things up a bit
|
||||
DWORD numLeft = msg->peekArg.numBytes;
|
||||
char* curAddr = (char*) msg->peekArg.address;
|
||||
while (numLeft > 0) {
|
||||
MEMORY_BASIC_INFORMATION memInfo;
|
||||
VirtualQueryEx(procHandle, curAddr, &memInfo, sizeof(memInfo));
|
||||
DWORD numToRead = memInfo.RegionSize;
|
||||
if (numToRead > numLeft) {
|
||||
numToRead = numLeft;
|
||||
}
|
||||
DWORD numRead;
|
||||
if (memInfo.State == MEM_COMMIT) {
|
||||
// Read the process memory at this address for this length
|
||||
// FIXME: should check the result of this read
|
||||
ReadProcessMemory(procHandle, curAddr, memBuf,
|
||||
numToRead, &numRead);
|
||||
// Write this out
|
||||
#ifdef DEBUGGING
|
||||
cerr << "*** Writing " << numToRead << " bytes as mapped ***" << endl;
|
||||
#endif
|
||||
ioBuf->writeBinUnsignedInt(numToRead);
|
||||
ioBuf->writeBinChar(1);
|
||||
ioBuf->writeBinBuf(memBuf, numToRead);
|
||||
} else {
|
||||
// Indicate region is free
|
||||
#ifdef DEBUGGING
|
||||
cerr << "*** Writing " << numToRead << " bytes as unmapped ***" << endl;
|
||||
#endif
|
||||
ioBuf->writeBinUnsignedInt(numToRead);
|
||||
ioBuf->writeBinChar(0);
|
||||
}
|
||||
curAddr += numToRead;
|
||||
numLeft -= numToRead;
|
||||
}
|
||||
}
|
||||
|
||||
ioBuf->flush();
|
||||
delete[] memBuf;
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Exiting handlePeek()" << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
handlePoke(Message* msg) {
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Entering handlePoke()" << endl;
|
||||
#endif
|
||||
DWORD numWritten;
|
||||
BOOL res = WriteProcessMemory(procHandle,
|
||||
(LPVOID) msg->pokeArg.address,
|
||||
msg->pokeArg.data,
|
||||
msg->pokeArg.numBytes,
|
||||
&numWritten);
|
||||
if (res && (numWritten == msg->pokeArg.numBytes)) {
|
||||
// Success
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
#ifdef DEBUGGING
|
||||
cerr << " (Succeeded)" << endl;
|
||||
#endif
|
||||
} else {
|
||||
// Failure
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
#ifdef DEBUGGING
|
||||
cerr << " (Failed)" << endl;
|
||||
#endif
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
// We clean up the data
|
||||
char* dataBuf = (char*) msg->pokeArg.data;
|
||||
delete[] dataBuf;
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Exiting handlePoke()" << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
suspend() {
|
||||
if (suspended) {
|
||||
return false;
|
||||
}
|
||||
// Before we suspend, we must take a snapshot of the loaded module
|
||||
// names and base addresses, since acquiring this snapshot requires
|
||||
// starting and exiting a thread in the remote process (at least on
|
||||
// NT 4).
|
||||
libs.clear();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Starting suspension" << endl;
|
||||
#endif
|
||||
libInfo(pid, libs);
|
||||
#ifdef DEBUGGING
|
||||
cerr << " Got lib info" << endl;
|
||||
#endif
|
||||
threads.lock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << " Got thread lock" << endl;
|
||||
#endif
|
||||
suspended = true;
|
||||
int j = 0;
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
j++;
|
||||
SuspendThread(threads.get(i).thread);
|
||||
}
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Suspended " << j << " threads" << endl;
|
||||
#endif
|
||||
threads.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
resume() {
|
||||
if (!suspended) {
|
||||
return false;
|
||||
}
|
||||
threads.lock();
|
||||
suspended = false;
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
ResumeThread(threads.get(i).thread);
|
||||
}
|
||||
threads.unlock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Resumed process" << endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
// Should only be used by performing CreateProcess within SwDbgSrv
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sscanf(argv[1], "%u", &pid) != 1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Try to attach to process
|
||||
if (!attachToProcess()) {
|
||||
// Attach failed. Notify parent by writing result to stdout file
|
||||
// handle.
|
||||
char res = 0;
|
||||
DWORD numBytes;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &res, sizeof(res),
|
||||
&numBytes, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Server is expecting success result back.
|
||||
char res = 1;
|
||||
DWORD numBytes;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &res, sizeof(res),
|
||||
&numBytes, NULL);
|
||||
|
||||
// Initialize our I/O buffer
|
||||
ioBuf = new IOBuf(32768, 131072);
|
||||
ioBuf->setOutputFileHandle(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||
|
||||
// At this point we are attached. Enter our main loop which services
|
||||
// requests from the server. Note that in order to handle attach/
|
||||
// detach properly (i.e., resumption of process upon "detach") we
|
||||
// will need another thread which handles debug events.
|
||||
while (true) {
|
||||
// Read a message from the server
|
||||
Message msg;
|
||||
if (!readMessage(&msg)) {
|
||||
endProcess();
|
||||
}
|
||||
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Main thread read message: " << msg.type << endl;
|
||||
#endif
|
||||
|
||||
switch (msg.type) {
|
||||
// ATTACH and DETACH messages MUST come in pairs
|
||||
case Message::ATTACH:
|
||||
suspend();
|
||||
eventLock->lock();
|
||||
generateDebugEvents = true;
|
||||
eventLock->unlock();
|
||||
break;
|
||||
|
||||
case Message::DETACH:
|
||||
eventLock->lock();
|
||||
generateDebugEvents = false;
|
||||
// Flush remaining event if any
|
||||
if (curDebugEvent != NULL) {
|
||||
curDebugEvent = NULL;
|
||||
eventLock->notifyAll();
|
||||
}
|
||||
eventLock->unlock();
|
||||
resume();
|
||||
break;
|
||||
|
||||
case Message::LIBINFO:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeInt(0);
|
||||
} else {
|
||||
// Send back formatted text
|
||||
ioBuf->writeInt(libs.size());
|
||||
for (int i = 0; i < libs.size(); i++) {
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeInt(1);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeInt(libs[i].name.size());
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeString(libs[i].name.c_str());
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(libs[i].base);
|
||||
}
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::PEEK:
|
||||
handlePeek(&msg);
|
||||
break;
|
||||
|
||||
case Message::POKE:
|
||||
handlePoke(&msg);
|
||||
break;
|
||||
|
||||
case Message::THREADLIST:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeInt(0);
|
||||
} else {
|
||||
threads.lock();
|
||||
ioBuf->writeInt(threads.size());
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress((void*) threads.get(i).thread);
|
||||
}
|
||||
threads.unlock();
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::DUPHANDLE:
|
||||
{
|
||||
HANDLE dup;
|
||||
if (DuplicateHandle(procHandle,
|
||||
msg.handleArg.handle,
|
||||
GetCurrentProcess(),
|
||||
&dup,
|
||||
0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress((void*) dup);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::CLOSEHANDLE:
|
||||
{
|
||||
CloseHandle(msg.handleArg.handle);
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::GETCONTEXT:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
|
||||
if (GetThreadContext(msg.handleArg.handle, &context)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
// EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP, DS, ES, FS, GS,
|
||||
// CS, SS, EFLAGS, DR0, DR1, DR2, DR3, DR6, DR7
|
||||
// See README-commands.txt
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Eax);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ebx);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ecx);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Edx);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Esi);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Edi);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ebp);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Esp);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Eip);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegDs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegEs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegFs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegGs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegCs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegSs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.EFlags);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr0);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr1);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr2);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr3);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr6);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr7);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::SETCONTEXT:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
|
||||
context.Eax = msg.setContextArg.Eax;
|
||||
context.Ebx = msg.setContextArg.Ebx;
|
||||
context.Ecx = msg.setContextArg.Ecx;
|
||||
context.Edx = msg.setContextArg.Edx;
|
||||
context.Esi = msg.setContextArg.Esi;
|
||||
context.Edi = msg.setContextArg.Edi;
|
||||
context.Ebp = msg.setContextArg.Ebp;
|
||||
context.Esp = msg.setContextArg.Esp;
|
||||
context.Eip = msg.setContextArg.Eip;
|
||||
context.SegDs = msg.setContextArg.Ds;
|
||||
context.SegEs = msg.setContextArg.Es;
|
||||
context.SegFs = msg.setContextArg.Fs;
|
||||
context.SegGs = msg.setContextArg.Gs;
|
||||
context.SegCs = msg.setContextArg.Cs;
|
||||
context.SegSs = msg.setContextArg.Ss;
|
||||
context.EFlags = msg.setContextArg.EFlags;
|
||||
context.Dr0 = msg.setContextArg.Dr0;
|
||||
context.Dr1 = msg.setContextArg.Dr1;
|
||||
context.Dr2 = msg.setContextArg.Dr2;
|
||||
context.Dr3 = msg.setContextArg.Dr3;
|
||||
context.Dr6 = msg.setContextArg.Dr6;
|
||||
context.Dr7 = msg.setContextArg.Dr7;
|
||||
if (SetThreadContext(msg.setContextArg.handle, &context)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::SELECTORENTRY:
|
||||
{
|
||||
LDT_ENTRY entry;
|
||||
|
||||
if (GetThreadSelectorEntry(msg.selectorArg.handle,
|
||||
msg.selectorArg.selector,
|
||||
&entry)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.LimitLow);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.BaseLow);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.BaseMid);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.Flags1);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.Flags2);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.BaseHi);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::SUSPEND:
|
||||
suspend();
|
||||
break;
|
||||
|
||||
case Message::RESUME:
|
||||
resume();
|
||||
break;
|
||||
|
||||
case Message::POLLEVENT:
|
||||
eventLock->lock();
|
||||
if (curDebugEvent == NULL) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
ioBuf->writeSpace();
|
||||
threads.lock();
|
||||
ioBuf->writeAddress((void*) threads.threadIDToHandle(curDebugEvent->dwThreadId));
|
||||
threads.unlock();
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeUnsignedInt(curDebugEvent->dwDebugEventCode);
|
||||
// Figure out what else to write
|
||||
switch (curDebugEvent->dwDebugEventCode) {
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(curDebugEvent->u.LoadDll.lpBaseOfDll);
|
||||
break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(curDebugEvent->u.UnloadDll.lpBaseOfDll);
|
||||
break;
|
||||
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
{
|
||||
DWORD code = curDebugEvent->u.Exception.ExceptionRecord.ExceptionCode;
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeUnsignedInt(code);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(curDebugEvent->u.Exception.ExceptionRecord.ExceptionAddress);
|
||||
switch (curDebugEvent->u.Exception.ExceptionRecord.ExceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeBoolAsInt(curDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0] != 0);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress((void*) curDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
eventLock->unlock();
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
|
||||
case Message::CONTINUEEVENT:
|
||||
eventLock->lock();
|
||||
if (curDebugEvent == NULL) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
curDebugEvent = NULL;
|
||||
passEventToClient = msg.boolArg.val;
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
eventLock->notify();
|
||||
}
|
||||
eventLock->unlock();
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endProcess();
|
||||
|
||||
// NOT REACHED
|
||||
return 0;
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
# Microsoft Developer Studio Project File - Name="SwDbgSub" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=SwDbgSub - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSub.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSub.mak" CFG="SwDbgSub - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "SwDbgSub - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "SwDbgSub - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "SwDbgSub - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "SwDbgSub - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "SwDbgSub___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "SwDbgSub___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "SwDbgSub - Win32 Release"
|
||||
# Name "SwDbgSub - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Buffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IOBuf.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\isNT4.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libInfo.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Monitor.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nt4internals.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\SwDbgSub.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\toolHelp.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <winsock2.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
initWinsock()
|
||||
{
|
||||
static int initted = 0;
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
int err;
|
||||
|
||||
if (!initted) {
|
||||
wVersionRequested = MAKEWORD( 2, 0 );
|
||||
|
||||
err = WSAStartup( wVersionRequested, &wsaData );
|
||||
if ( err != 0 ) {
|
||||
{
|
||||
/* Tell the user that we couldn't find a usable */
|
||||
/* WinSock DLL. */
|
||||
cerr << "SocketBase::SocketBase: unable to find usable "
|
||||
<< "WinSock DLL" << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Confirm that the WinSock DLL supports 2.0.*/
|
||||
/* Note that if the DLL supports versions greater */
|
||||
/* than 2.0 in addition to 2.0, it will still return */
|
||||
/* 2.0 in wVersion since that is the version we */
|
||||
/* requested. */
|
||||
|
||||
if ( LOBYTE( wsaData.wVersion ) != 2 ||
|
||||
HIBYTE( wsaData.wVersion ) != 0 ) {
|
||||
/* Tell the user that we couldn't find a usable */
|
||||
/* WinSock DLL. */
|
||||
{
|
||||
cerr << "Unable to find suitable version of WinSock DLL" << endl;
|
||||
WSACleanup( );
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
initted = 1;
|
||||
}
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "ioUtils.hpp"
|
||||
#include "IOBuf.hpp"
|
||||
|
||||
bool
|
||||
scanInt(char** data, int* num) {
|
||||
*num = 0;
|
||||
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (**data == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((**data != 0) && (!isspace(**data))) {
|
||||
char cur = **data;
|
||||
if ((cur < '0') || (cur > '9')) {
|
||||
return false;
|
||||
}
|
||||
*num *= 10;
|
||||
*num += cur - '0';
|
||||
++*data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
scanUnsignedLong(char** data, unsigned long* num) {
|
||||
*num = 0;
|
||||
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (**data == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((**data != 0) && (!isspace(**data))) {
|
||||
char cur = **data;
|
||||
if ((cur < '0') || (cur > '9')) {
|
||||
return false;
|
||||
}
|
||||
*num *= 10;
|
||||
*num += cur - '0';
|
||||
++*data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
charToNibble(char ascii, int* value) {
|
||||
if (ascii >= '0' && ascii <= '9') {
|
||||
*value = ascii - '0';
|
||||
return true;
|
||||
} else if (ascii >= 'A' && ascii <= 'F') {
|
||||
*value = 10 + ascii - 'A';
|
||||
return true;
|
||||
} else if (ascii >= 'a' && ascii <= 'f') {
|
||||
*value = 10 + ascii - 'a';
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
scanAddress(char** data, unsigned long* addr) {
|
||||
*addr = 0;
|
||||
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (**data == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp(*data, "0x", 2) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*data += 2;
|
||||
|
||||
while ((**data != 0) && (!isspace(**data))) {
|
||||
int val;
|
||||
bool res = charToNibble(**data, &val);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
*addr <<= 4;
|
||||
*addr |= val;
|
||||
++*data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
scanAndSkipBinEscapeChar(char** data) {
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (!IOBuf::isBinEscapeChar(**data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++*data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
scanBinUnsignedLong(char** data, unsigned long* num) {
|
||||
*num = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
unsigned char val = (unsigned char) **data;
|
||||
*num = (*num << 8) | val;
|
||||
++*data;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// Disable too-long symbol warnings
|
||||
#pragma warning ( disable : 4786 )
|
||||
|
||||
#include "libInfo.hpp"
|
||||
#include "nt4internals.hpp"
|
||||
#include "isNT4.hpp"
|
||||
#include "toolHelp.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef void LibInfoImplFunc(DWORD pid, vector<LibInfo>& info);
|
||||
|
||||
static void libInfoImplNT4(DWORD pid, vector<LibInfo>& info);
|
||||
static void libInfoImplToolHelp(DWORD pid, vector<LibInfo>& info);
|
||||
|
||||
void
|
||||
libInfo(DWORD pid, vector<LibInfo>& info) {
|
||||
static LibInfoImplFunc* impl = NULL;
|
||||
|
||||
if (impl == NULL) {
|
||||
// See which operating system we're on
|
||||
impl = (isNT4() ? &libInfoImplNT4 : &libInfoImplToolHelp);
|
||||
}
|
||||
|
||||
assert(impl != NULL);
|
||||
|
||||
(*impl)(pid, info);
|
||||
}
|
||||
|
||||
static ULONG
|
||||
ModuleCount(NT4::PDEBUG_BUFFER db) {
|
||||
return db->ModuleInformation ? *PULONG(db->ModuleInformation) : 0;
|
||||
}
|
||||
|
||||
#define MAX2(a, b) (((a) < (b)) ? (b) : (a))
|
||||
|
||||
static void
|
||||
libInfoImplNT4(DWORD pid, vector<LibInfo>& info) {
|
||||
static EnumProcessModulesFunc* enumFunc = NULL;
|
||||
static GetModuleFileNameExFunc* fnFunc = NULL;
|
||||
static GetModuleInformationFunc* infoFunc = NULL;
|
||||
|
||||
if (enumFunc == NULL) {
|
||||
HMODULE dll = loadPSAPIDLL();
|
||||
|
||||
enumFunc = (EnumProcessModulesFunc*) GetProcAddress(dll, "EnumProcessModules");
|
||||
fnFunc = (GetModuleFileNameExFunc*) GetProcAddress(dll, "GetModuleFileNameExA");
|
||||
infoFunc = (GetModuleInformationFunc*) GetProcAddress(dll, "GetModuleInformation");
|
||||
|
||||
assert(enumFunc != NULL);
|
||||
assert(fnFunc != NULL);
|
||||
assert(infoFunc != NULL);
|
||||
}
|
||||
|
||||
static HMODULE* mods = new HMODULE[256];
|
||||
static int numMods = 256;
|
||||
|
||||
if (mods == NULL) {
|
||||
mods = new HMODULE[numMods];
|
||||
if (mods == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
|
||||
HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||
if (proc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
DWORD bufSize = numMods * sizeof(HMODULE);
|
||||
DWORD neededSize;
|
||||
|
||||
if (!(*enumFunc)(proc, mods, bufSize, &neededSize)) {
|
||||
// Enum failed
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
int numFetched = neededSize / sizeof(HMODULE);
|
||||
|
||||
if (numMods < numFetched) {
|
||||
// Grow buffer
|
||||
numMods = MAX2(numFetched, 2 * numMods);
|
||||
delete[] mods;
|
||||
mods = new HMODULE[numMods];
|
||||
if (mods == NULL) {
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
char filename[MAX_PATH];
|
||||
MODULEINFO modInfo;
|
||||
|
||||
// Iterate through and fetch each one's info
|
||||
for (int i = 0; i < numFetched; i++) {
|
||||
if (!(*fnFunc)(proc, mods[i], filename, MAX_PATH)) {
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(*infoFunc)(proc, mods[i], &modInfo, sizeof(MODULEINFO))) {
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
info.push_back(LibInfo(string(filename), (void*) modInfo.lpBaseOfDll));
|
||||
}
|
||||
|
||||
done = true;
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
libInfoImplToolHelp(DWORD pid, vector<LibInfo>& info) {
|
||||
using namespace ToolHelp;
|
||||
|
||||
static CreateToolhelp32SnapshotFunc* snapshotFunc = NULL;
|
||||
static Module32FirstFunc* firstFunc = NULL;
|
||||
static Module32NextFunc* nextFunc = NULL;
|
||||
|
||||
if (snapshotFunc == NULL) {
|
||||
HMODULE dll = loadDLL();
|
||||
|
||||
snapshotFunc =
|
||||
(CreateToolhelp32SnapshotFunc*) GetProcAddress(dll,
|
||||
"CreateToolhelp32Snapshot");
|
||||
|
||||
firstFunc = (Module32FirstFunc*) GetProcAddress(dll,
|
||||
"Module32First");
|
||||
|
||||
nextFunc = (Module32NextFunc*) GetProcAddress(dll,
|
||||
"Module32Next");
|
||||
|
||||
assert(snapshotFunc != NULL);
|
||||
assert(firstFunc != NULL);
|
||||
assert(nextFunc != NULL);
|
||||
}
|
||||
|
||||
HANDLE snapshot = (*snapshotFunc)(TH32CS_SNAPMODULE, pid);
|
||||
if (snapshot == (HANDLE) -1) {
|
||||
// Error occurred during snapshot
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate
|
||||
MODULEENTRY32 module;
|
||||
if ((*firstFunc)(snapshot, &module)) {
|
||||
do {
|
||||
info.push_back(LibInfo(string(module.szExePath), (void*) module.modBaseAddr));
|
||||
} while ((*nextFunc)(snapshot, &module));
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
}
|
@ -1,273 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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.
|
||||
*
|
||||
* 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 _NT4INTERNALS_H_
|
||||
#define _NT4INTERNALS_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace NT4 {
|
||||
extern "C" {
|
||||
|
||||
// Data structures and constants required to be able to get necessary
|
||||
// debugging-related information on Windows NT 4.0 through internal
|
||||
// (i.e., non-public) APIs. These are adapted from those in the
|
||||
// _Windows NT/2000 Native API Reference_ by Gary Nebbett, Macmillan
|
||||
// Technical Publishing, 201 West 103rd Street, Indianapolis, IN
|
||||
// 46290, 2000.
|
||||
|
||||
typedef LONG NTSTATUS;
|
||||
typedef LONG KPRIORITY;
|
||||
|
||||
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
|
||||
#define NTAPI __stdcall
|
||||
#else
|
||||
#define _cdecl
|
||||
#define NTAPI
|
||||
#endif
|
||||
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
|
||||
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS {
|
||||
SystemProcessesAndThreadsInformation = 5
|
||||
} SYSTEM_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING;
|
||||
|
||||
typedef struct _VM_COUNTERS {
|
||||
ULONG PeakVirtualSize;
|
||||
ULONG VirtualSize;
|
||||
ULONG PageFaultCount;
|
||||
ULONG PeakWorkingSetSize;
|
||||
ULONG WorkingSetSize;
|
||||
ULONG QuotaPeakPagedPoolUsage;
|
||||
ULONG QuotaPagedPoolUsage;
|
||||
ULONG QuotaPeakNonPagedPoolUsage;
|
||||
ULONG QuotaNonPagedPoolUsage;
|
||||
ULONG PagefileUsage;
|
||||
ULONG PeakPagefileUsage;
|
||||
} VM_COUNTERS, *PVM_COUNTERS;
|
||||
|
||||
typedef struct _IO_COUNTERS {
|
||||
LARGE_INTEGER ReadOperationCount;
|
||||
LARGE_INTEGER WriteOperationCount;
|
||||
LARGE_INTEGER OtherOperationCount;
|
||||
LARGE_INTEGER ReadTransferCount;
|
||||
LARGE_INTEGER WriteTransferCount;
|
||||
LARGE_INTEGER OtherTransferCount;
|
||||
} IO_COUNTERS, *PIO_COUNTERS;
|
||||
|
||||
typedef struct _CLIENT_ID {
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef enum {
|
||||
StateInitialized,
|
||||
StateReady,
|
||||
StateRunning,
|
||||
StateStandby,
|
||||
StateTerminated,
|
||||
StateWait,
|
||||
StateTransition,
|
||||
StateUnknown
|
||||
} THREAD_STATE;
|
||||
|
||||
typedef enum {
|
||||
Executive,
|
||||
FreePage,
|
||||
PageIn,
|
||||
PoolAllocation,
|
||||
DelayExecution,
|
||||
Suspended,
|
||||
UserRequest,
|
||||
WrExecutive,
|
||||
WrFreePage,
|
||||
WrPageIn,
|
||||
WrPoolAllocation,
|
||||
WrDelayExecution,
|
||||
WrSuspended,
|
||||
WrUserRequest,
|
||||
WrEventPair,
|
||||
WrQueue,
|
||||
WrLpcReceive,
|
||||
WrLpcReply,
|
||||
WrVirtualMemory,
|
||||
WrPageOut,
|
||||
WrRendezvous,
|
||||
Spare2,
|
||||
Spare3,
|
||||
Spare4,
|
||||
Spare5,
|
||||
Spare6,
|
||||
WrKernel
|
||||
} KWAIT_REASON;
|
||||
|
||||
typedef struct _SYSTEM_THREADS {
|
||||
LARGE_INTEGER KernelTime;
|
||||
LARGE_INTEGER UserTime;
|
||||
LARGE_INTEGER CreateTime;
|
||||
ULONG WaitTime;
|
||||
PVOID StartAddress;
|
||||
CLIENT_ID ClientId;
|
||||
KPRIORITY Priority;
|
||||
KPRIORITY BasePriority;
|
||||
ULONG ContextSwitchCount;
|
||||
THREAD_STATE State;
|
||||
KWAIT_REASON WaitReason;
|
||||
} SYSTEM_THREADS, *PSYSTEM_THREADS;
|
||||
|
||||
typedef struct _SYSTEM_PROCESSES { // Information class 5
|
||||
ULONG NextEntryDelta;
|
||||
ULONG ThreadCount;
|
||||
ULONG Reserved1[6];
|
||||
LARGE_INTEGER CreateTime;
|
||||
LARGE_INTEGER UserTime;
|
||||
LARGE_INTEGER KernelTime;
|
||||
UNICODE_STRING ProcessName;
|
||||
KPRIORITY BasePriority;
|
||||
ULONG ProcessId;
|
||||
ULONG InheritedFromProcessId;
|
||||
ULONG HandleCount;
|
||||
ULONG Reserved2[2];
|
||||
ULONG PrivatePageCount;
|
||||
VM_COUNTERS VmCounters;
|
||||
IO_COUNTERS IoCounters; // Windows 2000 only
|
||||
SYSTEM_THREADS Threads[1];
|
||||
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
|
||||
|
||||
typedef NTSTATUS NTAPI
|
||||
ZwQuerySystemInformationFunc(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
IN OUT PVOID SystemInformation,
|
||||
IN ULONG SystemInformationLength,
|
||||
OUT PULONG ReturnLength OPTIONAL
|
||||
);
|
||||
|
||||
typedef struct _DEBUG_BUFFER {
|
||||
HANDLE SectionHandle;
|
||||
PVOID SectionBase;
|
||||
PVOID RemoteSectionBase;
|
||||
ULONG SectionBaseDelta;
|
||||
HANDLE EventPairHandle;
|
||||
ULONG Unknown[2];
|
||||
HANDLE RemoteThreadHandle;
|
||||
ULONG InfoClassMask;
|
||||
ULONG SizeOfInfo;
|
||||
ULONG AllocatedSize;
|
||||
ULONG SectionSize;
|
||||
PVOID ModuleInformation;
|
||||
PVOID BackTraceInformation;
|
||||
PVOID HeapInformation;
|
||||
PVOID LockInformation;
|
||||
PVOID Reserved[8];
|
||||
} DEBUG_BUFFER, *PDEBUG_BUFFER;
|
||||
|
||||
typedef PDEBUG_BUFFER NTAPI
|
||||
RtlCreateQueryDebugBufferFunc(IN ULONG Size,
|
||||
IN BOOLEAN EventPair);
|
||||
|
||||
#define PDI_MODULES 0x01 // The loaded modules of the process
|
||||
#define PDI_BACKTRACE 0x02 // The heap stack back traces
|
||||
#define PDI_HEAPS 0x04 // The heaps of the process
|
||||
#define PDI_HEAP_TAGS 0x08 // The heap tags
|
||||
#define PDI_HEAP_BLOCKS 0x10 // The heap blocks
|
||||
#define PDI_LOCKS 0x20 // The locks created by the process
|
||||
|
||||
typedef struct _DEBUG_MODULE_INFORMATION { // c.f. SYSTEM_MODULE_INFORMATION
|
||||
ULONG Reserved[2];
|
||||
ULONG Base;
|
||||
ULONG Size;
|
||||
ULONG Flags;
|
||||
USHORT Index;
|
||||
USHORT Unknown;
|
||||
USHORT LoadCount;
|
||||
USHORT ModuleNameOffset;
|
||||
CHAR ImageName[256];
|
||||
} DEBUG_MODULE_INFORMATION, *PDEBUG_MODULE_INFORMATION;
|
||||
|
||||
// Flags
|
||||
#define LDRP_STATIC_LINK 0x00000002
|
||||
#define LDRP_IMAGE_DLL 0x00000004
|
||||
#define LDRP_LOAD_IN_PROGRESS 0x00001000
|
||||
#define LDRP_UNLOAD_IN_PROGRESS 0x00002000
|
||||
#define LDRP_ENTRY_PROCESSED 0x00004000
|
||||
#define LDRP_ENTRY_INSERTED 0x00008000
|
||||
#define LDRP_CURRENT_LOAD 0x00010000
|
||||
#define LDRP_FAILED_BUILTIN_LOAD 0x00020000
|
||||
#define LDRP_DONT_CALL_FOR_THREADS 0x00040000
|
||||
#define LDRP_PROCESS_ATTACH_CALLED 0x00080000
|
||||
#define LDRP_DEBUG_SYMBOLS_LOADED 0x00100000
|
||||
#define LDRP_IMAGE_NOT_AT_BASE 0x00200000
|
||||
#define LDRP_WX86_IGNORE_MACHINETYPE 0x00400000
|
||||
|
||||
// NOTE that this will require creating a thread in the target
|
||||
// process, implying that we can not call this while the process is
|
||||
// suspended. May have to run this command in the child processes
|
||||
// rather than the server.
|
||||
|
||||
typedef NTSTATUS NTAPI
|
||||
RtlQueryProcessDebugInformationFunc(IN ULONG ProcessId,
|
||||
IN ULONG DebugInfoClassMask,
|
||||
IN OUT PDEBUG_BUFFER DebugBuffer);
|
||||
|
||||
typedef NTSTATUS NTAPI
|
||||
RtlDestroyQueryDebugBufferFunc(IN PDEBUG_BUFFER DebugBuffer);
|
||||
|
||||
// Routines to load and unload NTDLL.DLL.
|
||||
HMODULE loadNTDLL();
|
||||
// Safe to call even if has not been loaded
|
||||
void unloadNTDLL();
|
||||
|
||||
} // extern "C"
|
||||
} // namespace NT4
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// On NT 4 only, we now use PSAPI to enumerate the loaded modules in
|
||||
// the target processes. RtlQueryProcessDebugInformation creates a
|
||||
// thread in the target process, which causes problems when we are
|
||||
// handling events like breakpoints in the debugger. The dependence on
|
||||
// an external DLL which might not be present is unfortunate, but we
|
||||
// can either redistribute this DLL (if allowed) or refuse to start on
|
||||
// NT 4 if it is not present.
|
||||
|
||||
typedef struct _MODULEINFO {
|
||||
LPVOID lpBaseOfDll;
|
||||
DWORD SizeOfImage;
|
||||
LPVOID EntryPoint;
|
||||
} MODULEINFO, *LPMODULEINFO;
|
||||
|
||||
typedef BOOL (WINAPI EnumProcessModulesFunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
|
||||
typedef DWORD (WINAPI GetModuleFileNameExFunc)(HANDLE, HMODULE, LPTSTR, DWORD);
|
||||
typedef BOOL (WINAPI GetModuleInformationFunc)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
|
||||
// Routines to load and unload PSAPI.DLL.
|
||||
HMODULE loadPSAPIDLL();
|
||||
// Safe to call even if has not been loaded
|
||||
void unloadPSAPIDLL();
|
||||
|
||||
#endif // #defined _NT4INTERNALS_H_
|
@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "procList.hpp"
|
||||
#include "nt4internals.hpp"
|
||||
#include "isNT4.hpp"
|
||||
#include "toolHelp.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace NT4;
|
||||
|
||||
typedef void ProcListImplFunc(ProcEntryList& processes);
|
||||
|
||||
void procListImplNT4(ProcEntryList& processes);
|
||||
void procListImplToolHelp(ProcEntryList& processes);
|
||||
|
||||
ProcEntry::ProcEntry(ULONG pid, USHORT nameLength, WCHAR* name) {
|
||||
this->pid = pid;
|
||||
this->nameLength = nameLength;
|
||||
this->name = new WCHAR[nameLength];
|
||||
memcpy(this->name, name, nameLength * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
ProcEntry::ProcEntry(ULONG pid, USHORT nameLength, char* name) {
|
||||
this->pid = pid;
|
||||
this->nameLength = nameLength;
|
||||
this->name = new WCHAR[nameLength];
|
||||
int j = 0;
|
||||
for (int i = 0; i < nameLength; i++) {
|
||||
// FIXME: what is the proper promotion from ASCII to UNICODE?
|
||||
this->name[i] = name[i] & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
ProcEntry::ProcEntry(const ProcEntry& arg) {
|
||||
name = NULL;
|
||||
copyFrom(arg);
|
||||
}
|
||||
|
||||
ProcEntry&
|
||||
ProcEntry::operator=(const ProcEntry& arg) {
|
||||
copyFrom(arg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProcEntry::~ProcEntry() {
|
||||
delete[] name;
|
||||
}
|
||||
|
||||
void
|
||||
ProcEntry::copyFrom(const ProcEntry& arg) {
|
||||
if (name != NULL) {
|
||||
delete[] name;
|
||||
}
|
||||
pid = arg.pid;
|
||||
nameLength = arg.nameLength;
|
||||
name = new WCHAR[nameLength];
|
||||
memcpy(name, arg.name, nameLength * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
ULONG
|
||||
ProcEntry::getPid() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
USHORT
|
||||
ProcEntry::getNameLength() {
|
||||
return nameLength;
|
||||
}
|
||||
|
||||
WCHAR*
|
||||
ProcEntry::getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
procList(ProcEntryList& processes) {
|
||||
static ProcListImplFunc* impl = NULL;
|
||||
|
||||
if (impl == NULL) {
|
||||
// See which operating system we're on
|
||||
impl = (isNT4() ? &procListImplNT4 : &procListImplToolHelp);
|
||||
}
|
||||
|
||||
assert(impl != NULL);
|
||||
|
||||
(*impl)(processes);
|
||||
}
|
||||
|
||||
void
|
||||
procListImplNT4(ProcEntryList& processes) {
|
||||
using namespace NT4;
|
||||
|
||||
static ZwQuerySystemInformationFunc* query = NULL;
|
||||
|
||||
if (query == NULL) {
|
||||
HMODULE ntDLL = loadNTDLL();
|
||||
query =
|
||||
(ZwQuerySystemInformationFunc*) GetProcAddress(ntDLL,
|
||||
"ZwQuerySystemInformation");
|
||||
assert(query != NULL);
|
||||
}
|
||||
|
||||
ULONG n = 0x100;
|
||||
PSYSTEM_PROCESSES sp = new SYSTEM_PROCESSES[n];
|
||||
while ((*query)(SystemProcessesAndThreadsInformation,
|
||||
sp, n * sizeof(SYSTEM_PROCESSES), 0) == STATUS_INFO_LENGTH_MISMATCH) {
|
||||
delete[] sp;
|
||||
n *= 2;
|
||||
sp = new SYSTEM_PROCESSES[n];
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
for (PSYSTEM_PROCESSES p = sp; !done;
|
||||
p = PSYSTEM_PROCESSES(PCHAR(p) + p->NextEntryDelta)) {
|
||||
processes.push_back(ProcEntry(p->ProcessId,
|
||||
p->ProcessName.Length / 2,
|
||||
p->ProcessName.Buffer));
|
||||
done = p->NextEntryDelta == 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
procListImplToolHelp(ProcEntryList& processes) {
|
||||
using namespace ToolHelp;
|
||||
|
||||
static CreateToolhelp32SnapshotFunc* snapshotFunc = NULL;
|
||||
static Process32FirstFunc* firstFunc = NULL;
|
||||
static Process32NextFunc* nextFunc = NULL;
|
||||
|
||||
if (snapshotFunc == NULL) {
|
||||
HMODULE dll = loadDLL();
|
||||
|
||||
snapshotFunc =
|
||||
(CreateToolhelp32SnapshotFunc*) GetProcAddress(dll,
|
||||
"CreateToolhelp32Snapshot");
|
||||
|
||||
firstFunc = (Process32FirstFunc*) GetProcAddress(dll,
|
||||
"Process32First");
|
||||
|
||||
nextFunc = (Process32NextFunc*) GetProcAddress(dll,
|
||||
"Process32Next");
|
||||
|
||||
assert(snapshotFunc != NULL);
|
||||
assert(firstFunc != NULL);
|
||||
assert(nextFunc != NULL);
|
||||
}
|
||||
|
||||
HANDLE snapshot = (*snapshotFunc)(TH32CS_SNAPPROCESS, 0 /* ignored */);
|
||||
if (snapshot == (HANDLE) -1) {
|
||||
// Error occurred during snapshot
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate
|
||||
PROCESSENTRY32 proc;
|
||||
if ((*firstFunc)(snapshot, &proc)) {
|
||||
do {
|
||||
// FIXME: could make this uniform to the NT version by cutting
|
||||
// off the path name just before the executable name
|
||||
processes.push_back(ProcEntry(proc.th32ProcessID,
|
||||
strlen(proc.szExeFile),
|
||||
proc.szExeFile));
|
||||
} while ((*nextFunc)(snapshot, &proc));
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2003, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "serverLists.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Lists
|
||||
//
|
||||
|
||||
CRITICAL_SECTION Lists::crit;
|
||||
|
||||
void
|
||||
Lists::init() {
|
||||
InitializeCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void
|
||||
Lists::lock() {
|
||||
EnterCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void
|
||||
Lists::unlock() {
|
||||
LeaveCriticalSection(&crit);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ListsLocker
|
||||
//
|
||||
|
||||
ListsLocker::ListsLocker() {
|
||||
Lists::lock();
|
||||
}
|
||||
|
||||
ListsLocker::~ListsLocker() {
|
||||
Lists::unlock();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ChildInfo
|
||||
//
|
||||
|
||||
ChildInfo::ChildInfo(DWORD pid, HANDLE childProcessHandle,
|
||||
HANDLE writeToStdinHandle, HANDLE readFromStdoutHandle,
|
||||
HANDLE auxHandle1, HANDLE auxHandle2) {
|
||||
this->pid = pid;
|
||||
this->childProcessHandle = childProcessHandle;
|
||||
this->writeToStdinHandle = writeToStdinHandle;
|
||||
this->readFromStdoutHandle = readFromStdoutHandle;
|
||||
this->auxHandle1 = auxHandle1;
|
||||
this->auxHandle2 = auxHandle2;
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
DWORD
|
||||
ChildInfo::getPid() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
ChildInfo::getChildProcessHandle() {
|
||||
return childProcessHandle;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
ChildInfo::getWriteToStdinHandle() {
|
||||
return writeToStdinHandle;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
ChildInfo::getReadFromStdoutHandle() {
|
||||
return readFromStdoutHandle;
|
||||
}
|
||||
|
||||
void
|
||||
ChildInfo::setClient(ClientInfo* clientInfo) {
|
||||
client = clientInfo;
|
||||
}
|
||||
|
||||
ClientInfo*
|
||||
ChildInfo::getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
void
|
||||
ChildInfo::closeAll() {
|
||||
CloseHandle(childProcessHandle);
|
||||
CloseHandle(writeToStdinHandle);
|
||||
CloseHandle(readFromStdoutHandle);
|
||||
CloseHandle(auxHandle1);
|
||||
CloseHandle(auxHandle2);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ChildList
|
||||
//
|
||||
|
||||
ChildList::ChildList() {
|
||||
}
|
||||
|
||||
ChildList::~ChildList() {
|
||||
}
|
||||
|
||||
void
|
||||
ChildList::addChild(ChildInfo* info) {
|
||||
// Could store these in binary sorted order by pid for efficiency
|
||||
childList.push_back(info);
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ChildList::removeChild(HANDLE childProcessHandle) {
|
||||
for (ChildInfoList::iterator iter = childList.begin(); iter != childList.end();
|
||||
iter++) {
|
||||
ChildInfo* info = *iter;
|
||||
if (info->getChildProcessHandle() == childProcessHandle) {
|
||||
childList.erase(iter);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ChildList::removeChild(ChildInfo* info) {
|
||||
for (ChildInfoList::iterator iter = childList.begin(); iter != childList.end();
|
||||
iter++) {
|
||||
if (*iter == info) {
|
||||
childList.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ChildList::getChildByPid(DWORD pid) {
|
||||
for (ChildInfoList::iterator iter = childList.begin(); iter != childList.end();
|
||||
iter++) {
|
||||
ChildInfo* info = *iter;
|
||||
if (info->getPid() == pid) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ChildList::size() {
|
||||
return childList.size();
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ChildList::getChildByIndex(int index) {
|
||||
return childList[index];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ClientInfo
|
||||
//
|
||||
|
||||
ClientInfo::ClientInfo(SOCKET dataSocket) {
|
||||
this->dataSocket = dataSocket;
|
||||
buf = new IOBuf(32768, 131072);
|
||||
buf->setSocket(dataSocket);
|
||||
target = NULL;
|
||||
}
|
||||
|
||||
ClientInfo::~ClientInfo() {
|
||||
delete buf;
|
||||
}
|
||||
|
||||
SOCKET
|
||||
ClientInfo::getDataSocket() {
|
||||
return dataSocket;
|
||||
}
|
||||
|
||||
IOBuf*
|
||||
ClientInfo::getIOBuf() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
ClientInfo::setTarget(ChildInfo* childInfo) {
|
||||
target = childInfo;
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ClientInfo::getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
void
|
||||
ClientInfo::closeAll() {
|
||||
shutdown(dataSocket, SD_BOTH);
|
||||
closesocket(dataSocket);
|
||||
dataSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ClientList
|
||||
//
|
||||
|
||||
ClientList::ClientList() {
|
||||
}
|
||||
|
||||
ClientList::~ClientList() {
|
||||
}
|
||||
|
||||
void
|
||||
ClientList::addClient(ClientInfo* info) {
|
||||
clientList.push_back(info);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientList::isAnyDataSocketSet(fd_set* fds, ClientInfo** out) {
|
||||
for (ClientInfoList::iterator iter = clientList.begin(); iter != clientList.end();
|
||||
iter++) {
|
||||
ClientInfo* info = *iter;
|
||||
if (FD_ISSET(info->getDataSocket(), fds)) {
|
||||
*out = info;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ClientList::removeClient(ClientInfo* client) {
|
||||
for (ClientInfoList::iterator iter = clientList.begin(); iter != clientList.end();
|
||||
iter++) {
|
||||
if (*iter == client) {
|
||||
clientList.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
int
|
||||
ClientList::size() {
|
||||
return clientList.size();
|
||||
}
|
||||
|
||||
ClientInfo*
|
||||
ClientList::get(int num) {
|
||||
return clientList[num];
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2003, 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.
|
||||
*
|
||||
* 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 _SERVER_LISTS_
|
||||
#define _SERVER_LISTS_
|
||||
|
||||
#include <vector>
|
||||
#include <winsock2.h>
|
||||
#include "IOBuf.hpp"
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
//
|
||||
// All of these lists are guarded by the global lock managed by the
|
||||
// Lists class. Lists::init() must be called at the start of the
|
||||
// program.
|
||||
//
|
||||
|
||||
class Lists {
|
||||
friend class ListsLocker;
|
||||
public:
|
||||
static void init();
|
||||
private:
|
||||
static void lock();
|
||||
static void unlock();
|
||||
static CRITICAL_SECTION crit;
|
||||
};
|
||||
|
||||
// Should be allocated on stack. Ensures proper locking/unlocking
|
||||
// pairing.
|
||||
class ListsLocker {
|
||||
public:
|
||||
ListsLocker();
|
||||
~ListsLocker();
|
||||
};
|
||||
|
||||
// We must keep track of all of the child processes we have forked to
|
||||
// handle attaching to a target process. This is necessary because we
|
||||
// allow clients to detach from processes, but the child processes we
|
||||
// fork must necessarily stay alive for the duration of the target
|
||||
// application. A subsequent attach operation to the target process
|
||||
// results in the same child process being reused. For this reason,
|
||||
// child processes are known to be in one of two states: attached and
|
||||
// detached.
|
||||
|
||||
class ClientInfo;
|
||||
|
||||
class ChildInfo {
|
||||
public:
|
||||
/** The pid of the ChildInfo indicates the process ID of the target
|
||||
process which the subprocess was created to debug, not the pid
|
||||
of the subprocess itself. */
|
||||
ChildInfo(DWORD pid, HANDLE childProcessHandle,
|
||||
HANDLE writeToStdinHandle, HANDLE readFromStdoutHandle,
|
||||
HANDLE auxHandle1, HANDLE auxHandle2);
|
||||
|
||||
DWORD getPid();
|
||||
HANDLE getChildProcessHandle();
|
||||
HANDLE getWriteToStdinHandle();
|
||||
HANDLE getReadFromStdoutHandle();
|
||||
|
||||
/** Set the client which is currently attached to the target process
|
||||
via this child process. Set this to NULL to indicate that the
|
||||
child process is ready to accept another attachment. */
|
||||
void setClient(ClientInfo* clientInfo);
|
||||
|
||||
ClientInfo* getClient();
|
||||
|
||||
/** This is NOT automatically called in the destructor */
|
||||
void closeAll();
|
||||
|
||||
private:
|
||||
DWORD pid;
|
||||
HANDLE childProcessHandle;
|
||||
HANDLE writeToStdinHandle;
|
||||
HANDLE readFromStdoutHandle;
|
||||
HANDLE auxHandle1;
|
||||
HANDLE auxHandle2;
|
||||
ClientInfo* client;
|
||||
};
|
||||
|
||||
// We keep track of a list of child debugger processes, each of which
|
||||
// is responsible for debugging a certain target process. These
|
||||
// debugger processes can serve multiple clients during their
|
||||
// lifetime. When a client detaches from a given process or tells the
|
||||
// debugger to "exit", the debug server is notified that the child
|
||||
// process is once again available to accept connections from clients.
|
||||
|
||||
class ChildList {
|
||||
private:
|
||||
typedef std::vector<ChildInfo*> ChildInfoList;
|
||||
|
||||
public:
|
||||
ChildList();
|
||||
~ChildList();
|
||||
|
||||
void addChild(ChildInfo*);
|
||||
|
||||
/** Removes and returns the ChildInfo* associated with the given
|
||||
child process handle. */
|
||||
ChildInfo* removeChild(HANDLE childProcessHandle);
|
||||
|
||||
/** Removes the given ChildInfo. */
|
||||
void removeChild(ChildInfo* info);
|
||||
|
||||
/** Return the ChildInfo* associated with a given process ID without
|
||||
removing it from the list. */
|
||||
ChildInfo* getChildByPid(DWORD pid);
|
||||
|
||||
/** Iteration support */
|
||||
int size();
|
||||
|
||||
/** Iteration support */
|
||||
ChildInfo* getChildByIndex(int index);
|
||||
|
||||
private:
|
||||
ChildInfoList childList;
|
||||
};
|
||||
|
||||
// We also keep a list of clients whose requests we are responsible
|
||||
// for serving. Clients can attach and detach from child processes.
|
||||
|
||||
class ClientInfo {
|
||||
public:
|
||||
ClientInfo(SOCKET dataSocket);
|
||||
~ClientInfo();
|
||||
|
||||
SOCKET getDataSocket();
|
||||
/** Gets an IOBuf configured for the data socket, which should be
|
||||
used for all communication with the client. */
|
||||
IOBuf* getIOBuf();
|
||||
|
||||
/** Set the information for the process to which this client is
|
||||
attached. Set this to NULL to indicate that the client is not
|
||||
currently attached to any target process. */
|
||||
void setTarget(ChildInfo* childInfo);
|
||||
|
||||
/** Get the information for the process to which this client is
|
||||
currently attached, or NULL if none. */
|
||||
ChildInfo* getTarget();
|
||||
|
||||
/** Close down the socket connection to this client. This is NOT
|
||||
automatically called by the destructor. */
|
||||
void closeAll();
|
||||
|
||||
private:
|
||||
SOCKET dataSocket;
|
||||
IOBuf* buf;
|
||||
ChildInfo* target;
|
||||
};
|
||||
|
||||
class ClientList {
|
||||
private:
|
||||
typedef std::vector<ClientInfo*> ClientInfoList;
|
||||
|
||||
public:
|
||||
ClientList();
|
||||
~ClientList();
|
||||
|
||||
/** Adds a client to the list. */
|
||||
void addClient(ClientInfo* info);
|
||||
|
||||
/** Check to see whether the parent socket of any of the ClientInfo
|
||||
objects is readable in the given fd_set. If so, returns TRUE and
|
||||
sets the given ClientInfo* (a non-NULL pointer to which must be
|
||||
given) appropriately. */
|
||||
bool isAnyDataSocketSet(fd_set* fds, ClientInfo** info);
|
||||
|
||||
/** Removes a client from the list. User is responsible for deleting
|
||||
the ClientInfo* using operator delete. */
|
||||
void removeClient(ClientInfo* client);
|
||||
|
||||
/** Iteration support. */
|
||||
int size();
|
||||
|
||||
/** Iteration support. */
|
||||
ClientInfo* get(int num);
|
||||
|
||||
private:
|
||||
ClientInfoList clientList;
|
||||
};
|
||||
|
||||
#endif // #defined _SERVER_LISTS_
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.
|
||||
*
|
||||
* 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 _TOOLHELP_H_
|
||||
#define _TOOLHELP_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
namespace ToolHelp {
|
||||
extern "C" {
|
||||
|
||||
///////////////
|
||||
// Snapshots //
|
||||
///////////////
|
||||
typedef HANDLE WINAPI
|
||||
CreateToolhelp32SnapshotFunc(DWORD dwFlags, DWORD th32ProcessID);
|
||||
|
||||
//////////////////
|
||||
// Process List //
|
||||
//////////////////
|
||||
typedef BOOL WINAPI Process32FirstFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32 lppe);
|
||||
|
||||
typedef BOOL WINAPI Process32NextFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32 lppe);
|
||||
|
||||
// NOTE: although these routines are defined in TLHELP32.H, they
|
||||
// seem to always return false (maybe only under US locales)
|
||||
typedef BOOL WINAPI Process32FirstWFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32W lppe);
|
||||
|
||||
typedef BOOL WINAPI Process32NextWFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32W lppe);
|
||||
|
||||
/////////////////
|
||||
// Module List //
|
||||
/////////////////
|
||||
typedef BOOL WINAPI
|
||||
Module32FirstFunc(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
|
||||
|
||||
typedef BOOL WINAPI
|
||||
Module32NextFunc (HANDLE hSnapshot, LPMODULEENTRY32 lpme);
|
||||
|
||||
|
||||
// Routines to load and unload KERNEL32.DLL.
|
||||
HMODULE loadDLL();
|
||||
// Safe to call even if has not been loaded
|
||||
void unloadDLL();
|
||||
|
||||
} // extern "C"
|
||||
} // namespace "ToolHelp"
|
||||
|
||||
#endif // #defined _TOOLHELP_H_
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2003, 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
|
||||
@ -22,25 +22,30 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.debugger.dbx.sparc;
|
||||
package sun.jvm.hotspot;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.sparc.*;
|
||||
import sun.jvm.hotspot.debugger.dbx.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
import sun.jvm.hotspot.types.basic.*;
|
||||
|
||||
public class DbxSPARCThreadContext extends SPARCThreadContext {
|
||||
private DbxDebugger debugger;
|
||||
public class BsdVtblAccess extends BasicVtblAccess {
|
||||
private String vt;
|
||||
|
||||
public DbxSPARCThreadContext(DbxDebugger debugger) {
|
||||
super();
|
||||
this.debugger = debugger;
|
||||
public BsdVtblAccess(SymbolLookup symbolLookup,
|
||||
String[] dllNames) {
|
||||
super(symbolLookup, dllNames);
|
||||
|
||||
if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null ||
|
||||
symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) {
|
||||
// old C++ ABI
|
||||
vt = "__vt_";
|
||||
} else {
|
||||
// new C++ ABI
|
||||
vt = "_ZTV";
|
||||
}
|
||||
}
|
||||
|
||||
public void setRegisterAsAddress(int index, Address value) {
|
||||
setRegister(index, debugger.getAddressValue(value));
|
||||
}
|
||||
|
||||
public Address getRegisterAsAddress(int index) {
|
||||
return debugger.newAddress(getRegister(index));
|
||||
protected String vtblSymbolForType(Type type) {
|
||||
return vt + type.getName().length() + type;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2011, 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
|
||||
@ -170,6 +170,7 @@ public class CLHSDB {
|
||||
final String errMsg = formatMessage(e.getMessage(), 80);
|
||||
System.err.println("Unable to connect to process ID " + pid + ":\n\n" + errMsg);
|
||||
agent.detach();
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -191,6 +192,7 @@ public class CLHSDB {
|
||||
final String errMsg = formatMessage(e.getMessage(), 80);
|
||||
System.err.println("Unable to open core file\n" + corePath + ":\n\n" + errMsg);
|
||||
agent.detach();
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -209,6 +211,7 @@ public class CLHSDB {
|
||||
final String errMsg = formatMessage(e.getMessage(), 80);
|
||||
System.err.println("Unable to connect to machine \"" + remoteMachineName + "\":\n\n" + errMsg);
|
||||
agent.detach();
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.interpreter.*;
|
||||
import sun.jvm.hotspot.memory.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.opto.*;
|
||||
import sun.jvm.hotspot.ci.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.utilities.*;
|
||||
import sun.jvm.hotspot.utilities.soql.*;
|
||||
@ -48,6 +50,8 @@ import sun.jvm.hotspot.ui.tree.*;
|
||||
import sun.jvm.hotspot.tools.*;
|
||||
import sun.jvm.hotspot.tools.ObjectHistogram;
|
||||
import sun.jvm.hotspot.tools.StackTrace;
|
||||
import sun.jvm.hotspot.tools.jcore.ClassDump;
|
||||
import sun.jvm.hotspot.tools.jcore.ClassFilter;
|
||||
|
||||
public class CommandProcessor {
|
||||
public abstract static class DebuggerInterface {
|
||||
@ -59,6 +63,27 @@ public class CommandProcessor {
|
||||
public abstract void reattach();
|
||||
}
|
||||
|
||||
public static class BootFilter implements ClassFilter {
|
||||
public boolean canInclude(InstanceKlass kls) {
|
||||
return kls.getClassLoader() == null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NonBootFilter implements ClassFilter {
|
||||
private HashMap emitted = new HashMap();
|
||||
public boolean canInclude(InstanceKlass kls) {
|
||||
if (kls.getClassLoader() == null) return false;
|
||||
if (emitted.get(kls.getName()) != null) {
|
||||
// Since multiple class loaders are being shoved
|
||||
// together duplicate classes are a possibilty. For
|
||||
// now just ignore them.
|
||||
return false;
|
||||
}
|
||||
emitted.put(kls.getName(), kls);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class Tokens {
|
||||
final String input;
|
||||
int i;
|
||||
@ -258,9 +283,14 @@ public class CommandProcessor {
|
||||
}
|
||||
|
||||
void dumpFields(Type type) {
|
||||
dumpFields(type, true);
|
||||
}
|
||||
|
||||
void dumpFields(Type type, boolean allowStatic) {
|
||||
Iterator i = type.getFields();
|
||||
while (i.hasNext()) {
|
||||
Field f = (Field) i.next();
|
||||
if (!allowStatic && f.isStatic()) continue;
|
||||
out.print("field ");
|
||||
quote(type.getName());
|
||||
out.print(" ");
|
||||
@ -458,13 +488,18 @@ public class CommandProcessor {
|
||||
});
|
||||
}
|
||||
},
|
||||
new Command("flags", "flags [ flag ]", false) {
|
||||
new Command("flags", "flags [ flag | -nd ]", false) {
|
||||
public void doit(Tokens t) {
|
||||
int tokens = t.countTokens();
|
||||
if (tokens != 0 && tokens != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = tokens > 0 ? t.nextToken() : null;
|
||||
boolean nonDefault = false;
|
||||
if (name != null && name.equals("-nd")) {
|
||||
name = null;
|
||||
nonDefault = true;
|
||||
}
|
||||
|
||||
VM.Flag[] flags = VM.getVM().getCommandLineFlags();
|
||||
if (flags == null) {
|
||||
@ -474,7 +509,12 @@ public class CommandProcessor {
|
||||
for (int f = 0; f < flags.length; f++) {
|
||||
VM.Flag flag = flags[f];
|
||||
if (name == null || flag.getName().equals(name)) {
|
||||
out.println(flag.getName() + " = " + flag.getValue());
|
||||
|
||||
if (nonDefault && flag.getOrigin() == 0) {
|
||||
// only print flags which aren't their defaults
|
||||
continue;
|
||||
}
|
||||
out.println(flag.getName() + " = " + flag.getValue() + " " + flag.getOrigin());
|
||||
printed = true;
|
||||
}
|
||||
}
|
||||
@ -586,6 +626,158 @@ public class CommandProcessor {
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("printmdo", "printmdo [ -a | expression ]", false) {
|
||||
// Print every MDO in the heap or the one referenced by expression.
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String s = t.nextToken();
|
||||
if (s.equals("-a")) {
|
||||
HeapVisitor iterator = new DefaultHeapVisitor() {
|
||||
public boolean doObj(Oop obj) {
|
||||
if (obj instanceof MethodData) {
|
||||
Method m = ((MethodData)obj).getMethod();
|
||||
out.println("MethodData " + obj.getHandle() + " for " +
|
||||
"method " + m.getMethodHolder().getName().asString() + "." +
|
||||
m.getName().asString() +
|
||||
m.getSignature().asString() + "@" + m.getHandle());
|
||||
((MethodData)obj).printDataOn(out);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
VM.getVM().getObjectHeap().iteratePerm(iterator);
|
||||
} else {
|
||||
Address a = VM.getVM().getDebugger().parseAddress(s);
|
||||
OopHandle handle = a.addOffsetToAsOopHandle(0);
|
||||
MethodData mdo = (MethodData)VM.getVM().getObjectHeap().newOop(handle);
|
||||
mdo.printDataOn(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("dumpideal", "dumpideal { -a | id }", false) {
|
||||
// Do a full dump of the nodes reachabile from root in each compiler thread.
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = t.nextToken();
|
||||
boolean all = name.equals("-a");
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thread.printThreadIDOn(new PrintStream(bos));
|
||||
if (all || bos.toString().equals(name)) {
|
||||
if (thread instanceof CompilerThread) {
|
||||
CompilerThread ct = (CompilerThread)thread;
|
||||
out.println(ct);
|
||||
ciEnv env = ct.env();
|
||||
if (env != null) {
|
||||
Compile c = env.compilerData();
|
||||
c.root().dump(9999, out);
|
||||
} else {
|
||||
out.println(" not compiling");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("dumpcfg", "dumpcfg { -a | id }", false) {
|
||||
// Dump the PhaseCFG for every compiler thread that has one live.
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = t.nextToken();
|
||||
boolean all = name.equals("-a");
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thread.printThreadIDOn(new PrintStream(bos));
|
||||
if (all || bos.toString().equals(name)) {
|
||||
if (thread instanceof CompilerThread) {
|
||||
CompilerThread ct = (CompilerThread)thread;
|
||||
out.println(ct);
|
||||
ciEnv env = ct.env();
|
||||
if (env != null) {
|
||||
Compile c = env.compilerData();
|
||||
c.cfg().dump(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("dumpilt", "dumpilt { -a | id }", false) {
|
||||
// dumps the InlineTree of a C2 compile
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = t.nextToken();
|
||||
boolean all = name.equals("-a");
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thread.printThreadIDOn(new PrintStream(bos));
|
||||
if (all || bos.toString().equals(name)) {
|
||||
if (thread instanceof CompilerThread) {
|
||||
CompilerThread ct = (CompilerThread)thread;
|
||||
ciEnv env = ct.env();
|
||||
if (env != null) {
|
||||
Compile c = env.compilerData();
|
||||
InlineTree ilt = c.ilt();
|
||||
if (ilt != null) {
|
||||
ilt.print(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("vmstructsdump", "vmstructsdump", false) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 0) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
// Dump a copy of the type database in a form that can
|
||||
// be read back.
|
||||
Iterator i = agent.getTypeDataBase().getTypes();
|
||||
// Make sure the types are emitted in an order than can be read back in
|
||||
HashSet emitted = new HashSet();
|
||||
Stack pending = new Stack();
|
||||
while (i.hasNext()) {
|
||||
Type n = (Type)i.next();
|
||||
if (emitted.contains(n.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (n != null && !emitted.contains(n.getName())) {
|
||||
pending.push(n);
|
||||
n = n.getSuperclass();
|
||||
}
|
||||
while (!pending.empty()) {
|
||||
n = (Type)pending.pop();
|
||||
dumpType(n);
|
||||
emitted.add(n.getName());
|
||||
}
|
||||
}
|
||||
i = agent.getTypeDataBase().getTypes();
|
||||
while (i.hasNext()) {
|
||||
dumpFields((Type)i.next(), false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
new Command("inspect", "inspect expression", false) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
@ -760,6 +952,50 @@ public class CommandProcessor {
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("intConstant", "intConstant [ name [ value ] ]", true) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
||||
if (t.countTokens() == 1) {
|
||||
out.println("intConstant " + name + " " + db.lookupIntConstant(name));
|
||||
} else if (t.countTokens() == 0) {
|
||||
Iterator i = db.getIntConstants();
|
||||
while (i.hasNext()) {
|
||||
String name = (String)i.next();
|
||||
out.println("intConstant " + name + " " + db.lookupIntConstant(name));
|
||||
}
|
||||
} else if (t.countTokens() == 2) {
|
||||
String name = t.nextToken();
|
||||
Integer value = Integer.valueOf(t.nextToken());
|
||||
db.addIntConstant(name, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("longConstant", "longConstant [ name [ value ] ]", true) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
||||
if (t.countTokens() == 1) {
|
||||
out.println("longConstant " + name + " " + db.lookupLongConstant(name));
|
||||
} else if (t.countTokens() == 0) {
|
||||
Iterator i = db.getLongConstants();
|
||||
while (i.hasNext()) {
|
||||
String name = (String)i.next();
|
||||
out.println("longConstant " + name + " " + db.lookupLongConstant(name));
|
||||
}
|
||||
} else if (t.countTokens() == 2) {
|
||||
String name = t.nextToken();
|
||||
Long value = Long.valueOf(t.nextToken());
|
||||
db.addLongConstant(name, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
|
||||
@ -1311,13 +1547,13 @@ public class CommandProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
executeCommand(ln);
|
||||
executeCommand(ln, prompt);
|
||||
}
|
||||
}
|
||||
|
||||
static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*)|(![a-zA-Z][^ ]*))");
|
||||
|
||||
public void executeCommand(String ln) {
|
||||
public void executeCommand(String ln, boolean putInHistory) {
|
||||
if (ln.indexOf('!') != -1) {
|
||||
int size = history.size();
|
||||
if (size == 0) {
|
||||
@ -1406,7 +1642,7 @@ public class CommandProcessor {
|
||||
Tokens t = new Tokens(ln);
|
||||
if (t.hasMoreTokens()) {
|
||||
boolean error = false;
|
||||
history.add(ln);
|
||||
if (putInHistory) history.add(ln);
|
||||
int len = t.countTokens();
|
||||
if (len > 2) {
|
||||
String r = t.at(len - 2);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -25,7 +25,6 @@
|
||||
package sun.jvm.hotspot;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.dbx.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
|
||||
|
@ -1740,7 +1740,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
||||
else if (f.isCompiledFrame()) { tty.print("compiled"); }
|
||||
else if (f.isEntryFrame()) { tty.print("entry"); }
|
||||
else if (f.isNativeFrame()) { tty.print("native"); }
|
||||
else if (f.isGlueFrame()) { tty.print("glue"); }
|
||||
else if (f.isRuntimeFrame()) { tty.print("runtime"); }
|
||||
else { tty.print("external"); }
|
||||
tty.print(" frame with PC = " + f.getPC() + ", SP = " + f.getSP() + ", FP = " + f.getFP());
|
||||
if (f.isSignalHandlerFrameDbg()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -28,10 +28,9 @@ import java.io.PrintStream;
|
||||
import java.net.*;
|
||||
import java.rmi.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.dbx.*;
|
||||
import sun.jvm.hotspot.debugger.bsd.*;
|
||||
import sun.jvm.hotspot.debugger.proc.*;
|
||||
import sun.jvm.hotspot.debugger.remote.*;
|
||||
import sun.jvm.hotspot.debugger.win32.*;
|
||||
import sun.jvm.hotspot.debugger.windbg.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.memory.*;
|
||||
@ -337,6 +336,8 @@ public class HotSpotAgent {
|
||||
setupDebuggerWin32();
|
||||
} else if (os.equals("linux")) {
|
||||
setupDebuggerLinux();
|
||||
} else if (os.equals("bsd")) {
|
||||
setupDebuggerBsd();
|
||||
} else {
|
||||
// Add support for more operating systems here
|
||||
throw new DebuggerException("Operating system " + os + " not yet supported");
|
||||
@ -392,6 +393,10 @@ public class HotSpotAgent {
|
||||
db = new HotSpotTypeDataBase(machDesc,
|
||||
new LinuxVtblAccess(debugger, jvmLibNames),
|
||||
debugger, jvmLibNames);
|
||||
} else if (os.equals("bsd")) {
|
||||
db = new HotSpotTypeDataBase(machDesc,
|
||||
new BsdVtblAccess(debugger, jvmLibNames),
|
||||
debugger, jvmLibNames);
|
||||
} else {
|
||||
throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)");
|
||||
}
|
||||
@ -436,113 +441,35 @@ public class HotSpotAgent {
|
||||
|
||||
private void setupDebuggerSolaris() {
|
||||
setupJVMLibNamesSolaris();
|
||||
if(System.getProperty("sun.jvm.hotspot.debugger.useProcDebugger") != null) {
|
||||
ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true);
|
||||
debugger = dbg;
|
||||
attachDebugger();
|
||||
ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true);
|
||||
debugger = dbg;
|
||||
attachDebugger();
|
||||
|
||||
// Set up CPU-dependent stuff
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("sparc")) {
|
||||
int addressSize = dbg.getRemoteProcessAddressSize();
|
||||
if (addressSize == -1) {
|
||||
throw new DebuggerException("Error occurred while trying to determine the remote process's " +
|
||||
"address size");
|
||||
}
|
||||
|
||||
if (addressSize == 32) {
|
||||
machDesc = new MachineDescriptionSPARC32Bit();
|
||||
} else if (addressSize == 64) {
|
||||
machDesc = new MachineDescriptionSPARC64Bit();
|
||||
} else {
|
||||
throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
|
||||
}
|
||||
} else if (cpu.equals("amd64")) {
|
||||
machDesc = new MachineDescriptionAMD64();
|
||||
} else {
|
||||
throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64");
|
||||
// Set up CPU-dependent stuff
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("sparc")) {
|
||||
int addressSize = dbg.getRemoteProcessAddressSize();
|
||||
if (addressSize == -1) {
|
||||
throw new DebuggerException("Error occurred while trying to determine the remote process's " +
|
||||
"address size");
|
||||
}
|
||||
|
||||
dbg.setMachineDescription(machDesc);
|
||||
return;
|
||||
|
||||
if (addressSize == 32) {
|
||||
machDesc = new MachineDescriptionSPARC32Bit();
|
||||
} else if (addressSize == 64) {
|
||||
machDesc = new MachineDescriptionSPARC64Bit();
|
||||
} else {
|
||||
throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
|
||||
}
|
||||
} else if (cpu.equals("amd64")) {
|
||||
machDesc = new MachineDescriptionAMD64();
|
||||
} else {
|
||||
String dbxPathName;
|
||||
String dbxPathPrefix;
|
||||
String dbxSvcAgentDSOPathName;
|
||||
String dbxSvcAgentDSOPathPrefix;
|
||||
String[] dbxSvcAgentDSOPathNames = null;
|
||||
|
||||
// use path names/prefixes specified on command
|
||||
dbxPathName = System.getProperty("dbxPathName");
|
||||
if (dbxPathName == null) {
|
||||
dbxPathPrefix = System.getProperty("dbxPathPrefix");
|
||||
if (dbxPathPrefix == null) {
|
||||
dbxPathPrefix = defaultDbxPathPrefix;
|
||||
}
|
||||
dbxPathName = dbxPathPrefix + fileSep + os + fileSep + cpu + fileSep + "bin" + fileSep + "dbx";
|
||||
}
|
||||
|
||||
dbxSvcAgentDSOPathName = System.getProperty("dbxSvcAgentDSOPathName");
|
||||
if (dbxSvcAgentDSOPathName != null) {
|
||||
dbxSvcAgentDSOPathNames = new String[] { dbxSvcAgentDSOPathName } ;
|
||||
} else {
|
||||
dbxSvcAgentDSOPathPrefix = System.getProperty("dbxSvcAgentDSOPathPrefix");
|
||||
if (dbxSvcAgentDSOPathPrefix == null) {
|
||||
dbxSvcAgentDSOPathPrefix = defaultDbxSvcAgentDSOPathPrefix;
|
||||
}
|
||||
if (cpu.equals("sparc")) {
|
||||
dbxSvcAgentDSOPathNames = new String[] {
|
||||
// FIXME: bad hack for SPARC v9. This is necessary because
|
||||
// there are two dbx executables on SPARC, one for v8 and one
|
||||
// for v9, and it isn't obvious how to tell the two apart
|
||||
// using the dbx command line. See
|
||||
// DbxDebuggerLocal.importDbxModule().
|
||||
dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + "v9" + fileSep + "lib" +
|
||||
fileSep + "libsvc_agent_dbx.so",
|
||||
dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" +
|
||||
fileSep + "libsvc_agent_dbx.so",
|
||||
};
|
||||
} else {
|
||||
dbxSvcAgentDSOPathNames = new String[] {
|
||||
dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" +
|
||||
fileSep + "libsvc_agent_dbx.so"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Note we do not use a cache for the local debugger in server
|
||||
// mode; it's taken care of on the client side
|
||||
DbxDebuggerLocal dbg = new DbxDebuggerLocal(null, dbxPathName, dbxSvcAgentDSOPathNames, !isServer);
|
||||
debugger = dbg;
|
||||
|
||||
attachDebugger();
|
||||
|
||||
// Set up CPU-dependent stuff
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("sparc")) {
|
||||
int addressSize = dbg.getRemoteProcessAddressSize();
|
||||
if (addressSize == -1) {
|
||||
throw new DebuggerException("Error occurred while trying to determine the remote process's " +
|
||||
"address size. It's possible that the Serviceability Agent's dbx module failed to " +
|
||||
"initialize. Examine the standard output and standard error streams from the dbx " +
|
||||
"process for more information.");
|
||||
}
|
||||
|
||||
if (addressSize == 32) {
|
||||
machDesc = new MachineDescriptionSPARC32Bit();
|
||||
} else if (addressSize == 64) {
|
||||
machDesc = new MachineDescriptionSPARC64Bit();
|
||||
} else {
|
||||
throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
|
||||
}
|
||||
}
|
||||
|
||||
dbg.setMachineDescription(machDesc);
|
||||
|
||||
throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64");
|
||||
}
|
||||
|
||||
dbg.setMachineDescription(machDesc);
|
||||
return;
|
||||
}
|
||||
|
||||
private void connectRemoteDebugger() throws DebuggerException {
|
||||
@ -557,6 +484,8 @@ public class HotSpotAgent {
|
||||
setupJVMLibNamesWin32();
|
||||
} else if (os.equals("linux")) {
|
||||
setupJVMLibNamesLinux();
|
||||
} else if (os.equals("bsd")) {
|
||||
setupJVMLibNamesBsd();
|
||||
} else {
|
||||
throw new RuntimeException("Unknown OS type");
|
||||
}
|
||||
@ -589,11 +518,7 @@ public class HotSpotAgent {
|
||||
// mode; it will be taken care of on the client side (once remote
|
||||
// debugging is implemented).
|
||||
|
||||
if (System.getProperty("sun.jvm.hotspot.debugger.useWindbgDebugger") != null) {
|
||||
debugger = new WindbgDebuggerLocal(machDesc, !isServer);
|
||||
} else {
|
||||
debugger = new Win32DebuggerLocal(machDesc, !isServer);
|
||||
}
|
||||
debugger = new WindbgDebuggerLocal(machDesc, !isServer);
|
||||
|
||||
attachDebugger();
|
||||
|
||||
@ -638,6 +563,31 @@ public class HotSpotAgent {
|
||||
jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
|
||||
}
|
||||
|
||||
//
|
||||
// BSD
|
||||
//
|
||||
|
||||
private void setupDebuggerBsd() {
|
||||
setupJVMLibNamesBsd();
|
||||
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("amd64")) {
|
||||
machDesc = new MachineDescriptionAMD64();
|
||||
} else {
|
||||
throw new DebuggerException("BSD only supported on x86/amd64");
|
||||
}
|
||||
|
||||
BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer);
|
||||
debugger = dbg;
|
||||
|
||||
attachDebugger();
|
||||
}
|
||||
|
||||
private void setupJVMLibNamesBsd() {
|
||||
jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
|
||||
}
|
||||
|
||||
/** Convenience routine which should be called by per-platform
|
||||
debugger setup. Should not be called when startupMode is
|
||||
REMOTE_MODE. */
|
||||
|
@ -87,6 +87,7 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase {
|
||||
readVMStructs();
|
||||
readVMIntConstants();
|
||||
readVMLongConstants();
|
||||
readExternalDefinitions();
|
||||
}
|
||||
|
||||
public Type lookupType(String cTypeName, boolean throwException) {
|
||||
@ -98,9 +99,9 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase {
|
||||
fieldType = (BasicType)lookupType(cTypeName.substring(0, cTypeName.length() - 6), false);
|
||||
}
|
||||
if (fieldType == null) {
|
||||
if (cTypeName.startsWith("GrowableArray<") && cTypeName.endsWith(">*")) {
|
||||
if (cTypeName.startsWith("GrowableArray<") && cTypeName.endsWith(">")) {
|
||||
String ttype = cTypeName.substring("GrowableArray<".length(),
|
||||
cTypeName.length() - 2);
|
||||
cTypeName.length() - 1);
|
||||
Type templateType = lookupType(ttype, false);
|
||||
if (templateType == null && typeNameIsPointerType(ttype)) {
|
||||
templateType = recursiveCreateBasicPointerType(ttype);
|
||||
@ -108,7 +109,21 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase {
|
||||
if (templateType == null) {
|
||||
lookupOrFail(ttype);
|
||||
}
|
||||
fieldType = recursiveCreateBasicPointerType(cTypeName);
|
||||
|
||||
BasicType basicTargetType = createBasicType(cTypeName, false, false, false);
|
||||
|
||||
// transfer fields from GenericGrowableArray to template instance
|
||||
BasicType generic = lookupOrFail("GenericGrowableArray");
|
||||
BasicType specific = lookupOrFail("GrowableArray<int>");
|
||||
basicTargetType.setSize(specific.getSize());
|
||||
Iterator fields = generic.getFields();
|
||||
while (fields.hasNext()) {
|
||||
Field f = (Field)fields.next();
|
||||
basicTargetType.addField(internalCreateField(basicTargetType, f.getName(),
|
||||
f.getType(), f.isStatic(),
|
||||
f.getOffset(), null));
|
||||
}
|
||||
fieldType = basicTargetType;
|
||||
}
|
||||
}
|
||||
if (fieldType == null && typeNameIsPointerType(cTypeName)) {
|
||||
@ -208,6 +223,156 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase {
|
||||
return type;
|
||||
}
|
||||
|
||||
private void readExternalDefinitions() {
|
||||
String file = System.getProperty("sun.jvm.hotspot.typedb");
|
||||
if (file != null) {
|
||||
System.out.println("Reading " + file);
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
StreamTokenizer t = new StreamTokenizer(in = new BufferedReader(new InputStreamReader(new FileInputStream(file))));
|
||||
t.resetSyntax();
|
||||
t.wordChars('\u0000','\uFFFF');
|
||||
t.whitespaceChars(' ', ' ');
|
||||
t.whitespaceChars('\n', '\n');
|
||||
t.whitespaceChars('\r', '\r');
|
||||
t.quoteChar('\"');
|
||||
t.eolIsSignificant(true);
|
||||
while (t.nextToken() != StreamTokenizer.TT_EOF) {
|
||||
if (t.ttype == StreamTokenizer.TT_EOL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t.sval.equals("field")) {
|
||||
t.nextToken();
|
||||
BasicType containingType = (BasicType)lookupType(t.sval);
|
||||
t.nextToken();
|
||||
String fieldName = t.sval;
|
||||
|
||||
// The field's Type must already be in the database -- no exceptions
|
||||
t.nextToken();
|
||||
Type fieldType = lookupType(t.sval);
|
||||
t.nextToken();
|
||||
boolean isStatic = Boolean.valueOf(t.sval).booleanValue();
|
||||
t.nextToken();
|
||||
long offset = Long.parseLong(t.sval);
|
||||
t.nextToken();
|
||||
Address staticAddress = null;
|
||||
if (isStatic) {
|
||||
throw new InternalError("static fields not supported");
|
||||
}
|
||||
|
||||
// check to see if the field already exists
|
||||
Iterator i = containingType.getFields();
|
||||
boolean defined = false;
|
||||
while (i.hasNext()) {
|
||||
Field f = (Field) i.next();
|
||||
if (f.getName().equals(fieldName)) {
|
||||
if (f.isStatic() != isStatic) {
|
||||
throw new RuntimeException("static/nonstatic mismatch: " + fieldName);
|
||||
}
|
||||
if (!isStatic) {
|
||||
if (f.getOffset() != offset) {
|
||||
throw new RuntimeException("bad redefinition of field offset: " + fieldName);
|
||||
}
|
||||
} else {
|
||||
if (!f.getStaticFieldAddress().equals(staticAddress)) {
|
||||
throw new RuntimeException("bad redefinition of field location: " + fieldName);
|
||||
}
|
||||
}
|
||||
if (f.getType() != fieldType) {
|
||||
System.out.println(fieldType);
|
||||
System.out.println(f.getType());
|
||||
throw new RuntimeException("bad redefinition of field type: " + fieldName);
|
||||
}
|
||||
defined = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined) {
|
||||
// Create field by type
|
||||
createField(containingType,
|
||||
fieldName, fieldType,
|
||||
isStatic,
|
||||
offset,
|
||||
staticAddress);
|
||||
}
|
||||
} else if (t.sval.equals("type")) {
|
||||
t.nextToken();
|
||||
String typeName = t.sval;
|
||||
t.nextToken();
|
||||
String superclassName = t.sval;
|
||||
if (superclassName.equals("null")) {
|
||||
superclassName = null;
|
||||
}
|
||||
t.nextToken();
|
||||
boolean isOop = Boolean.valueOf(t.sval).booleanValue();
|
||||
t.nextToken();
|
||||
boolean isInteger = Boolean.valueOf(t.sval).booleanValue();
|
||||
t.nextToken();
|
||||
boolean isUnsigned = Boolean.valueOf(t.sval).booleanValue();
|
||||
t.nextToken();
|
||||
long size = Long.parseLong(t.sval);
|
||||
|
||||
BasicType type = null;
|
||||
try {
|
||||
type = (BasicType)lookupType(typeName);
|
||||
} catch (RuntimeException e) {
|
||||
}
|
||||
if (type != null) {
|
||||
if (type.isOopType() != isOop) {
|
||||
throw new RuntimeException("oop mismatch in type definition: " + typeName);
|
||||
}
|
||||
if (type.isCIntegerType() != isInteger) {
|
||||
throw new RuntimeException("integer type mismatch in type definition: " + typeName);
|
||||
}
|
||||
if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) {
|
||||
throw new RuntimeException("unsigned mismatch in type definition: " + typeName);
|
||||
}
|
||||
if (type.getSuperclass() == null) {
|
||||
if (superclassName != null) {
|
||||
if (type.getSize() == -1) {
|
||||
type.setSuperclass(lookupType(superclassName));
|
||||
} else {
|
||||
throw new RuntimeException("unexpected superclass in type definition: " + typeName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (superclassName == null) {
|
||||
throw new RuntimeException("missing superclass in type definition: " + typeName);
|
||||
}
|
||||
if (!type.getSuperclass().getName().equals(superclassName)) {
|
||||
throw new RuntimeException("incorrect superclass in type definition: " + typeName);
|
||||
}
|
||||
}
|
||||
if (type.getSize() != size) {
|
||||
if (type.getSize() == -1 || type.getSize() == 0) {
|
||||
type.setSize(size);
|
||||
} else {
|
||||
throw new RuntimeException("size mismatch in type definition: " + typeName + ": " + type.getSize() + " != " + size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lookupType(typeName, false) == null) {
|
||||
// Create type
|
||||
createType(typeName, superclassName, isOop, isInteger, isUnsigned, size);
|
||||
}
|
||||
} else {
|
||||
throw new InternalError("\"" + t.sval + "\"");
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readVMStructs() {
|
||||
// Get the variables we need in order to traverse the VMStructEntry[]
|
||||
long structEntryTypeNameOffset;
|
||||
@ -504,20 +669,6 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase {
|
||||
BasicType basicTargetType = createBasicType(targetTypeName, false, true, true);
|
||||
basicTargetType.setSize(1);
|
||||
targetType = basicTargetType;
|
||||
} else if (targetTypeName.startsWith("GrowableArray<")) {
|
||||
BasicType basicTargetType = createBasicType(targetTypeName, false, false, false);
|
||||
|
||||
// transfer fields from GenericGrowableArray to template instance
|
||||
BasicType generic = lookupOrFail("GenericGrowableArray");
|
||||
basicTargetType.setSize(generic.getSize());
|
||||
Iterator fields = generic.getFields();
|
||||
while (fields.hasNext()) {
|
||||
Field f = (Field)fields.next();
|
||||
basicTargetType.addField(internalCreateField(basicTargetType, f.getName(),
|
||||
f.getType(), f.isStatic(),
|
||||
f.getOffset(), null));
|
||||
}
|
||||
targetType = basicTargetType;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
System.err.println("WARNING: missing target type \"" + targetTypeName + "\" for pointer type \"" + typeName + "\"");
|
||||
@ -572,7 +723,7 @@ public class HotSpotTypeDataBase extends BasicTypeDataBase {
|
||||
|
||||
// Classes are created with a size of UNINITIALIZED_SIZE.
|
||||
// Set size if necessary.
|
||||
if (curType.getSize() == UNINITIALIZED_SIZE) {
|
||||
if (curType.getSize() == UNINITIALIZED_SIZE || curType.getSize() == 0) {
|
||||
curType.setSize(size);
|
||||
} else {
|
||||
if (curType.getSize() != size) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -25,18 +25,12 @@
|
||||
package sun.jvm.hotspot;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.dbx.*;
|
||||
import sun.jvm.hotspot.debugger.proc.*;
|
||||
|
||||
// A test of the debugger backend. This should be used to connect to
|
||||
// the helloWorld.cpp program.
|
||||
|
||||
public class TestDebugger {
|
||||
// FIXME: make these configurable, i.e., via a dotfile
|
||||
private static final String dbxPathName = "/export/home/kbr/ws/dbx_61/dev/Derived-sparcv9-S2./src/dbx/dbx";
|
||||
private static final String[] dbxSvcAgentDSOPathNames =
|
||||
new String[] {
|
||||
"/export/home/kbr/main/sa_baseline/src/os/solaris/agent/libsvc_agent_dbx.so"
|
||||
};
|
||||
|
||||
private static void usage() {
|
||||
System.out.println("usage: java TestDebugger [pid]");
|
||||
@ -58,8 +52,7 @@ public class TestDebugger {
|
||||
usage();
|
||||
}
|
||||
|
||||
JVMDebugger debugger = new DbxDebuggerLocal(new MachineDescriptionSPARC64Bit(),
|
||||
dbxPathName, dbxSvcAgentDSOPathNames, true);
|
||||
JVMDebugger debugger = new ProcDebuggerLocal(null, true);
|
||||
|
||||
try {
|
||||
debugger.attach(pid);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2011, 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
|
||||
@ -34,7 +34,7 @@ import javax.swing.filechooser.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.posix.*;
|
||||
import sun.jvm.hotspot.debugger.win32.*;
|
||||
import sun.jvm.hotspot.debugger.windbg.*;
|
||||
import sun.jvm.hotspot.livejvm.*;
|
||||
import sun.jvm.hotspot.memory.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
@ -604,7 +604,7 @@ public class BugSpot extends JPanel {
|
||||
throw new DebuggerException("Unsupported CPU \"" + cpu + "\" for Windows");
|
||||
}
|
||||
|
||||
localDebugger = new Win32DebuggerLocal(new MachineDescriptionIntelX86(), true);
|
||||
localDebugger = new WindbgDebuggerLocal(new MachineDescriptionIntelX86(), true);
|
||||
} else if (os.equals("linux")) {
|
||||
if (!cpu.equals("x86")) {
|
||||
throw new DebuggerException("Unsupported CPU \"" + cpu + "\" for Linux");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2011, 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
|
||||
@ -29,10 +29,9 @@ import java.net.*;
|
||||
import java.rmi.*;
|
||||
import sun.jvm.hotspot.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.dbx.*;
|
||||
import sun.jvm.hotspot.debugger.bsd.*;
|
||||
import sun.jvm.hotspot.debugger.proc.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.win32.*;
|
||||
import sun.jvm.hotspot.debugger.windbg.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.sparc.*;
|
||||
@ -516,6 +515,8 @@ public class BugSpotAgent {
|
||||
setupDebuggerWin32();
|
||||
} else if (os.equals("linux")) {
|
||||
setupDebuggerLinux();
|
||||
} else if (os.equals("bsd")) {
|
||||
setupDebuggerBsd();
|
||||
} else {
|
||||
// Add support for more operating systems here
|
||||
throw new DebuggerException("Operating system " + os + " not yet supported");
|
||||
@ -567,6 +568,9 @@ public class BugSpotAgent {
|
||||
} else if (os.equals("linux")) {
|
||||
db = new HotSpotTypeDataBase(machDesc, new LinuxVtblAccess(debugger, jvmLibNames),
|
||||
debugger, jvmLibNames);
|
||||
} else if (os.equals("bsd")) {
|
||||
db = new HotSpotTypeDataBase(machDesc, new BsdVtblAccess(debugger, jvmLibNames),
|
||||
debugger, jvmLibNames);
|
||||
} else {
|
||||
throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess implemented yet)");
|
||||
}
|
||||
@ -627,104 +631,33 @@ public class BugSpotAgent {
|
||||
|
||||
private void setupDebuggerSolaris() {
|
||||
setupJVMLibNamesSolaris();
|
||||
String prop = System.getProperty("sun.jvm.hotspot.debugger.useProcDebugger");
|
||||
if (prop != null && !prop.equals("false")) {
|
||||
ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true);
|
||||
debugger = dbg;
|
||||
attachDebugger();
|
||||
ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true);
|
||||
debugger = dbg;
|
||||
attachDebugger();
|
||||
|
||||
// Set up CPU-dependent stuff
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("sparc")) {
|
||||
int addressSize = dbg.getRemoteProcessAddressSize();
|
||||
if (addressSize == -1) {
|
||||
throw new DebuggerException("Error occurred while trying to determine the remote process's address size");
|
||||
}
|
||||
|
||||
if (addressSize == 32) {
|
||||
machDesc = new MachineDescriptionSPARC32Bit();
|
||||
} else if (addressSize == 64) {
|
||||
machDesc = new MachineDescriptionSPARC64Bit();
|
||||
} else {
|
||||
throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
|
||||
}
|
||||
} else if (cpu.equals("amd64")) {
|
||||
machDesc = new MachineDescriptionAMD64();
|
||||
} else {
|
||||
throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64");
|
||||
// Set up CPU-dependent stuff
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("sparc")) {
|
||||
int addressSize = dbg.getRemoteProcessAddressSize();
|
||||
if (addressSize == -1) {
|
||||
throw new DebuggerException("Error occurred while trying to determine the remote process's address size");
|
||||
}
|
||||
|
||||
dbg.setMachineDescription(machDesc);
|
||||
return;
|
||||
if (addressSize == 32) {
|
||||
machDesc = new MachineDescriptionSPARC32Bit();
|
||||
} else if (addressSize == 64) {
|
||||
machDesc = new MachineDescriptionSPARC64Bit();
|
||||
} else {
|
||||
throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
|
||||
}
|
||||
} else if (cpu.equals("amd64")) {
|
||||
machDesc = new MachineDescriptionAMD64();
|
||||
} else {
|
||||
String dbxPathName;
|
||||
String dbxPathPrefix;
|
||||
String dbxSvcAgentDSOPathName;
|
||||
String dbxSvcAgentDSOPathPrefix;
|
||||
String[] dbxSvcAgentDSOPathNames = null;
|
||||
|
||||
// use path names/prefixes specified on command
|
||||
dbxPathName = System.getProperty("dbxPathName");
|
||||
if (dbxPathName == null) {
|
||||
dbxPathPrefix = System.getProperty("dbxPathPrefix");
|
||||
if (dbxPathPrefix == null) {
|
||||
dbxPathPrefix = defaultDbxPathPrefix;
|
||||
}
|
||||
dbxPathName = dbxPathPrefix + fileSep + os + fileSep + cpu + fileSep + "bin" + fileSep + "dbx";
|
||||
}
|
||||
|
||||
dbxSvcAgentDSOPathName = System.getProperty("dbxSvcAgentDSOPathName");
|
||||
if (dbxSvcAgentDSOPathName != null) {
|
||||
dbxSvcAgentDSOPathNames = new String[] { dbxSvcAgentDSOPathName } ;
|
||||
} else {
|
||||
dbxSvcAgentDSOPathPrefix = System.getProperty("dbxSvcAgentDSOPathPrefix");
|
||||
if (dbxSvcAgentDSOPathPrefix == null) {
|
||||
dbxSvcAgentDSOPathPrefix = defaultDbxSvcAgentDSOPathPrefix;
|
||||
}
|
||||
if (cpu.equals("sparc")) {
|
||||
dbxSvcAgentDSOPathNames = new String[] {
|
||||
// FIXME: bad hack for SPARC v9. This is necessary because
|
||||
// there are two dbx executables on SPARC, one for v8 and one
|
||||
// for v9, and it isn't obvious how to tell the two apart
|
||||
// using the dbx command line. See
|
||||
// DbxDebuggerLocal.importDbxModule().
|
||||
dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + "v9" + fileSep + "lib" + fileSep + "libsvc_agent_dbx.so",
|
||||
dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" + fileSep + "libsvc_agent_dbx.so",
|
||||
};
|
||||
} else {
|
||||
dbxSvcAgentDSOPathNames = new String[] {
|
||||
dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" + fileSep + "libsvc_agent_dbx.so"
|
||||
};
|
||||
}
|
||||
}
|
||||
// Note we do not use a cache for the local debugger in server
|
||||
// mode; it's taken care of on the client side
|
||||
DbxDebuggerLocal dbg = new DbxDebuggerLocal(null, dbxPathName, dbxSvcAgentDSOPathNames, !isServer);
|
||||
debugger = dbg;
|
||||
|
||||
attachDebugger();
|
||||
|
||||
// Set up CPU-dependent stuff
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("sparc")) {
|
||||
int addressSize = dbg.getRemoteProcessAddressSize();
|
||||
if (addressSize == -1) {
|
||||
throw new DebuggerException("Error occurred while trying to determine the remote process's address size. It's possible that the Serviceability Agent's dbx module failed to initialize. Examine the standard output and standard error streams from the dbx process for more information.");
|
||||
}
|
||||
|
||||
if (addressSize == 32) {
|
||||
machDesc = new MachineDescriptionSPARC32Bit();
|
||||
} else if (addressSize == 64) {
|
||||
machDesc = new MachineDescriptionSPARC64Bit();
|
||||
} else {
|
||||
throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
|
||||
}
|
||||
}
|
||||
|
||||
dbg.setMachineDescription(machDesc);
|
||||
throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64");
|
||||
}
|
||||
|
||||
dbg.setMachineDescription(machDesc);
|
||||
}
|
||||
|
||||
private void connectRemoteDebugger() throws DebuggerException {
|
||||
@ -739,6 +672,8 @@ public class BugSpotAgent {
|
||||
setupJVMLibNamesWin32();
|
||||
} else if (os.equals("linux")) {
|
||||
setupJVMLibNamesLinux();
|
||||
} else if (os.equals("bsd")) {
|
||||
setupJVMLibNamesBsd();
|
||||
} else {
|
||||
throw new RuntimeException("Unknown OS type");
|
||||
}
|
||||
@ -772,11 +707,7 @@ public class BugSpotAgent {
|
||||
// mode; it will be taken care of on the client side (once remote
|
||||
// debugging is implemented).
|
||||
|
||||
if (System.getProperty("sun.jvm.hotspot.debugger.useWindbgDebugger") != null) {
|
||||
debugger = new WindbgDebuggerLocal(machDesc, !isServer);
|
||||
} else {
|
||||
debugger = new Win32DebuggerLocal(machDesc, !isServer);
|
||||
}
|
||||
debugger = new WindbgDebuggerLocal(machDesc, !isServer);
|
||||
|
||||
attachDebugger();
|
||||
}
|
||||
@ -822,6 +753,34 @@ public class BugSpotAgent {
|
||||
setupJVMLibNamesSolaris();
|
||||
}
|
||||
|
||||
//
|
||||
// BSD
|
||||
//
|
||||
|
||||
private void setupDebuggerBsd() {
|
||||
setupJVMLibNamesBsd();
|
||||
|
||||
if (cpu.equals("x86")) {
|
||||
machDesc = new MachineDescriptionIntelX86();
|
||||
} else if (cpu.equals("amd64")) {
|
||||
machDesc = new MachineDescriptionAMD64();
|
||||
} else {
|
||||
throw new DebuggerException("Bsd only supported on x86/amd64");
|
||||
}
|
||||
|
||||
// Note we do not use a cache for the local debugger in server
|
||||
// mode; it will be taken care of on the client side (once remote
|
||||
// debugging is implemented).
|
||||
|
||||
debugger = new BsdDebuggerLocal(machDesc, !isServer);
|
||||
attachDebugger();
|
||||
}
|
||||
|
||||
private void setupJVMLibNamesBsd() {
|
||||
// same as solaris
|
||||
setupJVMLibNamesSolaris();
|
||||
}
|
||||
|
||||
/** Convenience routine which should be called by per-platform
|
||||
debugger setup. Should not be called when startupMode is
|
||||
REMOTE_MODE. */
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciArrayKlass extends ciKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciArrayKlass");
|
||||
dimensionField = new IntField(type.getJIntField("_dimension"), 0);
|
||||
}
|
||||
|
||||
private static IntField dimensionField;
|
||||
|
||||
public ciArrayKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciArrayKlassKlass extends ciKlassKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciArrayKlassKlass");
|
||||
}
|
||||
|
||||
|
||||
public ciArrayKlassKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciConstant extends VMObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciConstant");
|
||||
valueObjectField = type.getAddressField("_value._object");
|
||||
valueDoubleField = type.getJDoubleField("_value._double");
|
||||
valueFloatField = type.getJFloatField("_value._float");
|
||||
valueLongField = type.getJLongField("_value._long");
|
||||
valueIntField = type.getJIntField("_value._int");
|
||||
typeField = new CIntField(type.getCIntegerField("_type"), 0);
|
||||
}
|
||||
|
||||
private static AddressField valueObjectField;
|
||||
private static JDoubleField valueDoubleField;
|
||||
private static JFloatField valueFloatField;
|
||||
private static JLongField valueLongField;
|
||||
private static JIntField valueIntField;
|
||||
private static CIntField typeField;
|
||||
|
||||
public ciConstant(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.opto.*;
|
||||
import sun.jvm.hotspot.compiler.CompileTask;
|
||||
import sun.jvm.hotspot.prims.JvmtiExport;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
import sun.jvm.hotspot.utilities.GrowableArray;
|
||||
|
||||
public class ciEnv extends VMObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciEnv");
|
||||
dependenciesField = type.getAddressField("_dependencies");
|
||||
factoryField = type.getAddressField("_factory");
|
||||
compilerDataField = type.getAddressField("_compiler_data");
|
||||
taskField = type.getAddressField("_task");
|
||||
systemDictionaryModificationCounterField = new CIntField(type.getCIntegerField("_system_dictionary_modification_counter"), 0);
|
||||
}
|
||||
|
||||
private static AddressField dependenciesField;
|
||||
private static AddressField factoryField;
|
||||
private static AddressField compilerDataField;
|
||||
private static AddressField taskField;
|
||||
private static CIntField systemDictionaryModificationCounterField;
|
||||
|
||||
public ciEnv(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public Compile compilerData() {
|
||||
return new Compile(compilerDataField.getValue(this.getAddress()));
|
||||
}
|
||||
|
||||
public ciObjectFactory factory() {
|
||||
return new ciObjectFactory(factoryField.getValue(this.getAddress()));
|
||||
}
|
||||
|
||||
public CompileTask task() {
|
||||
return new CompileTask(taskField.getValue(this.getAddress()));
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciField extends VMObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciField");
|
||||
constantValueField = type.getAddressField("_constant_value");
|
||||
isConstantField = type.getAddressField("_is_constant");
|
||||
offsetField = new CIntField(type.getCIntegerField("_offset"), 0);
|
||||
signatureField = type.getAddressField("_signature");
|
||||
nameField = type.getAddressField("_name");
|
||||
holderField = type.getAddressField("_holder");
|
||||
}
|
||||
|
||||
private static AddressField constantValueField;
|
||||
private static AddressField isConstantField;
|
||||
private static CIntField offsetField;
|
||||
private static AddressField signatureField;
|
||||
private static AddressField nameField;
|
||||
private static AddressField holderField;
|
||||
|
||||
public ciField(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciInstance extends ciObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciInstance");
|
||||
}
|
||||
|
||||
|
||||
public ciInstance(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.memory.SystemDictionary;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.Type;
|
||||
import sun.jvm.hotspot.types.TypeDataBase;
|
||||
import sun.jvm.hotspot.types.WrongTypeException;
|
||||
|
||||
public class ciInstanceKlass extends ciKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciInstanceKlass");
|
||||
initStateField = new CIntField(type.getCIntegerField("_init_state"), 0);
|
||||
isSharedField = new CIntField(type.getCIntegerField("_is_shared"), 0);
|
||||
CLASS_STATE_LINKED = db.lookupIntConstant("instanceKlass::linked").intValue();
|
||||
CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("instanceKlass::fully_initialized").intValue();
|
||||
}
|
||||
|
||||
private static CIntField initStateField;
|
||||
private static CIntField isSharedField;
|
||||
private static int CLASS_STATE_LINKED;
|
||||
private static int CLASS_STATE_FULLY_INITIALIZED;
|
||||
|
||||
public ciInstanceKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public int initState() {
|
||||
int initState = (int)initStateField.getValue(getAddress());
|
||||
if (isShared() && initState < CLASS_STATE_LINKED) {
|
||||
InstanceKlass ik = (InstanceKlass)getOop();
|
||||
initState = ik.getInitStateAsInt();
|
||||
}
|
||||
return initState;
|
||||
}
|
||||
|
||||
public boolean isShared() {
|
||||
return isSharedField.getValue(getAddress()) != 0;
|
||||
}
|
||||
|
||||
public boolean isLinked() {
|
||||
return initState() >= CLASS_STATE_LINKED;
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initState() == CLASS_STATE_FULLY_INITIALIZED;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciInstanceKlassKlass extends ciKlassKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciInstanceKlassKlass");
|
||||
}
|
||||
|
||||
|
||||
public ciInstanceKlassKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciKlass extends ciType {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciKlass");
|
||||
nameField = type.getAddressField("_name");
|
||||
}
|
||||
|
||||
private static AddressField nameField;
|
||||
|
||||
public String name() {
|
||||
ciSymbol sym = new ciSymbol(nameField.getValue(getAddress()));
|
||||
return sym.asUtf88();
|
||||
}
|
||||
|
||||
public ciKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciKlassKlass extends ciKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciKlassKlass");
|
||||
}
|
||||
|
||||
|
||||
public ciKlassKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.code.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciMethod extends ciObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciMethod");
|
||||
interpreterThrowoutCountField = new CIntField(type.getCIntegerField("_interpreter_throwout_count"), 0);
|
||||
interpreterInvocationCountField = new CIntField(type.getCIntegerField("_interpreter_invocation_count"), 0);
|
||||
try {
|
||||
// XXX
|
||||
instructionsSizeField = new CIntField(type.getCIntegerField("_instructions_size"), 0);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
private static CIntField interpreterThrowoutCountField;
|
||||
private static CIntField interpreterInvocationCountField;
|
||||
private static CIntField instructionsSizeField;
|
||||
|
||||
public ciMethod(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public Method method() {
|
||||
return (Method)getOop();
|
||||
}
|
||||
|
||||
public int interpreterThrowoutCount() {
|
||||
return (int) interpreterThrowoutCountField.getValue(getAddress());
|
||||
}
|
||||
|
||||
public int interpreterInvocationCount() {
|
||||
return (int) interpreterInvocationCountField.getValue(getAddress());
|
||||
}
|
||||
|
||||
public int instructionsSize() {
|
||||
if (instructionsSizeField == null) {
|
||||
// XXX
|
||||
Method method = (Method)getOop();
|
||||
NMethod nm = method.getNativeMethod();
|
||||
if (nm != null) return (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint());
|
||||
return 0;
|
||||
}
|
||||
return (int) instructionsSizeField.getValue(getAddress());
|
||||
}
|
||||
|
||||
public void printShortName(PrintStream st) {
|
||||
Method method = (Method)getOop();
|
||||
st.printf(" %s::%s", method.getMethodHolder().getName().asString().replace('/', '.'),
|
||||
method.getName().asString());
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciMethodData extends ciObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciMethodData");
|
||||
origField = type.getAddressField("_orig");
|
||||
currentMileageField = new CIntField(type.getCIntegerField("_current_mileage"), 0);
|
||||
argReturnedField = new CIntField(type.getCIntegerField("_arg_returned"), 0);
|
||||
argStackField = new CIntField(type.getCIntegerField("_arg_stack"), 0);
|
||||
argLocalField = new CIntField(type.getCIntegerField("_arg_local"), 0);
|
||||
eflagsField = new CIntField(type.getCIntegerField("_eflags"), 0);
|
||||
hintDiField = new CIntField(type.getCIntegerField("_hint_di"), 0);
|
||||
currentMileageField = new CIntField(type.getCIntegerField("_current_mileage"), 0);
|
||||
dataField = type.getAddressField("_data");
|
||||
extraDataSizeField = new CIntField(type.getCIntegerField("_extra_data_size"), 0);
|
||||
dataSizeField = new CIntField(type.getCIntegerField("_data_size"), 0);
|
||||
stateField = new CIntField(type.getCIntegerField("_state"), 0);
|
||||
sizeofMethodDataOopDesc = (int)db.lookupType("methodDataOopDesc").getSize();;
|
||||
}
|
||||
|
||||
private static AddressField origField;
|
||||
private static CIntField currentMileageField;
|
||||
private static CIntField argReturnedField;
|
||||
private static CIntField argStackField;
|
||||
private static CIntField argLocalField;
|
||||
private static CIntField eflagsField;
|
||||
private static CIntField hintDiField;
|
||||
private static AddressField dataField;
|
||||
private static CIntField extraDataSizeField;
|
||||
private static CIntField dataSizeField;
|
||||
private static CIntField stateField;
|
||||
private static int sizeofMethodDataOopDesc;
|
||||
|
||||
public ciMethodData(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
private byte[] fetchDataAt(Address base, long size) {
|
||||
byte[] result = new byte[(int)size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i] = base.getJByteAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] orig() {
|
||||
// fetch the orig methodDataOopDesc data between header and dataSize
|
||||
Address base = getAddress().addOffsetTo(origField.getOffset());
|
||||
byte[] result = new byte[MethodData.sizeofMethodDataOopDesc];
|
||||
for (int i = 0; i < MethodData.sizeofMethodDataOopDesc; i++) {
|
||||
result[i] = base.getJByteAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public long[] data() {
|
||||
// Read the data as an array of intptr_t elements
|
||||
Address base = dataField.getValue(getAddress());
|
||||
int elements = dataSize() / MethodData.cellSize;
|
||||
long[] result = new long[elements];
|
||||
for (int i = 0; i < elements; i++) {
|
||||
Address value = base.getAddressAt(i * MethodData.cellSize);
|
||||
if (value != null) {
|
||||
result[i] = value.minus(null);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int dataSize() {
|
||||
return (int)dataSizeField.getValue(getAddress());
|
||||
}
|
||||
|
||||
int state() {
|
||||
return (int)stateField.getValue(getAddress());
|
||||
}
|
||||
|
||||
int currentMileage() {
|
||||
return (int)currentMileageField.getValue(getAddress());
|
||||
}
|
||||
|
||||
boolean outOfBounds(int dataIndex) {
|
||||
return dataIndex >= dataSize();
|
||||
}
|
||||
|
||||
ProfileData dataAt(int dataIndex) {
|
||||
if (outOfBounds(dataIndex)) {
|
||||
return null;
|
||||
}
|
||||
DataLayout dataLayout = new DataLayout(dataField.getValue(getAddress()), dataIndex);
|
||||
|
||||
switch (dataLayout.tag()) {
|
||||
case DataLayout.noTag:
|
||||
default:
|
||||
throw new InternalError();
|
||||
case DataLayout.bitDataTag:
|
||||
return new BitData(dataLayout);
|
||||
case DataLayout.counterDataTag:
|
||||
return new CounterData(dataLayout);
|
||||
case DataLayout.jumpDataTag:
|
||||
return new JumpData(dataLayout);
|
||||
case DataLayout.receiverTypeDataTag:
|
||||
return new ciReceiverTypeData(dataLayout);
|
||||
case DataLayout.virtualCallDataTag:
|
||||
return new ciVirtualCallData(dataLayout);
|
||||
case DataLayout.retDataTag:
|
||||
return new RetData(dataLayout);
|
||||
case DataLayout.branchDataTag:
|
||||
return new BranchData(dataLayout);
|
||||
case DataLayout.multiBranchDataTag:
|
||||
return new MultiBranchData(dataLayout);
|
||||
}
|
||||
}
|
||||
|
||||
int dpToDi(int dp) {
|
||||
return dp;
|
||||
}
|
||||
|
||||
int firstDi() { return 0; }
|
||||
ProfileData firstData() { return dataAt(firstDi()); }
|
||||
ProfileData nextData(ProfileData current) {
|
||||
int currentIndex = dpToDi(current.dp());
|
||||
int nextIndex = currentIndex + current.sizeInBytes();
|
||||
return dataAt(nextIndex);
|
||||
}
|
||||
boolean isValid(ProfileData current) { return current != null; }
|
||||
|
||||
public void printDataOn(PrintStream st) {
|
||||
ProfileData data = firstData();
|
||||
for ( ; isValid(data); data = nextData(data)) {
|
||||
st.print(dpToDi(data.dp()));
|
||||
st.print(" ");
|
||||
// st->fillTo(6);
|
||||
data.printDataOn(st);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciMethodKlass extends ciKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciMethodKlass");
|
||||
}
|
||||
|
||||
|
||||
public ciMethodKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciObjArrayKlass extends ciArrayKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciObjArrayKlass");
|
||||
elementKlassField = type.getAddressField("_element_klass");
|
||||
baseElementKlassField = type.getAddressField("_base_element_klass");
|
||||
}
|
||||
|
||||
private static AddressField elementKlassField;
|
||||
private static AddressField baseElementKlassField;
|
||||
|
||||
public ciObjArrayKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciObjArrayKlassKlass extends ciArrayKlassKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciObjArrayKlassKlass");
|
||||
}
|
||||
|
||||
|
||||
public ciObjArrayKlassKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciObject extends VMObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciObject");
|
||||
identField = new CIntField(type.getCIntegerField("_ident"), 0);
|
||||
klassField = type.getAddressField("_klass");
|
||||
handleField = type.getAddressField("_handle");
|
||||
}
|
||||
|
||||
private static CIntField identField;
|
||||
private static AddressField klassField;
|
||||
private static AddressField handleField;
|
||||
|
||||
public Oop getOop() {
|
||||
OopHandle oh = handleField.getValue(getAddress()).getOopHandleAt(0);
|
||||
return VM.getVM().getObjectHeap().newOop(oh);
|
||||
}
|
||||
|
||||
public ciObject(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public void printOn(PrintStream out) {
|
||||
getOop().printValueOn(out);
|
||||
out.println();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getOop().toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.utilities.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciObjectFactory extends VMObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciObjectFactory");
|
||||
unloadedMethodsField = type.getAddressField("_unloaded_methods");
|
||||
ciObjectsField = type.getAddressField("_ci_objects");
|
||||
symbolsField = type.getAddressField("_symbols");
|
||||
|
||||
ciObjectConstructor = new VirtualBaseConstructor<ciObject>(db, db.lookupType("ciObject"), "sun.jvm.hotspot.ci", ciObject.class);
|
||||
ciSymbolConstructor = new VirtualBaseConstructor<ciSymbol>(db, db.lookupType("ciSymbol"), "sun.jvm.hotspot.ci", ciSymbol.class);
|
||||
}
|
||||
|
||||
private static AddressField unloadedMethodsField;
|
||||
private static AddressField ciObjectsField;
|
||||
private static AddressField symbolsField;
|
||||
|
||||
private static VirtualBaseConstructor<ciObject> ciObjectConstructor;
|
||||
private static VirtualBaseConstructor<ciSymbol> ciSymbolConstructor;
|
||||
|
||||
public static ciObject get(Address addr) {
|
||||
if (addr == null) return null;
|
||||
|
||||
return (ciObject)ciObjectConstructor.instantiateWrapperFor(addr);
|
||||
}
|
||||
|
||||
public GrowableArray<ciObject> objects() {
|
||||
return GrowableArray.create(ciObjectsField.getValue(getAddress()), ciObjectConstructor);
|
||||
}
|
||||
|
||||
public GrowableArray<ciSymbol> symbols() {
|
||||
return GrowableArray.create(symbolsField.getValue(getAddress()), ciSymbolConstructor);
|
||||
}
|
||||
|
||||
public ciObjectFactory(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciReceiverTypeData extends ReceiverTypeData {
|
||||
public ciReceiverTypeData(DataLayout data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
public Klass receiver(int row) {
|
||||
throw new InternalError("should not call");
|
||||
}
|
||||
|
||||
public ciKlass receiverAt(int row) {
|
||||
//assert((uint)row < rowLimit(), "oob");
|
||||
ciObject recv = ciObjectFactory.get(addressAt(receiverCellIndex(row)));
|
||||
if (recv != null && !(recv instanceof ciKlass)) {
|
||||
System.err.println(recv);
|
||||
}
|
||||
//assert(recv == NULL || recv->isKlass(), "wrong type");
|
||||
return (ciKlass)recv;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciSymbol extends VMObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciSymbol");
|
||||
identField = type.getCIntegerField("_ident");
|
||||
symbolField = type.getAddressField("_symbol");
|
||||
}
|
||||
|
||||
private static AddressField symbolField;
|
||||
private static CIntegerField identField;
|
||||
|
||||
public String asUtf88() {
|
||||
Symbol sym = Symbol.create(symbolField.getValue(getAddress()));
|
||||
return sym.asString();
|
||||
}
|
||||
|
||||
public ciSymbol(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciType extends ciObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciType");
|
||||
basicTypeField = new CIntField(type.getCIntegerField("_basic_type"), 0);
|
||||
}
|
||||
|
||||
private static CIntField basicTypeField;
|
||||
|
||||
public ciType(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciTypeArrayKlass extends ciArrayKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciTypeArrayKlass");
|
||||
}
|
||||
|
||||
public ciTypeArrayKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciTypeArrayKlassKlass extends ciArrayKlassKlass {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ciTypeArrayKlassKlass");
|
||||
}
|
||||
|
||||
|
||||
public ciTypeArrayKlassKlass(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.ci;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class ciVirtualCallData extends VirtualCallData {
|
||||
public ciVirtualCallData(DataLayout data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
public Klass receiver(int row) {
|
||||
throw new InternalError("should not call");
|
||||
}
|
||||
|
||||
public ciKlass receiverAt(int row) {
|
||||
//assert((uint)row < rowLimit(), "oob");
|
||||
ciObject recv = ciObjectFactory.get(addressAt(receiverCellIndex(row)));
|
||||
if (recv != null && !(recv instanceof ciKlass)) {
|
||||
System.err.println(recv);
|
||||
}
|
||||
//assert(recv == NULL || recv->isKlass(), "wrong type");
|
||||
return (ciKlass)recv;
|
||||
}
|
||||
}
|
@ -102,6 +102,11 @@ public class CodeBlob extends VMObject {
|
||||
/** On-Stack Replacement method */
|
||||
public boolean isOSRMethod() { return false; }
|
||||
|
||||
public NMethod asNMethodOrNull() {
|
||||
if (isNMethod()) return (NMethod)this;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Boundaries
|
||||
public Address headerBegin() {
|
||||
return addr;
|
||||
@ -195,7 +200,7 @@ public class CodeBlob extends VMObject {
|
||||
}
|
||||
|
||||
// Returns true, if the next frame is responsible for GC'ing oops passed as arguments
|
||||
public boolean callerMustGCArguments(JavaThread thread) { return false; }
|
||||
public boolean callerMustGCArguments() { return false; }
|
||||
|
||||
public String getName() {
|
||||
return CStringUtilities.getString(nameField.getValue(addr));
|
||||
|
@ -59,6 +59,7 @@ public class CodeCache {
|
||||
virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class);
|
||||
virtualConstructor.addMapping("RicochetBlob", RicochetBlob.class);
|
||||
virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
|
||||
virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class);
|
||||
virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
|
||||
virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
|
||||
if (VM.getVM().isServerCompiler()) {
|
||||
@ -126,6 +127,10 @@ public class CodeCache {
|
||||
Assert.that(result.blobContains(start) || result.blobContains(start.addOffsetTo(8)),
|
||||
"found wrong CodeBlob");
|
||||
}
|
||||
if (result.isRicochetBlob()) {
|
||||
// This should probably be done for other SingletonBlobs
|
||||
return VM.getVM().ricochetBlob();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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
|
||||
@ -22,31 +22,37 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.runtime.amd64;
|
||||
package sun.jvm.hotspot.code;
|
||||
|
||||
import sun.jvm.hotspot.asm.amd64.*;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class AMD64RegisterMap extends RegisterMap {
|
||||
|
||||
/** This is the only public constructor */
|
||||
public AMD64RegisterMap(JavaThread thread, boolean updateMap) {
|
||||
super(thread, updateMap);
|
||||
public class MethodHandlesAdapterBlob extends AdapterBlob {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected AMD64RegisterMap(RegisterMap map) {
|
||||
super(map);
|
||||
private static void initialize(TypeDataBase db) {
|
||||
Type type = db.lookupType("MethodHandlesAdapterBlob");
|
||||
|
||||
// FIXME: add any needed fields
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
AMD64RegisterMap retval = new AMD64RegisterMap(this);
|
||||
return retval;
|
||||
public MethodHandlesAdapterBlob(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
// no PD state to clear or copy:
|
||||
protected void clearPD() {}
|
||||
protected void initializePD() {}
|
||||
protected void initializeFromPD(RegisterMap map) {}
|
||||
protected Address getLocationPD(VMReg reg) { return null; }
|
||||
public boolean isMethodHandlesAdapterBlob() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "MethodHandlesAdapterBlob: " + super.getName();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -46,6 +46,7 @@ public class NMethod extends CodeBlob {
|
||||
/** Offsets for different nmethod parts */
|
||||
private static CIntegerField exceptionOffsetField;
|
||||
private static CIntegerField deoptOffsetField;
|
||||
private static CIntegerField deoptMhOffsetField;
|
||||
private static CIntegerField origPCOffsetField;
|
||||
private static CIntegerField stubOffsetField;
|
||||
private static CIntegerField oopsOffsetField;
|
||||
@ -95,6 +96,7 @@ public class NMethod extends CodeBlob {
|
||||
|
||||
exceptionOffsetField = type.getCIntegerField("_exception_offset");
|
||||
deoptOffsetField = type.getCIntegerField("_deoptimize_offset");
|
||||
deoptMhOffsetField = type.getCIntegerField("_deoptimize_mh_offset");
|
||||
origPCOffsetField = type.getCIntegerField("_orig_pc_offset");
|
||||
stubOffsetField = type.getCIntegerField("_stub_offset");
|
||||
oopsOffsetField = type.getCIntegerField("_oops_offset");
|
||||
@ -136,10 +138,11 @@ public class NMethod extends CodeBlob {
|
||||
/** Boundaries for different parts */
|
||||
public Address constantsBegin() { return contentBegin(); }
|
||||
public Address constantsEnd() { return getEntryPoint(); }
|
||||
public Address instsBegin() { return codeBegin(); }
|
||||
public Address instsBegin() { return codeBegin(); }
|
||||
public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); }
|
||||
public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); }
|
||||
public Address deoptBegin() { return headerBegin().addOffsetTo(getDeoptOffset()); }
|
||||
public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptOffset()); }
|
||||
public Address deoptMhHandlerBegin() { return headerBegin().addOffsetTo(getDeoptMhOffset()); }
|
||||
public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); }
|
||||
public Address stubEnd() { return headerBegin().addOffsetTo(getOopsOffset()); }
|
||||
public Address oopsBegin() { return headerBegin().addOffsetTo(getOopsOffset()); }
|
||||
@ -187,6 +190,8 @@ public class NMethod extends CodeBlob {
|
||||
public boolean handlerTableContains(Address addr) { return handlerTableBegin().lessThanOrEqual(addr) && handlerTableEnd().greaterThan(addr); }
|
||||
public boolean nulChkTableContains (Address addr) { return nulChkTableBegin() .lessThanOrEqual(addr) && nulChkTableEnd() .greaterThan(addr); }
|
||||
|
||||
public int getOopsLength() { return (int) (oopsSize() / VM.getVM().getOopSize()); }
|
||||
|
||||
/** Entry points */
|
||||
public Address getEntryPoint() { return entryPointField.getValue(addr); }
|
||||
public Address getVerifiedEntryPoint() { return verifiedEntryPointField.getValue(addr); }
|
||||
@ -195,7 +200,7 @@ public class NMethod extends CodeBlob {
|
||||
public OopHandle getOopAt(int index) {
|
||||
if (index == 0) return null;
|
||||
if (Assert.ASSERTS_ENABLED) {
|
||||
Assert.that(index > 0 && index <= oopsSize(), "must be a valid non-zero index");
|
||||
Assert.that(index > 0 && index <= getOopsLength(), "must be a valid non-zero index");
|
||||
}
|
||||
return oopsBegin().getOopHandleAt((index - 1) * VM.getVM().getOopSize());
|
||||
}
|
||||
@ -250,6 +255,22 @@ public class NMethod extends CodeBlob {
|
||||
return (int) scavengeRootStateField.getValue(addr);
|
||||
}
|
||||
|
||||
// MethodHandle
|
||||
public boolean isMethodHandleReturn(Address returnPc) {
|
||||
// Hard to read a bit fields from Java and it's only there for performance
|
||||
// so just go directly to the PCDesc
|
||||
// if (!hasMethodHandleInvokes()) return false;
|
||||
PCDesc pd = getPCDescAt(returnPc);
|
||||
if (pd == null)
|
||||
return false;
|
||||
return pd.isMethodHandleInvoke();
|
||||
}
|
||||
|
||||
// Deopt
|
||||
// Return true is the PC is one would expect if the frame is being deopted.
|
||||
public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc) || isDeoptMhEntry(pc); }
|
||||
public boolean isDeoptEntry (Address pc) { return pc == deoptHandlerBegin(); }
|
||||
public boolean isDeoptMhEntry (Address pc) { return pc == deoptMhHandlerBegin(); }
|
||||
|
||||
/** Tells whether frames described by this nmethod can be
|
||||
deoptimized. Note: native wrappers cannot be deoptimized. */
|
||||
@ -388,6 +409,7 @@ public class NMethod extends CodeBlob {
|
||||
private int getEntryBCI() { return (int) entryBCIField .getValue(addr); }
|
||||
private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); }
|
||||
private int getDeoptOffset() { return (int) deoptOffsetField .getValue(addr); }
|
||||
private int getDeoptMhOffset() { return (int) deoptMhOffsetField .getValue(addr); }
|
||||
private int getStubOffset() { return (int) stubOffsetField .getValue(addr); }
|
||||
private int getOopsOffset() { return (int) oopsOffsetField .getValue(addr); }
|
||||
private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); }
|
||||
|
@ -38,6 +38,9 @@ public class PCDesc extends VMObject {
|
||||
private static CIntegerField scopeDecodeOffsetField;
|
||||
private static CIntegerField objDecodeOffsetField;
|
||||
private static CIntegerField pcFlagsField;
|
||||
private static int reexecuteMask;
|
||||
private static int isMethodHandleInvokeMask;
|
||||
private static int returnOopMask;
|
||||
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
@ -54,6 +57,10 @@ public class PCDesc extends VMObject {
|
||||
scopeDecodeOffsetField = type.getCIntegerField("_scope_decode_offset");
|
||||
objDecodeOffsetField = type.getCIntegerField("_obj_decode_offset");
|
||||
pcFlagsField = type.getCIntegerField("_flags");
|
||||
|
||||
reexecuteMask = db.lookupIntConstant("PcDesc::PCDESC_reexecute");
|
||||
isMethodHandleInvokeMask = db.lookupIntConstant("PcDesc::PCDESC_is_method_handle_invoke");
|
||||
returnOopMask = db.lookupIntConstant("PcDesc::PCDESC_return_oop");
|
||||
}
|
||||
|
||||
public PCDesc(Address addr) {
|
||||
@ -81,7 +88,12 @@ public class PCDesc extends VMObject {
|
||||
|
||||
public boolean getReexecute() {
|
||||
int flags = (int)pcFlagsField.getValue(addr);
|
||||
return ((flags & 0x1)== 1); //first is the reexecute bit
|
||||
return (flags & reexecuteMask) != 0;
|
||||
}
|
||||
|
||||
public boolean isMethodHandleInvoke() {
|
||||
int flags = (int)pcFlagsField.getValue(addr);
|
||||
return (flags & isMethodHandleInvokeMask) != 0;
|
||||
}
|
||||
|
||||
public void print(NMethod code) {
|
||||
|
@ -41,11 +41,15 @@ public class RicochetBlob extends SingletonBlob {
|
||||
}
|
||||
|
||||
private static void initialize(TypeDataBase db) {
|
||||
// Type type = db.lookupType("RicochetBlob");
|
||||
Type type = db.lookupType("RicochetBlob");
|
||||
|
||||
// FIXME: add any needed fields
|
||||
bounceOffsetField = type.getCIntegerField("_bounce_offset");
|
||||
exceptionOffsetField = type.getCIntegerField("_exception_offset");
|
||||
}
|
||||
|
||||
private static CIntegerField bounceOffsetField;
|
||||
private static CIntegerField exceptionOffsetField;
|
||||
|
||||
public RicochetBlob(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
@ -53,4 +57,14 @@ public class RicochetBlob extends SingletonBlob {
|
||||
public boolean isRicochetBlob() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Address bounceAddr() {
|
||||
return codeBegin().addOffsetTo(bounceOffsetField.getValue(addr));
|
||||
}
|
||||
|
||||
public boolean returnsToBounceAddr(Address pc) {
|
||||
Address bouncePc = bounceAddr();
|
||||
return (pc.equals(bouncePc) || pc.addOffsetTo(Frame.pcReturnOffset()).equals(bouncePc));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class RuntimeStub extends CodeBlob {
|
||||
private static CIntegerField callerMustGCArgumentsField;
|
||||
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
@ -40,6 +42,7 @@ public class RuntimeStub extends CodeBlob {
|
||||
|
||||
private static void initialize(TypeDataBase db) {
|
||||
Type type = db.lookupType("RuntimeStub");
|
||||
callerMustGCArgumentsField = type.getCIntegerField("_caller_must_gc_arguments");
|
||||
|
||||
// FIXME: add any needed fields
|
||||
}
|
||||
@ -52,6 +55,11 @@ public class RuntimeStub extends CodeBlob {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean callerMustGCArguments() {
|
||||
return callerMustGCArgumentsField.getValue(addr) != 0;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return "RuntimeStub: " + super.getName();
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.compiler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.opto.*;
|
||||
import sun.jvm.hotspot.prims.JvmtiExport;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class CompileTask extends VMObject {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("CompileTask");
|
||||
methodField = type.getAddressField("_method");
|
||||
osrBciField = new CIntField(type.getCIntegerField("_osr_bci"), 0);
|
||||
}
|
||||
|
||||
private static AddressField methodField;
|
||||
private static CIntField osrBciField;
|
||||
|
||||
public CompileTask(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public Method method() {
|
||||
OopHandle oh = methodField.getValue(getAddress()).getOopHandleAt(0);
|
||||
return (Method)VM.getVM().getObjectHeap().newOop(oh);
|
||||
}
|
||||
|
||||
public int osrBci() {
|
||||
return (int)osrBciField.getValue(getAddress());
|
||||
}
|
||||
}
|
@ -246,7 +246,7 @@ public class OopMapSet extends VMObject {
|
||||
}
|
||||
|
||||
// Check if caller must update oop argument
|
||||
regMap.setIncludeArgumentOops(cb.callerMustGCArguments(regMap.getThread()));
|
||||
regMap.setIncludeArgumentOops(cb.callerMustGCArguments());
|
||||
|
||||
int nofCallee = 0;
|
||||
Address[] locs = new Address[2 * REG_COUNT + 1];
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -39,4 +39,8 @@ public class AddressException extends RuntimeException {
|
||||
public long getAddress() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return Long.toHexString(addr);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user