* Removed all Id tags.
[cacao.git] / src / native / jvmti / cacaodbg.c
index bfeee43b53a905ede73cb9896860e0f60d879dde..f5753dfe6430f3732325bcf4dbe8d7c38b25fb67 100644 (file)
    Changes: Edwin Steiner
             Samuel Vinson
 
-   $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 <signal.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <sys/wait.h>
 
 
-/* allthreads *****************************************************************
+/* jvmti_get_all_threads ******************************************************
 
    Gets an array of threadobjects of all threads
 
 *******************************************************************************/
-jvmtiError allthreads (jint * threads_count_ptr, threadobject*** threads_ptr) {
+jvmtiError jvmti_get_all_threads (jint * threads_count_ptr, 
+                                                                 threadobject*** threads_ptr) {
     int i = 0, cnt = 8; 
     threadobject *thread, **tthreads;
        
@@ -79,7 +79,7 @@ jvmtiError allthreads (jint * threads_count_ptr, threadobject*** threads_ptr) {
                   tthreads[i] = thread;
                   i++;
                }
-               thread = thread->info.prev;
+               thread = thread->prev;
 
                /* repeat until we got the pointer to the mainthread twice */
        } while (mainthreadobj != thread);
@@ -96,24 +96,24 @@ jvmtiError allthreads (jint * threads_count_ptr, threadobject*** threads_ptr) {
 }
 
 
-/* getcurrentthread ***********************************************************
+/* jvmti_get_current_thread ***************************************************
 
    Get jthread structure of current thread. 
 
 *******************************************************************************/
-jthread getcurrentthread() {
+jthread jvmti_get_current_thread() {
        return (jthread)(threads_get_current_threadobject())->o.thread;
 }
 
 
 
-/* brktablecreator*************************************************************
+/*  breakpointtable_creator ***************************************************
 
    helper function to enlarge the breakpoint table if needed
 
 *******************************************************************************/
 
-static void brktablecreator() {
+static void breakpointtable_creator() {
        struct _brkpt* tmp;
        struct brkpts *jvmtibrkpt;
 
@@ -134,54 +134,69 @@ static void brktablecreator() {
 }
 
 
-/* setsysbrkpt ****************************************************************
+/* jvmti_set_system_breakpoint ************************************************
 
    sets a system breakpoint in breakpoint table and calls set breakpoint
 
 *******************************************************************************/
 
-void setsysbrkpt(int sysbrk, void* addr) {     
+void jvmti_set_system_breakpoint(int sysbrk, bool mode) {      
        struct brkpts *jvmtibrkpt;
 
        pthread_mutex_lock(&dbgcomlock);
-       jvmtibrkpt = &dbgcom->jvmtibrkpt;;
+       jvmtibrkpt = &dbgcom->jvmtibrkpt;
 
+       assert (sysbrk < BEGINUSERBRK); 
        if (jvmtibrkpt->size == jvmtibrkpt->num)
-               brktablecreator();
-
-       assert (sysbrk < BEGINUSERBRK);
-       jvmtibrkpt->brk[sysbrk].addr = addr;
-
-
-       dbgcom->setbrkpt = true;
-       dbgcom->brkaddr = addr;
-       jvmtibrkpt->brk[sysbrk].orig = dbgcom->brkorig;
+               breakpointtable_creator();
+
+       if (mode) {
+               /* add breakpoint*/
+               if (jvmtibrkpt->brk[sysbrk].count > 0) {
+                       jvmtibrkpt->brk[sysbrk].count++;
+                       pthread_mutex_unlock(&dbgcomlock);
+                       return;
+               }
+               dbgcom->addbrkpt = true;
+               dbgcom->brkaddr = jvmtibrkpt->brk[sysbrk].addr;
+       } else {
+               /* remove breakpoint*/          
+               if ((jvmtibrkpt->brk[sysbrk].count == 1) ) {
+                       jvmtibrkpt->brk[sysbrk].count--;
+                       /* remove breakpoint */
+                       dbgcom->addbrkpt = false;
+                       dbgcom->brkaddr = jvmtibrkpt->brk[sysbrk].addr;
+               } else {
+                       /* avoid negative counter values */
+                       if (jvmtibrkpt->brk[sysbrk].count > 0) jvmtibrkpt->brk[sysbrk].count--;
+                       pthread_mutex_unlock(&dbgcomlock);
+                       return;
+               }
+       }
        pthread_mutex_unlock(&dbgcomlock);
-
        /* call cacaodbgserver */
+       __asm__ ("setsysbrkpt:");
        TRAP; 
-
-       fprintf (stderr,"setsysbrk %d %X  done\n",sysbrk, addr);
 }
 
 
-/* addbrkpt *******************************************************************
+/* jvmti_add_breakpoint *******************************************************
 
    adds a breakpoint to breakpoint table and calls set breakpoint
 
 *******************************************************************************/
 
-void addbrkpt(void* addr, jmethodID method, jlocation location) {
+void jvmti_add_breakpoint(void* addr, jmethodID method, jlocation location) {
        struct brkpts *jvmtibrkpt;
 
        pthread_mutex_lock(&dbgcomlock);
        jvmtibrkpt = &dbgcom->jvmtibrkpt;;
 
        if (jvmtibrkpt->size == jvmtibrkpt->num)
-               brktablecreator();
+               breakpointtable_creator();
 
        assert (jvmtibrkpt->size > jvmtibrkpt->num);
-       fprintf (stderr,"add brk add: %X\n",addr);
+       fprintf (stderr,"add brk add: %p\n",addr);
        jvmtibrkpt->brk[jvmtibrkpt->num].addr = addr;
        jvmtibrkpt->brk[jvmtibrkpt->num].method = method;
        jvmtibrkpt->brk[jvmtibrkpt->num].location = location;
@@ -195,115 +210,236 @@ void addbrkpt(void* addr, jmethodID method, jlocation location) {
 }
 
 
-/* setup_jdwp_thread *****************************************************
 
-   Helper function to start JDWP threads
 
-*******************************************************************************/
+/* jvmti_cacaodbgserver_quit **************************************************
 
-void setup_jdwp_thread(char* transport) {
-       java_objectheader *o;
-       methodinfo *m;
-       java_lang_String  *s;
-       classinfo *class;
+   quits cacaodbgserver if the last jvmti environment gets disposed
 
-       /* new gnu.classpath.jdwp.Jdwp() */
-       class = load_class_from_sysloader(
-            utf_new_char("gnu.classpath.jdwp.Jdwp"));
-       if (!class)
-               throw_main_exception_exit();
+*******************************************************************************/
+void jvmti_cacaodbgserver_quit(){
+       pthread_mutex_lock(&dbgcomlock);
+       dbgcom->running--;
+       if (dbgcom->running  == 0) {
+               __asm__ ("cacaodbgserver_quit:");
+               TRAP;
+               /* get cacaodbserver exit */
+               wait(NULL);
+               dbgcom = NULL;
+       }
+       pthread_mutex_unlock(&dbgcomlock);
+}
 
-       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_from_ascii(&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);
-}
 
-/* cacaobreakpointhandler **********************************************************
+/* jvmti_cacao_generic_breakpointhandler **************************************
 
-   handles breakpoints. called by cacaodbgserver.
+   convert cacao breakpoints in jvmti events and fire event
 
 *******************************************************************************/
 
-void cacaobreakpointhandler() {
-       basic_event ev;
-       genericEventData data;
-       int i;
-
-       /* XXX to be continued :-) */
-
-       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) && (i<dbgcom->jvmtibrkpt.num)) i++;
-               
-               fprintf(stderr,"cacaodbglisten SIGTRAP switch after while loop i %d\n",i);
-               
-               switch (i) {
-               case SETTHREADOBJECTBRK:
-                       /* threads_set_current_threadobject */
-                       fprintf(stderr,"IP %X == threads_set_current_threadobject\n",ev.ip);
-                       data.ev=JVMTI_EVENT_THREAD_START;
-                       fireEvent(&data);
-                       break;
-               default:
-                       if ((i >= BEGINUSERBRK) && (i<dbgcom->jvmtibrkpt.num)) {
-                               log_text("todo: user defined breakpoints are not handled yet");
-                       } else 
-                               log_text("breakpoint not handled - continue anyway");
-               }
+static void jvmti_cacao_generic_breakpointhandler(int kindofbrk){
+       genericEventData data; 
+
+       switch (kindofbrk) {
+       case THREADSTARTBRK:
+               data.ev=JVMTI_EVENT_THREAD_START; 
+               break;
+       case THREADENDBRK:
+               data.ev=JVMTI_EVENT_THREAD_END; 
+               break;
+       case CLASSLOADBRK:
+               data.ev=JVMTI_EVENT_CLASS_LOAD; 
+               break;
+       case CLASSPREPARERK:
+               data.ev=JVMTI_EVENT_CLASS_PREPARE; 
                break;
-       case SIGQUIT:
-               log_text("debugger process SIGQUIT");
-               data.ev=JVMTI_EVENT_VM_DEATH;
-               fireEvent(&data);               
+       case CLASSFILELOADHOOKBRK:
+               data.ev=JVMTI_EVENT_CLASS_FILE_LOAD_HOOK; 
+               break;
+       case COMPILEDMETHODLOADBRK:
+               data.ev=JVMTI_EVENT_COMPILED_METHOD_LOAD; 
+               break;
+       case COMPILEDMETHODUNLOADBRK:
+               data.ev=JVMTI_EVENT_COMPILED_METHOD_UNLOAD; 
                break;
        default:
-               log_text("signal not handled");
+               fprintf(stderr,"unhandled kind of cacao break %d\n",kindofbrk);
+               return;
        }
+       jvmti_fireEvent(&data);
+}
+
+
+
+/* jvmti_cacao_debug_init ***************************************************************
+
+   starts up a new cacaodbgserver process if needed
+
+*******************************************************************************/
+
+void jvmti_cacao_debug_init() {
+       pid_t dbgserver;        
+
+       /* start new cacaodbgserver if needed*/
+       pthread_mutex_lock(&dbgcomlock);
+       if (dbgcom == NULL) {
+               dbgcom = heap_allocate(sizeof(cacaodbgcommunication),true,NULL);                
+               dbgcom->running = 1;
+               jvmti = true;
+
+               breakpointtable_creator();
+               /* set addresses of hard coded TRAPs */
+               __asm__ ("movl $setsysbrkpt,%0;" 
+                        :"=m"(dbgcom->jvmtibrkpt.brk[SETSYSBRKPT].addr));
+               __asm__ ("movl $cacaodbgserver_quit,%0;" 
+                        :"=m"(dbgcom->jvmtibrkpt.brk[CACAODBGSERVERQUIT].addr));
+
+               dbgserver = fork();
+               if (dbgserver  == (-1)) {
+                       log_text("cacaodbgserver fork error");
+                       exit(1);
+               } else {
+                       if (dbgserver == 0) {
+                               if (execlp("cacaodbgserver","cacaodbgserver",(char *) NULL) == -1) {
+                                       log_text("unable to execute cacaodbgserver");
+                                       exit(1);
+                               }
+                       }
+               }
+               pthread_mutex_unlock(&dbgcomlock);
+               /* let cacaodbgserver get ready */
+               sleep(1);
+       } else {
+               dbgcom->running++;
+               pthread_mutex_unlock(&dbgcomlock);
+       }
+}
+
+
+/* jvmti_ClassFileLoadHook ****************************************************
+
+  prepares firing a new Class File Load Hook event
+
+*******************************************************************************/
+
+void jvmti_ClassFileLoadHook(utf* name, int class_data_len, 
+                                                        unsigned char* class_data, 
+                                                        java_objectheader* loader, 
+                                                        java_objectheader* protection_domain, 
+                                                        jint* new_class_data_len, 
+                                                        unsigned char** new_class_data) {
+       genericEventData d;
+       
+       d.ev = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK;
+       d.klass = NULL; /* class is not redefined */
+       d.object = loader;
+       d.name = (char*)MNEW(char,(utf_bytes(name)+1));
+       utf_sprint_convert_to_latin1(d.name, name);
+       d.protection_domain = protection_domain;
+       d.class_data = class_data;
+       d.jint1 = class_data_len;
+       d.new_class_data_len = new_class_data_len;
+       d.new_class_data = new_class_data;
+
+       jvmti_fireEvent(&d);
+       MFREE(d.name,char,utf_bytes(name)+1);
 }
 
 
+/* jvmti_ClassFileLoadHook ****************************************************
+
+  prepares firing a new Class Prepare or Load event
+
+*******************************************************************************/
+
+void jvmti_ClassLoadPrepare(bool prepared, classinfo *c) {
+       genericEventData d;
+
+       if (prepared) 
+               d.ev = JVMTI_EVENT_CLASS_PREPARE;
+       else 
+               d.ev = JVMTI_EVENT_CLASS_LOAD;
+
+       d.klass = c;
+       jvmti_fireEvent(&d);    
+}
+
+
+/* jvmti_MonitorContendedEntering *********************************************
+
+  prepares firing a new Monitor Contended Enter or Entered event
+
+*******************************************************************************/
+
+void jvmti_MonitorContendedEntering(bool entered, jobject obj) {
+       genericEventData d;
+
+       if (entered) 
+               d.ev = JVMTI_EVENT_MONITOR_CONTENDED_ENTERED;
+       else 
+               d.ev = JVMTI_EVENT_MONITOR_CONTENDED_ENTER;
+
+       d.object = obj;
+
+       jvmti_fireEvent(&d);    
+}
+
+/* jvmti_MonitorWaiting ******************************************************
+
+  prepares firing a new Monitor Wait or Waited event
+
+*******************************************************************************/
+
+void jvmti_MonitorWaiting(bool wait, jobject obj, jlong timeout) {
+       genericEventData d;
+
+       if (wait) {
+               d.ev = JVMTI_EVENT_MONITOR_WAIT;
+               d.jlong = timeout;
+       } else {
+               d.ev = JVMTI_EVENT_MONITOR_WAITED;
+               d.b = timeout != 0;
+       }
+
+       d.object = obj;
+
+       jvmti_fireEvent(&d);    
+}
+
+/* jvmti_ThreadStartEnd ********************************************************
+
+  prepares firing a new Thread Start or End event
+
+*******************************************************************************/
+
+void jvmti_ThreadStartEnd(jvmtiEvent ev) {
+       genericEventData d;
+
+       d.ev = ev;
+       jvmti_fireEvent(&d);    
+}
+
+/* jvmti_NativeMethodBind *****************************************************
+
+  prepares firing a new Native Method Bind event
+
+*******************************************************************************/
+
+void jvmti_NativeMethodBind(jmethodID method, void* address, 
+                                                       void** new_address_ptr) {
+       genericEventData d;
+
+       d.ev = JVMTI_EVENT_NATIVE_METHOD_BIND;
+       d.method = method;
+       d.address = address;
+       d.new_address_ptr = new_address_ptr;
+       
+       jvmti_fireEvent(&d);    
+}
+
+
+
 /*
  * 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