提交 1c252c32 编写于 作者: L lana

Merge

无相关合并请求
......@@ -127,3 +127,8 @@ de9223c94f9c710b3eebb599cd3586f36c8b94a9 jdk8-b01
6815e85bf96d6d3875954f9777660372cd70d065 jdk8-b03
31f5c34d78081572ad9a2401c0bb0c6b9711dd65 jdk8-b04
c4f9ea1ecb55ff44e0dd21d2888ead308c86a3aa jdk8-b05
429da7734bf491bccde2a752fae97e9f225896dc jdk8-b06
bc5710332b294676661103bb20d47d2ea3ba8def jdk8-b07
24ee504f80412770c6874836cd9e55b536427b1d jdk8-b08
fbf3cabc9e3bb1fcf710941d777cb0400505fbe6 jdk8-b09
f651ce87127980c58e3599daba964eba2f3b4026 jdk8-b10
......@@ -127,3 +127,8 @@ f42e3d9394b40a423d345b8da22687b5462e5f25 jdk8-b01
587bb549dff83131b65f40aa51864f69562f34a7 jdk8-b03
0b66a233bfb9ba2ebda1e5cdfdb0373d6c1e3c69 jdk8-b04
b910aac18c772b823b1f7da03e2c6528725cc6de jdk8-b05
28cf2aec4dd7c3c75efc1c15078522467c781a6d jdk8-b06
0db7ae9f2b1017124c779bccd016c976928859a0 jdk8-b07
fb1bc13260d76447e269e843859eb593fe2a8ab2 jdk8-b08
8adb70647b5af5273dfe6a540f07be667cd50216 jdk8-b09
a6c4c248e8fa350c35014fa94bab5ac1a1ac3299 jdk8-b10
......@@ -127,3 +127,8 @@ ed8d94519a87b4adac270c3eec9134ff1f62bff5 jdk8-b02
cd0da00694fbce642db9be936d3e4909a71d911d jdk8-b03
60a68d688e24473cf84dedd1e60901a61ab82555 jdk8-b04
cc1b599b986a37cb57de4584c5e58169766ca535 jdk8-b05
45c43dde7ba7f176333a51a98f086275478836fa jdk8-b06
3d61f0856f349e2163bf98146465dab3b7437f63 jdk8-b07
0d52b1c87aa8fdea7fdc9c4126ea58f95ca6b351 jdk8-b08
a891732c1a83082177ff7a4cf1506068d9cc0a47 jdk8-b09
cda87f7fefcee3b89742a57ce5ad9b03a54c210d jdk8-b10
......@@ -6,3 +6,4 @@
^src/share/tools/IdealGraphVisualizer/build/
^src/share/tools/IdealGraphVisualizer/dist/
^.hgtip
.DS_Store
......@@ -179,3 +179,17 @@ c149193c768b8b7233da4c3a3fdc0756b975848e jdk7-b143
3a2fb61165dfc72e398179a2796d740c8da5b8c0 jdk8-b03
0fa3ace511fe98fe948e751531f3e2b7c60c8376 jdk8-b04
dce7d24674f4d0bed00de24f00119057fdce7cfb jdk8-b05
0db80d8e77fccddf5e6fa49963226b54ac7d0f62 jdk8-b06
3f0cf875af83f55ec5e1a5cea80455315f9322a2 jdk8-b07
0cc8a70952c368e06de2adab1f2649a408f5e577 hs22-b01
7c29742c41b44fb0cd5a13c7ac8834f3f2ca649e hs22-b02
3a2fb61165dfc72e398179a2796d740c8da5b8c0 hs22-b03
ce9bde819dcba4a5d2822229d9183e69c74326ca hs22-b04
513a84dd0f8b56dc0836b4e0bdd5dd0a778fc634 hs22-b05
650d15d8f37255d3b805aa00c5bd1c30984b203d hs22-b06
da883b9e6d3788057f9577e72712998ed82c9b7e hs23-b01
49ed7eacfd16616166ff066493143889741097af jdk8-b08
7c20d272643f47195478708eff593a9cce40fec4 jdk8-b09
e4f412d2b75d2c797acff965aa2c420e3d358f09 hs23-b02
d815de2e85e511b7deab2a83cf80c0224d011da9 jdk8-b10
4d3850d9d326ac3a9bee2d867727e954322d014e hs23-b03
#
# Copyright (c) 2000, 2008, 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
......@@ -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 \
......@@ -84,6 +84,7 @@ sun.jvm.hotspot.debugger.windbg.ia64 \
sun.jvm.hotspot.debugger.windbg.x86 \
sun.jvm.hotspot.debugger.x86 \
sun.jvm.hotspot.gc_implementation \
sun.jvm.hotspot.gc_implementation.g1 \
sun.jvm.hotspot.gc_implementation.parallelScavenge \
sun.jvm.hotspot.gc_implementation.shared \
sun.jvm.hotspot.gc_interface \
......@@ -91,9 +92,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 +145,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,19 +172,26 @@ 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 \
sun/jvm/hotspot/debugger/windbg/x86/*.java \
sun/jvm/hotspot/debugger/x86/*.java \
sun/jvm/hotspot/gc_implementation/g1/*.java \
sun/jvm/hotspot/gc_implementation/parallelScavenge/*.java \
sun/jvm/hotspot/gc_implementation/shared/*.java \
sun/jvm/hotspot/interpreter/*.java \
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"
/*
* 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;
}
/*
* Copyright (c) 2002, 2007, 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.
*
*/
#include <objc/objc-runtime.h>
#import <Foundation/Foundation.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h>
#include <JavaVM/jni.h>
#import <mach/mach.h>
#import <mach/mach_types.h>
#import <sys/sysctl.h>
#import <stdlib.h>
jboolean debug = JNI_FALSE;
static jfieldID symbolicatorID = 0; // set in _init0
static jfieldID taskID = 0; // set in _init0
static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
(*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
}
static id getSymbolicator(JNIEnv *env, jobject this_obj) {
jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);
return (id)(intptr_t)ptr;
}
static void putTask(JNIEnv *env, jobject this_obj, task_t task) {
(*env)->SetLongField(env, this_obj, taskID, (jlong)task);
}
static task_t getTask(JNIEnv *env, jobject this_obj) {
jlong ptr = (*env)->GetLongField(env, this_obj, taskID);
return (task_t)ptr;
}
#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);
}
#if defined(__i386__)
#define hsdb_thread_state_t x86_thread_state32_t
#define hsdb_float_state_t x86_float_state32_t
#define HSDB_THREAD_STATE x86_THREAD_STATE32
#define HSDB_FLOAT_STATE x86_FLOAT_STATE32
#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE32_COUNT
#elif defined(__x86_64__)
#define hsdb_thread_state_t x86_thread_state64_t
#define hsdb_float_state_t x86_float_state64_t
#define HSDB_THREAD_STATE x86_THREAD_STATE64
#define HSDB_FLOAT_STATE x86_FLOAT_STATE64
#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT
#else
#error "Unsupported architecture"
#endif
/*
* 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) {
symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
taskID = (*env)->GetFieldID(env, cls, "task", "J");
CHECK_EXCEPTION;
}
/*
* 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) {
jlong address = 0;
JNF_COCOA_ENTER(env);
NSString *symbolNameString = JNFJavaToNSString(env, symbolName);
if (debug) {
printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
}
id symbolicator = getSymbolicator(env, this_obj);
if (symbolicator != nil) {
uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;
address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
}
if (debug) {
printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
}
JNF_COCOA_EXIT(env);
return address;
}
/*
* 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) {
if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
// must allocate storage instead of using former parameter buf
jboolean isCopy;
jbyteArray array;
jbyte *bufPtr;
array = (*env)->NewByteArray(env, numBytes);
CHECK_EXCEPTION_(0);
unsigned long alignedAddress;
unsigned long alignedLength;
kern_return_t result;
vm_offset_t *pages;
int *mapped;
long pageCount;
uint byteCount;
int i;
unsigned long remaining;
alignedAddress = trunc_page(addr);
if (addr != alignedAddress) {
alignedLength += addr - alignedAddress;
}
alignedLength = round_page(numBytes);
pageCount = alignedLength/vm_page_size;
// Allocate storage for pages and flags.
pages = malloc(pageCount * sizeof(vm_offset_t));
mapped = calloc(pageCount, sizeof(int));
task_t gTask = getTask(env, this_obj);
// Try to read each of the pages.
for (i = 0; i < pageCount; i++) {
result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size,
&pages[i], &byteCount);
mapped[i] = (result == KERN_SUCCESS);
// assume all failures are unmapped pages
}
if (debug) fprintf(stderr, "%ld pages\n", pageCount);
remaining = numBytes;
for (i = 0; i < pageCount; i++) {
unsigned long len = vm_page_size;
unsigned long start = 0;
if (i == 0) {
start = addr - alignedAddress;
len = vm_page_size - start;
}
if (i == (pageCount - 1)) {
len = remaining;
}
if (mapped[i]) {
if (debug) fprintf(stderr, "page %d mapped (len %ld start %ld)\n", i, len, start);
(*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));
vm_deallocate(mach_task_self(), pages[i], vm_page_size);
}
remaining -= len;
}
free (pages);
free (mapped);
return array;
}
/*
* Class: sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
* Method: getThreadIntegerRegisterSet0
* Signature: (I)[J
*/
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(JNIEnv *env, jobject this_obj, jint lwp_id) {
if (debug)
printf("getThreadRegisterSet0 called\n");
kern_return_t result;
thread_t tid;
mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;
hsdb_thread_state_t state;
unsigned int *r;
int i;
jlongArray registerArray;
jlong *primitiveArray;
tid = lwp_id;
result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
if (result != KERN_SUCCESS) {
if (debug)
printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result);
return NULL;
}
// 40 32-bit registers on ppc, 16 on x86.
// Output order is the same as the order in the ppc_thread_state/i386_thread_state struct.
#if defined(__i386__)
r = (unsigned int *)&state;
registerArray = (*env)->NewLongArray(env, 8);
primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
primitiveArray[0] = r[0]; // eax
primitiveArray[1] = r[2]; // ecx
primitiveArray[2] = r[3]; // edx
primitiveArray[3] = r[1]; // ebx
primitiveArray[4] = r[7]; // esp
primitiveArray[5] = r[6]; // ebp
primitiveArray[6] = r[5]; // esi
primitiveArray[7] = r[4]; // edi
(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
#elif defined(__x86_64__)
/* From AMD64ThreadContext.java
public static final int R15 = 0;
public static final int R14 = 1;
public static final int R13 = 2;
public static final int R12 = 3;
public static final int R11 = 4;
public static final int R10 = 5;
public static final int R9 = 6;
public static final int R8 = 7;
public static final int RDI = 8;
public static final int RSI = 9;
public static final int RBP = 10;
public static final int RBX = 11;
public static final int RDX = 12;
public static final int RCX = 13;
public static final int RAX = 14;
public static final int TRAPNO = 15;
public static final int ERR = 16;
public static final int RIP = 17;
public static final int CS = 18;
public static final int RFL = 19;
public static final int RSP = 20;
public static final int SS = 21;
public static final int FS = 22;
public static final int GS = 23;
public static final int ES = 24;
public static final int DS = 25;
public static final int FSBASE = 26;
public static final int GSBASE = 27;
*/
// 64 bit
if (debug) printf("Getting threads for a 64-bit process\n");
registerArray = (*env)->NewLongArray(env, 28);
primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
primitiveArray[0] = state.__r15;
primitiveArray[1] = state.__r14;
primitiveArray[2] = state.__r13;
primitiveArray[3] = state.__r12;
primitiveArray[4] = state.__r11;
primitiveArray[5] = state.__r10;
primitiveArray[6] = state.__r9;
primitiveArray[7] = state.__r8;
primitiveArray[8] = state.__rdi;
primitiveArray[9] = state.__rsi;
primitiveArray[10] = state.__rbp;
primitiveArray[11] = state.__rbx;
primitiveArray[12] = state.__rdx;
primitiveArray[13] = state.__rcx;
primitiveArray[14] = state.__rax;
primitiveArray[15] = 0; // trapno ?
primitiveArray[16] = 0; // err ?
primitiveArray[17] = state.__rip;
primitiveArray[18] = state.__cs;
primitiveArray[19] = state.__rflags;
primitiveArray[20] = state.__rsp;
primitiveArray[21] = 0; // We don't have SS
primitiveArray[22] = state.__fs;
primitiveArray[23] = state.__gs;
primitiveArray[24] = 0;
primitiveArray[25] = 0;
primitiveArray[26] = 0;
primitiveArray[27] = 0;
if (debug) printf("set registers\n");
(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
#else
#error Unsupported architecture
#endif
return registerArray;
}
/*
* Class: sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
* Method: translateTID0
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(JNIEnv *env, jobject this_obj, jint tid) {
if (debug)
printf("translateTID0 called on tid = 0x%x\n", (int)tid);
kern_return_t result;
thread_t foreign_tid, usable_tid;
mach_msg_type_name_t type;
foreign_tid = tid;
task_t gTask = getTask(env, this_obj);
result = mach_port_extract_right(gTask, foreign_tid,
MACH_MSG_TYPE_COPY_SEND,
&usable_tid, &type);
if (result != KERN_SUCCESS)
return -1;
if (debug)
printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
return (jint) usable_tid;
}
/*
* 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) {
JNF_COCOA_ENTER(env);
if (getenv("JAVA_SAPROC_DEBUG") != NULL)
debug = JNI_TRUE;
else
debug = JNI_FALSE;
if (debug) printf("attach0 called for jpid=%d\n", (int)jpid);
kern_return_t result;
task_t gTask = 0;
result = task_for_pid(mach_task_self(), jpid, &gTask);
if (result != KERN_SUCCESS) {
fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
}
putTask(env, this_obj, gTask);
id symbolicator = nil;
id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
if (jrsSymbolicator != nil) {
id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
}
if (symbolicator != nil) {
CFRetain(symbolicator); // pin symbolicator while in java heap
}
putSymbolicator(env, this_obj, symbolicator);
if (symbolicator == nil) {
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
}
JNF_COCOA_EXIT(env);
}
/*
* 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) {
JNF_COCOA_ENTER(env);
if (debug) printf("detach0 called\n");
task_t gTask = getTask(env, this_obj);
mach_port_deallocate(mach_task_self(), gTask);
id symbolicator = getSymbolicator(env, this_obj);
if (symbolicator != nil) {
CFRelease(symbolicator);
}
JNF_COCOA_EXIT(env);
}
#
# Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
# 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
......@@ -22,59 +22,56 @@
#
#
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)
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 \
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 *.obj *.idb *.pch *.pdb *.ncb *.opt *.plg *.exe *.ilk
rm -f $(LIBSA)
rm -f $(OBJS)
rm -f test.o
-rmdir $(ARCH)
.cpp.obj:
@ $(CPP) $(CFLAGS) /o $@ $<
/*
* 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;
}
/*
* 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_
#include <windows.h>
#include <vector>
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);
ULONG getPid();
/** Returns number of WCHAR characters in getName() */
USHORT getNameLength();
WCHAR* getName();
private:
ULONG pid;
USHORT nameLength;
WCHAR* name;
void copyFrom(const ProcEntry& arg);
};
typedef std::vector<ProcEntry> ProcEntryList;
void procList(ProcEntryList& processes);
#endif // #defined _PROCLIST_
#ifndef _ELFMACROS_H_
#define _ELFMACROS_H_
#define ELF_NHDR Elf_Note
#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
#ifndef ELF_ST_TYPE
#define ELF_ST_TYPE ELF64_ST_TYPE
#endif
#else
#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
#ifndef ELF_ST_TYPE
#define ELF_ST_TYPE ELF32_ST_TYPE
#endif
#endif
#endif /* _ELFMACROS_H_ */
/*
* 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_
/*
* 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;
}
/*
* 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_
#
#
# 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:
*;
};
此差异已折叠。
/*
* 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;
}
/*
* 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;
}
/*
* 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_ */
/*
* 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;
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");
if (symtab->hash_table == NULL)
goto bad;
// 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);
if (symtab->strs == NULL)
goto bad;
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));
if (symtab->symbols == NULL)
goto bad;
// 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);
}
}
}
goto quit;
bad:
destroy_symtab(symtab);
symtab = NULL;
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;
}
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;
}
/*
* 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_*/
/*
* 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
* 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 <stdlib.h>
#include "libproc.h"
int main(int argc, char** argv) {
struct ps_prochandle* ph;
init_libproc(true);
switch (argc) {
case 2: {
// process
ph = Pgrab(atoi(argv[1]));
break;
}
case 3: {
// core
ph = Pgrab_core(argv[1], argv[2]);
break;
}
default: {
fprintf(stderr, "usage %s <pid> or %s <exec file> <core file>\n", argv[0], argv[0]);
return 1;
}
}
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
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.
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' */
/*
* 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 */
/*
* 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
/*
* 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);
};
/*
* 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_
/*
* 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
}
/*
* 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_
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* 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;
}
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部