* src/vm/vm.c (vm_create): make agentlib/agentpath work
[cacao.git] / src / native / jvmti / cacaodbgserver.c
index d05b35645b241acef05c7cb5cfb8a4cf085991a4..51a520bc49c5f88f6c6ead919d972fc814e97b0e 100644 (file)
@@ -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,
@@ -27,8 +27,8 @@
 
    Authors: Martin Platter
 
-   Changes: 
-
+   Changes: Edwin Steiner
+            Samuel Vinson
 
    $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $
 
 #include <signal.h>
 #include <sys/wait.h>
 #include <stdlib.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <semaphore.h>
-#include <sys/msg.h>
-#include <linux/user.h>
+#include <stdio.h>
 
+pid_t debuggee;
 
 /* getchildprocptrace *********************************************************
 
 
 *******************************************************************************/
 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; i<longcnt; i++) {
                p[i]=GETMEM(debuggee,addr);
-               if (p[i]==-1) 
-                       perror("cacaodbgserver process: getchildprocptrace: ");
+               if (p[i]==-1)
+               {
+                       fprintf(stderr,"cacaodbgserver process: getchildprocptrace: %ld\n",i);
+                       perror("cacaodbgserver process: getchildprocptrace:");
+                       exit(1);
+               }
                addr+=sizeof(long);
        }
-       longcnt = GETMEM(debuggee,addr);
-       memcpy(ptr,&longcnt,cnt%sizeof(long));
-}
-
-/* contchild ******************************************************************
-
-   Helper function to continue child process. 
-
-*******************************************************************************/
-static bool contchild(int signal) {
-       /* get lock for running state */ 
-       sem_wait(&workingdata_lock);
-       fprintf(stderr,"cacaodbgserver: contchild called (hastostop: %d)\n",cdbgshmem->hastostop);
-       if(cdbgshmem->hastostop < 1) {
-               fprintf(stderr,"cacaodbgserver: going to continue child\n");
-               CONT(debuggee,signal);
-               cdbgshmem->hastostop = 0;
-               cdbgshmem->running=true;
-               /* release lock for running state */ 
-               sem_post(&workingdata_lock);
-               return true;
-       } else {
-               sem_post(&workingdata_lock);
-               return false;           
-       }
+       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);
-                       
-                       sem_wait(&workingdata_lock);
-                       cdbgshmem->running = false;
-                       cdbgshmem->hastostop = 1;
-                       sem_post(&workingdata_lock);
-
-                       if (signal==SIGUSR2) {
-                               fprintf(stderr,"SIGUSR2 - debuggee has stopped by jdwp process\n");
-                               return;
-                       }
+               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");
 }
 
 
@@ -311,4 +227,5 @@ void cacaodbgserver() {
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */