From 512e8d95ab6004592f83d8fcfb46f959944caa42 Mon Sep 17 00:00:00 2001 From: motse Date: Tue, 21 Mar 2006 00:04:59 +0000 Subject: [PATCH] major rework of jvmti. now we have three processes in jvmti mode. there are still many debug statements --- src/cacao/cacao.c | 145 ++----- src/native/jni.h | 5 +- src/native/jvmti/Makefile.am | 10 +- src/native/jvmti/VMjdwp.c | 151 +++++-- src/native/jvmti/cacaodbg.c | 670 ++++++++++++++++++++++++++++++ src/native/jvmti/cacaodbg.h | 159 +++++++ src/native/jvmti/cacaodbgserver.c | 314 ++++++++++++++ src/native/jvmti/cacaodbgserver.h | 110 +++++ src/native/jvmti/dbg.c | 84 ++++ src/native/jvmti/dbg.h | 41 +- src/native/jvmti/jvmti.c | 412 +++++++++++------- src/native/jvmti/jvmti.h | 50 +-- src/native/native.c | 38 +- src/native/vm/Makefile.am | 5 +- src/native/vm/VMVirtualMachine.c | 212 ++++++++-- src/threads/native/threads.c | 6 +- src/threads/native/threads.h | 7 +- src/vm/vm.c | 91 +++- 18 files changed, 2093 insertions(+), 417 deletions(-) create mode 100644 src/native/jvmti/cacaodbg.c create mode 100644 src/native/jvmti/cacaodbg.h create mode 100644 src/native/jvmti/cacaodbgserver.c create mode 100644 src/native/jvmti/cacaodbgserver.h create mode 100644 src/native/jvmti/dbg.c diff --git a/src/cacao/cacao.c b/src/cacao/cacao.c index 12e00846b..154d1a999 100644 --- a/src/cacao/cacao.c +++ b/src/cacao/cacao.c @@ -31,7 +31,7 @@ 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 $ */ @@ -49,10 +49,10 @@ #if defined(ENABLE_JVMTI) #include "native/jvmti/jvmti.h" -#include "native/jvmti/dbg.h" -#include -#include -#include +#include "native/jvmti/cacaodbg.h" +#if defined(USE_THREADS) && defined(NATIVE_THREADS) +#include +#endif #endif #include "toolbox/logging.h" @@ -72,74 +72,10 @@ #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. @@ -241,7 +177,6 @@ static char *getmainclassnamefromjar(char *mainstring) return javastring_tochar(o); } - void exit_handler(void); @@ -253,7 +188,9 @@ void exit_handler(void); int main(int argc, char **argv) { +#if defined(USE_THREADS) && !defined(NATIVE_THREADS) void *dummy; +#endif s4 i; /* local variables ********************************************************/ @@ -261,10 +198,11 @@ int main(int argc, char **argv) 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; igroup->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? */ diff --git a/src/native/jni.h b/src/native/jni.h index 8ab484cb8..31a97446a 100644 --- a/src/native/jni.h +++ b/src/native/jni.h @@ -29,7 +29,7 @@ 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 $ */ @@ -110,9 +110,6 @@ bool jni_init(void); 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 */ diff --git a/src/native/jvmti/Makefile.am b/src/native/jvmti/Makefile.am index a0e48696f..b9ce4697a 100644 --- a/src/native/jvmti/Makefile.am +++ b/src/native/jvmti/Makefile.am @@ -28,7 +28,7 @@ ## ## 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 @@ -40,7 +40,13 @@ libjvmti_la_SOURCES = \ jvmti.c \ jvmti.h \ VMjdwp.c \ - dbg.h + dbg.h\ + dbg.c\ + cacaodbg.h \ + cacaodbg.c \ + cacaodbgserver.c \ + cacaodbgserver.h + ## Local variables: diff --git a/src/native/jvmti/VMjdwp.c b/src/native/jvmti/VMjdwp.c index 030c12530..34811dcf8 100644 --- a/src/native/jvmti/VMjdwp.c +++ b/src/native/jvmti/VMjdwp.c @@ -29,38 +29,56 @@ 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 + + +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(); + } @@ -161,7 +179,24 @@ static void ExceptionCatch (jvmtiEnv *jvmti_env, 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,"","(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, @@ -199,13 +234,35 @@ static void ClassFileLoadHook (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,"", + "(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, @@ -294,7 +351,49 @@ static void GarbageCollectionFinish (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, @@ -302,7 +401,7 @@ jvmtiEventCallbacks jvmti_jdwp_EventCallbacks = { &ClassFileLoadHook, &ClassLoad, &ClassPrepare, - &VMStart, + NULL, /* &VMStart */ &Exception, &ExceptionCatch, &SingleStep, diff --git a/src/native/jvmti/cacaodbg.c b/src/native/jvmti/cacaodbg.c new file mode 100644 index 000000000..cb0ad4b33 --- /dev/null +++ b/src/native/jvmti/cacaodbg.c @@ -0,0 +1,670 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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;iebp < (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 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) && (irunning = 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: + */ diff --git a/src/native/jvmti/cacaodbg.h b/src/native/jvmti/cacaodbg.h new file mode 100644 index 000000000..cf84fecb9 --- /dev/null +++ b/src/native/jvmti/cacaodbg.h @@ -0,0 +1,159 @@ +/* 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: + */ diff --git a/src/native/jvmti/cacaodbgserver.c b/src/native/jvmti/cacaodbgserver.c new file mode 100644 index 000000000..d05b35645 --- /dev/null +++ b/src/native/jvmti/cacaodbgserver.c @@ -0,0 +1,314 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* 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; ihastostop); + 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: + */ diff --git a/src/native/jvmti/cacaodbgserver.h b/src/native/jvmti/cacaodbgserver.h new file mode 100644 index 000000000..dd39fc7da --- /dev/null +++ b/src/native/jvmti/cacaodbgserver.h @@ -0,0 +1,110 @@ +/* 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 + +/* 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: + */ diff --git a/src/native/jvmti/dbg.c b/src/native/jvmti/dbg.c new file mode 100644 index 000000000..4f669fa4c --- /dev/null +++ b/src/native/jvmti/dbg.c @@ -0,0 +1,84 @@ +/* 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 +#include + +#include + +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: + */ diff --git a/src/native/jvmti/dbg.h b/src/native/jvmti/dbg.h index 6313e1364..44370c39e 100644 --- a/src/native/jvmti/dbg.h +++ b/src/native/jvmti/dbg.h @@ -29,23 +29,46 @@ 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 #include #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: + */ diff --git a/src/native/jvmti/jvmti.c b/src/native/jvmti/jvmti.c index d8e3f2130..d4e673d4f 100644 --- a/src/native/jvmti/jvmti.c +++ b/src/native/jvmti/jvmti.c @@ -1,5 +1,5 @@ -/* 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, @@ -30,23 +30,25 @@ 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 #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" @@ -59,7 +61,8 @@ #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 #include @@ -68,6 +71,7 @@ #include #include #include +#include #include #include @@ -111,8 +115,7 @@ struct _environment { environment *next; }; - -static jvmtiEnv JVMTI_EnvTable; +static struct jvmtiEnv_struct JVMTI_EnvTable; static jvmtiCapabilities JVMTI_Capabilities; static lt_ptr unload; @@ -121,14 +124,40 @@ 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: @@ -160,7 +189,7 @@ static void execcallback(jvmtiEvent e, functionptr ec, genericEventData* data) { 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: @@ -309,27 +338,19 @@ static void execcallback(jvmtiEvent e, functionptr ec, genericEventData* data) { } } -/* 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 */ @@ -342,7 +363,7 @@ void fireEvent(jvmtiEvent e, genericEventData* data) { 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); } @@ -352,21 +373,30 @@ void fireEvent(jvmtiEvent e, genericEventData* 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 **************************************************** @@ -387,11 +417,11 @@ SetEventNotificationMode (jvmtiEnv * env, jvmtiEventMode mode, 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)) @@ -486,7 +516,6 @@ SetEventNotificationMode (jvmtiEnv * env, jvmtiEventMode mode, return JVMTI_ERROR_NONE; } - /* GetAllThreads *************************************************************** Get all live threads @@ -497,8 +526,11 @@ jvmtiError 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) @@ -507,27 +539,15 @@ GetAllThreads (jvmtiEnv * env, jint * threads_count_ptr, 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; } @@ -546,9 +566,15 @@ SuspendThread (jvmtiEnv * env, jthread thread) 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; } @@ -567,10 +593,15 @@ ResumeThread (jvmtiEnv * env, jthread thread) 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; } @@ -613,7 +644,7 @@ InterruptThread (jvmtiEnv * env, jthread thread) 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 @@ -631,22 +662,27 @@ InterruptThread (jvmtiEnv * env, jthread thread) 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; } @@ -663,8 +699,11 @@ GetOwnedMonitorInfo (jvmtiEnv * env, jthread thread, 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) @@ -683,9 +722,12 @@ GetOwnedMonitorInfo (jvmtiEnv * env, jthread thread, 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; jheader.size; j++) { @@ -779,7 +821,7 @@ typedef struct { 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; } @@ -805,7 +847,8 @@ RunAgentThread (jvmtiEnv * env, jthread thread, jvmtiStartFunction proc, 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; @@ -822,7 +865,8 @@ RunAgentThread (jvmtiEnv * env, jthread thread, jvmtiStartFunction 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); } @@ -986,16 +1030,12 @@ GetThreadGroupChildren (jvmtiEnv * env, jthreadGroup group, 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; } @@ -1009,7 +1049,7 @@ static jvmtiError getcacaostacktrace(stackTraceBuffer** trace, jthread thread) { jvmtiError GetFrameCount (jvmtiEnv * env, jthread thread, jint * count_ptr) { - stackTraceBuffer* trace; + char* trace; jvmtiError er; CHECK_PHASE_START @@ -1026,7 +1066,7 @@ GetFrameCount (jvmtiEnv * env, jthread thread, jint * count_ptr) er = getcacaostacktrace(&trace, thread); if (er==JVMTI_ERROR_NONE) return er; - *count_ptr = trace->size; +/* todo: *count_ptr = trace->size;*/ return JVMTI_ERROR_NONE; } @@ -1042,6 +1082,8 @@ jvmtiError 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; @@ -1060,8 +1102,18 @@ GetThreadState (jvmtiEnv * env, jthread thread, jint * thread_state_ptr) } 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; @@ -1535,6 +1587,7 @@ SetBreakpoint (jvmtiEnv * env, jmethodID method, jlocation location) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_breakpoint_events) + /* addbrkpt */ log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } @@ -1736,12 +1789,13 @@ GetClassStatus (jvmtiEnv * env, jclass klass, jint * status_ptr) *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) @@ -1774,11 +1828,12 @@ GetSourceFileName (jvmtiEnv * env, jclass klass, char **source_name_ptr) 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; } @@ -2268,7 +2323,7 @@ GetArgumentsSize (jvmtiEnv * env, jmethodID method, jint * size_ptr) 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; } @@ -2306,7 +2361,7 @@ GetLineNumberTable (jvmtiEnv * env, jmethodID method, 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; } @@ -2461,12 +2516,16 @@ IsMethodSynthetic (jvmtiEnv * env, jmethodID method, *******************************************************************************/ 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; @@ -2474,19 +2533,38 @@ GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, 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; isize; 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(jentries); *classes_ptr[j]=cce->classobj; j++; } @@ -2496,7 +2574,11 @@ GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, } } - tables_unlock(); + log_text ("GetLoadedClasses continue"); + + contdebuggee(0); + + log_text ("GetLoadedClasses finished"); return JVMTI_ERROR_NONE; } @@ -2513,6 +2595,8 @@ jvmtiError 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; @@ -2696,9 +2780,9 @@ GetStackTrace (jvmtiEnv * env, jthread thread, jint start_depth, 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) @@ -2717,14 +2801,14 @@ GetStackTrace (jvmtiEnv * env, jthread thread, jint start_depth, 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;isize;i++,j++) { +/* for (i=start_depth, j=0;isize;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; } @@ -3084,8 +3168,8 @@ SetJNIFunctionTable (jvmtiEnv * env, 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; } @@ -3108,7 +3192,7 @@ GetJNIFunctionTable (jvmtiEnv * env, jniNativeInterface ** function_table) 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; } @@ -3131,8 +3215,8 @@ SetEventCallbacks (jvmtiEnv * env, 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)); } @@ -3402,8 +3486,7 @@ GetJLocationFormat (jvmtiEnv * env, jvmtiJlocationFormat * format_ptr) 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; @@ -3422,18 +3505,18 @@ GetSystemProperties (jvmtiEnv * env, jint * count_ptr, char ***property_ptr) 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(); @@ -3442,7 +3525,7 @@ GetSystemProperties (jvmtiEnv * env, jint * count_ptr, char ***property_ptr) _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(); @@ -3450,12 +3533,12 @@ GetSystemProperties (jvmtiEnv * env, jint * count_ptr, char ***property_ptr) 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(); @@ -3499,7 +3582,7 @@ GetSystemProperty (jvmtiEnv * env, const char *property, char **value_ptr) 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(); @@ -3508,7 +3591,7 @@ GetSystemProperty (jvmtiEnv * env, const char *property, char **value_ptr) 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(); @@ -3549,7 +3632,7 @@ SetSystemProperty (jvmtiEnv * env, const char *property, const char *value) 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(); @@ -3558,7 +3641,7 @@ SetSystemProperty (jvmtiEnv * env, const char *property, const char *value) 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(); @@ -3954,7 +4037,9 @@ SetVerboseFlag (jvmtiEnv * env, jvmtiVerboseFlag flag, jboolean value) { switch (flag) { case JVMTI_VERBOSE_OTHER: - runverbose = value; + /* where is this defined ? + runverbose = value; + */ break; case JVMTI_VERBOSE_GC: opt_verbosegc = value; @@ -4019,7 +4104,8 @@ static jvmtiCapabilities JVMTI_Capabilities = { 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 @@ -4033,7 +4119,8 @@ static jvmtiCapabilities JVMTI_Capabilities = { 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 @@ -4051,7 +4138,7 @@ static jvmtiCapabilities JVMTI_Capabilities = { 0, /* can_generate_object_free_events */ }; -static jvmtiEnv JVMTI_EnvTable = { +static struct jvmtiEnv_struct JVMTI_EnvTable = { NULL, &SetEventNotificationMode, NULL, @@ -4208,42 +4295,59 @@ static jvmtiEnv JVMTI_EnvTable = { &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.*/ @@ -4251,7 +4355,8 @@ jvmtiEnv* new_jvmtienv() { RelinquishCapabilities(&(env->env),&(env->capabilities)); env->EnvironmentLocalStorage = NULL; env->tls = NULL; - return &(env->env); + + return (jvmtiEnv*)env; } void agentload(char* opt_arg) { @@ -4260,6 +4365,7 @@ void agentload(char* opt_arg) { char *libname, *arg; int i=0,len; jint retval; + classinfo* ci; len = strlen(opt_arg); @@ -4287,6 +4393,10 @@ void agentload(char* 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); @@ -4295,8 +4405,6 @@ void agentload(char* opt_arg) { MFREE(arg,char,len-i); if (retval != 0) exit (retval); - - /* todo: native_library_hash_add(name, (java_objectheader *) loader, handle); */ } void agentunload() { diff --git a/src/native/jvmti/jvmti.h b/src/native/jvmti/jvmti.h index ee26ad38d..3781e4635 100644 --- a/src/native/jvmti/jvmti.h +++ b/src/native/jvmti/jvmti.h @@ -30,11 +30,11 @@ 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" @@ -47,7 +47,7 @@ typedef jobject jthreadGroup; 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 @@ -1177,48 +1177,6 @@ struct jvmtiEnv_struct { #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 diff --git a/src/native/native.c b/src/native/native.c index 5ed7498e5..0e6062219 100644 --- a/src/native/native.c +++ b/src/native/native.c @@ -30,7 +30,7 @@ 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 $ */ @@ -87,7 +87,13 @@ #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) @@ -222,6 +228,34 @@ static functionptr dummynativetable[] = { (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) */ diff --git a/src/native/vm/Makefile.am b/src/native/vm/Makefile.am index f8c51c005..580370a89 100644 --- a/src/native/vm/Makefile.am +++ b/src/native/vm/Makefile.am @@ -28,7 +28,7 @@ ## ## 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 @@ -58,7 +58,8 @@ libnativevm_la_SOURCES = \ if ENABLE_JVMTI libnativevm_la_SOURCES += \ VMFrame.c \ - VMVirtualMachine.c + VMVirtualMachine.c \ + VMMethod.c endif diff --git a/src/native/vm/VMVirtualMachine.c b/src/native/vm/VMVirtualMachine.c index 49e376b76..0a5bfaa37 100644 --- a/src/native/vm/VMVirtualMachine.c +++ b/src/native/vm/VMVirtualMachine.c @@ -29,7 +29,7 @@ Authors: Martin Platter Changes: -$Id: VMVirtualMachine.c 4357 2006-01-22 23:33:38Z twisti $ +$Id: VMVirtualMachine.c 4661 2006-03-21 00:04:59Z motse $ */ @@ -43,6 +43,8 @@ $Id: VMVirtualMachine.c 4357 2006-01-22 23:33:38Z twisti $ #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 /* @@ -52,7 +54,7 @@ $Id: VMVirtualMachine.c 4357 2006-01-22 23:33:38Z twisti $ */ 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); } /* @@ -62,7 +64,7 @@ JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_suspendThread(JN */ 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); } @@ -72,8 +74,8 @@ JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_resumeThread(JNI * 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; } /* @@ -85,17 +87,87 @@ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getAllLoadedClasse 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 !!!"); } @@ -105,7 +177,10 @@ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getClassStatus(JNI * 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; } @@ -116,7 +191,7 @@ JNIEXPORT struct java_util_ArrayList* JNICALL Java_gnu_classpath_jdwp_VMVirtualM * 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; } @@ -127,8 +202,9 @@ JNIEXPORT struct gnu_classpath_jdwp_VMFrame* JNICALL Java_gnu_classpath_jdwp_VMV * 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; } @@ -138,8 +214,23 @@ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrameCount(JNIE * 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 */ } @@ -149,7 +240,7 @@ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getThreadStatus(JN * 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; } @@ -160,29 +251,7 @@ JNIEXPORT struct java_util_ArrayList* JNICALL Java_gnu_classpath_jdwp_VMVirtualM * 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; } @@ -193,10 +262,40 @@ JNIEXPORT struct gnu_classpath_jdwp_util_LineTable* JNICALL Java_gnu_classpath_j * 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 @@ -204,7 +303,20 @@ JNIEXPORT struct java_lang_String* JNICALL Java_gnu_classpath_jdwp_VMVirtualMach * 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 */ } @@ -214,7 +326,20 @@ JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_registerEvent(JN * 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 */ } @@ -224,7 +349,8 @@ JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_unregisterEvent( * 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!!!"); } diff --git a/src/threads/native/threads.c b/src/threads/native/threads.c index b696bd3df..1be6857c1 100644 --- a/src/threads/native/threads.c +++ b/src/threads/native/threads.c @@ -29,7 +29,7 @@ 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 $ */ @@ -463,7 +463,11 @@ int cacao_suspendhandler(ucontext_t *ctx) } #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); diff --git a/src/threads/native/threads.h b/src/threads/native/threads.h index 7a9099ce3..4f1afcbb7 100644 --- a/src/threads/native/threads.h +++ b/src/threads/native/threads.h @@ -28,7 +28,7 @@ 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 $ */ @@ -211,6 +211,11 @@ void interruptThread(java_lang_VMThread *); 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; diff --git a/src/vm/vm.c b/src/vm/vm.c index 3a132e03b..a4c334ded 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -68,6 +68,9 @@ #include "vm/jit/asmpart.h" #include "vm/jit/profile/profile.h" +#if defined(ENABLE_JVMTI) +#include "native/jvmti/cacaodbg.h" +#endif /* Invocation API variables ***************************************************/ @@ -191,6 +194,8 @@ enum { #ifdef ENABLE_JVMTI OPT_DEBUG, + OPT_XRUNJDWP, + OPT_NOAGENT, OPT_AGENTLIB, OPT_AGENTPATH, #endif @@ -276,6 +281,8 @@ opt_struct opts[] = { { "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 }, @@ -401,7 +408,11 @@ static void Xusage(void) puts(" -Xss set the thread stack size (default: 128kB)"); puts(" -Xprof[:bb] collect and print profiling data"); #if defined(ENABLE_JVMTI) - puts(" -Xdebug enable remote debugging"); + /* -Xdebug option depend on gnu classpath JDWP options. options: + transport=dt_socket,address=,server=(y|n),suspend(y|n) */ + puts(" -Xdebug enable remote debugging\n"); + puts(" -Xrunjdwp transport=[dt_socket|...],address=,server=[y|n],suspend=[y|n]\n"); + puts(" enable remote debugging\n"); #endif /* exit with error code */ @@ -503,6 +514,7 @@ bool vm_create(JavaVMInitArgs *vm_args) nogc_init(HEAP_MAXSIZE, HEAP_STARTSIZE); #endif + /* set the bootclasspath */ cp = getenv("BOOTCLASSPATH"); @@ -547,6 +559,15 @@ bool vm_create(JavaVMInitArgs *vm_args) 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()) @@ -642,15 +663,39 @@ bool vm_create(JavaVMInitArgs *vm_args) #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 (jstate & 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)) @@ -1222,9 +1284,12 @@ void vm_exit(s4 status) 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); @@ -1246,6 +1311,12 @@ void vm_shutdown(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); -- 2.25.1