changeset 809:eb512e8ac925

. Serviceability agent support for BSD. Fully functional on FreeBSD. Other platforms currently lack support for jmap's -pmap (default) option. This contains significant contributions from Kurt Miller and Brian Gardner.
author glewis@misty.eyesbeyond.com
date Fri, 29 May 2009 08:22:42 -0700
parents f658ac06fb8e
children 869a1152f33e
files agent/make/Makefile agent/src/os/bsd/BsdDebuggerLocal.c agent/src/os/bsd/Makefile agent/src/os/bsd/elfmacros.h agent/src/os/bsd/hsearch_r.c agent/src/os/bsd/hsearch_r.h agent/src/os/bsd/libproc.h agent/src/os/bsd/libproc_impl.c agent/src/os/bsd/libproc_impl.h agent/src/os/bsd/mapfile agent/src/os/bsd/ps_core.c agent/src/os/bsd/ps_proc.c agent/src/os/bsd/salibelf.c agent/src/os/bsd/salibelf.h agent/src/os/bsd/symtab.c agent/src/os/bsd/symtab.h agent/src/os/bsd/test.c agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdCDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdOopHandle.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThreadContextFactory.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64CFrame.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64ThreadContext.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86CFrame.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86ThreadContext.java agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java agent/src/share/classes/sun/jvm/hotspot/runtime/bsd/BsdSignals.java agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdSignals.java agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdX86JavaThreadPDAccess.java agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java make/bsd/makefiles/defs.make make/bsd/makefiles/saproc.make make/sa.files
diffstat 41 files changed, 5812 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/agent/make/Makefile	Fri May 22 11:31:05 2009 -0400
+++ b/agent/make/Makefile	Fri May 29 08:22:42 2009 -0700
@@ -52,6 +52,9 @@
 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 \
@@ -94,6 +97,9 @@
 sun.jvm.hotspot.oops \
 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 \
@@ -143,6 +149,8 @@
 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/x86/*.java \
 sun/jvm/hotspot/debugger/cdbg/*.java \
 sun/jvm/hotspot/debugger/cdbg/basic/*.java \
 sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/BsdDebuggerLocal.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2002-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/Makefile	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,78 @@
+#
+# Copyright 2002-2006 Sun Microsystems, Inc.  All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+#
+
+ARCH := $(shell if ([ `uname -m` = "ia64" ])  ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi )
+GCC      = gcc
+
+JAVAH    = ${JAVA_HOME}/bin/javah
+
+SOURCES  = salibelf.c   \
+        symtab.c        \
+	libproc_impl.c  \
+	ps_proc.c       \
+	ps_core.c       \
+	hsearch_r.c     \
+	BsdDebuggerLocal.c
+
+INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]")
+
+OBJS     = $(SOURCES:.c=.o)
+
+LIBS     = -lutil -lthread_db
+
+CFLAGS   = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES)
+
+LIBSA = $(ARCH)/libsaproc.so
+
+all: $(LIBSA)
+
+BsdDebuggerLocal.o: BsdDebuggerLocal.c
+	$(JAVAH) -jni -classpath ../../../../../build/bsd-i586/hotspot/outputdir/bsd_i486_compiler2/generated/saclasses  \
+		sun.jvm.hotspot.debugger.x86.X86ThreadContext \
+		sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
+	$(GCC) $(CFLAGS) $<
+
+.c.obj:
+	$(GCC) $(CFLAGS)
+
+ifndef LDNOMAP
+  LFLAGS_LIBSA = -Xlinker --version-script=mapfile
+endif
+
+$(LIBSA): $(OBJS) mapfile
+	if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi
+	$(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS)
+
+test.o: $(LIBSA) test.c
+	$(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c
+
+test: test.o
+	$(GCC) -o test test.o -L$(ARCH) -lsaproc $(LIBS)
+
+clean:
+	rm -f $(LIBSA)
+	rm -f $(OBJS)
+	rm -f test.o
+	-rmdir $(ARCH)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/elfmacros.h	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#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_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/hsearch_r.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,217 @@
+/* Copyright (C) 1993,1995-1997,2002,2005,2007,2008
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <search.h>
+
+#include "hsearch_r.h"
+
+#define __set_errno(ERRNO) errno = ERRNO
+
+/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
+   [Knuth]            The Art of Computer Programming, part 3 (6.4)  */
+
+
+/* The reentrant version has no static variables to maintain the state.
+   Instead the interface of all functions is extended to take an argument
+   which describes the current status.  */
+typedef struct _ENTRY
+{
+  unsigned int used;
+  ENTRY entry;
+}
+_ENTRY;
+
+
+/* For the used double hash method the table size has to be a prime. To
+   correct the user given table size we need a prime test.  This trivial
+   algorithm is adequate because
+   a)  the code is (most probably) called a few times per program run and
+   b)  the number is small because the table must fit in the core  */
+static int
+isprime (unsigned int number)
+{
+  /* no even number will be passed */
+  unsigned int div = 3;
+
+  while (div * div < number && number % div != 0)
+    div += 2;
+
+  return number % div != 0;
+}
+
+
+/* Before using the hash table we must allocate memory for it.
+   Test for an existing table are done. We allocate one element
+   more as the found prime number says. This is done for more effective
+   indexing as explained in the comment for the hsearch function.
+   The contents of the table is zeroed, especially the field used
+   becomes zero.  */
+int
+hcreate_r (size_t nel, struct hsearch_data *htab)
+{
+  /* Test for correct arguments.  */
+  if (htab == NULL)
+    {
+      __set_errno (EINVAL);
+      return 0;
+    }
+
+  /* There is still another table active. Return with error. */
+  if (htab->table != NULL)
+    return 0;
+
+  /* Change nel to the first prime number not smaller as nel. */
+  nel |= 1;      /* make odd */
+  while (!isprime (nel))
+    nel += 2;
+
+  htab->size = nel;
+  htab->filled = 0;
+
+  /* allocate memory and zero out */
+  htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY));
+  if (htab->table == NULL)
+    return 0;
+
+  /* everything went alright */
+  return 1;
+}
+
+
+/* After using the hash table it has to be destroyed. The used memory can
+   be freed and the local static variable can be marked as not used.  */
+void
+hdestroy_r (struct hsearch_data *htab)
+{
+  /* Test for correct arguments.  */
+  if (htab == NULL)
+    {
+      __set_errno (EINVAL);
+      return;
+    }
+
+  /* Free used memory.  */
+  free (htab->table);
+
+  /* the sign for an existing table is an value != NULL in htable */
+  htab->table = NULL;
+}
+
+
+/* This is the search function. It uses double hashing with open addressing.
+   The argument item.key has to be a pointer to an zero terminated, most
+   probably strings of chars. The function for generating a number of the
+   strings is simple but fast. It can be replaced by a more complex function
+   like ajw (see [Aho,Sethi,Ullman]) if the needs are shown.
+
+   We use an trick to speed up the lookup. The table is created by hcreate
+   with one more element available. This enables us to use the index zero
+   special. This index will never be used because we store the first hash
+   index in the field used where zero means not used. Every other value
+   means used. The used field can be used as a first fast comparison for
+   equality of the stored and the parameter value. This helps to prevent
+   unnecessary expensive calls of strcmp.  */
+int
+hsearch_r (ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab)
+{
+  unsigned int hval;
+  unsigned int count;
+  unsigned int len = strlen (item.key);
+  unsigned int idx;
+
+  /* Compute an value for the given string. Perhaps use a better method. */
+  hval = len;
+  count = len;
+  while (count-- > 0)
+    {
+      hval <<= 4;
+      hval += item.key[count];
+    }
+
+  /* First hash function: simply take the modul but prevent zero. */
+  idx = hval % htab->size + 1;
+
+  if (htab->table[idx].used)
+    {
+      /* Further action might be required according to the action value. */
+      if (htab->table[idx].used == hval
+	  && strcmp (item.key, htab->table[idx].entry.key) == 0)
+	{
+	  *retval = &htab->table[idx].entry;
+	  return 1;
+	}
+
+      /* Second hash function, as suggested in [Knuth] */
+      unsigned int hval2 = 1 + hval % (htab->size - 2);
+      unsigned int first_idx = idx;
+
+      do
+	{
+	  /* Because SIZE is prime this guarantees to step through all
+             available indeces.  */
+          if (idx <= hval2)
+	    idx = htab->size + idx - hval2;
+	  else
+	    idx -= hval2;
+
+	  /* If we visited all entries leave the loop unsuccessfully.  */
+	  if (idx == first_idx)
+	    break;
+
+            /* If entry is found use it. */
+          if (htab->table[idx].used == hval
+	      && strcmp (item.key, htab->table[idx].entry.key) == 0)
+	    {
+	      *retval = &htab->table[idx].entry;
+	      return 1;
+	    }
+	}
+      while (htab->table[idx].used);
+    }
+
+  /* An empty bucket has been found. */
+  if (action == ENTER)
+    {
+      /* If table is full and another entry should be entered return
+	 with error.  */
+      if (htab->filled == htab->size)
+	{
+	  __set_errno (ENOMEM);
+	  *retval = NULL;
+	  return 0;
+	}
+
+      htab->table[idx].used  = hval;
+      htab->table[idx].entry = item;
+
+      ++htab->filled;
+
+      *retval = &htab->table[idx].entry;
+      return 1;
+    }
+
+  __set_errno (ESRCH);
+  *retval = NULL;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/hsearch_r.h	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,42 @@
+/* Declarations for System V style searching functions.
+   Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _HSEARCH_R_H_
+#define _HSEARCH_R_H_
+
+#include <search.h>
+
+struct _ENTRY;
+
+/* Data type for reentrant functions.  */
+struct hsearch_data
+  {
+    struct _ENTRY *table;
+    unsigned int size;
+    unsigned int filled;
+  };
+
+/* Reentrant versions which can handle multiple hashing tables at the
+   same time.  */
+extern int hsearch_r (ENTRY __item, ACTION __action, ENTRY **__retval,
+                      struct hsearch_data *__htab);
+extern int hcreate_r (size_t __nel, struct hsearch_data *__htab);
+extern void hdestroy_r (struct hsearch_data *__htab);
+
+#endif /* _HSEARCH_R_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/libproc.h	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#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_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/libproc_impl.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/libproc_impl.h	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#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_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/mapfile	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,66 @@
+#
+
+#
+# Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#  
+#
+
+# 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:
+		*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/ps_core.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,1023 @@
+/*
+ * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include <jni.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <elf.h>
+#include <link.h>
+#include "libproc_impl.h"
+#include "salibelf.h"
+
+// This file has the libproc implementation to read core files.
+// For live processes, refer to ps_proc.c. Portions of this is adapted
+// /modelled after Solaris libproc.so (in particular Pcore.c)
+
+//----------------------------------------------------------------------
+// ps_prochandle cleanup helper functions
+
+// close all file descriptors
+static void close_elf_files(struct ps_prochandle* ph) {
+   lib_info* lib = NULL;
+
+   // close core file descriptor
+   if (ph->core->core_fd >= 0)
+     close(ph->core->core_fd);
+
+   // close exec file descriptor
+   if (ph->core->exec_fd >= 0)
+     close(ph->core->exec_fd);
+
+   // close interp file descriptor
+   if (ph->core->interp_fd >= 0)
+     close(ph->core->interp_fd);
+
+   // close class share archive file
+   if (ph->core->classes_jsa_fd >= 0)
+     close(ph->core->classes_jsa_fd);
+
+   // close all library file descriptors
+   lib = ph->libs;
+   while (lib) {
+      int fd = lib->fd;
+      if (fd >= 0 && fd != ph->core->exec_fd) close(fd);
+      lib = lib->next;
+   }
+}
+
+// clean all map_info stuff
+static void destroy_map_info(struct ps_prochandle* ph) {
+  map_info* map = ph->core->maps;
+  while (map) {
+     map_info* next = map->next;
+     free(map);
+     map = next;
+  }
+
+  if (ph->core->map_array) {
+     free(ph->core->map_array);
+  }
+
+  // Part of the class sharing workaround
+  map = ph->core->class_share_maps;
+  while (map) {
+     map_info* next = map->next;
+     free(map);
+     map = next;
+  }
+}
+
+// ps_prochandle operations
+static void core_release(struct ps_prochandle* ph) {
+   if (ph->core) {
+      close_elf_files(ph);
+      destroy_map_info(ph);
+      free(ph->core);
+   }
+}
+
+static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) {
+   map_info* map;
+   if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) {
+      print_debug("can't allocate memory for map_info\n");
+      return NULL;
+   }
+
+   // initialize map
+   map->fd     = fd;
+   map->offset = offset;
+   map->vaddr  = vaddr;
+   map->memsz  = memsz;
+   return map;
+}
+
+// add map info with given fd, offset, vaddr and memsz
+static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
+                             uintptr_t vaddr, size_t memsz) {
+   map_info* map;
+   if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) {
+      return NULL;
+   }
+
+   // add this to map list
+   map->next  = ph->core->maps;
+   ph->core->maps   = map;
+   ph->core->num_maps++;
+
+   return map;
+}
+
+// Part of the class sharing workaround
+static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset,
+                             uintptr_t vaddr, size_t memsz) {
+   map_info* map;
+   if ((map = allocate_init_map(ph->core->classes_jsa_fd,
+                                offset, vaddr, memsz)) == NULL) {
+      return NULL;
+   }
+
+   map->next = ph->core->class_share_maps;
+   ph->core->class_share_maps = map;
+   return map;
+}
+
+// Return the map_info for the given virtual address.  We keep a sorted
+// array of pointers in ph->map_array, so we can binary search.
+static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr)
+{
+   int mid, lo = 0, hi = ph->core->num_maps - 1;
+   map_info *mp;
+
+   while (hi - lo > 1) {
+     mid = (lo + hi) / 2;
+      if (addr >= ph->core->map_array[mid]->vaddr)
+         lo = mid;
+      else
+         hi = mid;
+   }
+
+   if (addr < ph->core->map_array[hi]->vaddr)
+      mp = ph->core->map_array[lo];
+   else
+      mp = ph->core->map_array[hi];
+
+   if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz)
+      return (mp);
+
+
+   // Part of the class sharing workaround
+   // Unfortunately, we have no way of detecting -Xshare state.
+   // Check out the share maps atlast, if we don't find anywhere.
+   // This is done this way so to avoid reading share pages
+   // ahead of other normal maps. For eg. with -Xshare:off we don't
+   // want to prefer class sharing data to data from core.
+   mp = ph->core->class_share_maps;
+   if (mp) {
+      print_debug("can't locate map_info at 0x%lx, trying class share maps\n",
+             addr);
+   }
+   while (mp) {
+      if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
+         print_debug("located map_info at 0x%lx from class share maps\n",
+                  addr);
+         return (mp);
+      }
+      mp = mp->next;
+   }
+
+   print_debug("can't locate map_info at 0x%lx\n", addr);
+   return (NULL);
+}
+
+//---------------------------------------------------------------
+// Part of the class sharing workaround:
+//
+// With class sharing, pages are mapped from classes[_g].jsa file.
+// The read-only class sharing pages are mapped as MAP_SHARED,
+// PROT_READ pages. These pages are not dumped into core dump.
+// With this workaround, these pages are read from classes[_g].jsa.
+
+// FIXME: !HACK ALERT!
+// The format of sharing achive file header is needed to read shared heap
+// file mappings. For now, I am hard coding portion of FileMapHeader here.
+// Refer to filemap.hpp.
+
+// FileMapHeader describes the shared space data in the file to be
+// mapped.  This structure gets written to a file.  It is not a class,
+// so that the compilers don't add any compiler-private data to it.
+
+// Refer to CompactingPermGenGen::n_regions in compactingPermGenGen.hpp
+#define NUM_SHARED_MAPS 4
+
+// Refer to FileMapInfo::_current_version in filemap.hpp
+#define CURRENT_ARCHIVE_VERSION 1
+
+struct FileMapHeader {
+  int   _magic;              // identify file type.
+  int   _version;            // (from enum, above.)
+  size_t _alignment;         // how shared archive should be aligned
+
+  struct space_info {
+    int    _file_offset;     // sizeof(this) rounded to vm page size
+    char*  _base;            // copy-on-write base address
+    size_t _capacity;        // for validity checking
+    size_t _used;            // for setting space top on read
+
+    // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with
+    // the C type matching the C++ bool type on any given platform. For
+    // Hotspot on BSD we assume the corresponding C type is char but
+    // licensees on BSD versions may need to adjust the type of these fields.
+    char   _read_only;       // read only space?
+    char   _allow_exec;      // executable code in space?
+
+  } _space[NUM_SHARED_MAPS]; // was _space[CompactingPermGenGen::n_regions];
+
+  // Ignore the rest of the FileMapHeader. We don't need those fields here.
+};
+
+static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) {
+   jboolean i;
+   if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) {
+      *pvalue = i;
+      return true;
+   } else {
+      return false;
+   }
+}
+
+static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) {
+   uintptr_t uip;
+   if (ps_pread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) {
+      *pvalue = uip;
+      return true;
+   } else {
+      return false;
+   }
+}
+
+// used to read strings from debuggee
+static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) {
+   size_t i = 0;
+   char  c = ' ';
+
+   while (c != '\0') {
+     if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK)
+         return false;
+      if (i < size - 1)
+         buf[i] = c;
+      else // smaller buffer
+         return false;
+      i++; addr++;
+   }
+
+   buf[i] = '\0';
+   return true;
+}
+
+#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
+// mangled name of Arguments::SharedArchivePath
+#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE"
+
+static bool init_classsharing_workaround(struct ps_prochandle* ph) {
+   lib_info* lib = ph->libs;
+   while (lib != NULL) {
+      // we are iterating over shared objects from the core dump. look for
+      // libjvm[_g].so.
+      const char *jvm_name = 0;
+      if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
+          (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) {
+         char classes_jsa[PATH_MAX];
+         struct FileMapHeader header;
+         size_t n = 0;
+         int fd = -1, m = 0;
+         uintptr_t base = 0, useSharedSpacesAddr = 0;
+         uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0;
+         jboolean useSharedSpaces = 0;
+
+         memset(classes_jsa, 0, sizeof(classes_jsa));
+         jvm_name = lib->name;
+         useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM);
+         if (useSharedSpacesAddr == 0) {
+            print_debug("can't lookup 'UseSharedSpaces' flag\n");
+            return false;
+         }
+
+	 // Hotspot vm types are not exported to build this library. So
+	 // using equivalent type jboolean to read the value of
+	 // UseSharedSpaces which is same as hotspot type "bool".
+         if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) {
+            print_debug("can't read the value of 'UseSharedSpaces' flag\n");
+            return false;
+         }
+
+         if ((int)useSharedSpaces == 0) {
+            print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
+            return true;
+         }
+
+         sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM);
+         if (sharedArchivePathAddrAddr == 0) {
+            print_debug("can't lookup shared archive path symbol\n");
+            return false;
+         }
+
+         if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
+            print_debug("can't read shared archive path pointer\n");
+            return false;
+         }
+
+         if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
+            print_debug("can't read shared archive path value\n");
+            return false;
+         }
+
+         print_debug("looking for %s\n", classes_jsa);
+         // open the class sharing archive file
+         fd = pathmap_open(classes_jsa);
+         if (fd < 0) {
+            print_debug("can't open %s!\n", classes_jsa);
+            ph->core->classes_jsa_fd = -1;
+            return false;
+         } else {
+            print_debug("opened %s\n", classes_jsa);
+         }
+
+         // read FileMapHeader from the file
+         memset(&header, 0, sizeof(struct FileMapHeader));
+         if ((n = read(fd, &header, sizeof(struct FileMapHeader)))
+              != sizeof(struct FileMapHeader)) {
+            print_debug("can't read shared archive file map header from %s\n", classes_jsa);
+            close(fd);
+            return false;
+         }
+
+         // check file magic
+         if (header._magic != 0xf00baba2) {
+            print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n",
+                        classes_jsa, header._magic);
+            close(fd);
+            return false;
+         }
+
+         // check version
+         if (header._version != CURRENT_ARCHIVE_VERSION) {
+            print_debug("%s has wrong shared archive file version %d, expecting %d\n",
+                        classes_jsa, header._version, CURRENT_ARCHIVE_VERSION);
+            close(fd);
+            return false;
+         }
+
+         ph->core->classes_jsa_fd = fd;
+         // add read-only maps from classes[_g].jsa to the list of maps
+         for (m = 0; m < NUM_SHARED_MAPS; m++) {
+            if (header._space[m]._read_only) {
+               base = (uintptr_t) header._space[m]._base;
+               // no need to worry about the fractional pages at-the-end.
+               // possible fractional pages are handled by core_read_data.
+               add_class_share_map_info(ph, (off_t) header._space[m]._file_offset,
+                         base, (size_t) header._space[m]._used);
+               print_debug("added a share archive map at 0x%lx\n", base);
+            }
+         }
+         return true;
+      }
+      lib = lib->next;
+   }
+   return true;
+}
+
+
+//---------------------------------------------------------------------------
+// functions to handle map_info
+
+// Order mappings based on virtual address.  We use this function as the
+// callback for sorting the array of map_info pointers.
+static int core_cmp_mapping(const void *lhsp, const void *rhsp)
+{
+   const map_info *lhs = *((const map_info **)lhsp);
+   const map_info *rhs = *((const map_info **)rhsp);
+
+   if (lhs->vaddr == rhs->vaddr)
+      return (0);
+
+   return (lhs->vaddr < rhs->vaddr ? -1 : 1);
+}
+
+// we sort map_info by starting virtual address so that we can do
+// binary search to read from an address.
+static bool sort_map_array(struct ps_prochandle* ph) {
+   size_t num_maps = ph->core->num_maps;
+   map_info* map = ph->core->maps;
+   int i = 0;
+
+   // allocate map_array
+   map_info** array;
+   if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) {
+      print_debug("can't allocate memory for map array\n");
+      return false;
+   }
+
+   // add maps to array
+   while (map) {
+      array[i] = map;
+      i++;
+      map = map->next;
+   }
+
+   // sort is called twice. If this is second time, clear map array
+   if (ph->core->map_array) free(ph->core->map_array);
+   ph->core->map_array = array;
+   // sort the map_info array by base virtual address.
+   qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*),
+            core_cmp_mapping);
+
+   // print map
+   if (is_debug()) {
+      int j = 0;
+      print_debug("---- sorted virtual address map ----\n");
+      for (j = 0; j < ph->core->num_maps; j++) {
+        print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr,
+                                         ph->core->map_array[j]->memsz);
+      }
+   }
+
+   return true;
+}
+
+#ifndef MIN
+#define MIN(x, y) (((x) < (y))? (x): (y))
+#endif
+
+static bool core_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) {
+   ssize_t resid = size;
+   int page_size=sysconf(_SC_PAGE_SIZE);
+   while (resid != 0) {
+      map_info *mp = core_lookup(ph, addr);
+      uintptr_t mapoff;
+      ssize_t len, rem;
+      off_t off;
+      int fd;
+
+      if (mp == NULL)
+         break;  /* No mapping for this address */
+
+      fd = mp->fd;
+      mapoff = addr - mp->vaddr;
+      len = MIN(resid, mp->memsz - mapoff);
+      off = mp->offset + mapoff;
+
+      if ((len = pread(fd, buf, len, off)) <= 0)
+         break;
+
+      resid -= len;
+      addr += len;
+      buf = (char *)buf + len;
+
+      // mappings always start at page boundary. But, may end in fractional
+      // page. fill zeros for possible fractional page at the end of a mapping.
+      rem = mp->memsz % page_size;
+      if (rem > 0) {
+         rem = page_size - rem;
+         len = MIN(resid, rem);
+         resid -= len;
+         addr += len;
+         // we are not assuming 'buf' to be zero initialized.
+         memset(buf, 0, len);
+         buf += len;
+      }
+   }
+
+   if (resid) {
+      print_debug("core read failed for %d byte(s) @ 0x%lx (%d more bytes)\n",
+              size, addr, resid);
+      return false;
+   } else {
+      return true;
+   }
+}
+
+// null implementation for write
+static bool core_write_data(struct ps_prochandle* ph,
+                             uintptr_t addr, const char *buf , size_t size) {
+   return false;
+}
+
+static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id,
+                          struct reg* regs) {
+   // for core we have cached the lwp regs from NOTE section
+   thread_info* thr = ph->threads;
+   while (thr) {
+     if (thr->lwp_id == lwp_id) {
+       memcpy(regs, &thr->regs, sizeof(struct reg));
+       return true;
+     }
+     thr = thr->next;
+   }
+   return false;
+}
+
+static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) {
+   print_debug("core_get_lwp_info not implemented\n");
+   return false;
+}
+
+static ps_prochandle_ops core_ops = {
+   .release=  core_release,
+   .p_pread=  core_read_data,
+   .p_pwrite= core_write_data,
+   .get_lwp_regs= core_get_lwp_regs,
+   .get_lwp_info= core_get_lwp_info
+};
+
+// read regs and create thread from NT_PRSTATUS entries from core file
+static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size_t nbytes) {
+   // we have to read prstatus_t from buf
+   // assert(nbytes == sizeof(prstaus_t), "size mismatch on prstatus_t");
+   prstatus_t* prstat = (prstatus_t*) buf;
+   thread_info* newthr;
+   print_debug("got integer regset for lwp %d\n", prstat->pr_pid);
+   // we set pthread_t to -1 for core dump
+   if((newthr = add_thread_info(ph, (pthread_t) -1,  prstat->pr_pid)) == NULL)
+      return false;
+
+   // copy regs
+   memcpy(&newthr->regs, &prstat->pr_reg, sizeof(struct reg));
+
+   if (is_debug()) {
+      print_debug("integer regset\n");
+#ifdef i386
+      // print the regset
+      print_debug("\teax = 0x%x\n", newthr->regs.r_eax);
+      print_debug("\tebx = 0x%x\n", newthr->regs.r_ebx);
+      print_debug("\tecx = 0x%x\n", newthr->regs.r_ecx);
+      print_debug("\tedx = 0x%x\n", newthr->regs.r_edx);
+      print_debug("\tesp = 0x%x\n", newthr->regs.r_esp);
+      print_debug("\tebp = 0x%x\n", newthr->regs.r_ebp);
+      print_debug("\tesi = 0x%x\n", newthr->regs.r_esi);
+      print_debug("\tedi = 0x%x\n", newthr->regs.r_edi);
+      print_debug("\teip = 0x%x\n", newthr->regs.r_eip);
+#endif
+
+#if defined(amd64) || defined(x86_64)
+      // print the regset
+      print_debug("\tr15 = 0x%lx\n", newthr->regs.r_r15);
+      print_debug("\tr14 = 0x%lx\n", newthr->regs.r_r14);
+      print_debug("\tr13 = 0x%lx\n", newthr->regs.r_r13);
+      print_debug("\tr12 = 0x%lx\n", newthr->regs.r_r12);
+      print_debug("\trbp = 0x%lx\n", newthr->regs.r_rbp);
+      print_debug("\trbx = 0x%lx\n", newthr->regs.r_rbx);
+      print_debug("\tr11 = 0x%lx\n", newthr->regs.r_r11);
+      print_debug("\tr10 = 0x%lx\n", newthr->regs.r_r10);
+      print_debug("\tr9 = 0x%lx\n", newthr->regs.r_r9);
+      print_debug("\tr8 = 0x%lx\n", newthr->regs.r_r8);
+      print_debug("\trax = 0x%lx\n", newthr->regs.r_rax);
+      print_debug("\trcx = 0x%lx\n", newthr->regs.r_rcx);
+      print_debug("\trdx = 0x%lx\n", newthr->regs.r_rdx);
+      print_debug("\trsi = 0x%lx\n", newthr->regs.r_rsi);
+      print_debug("\trdi = 0x%lx\n", newthr->regs.r_rdi);
+      //print_debug("\torig_rax = 0x%lx\n", newthr->regs.orig_rax);
+      print_debug("\trip = 0x%lx\n", newthr->regs.r_rip);
+      print_debug("\tcs = 0x%lx\n", newthr->regs.r_cs);
+      //print_debug("\teflags = 0x%lx\n", newthr->regs.eflags);
+      print_debug("\trsp = 0x%lx\n", newthr->regs.r_rsp);
+      print_debug("\tss = 0x%lx\n", newthr->regs.r_ss);
+      //print_debug("\tfs_base = 0x%lx\n", newthr->regs.fs_base);
+      //print_debug("\tgs_base = 0x%lx\n", newthr->regs.gs_base);
+      //print_debug("\tds = 0x%lx\n", newthr->regs.ds);
+      //print_debug("\tes = 0x%lx\n", newthr->regs.es);
+      //print_debug("\tfs = 0x%lx\n", newthr->regs.fs);
+      //print_debug("\tgs = 0x%lx\n", newthr->regs.gs);
+#endif
+   }
+
+   return true;
+}
+
+#define ROUNDUP(x, y)  ((((x)+((y)-1))/(y))*(y))
+
+// read NT_PRSTATUS entries from core NOTE segment
+static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) {
+   char* buf = NULL;
+   char* p = NULL;
+   size_t size = note_phdr->p_filesz;
+
+   // we are interested in just prstatus entries. we will ignore the rest.
+   // Advance the seek pointer to the start of the PT_NOTE data
+   if (lseek(ph->core->core_fd, note_phdr->p_offset, SEEK_SET) == (off_t)-1) {
+      print_debug("failed to lseek to PT_NOTE data\n");
+      return false;
+   }
+
+   // Now process the PT_NOTE structures.  Each one is preceded by
+   // an Elf{32/64}_Nhdr structure describing its type and size.
+   if ( (buf = (char*) malloc(size)) == NULL) {
+      print_debug("can't allocate memory for reading core notes\n");
+      goto err;
+   }
+
+   // read notes into buffer
+   if (read(ph->core->core_fd, buf, size) != size) {
+      print_debug("failed to read notes, core file must have been truncated\n");
+      goto err;
+   }
+
+   p = buf;
+   while (p < buf + size) {
+      ELF_NHDR* notep = (ELF_NHDR*) p;
+      char* descdata  = p + sizeof(ELF_NHDR) + ROUNDUP(notep->n_namesz, 4);
+      print_debug("Note header with n_type = %d and n_descsz = %u\n",
+                                   notep->n_type, notep->n_descsz);
+
+      if (notep->n_type == NT_PRSTATUS) {
+         if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true)
+            return false;
+      }
+      p = descdata + ROUNDUP(notep->n_descsz, 4);
+   }
+
+   free(buf);
+   return true;
+
+err:
+   if (buf) free(buf);
+   return false;
+}
+
+// read all segments from core file
+static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) {
+   int i = 0;
+   ELF_PHDR* phbuf = NULL;
+   ELF_PHDR* core_php = NULL;
+
+   if ((phbuf =  read_program_header_table(ph->core->core_fd, core_ehdr)) == NULL)
+      return false;
+
+   /*
+    * Now iterate through the program headers in the core file.
+    * We're interested in two types of Phdrs: PT_NOTE (which
+    * contains a set of saved /proc structures), and PT_LOAD (which
+    * represents a memory mapping from the process's address space).
+    *
+    * Difference b/w Solaris PT_NOTE and BSD PT_NOTE:
+    *
+    *     In Solaris there are two PT_NOTE segments the first PT_NOTE (if present)
+    *     contains /proc structs in the pre-2.6 unstructured /proc format. the last
+    *     PT_NOTE has data in new /proc format.
+    *
+    *     In Solaris, there is only one pstatus (process status). pstatus contains
+    *     integer register set among other stuff. For each LWP, we have one lwpstatus
+    *     entry that has integer regset for that LWP.
+    *
+    *     Linux threads are actually 'clone'd processes. To support core analysis
+    *     of "multithreaded" process, Linux creates more than one pstatus (called
+    *     "prstatus") entry in PT_NOTE. Each prstatus entry has integer regset for one
+    *     "thread". Please refer to Linux kernel src file 'fs/binfmt_elf.c', in particular
+    *     function "elf_core_dump".
+    */
+
+    for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) {
+      switch (core_php->p_type) {
+         case PT_NOTE:
+            if (core_handle_note(ph, core_php) != true) goto err;
+            break;
+
+         case PT_LOAD: {
+            if (core_php->p_filesz != 0) {
+               if (add_map_info(ph, ph->core->core_fd, core_php->p_offset,
+                  core_php->p_vaddr, core_php->p_filesz) == NULL) goto err;
+            }
+            break;
+         }
+      }
+
+      core_php++;
+   }
+
+   free(phbuf);
+   return true;
+err:
+   free(phbuf);
+   return false;
+}
+
+// read segments of a shared object
+static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) {
+   int i = 0;
+   ELF_PHDR* phbuf;
+   ELF_PHDR* lib_php = NULL;
+
+   if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL)
+      return false;
+
+   // we want to process only PT_LOAD segments that are not writable.
+   // i.e., text segments. The read/write/exec (data) segments would
+   // have been already added from core file segments.
+   for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) {
+      if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) {
+         if (add_map_info(ph, lib_fd, lib_php->p_offset, lib_php->p_vaddr + lib_base, lib_php->p_filesz) == NULL)
+            goto err;
+      }
+      lib_php++;
+   }
+
+   free(phbuf);
+   return true;
+err:
+   free(phbuf);
+   return false;
+}
+
+// process segments from interpreter (ld-elf.so.1)
+static bool read_interp_segments(struct ps_prochandle* ph) {
+   ELF_EHDR interp_ehdr;
+
+   if (read_elf_header(ph->core->interp_fd, &interp_ehdr) != true) {
+       print_debug("interpreter is not a valid ELF file\n");
+       return false;
+   }
+
+   if (read_lib_segments(ph, ph->core->interp_fd, &interp_ehdr, ph->core->ld_base_addr) != true) {
+       print_debug("can't read segments of interpreter\n");
+       return false;
+   }
+
+   return true;
+}
+
+// process segments of a a.out
+static bool read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehdr) {
+   int i = 0;
+   ELF_PHDR* phbuf = NULL;
+   ELF_PHDR* exec_php = NULL;
+
+   if ((phbuf = read_program_header_table(ph->core->exec_fd, exec_ehdr)) == NULL)
+      return false;
+
+   for (exec_php = phbuf, i = 0; i < exec_ehdr->e_phnum; i++) {
+      switch (exec_php->p_type) {
+
+         // add mappings for PT_LOAD segments
+         case PT_LOAD: {
+            // add only non-writable segments of non-zero filesz
+            if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) {
+               if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz) == NULL) goto err;
+            }
+            break;
+         }
+
+         // read the interpreter and it's segments
+         case PT_INTERP: {
+            char interp_name[BUF_SIZE];
+
+            pread(ph->core->exec_fd, interp_name, MIN(exec_php->p_filesz, BUF_SIZE), exec_php->p_offset);
+            print_debug("ELF interpreter %s\n", interp_name);
+            // read interpreter segments as well
+            if ((ph->core->interp_fd = pathmap_open(interp_name)) < 0) {
+               print_debug("can't open runtime loader\n");
+               goto err;
+            }
+            break;
+         }
+
+         // from PT_DYNAMIC we want to read address of first link_map addr
+         case PT_DYNAMIC: {
+            ph->core->dynamic_addr = exec_php->p_vaddr;
+            print_debug("address of _DYNAMIC is 0x%lx\n", ph->core->dynamic_addr);
+            break;
+         }
+
+      } // switch
+      exec_php++;
+   } // for
+
+   free(phbuf);
+   return true;
+err:
+   free(phbuf);
+   return false;
+}
+
+
+#define FIRST_LINK_MAP_OFFSET offsetof(struct r_debug,  r_map)
+#define LD_BASE_OFFSET        offsetof(struct r_debug,  r_ldbase)
+#define LINK_MAP_ADDR_OFFSET  offsetof(struct link_map, l_addr)
+#define LINK_MAP_NAME_OFFSET  offsetof(struct link_map, l_name)
+#define LINK_MAP_NEXT_OFFSET  offsetof(struct link_map, l_next)
+
+// read shared library info from runtime linker's data structures.
+// This work is done by librtlb_db in Solaris
+static bool read_shared_lib_info(struct ps_prochandle* ph) {
+   uintptr_t addr = ph->core->dynamic_addr;
+   uintptr_t debug_base;
+   uintptr_t first_link_map_addr;
+   uintptr_t ld_base_addr;
+   uintptr_t link_map_addr;
+   uintptr_t lib_base_diff;
+   uintptr_t lib_base;
+   uintptr_t lib_name_addr;
+   char lib_name[BUF_SIZE];
+   ELF_DYN dyn;
+   ELF_EHDR elf_ehdr;
+   int lib_fd;
+
+   // _DYNAMIC has information of the form
+   //         [tag] [data] [tag] [data] .....
+   // Both tag and data are pointer sized.
+   // We look for dynamic info with DT_DEBUG. This has shared object info.
+   // refer to struct r_debug in link.h
+
+   dyn.d_tag = DT_NULL;
+   while (dyn.d_tag != DT_DEBUG) {
+      if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) {
+         print_debug("can't read debug info from _DYNAMIC\n");
+         return false;
+      }
+      addr += sizeof(ELF_DYN);
+   }
+
+   // we have got Dyn entry with DT_DEBUG
+   debug_base = dyn.d_un.d_ptr;
+   // at debug_base we have struct r_debug. This has first link map in r_map field
+   if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET,
+                 &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) {
+      print_debug("can't read first link map address\n");
+      return false;
+   }
+
+   // read ld_base address from struct r_debug
+   // XXX: There is no r_ldbase member on BSD
+/*
+   if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr,
+                 sizeof(uintptr_t)) != PS_OK) {
+      print_debug("can't read ld base address\n");
+      return false;
+   }
+   ph->core->ld_base_addr = ld_base_addr;
+*/
+   ph->core->ld_base_addr = 0;
+
+   print_debug("interpreter base address is 0x%lx\n", ld_base_addr);
+
+   // now read segments from interp (i.e ld-elf.so.1)
+   if (read_interp_segments(ph) != true)
+      return false;
+
+   // after adding interpreter (ld.so) mappings sort again
+   if (sort_map_array(ph) != true)
+      return false;
+
+   print_debug("first link map is at 0x%lx\n", first_link_map_addr);
+
+   link_map_addr = first_link_map_addr;
+   while (link_map_addr != 0) {
+      // read library base address of the .so. Note that even though <sys/link.h> calls
+      // link_map->l_addr as "base address",  this is * not * really base virtual
+      // address of the shared object. This is actually the difference b/w the virtual
+      // address mentioned in shared object and the actual virtual base where runtime
+      // linker loaded it. We use "base diff" in read_lib_segments call below.
+
+      if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET,
+                   &lib_base_diff, sizeof(uintptr_t)) != PS_OK) {
+         print_debug("can't read shared object base address diff\n");
+         return false;
+      }
+
+      // read address of the name
+      if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET,
+                    &lib_name_addr, sizeof(uintptr_t)) != PS_OK) {
+         print_debug("can't read address of shared object name\n");
+         return false;
+      }
+
+      // read name of the shared object
+      if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) {
+         print_debug("can't read shared object name\n");
+         return false;
+      }
+
+      if (lib_name[0] != '\0') {
+         // ignore empty lib names
+         lib_fd = pathmap_open(lib_name);
+
+         if (lib_fd < 0) {
+            print_debug("can't open shared object %s\n", lib_name);
+            // continue with other libraries...
+         } else {
+            if (read_elf_header(lib_fd, &elf_ehdr)) {
+               lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr);
+               print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n",
+                           lib_name, lib_base, lib_base_diff);
+               // while adding library mappings we need to use "base difference".
+               if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) {
+                  print_debug("can't read shared object's segments\n");
+                  close(lib_fd);
+                  return false;
+               }
+               add_lib_info_fd(ph, lib_name, lib_fd, lib_base);
+               // Map info is added for the library (lib_name) so
+               // we need to re-sort it before calling the p_pdread.
+               if (sort_map_array(ph) != true)
+                  return false;
+            } else {
+               print_debug("can't read ELF header for shared object %s\n", lib_name);
+               close(lib_fd);
+               // continue with other libraries...
+            }
+         }
+      }
+
+      // read next link_map address
+      if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET,
+                        &link_map_addr, sizeof(uintptr_t)) != PS_OK) {
+         print_debug("can't read next link in link_map\n");
+         return false;
+      }
+   }
+
+   return true;
+}
+
+// the one and only one exposed stuff from this file
+struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) {
+   ELF_EHDR core_ehdr;
+   ELF_EHDR exec_ehdr;
+
+   struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle));
+   if (ph == NULL) {
+      print_debug("can't allocate ps_prochandle\n");
+      return NULL;
+   }
+
+   if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) {
+      free(ph);
+      print_debug("can't allocate ps_prochandle\n");
+      return NULL;
+   }
+
+   // initialize ph
+   ph->ops = &core_ops;
+   ph->core->core_fd   = -1;
+   ph->core->exec_fd   = -1;
+   ph->core->interp_fd = -1;
+
+   // open the core file
+   if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) {
+      print_debug("can't open core file\n");
+      goto err;
+   }
+
+   // read core file ELF header
+   if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) {
+      print_debug("core file is not a valid ELF ET_CORE file\n");
+      goto err;
+   }
+
+   if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) {
+      print_debug("can't open executable file\n");
+      goto err;
+   }
+
+   if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) {
+      print_debug("executable file is not a valid ELF ET_EXEC file\n");
+      goto err;
+   }
+
+   // process core file segments
+   if (read_core_segments(ph, &core_ehdr) != true)
+      goto err;
+
+   // process exec file segments
+   if (read_exec_segments(ph, &exec_ehdr) != true)
+      goto err;
+
+   // exec file is also treated like a shared object for symbol search
+   if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd,
+                       (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL)
+      goto err;
+
+   // allocate and sort maps into map_array, we need to do this
+   // here because read_shared_lib_info needs to read from debuggee
+   // address space
+   if (sort_map_array(ph) != true)
+      goto err;
+
+   if (read_shared_lib_info(ph) != true)
+      goto err;
+
+   // sort again because we have added more mappings from shared objects
+   if (sort_map_array(ph) != true)
+      goto err;
+
+   if (init_classsharing_workaround(ph) != true)
+      goto err;
+
+   return ph;
+
+err:
+   Prelease(ph);
+   return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/ps_proc.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,447 @@
+#ifdef USE_PRAGMA_IDENT_SRC
+#pragma ident "@(#)ps_proc.c	1.17 07/05/05 17:02:02 JVM"
+#endif
+/*
+ * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *  
+ */
+
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/salibelf.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/salibelf.h	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#ifndef _SALIBELF_H_
+#define _SALIBELF_H_
+
+#include <elf.h>
+#include "elfmacros.h"
+#include "libproc_impl.h"
+
+// read ELF file header.
+int read_elf_header(int fd, ELF_EHDR* ehdr);
+
+// is given file descriptor corresponds to an ELF file?
+bool is_elf_file(int fd);
+
+// 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);
+
+// 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);
+
+// 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);
+
+// 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_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/symtab.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include <unistd.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include "hsearch_r.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;
+  struct hsearch_data *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 = (struct elf_section *)
+              calloc(ehdr.e_shnum * sizeof(struct elf_section), 1);
+  if (scn_cache == NULL) {
+    goto quit;
+  }
+
+  for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) {
+    scn_cache[cnt].c_shdr = cursct;
+    if (cursct->sh_type == SHT_SYMTAB ||
+        cursct->sh_type == SHT_STRTAB ||
+        cursct->sh_type == SHT_DYNSYM) {
+      if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
+         goto quit;
+      }
+    }
+
+    if (cursct->sh_type == SHT_SYMTAB)
+       symtab_found++;
+
+    if (cursct->sh_type == SHT_DYNSYM)
+       dynsym_found++;
+
+    cursct++;
+  }
+
+  if (!symtab_found && dynsym_found)
+     symsection = SHT_DYNSYM;
+
+  for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
+    ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
+
+    if (shdr->sh_type == symsection) {
+      ELF_SYM  *syms;
+      int j, n, rslt;
+      size_t size;
+
+      // FIXME: there could be multiple data buffers associated with the
+      // same ELF section. Here we can handle only one buffer. See man page
+      // for elf_getdata on Solaris.
+
+      // guarantee(symtab == NULL, "multiple symtab");
+      symtab = (struct symtab*)calloc(1, sizeof(struct 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 hcreate_r, hsearch_r and hdestroy_r to
+      // manipulate the hash table.
+      symtab->hash_table = (struct hsearch_data*) calloc(1, sizeof(struct hsearch_data));
+      rslt = hcreate_r(n, symtab->hash_table);
+      // guarantee(rslt, "unexpected failure: hcreate_r");
+
+      // 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 = (char *)malloc(size);
+      memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);
+
+      // allocate memory for storing symbol offset and size;
+      symtab->num_symbols = n;
+      symtab->symbols = (struct elf_symbol *)calloc(n , sizeof(struct elf_symbol));
+
+      // copy symbols info our symtab and enter them info the hash table
+      for (j = 0; j < n; j++, syms++) {
+        ENTRY item, *ret;
+        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;
+
+        item.key = sym_name;
+        item.data = (void *)&(symtab->symbols[j]);
+
+        hsearch_r(item, ENTER, &ret, symtab->hash_table);
+      }
+    }
+  }
+
+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) {
+     hdestroy_r(symtab->hash_table);
+     free(symtab->hash_table);
+  }
+  free(symtab);
+}
+
+uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
+                      const char *sym_name, int *sym_size) {
+  ENTRY item;
+  ENTRY* ret = NULL;
+
+  // library does not have symbol table
+  if (!symtab || !symtab->hash_table)
+     return (uintptr_t)NULL;
+
+  item.key = (char*) strdup(sym_name);
+  hsearch_r(item, FIND, &ret, symtab->hash_table);
+  if (ret) {
+    struct elf_symbol * sym = (struct elf_symbol *)(ret->data);
+    uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
+    if (sym_size) *sym_size = sym->size;
+    free(item.key);
+    return rslt;
+  }
+
+quit:
+  free(item.key);
+  return (uintptr_t) NULL;
+}
+
+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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/symtab.h	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#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_*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/bsd/test.c	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#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;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.types.basic.*;
+
+public class BsdVtblAccess extends BasicVtblAccess {
+  private String vt;
+
+  public BsdVtblAccess(SymbolLookup symbolLookup,
+                         String[] dllNames) {
+    super(symbolLookup, dllNames);
+
+    if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null ||
+        symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) {
+       // old C++ ABI
+       vt = "__vt_";
+    } else {
+       // new C++ ABI
+       vt = "_ZTV";
+    }
+  }
+
+  protected String vtblSymbolForType(Type type) {
+    return vt + type.getName().length() + type;
+  }
+}
--- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java	Fri May 22 11:31:05 2009 -0400
+++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java	Fri May 29 08:22:42 2009 -0700
@@ -28,6 +28,7 @@
 import java.net.*;
 import java.rmi.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.bsd.*;
 import sun.jvm.hotspot.debugger.dbx.*;
 import sun.jvm.hotspot.debugger.proc.*;
 import sun.jvm.hotspot.debugger.remote.*;
@@ -337,6 +338,8 @@
                 setupDebuggerWin32();
             } else if (os.equals("linux")) {
                 setupDebuggerLinux();
+            } else if (os.equals("bsd")) {
+                setupDebuggerBsd();
             } else {
                 // Add support for more operating systems here
                 throw new DebuggerException("Operating system " + os + " not yet supported");
@@ -392,6 +395,10 @@
                 db = new HotSpotTypeDataBase(machDesc,
                 new LinuxVtblAccess(debugger, jvmLibNames),
                 debugger, jvmLibNames);
+            } else if (os.equals("bsd")) {
+                db = new HotSpotTypeDataBase(machDesc,
+                new BsdVtblAccess(debugger, jvmLibNames),
+                debugger, jvmLibNames);
             } else {
                 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)");
             }
@@ -557,6 +564,8 @@
             setupJVMLibNamesWin32();
         } else if (os.equals("linux")) {
             setupJVMLibNamesLinux();
+        } else if (os.equals("bsd")) {
+            setupJVMLibNamesBsd();
         } else {
             throw new RuntimeException("Unknown OS type");
         }
@@ -638,6 +647,31 @@
         jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
     }
 
+    //
+    // BSD
+    //
+
+    private void setupDebuggerBsd() {
+        setupJVMLibNamesBsd();
+
+        if (cpu.equals("x86")) {
+            machDesc = new MachineDescriptionIntelX86();
+        } else if (cpu.equals("amd64")) {
+            machDesc = new MachineDescriptionAMD64();
+        } else {
+            throw new DebuggerException("BSD only supported on x86/amd64");
+        }
+
+        BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer);
+        debugger = dbg;
+
+        attachDebugger();
+    }
+
+    private void setupJVMLibNamesBsd() {
+        jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
+    }
+
     /** Convenience routine which should be called by per-platform
       debugger setup. Should not be called when startupMode is
       REMOTE_MODE. */
--- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java	Fri May 22 11:31:05 2009 -0400
+++ b/agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java	Fri May 29 08:22:42 2009 -0700
@@ -29,6 +29,7 @@
 import java.rmi.*;
 import sun.jvm.hotspot.*;
 import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.bsd.*;
 import sun.jvm.hotspot.debugger.dbx.*;
 import sun.jvm.hotspot.debugger.proc.*;
 import sun.jvm.hotspot.debugger.cdbg.*;
@@ -516,6 +517,8 @@
                 setupDebuggerWin32();
             } else if (os.equals("linux")) {
                 setupDebuggerLinux();
+            } else if (os.equals("bsd")) {
+                setupDebuggerBsd();
             } else {
                 // Add support for more operating systems here
                 throw new DebuggerException("Operating system " + os + " not yet supported");
@@ -567,6 +570,9 @@
             } else if (os.equals("linux")) {
                 db = new HotSpotTypeDataBase(machDesc, new LinuxVtblAccess(debugger, jvmLibNames),
                 debugger, jvmLibNames);
+            } else if (os.equals("bsd")) {
+                db = new HotSpotTypeDataBase(machDesc, new BsdVtblAccess(debugger, jvmLibNames),
+                debugger, jvmLibNames);
             } else {
                 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess implemented yet)");
             }
@@ -739,6 +745,8 @@
             setupJVMLibNamesWin32();
         } else if (os.equals("linux")) {
             setupJVMLibNamesLinux();
+        } else if (os.equals("bsd")) {
+            setupJVMLibNamesBsd();
         } else {
             throw new RuntimeException("Unknown OS type");
         }
@@ -822,6 +830,34 @@
         setupJVMLibNamesSolaris();
     }
 
+    //
+    // BSD
+    //
+
+    private void setupDebuggerBsd() {
+        setupJVMLibNamesBsd();
+
+        if (cpu.equals("x86")) {
+            machDesc = new MachineDescriptionIntelX86();
+        } else if (cpu.equals("amd64")) {
+            machDesc = new MachineDescriptionAMD64();
+        } else {
+            throw new DebuggerException("Bsd only supported on x86/amd64");
+        }
+
+        // Note we do not use a cache for the local debugger in server
+        // mode; it will be taken care of on the client side (once remote
+        // debugging is implemented).
+
+        debugger = new BsdDebuggerLocal(machDesc, !isServer);
+        attachDebugger();
+    }
+
+    private void setupJVMLibNamesBsd() {
+        // same as solaris
+        setupJVMLibNamesSolaris();
+    }
+
     /** Convenience routine which should be called by per-platform
       debugger setup. Should not be called when startupMode is
       REMOTE_MODE. */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import sun.jvm.hotspot.debugger.*;
+
+class BsdAddress implements Address {
+    protected BsdDebugger debugger;
+    protected long addr;
+
+    BsdAddress(BsdDebugger debugger, long addr) {
+        this.debugger = debugger;
+        this.addr = addr;
+    }
+
+    //
+    // Basic Java routines
+    //
+
+    public boolean equals(Object arg) {
+        if (arg == null) {
+            return false;
+        }
+
+        if (!(arg instanceof BsdAddress)) {
+            return false;
+        }
+
+        return (addr == ((BsdAddress) arg).addr);
+    }
+
+    public int hashCode() {
+        // FIXME: suggestions on a better hash code?
+        return (int) addr;
+    }
+
+    public String toString() {
+        return debugger.addressValueToString(addr);
+    }
+
+    //
+    // C/C++-related routines
+    //
+
+    public long getCIntegerAt(long offset, long numBytes, boolean isUnsigned)
+            throws UnalignedAddressException, UnmappedAddressException {
+        return debugger.readCInteger(addr + offset, numBytes, isUnsigned);
+    }
+
+    public Address getAddressAt(long offset)
+            throws UnalignedAddressException, UnmappedAddressException {
+        return debugger.readAddress(addr + offset);
+    }
+
+    public Address getCompOopAddressAt(long offset)
+            throws UnalignedAddressException, UnmappedAddressException {
+        return debugger.readCompOopAddress(addr + offset);
+    }
+
+    //
+    // Java-related routines
+    //
+
+  public boolean getJBooleanAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJBoolean(addr + offset);
+  }
+
+  public byte getJByteAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJByte(addr + offset);
+  }
+
+  public char getJCharAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJChar(addr + offset);
+  }
+
+  public double getJDoubleAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJDouble(addr + offset);
+  }
+
+  public float getJFloatAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJFloat(addr + offset);
+  }
+
+  public int getJIntAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJInt(addr + offset);
+  }
+
+  public long getJLongAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJLong(addr + offset);
+  }
+
+  public short getJShortAt(long offset) throws UnalignedAddressException, UnmappedAddressException {
+    return debugger.readJShort(addr + offset);
+  }
+
+  public OopHandle getOopHandleAt(long offset)
+    throws UnalignedAddressException, UnmappedAddressException, NotInHeapException {
+    return debugger.readOopHandle(addr + offset);
+  }
+
+  public OopHandle getCompOopHandleAt(long offset)
+    throws UnalignedAddressException, UnmappedAddressException, NotInHeapException {
+    return debugger.readCompOopHandle(addr + offset);
+  }
+
+  // Mutators -- not implemented for now (FIXME)
+  public void setCIntegerAt(long offset, long numBytes, long value) {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void setAddressAt(long offset, Address value) {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJBooleanAt      (long offset, boolean value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJByteAt         (long offset, byte value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJCharAt         (long offset, char value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJDoubleAt       (long offset, double value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJFloatAt        (long offset, float value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJIntAt          (long offset, int value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJLongAt         (long offset, long value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setJShortAt        (long offset, short value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+  public void       setOopHandleAt     (long offset, OopHandle value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    throw new DebuggerException("Unimplemented");
+  }
+
+  //
+  // Arithmetic operations -- necessary evil.
+  //
+
+  public Address    addOffsetTo       (long offset) throws UnsupportedOperationException {
+    long value = addr + offset;
+    if (value == 0) {
+      return null;
+    }
+    return new BsdAddress(debugger, value);
+  }
+
+  public OopHandle  addOffsetToAsOopHandle(long offset) throws UnsupportedOperationException {
+    long value = addr + offset;
+    if (value == 0) {
+      return null;
+    }
+    return new BsdOopHandle(debugger, value);
+  }
+
+  /** (FIXME: any signed/unsigned issues? Should this work for
+      OopHandles?) */
+  public long       minus(Address arg) {
+    if (arg == null) {
+      return addr;
+    }
+    return addr - ((BsdAddress) arg).addr;
+  }
+
+  // Two's complement representation.
+  // All negative numbers are larger than positive numbers.
+  // Numbers with the same sign can be compared normally.
+  // Test harness is below in main().
+
+  public boolean    lessThan          (Address a) {
+    if (a == null) {
+      return false;
+    }
+    BsdAddress arg = (BsdAddress) a;
+    if ((addr >= 0) && (arg.addr < 0)) {
+      return true;
+    }
+    if ((addr < 0) && (arg.addr >= 0)) {
+      return false;
+    }
+    return (addr < arg.addr);
+  }
+
+  public boolean    lessThanOrEqual   (Address a) {
+    if (a == null) {
+      return false;
+    }
+    BsdAddress arg = (BsdAddress) a;
+    if ((addr >= 0) && (arg.addr < 0)) {
+      return true;
+    }
+    if ((addr < 0) && (arg.addr >= 0)) {
+      return false;
+    }
+    return (addr <= arg.addr);
+  }
+
+  public boolean    greaterThan       (Address a) {
+    if (a == null) {
+      return true;
+    }
+    BsdAddress arg = (BsdAddress) a;
+    if ((addr >= 0) && (arg.addr < 0)) {
+      return false;
+    }
+    if ((addr < 0) && (arg.addr >= 0)) {
+      return true;
+    }
+    return (addr > arg.addr);
+  }
+
+  public boolean    greaterThanOrEqual(Address a) {
+    if (a == null) {
+      return true;
+    }
+    BsdAddress arg = (BsdAddress) a;
+    if ((addr >= 0) && (arg.addr < 0)) {
+      return false;
+    }
+    if ((addr < 0) && (arg.addr >= 0)) {
+      return true;
+    }
+    return (addr >= arg.addr);
+  }
+
+  public Address    andWithMask(long mask) throws UnsupportedOperationException {
+    long value = addr & mask;
+    if (value == 0) {
+      return null;
+    }
+    return new BsdAddress(debugger, value);
+  }
+
+  public Address    orWithMask(long mask) throws UnsupportedOperationException {
+    long value = addr | mask;
+    if (value == 0) {
+      return null;
+    }
+    return new BsdAddress(debugger, value);
+  }
+
+  public Address    xorWithMask(long mask) throws UnsupportedOperationException {
+    long value = addr ^ mask;
+    if (value == 0) {
+      return null;
+    }
+    return new BsdAddress(debugger, value);
+  }
+
+
+  //--------------------------------------------------------------------------------
+  // Internals only below this point
+  //
+
+  long getValue() {
+    return addr;
+  }
+
+
+  private static void check(boolean arg, String failMessage) {
+    if (!arg) {
+      System.err.println(failMessage + ": FAILED");
+      System.exit(1);
+    }
+  }
+
+  // Test harness
+  public static void main(String[] args) {
+    // p/n indicates whether the interior address is really positive
+    // or negative. In unsigned terms, p1 < p2 < n1 < n2.
+
+    BsdAddress p1 = new BsdAddress(null, 0x7FFFFFFFFFFFFFF0L);
+    BsdAddress p2 = (BsdAddress) p1.addOffsetTo(10);
+    BsdAddress n1 = (BsdAddress) p2.addOffsetTo(10);
+    BsdAddress n2 = (BsdAddress) n1.addOffsetTo(10);
+
+    // lessThan positive tests
+    check(p1.lessThan(p2), "lessThan 1");
+    check(p1.lessThan(n1), "lessThan 2");
+    check(p1.lessThan(n2), "lessThan 3");
+    check(p2.lessThan(n1), "lessThan 4");
+    check(p2.lessThan(n2), "lessThan 5");
+    check(n1.lessThan(n2), "lessThan 6");
+
+    // lessThan negative tests
+    check(!p1.lessThan(p1), "lessThan 7");
+    check(!p2.lessThan(p2), "lessThan 8");
+    check(!n1.lessThan(n1), "lessThan 9");
+    check(!n2.lessThan(n2), "lessThan 10");
+
+    check(!p2.lessThan(p1), "lessThan 11");
+    check(!n1.lessThan(p1), "lessThan 12");
+    check(!n2.lessThan(p1), "lessThan 13");
+    check(!n1.lessThan(p2), "lessThan 14");
+    check(!n2.lessThan(p2), "lessThan 15");
+    check(!n2.lessThan(n1), "lessThan 16");
+
+    // lessThanOrEqual positive tests
+    check(p1.lessThanOrEqual(p1), "lessThanOrEqual 1");
+    check(p2.lessThanOrEqual(p2), "lessThanOrEqual 2");
+    check(n1.lessThanOrEqual(n1), "lessThanOrEqual 3");
+    check(n2.lessThanOrEqual(n2), "lessThanOrEqual 4");
+
+    check(p1.lessThanOrEqual(p2), "lessThanOrEqual 5");
+    check(p1.lessThanOrEqual(n1), "lessThanOrEqual 6");
+    check(p1.lessThanOrEqual(n2), "lessThanOrEqual 7");
+    check(p2.lessThanOrEqual(n1), "lessThanOrEqual 8");
+    check(p2.lessThanOrEqual(n2), "lessThanOrEqual 9");
+    check(n1.lessThanOrEqual(n2), "lessThanOrEqual 10");
+
+    // lessThanOrEqual negative tests
+    check(!p2.lessThanOrEqual(p1), "lessThanOrEqual 11");
+    check(!n1.lessThanOrEqual(p1), "lessThanOrEqual 12");
+    check(!n2.lessThanOrEqual(p1), "lessThanOrEqual 13");
+    check(!n1.lessThanOrEqual(p2), "lessThanOrEqual 14");
+    check(!n2.lessThanOrEqual(p2), "lessThanOrEqual 15");
+    check(!n2.lessThanOrEqual(n1), "lessThanOrEqual 16");
+
+    // greaterThan positive tests
+    check(n2.greaterThan(p1), "greaterThan 1");
+    check(n2.greaterThan(p2), "greaterThan 2");
+    check(n2.greaterThan(n1), "greaterThan 3");
+    check(n1.greaterThan(p1), "greaterThan 4");
+    check(n1.greaterThan(p2), "greaterThan 5");
+    check(p2.greaterThan(p1), "greaterThan 6");
+
+    // greaterThan negative tests
+    check(!p1.greaterThan(p1), "greaterThan 7");
+    check(!p2.greaterThan(p2), "greaterThan 8");
+    check(!n1.greaterThan(n1), "greaterThan 9");
+    check(!n2.greaterThan(n2), "greaterThan 10");
+
+    check(!p1.greaterThan(n2), "greaterThan 11");
+    check(!p2.greaterThan(n2), "greaterThan 12");
+    check(!n1.greaterThan(n2), "greaterThan 13");
+    check(!p1.greaterThan(n1), "greaterThan 14");
+    check(!p2.greaterThan(n1), "greaterThan 15");
+    check(!p1.greaterThan(p2), "greaterThan 16");
+
+    // greaterThanOrEqual positive tests
+    check(p1.greaterThanOrEqual(p1), "greaterThanOrEqual 1");
+    check(p2.greaterThanOrEqual(p2), "greaterThanOrEqual 2");
+    check(n1.greaterThanOrEqual(n1), "greaterThanOrEqual 3");
+    check(n2.greaterThanOrEqual(n2), "greaterThanOrEqual 4");
+
+    check(n2.greaterThanOrEqual(p1), "greaterThanOrEqual 5");
+    check(n2.greaterThanOrEqual(p2), "greaterThanOrEqual 6");
+    check(n2.greaterThanOrEqual(n1), "greaterThanOrEqual 7");
+    check(n1.greaterThanOrEqual(p1), "greaterThanOrEqual 8");
+    check(n1.greaterThanOrEqual(p2), "greaterThanOrEqual 9");
+    check(p2.greaterThanOrEqual(p1), "greaterThanOrEqual 10");
+
+    // greaterThanOrEqual negative tests
+    check(!p1.greaterThanOrEqual(n2), "greaterThanOrEqual 11");
+    check(!p2.greaterThanOrEqual(n2), "greaterThanOrEqual 12");
+    check(!n1.greaterThanOrEqual(n2), "greaterThanOrEqual 13");
+    check(!p1.greaterThanOrEqual(n1), "greaterThanOrEqual 14");
+    check(!p2.greaterThanOrEqual(n1), "greaterThanOrEqual 15");
+    check(!p1.greaterThanOrEqual(p2), "greaterThanOrEqual 16");
+
+    System.err.println("BsdAddress: all tests passed successfully.");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdCDebugger.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.x86.*;
+import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.bsd.x86.*;
+import sun.jvm.hotspot.debugger.bsd.amd64.*;
+import sun.jvm.hotspot.utilities.*;
+
+class BsdCDebugger implements CDebugger {
+  private BsdDebugger dbg;
+
+  BsdCDebugger(BsdDebugger dbg) {
+    this.dbg = dbg;
+  }
+
+  public List getThreadList() throws DebuggerException {
+    return dbg.getThreadList();
+  }
+
+  public List/*<LoadObject>*/ getLoadObjectList() throws DebuggerException {
+    return dbg.getLoadObjectList();
+  }
+
+  public LoadObject loadObjectContainingPC(Address pc) throws DebuggerException {
+    if (pc == null) {
+      return null;
+    }
+    List objs = getLoadObjectList();
+    Object[] arr = objs.toArray();
+    // load objects are sorted by base address, do binary search
+    int mid  = -1;
+    int low  = 0;
+    int high = arr.length - 1;
+
+    while (low <= high) {
+       mid = (low + high) >> 1;
+       LoadObject midVal = (LoadObject) arr[mid];
+       long cmp = pc.minus(midVal.getBase());
+       if (cmp < 0) {
+          high = mid - 1;
+       } else if (cmp > 0) {
+          long size = midVal.getSize();
+          if (cmp >= size) {
+             low = mid + 1;
+          } else {
+             return (LoadObject) arr[mid];
+          }
+       } else { // match found
+          return (LoadObject) arr[mid];
+       }
+    }
+    // no match found.
+    return null;
+  }
+
+  public CFrame topFrameForThread(ThreadProxy thread) throws DebuggerException {
+    String cpu = dbg.getCPU();
+    if (cpu.equals("x86")) {
+       X86ThreadContext context = (X86ThreadContext) thread.getContext();
+       Address ebp = context.getRegisterAsAddress(X86ThreadContext.EBP);
+       if (ebp == null) return null;
+       Address pc  = context.getRegisterAsAddress(X86ThreadContext.EIP);
+       if (pc == null) return null;
+       return new BsdX86CFrame(dbg, ebp, pc);
+    } else if (cpu.equals("amd64")) {
+       AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
+       Address rbp = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
+       if (rbp == null) return null;
+       Address pc  = context.getRegisterAsAddress(AMD64ThreadContext.RIP);
+       if (pc == null) return null;
+       return new BsdAMD64CFrame(dbg, rbp, pc);
+    } else {
+       throw new DebuggerException(cpu + " is not yet supported");
+    }
+  }
+
+  public String getNameOfFile(String fileName) {
+    return new File(fileName).getName();
+  }
+
+  public ProcessControl getProcessControl() throws DebuggerException {
+    // FIXME: after stabs parser
+    return null;
+  }
+
+  public boolean canDemangle() {
+    return false;
+  }
+
+  public String demangle(String sym) {
+    throw new UnsupportedOperationException();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import java.util.List;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+
+/** An extension of the JVMDebugger interface with a few additions to
+    support 32-bit vs. 64-bit debugging as well as features required
+    by the architecture-specific subpackages. */
+
+public interface BsdDebugger extends JVMDebugger {
+  public String       addressValueToString(long address) throws DebuggerException;
+  public boolean      readJBoolean(long address) throws DebuggerException;
+  public byte         readJByte(long address) throws DebuggerException;
+  public char         readJChar(long address) throws DebuggerException;
+  public double       readJDouble(long address) throws DebuggerException;
+  public float        readJFloat(long address) throws DebuggerException;
+  public int          readJInt(long address) throws DebuggerException;
+  public long         readJLong(long address) throws DebuggerException;
+  public short        readJShort(long address) throws DebuggerException;
+  public long         readCInteger(long address, long numBytes, boolean isUnsigned)
+    throws DebuggerException;
+  public BsdAddress readAddress(long address) throws DebuggerException;
+  public BsdAddress readCompOopAddress(long address) throws DebuggerException;
+  public BsdOopHandle readOopHandle(long address) throws DebuggerException;
+  public BsdOopHandle readCompOopHandle(long address) throws DebuggerException;
+  public long[]       getThreadIntegerRegisterSet(int lwp_id) throws DebuggerException;
+  public long         getAddressValue(Address addr) throws DebuggerException;
+  public Address      newAddress(long value) throws DebuggerException;
+
+  // For BsdCDebugger
+  public List         getThreadList();
+  public List         getLoadObjectList();
+  public ClosestSymbol lookup(long address);
+
+  // NOTE: this interface implicitly contains the following methods:
+  // From the Debugger interface via JVMDebugger
+  //   public void attach(int processID) throws DebuggerException;
+  //   public void attach(String executableName, String coreFileName) throws DebuggerException;
+  //   public boolean detach();
+  //   public Address parseAddress(String addressString) throws NumberFormatException;
+  //   public String getOS();
+  //   public String getCPU();
+  // From the SymbolLookup interface via Debugger and JVMDebugger
+  //   public Address lookup(String objectName, String symbol);
+  //   public OopHandle lookupOop(String objectName, String symbol);
+  // From the JVMDebugger interface
+  //   public void configureJavaPrimitiveTypeSizes(long jbooleanSize,
+  //                                               long jbyteSize,
+  //                                               long jcharSize,
+  //                                               long jdoubleSize,
+  //                                               long jfloatSize,
+  //                                               long jintSize,
+  //                                               long jlongSize,
+  //                                               long jshortSize);
+  // From the ThreadAccess interface via Debugger and JVMDebugger
+  //   public ThreadProxy getThreadForIdentifierAddress(Address addr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,595 @@
+/*
+ * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.x86.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.utilities.*;
+import java.lang.reflect.*;
+
+/** <P> An implementation of the JVMDebugger interface. The basic debug
+    facilities are implemented through ptrace interface in the JNI code
+    (libsaproc.so). Library maps and symbol table management are done in
+    JNI. </P>
+
+    <P> <B>NOTE</B> that since we have the notion of fetching "Java
+    primitive types" from the remote process (which might have
+    different sizes than we expect) we have a bootstrapping
+    problem. We need to know the sizes of these types before we can
+    fetch them. The current implementation solves this problem by
+    requiring that it be configured with these type sizes before they
+    can be fetched. The readJ(Type) routines here will throw a
+    RuntimeException if they are called before the debugger is
+    configured with the Java primitive type sizes. </P> */
+
+public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
+    private boolean useGCC32ABI;
+    private boolean attached;
+    private long    p_ps_prochandle; // native debugger handle
+    private boolean isCore;
+
+    // CDebugger support
+    private BsdCDebugger cdbg;
+
+    // threadList and loadObjectList are filled by attach0 method
+    private List threadList;
+    private List loadObjectList;
+
+    // called by native method lookupByAddress0
+    private ClosestSymbol createClosestSymbol(String name, long offset) {
+       return new ClosestSymbol(name, offset);
+    }
+
+    // called by native method attach0
+    private LoadObject createLoadObject(String fileName, long textsize,
+                                        long base) {
+       File f = new File(fileName);
+       Address baseAddr = newAddress(base);
+       return new SharedObject(this, fileName, f.length(), baseAddr);
+    }
+
+    // native methods
+
+    private native static void init0()
+                                throws DebuggerException;
+    private native void attach0(int pid)
+                                throws DebuggerException;
+    private native void attach0(String execName, String coreName)
+                                throws DebuggerException;
+    private native void detach0()
+                                throws DebuggerException;
+    private native long lookupByName0(String objectName, String symbol)
+                                throws DebuggerException;
+    private native ClosestSymbol lookupByAddress0(long address)
+                                throws DebuggerException;
+    private native long[] getThreadIntegerRegisterSet0(int lwp_id)
+                                throws DebuggerException;
+    private native byte[] readBytesFromProcess0(long address, long numBytes)
+                                throws DebuggerException;
+    public native static int  getAddressSize() ;
+
+    // Note on Bsd threads are really processes. When target process is
+    // attached by a serviceability agent thread, only that thread can do
+    // ptrace operations on the target. This is because from kernel's point
+    // view, other threads are just separate processes and they are not
+    // attached to the target. When they attempt to make ptrace calls,
+    // an ESRCH error will be returned as kernel believes target is not
+    // being traced by the caller.
+    // To work around the problem, we use a worker thread here to handle
+    // all JNI functions that are making ptrace calls.
+
+    interface WorkerThreadTask {
+       public void doit(BsdDebuggerLocal debugger) throws DebuggerException;
+    }
+
+    class BsdDebuggerLocalWorkerThread extends Thread {
+       BsdDebuggerLocal debugger;
+       WorkerThreadTask task;
+       DebuggerException lastException;
+
+       public BsdDebuggerLocalWorkerThread(BsdDebuggerLocal debugger) {
+         this.debugger = debugger;
+         setDaemon(true);
+       }
+
+       public void run() {
+          synchronized (workerThread) {
+             for (;;) {
+                if (task != null) {
+                   lastException = null;
+                   try {
+                      task.doit(debugger);
+                   } catch (DebuggerException exp) {
+                      lastException = exp;
+                   }
+                   task = null;
+                   workerThread.notifyAll();
+                }
+
+                try {
+                   workerThread.wait();
+                } catch (InterruptedException x) {}
+             }
+          }
+       }
+
+       public WorkerThreadTask execute(WorkerThreadTask task) throws DebuggerException {
+          synchronized (workerThread) {
+             this.task = task;
+             workerThread.notifyAll();
+             while (this.task != null) {
+                try {
+                   workerThread.wait();
+                } catch (InterruptedException x) {}
+             }
+             if (lastException != null) {
+                throw new DebuggerException(lastException);
+             } else {
+                return task;
+             }
+          }
+       }
+    }
+
+    private BsdDebuggerLocalWorkerThread workerThread = null;
+
+    //----------------------------------------------------------------------
+    // Implementation of Debugger interface
+    //
+
+    /** <P> machDesc may not be null. </P>
+
+    <P> useCache should be set to true if debugging is being done
+    locally, and to false if the debugger is being created for the
+    purpose of supporting remote debugging. </P> */
+    public BsdDebuggerLocal(MachineDescription machDesc,
+                              boolean useCache) throws DebuggerException {
+        this.machDesc = machDesc;
+        utils = new DebuggerUtilities(machDesc.getAddressSize(),
+                                      machDesc.isBigEndian()) {
+           public void checkAlignment(long address, long alignment) {
+             // Need to override default checkAlignment because we need to
+             // relax alignment constraints on Bsd/x86
+             if ( (address % alignment != 0)
+                &&(alignment != 8 || address % 4 != 0)) {
+                throw new UnalignedAddressException(
+                        "Trying to read at address: "
+                      + addressValueToString(address)
+                      + " with alignment: " + alignment,
+                        address);
+             }
+           }
+        };
+
+        if (useCache) {
+            // FIXME: re-test necessity of cache on Bsd, where data
+            // fetching is faster
+            // Cache portion of the remote process's address space.
+            // Fetching data over the socket connection to dbx is slow.
+            // Might be faster if we were using a binary protocol to talk to
+            // dbx, but would have to test. For now, this cache works best
+            // if it covers the entire heap of the remote process. FIXME: at
+            // least should make this tunable from the outside, i.e., via
+            // the UI. This is a cache of 4096 4K pages, or 16 MB. The page
+            // size must be adjusted to be the hardware's page size.
+            // (FIXME: should pick this up from the debugger.)
+            if (getCPU().equals("ia64")) {
+              initCache(16384, parseCacheNumPagesProperty(1024));
+            } else {
+              initCache(4096, parseCacheNumPagesProperty(4096));
+            }
+        }
+
+        workerThread = new BsdDebuggerLocalWorkerThread(this);
+        workerThread.start();
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public boolean hasProcessList() throws DebuggerException {
+        return false;
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public List getProcessList() throws DebuggerException {
+        throw new DebuggerException("getProcessList not implemented yet");
+    }
+
+    private void checkAttached() throws DebuggerException {
+        if (attached) {
+            if (isCore) {
+                throw new DebuggerException("attached to a core dump already");
+            } else {
+                throw new DebuggerException("attached to a process already");
+            }
+        }
+    }
+
+    private void requireAttach() {
+        if (! attached) {
+            throw new RuntimeException("not attached to a process or a core!");
+        }
+    }
+
+    /* called from attach methods */
+    private void findABIVersion() throws DebuggerException {
+        if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 ||
+            lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) {
+            // old C++ ABI
+            useGCC32ABI = false;
+        } else {
+            // new C++ ABI
+            useGCC32ABI = true;
+        }
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public synchronized void attach(int processID) throws DebuggerException {
+        checkAttached();
+        threadList = new ArrayList();
+        loadObjectList = new ArrayList();
+        class AttachTask implements WorkerThreadTask {
+           int pid;
+           public void doit(BsdDebuggerLocal debugger) {
+              debugger.attach0(pid);
+              debugger.attached = true;
+              debugger.isCore = false;
+              findABIVersion();
+           }
+        }
+
+        AttachTask task = new AttachTask();
+        task.pid = processID;
+        workerThread.execute(task);
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public synchronized void attach(String execName, String coreName) {
+        checkAttached();
+        threadList = new ArrayList();
+        loadObjectList = new ArrayList();
+        attach0(execName, coreName);
+        attached = true;
+        isCore = true;
+        findABIVersion();
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public synchronized boolean detach() {
+        if (!attached) {
+            return false;
+        }
+
+        threadList = null;
+        loadObjectList = null;
+
+        if (isCore) {
+            detach0();
+            attached = false;
+            return true;
+        } else {
+            class DetachTask implements WorkerThreadTask {
+                boolean result = false;
+
+                public void doit(BsdDebuggerLocal debugger) {
+                    debugger.detach0();
+                    debugger.attached = false;
+                    result = true;
+                }
+            }
+
+            DetachTask task = new DetachTask();
+            workerThread.execute(task);
+            return task.result;
+        }
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public Address parseAddress(String addressString)
+            throws NumberFormatException {
+        long addr = utils.scanAddress(addressString);
+        if (addr == 0) {
+            return null;
+        }
+        return new BsdAddress(this, addr);
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public String getOS() {
+        return PlatformInfo.getOS();
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public String getCPU() {
+        return PlatformInfo.getCPU();
+    }
+
+    public boolean hasConsole() throws DebuggerException {
+        return false;
+    }
+
+    public String consoleExecuteCommand(String cmd) throws DebuggerException {
+        throw new DebuggerException("No debugger console available on Bsd");
+    }
+
+    public String getConsolePrompt() throws DebuggerException {
+        return null;
+    }
+
+    /* called from lookup */
+    private long handleGCC32ABI(long addr, String symbol) throws DebuggerException {
+        if (useGCC32ABI && symbol.startsWith("_ZTV")) {
+            return addr + (2 * machDesc.getAddressSize());
+        } else {
+            return addr;
+        }
+    }
+
+    /** From the SymbolLookup interface via Debugger and JVMDebugger */
+    public synchronized Address lookup(String objectName, String symbol) {
+        requireAttach();
+        if (!attached) {
+            return null;
+        }
+
+        if (isCore) {
+            long addr = lookupByName0(objectName, symbol);
+            return (addr == 0)? null : new BsdAddress(this, handleGCC32ABI(addr, symbol));
+        } else {
+            class LookupByNameTask implements WorkerThreadTask {
+                String objectName, symbol;
+                Address result;
+
+                public void doit(BsdDebuggerLocal debugger) {
+                    long addr = debugger.lookupByName0(objectName, symbol);
+                    result = (addr == 0 ? null : new BsdAddress(debugger, handleGCC32ABI(addr, symbol)));
+                }
+            }
+
+            LookupByNameTask task = new LookupByNameTask();
+            task.objectName = objectName;
+            task.symbol = symbol;
+            workerThread.execute(task);
+            return task.result;
+        }
+    }
+
+    /** From the SymbolLookup interface via Debugger and JVMDebugger */
+    public synchronized OopHandle lookupOop(String objectName, String symbol) {
+        Address addr = lookup(objectName, symbol);
+        if (addr == null) {
+            return null;
+        }
+        return addr.addOffsetToAsOopHandle(0);
+    }
+
+    /** From the Debugger interface */
+    public MachineDescription getMachineDescription() {
+        return machDesc;
+    }
+
+    //----------------------------------------------------------------------
+    // Implementation of ThreadAccess interface
+    //
+
+    /** From the ThreadAccess interface via Debugger and JVMDebugger */
+    public ThreadProxy getThreadForIdentifierAddress(Address addr) {
+        return new BsdThread(this, addr);
+    }
+
+    /** From the ThreadAccess interface via Debugger and JVMDebugger */
+    public ThreadProxy getThreadForThreadId(long id) {
+        return new BsdThread(this, id);
+    }
+
+    //----------------------------------------------------------------------
+    // Internal routines (for implementation of BsdAddress).
+    // These must not be called until the MachineDescription has been set up.
+    //
+
+    /** From the BsdDebugger interface */
+    public String addressValueToString(long address) {
+        return utils.addressValueToString(address);
+    }
+
+    /** From the BsdDebugger interface */
+    public BsdAddress readAddress(long address)
+            throws UnmappedAddressException, UnalignedAddressException {
+        long value = readAddressValue(address);
+        return (value == 0 ? null : new BsdAddress(this, value));
+    }
+    public BsdAddress readCompOopAddress(long address)
+            throws UnmappedAddressException, UnalignedAddressException {
+        long value = readCompOopAddressValue(address);
+        return (value == 0 ? null : new BsdAddress(this, value));
+    }
+
+    /** From the BsdDebugger interface */
+    public BsdOopHandle readOopHandle(long address)
+            throws UnmappedAddressException, UnalignedAddressException,
+                NotInHeapException {
+        long value = readAddressValue(address);
+        return (value == 0 ? null : new BsdOopHandle(this, value));
+    }
+    public BsdOopHandle readCompOopHandle(long address)
+            throws UnmappedAddressException, UnalignedAddressException,
+                NotInHeapException {
+        long value = readCompOopAddressValue(address);
+        return (value == 0 ? null : new BsdOopHandle(this, value));
+    }
+
+    //----------------------------------------------------------------------
+    // Thread context access
+    //
+
+    public synchronized long[] getThreadIntegerRegisterSet(int lwp_id)
+                                            throws DebuggerException {
+        requireAttach();
+        if (isCore) {
+            return getThreadIntegerRegisterSet0(lwp_id);
+        } else {
+            class GetThreadIntegerRegisterSetTask implements WorkerThreadTask {
+                int lwp_id;
+                long[] result;
+                public void doit(BsdDebuggerLocal debugger) {
+                    result = debugger.getThreadIntegerRegisterSet0(lwp_id);
+                }
+            }
+
+            GetThreadIntegerRegisterSetTask task = new GetThreadIntegerRegisterSetTask();
+            task.lwp_id = lwp_id;
+            workerThread.execute(task);
+            return task.result;
+        }
+    }
+
+    /** Need to override this to relax alignment checks on x86. */
+    public long readCInteger(long address, long numBytes, boolean isUnsigned)
+        throws UnmappedAddressException, UnalignedAddressException {
+        // Only slightly relaxed semantics -- this is a hack, but is
+        // necessary on x86 where it seems the compiler is
+        // putting some global 64-bit data on 32-bit boundaries
+        if (numBytes == 8) {
+            utils.checkAlignment(address, 4);
+        } else {
+            utils.checkAlignment(address, numBytes);
+        }
+        byte[] data = readBytes(address, numBytes);
+        return utils.dataToCInteger(data, isUnsigned);
+    }
+
+    // Overridden from DebuggerBase because we need to relax alignment
+    // constraints on x86
+    public long readJLong(long address)
+        throws UnmappedAddressException, UnalignedAddressException {
+        utils.checkAlignment(address, jintSize);
+        byte[] data = readBytes(address, jlongSize);
+        return utils.dataToJLong(data, jlongSize);
+    }
+
+    //----------------------------------------------------------------------
+    // Address access. Can not be package private, but should only be
+    // accessed by the architecture-specific subpackages.
+
+    /** From the BsdDebugger interface */
+    public long getAddressValue(Address addr) {
+      if (addr == null) return 0;
+      return ((BsdAddress) addr).getValue();
+    }
+
+    /** From the BsdDebugger interface */
+    public Address newAddress(long value) {
+      if (value == 0) return null;
+      return new BsdAddress(this, value);
+    }
+
+    /** From the BsdCDebugger interface */
+    public List/*<ThreadProxy>*/ getThreadList() {
+      requireAttach();
+      return threadList;
+    }
+
+    /** From the BsdCDebugger interface */
+    public List/*<LoadObject>*/ getLoadObjectList() {
+      requireAttach();
+      return loadObjectList;
+    }
+
+    /** From the BsdCDebugger interface */
+    public synchronized ClosestSymbol lookup(long addr) {
+       requireAttach();
+       if (isCore) {
+          return lookupByAddress0(addr);
+       } else {
+          class LookupByAddressTask implements WorkerThreadTask {
+             long addr;
+             ClosestSymbol result;
+
+             public void doit(BsdDebuggerLocal debugger) {
+                 result = debugger.lookupByAddress0(addr);
+             }
+          }
+
+          LookupByAddressTask task = new LookupByAddressTask();
+          task.addr = addr;
+          workerThread.execute(task);
+          return task.result;
+       }
+    }
+
+    public CDebugger getCDebugger() {
+      if (cdbg == null) {
+         String cpu = getCPU();
+         if (cpu.equals("ia64") ) {
+            // IA-64 is not supported because of stack-walking issues
+            return null;
+         }
+         cdbg = new BsdCDebugger(this);
+      }
+      return cdbg;
+    }
+
+    /** This reads bytes from the remote process. */
+    public synchronized ReadResult readBytesFromProcess(long address,
+            long numBytes) throws UnmappedAddressException, DebuggerException {
+        requireAttach();
+        if (isCore) {
+            byte[] res = readBytesFromProcess0(address, numBytes);
+            return (res != null)? new ReadResult(res) : new ReadResult(address);
+        } else {
+            class ReadBytesFromProcessTask implements WorkerThreadTask {
+                long address, numBytes;
+                ReadResult result;
+                public void doit(BsdDebuggerLocal debugger) {
+                    byte[] res = debugger.readBytesFromProcess0(address, numBytes);
+                    if (res != null)
+                        result = new ReadResult(res);
+                    else
+                        result = new ReadResult(address);
+                }
+            }
+
+            ReadBytesFromProcessTask task = new ReadBytesFromProcessTask();
+            task.address = address;
+            task.numBytes = numBytes;
+            workerThread.execute(task);
+            return task.result;
+        }
+    }
+
+    public void writeBytesToProcess(long address, long numBytes, byte[] data)
+        throws UnmappedAddressException, DebuggerException {
+        // FIXME
+        throw new DebuggerException("Unimplemented");
+    }
+
+    static {
+        System.loadLibrary("saproc");
+        init0();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdOopHandle.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2002 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import sun.jvm.hotspot.debugger.*;
+
+class BsdOopHandle extends BsdAddress implements OopHandle {
+  BsdOopHandle(BsdDebugger debugger, long addr) {
+    super(debugger, addr);
+  }
+
+  public boolean equals(Object arg) {
+    if (arg == null) {
+      return false;
+    }
+
+    if (!(arg instanceof BsdOopHandle)) {
+      return false;
+    }
+
+    return (addr == ((BsdAddress) arg).addr);
+  }
+
+  public Address    addOffsetTo       (long offset) throws UnsupportedOperationException {
+    throw new UnsupportedOperationException("addOffsetTo not applicable to OopHandles (interior object pointers not allowed)");
+  }
+
+  public Address    andWithMask(long mask) throws UnsupportedOperationException {
+    throw new UnsupportedOperationException("andWithMask not applicable to OopHandles (i.e., anything but C addresses)");
+  }
+
+  public Address    orWithMask(long mask) throws UnsupportedOperationException {
+    throw new UnsupportedOperationException("orWithMask not applicable to OopHandles (i.e., anything but C addresses)");
+  }
+
+  public Address    xorWithMask(long mask) throws UnsupportedOperationException {
+    throw new UnsupportedOperationException("xorWithMask not applicable to OopHandles (i.e., anything but C addresses)");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import sun.jvm.hotspot.debugger.*;
+
+class BsdThread implements ThreadProxy {
+    private BsdDebugger debugger;
+    private int           lwp_id;
+
+    /** The address argument must be the address of the _thread_id in the
+        OSThread. It's value is result ::gettid() call. */
+    BsdThread(BsdDebugger debugger, Address addr) {
+        this.debugger = debugger;
+        // FIXME: size of data fetched here should be configurable.
+        // However, making it so would produce a dependency on the "types"
+        // package from the debugger package, which is not desired.
+        this.lwp_id = (int) addr.getCIntegerAt(0, 4, true);
+    }
+
+    BsdThread(BsdDebugger debugger, long id) {
+        this.debugger = debugger;
+        this.lwp_id = (int) id;
+    }
+
+    public boolean equals(Object obj) {
+        if ((obj == null) || !(obj instanceof BsdThread)) {
+            return false;
+        }
+
+        return (((BsdThread) obj).lwp_id == lwp_id);
+    }
+
+    public int hashCode() {
+        return lwp_id;
+    }
+
+    public String toString() {
+        return Integer.toString(lwp_id);
+    }
+
+    public ThreadContext getContext() throws IllegalThreadStateException {
+        long[] data = debugger.getThreadIntegerRegisterSet(lwp_id);
+        ThreadContext context = BsdThreadContextFactory.createThreadContext(debugger);
+        for (int i = 0; i < data.length; i++) {
+            context.setRegister(i, data[i]);
+        }
+        return context;
+    }
+
+    public boolean canSetContext() throws DebuggerException {
+        return false;
+    }
+
+    public void setContext(ThreadContext context)
+      throws IllegalThreadStateException, DebuggerException {
+        throw new DebuggerException("Unimplemented");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThreadContextFactory.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.bsd.amd64.*;
+import sun.jvm.hotspot.debugger.bsd.x86.*;
+
+class BsdThreadContextFactory {
+   static ThreadContext createThreadContext(BsdDebugger dbg) {
+      String cpu = dbg.getCPU();
+      if (cpu.equals("x86")) {
+         return new BsdX86ThreadContext(dbg);
+      } else if (cpu.equals("amd64")) {
+         return new BsdAMD64ThreadContext(dbg);
+      } else {
+         throw new RuntimeException("cpu " + cpu + " is not yet supported");
+      }
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.posix.*;
+
+/** A Object can represent either a .so or an a.out file. */
+
+class SharedObject extends DSO {
+  SharedObject(BsdDebugger dbg, String filename, long size, Address relocation) {
+    super(filename, size, relocation);
+    this.dbg     = dbg;
+  }
+
+  protected Address newAddress(long address) {
+    return dbg.newAddress(address);
+  }
+
+  protected long getAddressValue(Address addr) {
+    return dbg.getAddressValue(addr);
+  }
+
+  private BsdDebugger   dbg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64CFrame.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd.amd64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.bsd.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.cdbg.basic.*;
+
+final public class BsdAMD64CFrame extends BasicCFrame {
+   public BsdAMD64CFrame(BsdDebugger dbg, Address rbp, Address rip) {
+      super(dbg.getCDebugger());
+      this.rbp = rbp;
+      this.rip = rip;
+      this.dbg = dbg;
+   }
+
+   // override base class impl to avoid ELF parsing
+   public ClosestSymbol closestSymbolToPC() {
+      // try native lookup in debugger.
+      return dbg.lookup(dbg.getAddressValue(pc()));
+   }
+
+   public Address pc() {
+      return rip;
+   }
+
+   public Address localVariableBase() {
+      return rbp;
+   }
+
+   public CFrame sender() {
+      if (rbp == null) {
+        return null;
+      }
+
+      Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE);
+      if (nextRBP == null) {
+        return null;
+      }
+      Address nextPC  = rbp.getAddressAt( 1 * ADDRESS_SIZE);
+      if (nextPC == null) {
+        return null;
+      }
+      return new BsdAMD64CFrame(dbg, nextRBP, nextPC);
+   }
+
+   // package/class internals only
+   private static final int ADDRESS_SIZE = 8;
+   private Address rip;
+   private Address rbp;
+   private BsdDebugger dbg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64ThreadContext.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd.amd64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.bsd.*;
+
+public class BsdAMD64ThreadContext extends AMD64ThreadContext {
+  private BsdDebugger debugger;
+
+  public BsdAMD64ThreadContext(BsdDebugger debugger) {
+    super();
+    this.debugger = debugger;
+  }
+
+  public void setRegisterAsAddress(int index, Address value) {
+    setRegister(index, debugger.getAddressValue(value));
+  }
+
+  public Address getRegisterAsAddress(int index) {
+    return debugger.newAddress(getRegister(index));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86CFrame.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd.x86;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.bsd.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.cdbg.basic.*;
+
+final public class BsdX86CFrame extends BasicCFrame {
+   // package/class internals only
+   public BsdX86CFrame(BsdDebugger dbg, Address ebp, Address pc) {
+      super(dbg.getCDebugger());
+      this.ebp = ebp;
+      this.pc = pc;
+      this.dbg = dbg;
+   }
+
+   // override base class impl to avoid ELF parsing
+   public ClosestSymbol closestSymbolToPC() {
+      // try native lookup in debugger.
+      return dbg.lookup(dbg.getAddressValue(pc()));
+   }
+
+   public Address pc() {
+      return pc;
+   }
+
+   public Address localVariableBase() {
+      return ebp;
+   }
+
+   public CFrame sender() {
+      if (ebp == null) {
+        return null;
+      }
+
+      Address nextEBP = ebp.getAddressAt( 0 * ADDRESS_SIZE);
+      if (nextEBP == null) {
+        return null;
+      }
+      Address nextPC  = ebp.getAddressAt( 1 * ADDRESS_SIZE);
+      if (nextPC == null) {
+        return null;
+      }
+      return new BsdX86CFrame(dbg, nextEBP, nextPC);
+   }
+
+   private static final int ADDRESS_SIZE = 4;
+   private Address pc;
+   private Address ebp;
+   private BsdDebugger dbg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86ThreadContext.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.bsd.x86;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.x86.*;
+import sun.jvm.hotspot.debugger.bsd.*;
+
+public class BsdX86ThreadContext extends X86ThreadContext {
+  private BsdDebugger debugger;
+
+  public BsdX86ThreadContext(BsdDebugger debugger) {
+    super();
+    this.debugger = debugger;
+  }
+
+  public void setRegisterAsAddress(int index, Address value) {
+    setRegister(index, debugger.getAddressValue(value));
+  }
+
+  public Address getRegisterAsAddress(int index) {
+    return debugger.newAddress(getRegister(index));
+  }
+}
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Fri May 22 11:31:05 2009 -0400
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Fri May 29 08:22:42 2009 -0700
@@ -37,6 +37,8 @@
 import sun.jvm.hotspot.runtime.linux_ia64.LinuxIA64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess;
+import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess;
+import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess;
 import sun.jvm.hotspot.utilities.*;
 
 public class Threads {
@@ -90,7 +92,12 @@
             } else if (cpu.equals("sparc")) {
                 access = new LinuxSPARCJavaThreadPDAccess();
             }
-
+        } else if (os.equals("bsd")) {
+            if (cpu.equals("x86")) {
+                access = new BsdX86JavaThreadPDAccess();
+            } else if (cpu.equals("amd64")) {
+                access = new BsdAMD64JavaThreadPDAccess();
+            }
         }
 
         if (access == null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd/BsdSignals.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.bsd;
+
+public class BsdSignals {
+  private static String[] signalNames = {
+    "",           /* No signal 0 */
+    "SIGHUP",     /* hangup */
+    "SIGINT",     /* interrupt */
+    "SIGQUIT",    /* quit */
+    "SIGILL",     /* illegal instr. (not reset when caught) */
+    "SIGTRAP",    /* trace trap (not reset when caught) */
+    "SIGABRT",    /* abort() */
+    "SIGEMT",     /* EMT instruction */
+    "SIGFPE",     /* floating point exception */
+    "SIGKILL",    /* kill (cannot be caught or ignored) */
+    "SIGBUS",     /* bus error */
+    "SIGSEGV",    /* segmentation violation */
+    "SIGSYS",     /* non-existent system call invoked */
+    "SIGPIPE",    /* write on a pipe with no one to read it */
+    "SIGALRM",    /* alarm clock */
+    "SIGTERM",    /* software termination signal from kill */
+    "SIGURG",     /* urgent condition on IO channel */
+    "SIGSTOP",    /* sendable stop signal not from tty */
+    "SIGTSTP",    /* stop signal from tty */
+    "SIGCONT",    /* continue a stopped process */
+    "SIGCHLD",    /* to parent on child stop or exit */
+    "SIGTTIN",    /* to readers pgrp upon background tty read */
+    "SIGTTOU",    /* like TTIN if (tp->t_local&LTOSTOP) */
+    "SIGIO",      /* input/output possible signal */
+    "SIGXCPU",    /* exceeded CPU time limit */
+    "SIGXFSZ",    /* exceeded file size limit */
+    "SIGVTALRM",  /* virtual time alarm */
+    "SIGPROF",    /* profiling time alarm */
+    "SIGWINCH",   /* window size changes */
+    "SIGINFO",    /* information request */
+    "SIGUSR1",    /* user defined signal 1 */
+    "SIGUSR2"     /* user defined signal 2 */
+  };
+
+  public static String getSignalName(int sigNum) {
+    if ((sigNum <= 0) || (sigNum >= signalNames.length)) {
+      // Probably best to fail in a non-destructive way
+      return "<Error: Illegal signal number " + sigNum + ">";
+    }
+    return signalNames[sigNum];
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.bsd_amd64;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.amd64.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class BsdAMD64JavaThreadPDAccess implements JavaThreadPDAccess {
+  private static AddressField  lastJavaFPField;
+  private static AddressField  osThreadField;
+
+  // Field from OSThread
+  private static CIntegerField osThreadThreadIDField;
+
+  // This is currently unneeded but is being kept in case we change
+  // the currentFrameGuess algorithm
+  private static final long GUESS_SCAN_RANGE = 128 * 1024;
+
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+        public void update(Observable o, Object data) {
+          initialize(VM.getVM().getTypeDataBase());
+        }
+      });
+  }
+
+  private static synchronized void initialize(TypeDataBase db) {
+    Type type = db.lookupType("JavaThread");
+    osThreadField           = type.getAddressField("_osthread");
+
+    Type anchorType = db.lookupType("JavaFrameAnchor");
+    lastJavaFPField         = anchorType.getAddressField("_last_Java_fp");
+
+    Type osThreadType = db.lookupType("OSThread");
+    osThreadThreadIDField   = osThreadType.getCIntegerField("_thread_id");
+  }
+
+  public    Address getLastJavaFP(Address addr) {
+    return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset()));
+  }
+
+  public    Address getLastJavaPC(Address addr) {
+    return null;
+  }
+
+  public    Address getBaseOfStackPointer(Address addr) {
+    return null;
+  }
+
+  public    Frame getLastFramePD(JavaThread thread, Address addr) {
+    Address fp = thread.getLastJavaFP();
+    if (fp == null) {
+      return null; // no information
+    }
+    return new AMD64Frame(thread.getLastJavaSP(), fp);
+  }
+
+  public    RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
+    return new AMD64RegisterMap(thread, updateMap);
+  }
+
+  public    Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    AMD64ThreadContext context = (AMD64ThreadContext) t.getContext();
+    AMD64CurrentFrameGuess guesser = new AMD64CurrentFrameGuess(context, thread);
+    if (!guesser.run(GUESS_SCAN_RANGE)) {
+      return null;
+    }
+    if (guesser.getPC() == null) {
+      return new AMD64Frame(guesser.getSP(), guesser.getFP());
+    } else {
+      return new AMD64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+    }
+  }
+
+  public    void printThreadIDOn(Address addr, PrintStream tty) {
+    tty.print(getThreadProxy(addr));
+  }
+
+  public    void printInfoOn(Address threadAddr, PrintStream tty) {
+    tty.print("Thread id: ");
+    printThreadIDOn(threadAddr, tty);
+//    tty.println("\nPostJavaState: " + getPostJavaState(threadAddr));
+  }
+
+  public    Address getLastSP(Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    AMD64ThreadContext context = (AMD64ThreadContext) t.getContext();
+    return context.getRegisterAsAddress(AMD64ThreadContext.RSP);
+  }
+
+  public    ThreadProxy getThreadProxy(Address addr) {
+    // Addr is the address of the JavaThread.
+    // Fetch the OSThread (for now and for simplicity, not making a
+    // separate "OSThread" class in this package)
+    Address osThreadAddr = osThreadField.getValue(addr);
+    // Get the address of the _thread_id from the OSThread
+    Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+
+    JVMDebugger debugger = VM.getVM().getDebugger();
+    return debugger.getThreadForIdentifierAddress(threadIdAddr);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdSignals.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2002 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.bsd_x86;
+
+public class BsdSignals {
+  private static String[] signalNames = {
+    "",           /* No signal 0 */
+    "SIGHUP",     /* hangup */
+    "SIGINT",     /* interrupt */
+    "SIGQUIT",    /* quit */
+    "SIGILL",     /* illegal instr. (not reset when caught) */
+    "SIGTRAP",    /* trace trap (not reset when caught) */
+    "SIGABRT",    /* abort() */
+    "SIGEMT",     /* EMT instruction */
+    "SIGFPE",     /* floating point exception */
+    "SIGKILL",    /* kill (cannot be caught or ignored) */
+    "SIGBUS",     /* bus error */
+    "SIGSEGV",    /* segmentation violation */
+    "SIGSYS",     /* non-existent system call invoked */
+    "SIGPIPE",    /* write on a pipe with no one to read it */
+    "SIGALRM",    /* alarm clock */
+    "SIGTERM",    /* software termination signal from kill */
+    "SIGURG",     /* urgent condition on IO channel */
+    "SIGSTOP",    /* sendable stop signal not from tty */
+    "SIGTSTP",    /* stop signal from tty */
+    "SIGCONT",    /* continue a stopped process */
+    "SIGCHLD",    /* to parent on child stop or exit */
+    "SIGTTIN",    /* to readers pgrp upon background tty read */
+    "SIGTTOU",    /* like TTIN if (tp->t_local&LTOSTOP) */
+    "SIGIO",      /* input/output possible signal */
+    "SIGXCPU",    /* exceeded CPU time limit */
+    "SIGXFSZ",    /* exceeded file size limit */
+    "SIGVTALRM",  /* virtual time alarm */
+    "SIGPROF",    /* profiling time alarm */
+    "SIGWINCH",   /* window size changes */
+    "SIGINFO",    /* information request */
+    "SIGUSR1",    /* user defined signal 1 */
+    "SIGUSR2"     /* user defined signal 2 */
+  };
+
+  public static String getSignalName(int sigNum) {
+    if ((sigNum <= 0) || (sigNum >= signalNames.length)) {
+      // Probably best to fail in a non-destructive way
+      return "<Error: Illegal signal number " + sigNum + ">";
+    }
+    return signalNames[sigNum];
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdX86JavaThreadPDAccess.java	Fri May 29 08:22:42 2009 -0700
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.bsd_x86;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.x86.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.x86.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class BsdX86JavaThreadPDAccess implements JavaThreadPDAccess {
+  private static AddressField  lastJavaFPField;
+  private static AddressField  osThreadField;
+
+  // Field from OSThread
+  private static CIntegerField osThreadThreadIDField;
+
+  // This is currently unneeded but is being kept in case we change
+  // the currentFrameGuess algorithm
+  private static final long GUESS_SCAN_RANGE = 128 * 1024;
+
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+        public void update(Observable o, Object data) {
+          initialize(VM.getVM().getTypeDataBase());
+        }
+      });
+  }
+
+  private static synchronized void initialize(TypeDataBase db) {
+    Type type = db.lookupType("JavaThread");
+    osThreadField           = type.getAddressField("_osthread");
+
+    Type anchorType = db.lookupType("JavaFrameAnchor");
+    lastJavaFPField         = anchorType.getAddressField("_last_Java_fp");
+
+    Type osThreadType = db.lookupType("OSThread");
+    osThreadThreadIDField   = osThreadType.getCIntegerField("_thread_id");
+  }
+
+  public    Address getLastJavaFP(Address addr) {
+    return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset()));
+  }
+
+  public    Address getLastJavaPC(Address addr) {
+    return null;
+  }
+
+  public    Address getBaseOfStackPointer(Address addr) {
+    return null;
+  }
+
+  public    Frame getLastFramePD(JavaThread thread, Address addr) {
+    Address fp = thread.getLastJavaFP();
+    if (fp == null) {
+      return null; // no information
+    }
+    return new X86Frame(thread.getLastJavaSP(), fp);
+  }
+
+  public    RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
+    return new X86RegisterMap(thread, updateMap);
+  }
+
+  public    Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    X86ThreadContext context = (X86ThreadContext) t.getContext();
+    X86CurrentFrameGuess guesser = new X86CurrentFrameGuess(context, thread);
+    if (!guesser.run(GUESS_SCAN_RANGE)) {
+      return null;
+    }
+    if (guesser.getPC() == null) {
+      return new X86Frame(guesser.getSP(), guesser.getFP());
+    } else {
+      return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+    }
+  }
+
+  public    void printThreadIDOn(Address addr, PrintStream tty) {
+    tty.print(getThreadProxy(addr));
+  }
+
+  public    void printInfoOn(Address threadAddr, PrintStream tty) {
+    tty.print("Thread id: ");
+    printThreadIDOn(threadAddr, tty);
+//    tty.println("\nPostJavaState: " + getPostJavaState(threadAddr));
+  }
+
+  public    Address getLastSP(Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    X86ThreadContext context = (X86ThreadContext) t.getContext();
+    return context.getRegisterAsAddress(X86ThreadContext.ESP);
+  }
+
+  public    ThreadProxy getThreadProxy(Address addr) {
+    // Addr is the address of the JavaThread.
+    // Fetch the OSThread (for now and for simplicity, not making a
+    // separate "OSThread" class in this package)
+    Address osThreadAddr = osThreadField.getValue(addr);
+    // Get the address of the _thread_id from the OSThread
+    Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+
+    JVMDebugger debugger = VM.getVM().getDebugger();
+    return debugger.getThreadForIdentifierAddress(threadIdAddr);
+  }
+}
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java	Fri May 22 11:31:05 2009 -0400
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java	Fri May 29 08:22:42 2009 -0700
@@ -37,6 +37,14 @@
       return "solaris";
     } else if (os.equals("Linux")) {
       return "linux";
+    } else if (os.equals("FreeBSD")) {
+      return "bsd";
+    } else if (os.equals("NetBSD")) {
+      return "bsd";
+    } else if (os.equals("OpenBSD")) {
+      return "bsd";
+    } else if (os.equals("Darwin")) {
+      return "bsd";
     } else if (os.startsWith("Windows")) {
       return "win32";
     } else {
--- a/make/bsd/makefiles/defs.make	Fri May 22 11:31:05 2009 -0400
+++ b/make/bsd/makefiles/defs.make	Fri May 29 08:22:42 2009 -0700
@@ -121,3 +121,5 @@
   EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjsig.$(LIBRARY_SUFFIX)
   EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm.$(LIBRARY_SUFFIX)
 endif
+EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.so
+EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar
--- a/make/bsd/makefiles/saproc.make	Fri May 22 11:31:05 2009 -0400
+++ b/make/bsd/makefiles/saproc.make	Fri May 29 08:22:42 2009 -0700
@@ -42,17 +42,18 @@
              $(SASRCDIR)/libproc_impl.c               \
              $(SASRCDIR)/ps_proc.c                    \
              $(SASRCDIR)/ps_core.c                    \
+             $(SASRCDIR)/hsearch_r.c                  \
              $(SASRCDIR)/BsdDebuggerLocal.c
 
 SAMAPFILE = $(SASRCDIR)/mapfile
 
 DEST_SAPROC = $(JDK_LIBDIR)/$(LIBSAPROC)
 
-# if $(SASRCDIR) does not exist, we don't build SA
+# if $(AGENT_DIR) does not exist, we don't build SA
 # also, we don't build SA on Itanium.
 
 checkAndBuildSA:
-	$(QUIETLY) if [ -d $(SASRCDIR) -a "$(SRCARCH)" != "ia64" ] ; then \
+	$(QUIETLY) if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" ] ; then \
 	   $(MAKE) -f vm.make $(LIBSAPROC); \
 	fi
 
@@ -69,10 +70,11 @@
 	           -I$(SASRCDIR)                                        \
 	           -I$(GENERATED)                                       \
 	           -I$(BOOT_JAVA_HOME)/include                          \
-	           -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family)    \
+	           -I$(BOOT_JAVA_HOME)/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") \
 	           $(SASRCFILES)                                        \
 	           $(SA_LFLAGS)                                         \
 	           -o $@                                                \
+	           -lutil                                               \
 	           -lthread_db
 
 install_saproc: checkAndBuildSA
--- a/make/sa.files	Fri May 22 11:31:05 2009 -0400
+++ b/make/sa.files	Fri May 29 08:22:42 2009 -0700
@@ -50,6 +50,9 @@
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/compiler/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/x86/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
@@ -95,6 +98,9 @@
 AGENT_FILES2 = \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd_amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd_x86/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ia64/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux/*.java \
 $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_amd64/*.java \