[ros-dev] Using BOCHS and external gdb

Mark Junker mjscod at gmx.de
Tue May 3 14:15:49 CEST 2005


Hi,

I just want to mention that COM port redirection is possible in Bochs 
CVS HEAD. Currently it only supports "null", "file", "raw", and "mouse". 
I extended it in my local copy so that you can use "pipe" too.

I attached my patch and my own version of pipetunnel.

This patch is already on the Bochs "Patches" page. I hope that it'll be 
added ASAP to the main source trunk.

BTW: I've seen a patch to allow COM <-> TCP/IP redirection on the 
"Patches" page. When there is interest, I can combine the two patches 
and publish them here ...

Regards,
Mark

-------------- next part --------------
Index: config.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/config.cc,v
retrieving revision 1.34
diff -u -r1.34 config.cc
--- config.cc	3 Apr 2005 15:00:44 -0000	1.34
+++ config.cc	3 May 2005 00:39:58 -0000
@@ -863,6 +863,7 @@
   static char *serial_mode_list[] = {
     "null",
     "file",
+    "pipe",
     "term",
     "raw",
     "mouse",
Index: iodev/serial.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/serial.cc,v
retrieving revision 1.64
diff -u -r1.64 serial.cc
--- iodev/serial.cc	19 Jan 2005 18:21:37 -0000	1.64
+++ iodev/serial.cc	3 May 2005 00:54:44 -0000
@@ -45,6 +45,148 @@
 
 #define LOG_THIS theSerialDevice->
 
+#ifdef WIN32
+class TPipe {
+private:
+    HANDLE hPipe;
+    char *pszPipeName;
+
+public:
+    TPipe(const char *pszPipeName_arg=NULL) {
+        pszPipeName = NULL;
+        hPipe = INVALID_HANDLE_VALUE;
+        Open(pszPipeName_arg);
+    }
+    ~TPipe(void) {
+        Close();
+        if (pszPipeName!=NULL) {
+            free(pszPipeName);
+        }
+    }
+
+    bool Open(const char *pszPipeName_arg=NULL) {
+        Close();
+        if (pszPipeName_arg!=NULL) {
+            if (pszPipeName!=NULL) {
+                free(pszPipeName);
+            }
+            pszPipeName = strdup(pszPipeName_arg);
+        }
+        if (pszPipeName==NULL)
+            return false;
+        hPipe =
+            CreateFileA(pszPipeName,
+                        GENERIC_READ | GENERIC_WRITE,
+                        0,
+                        NULL,
+                        OPEN_EXISTING,
+                        0,
+                        NULL);
+        if (hPipe!=INVALID_HANDLE_VALUE) {
+            DWORD dwMode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
+            if (!SetNamedPipeHandleState(hPipe,
+                                         &dwMode,
+                                         NULL,
+                                         NULL))
+            {
+                Close();
+            }
+        }
+    }
+    void Close(void) {
+        if (hPipe!=INVALID_HANDLE_VALUE) {
+            CloseHandle(hPipe);
+            hPipe = INVALID_HANDLE_VALUE;
+        }
+    }
+
+    bool Ok(void) const {
+        return hPipe!=INVALID_HANDLE_VALUE;
+    }
+
+    size_t Write(const void *pcv,size_t size) {
+        assert(hPipe!=INVALID_HANDLE_VALUE);
+        DWORD dwWritten = 0;
+        if (!WriteFile(hPipe,
+                       pcv,
+                       (DWORD) size,
+                       &dwWritten,
+                       NULL))
+            return 0;
+        return (size_t) dwWritten;
+    }
+
+    size_t Read(void *pv,size_t size) {
+        assert(hPipe!=INVALID_HANDLE_VALUE);
+        DWORD dwRead = 0;
+        if (!ReadFile(hPipe,
+                      pv,
+                      (DWORD) size,
+                      &dwRead,
+                      NULL))
+        {
+            return 0;
+        }
+        return (size_t) dwRead;
+    }
+
+    bool Flush(void) {
+        assert(hPipe!=INVALID_HANDLE_VALUE);
+        return FlushFileBuffers(hPipe)!=0;
+    }
+
+    bool Terminated(void) {
+        assert(hPipe!=INVALID_HANDLE_VALUE);
+        DWORD dwBytesAvail = 0;
+        if (!PeekNamedPipe(hPipe,
+                           NULL,
+                           0,
+                           NULL,
+                           &dwBytesAvail,
+                           NULL))
+            return true;
+        return false;
+    }
+
+    HANDLE GetHandle(void) const {
+        return hPipe;
+    }
+};
+#else
+class TPipe
+{
+private:
+    int iHandle;
+
+public:
+    TPipe(const char *pszFileName) {
+        iHandle = open(pszFileName, O_RDWR | O_NONBLOCK, 600);
+    }
+    ~TPipe(void) {
+        if (iHandle >=0 )
+            close(iHandle);
+    }
+    bool Ok(void) const {
+        return iHandle >= 0;
+    }
+    size_t Write(const void *pv, size_t size)
+    {
+        return write(iHandle, pv, size);
+    }
+    size_t Read(void *pv, size_t size)
+    {
+        return read(iHandle, pv, size);
+    }
+    bool Flush(void) {
+        return commit(iHandle)==0;
+    }
+
+    int GetHandle(void) const {
+        return iHandle;
+    }
+};
+#endif
+
 bx_serial_c *theSerialDevice = NULL;
 
   int
@@ -82,6 +224,11 @@
           if (BX_SER_THIS s[i].output != NULL)
             fclose(BX_SER_THIS s[i].output);
           break;
+        case BX_SER_MODE_PIPE:
+          // Close the handler
+          // It must not happen that io_handler is NULL at this point
+          delete (TPipe*) BX_SER_THIS s[i].io_handler;
+          break;
         case BX_SER_MODE_TERM:
 #if defined(SERIAL_ENABLE)
           if (s[i].tty_id >= 0) {
@@ -227,6 +374,23 @@
           if (BX_SER_THIS s[i].output)
             BX_SER_THIS s[i].io_mode = BX_SER_MODE_FILE;
         }
+      } else if (!strcmp(mode, "pipe")) {
+        if (strlen(bx_options.com[i].Odev->getptr ()) > 0) {
+          TPipe *pIo = new TPipe(bx_options.com[i].Odev->getptr ());
+          if (!pIo->Ok()) {
+            // It's not an error if the connection to the pipe failed
+            // because the listening process might be available only
+            // when a developer wants to debug something without changing
+            // the configuration file
+            BX_INFO(("open of com%d (%s) failed\n", i+1, bx_options.com[i].Odev->getptr ()));
+            // Delete TPipe class to avoid a memory leak
+            delete pIo;
+          } else {
+            BX_DEBUG(("com%d pipe: %s", i+1, bx_options.com[i].Odev->getptr ()));
+            BX_SER_THIS s[i].io_mode = BX_SER_MODE_PIPE;
+            BX_SER_THIS s[i].io_handler = pIo;
+          }
+        }
       } else if (!strcmp(mode, "term")) {
 #if defined(SERIAL_ENABLE)
         if (strlen(bx_options.com[i].Odev->getptr ()) > 0) {
@@ -1031,6 +1195,17 @@
         fputc(BX_SER_THIS s[port].tsrbuffer, BX_SER_THIS s[port].output);
         fflush(BX_SER_THIS s[port].output);
         break;
+      case BX_SER_MODE_PIPE:
+        {
+          // Get the redirection target object.
+          TPipe *pIo = (TPipe*) BX_SER_THIS s[port].io_handler;
+          BX_DEBUG(("com%d: write: '%c'", port+1, BX_SER_THIS s[port].tsrbuffer));
+          // The status of this object must be Ok()==true so there's no need
+          // to test for this status explicitly.
+          pIo->Write((bx_ptr_t) & BX_SER_THIS s[port].tsrbuffer, 1);
+          pIo->Flush();
+        }
+        break;
       case BX_SER_MODE_TERM:
 #if defined(SERIAL_ENABLE)
         BX_DEBUG(("com%d: write: '%c'", port+1, BX_SER_THIS s[port].tsrbuffer));
@@ -1178,6 +1353,18 @@
         }
 #endif
         break;
+      case BX_SER_MODE_PIPE:
+        {
+          // Get the redirection target object.
+          TPipe *pIo = (TPipe*) BX_SER_THIS s[port].io_handler;
+          // The status of this object must be Ok()==true so there's no need
+          // to test for this status explicitly.
+          if (pIo->Read(&chbuf, 1)==1) {
+              BX_DEBUG(("com%d: read: '%c'", port+1, chbuf));
+              data_ready = 1;
+          }
+        }
+        break;
       case BX_SER_MODE_MOUSE:
         if (BX_SER_THIS mouse_internal_buffer.num_elements > 0) {
           chbuf = BX_SER_THIS mouse_internal_buffer.buffer[BX_SER_THIS mouse_internal_buffer.head];
Index: iodev/serial.h
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/serial.h,v
retrieving revision 1.25
diff -u -r1.25 serial.h
--- iodev/serial.h	5 Dec 2004 20:23:39 -0000	1.25
+++ iodev/serial.h	3 May 2005 00:41:34 -0000
@@ -67,6 +67,7 @@
 #define BX_SER_MODE_TERM  2
 #define BX_SER_MODE_RAW   3
 #define BX_SER_MODE_MOUSE 4
+#define BX_SER_MODE_PIPE   5
 
 enum {
   BX_SER_INT_IER,
@@ -110,6 +111,7 @@
   int io_mode;
   int tty_id;
   FILE *output;
+  void *io_handler;
 
 #if USE_RAW_SERIAL
   serial_raw* raw;
-------------- next part --------------
//
// pipetunnel.cpp
//
// Martin Fuchs, 30.11.2003
//

//
// Invoke as:	"pipetunnel [pipe_name]",
// for example:	"pipetunnel com_2"
//
// Then start up RectOS in VMWare, wait for the serial connect.
// After that you can connect GDB using the command "target remote :9999".
//


#define _WIN32_WINNT 0x0501
#define	WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <winsock.h>

#ifdef _MSC_VER
#pragma comment(lib, "wsock32")
#endif

#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#include <queue>
#include <vector>

 // This definition currently missing in MinGW.
#ifndef	FILE_FLAG_FIRST_PIPE_INSTANCE
#define	FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
#endif

void dumphex(const char *buf, int len, int pos)
{
	int i, j;
	for(j = 0; j < len; j += 16) {
		for(i = 0; i < 16; i++) {
			if(i + j < len)
				printf("%02x%c", (unsigned char)buf[i + j], j + i + 1 == pos ? '*' : ' ');
			else
				printf("   ");
		}
		for(i = 0; i < 16; i++) {
			if(i + j < len)
				printf("%c", buf[i + j] >= ' ' ? buf[i + j] : '.');
			else
				printf(" ");
		}
		printf("\n");
	}
}

class WinSockInit {
private:
    WSADATA wsa_data;
    bool bIsOK;
public:
    WinSockInit(void) {
        bIsOK = WSAStartup(MAKEWORD(2,2), &wsa_data)==0;
    }
    ~WinSockInit(void) {
        if (bIsOK)
            WSACleanup();
    }
    bool Ok(void) const {
        return bIsOK;
    }

};

class TSocketServer {
private:
    SOCKET sckServer;
    SOCKADDR_IN addr;
    SOCKET sckClient;
public:
    TSocketServer(void) {
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(9999);

        sckClient = INVALID_SOCKET;

        sckServer = socket(PF_INET, SOCK_STREAM, 0);
        if (sckServer==INVALID_SOCKET)
            return;

        u_long nbio_value = 1;
        ioctlsocket(sckServer,
                    FIONBIO,
                    &nbio_value);

        if (bind(sckServer, (struct sockaddr*) &addr, sizeof(addr))!=0) {
            sckServer = INVALID_SOCKET;
            return;
        }

        if (listen(sckServer, 4)!=0) {
            sckServer = INVALID_SOCKET;
            return;
        }
    }

    bool Ok(void) const {
        return (sckServer!=INVALID_SOCKET);
    }

    bool IsConnected(void) {
        if (sckClient==INVALID_SOCKET) {
            sckClient = accept(sckServer,
                               NULL,
                               NULL);
            if (sckClient!=INVALID_SOCKET) {
                BOOL bValue = TRUE;
                setsockopt(sckClient,
                           IPPROTO_TCP,
                           TCP_NODELAY,
                           (const char *) &bValue,
                           sizeof(BOOL));
            }
        }
        return sckClient!=INVALID_SOCKET;
    }

    size_t Write(const void *pcv,size_t size) {
        assert(sckClient!=INVALID_SOCKET);
        int count = send(sckClient,
                         (const char *) pcv,
                         (int) size,
                         0);
        if (count==SOCKET_ERROR) {
            sckClient = INVALID_SOCKET;
            return 0;
        }
        return (size_t) count;
    }

    size_t Read(void *pv,size_t size) {
        assert(sckClient!=INVALID_SOCKET);
        int count = recv(sckClient,
                         (char*) pv,
                         (int) size,
                         0);
        if (count==SOCKET_ERROR) {
            int iErrCode = WSAGetLastError();
            switch (iErrCode) {
            case WSAEWOULDBLOCK:
                break;
            case WSAECONNRESET:
                sckClient = INVALID_SOCKET;
                break;
            }
            return 0;
        } else if (count==0) {
            sckClient = INVALID_SOCKET;
        }
        return (size_t) count;
    }
};

class TPipeServer {
private:
    HANDLE hPipe;
    char *pszPipeName;

private:
    bool Listen(void) {
        assert(hPipe!=INVALID_HANDLE_VALUE);
        if (ConnectNamedPipe(hPipe, NULL)!=0)
            return true;
        if (GetLastError()==ERROR_PIPE_LISTENING)
            return true;
        return false;
    }

public:
    TPipeServer(const char *pszPipeName_arg=NULL) {
        pszPipeName = NULL;
        hPipe = INVALID_HANDLE_VALUE;
        Open(pszPipeName_arg);
    }
    ~TPipeServer(void) {
        Close();
        if (pszPipeName!=NULL) {
            free(pszPipeName);
        }
    }

    bool Open(const char *pszPipeName_arg=NULL) {
        if (hPipe!=INVALID_HANDLE_VALUE) {
            Close();
        }
        if (pszPipeName_arg!=NULL) {
            if (pszPipeName!=NULL) {
                free(pszPipeName);
            }
            pszPipeName = strdup(pszPipeName_arg);
        }
        if (pszPipeName==NULL)
            return false;
        hPipe =
            CreateNamedPipeA(pszPipeName,
                             PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH,
                             PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT,
                             1,
                             4096,
                             4096,
                             0,
                             NULL);
        if (hPipe!=INVALID_HANDLE_VALUE) {
            if (!Listen()) {
                Close();
            }
        }
        return true;
    }
    void Close(void) {
        if (hPipe!=INVALID_HANDLE_VALUE) {
            Flush();
            DisconnectNamedPipe(hPipe);
            CloseHandle(hPipe);
            hPipe = INVALID_HANDLE_VALUE;
        }
    }

    bool Ok(void) const {
        return hPipe!=INVALID_HANDLE_VALUE;
    }

    bool IsConnected(void) {
        assert(hPipe!=INVALID_HANDLE_VALUE);
        if (ConnectNamedPipe(hPipe, NULL)!=0)
            return false;
        DWORD dwErrCode = GetLastError();
        if (dwErrCode==ERROR_PIPE_CONNECTED)
            return true;
        if (dwErrCode==ERROR_NO_DATA) {
            // reopen
            Open();
        }
        return false;
    }

    size_t Write(const void *pcv,size_t size) {
        assert(hPipe!=INVALID_HANDLE_VALUE);
        DWORD dwWritten = 0;
        if (!WriteFile(hPipe,
                       pcv,
                       (DWORD) size,
                       &dwWritten,
                       NULL))
            return 0;
        return (size_t) dwWritten;
    }

    size_t Read(void *pv,size_t size) {
        assert(hPipe!=INVALID_HANDLE_VALUE);
        DWORD dwRead = 0;
        if (!ReadFile(hPipe,
                      pv,
                      (DWORD) size,
                      &dwRead,
                      NULL))
            return 0;
        return (size_t) dwRead;
    }

    bool Flush(void) {
        assert(hPipe!=INVALID_HANDLE_VALUE);
        return FlushFileBuffers(hPipe)!=0;
    }
};


typedef std::vector<unsigned char> TByteBuffer;
typedef std::queue<TByteBuffer> TBufferQueue;

int main(int argc, char** argv)
{
    // initialize winsock
    WinSockInit SocketInit;
    if (!SocketInit.Ok()) {
		fprintf(stderr, "Failed to initialize sockets\n");
		return 1;
    }

    // Get name of named pipe
	char path[MAX_PATH];
	const char* pipe_name;

    if (argc > 1) {
		pipe_name = *++argv;
    } else {
        pipe_name = "com_2";
    }

	sprintf(path, "\\\\.\\pipe\\%s", pipe_name);


    // increment priority to be faster than the cpu eating VMWare process
	SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);


    TPipeServer PipeServer(path);
    if (!PipeServer.Ok()) {
        fprintf(stderr, "Failed to create pipe %s\n", path);
        return 1;
    }

    TSocketServer SocketServer;
    if (!SocketServer.Ok()) {
        fprintf(stderr, "Failed to create socket\n");
        return 1;
    }

    bool bSocketWasOpen = false;
    bool bPipeWasOpen = false;
    TBufferQueue PipeReadQueue;
    TBufferQueue SocketReadQueue;
    TByteBuffer ReadBuffer(4096);
    for (;;) {
        if (PipeServer.IsConnected()) {
            if (!bPipeWasOpen) {
                printf("Pipe connected\n");
                bPipeWasOpen = true;
            }

            size_t BufSize = PipeServer.Read(&*ReadBuffer.begin(), ReadBuffer.size());
            if (BufSize!=0) {
                // send to socket
                TByteBuffer TempBuffer(BufSize);
                memcpy(&*TempBuffer.begin(),
                       &*ReadBuffer.begin(),
                       BufSize);

                printf("PIPE >>\n");
                dumphex((const char *) &*TempBuffer.begin(),
                        TempBuffer.size(),
                        0);

                PipeReadQueue.push(TempBuffer);
            }

            if (SocketReadQueue.size()!=0) {
                const TByteBuffer &TempBuffer(SocketReadQueue.front());

                printf("PIPE <<\n");
                dumphex((const char *) &*TempBuffer.begin(),
                        TempBuffer.size(),
                        0);

                PipeServer.Write(&*TempBuffer.begin(),
                                 TempBuffer.size());
                SocketReadQueue.pop();
            }

        } else {
            if (bPipeWasOpen) {
                printf("Pipe disconnected\n");
                // reopen pipe
                PipeServer.Open();
                bPipeWasOpen = false;
                PipeReadQueue = TBufferQueue();
            }
        }

        if (SocketServer.IsConnected()) {
            if (!bSocketWasOpen) {
                printf("TCP connection established\n");
                bSocketWasOpen = true;
            }

            size_t BufSize = SocketServer.Read(&*ReadBuffer.begin(), ReadBuffer.size());
            if (BufSize!=0) {
                // send to socket
                TByteBuffer TempBuffer(BufSize);
                memcpy(&*TempBuffer.begin(),
                       &*ReadBuffer.begin(),
                       BufSize);

                printf("TCP >>\n");
                dumphex((const char *) &*TempBuffer.begin(),
                        TempBuffer.size(),
                        0);

                SocketReadQueue.push(TempBuffer);
            }

            if (PipeReadQueue.size()!=0) {
                const TByteBuffer &TempBuffer(PipeReadQueue.front());

                printf("TCP <<\n");
                dumphex((const char *) &*TempBuffer.begin(),
                        TempBuffer.size(),
                        0);

                SocketServer.Write(&*TempBuffer.begin(),
                                   TempBuffer.size());
                PipeReadQueue.pop();
            }

        } else {
            if (bSocketWasOpen) {
                printf("TCP connection closed\n");
                bSocketWasOpen = false;
                SocketReadQueue = TBufferQueue();
            }
        }

        if (!bPipeWasOpen && !bSocketWasOpen) {
            Sleep(50);
        } else {
            Sleep(1);
        }
    }

	return 0;
}


More information about the Ros-dev mailing list