From: motse Date: Sat, 6 May 2006 18:29:55 +0000 (+0000) Subject: * src/vm/vm.c (vm_create): make agentlib/agentpath work X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=83b4d4eb37091c6f340268bf9647bc11e5192286;p=cacao.git * src/vm/vm.c (vm_create): make agentlib/agentpath work * src/cacao/cacao.c (main): changes for jvmti/jdwp startup due to removal of jdwp process * src/native/jni.c (JNI_CreateJavaVM): change order vm_create and initialization of _Jv_jvm due to jvmti agent support. * src/native/vm/VMVirtualMachine.c: change name of jvmtienv and bugfixes of Samuel Vinson * src/native/include/Makefile.am: add VMMethod.h * src/native/jvmti/Makefile.am: removal of cacaodbgserver * src/native/jvmti/jvmti.c: remove jdwp process and convert to thread * src/native/jvmti/cacaodbg.h: idem * src/native/jvmti/jvmti.h: idem * src/native/jvmti/dbg.h: idem * src/native/jvmti/cacaodbg.c: idem * src/native/jvmti/dbg.c: idem * src/native/jvmti/cacaodbgserver.c: change to a autonomous program and removal of jdwp thread. * src/native/jvmti/VMjdwp.c (VMInit): different invocation due to removal of jdwp thread * src/native/jvmti/VMjdwp.h: export jvmti environment and event callbacks. * src/native/vm/VMMethod.c: initial/dummy implementation of VMMetod native method --- diff --git a/src/cacao/cacao.c b/src/cacao/cacao.c index 388d9e866..4c5fb2cc0 100644 --- a/src/cacao/cacao.c +++ b/src/cacao/cacao.c @@ -31,7 +31,7 @@ Philipp Tomsich Christian Thalinger - $Id: cacao.c 4879 2006-05-05 17:34:49Z edwin $ + $Id: cacao.c 4892 2006-05-06 18:29:55Z motse $ */ @@ -50,6 +50,7 @@ #if defined(ENABLE_JVMTI) #include "native/jvmti/jvmti.h" #include "native/jvmti/cacaodbg.h" + #if defined(USE_THREADS) && defined(NATIVE_THREADS) #include #endif @@ -201,7 +202,7 @@ int main(int argc, char **argv) #if defined(USE_THREADS) && !defined(NATIVE_THREADS) stackbottom = &dummy; #endif - + if (atexit(vm_exit_handler)) throw_cacao_exception_exit(string_java_lang_InternalError, "Unable to register exit_handler"); @@ -221,8 +222,8 @@ int main(int argc, char **argv) JNI_CreateJavaVM(&jvm, (void **) &_Jv_env, vm_args); #if defined(ENABLE_JVMTI) - if (dbgprocess && jvmti && jdwp) /* is this the parent/debugger process ? */ - set_jvmti_phase(JVMTI_PHASE_START); + pthread_mutex_init(&dbgcomlock,NULL); + set_jvmti_phase(JVMTI_PHASE_START); #endif /* do we have a main class? */ @@ -313,20 +314,24 @@ int main(int argc, char **argv) /*class_showmethods(currentThread->group->header.vftbl->class); */ #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); + /* start the jdwp listening */ + if (jdwp) { + log_text("cacao vm - init VMjdwp"); + if (!VMjdwpInit()) exit(1); + setup_jdwp_thread(transport); + if (!suspend) { + fprintf(stderr,"suspend false -> continue debuggee\n"); + } else { + fprintf(stderr,"suspend true -> do no continue debuggee(todo)\n"); + /* XXX todo*/ + } } - if (!dbgprocess) { - fprintf(stderr,"debuggee: herewe go\n"); - fflush(stderr); - } - /* here we go... */ - herewego: + set_jvmti_phase(JVMTI_PHASE_LIVE); + + log_text("debuggee: herewe go"); #endif + (void) vm_call_method(m, NULL, oa); /* exception occurred? */ diff --git a/src/native/include/Makefile.am b/src/native/include/Makefile.am index 41fe92fd5..209fbd56b 100644 --- a/src/native/include/Makefile.am +++ b/src/native/include/Makefile.am @@ -28,7 +28,7 @@ ## ## Changes: ## -## $Id: Makefile.am 4594 2006-03-14 16:40:32Z twisti $ +## $Id: Makefile.am 4892 2006-05-06 18:29:55Z motse $ ## Process this file with automake to produce Makefile.in @@ -75,6 +75,7 @@ GEN_HEADER_FILES = \ GEN_JVMTI_HEADER_FILES = \ java_nio_ByteBuffer.h \ gnu_classpath_jdwp_VMFrame.h \ + gnu_classpath_jdwp_VMMethod.h \ gnu_classpath_jdwp_VMVirtualMachine.h \ gnu_classpath_jdwp_event_EventRequest.h diff --git a/src/native/jni.c b/src/native/jni.c index ad056fe88..ef96ff5c2 100644 --- a/src/native/jni.c +++ b/src/native/jni.c @@ -32,7 +32,7 @@ Christian Thalinger Edwin Steiner - $Id: jni.c 4874 2006-05-05 14:36:18Z edwin $ + $Id: jni.c 4892 2006-05-06 18:29:55Z motse $ */ @@ -5825,10 +5825,6 @@ jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args) _Jv_env = env; - /* actually create the JVM */ - - if (!vm_create(_vm_args)) - return -1; /* create and fill a JavaVM structure */ @@ -5836,9 +5832,15 @@ jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args) jvm->functions = &_Jv_JNIInvokeInterface; /* XXX Set the global variable. Maybe we should do that differently. */ - + /* XXX JVMTI Agents needs a JavaVM */ _Jv_jvm = jvm; + + /* actually create the JVM */ + + if (!vm_create(_vm_args)) + return -1; + /* setup the local ref table (must be created after vm_create) */ lrt = GCNEW(localref_table); diff --git a/src/native/jvmti/Makefile.am b/src/native/jvmti/Makefile.am index b9ce4697a..c78b6adf0 100644 --- a/src/native/jvmti/Makefile.am +++ b/src/native/jvmti/Makefile.am @@ -28,7 +28,7 @@ ## ## Changes: ## -## $Id: Makefile.am 4661 2006-03-21 00:04:59Z motse $ +## $Id: Makefile.am 4892 2006-05-06 18:29:55Z motse $ ## Process this file with automake to produce Makefile.in @@ -40,14 +40,16 @@ libjvmti_la_SOURCES = \ jvmti.c \ jvmti.h \ VMjdwp.c \ + VMjdwp.h \ dbg.h\ dbg.c\ cacaodbg.h \ - cacaodbg.c \ - cacaodbgserver.c \ - cacaodbgserver.h + cacaodbg.c +## seperate cacaodbgserver executable +## cacaodbgserver.c \ +## cacaodbgserver.h \ ## Local variables: ## mode: Makefile diff --git a/src/native/jvmti/VMjdwp.c b/src/native/jvmti/VMjdwp.c index 34811dcf8..e96be458b 100644 --- a/src/native/jvmti/VMjdwp.c +++ b/src/native/jvmti/VMjdwp.c @@ -29,12 +29,13 @@ Changes: - $Id: VMjdwp.c 4661 2006-03-21 00:04:59Z motse $ + $Id: VMjdwp.c 4892 2006-05-06 18:29:55Z motse $ */ #include "native/jvmti/jvmti.h" #include "native/jvmti/cacaodbg.h" +#include "native/jvmti/VMjdwp.h" #include "vm/loader.h" #include "vm/exceptions.h" #include "vm/jit/asmpart.h" @@ -351,24 +352,27 @@ static void GarbageCollectionFinish (jvmtiEnv *jvmti_env){ } -bool VMjdwpInit(jvmtiEnv* env) { +/* it would be more apropriate to call this function from gnu-cp jdwp */ +bool VMjdwpInit() { int end, i=0; jvmtiCapabilities cap; jvmtiError e; + log_text("cacao vm - create new jvmti environment"); + jvmtienv = new_jvmtienv(); /* set eventcallbacks */ if (JVMTI_ERROR_NONE != - (*env)->SetEventCallbacks(env, + (*jvmtienv)->SetEventCallbacks(jvmtienv, &jvmti_jdwp_EventCallbacks, sizeof(jvmti_jdwp_EventCallbacks))){ log_text("unable to setup event callbacks"); return false; } - e = (*env)->GetPotentialCapabilities(env, &cap); + e = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &cap); if (e == JVMTI_ERROR_NONE) { - e = (*env)->AddCapabilities(env, &cap); + e = (*jvmtienv)->AddCapabilities(jvmtienv, &cap); } if (e != JVMTI_ERROR_NONE) { log_text("error adding jvmti capabilities"); @@ -379,7 +383,7 @@ bool VMjdwpInit(jvmtiEnv* env) { for (i = 0; i < end; i++) { /* enable standard VM callbacks */ if (((void**)&jvmti_jdwp_EventCallbacks)[i] != NULL) { - e = (*env)->SetEventNotificationMode(env, + e = (*jvmtienv)->SetEventNotificationMode(jvmtienv, JVMTI_ENABLE, JVMTI_EVENT_START_ENUM+i, NULL); diff --git a/src/native/jvmti/VMjdwp.h b/src/native/jvmti/VMjdwp.h new file mode 100644 index 000000000..86e58439a --- /dev/null +++ b/src/native/jvmti/VMjdwp.h @@ -0,0 +1,44 @@ +/* src/native/vm/VMjdwp.c - jvmti->jdwp interface + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Contact: cacao@cacaojvm.org + + Author: Martin Platter + + Changes: + + + $Id: VMjdwp.c 4661 2006-03-21 00:04:59Z motse $ + +*/ + +#ifndef _VMJDWP_H +#define _VMJDWP_H + +#include "native/jvmti/jvmti.h" + +jvmtiEnv* jvmtienv; +jvmtiEventCallbacks jvmti_jdwp_EventCallbacks; + +#endif diff --git a/src/native/jvmti/cacaodbg.c b/src/native/jvmti/cacaodbg.c index 04792739c..bcd2c888e 100644 --- a/src/native/jvmti/cacaodbg.c +++ b/src/native/jvmti/cacaodbg.c @@ -28,7 +28,7 @@ Authors: Martin Platter Changes: Edwin Steiner - + Samuel Vinson $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $ @@ -51,176 +51,43 @@ #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) threads_sem_wait(&workingdata_lock); -} - -/* releaseworkingdatalock ********************************************************* - - release workingdata lock - -*******************************************************************************/ - -void releaseworkingdatalock() { - workingdatanum--; - assert(workingdatanum>=0); - if (workingdatanum==0) threads_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) { +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); - + threadobject *thread, **tthreads; + #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; + tthreads = MNEW(threadobject*, (sizeof(threadobject*) * cnt)); + thread = mainthreadobj; 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); + 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); + tthreads[i] = thread; i++; } - *addr = (void*)thread->info.prev; + thread = thread->info.prev; /* repeat until we got the pointer to the mainthread twice */ - } while (mainthread != *addr); + } while (mainthreadobj != thread); - 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); + *threads_ptr = tthreads; return JVMTI_ERROR_NONE; #else @@ -235,100 +102,10 @@ jvmtiError allthreads (jint * threads_count_ptr, threadobject ** threads_ptr) { *******************************************************************************/ 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; - } + return (jthread)((threadobject*)thread_getself())->o.thread; } -/* 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************************************************************* @@ -338,43 +115,51 @@ void stopdebuggee() { 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; + struct brkpts *jvmtibrkpt; + + jvmtibrkpt = &dbgcom->jvmtibrkpt;; + 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); + 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 + sets a system breakpoint in breakpoint table and calls set breakpoint *******************************************************************************/ -void setsysbrkpt(int sysbrk, void* addr) { - ptrace_request pt; - ptrace_reply *rcvbuf; - - if (jvmtibrkpt.size == jvmtibrkpt.num) +void setsysbrkpt(int sysbrk, void* addr) { + struct brkpts *jvmtibrkpt; + + pthread_mutex_lock(&dbgcomlock); + jvmtibrkpt = &dbgcom->jvmtibrkpt;; + + if (jvmtibrkpt->size == jvmtibrkpt->num) brktablecreator(); assert (sysbrk < BEGINUSERBRK); - jvmtibrkpt.brk[sysbrk].addr = addr; + jvmtibrkpt->brk[sysbrk].addr = addr; + - pt.kind = PTSETBRK; - pt.addr = addr; - msgqsendevent (&pt, &rcvbuf, sizeof(long)); + dbgcom->setbrkpt = true; + dbgcom->brkaddr = addr; + jvmtibrkpt->brk[sysbrk].orig = dbgcom->brkorig; + pthread_mutex_unlock(&dbgcomlock); - jvmtibrkpt.brk[sysbrk].orig = ((long*)rcvbuf->data)[0]; + /* call cacaodbgserver */ + TRAP; fprintf (stderr,"setsysbrk %d %X done\n",sysbrk, addr); } @@ -387,24 +172,24 @@ void setsysbrkpt(int sysbrk, void* addr) { *******************************************************************************/ void addbrkpt(void* addr, jmethodID method, jlocation location) { - ptrace_request pt; - ptrace_reply *rcvbuf; + struct brkpts *jvmtibrkpt; + + pthread_mutex_lock(&dbgcomlock); + jvmtibrkpt = &dbgcom->jvmtibrkpt;; - if (jvmtibrkpt.size == jvmtibrkpt.num) + if (jvmtibrkpt->size == jvmtibrkpt->num) brktablecreator(); - assert (jvmtibrkpt.size > jvmtibrkpt.num); + 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; + 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++; + /* todo: set breakpoint */ +/* jvmtibrkpt.brk[jvmtibrkpt.num].orig = */ + jvmtibrkpt->num++; + pthread_mutex_unlock(&dbgcomlock); fprintf (stderr,"add brk done\n"); } @@ -416,7 +201,7 @@ void addbrkpt(void* addr, jmethodID method, jlocation location) { *******************************************************************************/ -static void setup_jdwp_thread(char* transport) { +void setup_jdwp_thread(char* transport) { java_objectheader *o; methodinfo *m; java_lang_String *s; @@ -471,190 +256,53 @@ static void setup_jdwp_thread(char* transport) { vm_call_method(m,o); } -/* cacaodbglisten ************************************************************* +/* cacaobreakpointhandler ********************************************************** - setup listener thread for JDWP + handles breakpoints. called by cacaodbgserver. *******************************************************************************/ -void cacaodbglisten(char* transport) { +void cacaobreakpointhandler() { 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); + /* XXX to be continued :-) */ - /* handle messages from cacaodbgserver */ - while (true) { - if (-1 == msgrcv(msgqid,&ev,sizeof(basic_event),MSGQDEBUGGER,0)) - perror("debugger process: cacaodbglisten: "); + fprintf(stderr,"breakpoint handler called\n"); + log_text(" - signal %d", ev.signal); + switch (ev.signal) { + case SIGTRAP: + /* search the breakpoint that has been triggered */ + i=0; + while ((ev.ip!=dbgcom->jvmtibrkpt.brk[i].addr) && (ijvmtibrkpt.num)) i++; - 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) && (i= BEGINUSERBRK) && (ijvmtibrkpt.num)) { + log_text("todo: user defined breakpoints are not handled yet"); + } else + log_text("breakpoint not handled - continue anyway"); } + break; + case SIGQUIT: + log_text("debugger process SIGQUIT"); + data.ev=JVMTI_EVENT_VM_DEATH; + fireEvent(&data); + break; + default: + log_text("signal not handled"); } } -/* ipcrm *********************************************************************** - - removes messages queue - -********************************************************************************/ -void ipcrm() { - struct msqid_ds msgbuf; - struct shmid_ds shmbuf; - msgctl(msgqid, IPC_RMID, &msgbuf); - shmctl(shmid, IPC_RMID, &shmbuf); -} - - -/* cacaodbgfork **************************************************************** - - create debugger/jdwp and debuggee process. Returns true if this is the - parent (debugger/jdwp) process - -********************************************************************************/ - -bool cacaodbgfork() { - int waitproc; - - /* todo: remove shared memory and msg queue on exit */ - /* create/initialize semaphores/shared memory/message queue */ - threads_sem_init(&workingdata_lock, true, 1); - - shmid = shmget(IPC_PRIVATE, sizeof(cacaodbgserver_data), IPC_CREAT | 0x180); - if ((cdbgshmem = (cacaodbgserver_data*)shmat(shmid, NULL, 0)) == -1) { - perror("cacaodbgfork: shared memory attach error: "); - exit(1); - } - cdbgshmem->running = false; - cdbgshmem->hastostop = 1; - - if ((msgqid = msgget(IPC_PRIVATE, IPC_CREAT | 0x180)) == -1) { - perror("cacaodbgfork: message queue get error"); - exit(1); - } - ; - - - /* with this function the following process structure is created: - - cacaodbgserver - \_ debuggee (client/cacao vm) - \_ debugger (jdwp/cacao vm) - - */ - - debuggee = fork(); - if (debuggee == (-1)) { - log_text("debuggee fork error"); - exit(1); - } else { - if (debuggee == 0) { - /* debuggee process - this is where the java client is running */ - - /* allow helper process to trace us */ - if (TRACEME != 0) exit(1); - - fprintf(stderr, "debugee pid %d\n",getpid()); - fflush (stderr); - - /* give parent/debugger process control */ - kill(getpid(),SIGUSR2); - - log_text("debuggee: continue with normal startup"); - - /* continue with normal startup */ - return false; - } else { - log_text("debugger: fork listening jdwp process"); - waitproc = fork(); - - if (waitproc == (-1)) { - log_text("waitprocess fork error"); - exit(1); - } else { - if (waitproc == 0) { - log_text("jdwp process - create new jvmti environment"); - - remotedbgjvmtienv = new_jvmtienv(); - - log_text("jdwp process - init VMjdwp"); - - if (!VMjdwpInit(remotedbgjvmtienv)) exit(1); - - return true; - } else { - /* Debugger process (parent of debugge process) - Here a wait-loop is execute and all the ptrace calls are - done from within this process. - - This call will never return */ - - cacaodbgserver(); - fprintf(stderr,"cacaodbgserver returned - exit\n"); - ipcrm(); - exit(0); - } - } - } - } - return true; /* make compiler happy */ -} - - /* * These are local overrides for various environment variables in Emacs. diff --git a/src/native/jvmti/cacaodbg.h b/src/native/jvmti/cacaodbg.h index cf84fecb9..b5d1deb5e 100644 --- a/src/native/jvmti/cacaodbg.h +++ b/src/native/jvmti/cacaodbg.h @@ -38,10 +38,11 @@ #include "threads/native/threads.h" #include "native/jvmti/jvmti.h" +#include "native/include/java_lang_String.h" +#include + + -#define MSGQEVENT 1 -#define MSGQPTRACEREQ 2 -#define MSGQPTRACEANS 3 typedef struct { jvmtiEvent ev; @@ -71,6 +72,33 @@ typedef struct { jlong jlong; } genericEventData; + +struct _brkpt { + jmethodID method; + jlocation location; + void* addr; /* memory address */ + long orig; /* original memory content */ +}; + + +struct brkpts { + struct _brkpt* brk; + int num; + int size; +}; + + +typedef struct { + int running; + void* breakpointhandler; + bool setbrkpt; + void* brkaddr; + long brkorig; + struct brkpts jvmtibrkpt; +} cacaodbgcommunication; + +cacaodbgcommunication *dbgcom; + #if defined(USE_THREADS) && defined(NATIVE_THREADS) struct _jrawMonitorID { java_lang_String *name; @@ -92,57 +120,32 @@ struct threadmap thmap; /* 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 +#define SETTHREADOBJECTBRK 0 /* used for EVENT_THREAD_START */ +#define BEGINUSERBRK 1 /* 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? */ +extern pthread_mutex_t dbgcomlock; -bool cacaodbgfork(); -void cacaodbglisten(char* transport); +void setup_jdwp_thread(char* transport); +void cacaobreakpointhandler(); 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); +bool VMjdwpInit(); +void agentload(char* opt_arg, bool agentbypath, lt_dlhandle *handle, char **libname); 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); +jvmtiError allthreads (jint * threads_count_ptr, threadobject *** threads_ptr); jthread getcurrentthread(); -void ipcrm(); - #endif /* diff --git a/src/native/jvmti/cacaodbgserver.c b/src/native/jvmti/cacaodbgserver.c index 1a4dd345b..51a520bc4 100644 --- a/src/native/jvmti/cacaodbgserver.c +++ b/src/native/jvmti/cacaodbgserver.c @@ -1,5 +1,5 @@ /* src/native/jvmti/cacaodbgserver.c - contains the cacaodbgserver process. This - process controls the debuggee. + process controls the debuggee/cacao vm. Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, @@ -28,7 +28,7 @@ Authors: Martin Platter Changes: Edwin Steiner - + Samuel Vinson $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $ @@ -42,12 +42,9 @@ #include #include #include -#include -#include -#include -#include -#include +#include +pid_t debuggee; /* getchildprocptrace ********************************************************* @@ -56,247 +53,166 @@ *******************************************************************************/ static void getchildprocptrace (char *ptr, void* addr, int cnt) { - int i, longcnt; + long 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 */ - threads_sem_post(&workingdata_lock); - return true; - } else { - threads_sem_post(&workingdata_lock); - return false; - } + i = GETMEM(debuggee,addr); + memcpy(p+longcnt,&i,cnt%sizeof(long)); } -/* 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 + waits and handles signals from debuggee/child process. Returns true if + cacaodbgserver should exit. *******************************************************************************/ -static void waitloop() { +static bool waitloop(void* dbgcvm) { int status,retval,signal; void* ip; basic_event ev; + cacaodbgcommunication vm; + long data; + struct _brkpt* brk; 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); - } + retval = wait(&status); - if (retval != debuggee) { - fprintf(stderr,"cacaodbgserver got signal from process other then debuggee\n"); - exit(1); + fprintf(stderr,"cacaodbgserver: waitloop we got something to do\n"); + if (retval == -1) { + fprintf(stderr,"error in waitloop\n"); + perror("cacaodbgserver process: waitloop: "); + return true; + } + + if (retval != debuggee) { + fprintf(stderr,"cacaodbgserver got signal from process other then debuggee/cacao vm\n"); + return false; + } + + if (WIFSTOPPED(status)) { + signal = WSTOPSIG(status); + + /* ignore SIGSEGV, SIGPWR, SIGBUS and SIGXCPU for now. + todo: in future this signals could 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); + CONT(debuggee,signal); + return false; } - if (WIFEXITED(status)) { - /* generate event VMDeath */ - ev.signal = SIGQUIT; - ev.ip = NULL; - msgqsendevent(&ev); - return; + if (signal == SIGABRT) { + fprintf(stderr,"cacaodbgserver: got SIGABRT from debugee - exit\n"); + return true; } - 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); - - threads_sem_wait(&workingdata_lock); - cdbgshmem->running = false; - cdbgshmem->hastostop = 1; - threads_sem_post(&workingdata_lock); - - if (signal==SIGUSR2) { - fprintf(stderr,"SIGUSR2 - debuggee has stopped by jdwp process\n"); - return; - } + ip = getip(debuggee); + ip--; /* EIP has already been incremented */ + fprintf(stderr,"got signal: %d IP %X\n",signal,ip); + - ev.signal = signal; - ev.ip = ip; - msgqsendevent(&ev); - return; + ev.signal = signal; + ev.ip = ip; + + /* handle breakpoint */ + getchildprocptrace((char*)&vm,dbgcvm,sizeof(cacaodbgcommunication)); + + if (vm.setbrkpt) { + /* set a breakpoint */ + setbrk(debuggee, vm.brkaddr, &vm.brkorig); + CONT(debuggee,0); + return false; } + + if (signal == SIGTRAP) { + /* Breakpoint hit. Place original instruction and notify cacao vm to + handle it */ + fprintf(stderr,"breakpoint hit\n"); + } + + return false; + } - fprintf(stderr,"wait not handled(child not exited or stopped)\n"); - fprintf(stderr,"retval: %d status: %d\n",retval,status); + if (WIFEXITED(status)) { + fprintf(stderr,"cacaodbgserver: debuggee/cacao vm exited.\n"); + return true; + } + + if (WIFSIGNALED(status)) { + fprintf(stderr,"cacaodbgserver: child terminated by signal %d\n",WTERMSIG(status)); + return true; } + + if (WIFCONTINUED(status)) { + fprintf(stderr,"cacaodbgserver: continued\n"); + return false; + } + + + fprintf(stderr,"wait not handled(child not exited or stopped)\n"); + fprintf(stderr,"retval: %d status: %d\n",retval,status); + CONT(debuggee,0); + return false; } -/* ptraceloop ***************************************************************** +/* main (cacaodbgserver) ****************************************************** - this function handles the ptrace request from the jdwp/debugger process. + main function for cacaodbgserver 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); - } +int main(int argc, char **argv) { + bool running = true; + void *dbgcvm; + int status; + + if (argc != 2) { + fprintf(stderr,"cacaodbgserver: not enough arguments\n"); + fprintf(stderr, "cacaodbgserver cacaodbgcommunicationaddress\n"); - if (-1 == msgsnd(msgqid, buffer, size, 0)) { - perror("cacaodbgserver process: cacaodbglisten send error: "); - exit(1); - } - MFREE(buffer,char,size); + fprintf(stderr,"argc %d argv[0] %s\n",argc,argv[0]); + exit(1); } -} -/* cacaodbgserver ************************************************************* + dbgcvm=(cacaodbgcommunication*)strtol(argv[1],NULL,16); - waits for eventes from and issues ptrace calls to debuggee/child process + fprintf(stderr,"cacaodbgserver started pid %d ppid %d\n",getpid(), getppid()); -*******************************************************************************/ + debuggee = getppid(); + + if (TRACEATTACH(debuggee) == -1) perror("cacaodbgserver: "); -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 */ + fprintf(stderr,"cacaovm attached\n"); + + if (wait(&status) == -1) { + fprintf(stderr,"error initial wait\n"); + perror("cacaodbgserver: "); + exit(1); + } + + if (WIFSTOPPED(status)) + if (WSTOPSIG(status) == SIGSTOP) + CONT(debuggee,0); + + while(running) { + running = !waitloop(dbgcvm); } + fprintf(stderr,"cacaodbgserver exit\n"); } diff --git a/src/native/jvmti/dbg.c b/src/native/jvmti/dbg.c index 4f669fa4c..7af016db2 100644 --- a/src/native/jvmti/dbg.c +++ b/src/native/jvmti/dbg.c @@ -59,11 +59,12 @@ void setip(pid_t pid, void* ip) { 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); + fprintf (stderr,"pid %d set brk at %p orig: %X new: %X\n",pid,addr,*orig,ins); if (ptrace(PTRACE_POKEDATA, pid, (caddr_t) addr, ins)==-1) perror("setbrk error "); } diff --git a/src/native/jvmti/dbg.h b/src/native/jvmti/dbg.h index 44370c39e..52f63f295 100644 --- a/src/native/jvmti/dbg.h +++ b/src/native/jvmti/dbg.h @@ -29,7 +29,7 @@ Changes: - $Id: dbg.h 4661 2006-03-21 00:04:59Z motse $ + $Id: dbg.h 4892 2006-05-06 18:29:55Z motse $ */ @@ -42,7 +42,7 @@ #include #include -#define TRACEME ptrace(PTRACE_TRACEME, 0, 0, 0) +#define TRACEATTACH(pid) ptrace(PTRACE_ATTACH, pid, 0, 0) #define DETACH(pid,sig) ptrace(PTRACE_DETACH, pid, 0, sig) #define TRAPINS 0xcc /* opcode for brk */ #define TRAP asm("int3") diff --git a/src/native/jvmti/jvmti.c b/src/native/jvmti/jvmti.c index b2afcadec..e4ff37fa7 100644 --- a/src/native/jvmti/jvmti.c +++ b/src/native/jvmti/jvmti.c @@ -28,9 +28,10 @@ Author: Martin Platter Changes: Edwin Steiner + Samuel Vinson - $Id: jvmti.c 4874 2006-05-05 14:36:18Z edwin $ + $Id: jvmti.c 4892 2006-05-06 18:29:55Z motse $ */ @@ -70,10 +71,9 @@ #include "toolbox/logging.h" #include #include -#include -#include -#include #include +#include +#include #if defined(USE_THREADS) && defined(NATIVE_THREADS) #include "threads/native/threads.h" @@ -81,10 +81,13 @@ #include #endif +#include "native/jvmti/stacktrace.h" #include "dbg.h" + typedef struct _environment environment; -environment *envs=NULL; +static environment *envs=NULL; +pthread_mutex_t dbgcomlock; extern const struct JNIInvokeInterface _Jv_JNIInvokeInterface; @@ -99,12 +102,13 @@ struct _jvmtiEventModeLL { typedef struct _jvmtiThreadLocalStorage jvmtiThreadLocalStorage; struct _jvmtiThreadLocalStorage{ jthread thread; - jvmtiThreadLocalStorage *next; void *data; + jvmtiThreadLocalStorage *next; }; struct _environment { jvmtiEnv env; + environment *next; jvmtiEventCallbacks callbacks; /* table for enabled/disabled jvmtiEvents - first element contains global behavior */ @@ -112,7 +116,6 @@ struct _environment { jvmtiCapabilities capabilities; void *EnvironmentLocalStorage; jvmtiThreadLocalStorage *tls; - environment *next; }; static struct jvmtiEnv_struct JVMTI_EnvTable; @@ -137,13 +140,8 @@ static lt_ptr unload; *******************************************************************************/ 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) + if(t==NULL) return JVMTI_ERROR_THREAD_NOT_ALIVE; + if(((java_lang_Thread*) t)->vmThread==NULL) return JVMTI_ERROR_THREAD_NOT_ALIVE; return JVMTI_ERROR_NONE; } @@ -155,7 +153,7 @@ static jvmtiError check_thread_is_alive(jthread t) { *******************************************************************************/ static void execcallback(jvmtiEvent e, functionptr ec, genericEventData* data) { - JNIEnv* jni_env = (JNIEnv*)&_Jv_JNINativeInterface; + JNIEnv* jni_env = (JNIEnv*)_Jv_env; fprintf(stderr,"execcallback called (event: %d)\n",e); @@ -384,15 +382,14 @@ void fireEvent(genericEventData* d) { /* todo : respect event order JVMTI-Spec:Multiple Co-located Events */ if (d->ev != JVMTI_EVENT_VM_START) - thread = (jthread)getcurrentthread(); + thread = getcurrentthread(); else thread = NULL; - fprintf (stderr,"debugger: fireEvent: %d\n",d->ev); + fprintf (stderr,"jvmti: 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); @@ -427,11 +424,6 @@ SetEventNotificationMode (jvmtiEnv * env, jvmtiEventMode mode, if ((mode != JVMTI_ENABLE) && (mode != JVMTI_DISABLE)) return JVMTI_ERROR_ILLEGAL_ARGUMENT; - if ((event_type < JVMTI_EVENT_START_ENUM) || - (event_type > JVMTI_EVENT_END_ENUM)) - return JVMTI_ERROR_INVALID_EVENT_TYPE; - - switch (event_type) { /* check capability */ case JVMTI_EVENT_EXCEPTION: case JVMTI_EVENT_EXCEPTION_CATCH: @@ -483,6 +475,9 @@ SetEventNotificationMode (jvmtiEnv * env, jvmtiEventMode mode, break; default: /* all other events are required */ + if ((event_type < JVMTI_EVENT_START_ENUM) || + (event_type > JVMTI_EVENT_END_ENUM)) + return JVMTI_ERROR_INVALID_EVENT_TYPE; break; } @@ -526,7 +521,7 @@ jvmtiError GetAllThreads (jvmtiEnv * env, jint * threads_count_ptr, jthread ** threads_ptr) { - threadobject* threads; + threadobject** threads; int i; jvmtiError retval; @@ -539,14 +534,14 @@ GetAllThreads (jvmtiEnv * env, jint * threads_count_ptr, if ((threads_count_ptr == NULL) || (threads_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; - retval=allthreads(threads_count_ptr,&threads); + 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]); + for (i=0; i<*threads_count_ptr; i++) + (*threads_ptr)[i] = threads[i]->o.thread; return JVMTI_ERROR_NONE; } @@ -564,17 +559,10 @@ SuspendThread (jvmtiEnv * env, jthread thread) CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; - CHECK_CAPABILITY(env,can_suspend) + CHECK_CAPABILITY(env,can_suspend); -/* -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - suspend_thread((thread *) thread->thread); -#endif - -#if defined(USE_THREADS) && defined(NATIVE_THREADS) - suspend_thread((threadobject*) thread); -#endif -*/ + log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); + return JVMTI_ERROR_NOT_AVAILABLE; return JVMTI_ERROR_NONE; } @@ -591,17 +579,11 @@ ResumeThread (jvmtiEnv * env, jthread thread) CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; - CHECK_CAPABILITY(env,can_suspend) + CHECK_CAPABILITY(env,can_suspend); -/* -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - resume_thread((thread *) this->thread); -#endif + log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); + return JVMTI_ERROR_NOT_AVAILABLE; -#if defined(USE_THREADS) && defined(NATIVE_THREADS) - resume_thread((threadobject*) thread); -#endif -*/ return JVMTI_ERROR_NONE; } @@ -618,9 +600,11 @@ StopThread (jvmtiEnv * env, jthread thread, jobject exception) CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; - CHECK_CAPABILITY(env,can_signal_thread) + CHECK_CAPABILITY(env,can_signal_thread); - log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); + log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); + return JVMTI_ERROR_NOT_AVAILABLE; + return JVMTI_ERROR_NONE; } @@ -638,17 +622,15 @@ InterruptThread (jvmtiEnv * env, jthread thread) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_signal_thread) + log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); + + return JVMTI_ERROR_NOT_AVAILABLE; + if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); -#if defined(USE_THREADS) && defined(NATIVE_THREADS) -/* interruptThread((java_lang_VMThread*)thread);*/ -#else - return JVMTI_ERROR_NOT_AVAILABLE; -#endif - return JVMTI_ERROR_NONE; } @@ -660,29 +642,20 @@ InterruptThread (jvmtiEnv * env, jthread thread) *******************************************************************************/ jvmtiError -GetThreadInfo (jvmtiEnv * env, jthread th, jvmtiThreadInfo * info_ptr) +GetThreadInfo (jvmtiEnv * env, jthread t, jvmtiThreadInfo * info_ptr) { - int size; - char* data; - struct java_lang_Thread *t; + java_lang_Thread* th = (java_lang_Thread*)t; log_text("GetThreadInfo called"); CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; - - 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'; - + info_ptr->priority=(jint)th->priority; + info_ptr->is_daemon=(jboolean)th->daemon; + info_ptr->thread_group=(jthreadGroup)th->group; + info_ptr->context_class_loader=(jobject)th->contextClassLoader; + info_ptr->name= javastring_tochar((java_objectheader *)th->name); return JVMTI_ERROR_NONE; } @@ -701,9 +674,8 @@ GetOwnedMonitorInfo (jvmtiEnv * env, jthread thread, int i,j,size=20; java_objectheader **om; lockRecordPool* lrp; - char *data; - log_text("GetOwnedMonitorInfo called"); + log_text("GetOwnedMonitorInfo called - todo: fix object mapping"); CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) @@ -722,12 +694,8 @@ GetOwnedMonitorInfo (jvmtiEnv * env, jthread thread, om=MNEW(java_objectheader*,size); - stopdebuggee(); - - /* 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; + pthread_mutex_lock(&pool_lock); + lrp=global_pool; while (lrp != NULL) { for (j=0; jheader.size; j++) { @@ -821,7 +789,7 @@ typedef struct { static void *threadstartup(void *t) { runagentparam *rap = (runagentparam*)t; - rap->sf(rap->jvmti_env,&_Jv_JNINativeInterface,rap->arg); + rap->sf(rap->jvmti_env,(JNIEnv*)&_Jv_JNINativeInterface,rap->arg); return NULL; } @@ -851,6 +819,9 @@ RunAgentThread (jvmtiEnv * env, jthread thread, jvmtiStartFunction proc, (priority > JVMTI_THREAD_MAX_PRIORITY)) return JVMTI_ERROR_INVALID_PRIORITY; + /* XXX: Threads started with with this function should not be visible to + Java programming language queries but are included in JVM TI queries */ + rap.sf = proc; rap.arg = (void*)arg; rap.jvmti_env = env; @@ -895,6 +866,8 @@ GetTopThreadGroups (jvmtiEnv * env, jint * group_count_ptr, CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; + log_text("GetTopThreadGroups called"); + if ((groups_ptr == NULL) || (group_count_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; @@ -915,7 +888,6 @@ GetTopThreadGroups (jvmtiEnv * env, jint * group_count_ptr, while((j= size){ MREALLOC(tg,jthreadGroup*,size,size*2); @@ -1030,11 +1002,15 @@ 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) { + threadobject *t; log_text("getcacaostacktrace"); - + t = (threadobject*)((java_lang_Thread*)thread)->vmThread; + +/* XXX todo + *trace = stacktrace_create(t); */ return JVMTI_ERROR_NONE; } @@ -1042,6 +1018,7 @@ static jvmtiError getcacaostacktrace(char** trace, jthread thread) { /* GetFrameCount ************************************************************** + Get the number of frames in the specified thread's stack. *******************************************************************************/ @@ -1049,7 +1026,7 @@ static jvmtiError getcacaostacktrace(char** trace, jthread thread) { jvmtiError GetFrameCount (jvmtiEnv * env, jthread thread, jint * count_ptr) { - char* trace; + stacktracebuffer* trace; jvmtiError er; CHECK_PHASE_START @@ -1066,7 +1043,7 @@ GetFrameCount (jvmtiEnv * env, jthread thread, jint * count_ptr) er = getcacaostacktrace(&trace, thread); if (er==JVMTI_ERROR_NONE) return er; -/* todo: *count_ptr = trace->size;*/ + *count_ptr = trace->used; return JVMTI_ERROR_NONE; } @@ -2137,8 +2114,7 @@ GetFieldDeclaringClass (jvmtiEnv * env, jclass klass, jfieldID field, CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; - /* todo: how do I find declaring class other then iterate over all fields in all classes ?*/ - log_text ("JVMTI-Call: IMPLEMENT ME!!!"); + *declaring_class_ptr = (jclass) ((fieldinfo*)field)->class; return JVMTI_ERROR_NONE; } @@ -2214,12 +2190,16 @@ GetMethodName (jvmtiEnv * env, jmethodID method, char **name_ptr, if ((method == NULL) || (name_ptr == NULL) || (signature_ptr == NULL) || (generic_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; - *name_ptr = (char*)heap_allocate(m->name->blength,true,NULL); - memcpy(*name_ptr, m->name->text, m->name->blength); + if (m->name == NULL) return JVMTI_ERROR_INTERNAL; + + *name_ptr = (char*) + heap_allocate(sizeof(char) * (m->name->blength),true,NULL); + utf_sprint_convert_to_latin1(*name_ptr, m->name); + + *signature_ptr = (char*) + heap_allocate(sizeof(char) * (m->descriptor->blength),true,NULL); + utf_sprint_convert_to_latin1(*signature_ptr, m->descriptor); - *signature_ptr = (char*)heap_allocate(m->descriptor->blength,true,NULL); - memcpy(*signature_ptr, m->descriptor->text, m->descriptor->blength); - /* there is no generic signature attribute */ *generic_ptr = NULL; @@ -2399,6 +2379,7 @@ GetMethodLocation (jvmtiEnv * env, jmethodID method, /* XXX Don't know if that's the right way to deal with not-yet- * compiled methods. -Edwin */ + if (!m->code) return JVMTI_ERROR_NULL_POINTER; @@ -2524,7 +2505,12 @@ GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, jclass ** classes_ptr) classcache_name_entry *cne; classcache_class_entry *cce; - log_text ("GetLoadedClasses called"); + log_text ("GetLoadedClasses called %d ", phase); + + + /* XXX todo */ + + *class_count_ptr = 0; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) @@ -2535,10 +2521,9 @@ GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, jclass ** classes_ptr) log_text ("GetLoadedClasses1"); - stopdebuggee(); +/* + CLASSCACHE_LOCK(); 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; @@ -2549,23 +2534,24 @@ GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, jclass ** classes_ptr) fflush(stderr); *class_count_ptr = ht->entries; + log_text ("GetLoadedClasses %d", *class_count_ptr); j=0; - /* look in every slot of the hashtable */ + look in every slot of the hashtable for (i=0; isize; i++) { cne = ht->ptr[i]; - while (cne != NULL) { /* iterate over hashlink */ + 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; + 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++; } cce = cce->next; @@ -2573,10 +2559,12 @@ GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, jclass ** classes_ptr) cne = cne->hashlink; } } - + log_text ("GetLoadedClasses continue"); - contdebuggee(0); + CLASSCACHE_UNLOCK(); + +*/ log_text ("GetLoadedClasses finished"); @@ -2728,7 +2716,7 @@ IsMethodObsolete (jvmtiEnv * env, jmethodID method, } -/* ***************************************************************************** +/* SuspendThreadList ********************************************************** @@ -2742,14 +2730,15 @@ SuspendThreadList (jvmtiEnv * env, jint request_count, CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; - CHECK_CAPABILITY(env,can_suspend) + CHECK_CAPABILITY(env,can_suspend); - log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); + log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); + return JVMTI_ERROR_NONE; } -/* ***************************************************************************** +/* ResumeThreadList *********************************************************** @@ -2762,9 +2751,10 @@ ResumeThreadList (jvmtiEnv * env, jint request_count, CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; - CHECK_CAPABILITY(env,can_suspend) + CHECK_CAPABILITY(env,can_suspend); - log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); + log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); + return JVMTI_ERROR_NONE; } @@ -2780,9 +2770,9 @@ GetStackTrace (jvmtiEnv * env, jthread thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo * frame_buffer, jint * count_ptr) { - char* trace; + stacktracebuffer* trace; jvmtiError er; -/* int i,j;*/ + int i,j; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) @@ -2801,14 +2791,14 @@ GetStackTrace (jvmtiEnv * env, jthread thread, jint start_depth, er = getcacaostacktrace(&trace, thread); if (er==JVMTI_ERROR_NONE) return er; -/* todo: if ((trace->size >= start_depth) || ((trace->size * -1) > start_depth)) - return JVMTI_ERROR_ILLEGAL_ARGUMENT; */ + if ((trace->used >= start_depth) || ((trace->used * -1) > start_depth)) + return JVMTI_ERROR_ILLEGAL_ARGUMENT; -/* 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 + for (i=start_depth, j=0;iused;i++,j++) { + frame_buffer[j].method = (jmethodID)trace->entries[i].method; + /* todo: location BCI/MachinePC not avilable - Linenumber not expected */ frame_buffer[j].location = 0; - }*/ + } return JVMTI_ERROR_NONE; } @@ -3169,7 +3159,7 @@ SetJNIFunctionTable (jvmtiEnv * env, if (function_table == NULL) return JVMTI_ERROR_NULL_POINTER; _Jv_env->env = (void*)heap_allocate(sizeof(jniNativeInterface),true,NULL); - memcpy(_Jv_env->env, function_table, sizeof(jniNativeInterface)); + memcpy((void*)_Jv_env->env, function_table, sizeof(jniNativeInterface)); return JVMTI_ERROR_NONE; } @@ -3327,11 +3317,9 @@ DisposeEnvironment (jvmtiEnv * env) { environment* cacao_env = (environment*)env; environment* tenvs = envs; - memset(&((cacao_env)->events[0]),0,sizeof(jvmtiEventModeLL)* - (JVMTI_EVENT_END_ENUM-JVMTI_EVENT_START_ENUM)); - (cacao_env)->EnvironmentLocalStorage = NULL; - - if (tenvs!=cacao_env) { + jvmtiThreadLocalStorage *jtls, *tjtls; + + if (tenvs != cacao_env) { while (tenvs->next != cacao_env) { tenvs = tenvs->next; } @@ -3339,7 +3327,30 @@ DisposeEnvironment (jvmtiEnv * env) } else envs = NULL; - /* let Boehm GC do the rest */ + cacao_env->env=NULL; + memset(&(cacao_env->callbacks),0,sizeof(jvmtiEventCallbacks)* + (JVMTI_EVENT_END_ENUM-JVMTI_EVENT_START_ENUM)); + memset(cacao_env->events,0,sizeof(jvmtiEventModeLL)* + (JVMTI_EVENT_END_ENUM-JVMTI_EVENT_START_ENUM)); + cacao_env->EnvironmentLocalStorage = NULL; + + jtls = cacao_env->tls; + while (jtls != NULL) { + tjtls = jtls; + jtls = jtls->next; + tjtls->next = NULL; + } + cacao_env->tls = NULL; + + + pthread_mutex_lock(&dbgcomlock); + dbgcom->running--; + if (dbgcom->running == 0) { + TRAP; + } + pthread_mutex_unlock(&dbgcomlock); + + /* let the GC do the rest */ return JVMTI_ERROR_NONE; } @@ -4103,12 +4114,7 @@ static jvmtiCapabilities JVMTI_Capabilities = { 0, /* can_get_monitor_info */ 0, /* can_pop_frame */ 0, /* can_redefine_classes */ -#if defined(USE_THREADS) && defined(NATIVE_THREADS) - /* current implementation does not work if called from another process */ - 0, /* can_signal_thread */ -#else 0, /* can_signal_thread */ -#endif 1, /* can_get_source_file_name */ 1, /* can_get_line_numbers */ 0, /* can_get_source_debug_extension */ @@ -4118,12 +4124,7 @@ static jvmtiCapabilities JVMTI_Capabilities = { 0, /* can_generate_exception_events */ 0, /* can_generate_frame_pop_events */ 0, /* can_generate_breakpoint_events */ -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - /* current implementation does not work if called from another process */ - 0, /* can_suspend */ -#else 0, /* can_suspend */ -#endif 0, /* can_redefine_any_class */ 0, /* can_get_current_thread_cpu_time */ 0, /* can_get_thread_cpu_time */ @@ -4299,7 +4300,7 @@ static struct jvmtiEnv_struct JVMTI_EnvTable = { void set_jvmti_phase(jvmtiPhase p) { genericEventData d; - fprintf (stderr,"set JVMTI pid %d phase %d\n",getpid(),p); + fprintf (stderr,"set JVMTI phase %d\n",p); fflush(stderr); switch (p) { @@ -4313,7 +4314,7 @@ void set_jvmti_phase(jvmtiPhase p) { 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"); + log_text("set sysbrk in setthreadobj"); setsysbrkpt(SETTHREADOBJECTBRK,(void*)&setthreadobject); break; case JVMTI_PHASE_LIVE: @@ -4334,76 +4335,105 @@ void set_jvmti_phase(jvmtiPhase p) { jvmtiEnv* new_jvmtienv() { environment* env; + pid_t dbgserver; + char* comaddr; 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); + while (env->next != NULL) env = env->next; + env->next = heap_allocate(sizeof(environment),true,NULL); + env = env->next; } + 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.*/ - memset(&(env->capabilities), 1, sizeof(jvmtiCapabilities)); + memset(&(env->capabilities), 0, sizeof(jvmtiCapabilities)); RelinquishCapabilities(&(env->env),&(env->capabilities)); env->EnvironmentLocalStorage = NULL; env->tls = NULL; + /* start new cacaodbgserver if needed*/ + pthread_mutex_lock(&dbgcomlock); + if (dbgcom == NULL) { + dbgcom = heap_allocate(sizeof(cacaodbgcommunication),true,NULL); + dbgcom->running = 1; + dbgcom->breakpointhandler = (void*)cacaobreakpointhandler; + dbgserver = fork(); + if (dbgserver == (-1)) { + log_text("cacaodbgserver fork error"); + exit(1); + } else { + if (dbgserver == 0) { + comaddr = MNEW(char,11); + snprintf(comaddr,11,"%p",dbgcom); + if (execlp("cacaodbgserver","cacaodbgserver",comaddr,(char *) NULL) == -1) { + log_text("unable to execute cacaodbgserver"); + exit(1); + } + } + } + } else { + dbgcom->running++; + } + pthread_mutex_unlock(&dbgcomlock); + sched_yield(); + + return (jvmtiEnv*)env; } -void agentload(char* opt_arg) { - lt_dlhandle handle; - lt_ptr onload; - char *libname, *arg; +void agentload(char* opt_arg, bool agentbypath, lt_dlhandle *handle, char **libname) { + lt_ptr onload; + char *arg; int i=0,len; jint retval; - classinfo* ci; + len = strlen(opt_arg); - while ((opt_arg[i]!='=')&&(iclassloader, handle); + unload = lt_dlsym(*handle, "Agent_Unload"); retval = ((JNIEXPORT jint JNICALL (*) (JavaVM *vm, char *options, void *reserved)) - onload) ((JavaVM*) &_Jv_JNIInvokeInterface, arg, NULL); - - MFREE(libname,char,i); - MFREE(arg,char,len-i); - + onload) ((JavaVM *) _Jv_jvm, arg, NULL); + if (retval != 0) exit (retval); } diff --git a/src/native/jvmti/jvmti.h b/src/native/jvmti/jvmti.h index 3781e4635..1ff624194 100644 --- a/src/native/jvmti/jvmti.h +++ b/src/native/jvmti/jvmti.h @@ -30,17 +30,17 @@ Changes: - $Id: jvmti.h 4661 2006-03-21 00:04:59Z motse $ + $Id: jvmti.h 4892 2006-05-06 18:29:55Z motse $ */ #ifndef _JVMTI_H #define _JVMTI_H #include "native/jni.h" -#include "native/include/java_lang_String.h" #include #define JVMTI_VERSION_1_0 0x30010000 +#define JVMTI_VERSION JVMTI_VERSION_1_0 typedef jobject jthread; typedef jobject jthreadGroup; diff --git a/src/native/vm/VMMethod.c b/src/native/vm/VMMethod.c new file mode 100644 index 000000000..3d490037c --- /dev/null +++ b/src/native/vm/VMMethod.c @@ -0,0 +1,109 @@ +/* src/native/vm/VMMethod.c - jdwp->jvmti interface + +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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +Contact: cacao@cacaojvm.org + +Authors: Samuel Vinson + +Changes: + + +$Id: $ + +*/ + +#include "toolbox/logging.h" +#include "native/jni.h" +#include "native/include/gnu_classpath_jdwp_VMMethod.h" +#include "vm/stringlocal.h" +#include "toolbox/logging.h" + +/* + * Class: gnu/classpath/jdwp/VMMethod + * Method: getName + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT struct java_lang_String* JNICALL Java_gnu_classpath_jdwp_VMMethod_getName(JNIEnv *env, struct gnu_classpath_jdwp_VMMethod* this) +{ + classinfo *c; + methodinfo *m; + + c = (classinfo *)this->_class; + m = &(c->methods[this->_methodId]); + log_message_utf("Method_getName %s", m->name); + return javastring_new(m->name); +} + + +/* + * Class: gnu/classpath/jdwp/VMMethod + * Method: getSignature + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT struct java_lang_String* JNICALL Java_gnu_classpath_jdwp_VMMethod_getSignature(JNIEnv *env, struct gnu_classpath_jdwp_VMMethod* this) +{ + log_text ("JVMTI-Call: IMPLEMENT ME!!!"); + return 0; +} + + +/* + * Class: gnu/classpath/jdwp/VMMethod + * Method: getModifiers + * Signature: ()I + */ +JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMMethod_getModifiers(JNIEnv *env, struct gnu_classpath_jdwp_VMMethod* this) +{ + classinfo *c; + methodinfo *m; + + c = (classinfo *) this->_class; + m = &(c->methods[this->_methodId]); + + return m->flags; +} + + +/* + * Class: gnu/classpath/jdwp/VMMethod + * Method: getLineTable + * Signature: ()Lgnu/classpath/jdwp/util/LineTable; + */ +JNIEXPORT struct gnu_classpath_jdwp_util_LineTable* JNICALL Java_gnu_classpath_jdwp_VMMethod_getLineTable(JNIEnv *env, struct gnu_classpath_jdwp_VMMethod* this) +{ + log_text ("JVMTI-Call: IMPLEMENT ME!!!"); + return 0; +} + + +/* + * Class: gnu/classpath/jdwp/VMMethod + * Method: getVariableTable + * Signature: ()Lgnu/classpath/jdwp/util/VariableTable; + */ +JNIEXPORT struct gnu_classpath_jdwp_util_VariableTable* JNICALL Java_gnu_classpath_jdwp_VMMethod_getVariableTable(JNIEnv *env, struct gnu_classpath_jdwp_VMMethod* this) +{ + log_text ("JVMTI-Call: IMPLEMENT ME!!!"); + return 0; +} diff --git a/src/native/vm/VMVirtualMachine.c b/src/native/vm/VMVirtualMachine.c index 0a5bfaa37..2d2200933 100644 --- a/src/native/vm/VMVirtualMachine.c +++ b/src/native/vm/VMVirtualMachine.c @@ -26,10 +26,10 @@ Contact: cacao@cacaojvm.org Authors: Martin Platter -Changes: +Changes: Samuel Vinson -$Id: VMVirtualMachine.c 4661 2006-03-21 00:04:59Z motse $ +$Id: VMVirtualMachine.c 4892 2006-05-06 18:29:55Z motse $ */ @@ -43,7 +43,7 @@ $Id: VMVirtualMachine.c 4661 2006-03-21 00:04:59Z motse $ #include "native/include/gnu_classpath_jdwp_event_EventRequest.h" #include "native/include/gnu_classpath_jdwp_VMVirtualMachine.h" #include "native/jvmti/jvmti.h" -#include "native/jvmti/cacaodbg.h" +#include "native/jvmti/VMjdwp.h" #include @@ -54,7 +54,7 @@ $Id: VMVirtualMachine.c 4661 2006-03-21 00:04:59Z motse $ */ JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_suspendThread(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) { - (*remotedbgjvmtienv)->SuspendThread(remotedbgjvmtienv, (jthread) par1); + (*jvmtienv)->SuspendThread(jvmtienv, (jthread) par1); } /* @@ -64,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); + (*jvmtienv)->ResumeThread(jvmtienv, (jthread) par1); } @@ -87,7 +87,7 @@ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getAllLoadedClasse jint count; jclass* classes; - (*remotedbgjvmtienv)->GetLoadedClasses(remotedbgjvmtienv, &count, &classes); + (*jvmtienv)->GetLoadedClasses(jvmtienv, &count, &classes); return count; } @@ -107,9 +107,9 @@ JNIEXPORT struct java_util_Iterator* JNICALL Java_gnu_classpath_jdwp_VMVirtualMa jvmtiError err; char* errdesc; - if (JVMTI_ERROR_NONE != (err= (*remotedbgjvmtienv)-> - GetLoadedClasses(remotedbgjvmtienv, &classcount, &classes))) { - (*remotedbgjvmtienv)->GetErrorName(remotedbgjvmtienv,err, &errdesc); + if (JVMTI_ERROR_NONE != (err= (*jvmtienv)-> + GetLoadedClasses(jvmtienv, &classcount, &classes))) { + (*jvmtienv)->GetErrorName(jvmtienv,err, &errdesc); fprintf(stderr,"jvmti error: %s\n",errdesc); fflush(stderr); /* env->ThrowNew(env,ec,"jvmti error occoured");*/ @@ -119,6 +119,7 @@ JNIEXPORT struct java_util_Iterator* JNICALL Java_gnu_classpath_jdwp_VMVirtualMa /* Arrays.asList(Object[] classes)->List.Iterator()->Iterator */ joa = (*env)->NewObjectArray(env, (jsize)classcount, cl , NULL); + if (!joa) return NULL; for (i = 0; i < classcount; i++) (*env)->SetObjectArrayElement(env,joa,(jsize)i, (jobject)classes[i]); @@ -134,8 +135,8 @@ JNIEXPORT struct java_util_Iterator* JNICALL Java_gnu_classpath_jdwp_VMVirtualMa cl = (*env)->FindClass(env,"java.util.List"); if (!cl) return NULL; - m = (*env)->GetMethodID(env,cl,"Iterator","()Ljava/util/Iterator;"); - + m = (*env)->GetMethodID(env,cl,"iterator","()Ljava/util/Iterator;"); + if (!m) return NULL; oi = (*env)->CallObjectMethod(env,*ol,m); return (struct java_util_Iterator*)oi; @@ -147,7 +148,7 @@ JNIEXPORT struct java_util_Iterator* JNICALL Java_gnu_classpath_jdwp_VMVirtualMa */ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getClassStatus(JNIEnv *env, jclass clazz, struct java_lang_Class* par1) { jint status; - (*remotedbgjvmtienv)->GetClassStatus(remotedbgjvmtienv, (jclass) par1, &status); + (*jvmtienv)->GetClassStatus(jvmtienv, (jclass) par1, &status); return status; } @@ -158,6 +159,7 @@ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getClassStatus(JNI */ 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 !!!"); + return NULL; } @@ -168,6 +170,7 @@ JNIEXPORT java_objectarray* JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_get */ 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 !!!"); + return NULL; } @@ -179,7 +182,7 @@ JNIEXPORT struct gnu_classpath_jdwp_VMMethod* JNICALL Java_gnu_classpath_jdwp_VM 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 ("VMVirtualMachine_getFrames - IMPLEMENT ME!!!"); /* jclass ec = (*env)->FindClass(env,"gnu/classpath/jdwp/JdwpInternalErrorException"); - if (JVMTI_ERROR_NONE != (*remotedbgjvmtienv)->GetClassStatus(remotedbgjvmtienv, par1, &status)) + if (JVMTI_ERROR_NONE != (*jvmtienv)->GetClassStatus(jvmtienv, par1, &status)) env->ThrowNew(env,ec,"jvmti error occoured");*/ return 0; } @@ -203,7 +206,7 @@ JNIEXPORT struct gnu_classpath_jdwp_VMFrame* JNICALL Java_gnu_classpath_jdwp_VMV */ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrameCount(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) { jint count; - (*remotedbgjvmtienv)->GetFrameCount(remotedbgjvmtienv, (jthread)par1, &count); + (*jvmtienv)->GetFrameCount(jvmtienv, (jthread)par1, &count); return count; } @@ -215,7 +218,7 @@ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getFrameCount(JNIE */ JNIEXPORT s4 JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_getThreadStatus(JNIEnv *env, jclass clazz, struct java_lang_Thread* par1) { jint status; - if (JVMTI_ERROR_NONE != (*remotedbgjvmtienv)->GetThreadState(remotedbgjvmtienv, (jthread)par1, &status)) + if (JVMTI_ERROR_NONE != (*jvmtienv)->GetThreadState(jvmtienv, (jthread)par1, &status)) return 0; if (status && JVMTI_THREAD_STATE_ALIVE) { if (status && JVMTI_THREAD_STATE_WAITING) { @@ -265,8 +268,8 @@ JNIEXPORT struct java_lang_String* JNICALL Java_gnu_classpath_jdwp_VMVirtualMach char* srcname; jstring str; - (*remotedbgjvmtienv)-> - GetSourceFileName(remotedbgjvmtienv, (jclass)par1, &srcname); + (*jvmtienv)-> + GetSourceFileName(jvmtienv, (jclass)par1, &srcname); str = (*env)->NewString(env,(jchar*)srcname,(jsize)strlen(srcname)); return (struct java_lang_String*)str; @@ -312,8 +315,8 @@ JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_registerEvent(JN kindid = (*env)->GetFieldID(env, erc, "_kind", "B"); kind = (*env)->GetByteField(env, (jobject)par1, kindid); - (*remotedbgjvmtienv)-> - SetEventNotificationMode(remotedbgjvmtienv, JVMTI_ENABLE, + (*jvmtienv)-> + SetEventNotificationMode(jvmtienv, JVMTI_ENABLE, EventKind2jvmtiEvent(kind), NULL); /* todo: error handling, suspend policy */ @@ -335,8 +338,8 @@ JNIEXPORT void JNICALL Java_gnu_classpath_jdwp_VMVirtualMachine_unregisterEvent( kindid = (*env)->GetFieldID(env, erc, "_kind", "B"); kind = (*env)->GetByteField(env, (jobject)par1, kindid); - (*remotedbgjvmtienv)-> - SetEventNotificationMode(remotedbgjvmtienv, JVMTI_DISABLE, + (*jvmtienv)-> + SetEventNotificationMode(jvmtienv, JVMTI_DISABLE, EventKind2jvmtiEvent(kind), NULL); /* todo: error handling, suspend policy */ diff --git a/src/vm/vm.c b/src/vm/vm.c index 6aeecd43b..93c04ce79 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -26,7 +26,7 @@ Authors: Christian Thalinger - Changes: + Changes: Martin Platter $Id: finalizer.c 4357 2006-01-22 23:33:38Z twisti $ @@ -511,6 +511,15 @@ bool vm_create(JavaVMInitArgs *vm_args) s4 opt; s4 i, j, k; + +#if defined(ENABLE_JVMTI) + lt_dlhandle handle; + char* libname; + bool agentbypath = false;; +#endif + + + /* check the JNI version requested */ switch (vm_args->version) { @@ -583,10 +592,7 @@ bool vm_create(JavaVMInitArgs *vm_args) #if defined(ENABLE_JVMTI) /* initialize JVMTI related **********************************************/ - jvmtibrkpt.brk=NULL; - jvmtibrkpt.num=0; - jvmtibrkpt.size=0; - jdwp = jvmti = dbgprocess = false; + jdwp = jvmti = false; #endif /* initialize properties before commandline handling */ @@ -713,7 +719,9 @@ bool vm_create(JavaVMInitArgs *vm_args) } break; + case OPT_AGENTPATH: + agentbypath = true; case OPT_AGENTLIB: jvmti=true; agentarg = opt_arg; @@ -1053,18 +1061,11 @@ bool vm_create(JavaVMInitArgs *vm_args) } #if defined(ENABLE_JVMTI) - /* The fork has to occure before threads a created because threads are - not forked correctly (see man pthread_atfork). Varibale dbgprocess - stores information whether this is the debugger or debuggee process. */ - if (jvmti || jdwp) { + if (jvmti) { set_jvmti_phase(JVMTI_PHASE_ONLOAD); - dbgprocess = cacaodbgfork(); - } - - if (dbgprocess && jvmti) { /* is this the parent/debugger process ? */ - agentload(agentarg); - set_jvmti_phase(JVMTI_PHASE_PRIMORDIAL); + agentload(agentarg, agentbypath, &handle, &libname); } + set_jvmti_phase(JVMTI_PHASE_PRIMORDIAL); #endif @@ -1211,6 +1212,13 @@ bool vm_create(JavaVMInitArgs *vm_args) /* throw_main_exception_exit(); */ #endif +#if defined(ENABLE_JVMTI) + if (jvmti) { + /* add agent library to native library hashtable */ + native_hashtable_library_add(utf_new_char(libname), class_java_lang_Object->classloader, handle); + } +#endif + /* increment the number of VMs */ vms++; @@ -1265,10 +1273,8 @@ void vm_exit(s4 status) assert(class_java_lang_System->state & CLASS_LOADED); #if defined(ENABLE_JVMTI) - if (dbgprocess) { - set_jvmti_phase(JVMTI_PHASE_DEAD); - if (jvmti) agentunload(); - } + set_jvmti_phase(JVMTI_PHASE_DEAD); + if (jvmti) agentunload(); #endif if (!link_class(class_java_lang_System)) @@ -1305,13 +1311,6 @@ void vm_exit(s4 status) void vm_shutdown(s4 status) { -#if defined(ENABLE_JVMTI) - if (dbgprocess) { - set_jvmti_phase(JVMTI_PHASE_DEAD); - if (jvmti) agentunload(); - ipcrm(); - } -#endif if (opt_verbose #if defined(ENABLE_STATISTICS) || opt_getcompilingtime || opt_stat @@ -1338,12 +1337,6 @@ 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);