Philipp Tomsich
Christian Thalinger
- $Id: cacao.c 4630 2006-03-16 14:00:48Z twisti $
+ $Id: cacao.c 4661 2006-03-21 00:04:59Z motse $
*/
#if defined(ENABLE_JVMTI)
#include "native/jvmti/jvmti.h"
-#include "native/jvmti/dbg.h"
-#include <sys/types.h>
-#include <signal.h>
-#include <sys/wait.h>
+#include "native/jvmti/cacaodbg.h"
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+#include <pthread.h>
+#endif
#endif
#include "toolbox/logging.h"
#include "vm/jit/verify/typeinfo.h"
#endif
-
#ifdef TYPECHECK_STATISTICS
void typecheck_print_statistics(FILE *file);
#endif
-/* setup_debugger_process *****************************************************
-
- Helper function to start JDWP threads
-
-*******************************************************************************/
-#if defined(ENABLE_JVMTI)
-
-static void setup_debugger_process(char* transport) {
- java_objectheader *o;
- methodinfo *m;
- java_lang_String *s;
-
- /* new gnu.classpath.jdwp.Jdwp() */
- mainclass =
- load_class_from_sysloader(utf_new_char("gnu.classpath.jdwp.Jdwp"));
- if (!mainclass)
- throw_main_exception_exit();
-
- o = builtin_new(mainclass);
-
- if (!o)
- throw_main_exception_exit();
-
- m = class_resolveclassmethod(mainclass,
- utf_init,
- utf_java_lang_String__void,
- class_java_lang_Object,
- true);
- if (!m)
- throw_main_exception_exit();
-
- (void) vm_call_method(m, o);
-
- /* configure(transport,NULL) */
- m = class_resolveclassmethod(
- mainclass, utf_new_char("configure"),
- utf_new_char("(Ljava/lang/String;Ljava/lang/Thread;)V"),
- class_java_lang_Object,
- false);
-
-
- s = javastring_new_char(transport);
-
- (void) vm_call_method(m, o, s);
-
- if (!m)
- throw_main_exception_exit();
-
- /* _doInitialization */
- m = class_resolveclassmethod(mainclass,
- utf_new_char("_doInitialization"),
- utf_new_char("()V"),
- mainclass,
- false);
-
- if (!m)
- throw_main_exception_exit();
-
- (void) vm_call_method(m, o);
-}
-#endif
-
-
/* getmainclassfromjar *********************************************************
Gets the name of the main class form a JAR's manifest file.
return javastring_tochar(o);
}
-
void exit_handler(void);
int main(int argc, char **argv)
{
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
void *dummy;
+#endif
s4 i;
/* local variables ********************************************************/
JavaVMInitArgs *vm_args;
JavaVM *jvm; /* denotes a Java VM */
-#if defined(ENABLE_JVMTI)
- bool dbg = false;
- char *transport;
- int waitval;
+
+#if defined(NDEBUG)
+ /* motse: for jdwp/jvmti debugging*/
+ for (i=0; i<argc; i++)
+ fprintf(stderr,"argument string[%d]: %s\n",i,argv[i]);
#endif
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
JNI_CreateJavaVM(&jvm, (void **) &_Jv_env, vm_args);
#if defined(ENABLE_JVMTI)
- set_jvmti_phase(JVMTI_PHASE_START);
+ if (dbgprocess && jvmti && jdwp) /* is this the parent/debugger process ? */
+ set_jvmti_phase(JVMTI_PHASE_START);
#endif
/* do we have a main class? */
#endif
/*class_showmethods(currentThread->group->header.vftbl->class); */
-#if defined(ENABLE_JVMTI) && defined(NATIVE_THREADS)
- if(dbg) {
- debuggee = fork();
- if (debuggee == (-1)) {
- log_text("fork error");
- exit(1);
- } else {
- if (debuggee == 0) {
- /* child: allow helper process to trace us */
- if (TRACEME != 0) exit(0);
-
- /* give parent/helper debugger process control */
- kill(0, SIGTRAP); /* do we need this at this stage ? */
-
- /* continue with normal startup */
-
- } else {
-
- /* parent/helper debugger process */
- wait(&waitval);
-
- remotedbgjvmtienv = new_jvmtienv();
- /* set eventcallbacks */
- if (JVMTI_ERROR_NONE ==
- remotedbgjvmtienv->
- SetEventCallbacks(remotedbgjvmtienv,
- &jvmti_jdwp_EventCallbacks,
- sizeof(jvmti_jdwp_EventCallbacks))){
- log_text("unable to setup event callbacks");
- vm_exit(1);
- }
-
- /* setup listening process (JDWP) */
- setup_debugger_process(transport);
- /* start to be debugged program */
- CONT(debuggee);
- /* exit debugger process - todo: cleanup */
- joinAllThreads();
- cacao_exit(0);
- }
- }
+#if defined(ENABLE_JVMTI)
+ /* if this is the parent process than start the jdwp listening */
+ if (jvmti || jdwp) {
+ fprintf(stderr, "jdwp/debugger set herewego brkpt %p\n",&&herewego);
+ setsysbrkpt(HEREWEGOBRK,&&herewego);
+ if (dbgprocess && jdwp) cacaodbglisten(transport);
}
- else
- debuggee= -1;
+
+ if (!dbgprocess) {
+ fprintf(stderr,"debuggee: herewe go\n");
+ fflush(stderr);
+ }
#endif
/* here we go... */
-
+ herewego:
(void) vm_call_method(m, NULL, oa);
/* exception occurred? */
Changes: Christian Thalinger
- $Id: jni.h 4565 2006-03-07 09:40:37Z twisti $
+ $Id: jni.h 4661 2006-03-21 00:04:59Z motse $
*/
java_objectheader *_Jv_jni_invokeNative(methodinfo *m, java_objectheader *o,
java_objectarray *params);
-extern void* ptr_env;
-extern struct JNINativeInterface JNI_JNIEnvTable;
-
#endif /* _JNI_H */
##
## Changes:
##
-## $Id: Makefile.am 4357 2006-01-22 23:33:38Z twisti $
+## $Id: Makefile.am 4661 2006-03-21 00:04:59Z motse $
## Process this file with automake to produce Makefile.in
jvmti.c \
jvmti.h \
VMjdwp.c \
- dbg.h
+ dbg.h\
+ dbg.c\
+ cacaodbg.h \
+ cacaodbg.c \
+ cacaodbgserver.c \
+ cacaodbgserver.h
+
## Local variables:
Changes:
- $Id: VMjdwp.c 4357 2006-01-22 23:33:38Z twisti $
+ $Id: VMjdwp.c 4661 2006-03-21 00:04:59Z motse $
*/
-#include "jvmti.h"
+#include "native/jvmti/jvmti.h"
+#include "native/jvmti/cacaodbg.h"
#include "vm/loader.h"
#include "vm/exceptions.h"
#include "vm/jit/asmpart.h"
-static jmethodID notifymid = NULL;
-static jclass Jdwpclass = NULL;
+#include <stdlib.h>
+
+
+static methodinfo *notifymid = NULL;
+static classinfo *Jdwpclass = NULL;
+
+
+#define FINDCLASS(jni_env,class,classname) \
+ class = load_class_from_sysloader(utf_new_char(classname)); \
+ if (!class) throw_main_exception_exit();
+
+
+#define GETJNIMETHOD(jni_env,class,classname,method,methodname,methodsig) \
+ FINDCLASS(jni_env,class,classname) \
+ method = class_resolveclassmethod (class,utf_new_char(methodname), \
+ utf_new_char(methodsig), \
+ class_java_lang_Object,true); \
+ if (!method) throw_main_exception_exit();
+
+#define GETJNISTATICMETHOD(jni_env,class,classname,method,methodname,methodsig) \
+ FINDCLASS(jni_env,class,classname) \
+ method = class_resolveclassmethod (class,utf_new_char(methodname), \
+ utf_new_char(methodsig), \
+ class_java_lang_Object,true); \
+ if (!method) throw_main_exception_exit();
+
+
+static void notify (JNIEnv* env, jobject event){
+ log_text("VMjdwp notfiy called");
-void notify (jobject event){
- methodinfo *m;
if (notifymid == NULL) {
- Jdwpclass =
- load_class_from_sysloader(utf_new_char("gnu.classpath.jdwp.Jdwp"));
- if (!Jdwpclass)
- throw_main_exception_exit();
-
- notifymid = class_resolveclassmethod(
- Jdwpclass,
- utf_new_char("notify"),
- utf_new_char("(Lgnu.classpath.jdwp.event.Event;)V"),
- class_java_lang_Object,
- true);
-
- if (!notifymid)
- throw_main_exception_exit();
+ GETJNISTATICMETHOD(env,Jdwpclass,"gnu/classpath/jdwp/Jdwp",notifymid,
+ "notify","(Lgnu/classpath/jdwp/event/Event;)V");
+
}
- asm_calljavafunction(m, Jdwpclass, event, NULL, NULL);
+ vm_call_method(notifymid, NULL ,event);
+ if (*exceptionptr)
+ throw_main_exception_exit();
+
}
static void ThreadStart (jvmtiEnv *jvmti_env,
JNIEnv* jni_env,
jthread thread){
- log_text ("JVMTI-Event: IMPLEMENT ME!!!");
+ jclass cl;
+ jmethodID cc;
+ jobject obj;
+
+ GETJNIMETHOD(jni_env,cl,"gnu/classpath/jdwp/event/ThreadStartEvent",cc,"<init>","(Ljava/lang/Thread;)V");
+
+ obj = builtin_new(cl);
+ if (!obj) throw_main_exception_exit();
+
+ fprintf(stderr,"VMjdwp:ThreadStart: thread %p\n",thread);
+ fflush(stderr);
+
+ vm_call_method((methodinfo*)cc, obj, thread);
+
+ if (*exceptionptr)
+ throw_main_exception_exit();
+
+ notify (jni_env,obj);
}
static void ThreadEnd (jvmtiEnv *jvmti_env,
static void VMStart (jvmtiEnv *jvmti_env,
JNIEnv* jni_env) {
- log_text ("JVMTI-Event: IMPLEMENT ME!!!");
+ log_text ("JVMTI-Event:VMStart IMPLEMENT ME!!!");
}
static void VMInit (jvmtiEnv *jvmti_env,
JNIEnv* jni_env,
jthread thread) {
- log_text ("JVMTI-Event: IMPLEMENT ME!!!");
+ classinfo* cl;
+ methodinfo* cc;
+ java_objectheader* obj;
+
+ log_text ("JVMTI-Event:VMInit");
+
+ GETJNIMETHOD(jni_env,cl,"gnu/classpath/jdwp/event/VmInitEvent",cc,"<init>",
+ "(Ljava/lang/Thread;)V");
+
+ fprintf(stderr,"VMjdwp:VMInit: 1\n");
+
+ obj = builtin_new(cl);
+ if (!obj) throw_main_exception_exit();
+
+ fprintf(stderr,"VMjdwp:VMInit: thread %p\n",thread);
+ fflush(stderr);
+
+ vm_call_method((methodinfo*)cc, obj, thread);
+
+ if (*exceptionptr)
+ throw_main_exception_exit();
+
+ notify (jni_env,obj);
}
static void VMDeath (jvmtiEnv *jvmti_env,
}
-jvmtiEventCallbacks jvmti_jdwp_EventCallbacks = {
+bool VMjdwpInit(jvmtiEnv* env) {
+ int end, i=0;
+ jvmtiCapabilities cap;
+ jvmtiError e;
+
+
+ /* set eventcallbacks */
+ if (JVMTI_ERROR_NONE !=
+ (*env)->SetEventCallbacks(env,
+ &jvmti_jdwp_EventCallbacks,
+ sizeof(jvmti_jdwp_EventCallbacks))){
+ log_text("unable to setup event callbacks");
+ return false;
+ }
+
+ e = (*env)->GetPotentialCapabilities(env, &cap);
+ if (e == JVMTI_ERROR_NONE) {
+ e = (*env)->AddCapabilities(env, &cap);
+ }
+ if (e != JVMTI_ERROR_NONE) {
+ log_text("error adding jvmti capabilities");
+ exit(1);
+ }
+
+ end = sizeof(jvmti_jdwp_EventCallbacks) / sizeof(void*);
+ for (i = 0; i < end; i++) {
+ /* enable standard VM callbacks */
+ if (((void**)&jvmti_jdwp_EventCallbacks)[i] != NULL) {
+ e = (*env)->SetEventNotificationMode(env,
+ JVMTI_ENABLE,
+ JVMTI_EVENT_START_ENUM+i,
+ NULL);
+
+ if (JVMTI_ERROR_NONE != e) {
+ log_text("unable to setup event notification mode");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+ jvmtiEventCallbacks jvmti_jdwp_EventCallbacks = {
&VMInit,
&VMDeath,
&ThreadStart,
&ClassFileLoadHook,
&ClassLoad,
&ClassPrepare,
- &VMStart,
+ NULL, /* &VMStart */
&Exception,
&ExceptionCatch,
&SingleStep,
--- /dev/null
+/* src/native/jvmti/cacaodbg.c - contains entry points for debugging support
+ in cacao.
+
+ Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Martin Platter
+
+ Changes:
+
+
+ $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $
+
+*/
+
+#include "native/jvmti/jvmti.h"
+#include "native/jvmti/cacaodbg.h"
+#include "native/jvmti/cacaodbgserver.h"
+#include "native/jvmti/dbg.h"
+#include "vm/vm.h"
+#include "vm/loader.h"
+#include "vm/exceptions.h"
+#include "vm/builtin.h"
+#include "vm/jit/asmpart.h"
+#include "vm/stringlocal.h"
+#include "toolbox/logging.h"
+#include "threads/native/threads.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <semaphore.h>
+#include <sys/msg.h>
+#include <linux/user.h>
+#include <assert.h>
+
+/* count the request for workingdatalock */
+static int workingdatanum = 0;
+
+
+/* msgqsendevent ***************************************************************
+
+ sends a ptrace request to the cacaodbgserver process through the message
+ queue
+
+*******************************************************************************/
+
+static void msgqsendevent(ptrace_request *pt, ptrace_reply** rcvbuf, int buflen) {
+ int size;
+
+ pt->mtype = MSGQPTRACESND;
+
+ fprintf(stderr,"msgqsendevent send new message (kind %d)\n",pt->kind);
+ if (-1 == msgsnd(msgqid, pt, sizeof(ptrace_request), 0))
+ perror("debugger process: msgqsendevent send error: ");
+
+ size = sizeof(ptrace_reply)+buflen;
+ *rcvbuf =(ptrace_reply*) heap_allocate(size,true,NULL);
+
+ if (-1 == msgrcv(msgqid, *rcvbuf, size, MSGQPTRACERCV, 0))
+ perror("debugger process: msgqsendevent receive error: ");
+ fprintf(stderr,"msgqsendevent reply received(kind %d)\n",pt->kind);
+}
+
+
+/* getworkingdatalock *********************************************************
+
+ blocks until the workingdata lock has been obtained
+
+*******************************************************************************/
+
+void getworkingdatalock() {
+ workingdatanum++;
+ if (workingdatanum==1) sem_wait(&workingdata_lock);
+}
+
+/* releaseworkingdatalock *********************************************************
+
+ release workingdata lock
+
+*******************************************************************************/
+
+void releaseworkingdatalock() {
+ workingdatanum--;
+ assert(workingdatanum>=0);
+ if (workingdatanum==0) sem_post(&workingdata_lock);
+}
+
+/* getchildproc ***************************************************************
+
+ Get data count number of bytes from address addr for child process address
+ space. After a successfull call *ptr points to a newly created array
+ containing the requested data.
+
+*******************************************************************************/
+
+void getchildproc (char **ptr, void* addr, int count) {
+ ptrace_request pt;
+ ptrace_reply *rcvbuf;
+
+ stopdebuggee();
+
+ pt.kind = PTPEEKDATA;
+ pt.addr = addr;
+ pt.data = count;
+
+ msgqsendevent (&pt,&rcvbuf,count);
+ *ptr = rcvbuf->data;
+
+ contdebuggee(0);
+}
+
+/* threadobject2jthread *******************************************************
+
+ Convert a cacao threadobject to jthread (java_lang_Thread)
+
+*******************************************************************************/
+jthread threadobject2jthread(threadobject* thread) {
+ java_lang_Thread* t;
+
+ stopdebuggee();
+
+ fprintf (stderr,"debugger: threadobject2jthread\n");
+ fflush(stderr);
+
+ getchildproc((char**)&t, thread->o.thread, sizeof(java_lang_Thread));
+ t->header.vftbl = class_java_lang_Thread->vftbl;
+ t->vmThread = thread;
+
+ fprintf (stderr,"debugger: threadobject2jthread done (t: %p)\n",t);
+ fflush(stderr);
+
+ contdebuggee(0);
+
+ return (jthread)t;
+}
+
+/* allthreads *****************************************************************
+
+ Gets an array of threadobjects of all threads
+
+*******************************************************************************/
+jvmtiError allthreads (jint * threads_count_ptr, threadobject ** threads_ptr) {
+ int i = 0, cnt = 8;
+ char *data;
+ threadobject *thread, *tthreads;;
+ void **addr, *mainthread;
+
+ stopdebuggee();
+
+ fprintf (stderr,"debugger: allthreads: addr of mainthreadobj: %p sizeof(threadobject*) %d sizeof(long) %d\n",&mainthreadobj,sizeof(threadobject*),sizeof(long));
+ fflush(stderr);
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ tthreads = MNEW(jthread, (sizeof(threadobject) * cnt));
+
+ stopdebuggee();
+ /* mainthreadobj is in the same place in the child process memory because
+ the child is a copy of this process */
+ getchildproc(&data, &mainthreadobj,sizeof(threadobject*));
+ addr = (void**) data;
+ mainthread = *addr;
+
+ do {
+ getchildproc(&data, *addr, sizeof(threadobject));
+ thread = (threadobject*) data;
+ fprintf (stderr,"debugger: get all threads addr %X *addr %X thread->info.prev %p &data %p data %p\n",addr, *addr, &(thread->info.prev), &data, data);
+
+ if(thread->o.thread != NULL) {
+ fprintf (stderr,"debugger: get all threads: thread alive (i %d cnt %d tthreads %p)\n",i,cnt,tthreads);
+ fflush(stderr);
+
+ /* count and copy only live threads */
+ if (i>=cnt) {
+ MREALLOC(tthreads,threadobject,cnt,cnt+8);
+ cnt += 8;
+ }
+ memcpy(&tthreads[i],thread,sizeof(threadobject));
+ fprintf(stderr,"allthreads - i %d tthreads[i].o.thread %p\n",i,tthreads[i].o.thread);
+ i++;
+ }
+ *addr = (void*)thread->info.prev;
+
+ /* repeat until we got the pointer to the mainthread twice */
+ } while (mainthread != *addr);
+
+ fprintf (stderr,"debugger: get all threads: %d thread alive - going to copy\n",i);
+ fflush(stderr);
+
+ *threads_count_ptr = i;
+
+ *threads_ptr = (threadobject*) heap_allocate(sizeof(threadobject) * i,true,NULL);
+ memcpy(*threads_ptr,tthreads,sizeof(threadobject)*i);
+ MFREE(tthreads,threadobject,cnt);
+
+ fprintf (stderr,"debugger: get all threads: done\n");
+ fflush(stderr);
+
+ contdebuggee(0);
+
+ return JVMTI_ERROR_NONE;
+#else
+ return JVMTI_ERROR_NOT_AVAILABLE;
+#endif
+}
+
+
+/* getcurrentthread ***********************************************************
+
+ Get jthread structure of current thread.
+
+*******************************************************************************/
+jthread getcurrentthread() {
+ /* get current thread through stacktrace. */
+ threadobject *threads;
+ threadobject *currthread=(threadobject*)0xffffffff; /* 32 bit max value */
+ jint tcnt;
+ int i;
+ struct user_regs_struct *regs;
+ ptrace_request pt;
+ ptrace_reply* rcvbuf;
+
+ assert (allthreads(&tcnt, &threads) == JVMTI_ERROR_NONE);
+
+ pt.kind=PTGETREG;
+ msgqsendevent(&pt,&rcvbuf,sizeof(struct user_regs_struct));
+ regs = rcvbuf->data;
+
+
+ /* ebp address of current thread has to have a smaller nummeric value then
+ the bottom of the stack whose address is in
+ currentthread->info._stackframeinfo; and a stack can belong to only one
+ thread.
+ exception: before mainthread has been started
+ */
+
+ if (threads[0].info._stackframeinfo != NULL) {
+ fprintf (stderr,"debugger: get all threads: done\n");
+ for (i=0;i<tcnt;i++) {
+ if ((regs->ebp < (long)threads[i].info._stackframeinfo)
+ && ((long)&threads[i]> (long)currthread))
+ currthread = &threads[i];
+ }
+ } else {
+ /* if the mainthread has not been started yet return mainthread */
+ fprintf (stderr,"debugger: getcurrentthread mainthreadobj - threads[0].o.thread %p\n",threads[0].o.thread);
+ currthread = &threads[0];
+ }
+
+ return (jthread)threadobject2jthread(currthread);
+}
+
+
+/* contdebuggee ****************************************************************
+
+ Send request to continue debuggee process through the message queue to the
+ cacaodbgserver process.
+
+*******************************************************************************/
+
+bool contdebuggee(int signal) {
+ ptrace_request pt;
+ ptrace_reply *rcvbuf;
+
+ /* get lock for running state */
+ getworkingdatalock();
+ cdbgshmem->hastostop--;
+
+ if ((!cdbgshmem->running)&&(cdbgshmem->hastostop==0)) {
+ /* release lock for running state */
+ releaseworkingdatalock();
+ pt.kind=PTCONT;
+ pt.data=signal;
+ msgqsendevent (&pt,&rcvbuf,sizeof(bool));
+ return *((bool*)rcvbuf->data);
+ } else {
+ /* release lock for running state */
+ releaseworkingdatalock();
+ return false;
+ }
+}
+
+
+/* stopdebuggee ***************************************************************
+
+ Helper function to stop debugge process. It only sends a signal to stop if
+ the debuggee is not already stopped.
+
+*******************************************************************************/
+void stopdebuggee() {
+ /* get lock for running state */
+ getworkingdatalock();
+ cdbgshmem->hastostop++;
+ if (cdbgshmem->running) {
+ fprintf (stderr,"debugger process: going to stop debuggee\n");
+ fflush(stderr);
+ /* release lock for running state */
+ releaseworkingdatalock();
+
+ if (kill (debuggee, SIGUSR2)==-1) {
+ perror("debugger process: stopdebuggee kill error: ");
+ }
+ } else
+ /* release lock for running state */
+ releaseworkingdatalock();
+}
+
+
+/* brktablecreator*************************************************************
+
+ helper function to enlarge the breakpoint table if needed
+
+*******************************************************************************/
+
+static void brktablecreator() {
+ struct _brkpt* tmp;
+ if (jvmtibrkpt.size == 0) {
+ jvmtibrkpt.brk = MNEW(struct _brkpt, 16);
+ memset(jvmtibrkpt.brk, 0, sizeof(struct _brkpt)*16);
+ jvmtibrkpt.size = 16;
+ jvmtibrkpt.num = BEGINUSERBRK;
+ } else {
+ jvmtibrkpt.size += 16;
+ tmp = jvmtibrkpt.brk;
+ jvmtibrkpt.brk = MNEW(struct _brkpt, jvmtibrkpt.size);
+ memset(jvmtibrkpt.brk, 0, sizeof(struct _brkpt)*jvmtibrkpt.size);
+ memcpy((void*)jvmtibrkpt.brk,(void*)tmp,jvmtibrkpt.size);
+ MFREE(tmp,struct _brkpt,jvmtibrkpt.size-16);
+ }
+}
+
+
+/* setsysbrkpt ****************************************************************
+
+ sets a system breakpoint int breakpoint table and calls set breakpoint
+
+*******************************************************************************/
+
+void setsysbrkpt(int sysbrk, void* addr) {
+ ptrace_request pt;
+ ptrace_reply *rcvbuf;
+
+ if (jvmtibrkpt.size == jvmtibrkpt.num)
+ brktablecreator();
+
+ assert (sysbrk < BEGINUSERBRK);
+ jvmtibrkpt.brk[sysbrk].addr = addr;
+
+ pt.kind = PTSETBRK;
+ pt.addr = addr;
+ msgqsendevent (&pt, &rcvbuf, sizeof(long));
+
+ jvmtibrkpt.brk[sysbrk].orig = ((long*)rcvbuf->data)[0];
+
+ fprintf (stderr,"setsysbrk %d %X done\n",sysbrk, addr);
+}
+
+
+/* addbrkpt *******************************************************************
+
+ adds a breakpoint to breakpoint table and calls set breakpoint
+
+*******************************************************************************/
+
+void addbrkpt(void* addr, jmethodID method, jlocation location) {
+ ptrace_request pt;
+ ptrace_reply *rcvbuf;
+
+ if (jvmtibrkpt.size == jvmtibrkpt.num)
+ brktablecreator();
+
+ assert (jvmtibrkpt.size > jvmtibrkpt.num);
+ fprintf (stderr,"add brk add: %X\n",addr);
+ jvmtibrkpt.brk[jvmtibrkpt.num].addr = addr;
+ jvmtibrkpt.brk[jvmtibrkpt.num].method = method;
+ jvmtibrkpt.brk[jvmtibrkpt.num].location = location;
+
+ pt.kind = PTSETBRK;
+ pt.addr = addr;
+ msgqsendevent (&pt, &rcvbuf, sizeof(long));
+
+ jvmtibrkpt.brk[jvmtibrkpt.num].orig = ((long*)rcvbuf->data)[0];
+ jvmtibrkpt.num++;
+
+ fprintf (stderr,"add brk done\n");
+}
+
+
+/* setup_jdwp_thread *****************************************************
+
+ Helper function to start JDWP threads
+
+*******************************************************************************/
+
+static void setup_jdwp_thread(char* transport) {
+ java_objectheader *o;
+ methodinfo *m;
+ java_lang_String *s;
+ classinfo *class;
+
+ /* new gnu.classpath.jdwp.Jdwp() */
+ class = load_class_from_sysloader(
+ utf_new_char("gnu.classpath.jdwp.Jdwp"));
+ if (!class)
+ throw_main_exception_exit();
+
+ o = builtin_new(class);
+
+ if (!o)
+ throw_main_exception_exit();
+
+ m = class_resolveclassmethod(class,
+ utf_init,
+ NULL,
+ class_java_lang_Object,
+ true);
+ if (!m)
+ throw_main_exception_exit();
+
+ vm_call_method(m,o);
+
+ /* configure(transport,NULL) */
+ m = class_resolveclassmethod(
+ class, utf_new_char("configure"),
+ utf_new_char("(Ljava/lang/String;)V"),
+ class_java_lang_Object,
+ false);
+
+ s = javastring_new_char(&transport[1]);
+
+ vm_call_method(m,o,s);
+
+ if (!m)
+ throw_main_exception_exit();
+
+
+ /* _doInitialization */
+ m = class_resolveclassmethod(class,
+ utf_new_char("_doInitialization"),
+ utf_new_char("()V"),
+ class,
+ false);
+
+ if (!m)
+ throw_main_exception_exit();
+
+ vm_call_method(m,o);
+}
+
+/* cacaodbglisten *************************************************************
+
+ setup listener thread for JDWP
+
+*******************************************************************************/
+
+void cacaodbglisten(char* transport) {
+ basic_event ev;
+ genericEventData data;
+ int i;
+
+ fprintf(stderr, "jdwp/debugger process jdwp pid %d\n",getpid());
+ fflush (stderr);
+
+ log_text("jdwp/debugger process - set up jdwp listening thread");
+
+ /* setup listening thread (JDWP) */
+ setup_jdwp_thread(transport);
+
+ log_text("jdwp/debugger process - continue debuggee");
+ /* start to be debugged program */
+ contdebuggee(0);
+
+ /* handle messages from cacaodbgserver */
+ while (true) {
+ if (-1 == msgrcv(msgqid,&ev,sizeof(basic_event),MSGQDEBUGGER,0))
+ perror("debugger process: cacaodbglisten: ");
+
+ switch (ev.signal) {
+ case SIGTRAP:
+ /* search the breakpoint that has been triggered */
+ i=0;
+ while ((ev.ip!=jvmtibrkpt.brk[i].addr) && (i<jvmtibrkpt.num)) i++;
+
+ fprintf(stderr,"cacaodbglisten SIGTRAP switch after while loop i %d\n",i);
+
+ switch (i) {
+ case HEREWEGOBRK:
+ /* herewego trap */
+ if (!suspend) {
+ fprintf(stderr,"cacaodbglisten suspend false -> continue debuggee\n");
+ contdebuggee(0);
+ } else {
+ fprintf(stderr,"cacaodbglisten suspend true -> do no continue debuggee\n");
+ getworkingdatalock();
+ cdbgshmem->hastostop=1;
+ releaseworkingdatalock();
+ }
+ set_jvmti_phase(JVMTI_PHASE_LIVE);
+ break;
+ case SETTHREADOBJECTBRK:
+ /* setthreadobject */
+ fprintf(stderr,"IP %X == setthreadobject\n",ev.ip);
+ data.ev=JVMTI_EVENT_THREAD_START;
+ fireEvent(&data);
+ break;
+ default:
+ if ((i >= BEGINUSERBRK) && (i<jvmtibrkpt.num)) {
+ log_text("todo: user defined breakpoints are not handled yet");
+ } else {
+ log_text("breakpoint not handled - continue anyway");
+ contdebuggee(0);
+ }
+ }
+ break;
+ case SIGQUIT:
+ log_text("debugger process SIGQUIT");
+ data.ev=JVMTI_EVENT_VM_DEATH;
+ fireEvent(&data);
+ break;
+ default:
+ log_text("signal not handled");
+ }
+ }
+}
+
+/* ipcrm ***********************************************************************
+
+ removes messages queue
+
+********************************************************************************/
+void ipcrm() {
+ struct msqid_ds msgbuf;
+ struct shmid_ds shmbuf;
+ msgctl(msgqid, IPC_RMID, &msgbuf);
+ shmctl(shmid, IPC_RMID, &shmbuf);
+}
+
+
+/* cacaodbgfork ****************************************************************
+
+ create debugger/jdwp and debuggee process. Returns true if this is the
+ parent (debugger/jdwp) process
+
+********************************************************************************/
+
+bool cacaodbgfork() {
+ int waitproc;
+
+ /* todo: remove shared memory and msg queue on exit */
+ /* create/initialize semaphores/shared memory/message queue */
+ sem_init(&workingdata_lock, 1, 1);
+
+ shmid = shmget(IPC_PRIVATE, sizeof(cacaodbgserver_data), IPC_CREAT | 0x180);
+ if ((cdbgshmem = (cacaodbgserver_data*)shmat(shmid, NULL, 0)) == -1) {
+ perror("cacaodbgfork: shared memory attach error: ");
+ exit(1);
+ }
+ cdbgshmem->running = false;
+ cdbgshmem->hastostop = 1;
+
+ if ((msgqid = msgget(IPC_PRIVATE, IPC_CREAT | 0x180)) == -1) {
+ perror("cacaodbgfork: message queue get error");
+ exit(1);
+ }
+ ;
+
+
+ /* with this function the following process structure is created:
+
+ cacaodbgserver
+ \_ debuggee (client/cacao vm)
+ \_ debugger (jdwp/cacao vm)
+
+ */
+
+ debuggee = fork();
+ if (debuggee == (-1)) {
+ log_text("debuggee fork error");
+ exit(1);
+ } else {
+ if (debuggee == 0) {
+ /* debuggee process - this is where the java client is running */
+
+ /* allow helper process to trace us */
+ if (TRACEME != 0) exit(1);
+
+ fprintf(stderr, "debugee pid %d\n",getpid());
+ fflush (stderr);
+
+ /* give parent/debugger process control */
+ kill(getpid(),SIGUSR2);
+
+ log_text("debuggee: continue with normal startup");
+
+ /* continue with normal startup */
+ return false;
+ } else {
+ log_text("debugger: fork listening jdwp process");
+ waitproc = fork();
+
+ if (waitproc == (-1)) {
+ log_text("waitprocess fork error");
+ exit(1);
+ } else {
+ if (waitproc == 0) {
+ log_text("jdwp process - create new jvmti environment");
+
+ remotedbgjvmtienv = new_jvmtienv();
+
+ log_text("jdwp process - init VMjdwp");
+
+ if (!VMjdwpInit(remotedbgjvmtienv)) exit(1);
+
+ return true;
+ } else {
+ /* Debugger process (parent of debugge process)
+ Here a wait-loop is execute and all the ptrace calls are
+ done from within this process.
+
+ This call will never return */
+
+ cacaodbgserver();
+ fprintf(stderr,"cacaodbgserver returned - exit\n");
+ ipcrm();
+ exit(0);
+ }
+ }
+ }
+ }
+ return true; /* make compiler happy */
+}
+
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/* src/native/jvmti/cacaodbg.h - contains cacao specifics for debugging support
+
+ Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Martin Platter
+
+ Changes:
+
+
+ $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $
+
+*/
+
+#ifndef _CACAODBG_H
+#define _CACAODBG_H
+
+#include "threads/native/threads.h"
+#include "native/jvmti/jvmti.h"
+
+#define MSGQEVENT 1
+#define MSGQPTRACEREQ 2
+#define MSGQPTRACEANS 3
+
+typedef struct {
+ jvmtiEvent ev;
+ jvmtiEnv *jvmti_env;
+ jthread thread;
+ jmethodID method;
+ jlocation location;
+ jclass klass;
+ jobject object;
+ jfieldID field;
+ char signature_type;
+ jvalue value;
+ jboolean b;
+ void* address;
+ void** new_address_ptr;
+ jmethodID catch_method;
+ jlocation catch_location;
+ char* name;
+ jobject protection_domain;
+ jint jint1;
+ jint jint2;
+ unsigned char* class_data;
+ jint* new_class_data_len;
+ unsigned char** new_class_data;
+ jvmtiAddrLocationMap* map;
+ void* compile_info;
+ jlong jlong;
+} genericEventData;
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+struct _jrawMonitorID {
+ java_lang_String *name;
+};
+
+struct _threadmap {
+ pthread_t tid;
+ threadobject* cacaothreadobj;
+};
+
+struct threadmap {
+ struct _threadmap* map;
+ int num;
+ int size;
+};
+
+struct threadmap thmap;
+#endif
+
+
+/* constants where system breakpoints are stored in the breakpoint table */
+#define HEREWEGOBRK 0 /* used for suspend VM on startup */
+#define SETTHREADOBJECTBRK 1 /* used for EVENT_THREAD_START */
+#define BEGINUSERBRK 2 /* here is where the first user breakpoint is
+ stored */
+struct _brkpt {
+ jmethodID method;
+ jlocation location;
+ void* addr;
+ long orig; /* original memory content */
+};
+
+
+struct brkpts {
+ struct _brkpt* brk;
+ int num;
+ int size;
+};
+
+struct brkpts jvmtibrkpt;
+
+bool jdwp; /* debugger via jdwp */
+bool jvmti; /* jvmti agent */
+bool dbgprocess; /* ture if debugger else debuggee process */
+pid_t debuggee; /* PID of debuggee */
+
+char *transport, *agentarg; /* arguments for jdwp transport and agent load */
+bool suspend; /* should the virtual machine suspend on startup? */
+
+
+bool cacaodbgfork();
+void cacaodbglisten(char* transport);
+jvmtiEnv* new_jvmtienv();
+void set_jvmti_phase(jvmtiPhase p);
+bool contdebuggee(int signal);
+void stopdebuggee();
+void fireEvent(genericEventData* data);
+bool VMjdwpInit(jvmtiEnv *jvmti_env);
+jvmtiEnv* remotedbgjvmtienv;
+jvmtiEventCallbacks jvmti_jdwp_EventCallbacks;
+void agentload(char* opt_arg);
+void agentunload();
+
+void getchildproc (char **ptr, void* addr, int count);
+void addbrkpt(void* addr, jmethodID method, jlocation location);
+void setsysbrkpt(int sysbrk, void* addr);
+jthread threadobject2jthread(threadobject* thread);
+jvmtiError allthreads (jint * threads_count_ptr, threadobject ** threads_ptr);
+jthread getcurrentthread();
+
+void ipcrm();
+
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/* src/native/jvmti/cacaodbgserver.c - contains the cacaodbgserver process. This
+ process controls the debuggee.
+
+ Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Martin Platter
+
+ Changes:
+
+
+ $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $
+
+*/
+
+#include "native/jvmti/cacaodbgserver.h"
+#include "native/jvmti/cacaodbg.h"
+#include "native/jvmti/dbg.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <semaphore.h>
+#include <sys/msg.h>
+#include <linux/user.h>
+
+
+/* getchildprocptrace *********************************************************
+
+ Get data count number of bytes from address addr for child process address
+ space. Requested data is stored in the array pointed to by ptr.
+
+*******************************************************************************/
+static void getchildprocptrace (char *ptr, void* addr, int cnt) {
+ int i, longcnt;
+ long *p = (long*) ptr;
+
+ longcnt = cnt/sizeof(long);
+ for (i=0; i<longcnt; i++) {
+ p[i]=GETMEM(debuggee,addr);
+ if (p[i]==-1)
+ perror("cacaodbgserver process: getchildprocptrace: ");
+ addr+=sizeof(long);
+ }
+ longcnt = GETMEM(debuggee,addr);
+ memcpy(ptr,&longcnt,cnt%sizeof(long));
+}
+
+/* contchild ******************************************************************
+
+ Helper function to continue child process.
+
+*******************************************************************************/
+static bool contchild(int signal) {
+ /* get lock for running state */
+ sem_wait(&workingdata_lock);
+ fprintf(stderr,"cacaodbgserver: contchild called (hastostop: %d)\n",cdbgshmem->hastostop);
+ if(cdbgshmem->hastostop < 1) {
+ fprintf(stderr,"cacaodbgserver: going to continue child\n");
+ CONT(debuggee,signal);
+ cdbgshmem->hastostop = 0;
+ cdbgshmem->running=true;
+ /* release lock for running state */
+ sem_post(&workingdata_lock);
+ return true;
+ } else {
+ sem_post(&workingdata_lock);
+ return false;
+ }
+}
+
+/* msgqsendevent *******************************************************************
+
+ sends an event notification to the jdwp/debugger process through the
+ message queue
+
+*******************************************************************************/
+static void msgqsendevent(basic_event *ev) {
+ ev->mtype = MSGQDEBUGGER;
+
+ if (-1 == msgsnd(msgqid, ev, sizeof(basic_event), 0)) {
+ perror("cacaodbgserver process: cacaodbglisten send error: ");
+ exit(1);
+ }
+}
+
+/* waitloop *******************************************************************
+
+ waits and handles signals from debuggee/child process
+
+*******************************************************************************/
+
+static void waitloop() {
+ int status,retval,signal;
+ void* ip;
+ basic_event ev;
+
+ fprintf(stderr,"waitloop\n");
+ fflush (stderr);
+
+ while (true) {
+ retval = wait(&status);
+
+ fprintf(stderr,"cacaodbgserver: waitloop we got something to do\n");
+ if (retval == -1) {
+ fprintf(stderr,"error in waitloop\n");
+ perror("cacaodbgserver process: waitloop: ");
+ exit(1);
+ }
+
+ if (retval != debuggee) {
+ fprintf(stderr,"cacaodbgserver got signal from process other then debuggee\n");
+ exit(1);
+ }
+
+ if (WIFEXITED(status)) {
+ /* generate event VMDeath */
+ ev.signal = SIGQUIT;
+ ev.ip = NULL;
+ msgqsendevent(&ev);
+ return;
+ }
+
+ if (WIFSTOPPED(status)) {
+ signal = WSTOPSIG(status);
+
+ /* ignore SIGSEGV, SIGPWR, SIGBUS and SIGXCPU for now.
+ todo: in future this signals can be used to detect Garbage
+ Collection Start/Finish or NullPointerException Events */
+ if ((signal == SIGSEGV) || (signal == SIGPWR) ||
+ (signal == SIGBUS) || (signal == SIGXCPU)) {
+ fprintf(stderr,"cacaodbgserver: ignore internal signal (%d)\n",signal);
+ contchild(signal);
+ continue;
+ }
+
+ if (signal == SIGABRT) {
+ fprintf(stderr,"cacaodbgserver: got SIGABRT from debugee - exit\n");
+ exit(1);
+ }
+
+ ip = getip(debuggee);
+ ip--; /* EIP has already been incremented */
+ fprintf(stderr,"got signal: %d IP %X\n",signal,ip);
+
+ sem_wait(&workingdata_lock);
+ cdbgshmem->running = false;
+ cdbgshmem->hastostop = 1;
+ sem_post(&workingdata_lock);
+
+ if (signal==SIGUSR2) {
+ fprintf(stderr,"SIGUSR2 - debuggee has stopped by jdwp process\n");
+ return;
+ }
+
+ ev.signal = signal;
+ ev.ip = ip;
+ msgqsendevent(&ev);
+ return;
+ }
+
+ fprintf(stderr,"wait not handled(child not exited or stopped)\n");
+ fprintf(stderr,"retval: %d status: %d\n",retval,status);
+ }
+}
+
+/* ptraceloop *****************************************************************
+
+ this function handles the ptrace request from the jdwp/debugger process.
+
+*******************************************************************************/
+
+void ptraceloop() {
+ bool contdebuggee=false;
+ ptrace_request pt;
+ ptrace_reply *buffer;
+ int size;
+ struct user_regs_struct *regs;
+
+ fprintf(stderr,"ptraceloop\n");
+ fflush (stderr);
+ while (!contdebuggee) {
+ if (-1 == msgrcv(msgqid, &pt, sizeof(ptrace_request), MSGQPTRACESND, 0))
+ perror("cacaodbgserver process: cacaodbglisten receive error: ");
+
+ switch(pt.kind){
+ case PTCONT:
+ /* continue debuggee process */
+ size= sizeof(ptrace_reply);
+ buffer =(ptrace_reply*) MNEW(char,size);
+
+ contdebuggee = contchild(pt.data);
+
+ buffer->mtype = MSGQPTRACERCV;
+ buffer->successful=true;
+ buffer->datasize=0;
+ break;
+ case PTPEEKDATA:
+ /* get memory content from the debuggee process */
+ size= sizeof(ptrace_reply)+pt.data;
+ buffer =(ptrace_reply*) MNEW(char,size);
+
+ buffer->mtype = MSGQPTRACERCV;
+ buffer->datasize = size-sizeof(ptrace_reply);
+
+ fprintf(stderr,"getchildprocptrace: pid %d get %p - %p cnt: %d (buffer %p buffer->data %p)\n",
+ debuggee, pt.addr,pt.addr+pt.data, buffer->datasize,buffer, buffer->data);
+ fflush(stderr);
+
+ getchildprocptrace(buffer->data,pt.addr,buffer->datasize);
+ break;
+ case PTSETBRK:
+ size= sizeof(ptrace_reply)+sizeof(long);
+ buffer =(ptrace_reply*) MNEW(char,size);
+
+ /* set new breakpoint */
+ buffer->mtype = MSGQPTRACERCV;
+ buffer->successful=true;
+ buffer->datasize=sizeof(long);
+
+ setbrk(debuggee,pt.addr, (long*)(buffer->data));
+ break;
+ case PTDELBRK:
+ /* delete breakpoint */
+ size= sizeof(ptrace_reply);
+ buffer =(ptrace_reply*) MNEW(char,size);
+
+ DISABLEBRK(debuggee,pt.ldata,pt.addr);
+
+ buffer->mtype = MSGQPTRACERCV;
+ buffer->successful=true;
+ buffer->datasize=0;
+ break;
+ case PTGETREG:
+ /* get registers */
+ size= sizeof(ptrace_reply)+sizeof(struct user_regs_struct);
+ buffer =(ptrace_reply*) MNEW(char,size);
+ regs=buffer->data;
+
+ GETREGS(debuggee,*regs);
+
+ buffer->mtype = MSGQPTRACERCV;
+ buffer->successful=true;
+ buffer->datasize=sizeof(struct user_regs_struct);
+ break;
+ default:
+ fprintf(stderr,"unkown ptrace request %d\n",pt.kind);
+ exit(1);
+ }
+
+ if (-1 == msgsnd(msgqid, buffer, size, 0)) {
+ perror("cacaodbgserver process: cacaodbglisten send error: ");
+ exit(1);
+ }
+ MFREE(buffer,char,size);
+ }
+}
+
+/* cacaodbgserver *************************************************************
+
+ waits for eventes from and issues ptrace calls to debuggee/child process
+
+*******************************************************************************/
+
+void cacaodbgserver() {
+ fprintf(stderr,"cacaodbgserver started\n");
+ fflush(stderr);
+ while(true) {
+ /* wait until debuggee process gets stopped
+ and inform debugger process */
+ waitloop();
+ /* give the debugger process the opportunity to issue ptrace calls */
+ ptraceloop();
+ /* ptraceloop returns after a PTRACE_CONT call has been issued */
+ }
+}
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/* src/native/jvmti/cacaodbgserver.h - contains cacao specifics for
+ debugging support
+
+ Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Martin Platter
+
+ Changes:
+
+
+ $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $
+
+*/
+
+#ifndef _CACAODBGSERVER_H
+#define _CACAODBGSERVER_H
+
+#include "vm/global.h"
+#include <semaphore.h>
+
+/* supported message types */
+#define MSGQCACAODBGSRV 1 /* messages for cacaodbgserver process */
+#define MSGQDEBUGGER 2 /* messages for debugger process */
+#define MSGQPTRACESND 3 /* messages for ptrace request */
+#define MSGQPTRACERCV 4 /* messages for ptrace return value */
+
+/* supported ptrace loop calls */
+#define PTCONT 1 /* ptrace continue */
+#define PTPEEKDATA 2 /* ptrace peek data */
+#define PTSETBRK 3 /* set breakpiont */
+#define PTDELBRK 4 /* delete breakpiont */
+#define PTGETREG 5 /* get registers */
+
+
+typedef struct {
+ long mtype;
+ int kind;
+ void* addr;
+ int data;
+ long ldata;
+} ptrace_request;
+
+typedef struct {
+ long mtype;
+ bool successful;
+ int datasize;
+ char data[1];
+} ptrace_reply;
+
+
+typedef struct {
+ long mtype;
+ int signal;
+ void *ip;
+} basic_event;
+
+typedef struct {
+ bool running; /* true if debuggee process is running */
+ int hastostop; /* if greater then zero the debugger needs the
+ debuggee to be stopped */
+} cacaodbgserver_data;
+
+
+int msgqid; /* message queue for the communication between
+ debugger/jdwp and cacaodbgserver process */
+int shmid; /* shared memory for saving running state */
+sem_t workingdata_lock; /* semaphore for cacaodbgserver_data shared
+ memory structure */
+cacaodbgserver_data *cdbgshmem; /* cacaodbgserver shared memory pointer */
+
+
+
+void cacaodbgserver(); /* entry point function to cacaodbgserver proc */
+
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/* src/native/jvmti/dbg.c - jvmti os/architecture support
+
+ Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Martin Platter
+
+ Changes:
+
+
+ $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $
+
+*/
+
+/* at the moment linux/i386 is the only plattform available */
+#if defined(__LINUX__) && defined (__I386__)
+
+#include "dbg.h"
+#include <sys/ptrace.h>
+#include <linux/user.h>
+
+#include <stdio.h>
+
+void* getip(pid_t pid) {
+ struct user_regs_struct regs;
+
+ GETREGS(pid,regs);
+ return (void*)regs.eip;
+}
+
+void setip(pid_t pid, void* ip) {
+ struct user_regs_struct regs;
+
+ GETREGS(pid,regs);
+ regs.eip=(long)ip;
+ ptrace(PTRACE_SETREGS, pid, 0, ®s);
+}
+
+void setbrk(pid_t pid, void* addr, long* orig) {
+ long ins;
+ *orig = GETMEM(pid,addr);
+
+ ins = (*orig & ~0x000000FF) | TRAPINS;
+
+ fprintf (stderr,"pid %d set brk at %p orig: %X new: %X\n",getpid(),addr,*orig,ins);
+ if (ptrace(PTRACE_POKEDATA, pid, (caddr_t) addr, ins)==-1)
+ perror("setbrk error ");
+}
+
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
Changes:
- $Id: dbg.h 4357 2006-01-22 23:33:38Z twisti $
+ $Id: dbg.h 4661 2006-03-21 00:04:59Z motse $
*/
/* at the moment linux/i386 is the only plattform available */
#if defined(__LINUX__) && defined (__I386__)
+
+#ifndef _DBG_H
+#define _DBG_H
+
+#include <sys/types.h>
#include <sys/ptrace.h>
#define TRACEME ptrace(PTRACE_TRACEME, 0, 0, 0)
-#define GETREGS(pid, regs) ptrace(PTRACE_GETREGS, pid, 0, ®s)
-#define GETMEM(pid, addr) ptrace(PTRACE_PEEKDATA, pid, (caddr_t) addr, 0)
-#define ENABLEBRK(pid,ins,addr) ptrace(PTRACE_POKEDATA, pid, (caddr_t) addr, (ins & ~0x000000FF) | 0xcc)
-#define CONT(pid) ptrace(PTRACE_CONT, pid, 0, 0)
+#define DETACH(pid,sig) ptrace(PTRACE_DETACH, pid, 0, sig)
+#define TRAPINS 0xcc /* opcode for brk */
+#define TRAP asm("int3")
+#define GETMEM(pid, addr) ptrace(PTRACE_PEEKDATA, pid, addr, 0)
+#define CONT(pid,sig) if(ptrace(PTRACE_CONT, pid, 0, sig)==-1) \
+ perror("continue failed: ");
#define DISABLEBRK(pid,ins,addr) ptrace(PTRACE_POKEDATA, pid, (caddr_t) addr, ins)
-#define GETIP(pid,ip) ptrace(PTRACE_GETREGS, pid, 0, ®s); \
- ip=regs.eip;
-#define SETIP(pid,ip) ip=regs.eip; \
- ptrace(PTRACE_SETREGS, pid, 0, ®s);
+#define GETREGS(pid,regs) ptrace(PTRACE_GETREGS, pid, 0, ®s)
+
+void* getip(pid_t pid);
+void setip(pid_t pid, void* ip);
+
+void setbrk(pid_t pid, void* addr,long* orig);
+
+#endif
#endif
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
-/* src/native/jvmti/jvmti.c - implementation of the Java Virtual Machine Tool
- Interface functions
+/* src/native/jvmti/jvmti.c - implementation of the Java Virtual Machine
+ Tool Interface functions
Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
Changes: Edwin Steiner
- $Id: jvmti.c 4599 2006-03-14 22:30:58Z edwin $
+ $Id: jvmti.c 4661 2006-03-21 00:04:59Z motse $
*/
#include <assert.h>
#include "native/jni.h"
+#include "native/native.h"
+#include "native/jvmti/cacaodbg.h"
#include "native/jvmti/jvmti.h"
#include "vm/global.h"
#include "vm/loader.h"
#include "vm/builtin.h"
#include "vm/jit/asmpart.h"
+#include "vm/class.h"
#include "vm/classcache.h"
#include "mm/boehm.h"
#include "toolbox/logging.h"
#include "vm/options.h"
-#include "cacao/cacao.h"
#include "vm/stringlocal.h"
#include "mm/memory.h"
#include "threads/native/threads.h"
#include "native/include/java_lang_VMObject.h"
#include "native/include/java_lang_VMSystem.h"
#include "native/include/java_lang_VMClass.h"
-#include "vm/jit/stacktrace.h"
+#include "vm/suck.h"
+#include "boehm-gc/include/gc.h"
#include <string.h>
#include <linux/unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/user.h>
#include <signal.h>
#include <ltdl.h>
environment *next;
};
-
-static jvmtiEnv JVMTI_EnvTable;
+static struct jvmtiEnv_struct JVMTI_EnvTable;
static jvmtiCapabilities JVMTI_Capabilities;
static lt_ptr unload;
#define CHECK_PHASE_END )) return JVMTI_ERROR_WRONG_PHASE
#define CHECK_CAPABILITY(env,CAP) if(((environment*)env)->capabilities.CAP == 0) \
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
-#define CHECK_THREAD_IS_ALIVE(t) if((((java_lang_Thread*)t)->vmThread==NULL)&& \
- (((java_lang_Thread*)t)->group==NULL)) \
+#define CHECK_THREAD_IS_ALIVE(t) if(check_thread_is_alive(t)== \
+ JVMTI_ERROR_THREAD_NOT_ALIVE) \
return JVMTI_ERROR_THREAD_NOT_ALIVE;
+
+/* check_thread_is_alive *******************************************************
+
+ checks if the given thread is alive
+
+*******************************************************************************/
+static jvmtiError check_thread_is_alive(jthread t) {
+ char* data;
+ java_lang_Thread* th;
+ if(t==NULL)
+ return JVMTI_ERROR_THREAD_NOT_ALIVE;
+ getchildproc(&data, t, sizeof(java_lang_Thread));
+ th = (java_lang_Thread*)data;
+ if(th->vmThread==NULL)
+ return JVMTI_ERROR_THREAD_NOT_ALIVE;
+ return JVMTI_ERROR_NONE;
+}
+
+/* execcallback ***************************************************************
+
+ executes the registerd callbacks for the given jvmti event with parameter
+ in the data structure.
+
+*******************************************************************************/
static void execcallback(jvmtiEvent e, functionptr ec, genericEventData* data) {
- JNIEnv* jni_env = ptr_env;
+ JNIEnv* jni_env = (JNIEnv*)&_Jv_JNINativeInterface;
+
+ fprintf(stderr,"execcallback called (event: %d)\n",e);
switch (e) {
case JVMTI_EVENT_VM_INIT:
case JVMTI_EVENT_VM_DEATH:
case JVMTI_EVENT_VM_START:
- ((jvmtiEventThreadStart)ec) (data->jvmti_env, jni_env, data->thread);
+ ((jvmtiEventVMStart)ec) (data->jvmti_env, jni_env);
break;
case JVMTI_EVENT_EXCEPTION:
}
}
-/* fireEvent **************************************************************
- fire event callback with data arguments.
+/* dofireEvent ******************************************************************
-*******************************************************************************/
+ sends event if it is enabled either globally or for some threads
-void fireEvent(jvmtiEvent e, genericEventData* data) {
+*******************************************************************************/
+static void dofireEvent(jvmtiEvent e, genericEventData* data) {
environment* env;
jvmtiEventModeLL *evm;
- jthread thread;
-
functionptr ec;
- /* todo : respect event order JVMTI-Spec:Multiple Co-located Events */
-
- thread = (jthread)THREADOBJECT;
-
- data->thread = thread;
env = envs;
while (env!=NULL) {
-
if (env->events[e-JVMTI_EVENT_START_ENUM].mode == JVMTI_DISABLE) {
evm = env->events[e-JVMTI_EVENT_START_ENUM].next;
/* test if the event is enable for some threads */
evm=evm->next;
}
} else { /* event enabled globally */
- data->jvmti_env=&env->env;
+ data->jvmti_env=&env->env;
ec = ((functionptr*)(&env->callbacks))[e-JVMTI_EVENT_START_ENUM];
execcallback(e, ec, data);
}
}
+/* fireEvent ******************************************************************
-/* getchildproc ***************************************************************
-
- Get data from child process
+ fire event callback with data arguments. This function mainly fills the
+ missing EventData.
*******************************************************************************/
-static long getchildproc (void *ptr) {
- if (debuggee > 0) {
- /* get data from child process */
- return GETMEM(debuggee,ptr);
- } else {
- return *((long*)ptr);
- }
-}
+void fireEvent(genericEventData* d) {
+ jthread thread;
+ /* todo : respect event order JVMTI-Spec:Multiple Co-located Events */
+
+ if (d->ev != JVMTI_EVENT_VM_START)
+ thread = (jthread)getcurrentthread();
+ else
+ thread = NULL;
+ fprintf (stderr,"debugger: fireEvent: %d\n",d->ev);
+ d->thread = thread;
+ dofireEvent(d->ev,d);
+
+ fprintf (stderr,"debugger: fireEvent 2\n");
+ /* if we need to send a VM_INIT event then also send a THREAD_START event */
+ if (d->ev == JVMTI_EVENT_VM_INIT)
+ dofireEvent(JVMTI_EVENT_THREAD_START,d);
+}
/* SetEventNotificationMode ****************************************************
CHECK_PHASE(JVMTI_PHASE_LIVE)
CHECK_PHASE_END;
- if((event_thread != NULL)&&
- (!builtin_instanceof(event_thread,class_java_lang_Thread)))
- return JVMTI_ERROR_INVALID_THREAD;
-
- CHECK_THREAD_IS_ALIVE(event_thread);
+ if(event_thread != NULL) {
+ if (!builtin_instanceof(event_thread,class_java_lang_Thread))
+ return JVMTI_ERROR_INVALID_THREAD;
+ CHECK_THREAD_IS_ALIVE(event_thread);
+ }
cacao_env = (environment*) env;
if ((mode != JVMTI_ENABLE) && (mode != JVMTI_DISABLE))
return JVMTI_ERROR_NONE;
}
-
/* GetAllThreads ***************************************************************
Get all live threads
GetAllThreads (jvmtiEnv * env, jint * threads_count_ptr,
jthread ** threads_ptr)
{
- int i = 0;
- threadobject* thread;
+ threadobject* threads;
+ int i;
+ jvmtiError retval;
+
+ log_text ("GetAllThreads called");
CHECK_PHASE_START
CHECK_PHASE(JVMTI_PHASE_LIVE)
if ((threads_count_ptr == NULL) || (threads_ptr == NULL))
return JVMTI_ERROR_NULL_POINTER;
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- thread = mainthreadobj;
- do {
- if((thread->o.thread->vmThread==NULL)&& (thread->o.thread->group==NULL))
- i++; /* count only live threads */
- thread = thread->info.prev;
- } while (thread != mainthreadobj);
-
- *threads_count_ptr = i;
-
- *threads_ptr = (jthread*) heap_allocate(sizeof(jthread) * i,true,NULL);
- i=0;
- do {
- memcpy(*threads_ptr[i],thread,sizeof(jthread));
- thread = thread->info.prev;
- i++;
- } while (thread != mainthreadobj);
-#else
- return JVMTI_ERROR_NOT_AVAILABLE;
-#endif
+ retval=allthreads(threads_count_ptr,&threads);
+ if (retval != JVMTI_ERROR_NONE) return retval;
+
+ *threads_ptr =
+ heap_allocate(sizeof(jthread*)* (*threads_count_ptr),true,NULL);
+ for (i=0; i<*threads_count_ptr; i++)
+ (*threads_ptr)[i] = threadobject2jthread(&threads[i]);
+
return JVMTI_ERROR_NONE;
}
CHECK_PHASE_END;
CHECK_CAPABILITY(env,can_suspend)
+/*
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
- suspendThread((thread *) thread->thread);
+ suspend_thread((thread *) thread->thread);
+#endif
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ suspend_thread((threadobject*) thread);
#endif
+*/
return JVMTI_ERROR_NONE;
}
CHECK_PHASE_END;
CHECK_CAPABILITY(env,can_suspend)
+/*
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
- resumeThread((thread *) this->thread);
+ resume_thread((thread *) this->thread);
#endif
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ resume_thread((threadobject*) thread);
+#endif
+*/
return JVMTI_ERROR_NONE;
}
CHECK_THREAD_IS_ALIVE(thread);
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- interruptThread((java_lang_VMThread*)thread);
+/* interruptThread((java_lang_VMThread*)thread);*/
#else
return JVMTI_ERROR_NOT_AVAILABLE;
#endif
jvmtiError
GetThreadInfo (jvmtiEnv * env, jthread th, jvmtiThreadInfo * info_ptr)
{
- java_lang_Thread* t = (java_lang_Thread*)th;
int size;
- char* name;
+ char* data;
+ struct java_lang_Thread *t;
+
+ log_text("GetThreadInfo called");
CHECK_PHASE_START
CHECK_PHASE(JVMTI_PHASE_LIVE)
CHECK_PHASE_END;
-
- name = javastring_tochar((java_objectheader*)t->name);
- size = strlen(name);
- info_ptr->name=heap_allocate(size*sizeof(char),true,NULL);
- strncpy(info_ptr->name,name,size);
+
+ getchildproc(&data,th,sizeof(struct java_lang_Thread));
+ t = (java_lang_Thread*)data;
info_ptr->priority=(jint)t->priority;
info_ptr->is_daemon=(jboolean)t->daemon;
info_ptr->thread_group=(jthreadGroup)t->group;
info_ptr->context_class_loader=(jobject)t->contextClassLoader;
+ getchildproc(&data,t->name,sizeof(struct java_lang_String));
+ size = ((struct java_lang_String*)data)->count;
+ getchildproc(&(info_ptr->name),((struct java_lang_String*)data)->value,size);
+ info_ptr->name[size]='\0';
+
return JVMTI_ERROR_NONE;
}
jobject ** owned_monitors_ptr)
{
int i,j,size=20;
- jobject* om;
+ java_objectheader **om;
lockRecordPool* lrp;
+ char *data;
+
+ log_text("GetOwnedMonitorInfo called");
CHECK_PHASE_START
CHECK_PHASE(JVMTI_PHASE_LIVE)
om=MNEW(java_objectheader*,size);
- pthread_mutex_lock(&pool_lock);
+ stopdebuggee();
- lrp=global_pool;
+ /* global_pool is in the same place in the child process memory because the
+ the child is a copy of this process */
+ getchildproc(&data, &global_pool,sizeof(lockRecordPool*));
+ lrp=(lockRecordPool*)data;
while (lrp != NULL) {
for (j=0; j<lrp->header.size; j++) {
static void *threadstartup(void *t) {
runagentparam *rap = (runagentparam*)t;
- rap->sf(rap->jvmti_env,ptr_env,rap->arg);
+ rap->sf(rap->jvmti_env,&_Jv_JNINativeInterface,rap->arg);
return NULL;
}
if((thread != NULL)&&(!builtin_instanceof(thread,class_java_lang_Thread)))
return JVMTI_ERROR_INVALID_THREAD;
if (proc == NULL) return JVMTI_ERROR_NULL_POINTER;
- if ((priority < JVMTI_THREAD_MIN_PRIORITY) || (priority > JVMTI_THREAD_MAX_PRIORITY))
+ if ((priority < JVMTI_THREAD_MIN_PRIORITY) ||
+ (priority > JVMTI_THREAD_MAX_PRIORITY))
return JVMTI_ERROR_INVALID_PRIORITY;
rap.sf = proc;
sp.__sched_priority = sched_get_priority_min(SCHED_FIFO);
}
pthread_attr_setschedparam(&threadattr,&sp);
- if (pthread_create(&((threadobject*) thread)->info.tid, &threadattr, &threadstartup, &rap)) {
+ if (pthread_create(&((threadobject*)
+ thread)->info.tid, &threadattr, &threadstartup, &rap)) {
log_text("pthread_create failed");
assert(0);
}
Has to take care of suspend/resume issuses
*******************************************************************************/
+static jvmtiError getcacaostacktrace(char** trace, jthread thread) {
-static jvmtiError getcacaostacktrace(stackTraceBuffer** trace, jthread thread) {
+ log_text("getcacaostacktrace");
+
+
- /* todo: suspend specified thread */
-/*
- if (!cacao_stacktrace_fillInStackTrace((void**)trace,&stackTraceCollector, (threadobject*)thread))
- return JVMTI_ERROR_INTERNAL;
-*/
- /* todo: resume specified thread */
- log_text("todo: stacktraces");
return JVMTI_ERROR_NONE;
}
jvmtiError
GetFrameCount (jvmtiEnv * env, jthread thread, jint * count_ptr)
{
- stackTraceBuffer* trace;
+ char* trace;
jvmtiError er;
CHECK_PHASE_START
er = getcacaostacktrace(&trace, thread);
if (er==JVMTI_ERROR_NONE) return er;
- *count_ptr = trace->size;
+/* todo: *count_ptr = trace->size;*/
return JVMTI_ERROR_NONE;
}
GetThreadState (jvmtiEnv * env, jthread thread, jint * thread_state_ptr)
{
java_lang_Thread* th = (java_lang_Thread*)thread;
+ threadobject* t = (threadobject*)th->vmThread;
+
CHECK_PHASE_START
CHECK_PHASE(JVMTI_PHASE_LIVE)
CHECK_PHASE_END;
} else {
/* alive */
*thread_state_ptr = JVMTI_THREAD_STATE_ALIVE;
- if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_SUSPENDED; /* todo */
+ if (t->interrupted) *thread_state_ptr |= JVMTI_THREAD_STATE_INTERRUPTED;
/* todo */
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_SUSPENDED;
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_IN_NATIVE;
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_RUNNABLE;
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
+ if (false /* t->ee.waiting ? */) *thread_state_ptr |= JVMTI_THREAD_STATE_WAITING;
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_WAITING_INDEFINITELY;
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT;
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
+ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_PARKED;
+ if (t->isSleeping) *thread_state_ptr |= JVMTI_THREAD_STATE_SLEEPING;
}
#else
return JVMTI_ERROR_INTERNAL;
CHECK_PHASE_END;
CHECK_CAPABILITY(env,can_generate_breakpoint_events)
+ /* addbrkpt */
log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!");
return JVMTI_ERROR_NONE;
}
*status_ptr = 0;
/* if (c) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_VERIFIED; ? */
-/* if () *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_PREPARED; ? */
+ if (c->state&=CLASS_LINKED)
+ *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_PREPARED;
- if (c->initialized)
+ if (c->state&=CLASS_INITIALIZED)
*status_ptr = *status_ptr | JVMTI_CLASS_STATUS_INITIALIZED;
- if (c->erroneous_state)
+ if (c->state&=CLASS_ERROR)
*status_ptr = *status_ptr | JVMTI_CLASS_STATUS_ERROR;
if (c->vftbl->arraydesc != NULL)
if ((klass == NULL)||(source_name_ptr == NULL))
return JVMTI_ERROR_NULL_POINTER;
- size = (((classinfo*)klass)->sourcefile->blength);
+ size = (((classinfo*)klass)->sourcefile->blength)+1;
*source_name_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL);
memcpy(*source_name_ptr,((classinfo*)klass)->sourcefile->text, size);
+ (*source_name_ptr)[size]='\0';
return JVMTI_ERROR_NONE;
}
if (((methodinfo*)method)->flags & ACC_NATIVE)
return JVMTI_ERROR_NATIVE_METHOD;
- *size_ptr = (jint)((methodinfo*)method)->paramcount;
+/* todo *size_ptr = (jint)((methodinfo*)method)->paramcount;*/
return JVMTI_ERROR_NONE;
}
for (i=0; i < *entry_count_ptr; i++) {
(*table_ptr[i]).start_location =
- (jlocation) method->linenumbers[i].start_pc;
+ (jlocation) ((methodinfo*)method)->linenumbers[i].start_pc;
(*table_ptr[i]).line_number =
(jint) ((methodinfo*)method)->linenumbers[i].line_number;
}
*******************************************************************************/
jvmtiError
-GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr,
- jclass ** classes_ptr)
+GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, jclass ** classes_ptr)
{
int i,j;
+ char* data;
+ hashtable* ht;
classcache_name_entry *cne;
classcache_class_entry *cce;
+
+ log_text ("GetLoadedClasses called");
+
CHECK_PHASE_START
CHECK_PHASE(JVMTI_PHASE_LIVE)
CHECK_PHASE_END;
if (class_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
if (classes_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;
- tables_lock();
+ log_text ("GetLoadedClasses1");
+
+ stopdebuggee();
+ log_text ("GetLoadedClasses2");
+ /* hashtable_classcache is in the same place in the child process memory
+ because the child is a copy of this process */
+ getchildproc(&data, &hashtable_classcache, sizeof(hashtable));
+ ht = (hashtable*) &data;
- *classes_ptr = heap_allocate(sizeof(jclass*)*classcache_hash.entries,true,NULL);
- *class_count_ptr = classcache_hash.entries;
+ log_text ("GetLoadedClasses got ht pointer");
+ *classes_ptr =
+ heap_allocate(sizeof(jclass*) * (ht->entries),true,NULL);
+ fprintf (stderr,"hashtable_classcache.entries = %d\n",ht->entries);
+ fflush(stderr);
+
+ *class_count_ptr = ht->entries;
j=0;
/* look in every slot of the hashtable */
- for (i=0; i<classcache_hash.size; i++) {
- cne =(classcache_name_entry*) classcache_hash.ptr[i];
+ for (i=0; i<ht->size; i++) {
+ cne = ht->ptr[i];
+
while (cne != NULL) { /* iterate over hashlink */
+ getchildproc(&data, cne, sizeof(classcache_name_entry));
+ cne =(classcache_name_entry*) &data;
+
cce = cne->classes;
while (cce != NULL){ /* iterate over classes with same name */
+ getchildproc(&data, cce, sizeof(classcache_class_entry));
+ cce =(classcache_class_entry*) &data;
+
if (cce->classobj != NULL) { /* get only loaded classes */
- assert(j<classcache_hash.entries);
+ assert(j<ht->entries);
*classes_ptr[j]=cce->classobj;
j++;
}
}
}
- tables_unlock();
+ log_text ("GetLoadedClasses continue");
+
+ contdebuggee(0);
+
+ log_text ("GetLoadedClasses finished");
return JVMTI_ERROR_NONE;
}
GetClassLoaderClasses (jvmtiEnv * env, jobject initiating_loader,
jint * class_count_ptr, jclass ** classes_ptr)
{
+ log_text("GetClassLoaderClasses called");
+
CHECK_PHASE_START
CHECK_PHASE(JVMTI_PHASE_LIVE)
CHECK_PHASE_END;
jint max_frame_count, jvmtiFrameInfo * frame_buffer,
jint * count_ptr)
{
- stackTraceBuffer* trace;
+ char* trace;
jvmtiError er;
- int i,j;
+/* int i,j;*/
CHECK_PHASE_START
CHECK_PHASE(JVMTI_PHASE_LIVE)
er = getcacaostacktrace(&trace, thread);
if (er==JVMTI_ERROR_NONE) return er;
- if ((trace->size >= start_depth) || ((trace->size * -1) > start_depth))
- return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+/* todo: if ((trace->size >= start_depth) || ((trace->size * -1) > start_depth))
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT; */
- for (i=start_depth, j=0;i<trace->size;i++,j++) {
+/* for (i=start_depth, j=0;i<trace->size;i++,j++) {
frame_buffer[j].method = (jmethodID)trace[i].start->method;
- /* todo: location MachinePC not avilable - Linenumber not expected */
+ todo: location MachinePC not avilable - Linenumber not expected
frame_buffer[j].location = 0;
- }
+ }*/
return JVMTI_ERROR_NONE;
}
CHECK_PHASE_END;;
if (function_table == NULL) return JVMTI_ERROR_NULL_POINTER;
- ptr_env = (void*)heap_allocate(sizeof(jniNativeInterface),true,NULL);
- memcpy(ptr_env, function_table, sizeof(jniNativeInterface));
+ _Jv_env->env = (void*)heap_allocate(sizeof(jniNativeInterface),true,NULL);
+ memcpy(_Jv_env->env, function_table, sizeof(jniNativeInterface));
return JVMTI_ERROR_NONE;
}
if (function_table == NULL) return JVMTI_ERROR_NULL_POINTER;
*function_table = (jniNativeInterface*)
heap_allocate(sizeof(jniNativeInterface),true,NULL);
- memcpy(*function_table, ptr_env, sizeof(jniNativeInterface));
+ memcpy(*function_table, _Jv_env->env, sizeof(jniNativeInterface));
return JVMTI_ERROR_NONE;
}
CHECK_PHASE_END;
if (size_of_callbacks < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT;
-
- if (callbacks == NULL) { /* remove the existing callbacks */
+
+ if (callbacks == NULL) { /* remove the existing callbacks */
memset(&(((environment* )env)->callbacks), 0,
sizeof(jvmtiEventCallbacks));
}
jvmtiError
GetSystemProperties (jvmtiEnv * env, jint * count_ptr, char ***property_ptr)
{
- jmethodID mid;
- jmethodID moremid;
+ jmethodID mid, moremid;
classinfo *sysclass, *propclass, *enumclass;
java_objectheader *sysprop, *keys, *obj;
char* ch;
if (!sysclass) throw_main_exception_exit();
- mid = class_resolvemethod(sysclass,
+ mid = (jmethodID)class_resolvemethod(sysclass,
utf_new_char("getProperties"),
utf_new_char("()Ljava/util/Properties;"));
if (!mid) throw_main_exception_exit();
- sysprop = asm_calljavafunction(mid, sysclass, NULL, NULL, NULL);
+ sysprop = _Jv_JNINativeInterface.CallStaticObjectMethod(NULL, sysclass, mid);
if (!sysprop) throw_main_exception_exit();
propclass = sysprop->vftbl->class;
- mid = class_resolvemethod(propclass,
+ mid = (jmethodID)class_resolvemethod(propclass,
utf_new_char("size"),
utf_new_char("()I"));
if (!mid) throw_main_exception_exit();
_Jv_JNINativeInterface.CallIntMethod(NULL, sysprop, mid);
*property_ptr = heap_allocate(sizeof(char*) * (*count_ptr) ,true,NULL);
- mid = class_resolvemethod(propclass,
+ mid = (jmethodID)class_resolvemethod(propclass,
utf_new_char("keys"),
utf_new_char("()Ljava/util/Enumeration;"));
if (!mid) throw_main_exception_exit();
keys = _Jv_JNINativeInterface.CallObjectMethod(NULL, sysprop, mid);
enumclass = keys->vftbl->class;
- moremid = class_resolvemethod(enumclass,
+ moremid = (jmethodID)class_resolvemethod(enumclass,
utf_new_char("hasMoreElements"),
utf_new_char("()Z"));
if (!moremid) throw_main_exception_exit();
- mid = class_resolvemethod(propclass,
+ mid = (jmethodID)class_resolvemethod(propclass,
utf_new_char("nextElement"),
utf_new_char("()Ljava/lang/Object;"));
if (!mid) throw_main_exception_exit();
sysclass = load_class_from_sysloader(utf_new_char("java/lang/System"));
if (!sysclass) throw_main_exception_exit();
- mid = class_resolvemethod(sysclass,
+ mid = (jmethodID)class_resolvemethod(sysclass,
utf_new_char("getProperties"),
utf_new_char("()Ljava/util/Properties;"));
if (!mid) throw_main_exception_exit();
propclass = sysprop->vftbl->class;
- mid = class_resolvemethod(propclass,
+ mid = (jmethodID)class_resolvemethod(propclass,
utf_new_char("getProperty"),
utf_new_char("(Ljava/lang/String;)Ljava/lang/String;"));
if (!mid) throw_main_exception_exit();
sysclass = load_class_from_sysloader(utf_new_char("java/lang/System"));
if (!sysclass) throw_main_exception_exit();
- mid = class_resolvemethod(sysclass,
+ mid = (jmethodID)class_resolvemethod(sysclass,
utf_new_char("getProperties"),
utf_new_char("()Ljava/util/Properties;"));
if (!mid) throw_main_exception_exit();
propclass = sysprop->vftbl->class;
- mid = class_resolvemethod(propclass,
+ mid = (jmethodID)class_resolvemethod(propclass,
utf_new_char("setProperty"),
utf_new_char("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"));
if (!mid) throw_main_exception_exit();
{
switch (flag) {
case JVMTI_VERBOSE_OTHER:
- runverbose = value;
+ /* where is this defined ?
+ runverbose = value;
+ */
break;
case JVMTI_VERBOSE_GC:
opt_verbosegc = value;
0, /* can_pop_frame */
0, /* can_redefine_classes */
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- 1, /* can_signal_thread */
+ /* current implementation does not work if called from another process */
+ 0, /* can_signal_thread */
#else
0, /* can_signal_thread */
#endif
0, /* can_generate_frame_pop_events */
0, /* can_generate_breakpoint_events */
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
- 1, /* can_suspend */
+ /* current implementation does not work if called from another process */
+ 0, /* can_suspend */
#else
0, /* can_suspend */
#endif
0, /* can_generate_object_free_events */
};
-static jvmtiEnv JVMTI_EnvTable = {
+static struct jvmtiEnv_struct JVMTI_EnvTable = {
NULL,
&SetEventNotificationMode,
NULL,
&GetObjectSize
};
+
void set_jvmti_phase(jvmtiPhase p) {
genericEventData d;
- jvmtiEvent e;
- phase = p;
+ fprintf (stderr,"set JVMTI pid %d phase %d\n",getpid(),p);
+ fflush(stderr);
+
switch (p) {
case JVMTI_PHASE_ONLOAD:
- /* nothing to be done */
+ phase = p;
return;
case JVMTI_PHASE_PRIMORDIAL:
- /* nothing to be done */
+ phase = p;
return;
case JVMTI_PHASE_START:
- e = JVMTI_EVENT_VM_START;
+ phase = p;
+ d.ev = JVMTI_EVENT_VM_START;
+ /* this event is sent during start or live phase */
+ log_text("debugger process - set brk in setthreadobj");
+ setsysbrkpt(SETTHREADOBJECTBRK,(void*)&setthreadobject);
break;
case JVMTI_PHASE_LIVE:
- e = JVMTI_EVENT_VM_INIT;
- break;
+ phase = p;
+ d.ev = JVMTI_EVENT_VM_INIT;
+ break;
case JVMTI_PHASE_DEAD:
- e = JVMTI_EVENT_VM_DEATH;
+ phase = p;
+ d.ev = JVMTI_EVENT_VM_DEATH;
break;
+ default:
+ log_text("wrong jvmti phase to be set");
+ exit(1);
}
- fireEvent(e,&d);
+ fireEvent(&d);
}
jvmtiEnv* new_jvmtienv() {
environment* env;
- env = envs;
- if (env != NULL)
- while (env->next!=NULL) {
- env=env->next;
- }
- env = heap_allocate(sizeof(environment),true,NULL);
- memcpy(&(env->env),&JVMTI_EnvTable,sizeof(jvmtiEnv));
+ if (envs == NULL) {
+ envs = heap_allocate(sizeof(environment),true,NULL);
+ env = envs;
+ } else {
+ env = envs;
+ if (env != NULL)
+ while (env->next!=NULL) {
+ env=env->next;
+ }
+ env = heap_allocate(sizeof(environment),true,NULL);
+ }
+ env->env = heap_allocate(sizeof(struct jvmtiEnv_struct),true,NULL);
+ memcpy(env->env,&JVMTI_EnvTable,sizeof(struct jvmtiEnv_struct));
memset(&(env->events),JVMTI_DISABLE,(JVMTI_EVENT_END_ENUM - JVMTI_EVENT_START_ENUM)*
sizeof(jvmtiEventModeLL));
/* To possess a capability, the agent must add the capability.*/
RelinquishCapabilities(&(env->env),&(env->capabilities));
env->EnvironmentLocalStorage = NULL;
env->tls = NULL;
- return &(env->env);
+
+ return (jvmtiEnv*)env;
}
void agentload(char* opt_arg) {
char *libname, *arg;
int i=0,len;
jint retval;
+ classinfo* ci;
len = strlen(opt_arg);
/* resolve Agent_UnLoad function */
unload = lt_dlsym(handle, "Agent_Unload");
+ /* add library to native library hashtable */
+ ci = load_class_from_sysloader(utf_new_char("java.lang.Object"));
+ native_hashtable_library_add(utf_new_char(libname), ci->classloader, handle);
+
retval =
((JNIEXPORT jint JNICALL (*) (JavaVM *vm, char *options, void *reserved))
onload) ((JavaVM*) &_Jv_JNIInvokeInterface, arg, NULL);
MFREE(arg,char,len-i);
if (retval != 0) exit (retval);
-
- /* todo: native_library_hash_add(name, (java_objectheader *) loader, handle); */
}
void agentunload() {
Changes:
- $Id: jvmti.h 4357 2006-01-22 23:33:38Z twisti $
+ $Id: jvmti.h 4661 2006-03-21 00:04:59Z motse $
*/
-#ifndef JVMTI_H
-#define JVMTI_H
+#ifndef _JVMTI_H
+#define _JVMTI_H
#include "native/jni.h"
#include "native/include/java_lang_String.h"
typedef jlong jlocation;
struct _jrawMonitorID;
typedef struct _jrawMonitorID *jrawMonitorID;
-typedef struct jvmtiEnv_struct jvmtiEnv;
+typedef struct jvmtiEnv_struct *jvmtiEnv;
typedef enum {
JVMTI_ERROR_NONE = 0, /* No error has occurred. This is the error code that is
#define JVMTI_CLASS_STATUS_ARRAY 16
#define JVMTI_CLASS_STATUS_PRIMITIVE 32
-/* cacao specific */
-
-typedef struct {
- jvmtiEnv *jvmti_env;
- jthread thread;
- jmethodID method;
- jlocation location;
- jclass klass;
- jobject object;
- jfieldID field;
- char signature_type;
- jvalue value;
- jboolean b;
- void* address;
- void** new_address_ptr;
- jmethodID catch_method;
- jlocation catch_location;
- char* name;
- jobject protection_domain;
- jint jint1;
- jint jint2;
- unsigned char* class_data;
- jint* new_class_data_len;
- unsigned char** new_class_data;
- jvmtiAddrLocationMap* map;
- void* compile_info;
- jlong jlong;
-} genericEventData;
-
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-struct _jrawMonitorID {
- java_lang_String *name;
-};
-#endif
-
-jvmtiEnv* new_jvmtienv();
-void set_jvmti_phase(jvmtiPhase p);
-pid_t debuggee;
-jvmtiEnv* remotedbgjvmtienv;
-jvmtiEventCallbacks jvmti_jdwp_EventCallbacks;
-void agentload(char* opt_arg);
-void agentunload();
#endif
Changes: Christian Thalinger
- $Id: native.c 4559 2006-03-05 23:24:50Z twisti $
+ $Id: native.c 4661 2006-03-21 00:04:59Z motse $
*/
#include "native/include/java_lang_reflect_Method.h"
#include "native/include/java_lang_reflect_VMProxy.h"
#include "native/include/java_security_VMAccessController.h"
-
+#if defined(ENABLE_JVMTI)
+#include "native/include/gnu_classpath_jdwp_event_EventRequest.h"
+#include "native/include/java_nio_ByteBuffer.h"
+#include "native/include/gnu_classpath_jdwp_VMVirtualMachine.h"
+#include "native/include/gnu_classpath_jdwp_VMFrame.h"
+#include "native/include/gnu_classpath_jdwp_VMMethod.h"
+#endif
#if defined(WITH_STATIC_CLASSPATH)
(functionptr) Java_java_lang_reflect_VMProxy_generateProxyClass,
(functionptr) Java_java_security_VMAccessController_getStack,
+#if defined(ENABLE_JVMTI)
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_suspendThread,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_resumeThread,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getSuspendCount,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getAllLoadedClassesCount,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getClassStatus,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getAllClassMethods,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getClassMethod,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getFrames,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getFrame,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getFrameCount,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getThreadStatus,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getLoadRequests,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_executeMethod,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getSourceFile,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_registerEvent,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_unregisterEvent,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_clearEvents,
+ (functionptr) Java_gnu_classpath_jdwp_VMVirtualMachine_getAllLoadedClasses,
+ (functionptr) Java_gnu_classpath_jdwp_VMFrame_setValue,
+ (functionptr) Java_gnu_classpath_jdwp_VMFrame_getValue,
+ (functionptr) Java_gnu_classpath_jdwp_VMMethod_getName,
+ (functionptr) Java_gnu_classpath_jdwp_VMMethod_getSignature,
+ (functionptr) Java_gnu_classpath_jdwp_VMMethod_getModifiers,
+ (functionptr) Java_gnu_classpath_jdwp_VMMethod_getLineTable,
+ (functionptr) Java_gnu_classpath_jdwp_VMMethod_getVariableTable
+#endif
+
};
#endif /* defined(WITH_STATIC_CLASSPATH) */
##
## Changes:
##
-## $Id: Makefile.am 4627 2006-03-16 12:53:32Z twisti $
+## $Id: Makefile.am 4661 2006-03-21 00:04:59Z motse $
## Process this file with automake to produce Makefile.in
if ENABLE_JVMTI
libnativevm_la_SOURCES += \
VMFrame.c \
- VMVirtualMachine.c
+ VMVirtualMachine.c \
+ VMMethod.c
endif
Changes:
-$Id: VMVirtualMachine.c 4357 2006-01-22 23:33:38Z twisti $
+$Id: VMVirtualMachine.c 4661 2006-03-21 00:04:59Z motse $
*/
#include "native/include/gnu_classpath_jdwp_event_EventRequest.h"
#include "native/include/gnu_classpath_jdwp_VMVirtualMachine.h"
#include "native/jvmti/jvmti.h"
+#include "native/jvmti/cacaodbg.h"
+#include <string.h>
/*
*/
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_suspendThread(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1)
{
- remotedbgjvmtienv->SuspendThread(remotedbgjvmtienv, (jthread) par1);
+ (*remotedbgjvmtienv)->SuspendThread(remotedbgjvmtienv, (jthread) par1);
}
/*
*/
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_resumeThread(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1)
{
- remotedbgjvmtienv->ResumeThread(remotedbgjvmtienv, (jthread) par1);
+ (*remotedbgjvmtienv)->ResumeThread(remotedbgjvmtienv, (jthread) par1);
}
* Signature: (Ljava/lang/Thread;)I
*/
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getSuspendCount(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
- return 0;
+ log_text ("VMVirtualMachine_getSuspendCount: not supported");
+ return 1;
}
/*
jint count;
jclass* classes;
- remotedbgjvmtienv->GetLoadedClasses(remotedbgjvmtienv, &count, &classes);
+ (*remotedbgjvmtienv)->GetLoadedClasses(remotedbgjvmtienv, &count, &classes);
return count;
}
+/*
+ * Class: gnu_classpath_jdwp_VMVirtualMachine
+ * Method: getAllLoadedClasses
+ * Signature: ()Ljava/util/Iterator
+ */
+JNIEXPORT struct java_util_Iterator* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getAllLoadedClasses(JNIEnv *env, jclass clazz) {
+ jclass *classes, *cl;
+ jint classcount;
+ jobjectArray joa;
+/* jthrowable e;*/
+ jmethodID m;
+ jobject *ol,*oi;
+ int i;
+ jvmtiError err;
+ char* errdesc;
+
+ if (JVMTI_ERROR_NONE != (err= (*remotedbgjvmtienv)->
+ GetLoadedClasses(remotedbgjvmtienv, &classcount, &classes))) {
+ (*remotedbgjvmtienv)->GetErrorName(remotedbgjvmtienv,err, &errdesc);
+ fprintf(stderr,"jvmti error: %s\n",errdesc);
+ fflush(stderr);
+/* env->ThrowNew(env,ec,"jvmti error occoured");*/
+ }
+
+ cl = (*env)->FindClass(env,"java.lang.Class");
+
+ /* Arrays.asList(Object[] classes)->List.Iterator()->Iterator */
+ joa = (*env)->NewObjectArray(env, (jsize)classcount, cl , NULL);
+
+ for (i = 0; i < classcount; i++)
+ (*env)->SetObjectArrayElement(env,joa,(jsize)i, (jobject)classes[i]);
+
+ cl = (*env)->FindClass(env,"java.util.Arrays");
+ if (!cl) return NULL;
+
+ m = (*env)->GetStaticMethodID(env, cl, "asList", "([Ljava/lang/Object;)Ljava/util/List;");
+ if (!m) return NULL;
+
+ ol = (*env)->CallStaticObjectMethod(env,(jclass)cl,m,joa);
+ if (!ol) return NULL;
+
+ cl = (*env)->FindClass(env,"java.util.List");
+ if (!cl) return NULL;
+ m = (*env)->GetMethodID(env,cl,"Iterator","()Ljava/util/Iterator;");
+
+ oi = (*env)->CallObjectMethod(env,*ol,m);
+
+ return (struct java_util_Iterator*)oi;
+}
+
/* Class: gnu/classpath/jdwp/VMVirtualMachine
* Method: getClassStatus
* Signature: (Ljava/lang/Class;)I
*/
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getClassStatus(JNIEnv *env, jclass clazz, struct java_lang_Class* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
- return 0;
+ jint status;
+ (*remotedbgjvmtienv)->GetClassStatus(remotedbgjvmtienv, (jclass) par1, &status);
+ return status;
+}
+
+/*
+ * Class: gnu/classpath/jdwp/VMVirtualMachine
+ * Method: getAllClassMethods
+ * Signature: (Ljava/lang/Class;)[Lgnu/classpath/jdwp/VMMethod;
+ */
+JNIEXPORT java_objectarray* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getAllClassMethods(JNIEnv *env, jclass clazz, struct java_lang_Class* par1) {
+ log_text ("VMVirtualMachine_getAllClassMethods: IMPLEMENT ME !!!");
+}
+
+
+/*
+ * Class: gnu/classpath/jdwp/VMVirtualMachine
+ * Method: getClassMethod
+ * Signature: (Ljava/lang/Class;J)Lgnu/classpath/jdwp/VMMethod;
+ */
+JNIEXPORT struct gnu_classpath_jdwp_VMMethod* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getClassMethod(JNIEnv *env, jclass clazz, struct java_lang_Class* par1, s8 par2) {
+ log_text ("VMVirtualMachine_getAllClassMethod: IMPLEMENT ME !!!");
}
* Signature: (Ljava/lang/Thread;II)Ljava/util/ArrayList;
*/
JNIEXPORT struct java_util_ArrayList* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrames(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1, s4 par2, s4 par3) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
+ log_text ("VMVirtualMachine_getFrames - IMPLEMENT ME!!!");
+/* jclass ec = (*env)->FindClass(env,"gnu/classpath/jdwp/JdwpInternalErrorException");
+ if (JVMTI_ERROR_NONE != (*remotedbgjvmtienv)->GetClassStatus(remotedbgjvmtienv, par1, &status))
+ env->ThrowNew(env,ec,"jvmti error occoured");*/
return 0;
}
* Signature: (Ljava/lang/Thread;Ljava/nio/ByteBuffer;)Lgnu/classpath/jdwp/VMFrame;
*/
JNIEXPORT struct gnu_classpath_jdwp_VMFrame* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrame(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1, struct java_nio_ByteBuffer* par2) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
+ log_text ("VMVirtualMachine_getFrame - IMPLEMENT ME!!!");
return 0;
}
* Signature: (Ljava/lang/Thread;)I
*/
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrameCount(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
- return 0;
+ jint count;
+ (*remotedbgjvmtienv)->GetFrameCount(remotedbgjvmtienv, (jthread)par1, &count);
+ return count;
}
* Signature: (Ljava/lang/Thread;)I
*/
JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getThreadStatus(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
- return 0;
+ jint status;
+ if (JVMTI_ERROR_NONE != (*remotedbgjvmtienv)->GetThreadState(remotedbgjvmtienv, (jthread)par1, &status))
+ return 0;
+ if (status && JVMTI_THREAD_STATE_ALIVE) {
+ if (status && JVMTI_THREAD_STATE_WAITING) {
+ return 4; /* WAIT - see JdwpConstants */
+ }
+ if (status && JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) {
+ return 3; /* MONITOR - see JdwpConstants */
+ }
+ if (status && JVMTI_THREAD_STATE_SLEEPING) {
+ return 2; /* SLEEPING - see JdwpConstants */
+ }
+ return 1; /* RUNNING - see JdwpConstants */
+ } else
+ return 0; /* ZOMBIE - see JdwpConstants */
+ return -1; /* some error */
}
* Signature: (Ljava/lang/ClassLoader;)Ljava/util/ArrayList;
*/
JNIEXPORT struct java_util_ArrayList* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getLoadRequests(JNIEnv *env, jclass clazz, struct java_lang_ClassLoader* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
+ log_text ("VMVirtualMachine_getLoadRequests(");
return 0;
}
* Signature: (Ljava/lang/Object;Ljava/lang/Thread;Ljava/lang/Class;Ljava/lang/reflect/Method;[Ljava/lang/Object;Z)Lgnu/classpath/jdwp/util/MethodResult;
*/
JNIEXPORT struct gnu_classpath_jdwp_util_MethodResult* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_executeMethod(JNIEnv *env, jclass clazz, struct java_lang_Object* par1, struct java_lang_Thread* par2, struct java_lang_Class* par3, struct java_lang_reflect_Method* par4, java_objectarray* par5, s4 par6) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
- return 0;
-}
-
-
-/*
- * Class: gnu/classpath/jdwp/VMVirtualMachine
- * Method: getVarTable
- * Signature: (Ljava/lang/Class;Ljava/lang/reflect/Method;)Lgnu/classpath/jdwp/util/VariableTable;
- */
-JNIEXPORT struct gnu_classpath_jdwp_util_VariableTable* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getVarTable(JNIEnv *env, jclass clazz, struct java_lang_Class* par1, struct java_lang_reflect_Method* par2) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
- return 0;
-}
-
-
-/*
- * Class: gnu/classpath/jdwp/VMVirtualMachine
- * Method: getLineTable
- * Signature: (Ljava/lang/Class;Ljava/lang/reflect/Method;)Lgnu/classpath/jdwp/util/LineTable;
- */
-JNIEXPORT struct gnu_classpath_jdwp_util_LineTable* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getLineTable(JNIEnv *env, jclass clazz, struct java_lang_Class* par1, struct java_lang_reflect_Method* par2) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
+ log_text ("VMVirtualMachine_executeMethod");
return 0;
}
* Signature: (Ljava/lang/Class;)Ljava/lang/String;
*/
JNIEXPORT struct java_lang_String* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getSourceFile(JNIEnv *env, jclass clazz, struct java_lang_Class* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
- return 0;
+ char* srcname;
+ jstring str;
+
+ (*remotedbgjvmtienv)->
+ GetSourceFileName(remotedbgjvmtienv, (jclass)par1, &srcname);
+ str = (*env)->NewString(env,(jchar*)srcname,(jsize)strlen(srcname));
+
+ return (struct java_lang_String*)str;
}
+/* match JdwpConstants.EventKind to jvmtiEvent constants */
+static jvmtiEvent EventKind2jvmtiEvent(jbyte kind){
+ switch (kind) {
+ case /* SINGLE_STEP */ 1: return JVMTI_EVENT_SINGLE_STEP;
+ case /* BREAKPOINT */ 2: return JVMTI_EVENT_BREAKPOINT;
+ case /* FRAME_POP */ 3: return JVMTI_EVENT_FRAME_POP;
+ case /* EXCEPTION */ 4: return JVMTI_EVENT_EXCEPTION;
+ case /* USER_DEFINED */ 5: return -1; /* can this be matched ? */
+ case /* THREAD_START */ 6: return JVMTI_EVENT_THREAD_START;
+ case /* THREAD_END */ 7: return JVMTI_EVENT_THREAD_END;
+ case /* CLASS_PREPARE */ 8: return JVMTI_EVENT_CLASS_PREPARE;
+ case /* CLASS_UNLOAD */ 9: return -1; /* can this be matched ? */
+ case /* CLASS_LOAD */ 10: return JVMTI_EVENT_CLASS_LOAD;
+ case /* FIELD_ACCESS */ 20: return JVMTI_EVENT_FIELD_ACCESS;
+ case /* FIELD_MODIFICATION */ 21: return JVMTI_EVENT_FIELD_MODIFICATION;
+ case /* EXCEPTION_CATCH */ 30: return JVMTI_EVENT_EXCEPTION_CATCH;
+ case /* METHOD_ENTRY */ 40: return JVMTI_EVENT_METHOD_ENTRY;
+ case /* METHOD_EXIT */ 41: return JVMTI_EVENT_METHOD_EXIT;
+ case /* VM_INIT */ 90: return JVMTI_EVENT_VM_INIT;
+ case /* VM_DEATH */ 99: return JVMTI_EVENT_VM_DEATH;
+ case /* VM_DISCONNECTED */ 100: return -1; /* can this be matched ? */
+ default: return -1;
+ }
+}
/*
* Class: gnu/classpath/jdwp/VMVirtualMachine
* Signature: (Lgnu/classpath/jdwp/event/EventRequest;)V
*/
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_registerEvent(JNIEnv *env, jclass clazz, struct gnu_classpath_jdwp_event_EventRequest* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
+ jbyte kind;
+ jfieldID kindid;
+ jclass erc;
+
+ erc = (*env)->FindClass(env,"gnu.classpath.jdwp.event.EventRequest");
+
+ kindid = (*env)->GetFieldID(env, erc, "_kind", "B");
+ kind = (*env)->GetByteField(env, (jobject)par1, kindid);
+
+ (*remotedbgjvmtienv)->
+ SetEventNotificationMode(remotedbgjvmtienv, JVMTI_ENABLE,
+ EventKind2jvmtiEvent(kind), NULL);
+
+ /* todo: error handling, suspend policy */
}
* Signature: (Lgnu/classpath/jdwp/event/EventRequest;)V
*/
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_unregisterEvent(JNIEnv *env, jclass clazz, struct gnu_classpath_jdwp_event_EventRequest* par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
+ jbyte kind;
+ jfieldID kindid;
+ jclass erc;
+
+ erc = (*env)->FindClass(env,"gnu.classpath.jdwp.event.EventRequest");
+
+ kindid = (*env)->GetFieldID(env, erc, "_kind", "B");
+ kind = (*env)->GetByteField(env, (jobject)par1, kindid);
+
+ (*remotedbgjvmtienv)->
+ SetEventNotificationMode(remotedbgjvmtienv, JVMTI_DISABLE,
+ EventKind2jvmtiEvent(kind), NULL);
+
+ /* todo: error handling, suspend policy */
}
* Signature: (B)V
*/
JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_clearEvents(JNIEnv *env, jclass clazz, s4 par1) {
- log_text ("JVMTI-Call: IMPLEMENT ME!!!");
+ /* jvmti events are not saved */
+ log_text ("VMVirtualMachine_clearEvents IMPLEMENT ME!!!");
}
Changes: Christian Thalinger
Edwin Steiner
- $Id: threads.c 4559 2006-03-05 23:24:50Z twisti $
+ $Id: threads.c 4661 2006-03-21 00:04:59Z motse $
*/
}
#endif
+#if !defined(ENABLE_JVMTI)
static void setthreadobject(threadobject *thread)
+#else
+void setthreadobject(threadobject *thread)
+#endif
{
#if !defined(HAVE___THREAD)
pthread_setspecific(tkey_threadinfo, thread);
Changes: Christian Thalinger
- $Id: threads.h 4475 2006-02-06 21:06:12Z twisti $
+ $Id: threads.h 4661 2006-03-21 00:04:59Z motse $
*/
bool interruptedThread();
bool isInterruptedThread(java_lang_VMThread *);
+#if defined(ENABLE_JVMTI)
+void setthreadobject(threadobject *thread);
+#endif
+
+
/* This must not be changed, it is used in asm_criticalsections */
typedef struct {
u1 *mcodebegin;
#include "vm/jit/asmpart.h"
#include "vm/jit/profile/profile.h"
+#if defined(ENABLE_JVMTI)
+#include "native/jvmti/cacaodbg.h"
+#endif
/* Invocation API variables ***************************************************/
#ifdef ENABLE_JVMTI
OPT_DEBUG,
+ OPT_XRUNJDWP,
+ OPT_NOAGENT,
OPT_AGENTLIB,
OPT_AGENTPATH,
#endif
{ "Xbootclasspath/p:", true, OPT_BOOTCLASSPATH_P },
#ifdef ENABLE_JVMTI
{ "Xdebug", false, OPT_DEBUG },
+ { "Xnoagent", false, OPT_NOAGENT },
+ { "Xrunjdwp", true, OPT_XRUNJDWP },
#endif
{ "Xms", true, OPT_MS },
{ "ms", true, OPT_MS },
puts(" -Xss<size> set the thread stack size (default: 128kB)");
puts(" -Xprof[:bb] collect and print profiling data");
#if defined(ENABLE_JVMTI)
- puts(" -Xdebug<transport> enable remote debugging");
+ /* -Xdebug option depend on gnu classpath JDWP options. options:
+ transport=dt_socket,address=<hostname:port>,server=(y|n),suspend(y|n) */
+ puts(" -Xdebug enable remote debugging\n");
+ puts(" -Xrunjdwp transport=[dt_socket|...],address=<hostname:port>,server=[y|n],suspend=[y|n]\n");
+ puts(" enable remote debugging\n");
#endif
/* exit with error code */
nogc_init(HEAP_MAXSIZE, HEAP_STARTSIZE);
#endif
+
/* set the bootclasspath */
cp = getenv("BOOTCLASSPATH");
heapstartsize = HEAP_STARTSIZE;
opt_stacksize = STACK_SIZE;
+
+#if defined(ENABLE_JVMTI)
+ /* initialize JVMTI related **********************************************/
+ jvmtibrkpt.brk=NULL;
+ jvmtibrkpt.num=0;
+ jvmtibrkpt.size=0;
+ jdwp = jvmti = dbgprocess = false;
+#endif
+
/* initialize properties before commandline handling */
if (!properties_init())
#if defined(ENABLE_JVMTI)
case OPT_DEBUG:
- dbg = true;
+ jdwp=true;
+ break;
+ case OPT_NOAGENT:
+ /* I don't know yet what Xnoagent should do. This is only for
+ compatiblity with eclipse - motse */
+ break;
+ case OPT_XRUNJDWP:
transport = opt_arg;
+ j=0;
+ while (transport[j]!='=') j++;
+ j++;
+ while (j<strlen(transport)) {
+ if (strncmp("suspend=",&transport[j],8)==0) {
+ if ((j+8)>=strlen(transport) ||
+ (transport[j+8]!= 'y' && transport[j+8]!= 'n')) {
+ printf("bad Xrunjdwp option: -Xrunjdwp%s\n",transport);
+ usage();
+ break;
+ }
+ else {
+ suspend = transport[j+8] == 'y';
+ break;
+ }
+ }
+ while (transport[j]!=',') j++;
+ j++;
+ }
+
break;
-
case OPT_AGENTPATH:
case OPT_AGENTLIB:
- set_jvmti_phase(JVMTI_PHASE_ONLOAD);
- agentload(opt_arg);
- set_jvmti_phase(JVMTI_PHASE_PRIMORDIAL);
+ jvmti=true;
+ agentarg = opt_arg;
break;
#endif
}
}
+#if defined(ENABLE_JVMTI)
+ /* The fork has to occure before threads a created because threads are
+ not forked correctly (see man pthread_atfork). Varibale dbgprocess
+ stores information whether this is the debugger or debuggee process. */
+ if (jvmti || jdwp) {
+ set_jvmti_phase(JVMTI_PHASE_ONLOAD);
+ dbgprocess = cacaodbgfork();
+ }
+
+ if (dbgprocess && jvmti) { /* is this the parent/debugger process ? */
+ agentload(agentarg);
+ set_jvmti_phase(JVMTI_PHASE_PRIMORDIAL);
+ }
+#endif
+
/* initialize this JVM ****************************************************/
assert(class_java_lang_System->state & CLASS_LOADED);
#if defined(ENABLE_JVMTI)
- set_jvmti_phase(JVMTI_PHASE_DEAD);
- agentunload();
+ if (dbgprocess) {
+ set_jvmti_phase(JVMTI_PHASE_DEAD);
+ if (jvmti) agentunload();
+ }
#endif
if (!link_class(class_java_lang_System))
void vm_shutdown(s4 status)
{
#if defined(ENABLE_JVMTI)
- agentunload();
+ if (dbgprocess) {
+ set_jvmti_phase(JVMTI_PHASE_DEAD);
+ if (jvmti) agentunload();
+ ipcrm();
+ }
#endif
-
if (opt_verbose || getcompilingtime || opt_stat) {
log_text("CACAO terminated by shutdown");
dolog("Exit status: %d\n", (s4) status);
void vm_exit_handler(void)
{
+#if defined(ENABLE_JVMTI)
+ if (jvmti && jdwp) set_jvmti_phase(JVMTI_PHASE_DEAD);
+ if (jvmti) agentunload();
+ ipcrm();
+#endif
+
#if !defined(NDEBUG)
if (showmethods)
class_showmethods(mainclass);