[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[dotgnu-pnet-commits] pnet ChangeLog engine/debugger.c engine/debugge...
From: |
Radek Polak |
Subject: |
[dotgnu-pnet-commits] pnet ChangeLog engine/debugger.c engine/debugge... |
Date: |
Thu, 20 Dec 2007 09:37:23 +0000 |
CVSROOT: /sources/dotgnu-pnet
Module name: pnet
Changes by: Radek Polak <radekp> 07/12/20 09:37:23
Modified files:
. : ChangeLog
engine : debugger.c debugger.h ilrun.c
include : il_debugger.h
Added files:
doc : debugger.txt
Log message:
Implemented parameters for remote debugging, some more debugger
features and fixes
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pnet/ChangeLog?cvsroot=dotgnu-pnet&r1=1.3526&r2=1.3527
http://cvs.savannah.gnu.org/viewcvs/pnet/doc/debugger.txt?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/pnet/engine/debugger.c?cvsroot=dotgnu-pnet&r1=1.28&r2=1.29
http://cvs.savannah.gnu.org/viewcvs/pnet/engine/debugger.h?cvsroot=dotgnu-pnet&r1=1.8&r2=1.9
http://cvs.savannah.gnu.org/viewcvs/pnet/engine/ilrun.c?cvsroot=dotgnu-pnet&r1=1.59&r2=1.60
http://cvs.savannah.gnu.org/viewcvs/pnet/include/il_debugger.h?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/dotgnu-pnet/pnet/ChangeLog,v
retrieving revision 1.3526
retrieving revision 1.3527
diff -u -b -r1.3526 -r1.3527
--- ChangeLog 11 Dec 2007 20:27:42 -0000 1.3526
+++ ChangeLog 20 Dec 2007 09:37:22 -0000 1.3527
@@ -1,3 +1,19 @@
+2007-12-20 Radek Polak <address@hidden>
+
+ * engine/debugger.c: Implemented debugger connecection to frontend. It
+ can be specified by IP address, it can work on stdio and it can be
+ tracing automat with output on stdout. Fixed unregistering debug hook
+ properly.
+
+ * engine/debugger.h: Added flag to not start IO thread.
+
+ * include/il_debugger.h: Added one more variable for user data.
+
+ * engine/ilrun.c: Removed unnecessary error output. Debugger
+ parameters cleanup.
+
+ * doc/debugger.txt: Added some documentation for debugger.
+
2007-12-11 Klaus Treichel <address@hidden>
* engine/jitc.c: Clean up a not needed commented
_IL_JIT_OPTIMIZE_LOCALS.
Index: engine/debugger.c
===================================================================
RCS file: /sources/dotgnu-pnet/pnet/engine/debugger.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- engine/debugger.c 11 Dec 2007 09:50:58 -0000 1.28
+++ engine/debugger.c 20 Dec 2007 09:37:23 -0000 1.29
@@ -65,14 +65,14 @@
*/
static void ILDbOutOfMemory()
{
- fputs("il_debugger: virtual memory exhausted\n", stderr);
+ fputs("debugger: virtual memory exhausted\n", stderr);
exit(1);
}
/*
* Open stream for writing and reading text. Return 0 on failure.
*/
-static FILE *OpenStream()
+static FILE *OpenTmpStream()
{
return tmpfile();
}
@@ -104,12 +104,47 @@
/*
* Open socket IO.
- * TODO: only supported connection string is tcp://localhost:4571
*/
static int SocketIO_Open(ILDebuggerIO *io, const char *connectionString)
{
ILSysIOHandle sockfd;
- int port = 4571;
+ int index = 0;
+ const char *ch;
+ unsigned int conn[5];
+ unsigned char addr[16];
+
+ /* Parse connection string */
+ if(connectionString != 0)
+ {
+ ch = connectionString;
+ ILMemSet(conn, 0, sizeof(conn));
+ while(*ch != 0 && index <= 4)
+ {
+ if(*ch >= '0' && *ch <= '9')
+ {
+ conn[index] = (10 * conn[index]) + (*ch - '0');
+ }
+ else if(*ch == '.' || *ch == ':')
+ {
+ index++;
+ }
+ ch++;
+ }
+ }
+ else
+ {
+ /* Default host */
+ conn[0] = 127;
+ conn[1] = 0;
+ conn[2] = 0;
+ conn[3] = 1;
+ }
+
+ /* Default port if we havent parsed it */
+ if(index <= 3)
+ {
+ conn[4] = 4571;
+ }
/*
* Create socket descriptor
@@ -120,47 +155,33 @@
sockfd = ILSysIOSocket(2, 1, 6);
if(sockfd == ILSysIOHandle_Invalid)
{
- perror("il_debugger: socket creation failed");
+ perror("debugger create socket");
return 0;
}
/* Convert the end point into a sockaddr buffer like in
* CombinedToSerialized() in socket.c */
- unsigned char addr[16];
addr[0] = 2;
/* address family - AF_INET */
addr[1] = 0;
- addr[2] = (unsigned char)(port >> 8); /* port */
- addr[3] = (unsigned char)port;
- addr[4] = 127;
/* end point 127.0.0.1 */
- addr[5] = 0;
- addr[6] = 0;
- addr[7] = 1;
+ addr[2] = (unsigned char)(conn[4] >> 8); /* port */
+ addr[3] = (unsigned char)(conn[4]);
+ addr[4] = (unsigned char)(conn[0]); /* end point
127.0.0.1 */
+ addr[5] = (unsigned char)(conn[1]);
+ addr[6] = (unsigned char)(conn[2]);
+ addr[7] = (unsigned char)(conn[3]);
addr[8] = addr[9] = addr[10] = addr[11] =
addr[12] = addr[13] =
addr[14]= addr[15] = 0;
- /* Connect, this connects socket for ipv4.
- TODO: we should do it more correctly (see Socket.cs Connect()) */
+ /* Connect, this connects socket for ipv4 */
if(!ILSysIOSocketConnect(sockfd, addr, 16))
{
- perror("il_debugger: connect to socket failed");
+ perror("debugger connect");
return 0;
}
/* Setup io struct */
io->sockfd = sockfd;
- io->input = OpenStream();
- if(io->input == 0)
- {
- perror("il_debugger: failed to open input stream");
- return 0;
- }
- io->output = OpenStream();
- if(io->output == 0)
- {
- perror("il_debugger: failed to open output stream");
- return 0;
- }
return 1;
}
@@ -190,7 +211,7 @@
len = ILSysIOSocketReceive(io->sockfd, (void *)buffer, 128, 0);
if(len < 0)
{
- perror("il_debugger: recieve failed");
+ perror("debugger recieve");
return 0;
}
fwrite(buffer, 1, len, io->input);
@@ -230,12 +251,12 @@
}
if(fread((void *)buffer, 1, count, io->output) != count)
{
- perror("il_debugger: send failed");
+ perror("debugger send");
return 0;
}
if(ILSysIOSocketSend(io->sockfd, buffer, count, 0) < 0)
{
- perror("il_debugger: send failed");
+ perror("debugger send");
return 0;
}
len -= 1024;
@@ -249,6 +270,142 @@
}
/*
+ * Common recieving function std and file IO.
+ */
+static int StreamRecieve(ILDebuggerIO *io, FILE *stream, int isStd)
+{
+ int ch;
+
+ /* Rewind input stream */
+ fseek(io->input, 0, SEEK_SET);
+
+ /* Display cursor */
+ if(isStd)
+ {
+ fputs("\n> ", stdout);
+ }
+
+ /* Read line */
+ for(;;)
+ {
+ ch = fgetc(stream);
+
+ if(ch == EOF && !isStd)
+ {
+ fseek(stream, 0, SEEK_SET); // rewind input
+ }
+ else if(ch != '\n')
+ {
+ fputc(ch, io->input);
+ continue;
+ }
+ return 1;
+ }
+}
+
+/*
+ * Common sending function for std and file IO.
+ */
+static int StreamSend(ILDebuggerIO *io, FILE *stream, int isStd)
+{
+ int ch;
+
+ /* Terminate output with 0 */
+ putc(0, io->output);
+
+ /* Rewind output stream */
+ fseek(io->output, 0, SEEK_SET);
+
+ /* Read data from output stream and send it out */
+ while((ch = fgetc(io->output)) != 0)
+ {
+ fputc(ch, stream);
+ }
+
+ /* Rewind output stream for next command */
+ fseek(io->output, 0, SEEK_SET);
+
+ return 1;
+}
+
+/*
+ * Open stdio IO.
+ */
+static int StdIO_Open(ILDebuggerIO *io, const char *connectionString)
+{
+ return 1;
+}
+
+/*
+ * Close std IO.
+ */
+static void StdIO_Close(ILDebuggerIO *io)
+{
+ /* Nothing to do here */
+}
+
+/*
+ * Recieve input data from input file.
+ */
+static int StdIO_Recieve(ILDebuggerIO *io)
+{
+ return StreamRecieve(io, stdin, 1);
+}
+
+/*
+ * Send data in output stream out.
+ */
+static int StdIO_Send(ILDebuggerIO *io)
+{
+ return StreamSend(io, stdout, 1);
+}
+
+/*
+ * Return next trace command.
+ */
+static int TraceIO_Recieve(ILDebuggerIO *io)
+{
+ const char *ch;
+ static const char *commands = "show_position\nstep\nshow_locals";
+
+ /* Rewind input stream */
+ fseek(io->input, 0, SEEK_SET);
+
+ /* Make ch point to command to be executed */
+ if(io->data1 == 0)
+ {
+ ch = commands;
+ }
+ else
+ {
+ ch = (const char *) io->data1;
+ }
+
+ /* Output command to io->input */
+ for(;;)
+ {
+ if(*ch == 0)
+ {
+ ch = commands;
+ break;
+ }
+ if(*ch == '\n')
+ {
+ ch++;
+ break;
+ }
+ fputc(*ch, io->input);
+ fputc(*ch, stdout);
+ ch++;
+ }
+
+ io->data1 = (void *) ch;
+ fputc('\n', stdout);
+
+ return 1;
+}
+
+/*
* Return next argument for current command.
* Call with prev=0 to obtain first argument.
* Returns 0 after last argument is reached.
@@ -3054,6 +3211,11 @@
return 0;
}
+ if(debugger->dontStartIoThread)
+ {
+ return 0;
+ }
+
/* Create command loop thread */
debugger->ioThread = ILThreadCreate(IOThreadFn, (void *) debugger);
@@ -3328,36 +3490,58 @@
int ILDebuggerConnect(ILDebugger *debugger, char *connectionString)
{
+ ILDebuggerIO *io = debugger->io;
+
/* Check if custom IO was previously set */
- if(debugger->io == 0)
+ if(io == 0)
{
- /* Only supported connection string is tcp://localhost:4571
- * return error for anything else for now */
- if(strcmp(connectionString, "tcp://localhost:4571") != 0)
+ /* Create debugger IO structure */
+ debugger->io = io = (ILDebuggerIO *)
ILMalloc(sizeof(ILDebuggerIO));
+ if(io == 0)
{
- fprintf(stderr, "il_debugger: connection string not
supported\n");
return 0;
}
- /* Create debugger IO from known connectionString scheme */
- debugger->io = (ILDebuggerIO *) ILMalloc(sizeof(ILDebuggerIO));
- if(debugger->io == 0)
+ /* Setup default socket based IO */
+ io->open = &SocketIO_Open;
+ io->close = &SocketIO_Close;
+ io->recieve = &SocketIO_Recieve;
+ io->send = &SocketIO_Send;
+
+ if(connectionString != 0)
{
- return 0;
+ if(strcmp(connectionString, "stdio") == 0)
+ {
+ /* Reading and sending on stdio */
+ io->open = &StdIO_Open;
+ io->close = &StdIO_Close;
+ io->recieve = &StdIO_Recieve;
+ io->send = &StdIO_Send;
+ }
+ else if(strcmp(connectionString, "trace") == 0)
+ {
+ io->open = &StdIO_Open;
+ io->close = &StdIO_Close;
+ io->recieve = &TraceIO_Recieve;
+ io->send = &StdIO_Send;
+
+ /* When tracing we dont need command thread */
+ debugger->dontStartIoThread = 1;
+ }
+ }
}
- /*
- * Only supported connection string is tcp://localhost:4571
- * so setup members for socket based IO
- */
- debugger->io->open = &SocketIO_Open;
- debugger->io->close = &SocketIO_Close;
- debugger->io->recieve = &SocketIO_Recieve;
- debugger->io->send = &SocketIO_Send;
+ /* Open temporary seekable streams */
+ io->input = OpenTmpStream();
+ io->output = OpenTmpStream();
+ if(io->input == 0 || io->output == 0)
+ {
+ perror("debugger open stream");
+ return 0;
}
/* Try to connect to debugger client */
- return debugger->io->open(debugger->io, connectionString);
+ return io->open(io, connectionString);
}
int ILDebuggerIsAttached(ILExecProcess *process)
@@ -3409,8 +3593,9 @@
{
ILDebuggerIODestroy(debugger->io);
}
- /* Unregister hook function */
+ /* Unregister hook function and unwatch all */
ILExecProcessDebugHook(debugger->process, 0, 0);
+ ILExecProcessWatchAll(debugger->process, 0);
/* Detach debugger from process */
if(debugger->process)
@@ -3439,7 +3624,7 @@
debugger->lock = ILMutexCreate();
if(!(debugger->lock))
{
- fprintf(stderr, "il_debugger: failed to create mutex\n");
+ fputs("debugger: failed to create mutex\n", stderr);
ILDebuggerDestroy(debugger);
return 0;
}
@@ -3448,7 +3633,7 @@
debugger->userData = ILUserDataCreate();
if(debugger->userData == 0)
{
- fprintf(stderr, "il_debugger: failed to create user data\n");
+ fputs("debugger: failed to create user data\n", stderr);
ILDebuggerDestroy(debugger);
return 0;
}
@@ -3476,7 +3661,7 @@
debugger->event = ILWaitEventCreate(0, 0);
if(!(debugger->event))
{
- fprintf(stderr, "il_debugger: failed to create wait handle\n");
+ fputs("debugger: failed to create wait handle\n", stderr);
ILDebuggerDestroy(debugger);
return 0;
}
@@ -3484,8 +3669,8 @@
/* Register debug hook function */
if(ILExecProcessDebugHook(process, DebugHook, 0) == 0)
{
- fprintf(stderr,
- "il_debugger: the runtime engine does not support
debugging.\n");
+ fputs("debugger: the runtime engine does not support
debugging.\n",
+
stderr);
ILDebuggerDestroy(debugger);
return 0;
}
Index: engine/debugger.h
===================================================================
RCS file: /sources/dotgnu-pnet/pnet/engine/debugger.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -b -r1.8 -r1.9
--- engine/debugger.h 11 Dec 2007 09:50:58 -0000 1.8
+++ engine/debugger.h 20 Dec 2007 09:37:23 -0000 1.9
@@ -233,6 +233,9 @@
/* Return IL_HOOK_ABORT from hook function when this flag is set */
int volatile abort;
+ /* Nonzero to not start IO thread */
+ int dontStartIoThread;
+
};
Index: engine/ilrun.c
===================================================================
RCS file: /sources/dotgnu-pnet/pnet/engine/ilrun.c,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -b -r1.59 -r1.60
--- engine/ilrun.c 10 Mar 2007 21:54:57 -0000 1.59
+++ engine/ilrun.c 20 Dec 2007 09:37:23 -0000 1.60
@@ -191,6 +191,7 @@
int profilingEnabled = 0;
#endif
#ifdef IL_DEBUGGER
+ int debuggerEnabled = 0;
char *debuggerConnectionString = 0;
ILDebugger *debugger = 0;
#endif
@@ -320,18 +321,16 @@
#endif
#ifdef IL_DEBUGGER
- case 'g':
- {
- if(debuggerConnectionString == 0)
+ case 'G':
{
- debuggerConnectionString =
"tcp://localhost:4571";
- }
+ debuggerConnectionString = param;
+ debuggerEnabled = 1;
}
break;
- case 'G':
+ case 'g':
{
- debuggerConnectionString = param;
+ debuggerEnabled = 1;
}
break;
#endif
@@ -416,12 +415,13 @@
#ifdef IL_DEBUGGER
/* Extract debugger connection string from environment
* if not specified on command line */
- if(debuggerConnectionString == 0)
+ if(!debuggerEnabled)
{
debuggerConnectionString =
getenv("IL_DEBUGGER_CONNECTION_STRING");
+ debuggerEnabled = (debuggerConnectionString != 0);
}
/* Connect to debugger client, if we have connection string */
- if(debuggerConnectionString)
+ if(debuggerEnabled)
{
/* Create debugger */
debugger = ILDebuggerCreate(process);
@@ -437,9 +437,6 @@
/* Connect failed - destroy debugger and print
error */
ILDebuggerDestroy(debugger);
debugger = 0;
- fprintf(stderr, "%s: debugger connection failed
on %s\n",
-
progname,
-
debuggerConnectionString);
}
}
}
Index: include/il_debugger.h
===================================================================
RCS file: /sources/dotgnu-pnet/pnet/include/il_debugger.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- include/il_debugger.h 10 Mar 2007 21:54:57 -0000 1.5
+++ include/il_debugger.h 20 Dec 2007 09:37:23 -0000 1.6
@@ -61,7 +61,8 @@
/*
* Implementation specific data.
*/
- void *data;
+ void *data1;
+ void *data2;
/*
* Handle for socket stream implementation.
@@ -69,12 +70,14 @@
ILSysIOHandle sockfd;
/*
- * Stream used by debugger for recieving data.
+ * Stream used for recieving data.
+ * IO fills it with NIL terminated string on recieve.
*/
FILE *input;
/*
- * Stream used by debugger for sending data.
+ * Stream used for sending data.
+ * IO sends it's NIL terminated content to client on send.
*/
FILE *output;
Index: doc/debugger.txt
===================================================================
RCS file: doc/debugger.txt
diff -N doc/debugger.txt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ doc/debugger.txt 20 Dec 2007 09:37:22 -0000 1.1
@@ -0,0 +1,170 @@
+Quick start
+-----------
+
+If you want to use debugger for debugging your applications please visit this
+page:
+
+ http://home.gna.org/libide/
+
+Rest of this document will deal with debugger internals that regular user does
+not need to know.
+
+Introduction
+------------
+
+Current debugger implementation is by default a part of ilrun program. Debugger
+can be activated e.g. by command line switch of ilrun. Ilrun then connects
+to debugger frontend which is most often some IDE. The frontend can then send
+simple text commands and read responses.
+
+Activation
+----------
+
+Debugger is enabled in default build profile. You can check if you have
+debugger support by invoking:
+
+$ ilrun -D
+Engine Version : 0.8.1
+...
+Debugger support : Yes
+Build Profile : Full
+...
+
+To start debugging ilrun has two command line switches -g and -G. They are used
+to tell ilrun to activate the debugging module before your program starts. They
+also specify how will the debugger talk to it's frontend. Let's see example:
+
+$ ilrun -g MyProgram.exe
+
+The -g option specifies that the default connection should be used. The default
+connection is always socket connection to localhost on port 4571.
+
+Alternatively you can use -G option for custom connection:
+
+$ ilrun -G 192.168.1.2:1234
+$ IL_DEBUGGER_CONNECTION_STRING=192.168.1.2:1234 ilrun MyProgram.exe
+$ ilrun -G stdio MyProgram.exe
+
+The first example can be used e.g. when program is running on different machine
+than the debugger frontend - this is called remote debugging. In this case the
+frontend is on 192.168.1.2 on port 1234. The port information can be ommited
+and standard port 4571 will be used. You should always use IP address because
+debugger does not support DNS resolving.
+
+The second example works similar to -G option, but uses environment variable
+IL_DEBUGGER_CONNECTION_STRING to specify remote frontend. This could be useful
+in situations where you cant modify ilrun's command line options.
+
+The last example will use stdio for sending debugger commands. This is the
+easiest way how to start debugger, but also the most useless for practical use.
+
+Example session
+---------------
+
+In this section we will walkthrough debugging of simple C# program. You will
+need simple TCP server that listens on default debugger port 4571 and that can
+send text commands and read responses after client connects. You can find such
+program here [1]. The program is called ServiceConsole and is part of bigger
+project called PortableStudio [2], which is C# IDE with integrated support for
+Portable.NET.
+
+So first thing to be done is starting server:
+
+$ ilrun ServiceConsole.exe 4571
+The server is running at port 4571
+Waiting for a connection...
+
+Now the program that we want to debug - let's say hello.exe which can be found
+in pnetlib samples.
+
+$ ilrun -g hello.exe
+
+Server should now say:
+Connection accepted
+
+and display prompt:
+>
+
+If you do not want to start server you can try communication with debugger on
+stdio. So instead of previous setup just do:
+
+$ ilrun -G stdio hello.exe
+
+Once you are connected, you can display help for debugger commands:
+> help
+...
+
+Commands function and usage are in most cases clear so we will not describe all
+of them here. Every debugger command sends response after it is executed.
+Response is always structure DebuggerResponse that is serialized to XML text.
+You can find this structure with useful comments here [3]. The XML text is
+always NIL terminated.
+
+For quick start you can try these commands:
+
+> show_position
+> show_locals
+> step
+
+Please note that show_locals is now supported only if you compiled pnet with
+jit coder (--with-jit configure switch).
+
+In most cases you will want to specify which assemblies you want to debug. This
+can be done via watch_assembly command. Debugger will then step only into
+assemblies specified with this command. This will also speedup debugged program
+greatly.
+
+Some debugger commands should be executed only when the program execution is
+stopped. For this purpose use command:
+
+> is_stopped
+
+If the command returns "yes", all debugger commands are safe to be executed.
+Otherwise the program should be stopped. You can use command:
+
+> break
+
+Now you should check is_stopped until it says yes.
+
+If you call some commands e.g. show_locals while program is running it can lead
+to incorrect behavior or even program crash. This will be fixed in future.
+
+Implemntation
+-------------
+
+Most important for implementing debugger is support in engine. Both CVM and JIT
+engine provide debug hooks. This is low-level mechanism, that allows you to
+inject callbacks into various places of debugged program.
+
+Debugger handles engine callbacks in DebugHook() function. This function is
+called after every IL instruction. Debugger decides here what to do. E.g. it
+can decide to stop if breakpoint is reached, it can display local variables or
+do any other command.
+
+Implementing debugger via debug hooks is really easy and portable solution, but
+it has it's downsides too. Calling debug hook function after every instruction
+can dramatically slowdown program execution. Fortunately this only applies when
+debugger is connected - otherwise hooks are not inserted at all. We can also
+achieve a big speedup if we insert hooks only in functions that we are
+interested in. E.g. most user will not want to debug system libraries.
+
+Debugger should also handle multiple threads although it's possible to run
+debugger even on systems that dont have threading (with some limitations).
+Commands like show_locals should be always executed in their thread, because
+displaying watches can involve working with Thread.CurrentThread.
+
+Some debugger functions are difficult to implement in C. For these functions
+we have DebuggerHelper class that is implemented in C#. You can find this class
+in pnetlib/runtime/System/Private directory. This class is called from C and is
+used mainly for displaying watches.
+
+Most of the debugger functions can be found in engine/debugger.c file. Some
+support is also in coders. You can grep for IL_DEBUGGER to find these places.
+
+References
+----------
+
+[1] svn://svn.gna.org/svn/libide/trunk/studio/service_console
+[2] https://gna.org/projects/libide
+[3]
svn://svn.gna.org/svn/libide/trunk/studio/PortableStudio.Data/DebuggerResponseDataInfo.cs
+[4] https://gna.org/projects/libide/studio
\ No newline at end of file
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [dotgnu-pnet-commits] pnet ChangeLog engine/debugger.c engine/debugge...,
Radek Polak <=