diff -Naur MDB-v0.60-r91325/backend/arch/bfd/bfd.h MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/bfd.h --- MDB-v0.60-r91325/backend/arch/bfd/bfd.h 2004-04-10 07:37:41.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/bfd.h 2007-11-14 12:25:12.000000000 +0100 @@ -1,3 +1,5 @@ +/* Update: with the Mono Debugger, this file is not updated during build. */ + /* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", "bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c", @@ -31,6 +33,15 @@ #ifndef __BFD_H_SEEN__ #define __BFD_H_SEEN__ +//#define BFDDEBUG +#ifdef BFDDEBUG +#define INFO fprintf(stderr,"%s\n",__PRETTY_FUNCTION__) +#define INFOS(x) fprintf(stderr,"%s: %s\n",__PRETTY_FUNCTION__,(x)) +#else +#define INFO do {} while (0); +#define INFOS(x) do {} while (0); +#endif + #ifdef __cplusplus extern "C" { #endif diff -Naur MDB-v0.60-r91325/backend/arch/bfd/bfdio.c MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/bfdio.c --- MDB-v0.60-r91325/backend/arch/bfd/bfdio.c 2004-04-10 08:15:51.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/bfdio.c 2007-11-13 18:06:57.000000000 +0100 @@ -25,6 +25,13 @@ #include "libbfd.h" #include +#include +#include /* for remote debugging */ + +/* externs for remote debugging */ +extern CLIENT* rpc_get_client(void); +extern void rpc_put_client(void); +extern int mono_debugger_server_get_remote_debug(void); #ifndef S_IXUSR #define S_IXUSR 0100 /* Execute by owner. */ @@ -67,12 +74,74 @@ #if defined (__VAX) && defined (VMS) /* Apparently fread on Vax VMS does not keep the record length information. */ + + /* The fileno() function is never called by the Mono Debugger. + Hence, fileno() and read() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + return read (fileno (file), where, a * b); #else - return fread (where, a, b, file); + + if (mono_debugger_server_get_remote_debug() == 1) + { + INFO; + + struct bfd_fread_struct_out *result; + struct bfd_fread_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + return 0; + } + + arg.size = a; + arg.nmemb = b; + arg.stream = (u_int)file; + + result = bfd_fread_1(&arg, clnt); + rpc_put_client(); + if (result == (struct bfd_fread_struct_out *) NULL) { + clnt_perror (clnt, "call failed"); + return 0; + } + + memcpy(where,result->retval.retval_val,result->retval.retval_len); + + return result->retval.retval_len; + } + else + return fread (where, a, b, file); + #endif } + +static int ferror_rpc(FILE *stream) +{ + INFO; + + int *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + return -1; + } + + arg = (u_int)stream; + + result = bfd_ferror_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "call failed"); + return -1; + } + + return *result; +} + + /* Return value is amount read. */ bfd_size_type @@ -116,7 +185,13 @@ provide something more useful (eg. no_symbols or wrong_format). */ if (nread != size) { - if (ferror (bfd_cache_lookup (abfd))) + int retval; + if (mono_debugger_server_get_remote_debug() == 1) + retval = ferror_rpc (bfd_cache_lookup (abfd)); + else + retval = ferror (bfd_cache_lookup (abfd)); + + if (retval) bfd_set_error (bfd_error_system_call); else bfd_set_error (bfd_error_file_truncated); @@ -131,6 +206,11 @@ bfd_size_type size; bfd *abfd; { + /* This function is never called by the Mono Debugger. + Hence, fwrite() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + size_t nwrote; if ((abfd->flags & BFD_IN_MEMORY) != 0) @@ -177,6 +257,11 @@ bfd_tell (abfd) bfd *abfd; { + /* This function is never called by the Mono Debugger. + Hence, ftell() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + file_ptr ptr; if ((abfd->flags & BFD_IN_MEMORY) != 0) @@ -196,6 +281,12 @@ { if ((abfd->flags & BFD_IN_MEMORY) != 0) return 0; + + /* This function is never called by the Mono Debugger. + Hence, fflush() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + return fflush (bfd_cache_lookup(abfd)); } @@ -206,6 +297,11 @@ bfd *abfd; struct stat *statbuf; { + /* This function is never called by the Mono Debugger. + Hence, fileno() and fstat() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + FILE *f; int result; @@ -224,6 +320,34 @@ return result; } + +static int fseek_rpc(FILE *stream, long offset, int whence) +{ + INFO; + + int *result; + struct bfd_fseek_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + return -1; + } + + arg.stream = (u_int) stream; + arg.offset = offset; + arg.whence = whence; + + result = bfd_fseek_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "call failed"); + return -1; + } + + return *result; +} + + /* Returns 0 for success, nonzero for failure (in which case bfd_get_error can retrieve the error code). */ @@ -325,7 +449,11 @@ if (direction == SEEK_SET && abfd->my_archive != NULL) file_position += abfd->origin; - result = fseek (f, file_position, direction); + if (mono_debugger_server_get_remote_debug() == 1) + result = fseek_rpc (f, file_position, direction); + else + result = fseek (f, file_position, direction); + if (result != 0) { int hold_errno = errno; @@ -371,6 +499,11 @@ bfd_get_mtime (abfd) bfd *abfd; { + /* This function is never called by the Mono Debugger. + Hence, fileno() and fstat() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + FILE *fp; struct stat buf; @@ -422,6 +555,11 @@ bfd_get_size (abfd) bfd *abfd; { + /* This function is never called by the Mono Debugger. + Hence, fileno() and fstat() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + FILE *fp; struct stat buf; diff -Naur MDB-v0.60-r91325/backend/arch/bfd/cache.c MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/cache.c --- MDB-v0.60-r91325/backend/arch/bfd/cache.c 2004-04-10 07:19:31.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/cache.c 2007-11-28 09:57:13.000000000 +0100 @@ -36,10 +36,18 @@ */ +#include /* for remote debugging */ +#include #include "bfd.h" #include "sysdep.h" #include "libbfd.h" +/* externs for remote debugging */ +extern CLIENT* rpc_get_client(void); +extern void rpc_put_client(void); +extern int mono_debugger_server_get_remote_debug(void); + + static void insert PARAMS ((bfd *)); static void snip PARAMS ((bfd *)); static bfd_boolean close_one PARAMS ((void)); @@ -130,6 +138,32 @@ } } + +static long ftell_rpc(FILE *stream) +{ + INFO; + + int *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + return -1; + } + + arg = (u_int)stream; + + result = bfd_ftell_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "call failed"); + return -1; + } + + return *result; +} + + /* We need to open a new file, and the cache is full. Find the least recently used cacheable BFD and close it. */ @@ -160,11 +194,38 @@ return TRUE; } - kill->where = ftell ((FILE *) kill->iostream); + if (mono_debugger_server_get_remote_debug() == 1) + kill->where = ftell_rpc ((FILE *) kill->iostream); + else + kill->where = ftell ((FILE *) kill->iostream); return bfd_cache_delete (kill); } + +static int fclose_rpc(FILE *file) +{ + INFO; + + int *result; + u_int arg = (u_int)file; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + return -1; + } + + result = bfd_fclose_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "call failed"); + return -1; + } + + return *result; +} + + /* Close a BFD and remove it from the cache. */ static bfd_boolean @@ -173,7 +234,13 @@ { bfd_boolean ret; - if (fclose ((FILE *) abfd->iostream) == 0) + int retval; + if (mono_debugger_server_get_remote_debug() == 1) + retval = fclose_rpc ((FILE *) abfd->iostream); + else + retval = fclose ((FILE *) abfd->iostream); + + if (retval == 0) ret = TRUE; else { @@ -242,6 +309,37 @@ return bfd_cache_delete (abfd); } + +static FILE *fopen_rpc(const char *path, const char *mode) +{ + INFO; + + u_int *result; + struct bfd_fopen_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + return NULL; + } + + arg.path = calloc(strlen(path)+1,1); + arg.mode = calloc(strlen(mode)+1,1); + strcpy(arg.path,path); + strcpy(arg.mode,mode); + + result = bfd_fopen_1(&arg, clnt); + rpc_put_client(); + free(arg.path); + free(arg.mode); + if (result == (u_int *) NULL) { + clnt_perror (clnt, "call failed"); + return NULL; + } + + return (FILE *)*result; +} + + /* INTERNAL_FUNCTION bfd_open_file @@ -273,10 +371,18 @@ { case read_direction: case no_direction: - abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RB); + if (mono_debugger_server_get_remote_debug() == 1) + abfd->iostream = (PTR) fopen_rpc (abfd->filename, FOPEN_RB); + else + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RB); break; case both_direction: case write_direction: + /* This case is never used by the Mono Debugger. + Hence, stat() and unlink() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + if (abfd->opened_once) { abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RUB); @@ -326,6 +432,34 @@ return (FILE *) abfd->iostream; } + +static int fseek_rpc(FILE *stream, long offset, int whence) +{ + INFO; + + int *result; + struct bfd_fseek_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + return -1; + } + + arg.stream = (u_int) stream; + arg.offset = offset; + arg.whence = whence; + + result = bfd_fseek_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "call failed"); + return -1; + } + + return *result; +} + + /* INTERNAL_FUNCTION bfd_cache_lookup_worker @@ -366,7 +500,12 @@ return NULL; if (abfd->where != (unsigned long) abfd->where) return NULL; - if (fseek ((FILE *) abfd->iostream, (long) abfd->where, SEEK_SET) != 0) + int retval; + if (mono_debugger_server_get_remote_debug() == 1) + retval = fseek_rpc ((FILE *) abfd->iostream, (long) abfd->where, SEEK_SET); + else + retval = fseek ((FILE *) abfd->iostream, (long) abfd->where, SEEK_SET); + if (retval != 0) return NULL; } diff -Naur MDB-v0.60-r91325/backend/arch/bfd/elf.c MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/elf.c --- MDB-v0.60-r91325/backend/arch/bfd/elf.c 2004-04-10 07:19:31.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/elf.c 2007-11-14 12:25:12.000000000 +0100 @@ -39,6 +39,10 @@ #define ARCH_SIZE 0 #include "elf-bfd.h" #include "libiberty.h" +#include + +extern int mono_debugger_server_get_remote_debug(void); + static INLINE struct elf_segment_map *make_mapping PARAMS ((bfd *, asection **, unsigned int, unsigned int, bfd_boolean)); @@ -1042,6 +1046,11 @@ bfd *abfd; PTR farg; { + /* This function is never called by the Mono Debugger. + Hence, fprintf() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + FILE *f = (FILE *) farg; Elf_Internal_Phdr *p; asection *s; @@ -1283,6 +1292,11 @@ asymbol *symbol; bfd_print_symbol_type how; { + /* This function is never called by the Mono Debugger. + Hence, fprintf() and putc() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + FILE *file = (FILE *) filep; switch (how) { @@ -7430,6 +7444,11 @@ PTR stream; bfd_vma value; { + /* This function is never called by the Mono Debugger. + Hence, fprintf() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + #ifdef BFD64 Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ diff -Naur MDB-v0.60-r91325/backend/arch/bfd/Makefile.am MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/Makefile.am --- MDB-v0.60-r91325/backend/arch/bfd/Makefile.am 2005-04-08 14:04:36.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/Makefile.am 2007-11-13 18:06:57.000000000 +0100 @@ -35,7 +35,8 @@ endif endif -INCLUDES = -D_GNU_SOURCE $(bfd_cflags) $(CSEARCH) $(CSWITCHES) +RPCDIR = ../../../mdbserver/rpc +INCLUDES = -D_GNU_SOURCE $(bfd_cflags) $(CSEARCH) $(CSWITCHES) -I$(RPCDIR) SOURCE_FILES = \ archive.c archures.c bfd.c cache.c coffgen.c corefile.c \ diff -Naur MDB-v0.60-r91325/backend/arch/bfd/opncls.c MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/opncls.c --- MDB-v0.60-r91325/backend/arch/bfd/opncls.c 2004-04-10 07:19:31.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/opncls.c 2007-11-12 17:17:48.000000000 +0100 @@ -26,6 +26,7 @@ #include "objalloc.h" #include "libbfd.h" #include "libiberty.h" +#include #ifndef S_IXUSR #define S_IXUSR 0100 /* Execute by owner. */ @@ -41,6 +42,8 @@ static unsigned int _bfd_id_counter = 0; +extern int mono_debugger_server_get_remote_debug(void); + /* fdopen is a loser -- we should use stdio exclusively. Unfortunately if we do that we can't use fcntl. */ @@ -219,6 +222,11 @@ const char *target; int fd; { + /* This function is never called by the Mono Debugger. + Hence, fcntl() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + bfd *nbfd; const bfd_target *target_vec; int fdflags; @@ -244,14 +252,39 @@ } #ifndef HAVE_FDOPEN + /* This function is never called by the Mono Debugger. + Hence, fflush() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + nbfd->iostream = (PTR) fopen (filename, FOPEN_RB); #else /* (O_ACCMODE) parens are to avoid Ultrix header file bug. */ switch (fdflags & (O_ACCMODE)) { - case O_RDONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RB); break; - case O_WRONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break; - case O_RDWR: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break; + case O_RDONLY: + /* This function is never called by the Mono Debugger. + Hence, fdopen() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + + nbfd->iostream = (PTR) fdopen (fd, FOPEN_RB); + break; + case O_WRONLY: + /* This function is never called by the Mono Debugger. + Hence, fdopen() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + + nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); + break; + case O_RDWR: + /* This function is never called by the Mono Debugger. + Hence, fdopen() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + + nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break; default: abort (); } #endif @@ -437,6 +470,11 @@ && abfd->direction == write_direction && abfd->flags & EXEC_P) { + /* This case is never used by the Mono Debugger. + Hence, stat() and chmod() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + struct stat buf; if (stat (abfd->filename, &buf) == 0) @@ -491,6 +529,11 @@ && abfd->direction == write_direction && abfd->flags & EXEC_P) { + /* This case is never used by the Mono Debugger. + Hence, chmod() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + struct stat buf; if (stat (abfd->filename, &buf) == 0) @@ -874,6 +917,11 @@ const char *name; const unsigned long crc; { + /* This function is never called by the Mono Debugger. + Hence, read(), open() and close() are not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + static char buffer [8 * 1024]; unsigned long file_crc = 0; int fd; diff -Naur MDB-v0.60-r91325/backend/arch/bfd/syms.c MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/syms.c --- MDB-v0.60-r91325/backend/arch/bfd/syms.c 2004-04-10 07:19:31.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/bfd/syms.c 2007-11-12 16:55:30.000000000 +0100 @@ -313,11 +313,14 @@ #include "safe-ctype.h" #include "bfdlink.h" #include "aout/stab_gnu.h" +#include static char coff_section_type PARAMS ((const char *)); static char decode_section_type PARAMS ((const struct sec *)); static int cmpindexentry PARAMS ((const PTR, const PTR)); +extern int mono_debugger_server_get_remote_debug(void); + /* DOCDD INODE @@ -450,6 +453,11 @@ PTR arg; asymbol *symbol; { + /* This function is never called by the Mono Debugger. + Hence, fprintf() is not forwarded via RPC for remote debugging. */ + if (mono_debugger_server_get_remote_debug()) + assert(0); + FILE *file = (FILE *) arg; flagword type = symbol->flags; diff -Naur MDB-v0.60-r91325/backend/arch/Bfd.cs MDB-v0.60-r91325-RemoteDebug/backend/arch/Bfd.cs --- MDB-v0.60-r91325/backend/arch/Bfd.cs 2007-11-28 14:03:17.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/arch/Bfd.cs 2008-03-03 17:25:16.000000000 +0100 @@ -691,6 +691,27 @@ return TargetAddress.Null; } + /// Reads out all local symbols of this Bfd and returns the symbol names and + /// symbol addresses in two arrays. We need that for remote debugging. + /// Array with symbol names + /// Array with corresponding symbol addresses + /// Number of elements + public int GetLocalSymbols (out string[] symbolNames, out long[] symbolAddrs) + { + ICollection locSymKeys = local_symbols.Keys; + symbolNames = new string[local_symbols.Count]; + symbolAddrs = new long[local_symbols.Count]; + int i=0; + + foreach (object key in locSymKeys) + { + symbolNames[i] = (string)key; + symbolAddrs[i] = ((TargetAddress)local_symbols[key]).Address; + i++; + } + return i; + } + internal Section FindSection (long address) { read_sections (); diff -Naur MDB-v0.60-r91325/backend/Inferior.cs MDB-v0.60-r91325-RemoteDebug/backend/Inferior.cs --- MDB-v0.60-r91325/backend/Inferior.cs 2007-12-08 16:46:59.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/Inferior.cs 2008-03-03 17:25:16.000000000 +0100 @@ -46,6 +46,15 @@ bool has_signals; SignalInfo signal_info; + /// + /// Returns the ServerHandle. We need that for some ThreadDB methods while remote debugging. + /// + public IntPtr ServerHandle { + get { + return server_handle; + } + } + public bool HasTarget { get { return has_target; @@ -182,6 +191,13 @@ [DllImport("monodebuggerserver")] static extern void mono_debugger_server_set_runtime_info (IntPtr handle, IntPtr mono_runtime_info); + [DllImport("monodebuggerserver")] + static extern void mono_debugger_server_get_map_file (string filename, out string content); + + [DllImport("monodebuggerserver")] + static extern int mono_debugger_server_get_remote_debug (); + + internal enum ChildEventType { NONE = 0, UNKNOWN_ERROR = 1, @@ -1414,7 +1430,14 @@ // the current file position and System.IO will try to "fix" this // by seeking back. string mapfile = String.Format ("/proc/{0}/maps", child_pid); - string contents = GetFileContents (mapfile); + + string contents; + if (mono_debugger_server_get_remote_debug() == 1) { + /* debugging remotely - forward to C library */ + mono_debugger_server_get_map_file(mapfile, out contents); + } else { + contents = GetFileContents (mapfile); + } if (contents == null) return null; diff -Naur MDB-v0.60-r91325/backend/server/i386-arch.c MDB-v0.60-r91325-RemoteDebug/backend/server/i386-arch.c --- MDB-v0.60-r91325/backend/server/i386-arch.c 2007-12-10 11:32:59.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/i386-arch.c 2008-03-03 17:25:16.000000000 +0100 @@ -287,7 +287,7 @@ cdata->data_pointer = new_esp + 56; cdata->data_size = data_size; } - + server_ptrace_write_memory (handle, (guint32) new_esp, size, code); g_free (code); if (result != COMMAND_ERROR_NONE) @@ -402,26 +402,96 @@ return g_ptr_array_index (arch->callback_stack, arch->callback_stack->len - 1); } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError x86_arch_get_registers (ServerHandle *handle) { - ServerCommandError result; - - result = _server_ptrace_get_registers (handle->inferior, &handle->arch->current_regs); - if (result != COMMAND_ERROR_NONE) - return result; - - result = _server_ptrace_get_fp_registers (handle->inferior, &handle->arch->current_fpregs); - if (result != COMMAND_ERROR_NONE) - return result; - - result = _server_ptrace_get_dr (handle->inferior, DR_STATUS, &handle->arch->dr_status); - if (result != COMMAND_ERROR_NONE) - return result; + INFO; - return COMMAND_ERROR_NONE; + if (remote_debug_flag) + { + struct get_registers_struct_out *result; + u_int arg; + int i; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = get_registers_1(&arg, clnt); + rpc_put_client(); + if (result == (struct get_registers_struct_out *) NULL) { + clnt_perror (clnt, "get_registers_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + handle->arch->current_regs.ebx = result->ebx; + handle->arch->current_regs.ecx = result->ecx; + handle->arch->current_regs.edx = result->edx; + handle->arch->current_regs.esi = result->esi; + handle->arch->current_regs.edi = result->edi; + handle->arch->current_regs.ebp = result->ebp; + handle->arch->current_regs.eax = result->eax; + handle->arch->current_regs.ds = result->ds; + handle->arch->current_regs.__ds = result->__ds; + handle->arch->current_regs.es = result->es; + handle->arch->current_regs.__es = result->__es; + handle->arch->current_regs.fs = result->fs; + handle->arch->current_regs.__fs = result->__fs; + handle->arch->current_regs.gs = result->gs; + handle->arch->current_regs.__gs = result->__gs; + handle->arch->current_regs.orig_eax = result->orig_eax; + handle->arch->current_regs.eip = result->eip; + handle->arch->current_regs.cs = result->cs; + handle->arch->current_regs.__cs = result->__cs; + handle->arch->current_regs.eflags = result->eflags; + handle->arch->current_regs.esp = result->esp; + handle->arch->current_regs.ss = result->ss; + handle->arch->current_regs.__ss = result->__ss; + + handle->arch->current_fpregs.cwd = result->cwd; + handle->arch->current_fpregs.swd = result->swd; + handle->arch->current_fpregs.twd = result->twd; + handle->arch->current_fpregs.fip = result->fip; + handle->arch->current_fpregs.fcs = result->fcs; + handle->arch->current_fpregs.foo = result->foo; + handle->arch->current_fpregs.fos = result->fos; + for (i=0; i<20; i++) + handle->arch->current_fpregs.st_space[i] = result->st_space[i]; + + handle->arch->dr_status = result->dr_status[1]; + handle->arch->dr_status <<= 32; + handle->arch->dr_status |= result->dr_status[0]; + + return result->servercommanderror; + + } + else + { + + ServerCommandError result; + + result = _server_ptrace_get_registers (handle->inferior, &handle->arch->current_regs); + if (result != COMMAND_ERROR_NONE) + return result; + + result = _server_ptrace_get_fp_registers (handle->inferior, &handle->arch->current_fpregs); + if (result != COMMAND_ERROR_NONE) + return result; + + result = _server_ptrace_get_dr (handle->inferior, DR_STATUS, &handle->arch->dr_status); + if (result != COMMAND_ERROR_NONE) + return result; + + return COMMAND_ERROR_NONE; + + } } + ChildStoppedAction x86_arch_child_stopped (ServerHandle *handle, int stopsig, guint64 *callback_arg, guint64 *retval, guint64 *retval2, @@ -502,7 +572,7 @@ if (cdata->data_pointer) { *opt_data_size = cdata->data_size; *opt_data = g_malloc0 (cdata->data_size); - + if (_server_ptrace_read_memory ( handle, cdata->data_pointer, cdata->data_size, *opt_data)) g_error (G_STRLOC ": Can't read data buffer after returning from a call"); @@ -510,7 +580,7 @@ *opt_data_size = 0; *opt_data = NULL; } - + if (cdata->exc_address && (server_ptrace_peek_word (handle, cdata->exc_address, &exc_object) != COMMAND_ERROR_NONE)) @@ -877,7 +947,7 @@ breakpoint->enabled = TRUE; mono_debugger_breakpoint_manager_insert (handle->bpm, (BreakpointInfo *) breakpoint); - done: +done: *bhandle = breakpoint->id; mono_debugger_breakpoint_manager_unlock (); @@ -909,7 +979,7 @@ breakpoint->enabled = FALSE; mono_debugger_breakpoint_manager_remove (handle->bpm, (BreakpointInfo *) breakpoint); - out: +out: mono_debugger_breakpoint_manager_unlock (); return result; } @@ -981,7 +1051,7 @@ breakpoint->enabled = TRUE; mono_debugger_breakpoint_manager_insert (handle->bpm, (BreakpointInfo *) breakpoint); - done: +done: *bhandle = breakpoint->id; mono_debugger_breakpoint_manager_unlock (); diff -Naur MDB-v0.60-r91325/backend/server/library.c MDB-v0.60-r91325-RemoteDebug/backend/server/library.c --- MDB-v0.60-r91325/backend/server/library.c 2007-12-08 16:46:59.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/library.c 2008-03-03 17:25:16.000000000 +0100 @@ -20,6 +20,7 @@ static InferiorVTable *global_vtable = &i386_ptrace_inferior; #endif + ServerHandle * mono_debugger_server_create_inferior (BreakpointManager *breakpoint_manager) { @@ -464,6 +465,8 @@ void mono_debugger_server_static_init (void) { + INFO; + struct sigaction sa; if (initialized) diff -Naur MDB-v0.60-r91325/backend/server/Makefile.am MDB-v0.60-r91325-RemoteDebug/backend/server/Makefile.am --- MDB-v0.60-r91325/backend/server/Makefile.am 2007-08-22 16:45:16.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/Makefile.am 2008-03-06 15:14:52.000000000 +0100 @@ -1,4 +1,6 @@ -INCLUDES = @SERVER_DEPENDENCIES_CFLAGS@ @server_cflags@ +RPCDIR = ../../mdbserver/rpc + +INCLUDES = @SERVER_DEPENDENCIES_CFLAGS@ @server_cflags@ -I$(RPCDIR) lib_LTLIBRARIES = libmonodebuggerserver.la @@ -11,7 +13,8 @@ x86-linux-ptrace.c \ x86-linux-ptrace.h \ x86-ptrace.c \ - x86-ptrace.h + x86-ptrace.h \ + remote.c if PLATFORM_POWERPC platform_sources = @@ -29,7 +32,9 @@ mutex.h \ thread-db.c \ thread-db.h \ - linux-proc-service.h + linux-proc-service.h \ + $(RPCDIR)/remotedebug_clnt.c \ + $(RPCDIR)/remotedebug_xdr.c libmonodebuggerserver_la_LIBADD = \ @SERVER_DEPENDENCIES_LIBS@ -lthread_db \ @@ -38,3 +43,7 @@ -no-undefined -export-dynamic -shared CLEANFILES = lib*.a lib*.dll + +bin_PROGRAMS = mdbremoteinputforwarder + +mdbremoteinputforwarder_SOURCES = remoteinputforwarder.c diff -Naur MDB-v0.60-r91325/backend/server/remote.c MDB-v0.60-r91325-RemoteDebug/backend/server/remote.c --- MDB-v0.60-r91325/backend/server/remote.c 1970-01-01 00:00:00.000000000 +0000 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/remote.c 2008-03-18 11:45:15.000000000 +0100 @@ -0,0 +1,508 @@ +/* + * Remote debugging extension for the Mono Debugger. + * Developed within the ViMEM project - visit + * http://www.streamunlimited.com/vimem for details. + * + * Copyright (C) 2008 TU Vienna, Institute of Computer Technology + * All rights reserved. /* + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Contributors: + * Harald Krapfenbauer + * - Initial API and implementation + */ + + +/* This file contains stuff for remote debugging with MDB. */ + + +/// flag: remote debugging? 1=yes 0=no +int remote_debug_flag=0; + +/// if remote debugging: IP address of target +static char *target_address = NULL; + +/// if remote debugging: path to exe file on target +static char *target_exe = NULL; + +/// mutex for RPC client handle no. 1 +static GStaticMutex clnt_mutex = G_STATIC_MUTEX_INIT; + +/// mutex for RPC client handle no. 2 +static GStaticMutex dowait_clnt_mutex = G_STATIC_MUTEX_INIT; + +/// RPC client handle no. 1 +static CLIENT* client = NULL; + +/// RPC client handle no. 2 +static CLIENT* dowait_client = NULL; + +/// Remote debugging: PID of input forwarder process +static int input_forwarder_pid=-1; + +/// port which inferior stdout socket is connected to +static uint16_t port; + +/// needed for path replacement +static char *exe_replace = NULL; + +/// needed for path replacement +static char *exe_replacewith = NULL; + +/// needed for path replacement +static char *mono_replace = NULL; + +/// needed for path replacement +static char *mono_replacewith = NULL; + +/// socket for stdout inferior output +static int stdoutsock=-1; + +/// socket for stderr inferior output +static int stderrsock=-1; + + +/* prototype declarations */ +CLIENT* rpc_get_client(void); +void rpc_destroy_client(void); +void rpc_put_client(void); + + +/// Checks if the argument string contains a path that is only valid on the target and replaces +/// parts of the path so that it will be valid on the host. Remote paths are detected if they belong to the +/// Mono installation or the directory where the application lives in. +/// The remote path +/// The corresponding local path +const gchar *adjust_pathname(const gchar *path) +{ + if (remote_debug_flag) + { + gchar *retval; + + if (exe_replace != NULL && exe_replacewith != NULL) + if (strncmp(path,exe_replace,strlen(exe_replace)) == 0) + { + retval = calloc(strlen(exe_replacewith)+strlen(path+strlen(exe_replace))+1,1); + // retval is freed by mono + strcpy(retval,exe_replacewith); + strcpy(retval+strlen(exe_replacewith),path+strlen(exe_replace)); + return retval; + } + if (mono_replace != NULL && mono_replacewith != NULL) + if (strncmp(path,mono_replace,strlen(mono_replace)) == 0) + { + retval = calloc(strlen(mono_replacewith)+strlen(path+strlen(mono_replace))+1,1); + // retval is freed by mono + strcpy(retval,mono_replacewith); + strcpy(retval+strlen(mono_replacewith),path+strlen(mono_replace)); + return retval; + } + } + return NULL; +} + + +/// +/// Sets up the replacement of remote paths with local paths, which is required for the use of +/// adjust_pathname(). +/// +/// Absolute local path of application +/// Absolute remote path of application +/// Absolute local path of mdb.exe executable +/// Absolute remote path of mono shell script (located in MONO_INST_DIR/bin/) +static void +setup_pathname_adjustment(const char *localexe, const char *remoteexe, const char *localmono, const char *remotemono) +{ + int memory_needed = 0; + + if (localexe != NULL && remoteexe != NULL && *localexe=='/' && *remoteexe=='/') + { + memory_needed = strlen(remoteexe)-strlen(rindex(remoteexe,'/'))+1; + exe_replace = calloc(memory_needed,1); + strncpy(exe_replace,remoteexe,memory_needed-1); + + memory_needed = strlen(localexe)-strlen(rindex(localexe,'/'))+1; + exe_replacewith = calloc(memory_needed,1); + strncpy(exe_replacewith,localexe,memory_needed-1); + } + + if (localmono != NULL && remotemono != NULL && *localmono=='/' && *remotemono=='/') + { + memory_needed = strlen(remotemono)-strlen("/bin/mono")+1; + mono_replace = calloc(memory_needed,1); + strncpy(mono_replace,remotemono,memory_needed-1); + + memory_needed = strlen(localmono)-strlen("/lib/mono/1.0/mdb.exe")+1; + mono_replacewith = calloc(memory_needed,1); + strncpy(mono_replacewith,localmono,memory_needed-1); + } +} + + +/// Sets remote debugging options, connects to MDBSERVER on target +/// 1: remote debugging, 0: local debugging +/// String with the address of the target where MDBSERVER runs in dotted-quad format +/// String with the local path of the application +/// String with the remote path of the application +/// String with the local path of the debugger executable +/// String with the remote path of the mono shell script +/// 0: no error, 1: no valid IP address, 2: cannot connect to mdbserver +gint32 +mono_debugger_server_set_debug_opts(gint32 flag, const char *address, const char *localexe, const char *remoteexe, + const char *localmono, const char *remotemono) +{ + remote_debug_flag = flag; + + if (remote_debug_flag) + { + if (address != NULL) + { + target_address = calloc(strlen(address)+1,1); + // not freed, because only called once in process lifetime + strcpy(target_address,address); + } + if (remoteexe != NULL) + { + target_exe = calloc(strlen(remoteexe)+1,1); + // not freed, because only called once in process lifetime + strcpy(target_exe,remoteexe); + } + + setup_pathname_adjustment(localexe, remoteexe, localmono, remotemono); + + /* connect to mdbserver RPC service */ + if (target_address == NULL) + return 1; + if (inet_aton(target_address, NULL) == 0) + return 1; + + CLIENT *clnt; + int *result; + char *testconn; + + port = PORT_RPC; + /* search for listening mdbserver */ + while (port < PORT_RPC + MAX_PORTS) + { + if ((clnt = rpc_get_client()) == NULL) /* no one listening */ + { + port += 2; + continue; + } + result = testconn_1((void*)&testconn, clnt); + rpc_put_client(); + if (result == (int *) NULL) + { + port += 2; + rpc_destroy_client(); + continue; + } + if (*result == 1) /* mdbserver listening, but occupied */ + { + port += 2; + rpc_destroy_client(); + continue; + } + g_assert(*result == 0); + break; + } + if (port >= PORT_RPC + MAX_PORTS) /* no free mdbserver found */ + return 2; + g_message("Successfully connected to MDBSERVER on target %s listening on TCP port %d.", + target_address,port); + } + return 0; +} + + +/// 1 if we are remote debugging, 0 for local debugging +int +mono_debugger_server_get_remote_debug(void) +{ + return remote_debug_flag; +} + + +/// Returns an RPC client handle no. 1 for most remote debugging requests. +/// The handle is locked, which means that this function may block until +/// the handle is unlocked by the current owner. +/// An RPC client handle +CLIENT* +rpc_get_client(void) +{ + g_static_mutex_lock(&clnt_mutex); + + if (client == NULL) + { + struct sockaddr_in rpc_addr; + int sockp = RPC_ANYSOCK; + + bzero((char *) &rpc_addr, sizeof(rpc_addr)); + rpc_addr.sin_family = AF_INET; + inet_aton(target_address, &(rpc_addr.sin_addr)); + rpc_addr.sin_port = htons(port); + client = clnttcp_create(&rpc_addr, MDBSERVER, MDBSERVERVERSION, &sockp, 0, 0); + + /* "Using UDP has its shortcomings. Since UDP-based RPC messages can only hold up to + 8 Kbytes of encoded data, this transport cannot be used for procedures that take + large arguments or return huge results." + Functions like mono_debugger_thread_db_init_remote() transfer ~10 KBytes of payload, + so we have to use TCP! + */ + if (client == NULL) + { + /* error creating client */ + g_static_mutex_unlock(&clnt_mutex); + return NULL; + } + } + return client; +} + + +/// Frees the RPC client handle no. 1 +void +rpc_destroy_client(void) +{ + g_static_mutex_lock(&clnt_mutex); + clnt_destroy(client); + client = NULL; + g_static_mutex_unlock(&clnt_mutex); +} + + +/// Returns an RPC client handle no. 2 for do_wait() requests. +/// The handle is locked, which means that this function may block until +/// the handle is unlocked by the current owner. (Actually, this never happens, because +/// do_wait() is the only function that is called with this handle.) +/// An RPC client handle +CLIENT* +rpc_get_dowait_client(void) +{ + g_static_mutex_lock(&dowait_clnt_mutex); + + if (dowait_client == NULL) + { + struct sockaddr_in rpc_addr; + int sockp; + + bzero((char *) &rpc_addr, sizeof(rpc_addr)); + rpc_addr.sin_family = AF_INET; + inet_aton(target_address, &(rpc_addr.sin_addr)); + rpc_addr.sin_port = htons(port+1); + dowait_client = clnttcp_create(&rpc_addr, MDBSERVER, DOWAIT_VERSION, &sockp, 0, 0); + + if (dowait_client == NULL) + { + /* error creating client */ + clnt_pcreateerror (target_address); + g_static_mutex_unlock(&dowait_clnt_mutex); + return NULL; + } + } + + return dowait_client; +} + + +/// Unlocks the RPC client handle no. 1 +void +rpc_put_client(void) +{ + g_static_mutex_unlock(&clnt_mutex); +} + + +/// Unlocks the RPC client handle no. 2 +void +rpc_put_dowait_client(void) +{ + g_static_mutex_unlock(&dowait_clnt_mutex); +} + + +/// Reads out the content of a remote file. Used to get contents of /proc/[PID]/maps. +void +mono_debugger_server_get_map_file(char *filename, char **content) +{ + INFO; + g_assert(remote_debug_flag); /* Native debugging: Read via C# Code */ + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) { + *content = NULL; + return; + } + + content = get_map_file_1(&filename, clnt); + rpc_put_client(); + if (content == (char **) NULL) { + clnt_perror (clnt, "get_map_file_1() call failed"); + *content = NULL; + return; + } +} + + +/// Terminates the remote MDBSERVER via RPC. +void +mdbserver_quit(void) +{ + INFO; + + void *result; + char *arg; + if (remote_debug_flag) + { + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + { + return; + } + result = quit_1((void*)&arg, clnt); + rpc_put_client(); + if (result == (void *) NULL) { + clnt_perror (clnt, "quit_1() call failed"); + } + } + return; +} + + +#define INPUTFORW "/bin/mdbremoteinputforwarder" + +/// Forks a child process with the input forwarder that reads data for the inferior +/// application's stdin port locally and sends it to the target via a socket. Records the PID of +/// the child process for future use. +/// The TCP port number on which the listening socket shall be created by +/// the input forwarder process. +static void +start_input_forwarder(uint16_t port) +{ + int child_pid, fd[2], len, ret; + gchar *error; + + g_assert(remote_debug_flag); + + /* pipe used for errors in execve() */ + pipe (fd); + + child_pid = fork (); + if (child_pid == 0) { + /* child */ + struct rlimit core_limit; + int open_max, i; + gchar *error_message; + + open_max = sysconf (_SC_OPEN_MAX); + for (i = 3; i < open_max; i++) + fcntl (i, F_SETFD, FD_CLOEXEC); + + getrlimit (RLIMIT_CORE, &core_limit); + core_limit.rlim_cur = 0; + setrlimit (RLIMIT_CORE, &core_limit); + + /* set up argv */ + char *executable = calloc(strlen(mono_replacewith)+strlen(INPUTFORW)+1,1); + strcpy(executable,mono_replacewith); + strcpy(executable+strlen(mono_replacewith),INPUTFORW); + char **argv = calloc(sizeof(char*)*3,1); + argv[0] = executable; + char *port_string = calloc(sizeof(char)*6,1); + sprintf(port_string,"%u",port); + argv[1] = port_string; + + execve(argv[0], argv, environ); + + /* only reached on error */ + error_message = g_strdup_printf("Cannot exec `%s': %s", argv[0], g_strerror (errno)); + len = strlen(error_message)+1; + write(fd [1], &len, sizeof (len)); + write (fd [1], error_message, len); + + _exit (1); + } + + if (child_pid == -1) { + /* error */ + g_warning("Could not fork process that forwards stdin data for the inferior application: %s. %s", + strerror(errno), + "Input to inferior appliation will not be possible."); + return; + } + + close (fd [1]); + /* get error message from child */ + ret = read (fd [0], &len, sizeof (len)); + if (ret != 0) { + g_assert (ret == 4); + error = g_malloc0 (len); + read (fd [0], error, len); + close (fd [0]); + g_warning("%s. Input to inferior application will not be possible.",error); + return; + } + + /* remember child pid */ + input_forwarder_pid = child_pid; +} + +/// Continues the input forwarder process. If it is continued, all input on the terminal +/// goes to it and hence to the inferior application's stdin, and _NOT_ to mdb! The PID of the input +/// forwarder process must have been set previously by start_input_forwarder(), otherwise the function +/// has no effect. +static void +continue_input_forwarder() +{ + g_assert(remote_debug_flag); + + if (input_forwarder_pid == -1) + return; + + /* send continue */ + kill(input_forwarder_pid, SIGCONT); +} + +/// Stops the input forwarder process. If it is stopped, all input on the terminal +/// goes to mdb. The PID of the input forwarder process must have been set previously by start_input_forwarder(), +/// otherwise the function has no effect. +static void +stop_input_forwarder() +{ + g_assert(remote_debug_flag); + + if (input_forwarder_pid == -1) + return; + + /* send stop */ + kill(input_forwarder_pid, SIGSTOP); +} + +/// Terminates the input forwarder process. +static void +kill_input_forwarder() +{ + g_assert(remote_debug_flag); + + if (input_forwarder_pid == -1) + return; + + /* send terminate and wait */ + kill(input_forwarder_pid, SIGTERM); + waitpid(input_forwarder_pid, NULL, 0); +} diff -Naur MDB-v0.60-r91325/backend/server/remoteinputforwarder.c MDB-v0.60-r91325-RemoteDebug/backend/server/remoteinputforwarder.c --- MDB-v0.60-r91325/backend/server/remoteinputforwarder.c 1970-01-01 00:00:00.000000000 +0000 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/remoteinputforwarder.c 2008-03-18 11:45:15.000000000 +0100 @@ -0,0 +1,95 @@ +/* + * Remote debugging extension for the Mono Debugger. + * Developed within the ViMEM project - visit + * http://www.streamunlimited.com/vimem for details. + * + * Copyright (C) 2008 TU Vienna, Institute of Computer Technology + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Contributors: + * Harald Krapfenbauer + * - Initial API and implementation + */ + + +#include +#include +#include +#include +#include +#include + + +/// Simple application: input forwarder. Creates a listening socket on the specified port, +/// waits for a connecting and repeatedly sends input on stdin over the socket. Stops after setting up +/// the listening socket and after the socket is connected. +/// Amount of command line arguments +/// Second one is the port +int main (int argc, char** argv) +{ + char input[BUFSIZ+1]; + int len, stdinsock=-1, tempsock=-1; + + /* we need exactly 1 argument, the port */ + if (argc != 2) + return(1); + + /* create listening socket */ + struct sockaddr_in stdin_addr; + stdinsock = socket(AF_INET, SOCK_STREAM, 0); + bzero((char *) &stdin_addr, sizeof(stdin_addr)); + stdin_addr.sin_family = AF_INET; + stdin_addr.sin_addr.s_addr = INADDR_ANY; + + uint16_t port = (uint16_t)strtol(argv[1],NULL,10); /* get port out of first argument */ + + stdin_addr.sin_port = htons(port); + if (bind(stdinsock, (struct sockaddr *) &stdin_addr, sizeof(stdin_addr)) == -1) { + fprintf(stderr,"** Warning: Could not bind socket for inferior stdin data at port %u,%s", + port,"\n input to inferior application will not be possible.\n"); + return 1; + } + + if (listen(stdinsock, 1) == -1) { + fprintf(stderr,"** Warning: Could not set socket for inferior stdin data %s", + "in listening mode,\n input to inferior application will not be possible.\n"); + return 1; + } + + /* stop myself - mdb waits for this */ + kill(getpid(),SIGSTOP); + + /* wait for connection */ + tempsock = accept(stdinsock,NULL,NULL); + close(stdinsock); + stdinsock = tempsock; + + /* stop again so that mdb gets the terminal input */ + kill(getpid(),SIGSTOP); + + /* read data for stdin in an endless loop */ + while(1) { + len = read(0,(void*)&input,BUFSIZ); + if (len > 0) { + /* write to socket */ + write(stdinsock,input,len); + } + } + return 0; +} diff -Naur MDB-v0.60-r91325/backend/server/server.h MDB-v0.60-r91325-RemoteDebug/backend/server/server.h --- MDB-v0.60-r91325/backend/server/server.h 2007-12-08 16:46:59.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/server.h 2008-03-03 17:25:16.000000000 +0100 @@ -7,6 +7,15 @@ G_BEGIN_DECLS +//#define SERVERDEBUG +#ifdef SERVERDEBUG +#define INFO fprintf(stderr,"%s\n",(G_STRFUNC)) +#define INFOS(x) fprintf(stderr,"%s: %s\n",(G_STRFUNC),(x)) +#else +#define INFO do {} while (0); +#define INFOS(x) do {} while (0); +#endif + #define MONO_DEBUGGER_REMOTE_VERSION 1 #define MONO_DEBUGGER_REMOTE_MAGIC 0x36885fe4 diff -Naur MDB-v0.60-r91325/backend/server/thread-db.c MDB-v0.60-r91325-RemoteDebug/backend/server/thread-db.c --- MDB-v0.60-r91325/backend/server/thread-db.c 2007-08-22 16:45:16.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/thread-db.c 2007-11-28 09:57:13.000000000 +0100 @@ -3,11 +3,19 @@ #endif #include +#include + + +extern int remote_debug_flag; +extern CLIENT* rpc_get_client(void); + ps_err_e ps_pglobal_lookup (ThreadDbHandle *handle, const char *object_name, const char *sym_name, psaddr_t *sym_addr) { + g_assert(!remote_debug_flag); + guint64 address; ps_err_e e; @@ -19,55 +27,224 @@ ps_err_e ps_pdread (ThreadDbHandle *handle, psaddr_t addr, void *buffer, size_t size) { + g_assert(!remote_debug_flag); + return (* handle->read_memory) ((guint64) (gsize) addr, buffer, size); } ps_err_e ps_pdwrite (ThreadDbHandle *handle, psaddr_t addr, const void *buffer, size_t size) { + g_assert(!remote_debug_flag); + return (* handle->write_memory) ((guint64) (gsize) addr, buffer, size); } pid_t ps_getpid (ThreadDbHandle *handle) { + g_assert(!remote_debug_flag); + return -1; } + ThreadDbHandle * mono_debugger_thread_db_init (GlobalLookupFunc global_lookup, ReadMemoryFunc read_memory, WriteMemoryFunc write_memory) { + INFO; + g_assert(!remote_debug_flag); + ThreadDbHandle *handle; td_err_e e; - + e = td_init (); if (e) return NULL; - + handle = g_new0 (ThreadDbHandle, 1); handle->global_lookup = global_lookup; handle->read_memory = read_memory; handle->write_memory = write_memory; - + e = td_ta_new (handle, &handle->thread_agent); if (e) return NULL; - + return handle; } + +/// copied from x86-ptrace.c +struct InferiorHandle +{ + guint32 pid; +#ifdef __linux__ + int mem_fd; +#endif + int last_signal; + int output_fd [2], error_fd [2]; + int is_thread, is_initialized; + guint64 notification_address; +}; + + +/// +/// Makes a list of current set breakpoints. +/// +/// The ServerHandle +/// Pointer is set to guint64 addresses of breakpoints +/// Pointer is set to original instructions +/// Number of breakpoints +u_int +get_breakpoint_list (ServerHandle *handle, guint64 **addresses, char **instructions) +{ + GPtrArray *breakpoints; + int i, count=0; + + mono_debugger_breakpoint_manager_lock (); + + breakpoints = mono_debugger_breakpoint_manager_get_breakpoints (handle->bpm); + for (i = 0; i < breakpoints->len; i++) { + BreakpointInfo *info = g_ptr_array_index (breakpoints, i); + + if (info->is_hardware_bpt || !info->enabled) + continue; + + count++; // count the breakpoints + } + *addresses = g_malloc(count * sizeof(guint64)); + *instructions = g_malloc(count * sizeof(char)); + guint64 *adr_ptr = *addresses; + char *insn_ptr = *instructions; + + for (i=0; ilen; i++) { + BreakpointInfo *info = g_ptr_array_index(breakpoints, i); + + if (info->is_hardware_bpt || !info->enabled) + continue; + + *adr_ptr = info->address; + adr_ptr++; + *insn_ptr = info->saved_insn; + insn_ptr++; + } + + mono_debugger_breakpoint_manager_unlock (); + + return count; +} + + +/// Function for initializing ThreadDB for remote debugging. Similar to mono_debugger_thread_db_init(), but +/// this one gets more information that need to be transferred onto the target +/// We need the memory file descriptor of the target process out of this struct. +/// This string array contains the names of symbols +/// This array of long's contains the corresponding addresses of symbols. +/// The number of symbols the functions gets in sym_names and sym_addrs +/// A handle for future referencing +ThreadDbHandle * +mono_debugger_thread_db_init_remote (ServerHandle *handle, gchar **sym_names, guint64 *sym_addrs, int sym_count) +{ + INFO; + g_assert(remote_debug_flag); + + u_int *result; + struct thread_db_init_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return NULL; + + /* fill in breakpoint information sent to target */ + arg.mem_fd = handle->inferior->mem_fd; + int bpts = get_breakpoint_list(handle,(guint64**)&arg.bpt_addrs.bpt_addrs_val,&arg.bpt_insns.bpt_insns_val); + arg.bpt_addrs.bpt_addrs_len = bpts * sizeof(guint64); + arg.bpt_insns.bpt_insns_len = bpts * sizeof(char); + + /* fill in symbol information sent to target */ + if (sym_count > 0) { + int sym_str_len = 0; + int i; + /* count the total length of all symbol strings */ + for (i=0; i This function makes an RPC call if remote debugging is enabled void mono_debugger_thread_db_destroy (ThreadDbHandle *handle) { - td_ta_delete (handle->thread_agent); - g_free (handle); + INFO; + + if (remote_debug_flag) + { + void *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return; + + arg = (u_int) handle; + + result = thread_db_destroy_1(&arg, clnt); + rpc_put_client(); + if (result == (void *) NULL) { + clnt_perror (clnt, "call failed"); + return; + } + + } + else + { + td_ta_delete (handle->thread_agent); + g_free (handle); + } } + gboolean mono_debugger_thread_db_get_thread_info (const td_thrhandle_t *th, guint64 *tid, guint64 *tls, guint64 *lwp) { + g_assert(!remote_debug_flag); + td_thrinfo_t ti; td_err_e e; @@ -85,16 +262,21 @@ static int iterate_over_threads_cb (const td_thrhandle_t *th, void *user_data) { + g_assert(!remote_debug_flag); + IterateOverThreadsFunc func = (IterateOverThreadsFunc) user_data; td_thrinfo_t ti; td_err_e e; - + return (* func) (th) ? 0 : 1; } + gboolean mono_debugger_thread_db_iterate_over_threads (ThreadDbHandle *handle, IterateOverThreadsFunc func) { + INFO; + td_thrhandle_t th; td_err_e e; @@ -104,3 +286,76 @@ return e == PS_OK; } + + +/// Replaces function mono_debugger_thread_db_iterate_over_threads() if remote debugging is enabled +gboolean +mono_debugger_thread_db_iterate_over_threads_remote (ThreadDbHandle *handle, ServerHandle *servhandle, + gchar **sym_names, guint64 *sym_addrs, int sym_count, + guint64 **lwp, guint64 **tid, int *thread_count) +{ + INFO; + g_assert(remote_debug_flag); + + struct thread_db_iterate_struct_out *result; + struct thread_db_iterate_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return FALSE; + + arg.mem_fd = servhandle->inferior->mem_fd; + arg.handle = (u_int) handle; + + /* fill in breakpoint information sent to target */ + int bpts = get_breakpoint_list(servhandle,(guint64**)&arg.bpt_addrs.bpt_addrs_val,&arg.bpt_insns.bpt_insns_val); + arg.bpt_addrs.bpt_addrs_len = bpts * sizeof(guint64); + arg.bpt_insns.bpt_insns_len = bpts * sizeof(char); + + /* fill in symbol information sent to target */ + if (sym_count > 0) { + int sym_str_len = 0; + int i; + /* count the total length of all symbol strings */ + for (i=0; ilwp.lwp_val; + *tid = (guint64*) result->tid.tid_val; + *thread_count = (result->lwp.lwp_len)/sizeof(guint64); + + return TRUE; +} diff -Naur MDB-v0.60-r91325/backend/server/x86-linux-ptrace.c MDB-v0.60-r91325-RemoteDebug/backend/server/x86-linux-ptrace.c --- MDB-v0.60-r91325/backend/server/x86-linux-ptrace.c 2007-12-10 11:32:59.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/x86-linux-ptrace.c 2008-03-04 17:19:10.000000000 +0100 @@ -1,6 +1,9 @@ +/* The function is always executed on target while remote debugging */ static ServerCommandError _server_ptrace_check_errno (InferiorHandle *inferior) { + g_assert(!remote_debug_flag); + gchar *filename; if (!errno) @@ -22,67 +25,197 @@ return COMMAND_ERROR_NO_TARGET; } + +/* The function is always executed on target while remote debugging */ static ServerCommandError _server_ptrace_get_registers (InferiorHandle *inferior, INFERIOR_REGS_TYPE *regs) { + g_assert(!remote_debug_flag); + if (ptrace (PT_GETREGS, inferior->pid, NULL, regs) != 0) return _server_ptrace_check_errno (inferior); return COMMAND_ERROR_NONE; } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError _server_ptrace_set_registers (InferiorHandle *inferior, INFERIOR_REGS_TYPE *regs) { - if (ptrace (PT_SETREGS, inferior->pid, NULL, regs) != 0) - return _server_ptrace_check_errno (inferior); + if (remote_debug_flag) + { + int *result; + struct set_registers_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = inferior->pid; + arg.ebx = regs->ebx; + arg.ecx = regs->ecx; + arg.edx = regs->edx; + arg.esi = regs->esi; + arg.edi = regs->edi; + arg.ebp = regs->ebp; + arg.eax = regs->eax; + arg.ds = regs->ds; + arg.__ds = regs->__ds; + arg.es = regs->es; + arg.__es = regs->__es; + arg.fs = regs->fs; + arg.__fs = regs->__fs; + arg.gs = regs->gs; + arg.__gs = regs->__gs; + arg.orig_eax = regs->orig_eax; + arg.eip = regs->eip; + arg.cs = regs->cs; + arg.__cs = regs->__cs; + arg.eflags = regs->eflags; + arg.esp = regs->esp; + arg.ss = regs->ss; + arg.__ss = regs->__ss; + + result = set_registers_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "set_registers_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return *result; - return COMMAND_ERROR_NONE; + } + else + { + + if (ptrace (PT_SETREGS, inferior->pid, NULL, regs) != 0) + return _server_ptrace_check_errno (inferior); + + return COMMAND_ERROR_NONE; + } } + +/* The function is always executed on target while remote debugging */ static ServerCommandError _server_ptrace_get_fp_registers (InferiorHandle *inferior, INFERIOR_FPREGS_TYPE *regs) { + g_assert(!remote_debug_flag); + if (ptrace (PT_GETFPREGS, inferior->pid, NULL, regs) != 0) return _server_ptrace_check_errno (inferior); return COMMAND_ERROR_NONE; } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError _server_ptrace_set_fp_registers (InferiorHandle *inferior, INFERIOR_FPREGS_TYPE *regs) { - if (ptrace (PT_SETFPREGS, inferior->pid, NULL, regs) != 0) - return _server_ptrace_check_errno (inferior); + INFO; - return COMMAND_ERROR_NONE; + if (remote_debug_flag) + { + int *result; + struct set_fp_registers_struct_in arg; + int i; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = inferior->pid; + arg.cwd = regs->cwd; + arg.swd = regs->swd; + arg.twd = regs->twd; + arg.fip = regs->fip; + arg.fcs = regs->fcs; + arg.foo = regs->foo; + arg.fos = regs->fos; + for (i=0;i<20;i++) + arg.st_space[i] = regs->st_space[i]; + + result = set_fp_registers_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "set_fp_registers_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return *result; + } + else + { + if (ptrace (PT_SETFPREGS, inferior->pid, NULL, regs) != 0) + return _server_ptrace_check_errno (inferior); + + return COMMAND_ERROR_NONE; + } } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError _server_ptrace_read_memory (ServerHandle *handle, guint64 start, guint32 size, gpointer buffer) { - guint8 *ptr = buffer; - guint32 old_size = size; + INFO; - while (size) { - int ret = pread64 (handle->inferior->mem_fd, ptr, size, start); - if (ret < 0) { - if (errno == EINTR) - continue; - else if (errno == ESRCH) - return COMMAND_ERROR_NOT_STOPPED; - else if (errno == EIO) + if (remote_debug_flag) + { + struct read_memory_struct_in arg; + struct read_memory_struct_out *result; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.mem_fd = handle->inferior->mem_fd; + arg.start[0] = start; + arg.start[1] = (start >> 32); + arg.size = size; + + result = read_memory_1(&arg, clnt); + rpc_put_client(); + if (result == (struct read_memory_struct_out *) NULL) { + clnt_perror(clnt, "read_memory_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + memcpy(buffer,(const void *)result->buffer.buffer_val,size); + + return result->servercommanderror; + } + + else + + { /* no remote debugging */ + + guint8 *ptr = buffer; + guint32 old_size = size; + + while (size) { + int ret = pread64 (handle->inferior->mem_fd, ptr, size, start); + if (ret < 0) { + if (errno == EINTR) + continue; + else if (errno == ESRCH) + return COMMAND_ERROR_NOT_STOPPED; + else if (errno == EIO) + return COMMAND_ERROR_MEMORY_ACCESS; return COMMAND_ERROR_MEMORY_ACCESS; - return COMMAND_ERROR_MEMORY_ACCESS; + } + + size -= ret; + ptr += ret; } - - size -= ret; - ptr += ret; + return COMMAND_ERROR_NONE; } - - return COMMAND_ERROR_NONE; } + static ServerCommandError server_ptrace_read_memory (ServerHandle *handle, guint64 start, guint32 size, gpointer buffer) { @@ -93,23 +226,56 @@ return COMMAND_ERROR_NONE; } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError _server_ptrace_set_dr (InferiorHandle *handle, int regnum, guint64 value) { - errno = 0; - ptrace (PTRACE_POKEUSER, handle->pid, offsetof (struct user, u_debugreg [regnum]), value); - if (errno) { - g_message (G_STRLOC ": %d - %d - %s", handle->pid, regnum, g_strerror (errno)); - return COMMAND_ERROR_UNKNOWN_ERROR; - } + INFO; - return COMMAND_ERROR_NONE; + if (remote_debug_flag) + { + int *result; + struct set_dr_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = handle->pid; + arg.regnum = regnum; + arg.value[0] = value; + arg.value[1] = (value >> 32); + + result = set_dr_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "set_dr_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return *result; + } + else + { + errno = 0; + ptrace (PTRACE_POKEUSER, handle->pid, offsetof (struct user, u_debugreg [regnum]), value); + if (errno) { + g_message (G_STRLOC ": %d - %d - %s", handle->pid, regnum, g_strerror (errno)); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return COMMAND_ERROR_NONE; + } } +/* The function is always executed on target while remote debugging */ static ServerCommandError _server_ptrace_get_dr (InferiorHandle *handle, int regnum, guint64 *value) { + g_assert(!remote_debug_flag); + int ret; errno = 0; @@ -127,30 +293,62 @@ GStaticMutex wait_mutex_2 = G_STATIC_MUTEX_INIT; GStaticMutex wait_mutex_3 = G_STATIC_MUTEX_INIT; + +/// This function makes an RPC call if remote debugging is enabled static int do_wait (int pid, guint32 *status) { - int ret; + INFO; + if (remote_debug_flag) + { + do_wait_struct_out *result; + int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_dowait_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = pid; + + result = do_wait_2(&arg, clnt); + rpc_put_dowait_client(); + if (result == (do_wait_struct_out *) NULL) { + clnt_perror (clnt, "do_wait_2() call failed"); + return -1; + } + + *status = result->status; + + INFOS("end"); + return result->retval; + } + else + { + int ret; + #if DEBUG_WAIT - g_message (G_STRLOC ": do_wait (%d)", pid); + g_message (G_STRLOC ": do_wait (%d)", pid); #endif - ret = waitpid (pid, status, WUNTRACED | __WALL | __WCLONE); + ret = waitpid (pid, status, WUNTRACED | __WALL | __WCLONE); #if DEBUG_WAIT - g_message (G_STRLOC ": do_wait (%d) finished: %d - %x", pid, ret, *status); + g_message (G_STRLOC ": do_wait (%d) finished: %d - %x", pid, ret, *status); #endif - if (ret < 0) { - if (errno == EINTR) - return 0; - else if (errno == ECHILD) + if (ret < 0) { + if (errno == EINTR) + return 0; + else if (errno == ECHILD) + return -1; + g_warning (G_STRLOC ": Can't waitpid for %d: %s", pid, g_strerror (errno)); return -1; - g_warning (G_STRLOC ": Can't waitpid for %d: %s", pid, g_strerror (errno)); - return -1; + } + + INFOS("end"); + return ret; } - - return ret; } + static int stop_requested = 0; static int stop_status = 0; @@ -159,7 +357,7 @@ { int ret, status; - again: +again: g_static_mutex_lock (&wait_mutex); ret = do_wait (-1, &status); if (ret <= 0) @@ -189,37 +387,106 @@ g_static_mutex_unlock (&wait_mutex_2); *status_ret = status; - out: +out: g_static_mutex_unlock (&wait_mutex); return ret; } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_stop (ServerHandle *handle) { - ServerCommandError result; + INFO; - /* - * Try to get the thread's registers. If we suceed, then it's already stopped - * and still alive. - */ - result = x86_arch_get_registers (handle); - if (result == COMMAND_ERROR_NONE) - return COMMAND_ERROR_ALREADY_STOPPED; + if (remote_debug_flag) + { + struct stop_struct_out *result; + u_int arg; + int i; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = stop_1(&arg, clnt); + rpc_put_client(); + if (result == (struct stop_struct_out *) NULL) { + clnt_perror (clnt, "stop_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + handle->arch->current_regs.ebx = result->ebx; + handle->arch->current_regs.ecx = result->ecx; + handle->arch->current_regs.edx = result->edx; + handle->arch->current_regs.esi = result->esi; + handle->arch->current_regs.edi = result->edi; + handle->arch->current_regs.ebp = result->ebp; + handle->arch->current_regs.eax = result->eax; + handle->arch->current_regs.ds = result->ds; + handle->arch->current_regs.__ds = result->__ds; + handle->arch->current_regs.es = result->es; + handle->arch->current_regs.__es = result->__es; + handle->arch->current_regs.fs = result->fs; + handle->arch->current_regs.__fs = result->__fs; + handle->arch->current_regs.gs = result->gs; + handle->arch->current_regs.__gs = result->__gs; + handle->arch->current_regs.orig_eax = result->orig_eax; + handle->arch->current_regs.eip = result->eip; + handle->arch->current_regs.cs = result->cs; + handle->arch->current_regs.__cs = result->__cs; + handle->arch->current_regs.eflags = result->eflags; + handle->arch->current_regs.esp = result->esp; + handle->arch->current_regs.ss = result->ss; + handle->arch->current_regs.__ss = result->__ss; + + handle->arch->current_fpregs.cwd = result->cwd; + handle->arch->current_fpregs.swd = result->swd; + handle->arch->current_fpregs.twd = result->twd; + handle->arch->current_fpregs.fip = result->fip; + handle->arch->current_fpregs.fcs = result->fcs; + handle->arch->current_fpregs.foo = result->foo; + handle->arch->current_fpregs.fos = result->fos; + for (i=0; i<20; i++) + handle->arch->current_fpregs.st_space[i] = result->st_space[i]; + + handle->arch->dr_status = result->dr_status[1]; + handle->arch->dr_status <<= 32; + handle->arch->dr_status |= result->dr_status[0]; + + return result->servercommanderror; - if (syscall (__NR_tkill, handle->inferior->pid, SIGSTOP)) { + } + else + { + + ServerCommandError result; + /* - * It's already dead. + * Try to get the thread's registers. If we suceed, then it's already stopped + * and still alive. */ - if (errno == ESRCH) - return COMMAND_ERROR_NO_TARGET; - else - return COMMAND_ERROR_UNKNOWN_ERROR; + result = x86_arch_get_registers (handle); + if (result == COMMAND_ERROR_NONE) + return COMMAND_ERROR_ALREADY_STOPPED; + + if (syscall (__NR_tkill, handle->inferior->pid, SIGSTOP)) { + /* + * It's already dead. + */ + if (errno == ESRCH) + return COMMAND_ERROR_NO_TARGET; + else + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return COMMAND_ERROR_NONE; } - - return COMMAND_ERROR_NONE; } + static ServerCommandError server_ptrace_stop_and_wait (ServerHandle *handle, guint32 *status) { @@ -288,9 +555,13 @@ return COMMAND_ERROR_NONE; } + +/* The function is always executed on target while remote debugging */ static ServerCommandError _server_ptrace_setup_inferior (ServerHandle *handle) { + g_assert(!remote_debug_flag); + gchar *filename = g_strdup_printf ("/proc/%d/mem", handle->inferior->pid); handle->inferior->mem_fd = open64 (filename, O_RDONLY); @@ -304,21 +575,53 @@ return COMMAND_ERROR_NONE; } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_initialize_process (ServerHandle *handle) { - int flags = PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | - PTRACE_O_TRACEEXEC; + INFO; - if (ptrace (PTRACE_SETOPTIONS, handle->inferior->pid, 0, flags)) { - g_warning (G_STRLOC ": Can't PTRACE_SETOPTIONS %d: %s", - handle->inferior->pid, g_strerror (errno)); - return COMMAND_ERROR_UNKNOWN_ERROR; + if (remote_debug_flag) + { + int *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = initialize_process_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "initialize_process_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return *result; } - return COMMAND_ERROR_NONE; + else + + { + + int flags = PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | + PTRACE_O_TRACEEXEC; + + if (ptrace (PTRACE_SETOPTIONS, handle->inferior->pid, 0, flags)) { + g_warning (G_STRLOC ": Can't PTRACE_SETOPTIONS %d: %s", + handle->inferior->pid, g_strerror (errno)); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return COMMAND_ERROR_NONE; + + } } + static ServerCommandError server_ptrace_get_signal_info (ServerHandle *handle, SignalInfo **sinfo_out) { @@ -342,123 +645,214 @@ stop_status = 0; } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_get_threads (ServerHandle *handle, guint32 *count, guint32 **threads) { - gchar *dirname = g_strdup_printf ("/proc/%d/task", handle->inferior->pid); - const gchar *filename; - GPtrArray *array; - GDir *dir; - int i; + INFO; + + if (remote_debug_flag) + { + struct get_threads_struct_out *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = get_threads_1(&arg, clnt); + rpc_put_client(); + if (result == (struct get_threads_struct_out *) NULL) { + clnt_perror (clnt, "get_threads_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + *count = result->count; + threads = &result->threads.threads_val; + + return result->servercommanderror; - dir = g_dir_open (dirname, 0, NULL); - if (!dir) { - g_warning (G_STRLOC ": Can't get threads of %d", handle->inferior->pid); + } + + else + + { + + gchar *dirname = g_strdup_printf ("/proc/%d/task", handle->inferior->pid); + const gchar *filename; + GPtrArray *array; + GDir *dir; + int i; + + dir = g_dir_open (dirname, 0, NULL); + if (!dir) { + g_warning (G_STRLOC ": Can't get threads of %d", handle->inferior->pid); + g_free (dirname); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + array = g_ptr_array_new (); + + while ((filename = g_dir_read_name (dir)) != NULL) { + gchar *endptr; + guint32 pid; + + pid = (guint32) strtol (filename, &endptr, 10); + if (*endptr) + goto out_error; + + g_ptr_array_add (array, GUINT_TO_POINTER (pid)); + } + + *count = array->len; + *threads = g_new0 (guint32, array->len); + + for (i = 0; i < array->len; i++) + (*threads) [i] = GPOINTER_TO_UINT (g_ptr_array_index (array, i)); + g_free (dirname); + g_dir_close (dir); + g_ptr_array_free (array, FALSE); + return COMMAND_ERROR_NONE; + + out_error: + g_free (dirname); + g_dir_close (dir); + g_ptr_array_free (array, FALSE); + g_warning (G_STRLOC ": Can't get threads of %d", handle->inferior->pid); return COMMAND_ERROR_UNKNOWN_ERROR; } +} - array = g_ptr_array_new (); - while ((filename = g_dir_read_name (dir)) != NULL) { - gchar *endptr; - guint32 pid; +/// This function makes an RPC call if remote debugging is enabled +static ServerCommandError +server_ptrace_get_application (ServerHandle *handle, gchar **exe_file, gchar **cwd, + guint32 *nargs, gchar ***cmdline_args) +{ + INFO; - pid = (guint32) strtol (filename, &endptr, 10); - if (*endptr) - goto out_error; + if (remote_debug_flag) + { + struct get_application_struct_out *result; + u_int arg; + gchar *cmdline, **ptr; + gsize pos, len; + GPtrArray *array; + int i; - g_ptr_array_add (array, GUINT_TO_POINTER (pid)); + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = get_application_1(&arg, clnt); + rpc_put_client(); + if (result == (struct get_application_struct_out *) NULL) { + clnt_perror (clnt, "get_application_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + strcpy(*exe_file, result->exe_file); /* ends with 0 character --> use strcpy */ + strcpy(*cwd, result->cwd); /* same */ + + len = result->cmdline_args.cmdline_args_len; + cmdline = result->cmdline_args.cmdline_args_val; + + array = g_ptr_array_new (); + + pos = 0; + while (pos < len) { + g_ptr_array_add (array, cmdline + pos); + pos += strlen (cmdline + pos) + 1; + } + + *nargs = array->len; + *cmdline_args = ptr = g_new0 (gchar *, array->len + 1); + + for (i = 0; i < array->len; i++) + ptr [i] = g_ptr_array_index (array, i); + + g_ptr_array_free (array, FALSE); + return COMMAND_ERROR_NONE; } - *count = array->len; - *threads = g_new0 (guint32, array->len); + else + + { + gchar *exe_filename = g_strdup_printf ("/proc/%d/exe", handle->inferior->pid); + gchar *cwd_filename = g_strdup_printf ("/proc/%d/cwd", handle->inferior->pid); + gchar *cmdline_filename = g_strdup_printf ("/proc/%d/cmdline", handle->inferior->pid); + char buffer [BUFSIZ+1]; + GPtrArray *array; + gchar *cmdline, **ptr; + gsize pos, len; + int i; + + len = readlink (exe_filename, buffer, BUFSIZ); + if (len < 0) { + g_free (cwd_filename); + g_free (exe_filename); + g_free (cmdline_filename); + g_warning (G_STRLOC ": Can't get exe file of %d", handle->inferior->pid); + return COMMAND_ERROR_UNKNOWN_ERROR; + } - for (i = 0; i < array->len; i++) - (*threads) [i] = GPOINTER_TO_UINT (g_ptr_array_index (array, i)); + buffer [len] = 0; + *exe_file = g_strdup (buffer); - g_free (dirname); - g_dir_close (dir); - g_ptr_array_free (array, FALSE); - return COMMAND_ERROR_NONE; + len = readlink (cwd_filename, buffer, BUFSIZ); + if (len < 0) { + g_free (cwd_filename); + g_free (exe_filename); + g_free (cmdline_filename); + g_warning (G_STRLOC ": Can't get cwd of %d", handle->inferior->pid); + return COMMAND_ERROR_UNKNOWN_ERROR; + } - out_error: - g_free (dirname); - g_dir_close (dir); - g_ptr_array_free (array, FALSE); - g_warning (G_STRLOC ": Can't get threads of %d", handle->inferior->pid); - return COMMAND_ERROR_UNKNOWN_ERROR; -} + buffer [len] = 0; + *cwd = g_strdup (buffer); -static ServerCommandError -server_ptrace_get_application (ServerHandle *handle, gchar **exe_file, gchar **cwd, - guint32 *nargs, gchar ***cmdline_args) -{ - gchar *exe_filename = g_strdup_printf ("/proc/%d/exe", handle->inferior->pid); - gchar *cwd_filename = g_strdup_printf ("/proc/%d/cwd", handle->inferior->pid); - gchar *cmdline_filename = g_strdup_printf ("/proc/%d/cmdline", handle->inferior->pid); - char buffer [BUFSIZ+1]; - GPtrArray *array; - gchar *cmdline, **ptr; - gsize pos, len; - int i; + if (!g_file_get_contents (cmdline_filename, &cmdline, &len, NULL)) { + g_free (cwd_filename); + g_free (exe_filename); + g_free (cmdline_filename); + g_warning (G_STRLOC ": Can't get cmdline args of %d", handle->inferior->pid); + return COMMAND_ERROR_UNKNOWN_ERROR; + } - len = readlink (exe_filename, buffer, BUFSIZ); - if (len < 0) { - g_free (cwd_filename); - g_free (exe_filename); - g_free (cmdline_filename); - g_warning (G_STRLOC ": Can't get exe file of %d", handle->inferior->pid); - return COMMAND_ERROR_UNKNOWN_ERROR; - } + array = g_ptr_array_new (); - buffer [len] = 0; - *exe_file = g_strdup (buffer); + pos = 0; + while (pos < len) { + g_ptr_array_add (array, cmdline + pos); + pos += strlen (cmdline + pos) + 1; + } - len = readlink (cwd_filename, buffer, BUFSIZ); - if (len < 0) { - g_free (cwd_filename); - g_free (exe_filename); - g_free (cmdline_filename); - g_warning (G_STRLOC ": Can't get cwd of %d", handle->inferior->pid); - return COMMAND_ERROR_UNKNOWN_ERROR; - } + *nargs = array->len; + *cmdline_args = ptr = g_new0 (gchar *, array->len + 1); - buffer [len] = 0; - *cwd = g_strdup (buffer); + for (i = 0; i < array->len; i++) + ptr [i] = g_ptr_array_index (array, i); - if (!g_file_get_contents (cmdline_filename, &cmdline, &len, NULL)) { g_free (cwd_filename); g_free (exe_filename); g_free (cmdline_filename); - g_warning (G_STRLOC ": Can't get cmdline args of %d", handle->inferior->pid); - return COMMAND_ERROR_UNKNOWN_ERROR; - } - - array = g_ptr_array_new (); - - pos = 0; - while (pos < len) { - g_ptr_array_add (array, cmdline + pos); - pos += strlen (cmdline + pos) + 1; + g_ptr_array_free (array, FALSE); + return COMMAND_ERROR_NONE; } - - *nargs = array->len; - *cmdline_args = ptr = g_new0 (gchar *, array->len + 1); - - for (i = 0; i < array->len; i++) - ptr [i] = g_ptr_array_index (array, i); - - g_free (cwd_filename); - g_free (exe_filename); - g_free (cmdline_filename); - g_ptr_array_free (array, FALSE); - return COMMAND_ERROR_NONE; } +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_detach_after_fork (ServerHandle *handle) { + INFO; + GPtrArray *breakpoints; guint32 status; int i; @@ -476,8 +870,30 @@ mono_debugger_breakpoint_manager_unlock (); - if (ptrace (PT_DETACH, handle->inferior->pid, NULL, NULL) != 0) - return _server_ptrace_check_errno (handle->inferior); + if (remote_debug_flag) + { + int *result; + u_int arg; - return COMMAND_ERROR_NONE; + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = detach_after_fork_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "detach_after_fork_1() call failed"); + } + + return *result; + } + else + { + if (ptrace (PT_DETACH, handle->inferior->pid, NULL, NULL) != 0) + return _server_ptrace_check_errno (handle->inferior); + + return COMMAND_ERROR_NONE; + } } diff -Naur MDB-v0.60-r91325/backend/server/x86-ptrace.c MDB-v0.60-r91325-RemoteDebug/backend/server/x86-ptrace.c --- MDB-v0.60-r91325/backend/server/x86-ptrace.c 2007-12-08 16:46:59.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/server/x86-ptrace.c 2008-03-10 15:45:28.000000000 +0100 @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,6 +25,8 @@ #include #include +#include // for remote debugging + /* * NOTE: The manpage is wrong about the POKE_* commands - the last argument * is the data (a word) to be written, not a pointer to it. @@ -63,6 +65,11 @@ ChildOutputFunc stdout_handler, stderr_handler; } IOThreadData; + +/* contains stuff for remote debugging */ +#include + + MonoRuntimeInfo * mono_debugger_server_initialize_mono_runtime (guint32 address_size, guint64 notification_address, @@ -105,129 +112,378 @@ g_free (handle); } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_continue (ServerHandle *handle) { - InferiorHandle *inferior = handle->inferior; + INFO; - errno = 0; - if (ptrace (PT_CONTINUE, inferior->pid, (caddr_t) 1, inferior->last_signal)) { - return _server_ptrace_check_errno (inferior); - } + if (remote_debug_flag) + { + int *result; + struct continue_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = handle->inferior->pid; + arg.last_signal = handle->inferior->last_signal; + + result = continue_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "continue_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + /* inferior continued -> also continue input forwarder */ + continue_input_forwarder(); - return COMMAND_ERROR_NONE; + return *result; + } + else + { + InferiorHandle *inferior = handle->inferior; + + errno = 0; + if (ptrace (PT_CONTINUE, inferior->pid, (caddr_t) 1, inferior->last_signal)) { + return _server_ptrace_check_errno (inferior); + } + + return COMMAND_ERROR_NONE; + } } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_step (ServerHandle *handle) { - InferiorHandle *inferior = handle->inferior; + INFO; - errno = 0; - if (ptrace (PT_STEP, inferior->pid, (caddr_t) 1, inferior->last_signal)) - return _server_ptrace_check_errno (inferior); + if (remote_debug_flag) + { + int *result; + struct step_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = handle->inferior->pid; + arg.last_signal = handle->inferior->last_signal; + + result = step_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "step_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + /* inferior continued -> also continue input forwarder */ + continue_input_forwarder(); - return COMMAND_ERROR_NONE; + return *result; + } + else + { + InferiorHandle *inferior = handle->inferior; + + errno = 0; + if (ptrace (PT_STEP, inferior->pid, (caddr_t) 1, inferior->last_signal)) + return _server_ptrace_check_errno (inferior); + + return COMMAND_ERROR_NONE; + } } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_detach (ServerHandle *handle) { - InferiorHandle *inferior = handle->inferior; + INFO; - if (ptrace (PT_DETACH, inferior->pid, NULL, 0)) { - g_message (G_STRLOC ": %d - %s", inferior->pid, g_strerror (errno)); - return COMMAND_ERROR_UNKNOWN_ERROR; + if (remote_debug_flag) + { + int *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = detach_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "detach_1() call failed"); + } + + return *result; } + else + { - return COMMAND_ERROR_NONE; + InferiorHandle *inferior = handle->inferior; + + if (ptrace (PT_DETACH, inferior->pid, NULL, 0)) { + g_message (G_STRLOC ": %d - %s", inferior->pid, g_strerror (errno)); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return COMMAND_ERROR_NONE; + } } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_kill (ServerHandle *handle) { - if (ptrace (PTRACE_KILL, handle->inferior->pid, NULL, 0)) - return COMMAND_ERROR_UNKNOWN_ERROR; + INFO; - return COMMAND_ERROR_NONE; + if (remote_debug_flag) + { + int *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = handle->inferior->pid; + + result = kill_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "kill_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return *result; + } + + else + + { + + if (ptrace (PTRACE_KILL, handle->inferior->pid, NULL, 0)) + return COMMAND_ERROR_UNKNOWN_ERROR; + + return COMMAND_ERROR_NONE; + + } } + static ServerCommandError server_ptrace_peek_word (ServerHandle *handle, guint64 start, guint64 *retval) { return server_ptrace_read_memory (handle, start, sizeof (gsize), retval); } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_write_memory (ServerHandle *handle, guint64 start, guint32 size, gconstpointer buffer) { - InferiorHandle *inferior = handle->inferior; - ServerCommandError result; - const long *ptr = buffer; - guint64 addr = start; - char temp [8]; - - while (size >= sizeof (long)) { - long word = *ptr++; + INFO; - errno = 0; - if (ptrace (PT_WRITE_D, inferior->pid, GSIZE_TO_POINTER (addr), word) != 0) - return _server_ptrace_check_errno (inferior); + if (remote_debug_flag) + { + int *result; + struct write_memory_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = handle->inferior->pid; + arg.start[0] = start; + arg.start[1] = (start >> 32); + arg.size = size; + arg.buffer.buffer_val = calloc(size,1); + memcpy(arg.buffer.buffer_val,buffer,size); /* copy the buffer to be sure nothing gets written to it + (since it is const) */ + arg.buffer.buffer_len = size; + arg.mem_fd = handle->inferior->mem_fd; + + result = write_memory_1(&arg, clnt); + rpc_put_client(); + free(arg.buffer.buffer_val); + if (result == (int *) NULL) { + clnt_perror (clnt, "write_memory_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return *result; - addr += sizeof (long); - size -= sizeof (long); } + else + { - if (!size) - return COMMAND_ERROR_NONE; - - result = _server_ptrace_read_memory (handle, addr, sizeof (long), &temp); - if (result != COMMAND_ERROR_NONE) - return result; - - memcpy (&temp, ptr, size); - - return server_ptrace_write_memory (handle, addr, sizeof (long), &temp); + InferiorHandle *inferior = handle->inferior; + ServerCommandError result; + const long *ptr = buffer; + guint64 addr = start; + char temp [8]; + + while (size >= sizeof (long)) { + long word = *ptr++; + + errno = 0; + if (ptrace (PT_WRITE_D, inferior->pid, GSIZE_TO_POINTER (addr), word) != 0) + return _server_ptrace_check_errno (inferior); + + addr += sizeof (long); + size -= sizeof (long); + } + + if (!size) + return COMMAND_ERROR_NONE; + + result = _server_ptrace_read_memory (handle, addr, sizeof (long), &temp); + if (result != COMMAND_ERROR_NONE) + return result; + + memcpy (&temp, ptr, size); + + return server_ptrace_write_memory (handle, addr, sizeof (long), &temp); + + } } static ServerCommandError server_ptrace_poke_word (ServerHandle *handle, guint64 addr, gsize value) { - errno = 0; - if (ptrace (PT_WRITE_D, handle->inferior->pid, GSIZE_TO_POINTER (addr), value) != 0) - return _server_ptrace_check_errno (handle->inferior); + INFO; - return COMMAND_ERROR_NONE; + if (remote_debug_flag) + { + int *result; + struct poke_word_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = handle->inferior->pid; + arg.addr[0] = addr; + arg.addr[1] = (addr >> 32); + arg.value = value; + + result = poke_word_1(&arg, clnt); + rpc_put_client(); + if (result == (int *) NULL) { + clnt_perror (clnt, "poke_word_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + return *result; + } + else + { + errno = 0; + if (ptrace (PT_WRITE_D, handle->inferior->pid, GSIZE_TO_POINTER (addr), value) != 0) + return _server_ptrace_check_errno (handle->inferior); + + return COMMAND_ERROR_NONE; + } } +/// This function makes an RPC call if remote debugging is enabled static ServerStatusMessageType server_ptrace_dispatch_event (ServerHandle *handle, guint32 status, guint64 *arg, guint64 *data1, guint64 *data2, guint32 *opt_data_size, gpointer *opt_data) { + INFO; + if (status >> 16) { switch (status >> 16) { case PTRACE_EVENT_CLONE: { int new_pid; - - if (ptrace (PTRACE_GETEVENTMSG, handle->inferior->pid, 0, &new_pid)) { - g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, - g_strerror (errno)); - return FALSE; + + if (remote_debug_flag) + { + /* RPC */ + struct ptrace_geteventmessage_struct_out *result; + int rpcarg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + rpcarg = handle->inferior->pid; + + result = ptrace_geteventmessage_1(&rpcarg, clnt); + rpc_put_client(); + if (result == (struct ptrace_geteventmessage_struct_out *) NULL) { + clnt_perror (clnt, "ptrace_geteventmessage_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + new_pid = result->new_pid; + if (result->retval) // ptrace retval + { + g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, g_strerror (errno)); + return FALSE; + } + } + else + { + if (ptrace (PTRACE_GETEVENTMSG, handle->inferior->pid, 0, &new_pid)) { + g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, + g_strerror (errno)); + return FALSE; + } } *arg = new_pid; return MESSAGE_CHILD_CREATED_THREAD; } - + case PTRACE_EVENT_FORK: { int new_pid; - if (ptrace (PTRACE_GETEVENTMSG, handle->inferior->pid, 0, &new_pid)) { - g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, - g_strerror (errno)); - return FALSE; + if (remote_debug_flag) + { + /* RPC */ + struct ptrace_geteventmessage_struct_out *result; + int rpcarg; + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + rpcarg = handle->inferior->pid; + + result = ptrace_geteventmessage_1(&rpcarg, clnt); + rpc_put_client(); + if (result == (struct ptrace_geteventmessage_struct_out *) NULL) { + clnt_perror (clnt, "ptrace_geteventmessage_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + new_pid = result->new_pid; + if (result->retval) // ptrace retval + { + g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, + g_strerror (errno)); + return FALSE; + } + } + else + { + if (ptrace (PTRACE_GETEVENTMSG, handle->inferior->pid, 0, &new_pid)) { + g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, + g_strerror (errno)); + return FALSE; + } } *arg = new_pid; @@ -240,10 +496,40 @@ case PTRACE_EVENT_EXIT: { int exitcode; - if (ptrace (PTRACE_GETEVENTMSG, handle->inferior->pid, 0, &exitcode)) { - g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, - g_strerror (errno)); - return FALSE; + if (remote_debug_flag) + { + /* RPC */ + struct ptrace_geteventmessage_struct_out *result; + int rpcarg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + rpcarg = handle->inferior->pid; + + result = ptrace_geteventmessage_1(&rpcarg, clnt); + rpc_put_client(); + if (result == (struct ptrace_geteventmessage_struct_out *) NULL) { + clnt_perror (clnt, "ptrace_geteventmessage_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + exitcode = result->new_pid; + if (result->retval) // ptrace retval + { + g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, + g_strerror (errno)); + return FALSE; + } + } + else + { + if (ptrace (PTRACE_GETEVENTMSG, handle->inferior->pid, 0, &exitcode)) { + g_warning (G_STRLOC ": %d - %s", handle->inferior->pid, + g_strerror (errno)); + return FALSE; + } } *arg = 0; @@ -262,6 +548,9 @@ ChildStoppedAction action; int stopsig; + if (remote_debug_flag) + stop_input_forwarder(); + stopsig = WSTOPSIG (status); if (!handle->inferior->is_initialized) { @@ -318,6 +607,10 @@ g_assert_not_reached (); } else if (WIFEXITED (status)) { *arg = WEXITSTATUS (status); + + if (remote_debug_flag) + kill_input_forwarder(); + return MESSAGE_CHILD_EXITED; } else if (WIFSIGNALED (status)) { if ((WTERMSIG (status) == SIGTRAP) || (WTERMSIG (status) == SIGKILL)) { @@ -345,179 +638,482 @@ return handle; } + +/* The function is always executed on target while remote debugging */ static void child_setup_func (InferiorHandle *inferior) { + g_assert(!remote_debug_flag); + if (ptrace (PT_TRACE_ME, getpid (), NULL, 0)) g_error (G_STRLOC ": Can't PT_TRACEME: %s", g_strerror (errno)); - dup2 (inferior->output_fd[1], 1); - dup2 (inferior->error_fd[1], 2); + dup2 (inferior->output_fd[1], 1); /* make stdout print to pipe */ + dup2 (inferior->error_fd[1], 2); /* make stderr print to pipe */ } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_spawn (ServerHandle *handle, const gchar *working_directory, const gchar **argv, const gchar **envp, gint *child_pid, ChildOutputFunc stdout_handler, ChildOutputFunc stderr_handler, gchar **error) { - InferiorHandle *inferior = handle->inferior; - IOThreadData *io_data = g_new0 (IOThreadData, 1); - int fd[2], open_max, ret, len, i; - ServerCommandError result; - - *error = NULL; - - pipe (fd); - - pipe (inferior->output_fd); - pipe (inferior->error_fd); + INFO; - io_data->output_fd = inferior->output_fd[0]; - io_data->error_fd = inferior->error_fd[0]; + if (remote_debug_flag) + { + struct spawn_struct_out *result; + struct spawn_struct_in arg; + IOThreadData *io_data = g_new0 (IOThreadData, 1); + struct sockaddr_in stdout_addr, stderr_addr; + + /* create two listening sockets for stdout and stderr data from inferior*/ + stdoutsock = socket(AF_INET, SOCK_STREAM, 0); + stderrsock = socket(AF_INET, SOCK_STREAM, 0); + bzero((char *) &stdout_addr, sizeof(stdout_addr)); + bzero((char *) &stderr_addr, sizeof(stderr_addr)); + stdout_addr.sin_family = stderr_addr.sin_family = AF_INET; + stdout_addr.sin_addr.s_addr = stderr_addr.sin_addr.s_addr = INADDR_ANY; + + uint16_t port = PORT_OUTPUT; + while (port < PORT_OUTPUT + MAX_PORTS - 1) + { + stdout_addr.sin_port = htons(port); + if (bind(stdoutsock, (struct sockaddr *) &stdout_addr, sizeof(stdout_addr)) == -1) + { + port += 3; /* the third socket is needed to send stdin data */ + continue; + } + else + break; + } + if (port >= PORT_OUTPUT + MAX_PORTS) + g_warning("Could not bind socket for inferior stdout data (tried ports %d to %d), %s", + PORT_OUTPUT, + PORT_OUTPUT+MAX_PORTS-3, + "inferior I/O will not be available."); + else + { + stderr_addr.sin_port = htons(port + 1); + if (bind(stderrsock, (struct sockaddr *) &stderr_addr, sizeof(stderr_addr)) == -1) + g_message(G_STRLOC ": Could not bind socket for inferior stderr data"); + if (listen(stdoutsock, 1) == -1) + g_message(G_STRLOC ": Could not set socket for inferior stdout data in listening mode"); + if (listen(stderrsock, 1) == -1) + g_message(G_STRLOC ": Could not set socket for inferior stderr data in listening mode"); + + io_data->stdout_handler = stdout_handler; /* ChildOutputFunc - implemented in C# code */ + io_data->stderr_handler = stderr_handler; /* same */ + + /* we do not set io_data->[output|error]_fd here, because we must first accept() the TCP + connections (which gives us the real socket descriptors) and this is done in an own thread */ + + /* creates mono thread that handles stdout and stderr + io_thread() is the function, io_data it's parameter */ + mono_thread_create (mono_domain_get (), io_thread, io_data); + + /* forks a new process that transfers stdin data to the inferior */ + start_input_forwarder(port+2); + waitpid(input_forwarder_pid,NULL,WUNTRACED); + continue_input_forwarder(); + } - io_data->stdout_handler = stdout_handler; - io_data->stderr_handler = stderr_handler; + /* rpc stuff */ + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + /* modify argv[] for target */ + unsigned int count=0; + while (argv[count] != 0) + count++; // count = number of strings in argv array + const gchar **argv_copy; + argv_copy = calloc(sizeof(gchar*) * (count + 1), 1); + int i=0; + for (i=0; i set to beginning of string + else + argvptr++; // increment to point to char after '/' + ptr = target_exe; + if (strlen(target_exe) >= strlen(argvptr)) + ptr += (strlen(target_exe) - strlen(argvptr)); + /* points to same segment at end of target exe path */ + + if (strcmp(argvptr,ptr) == 0) + { + argv_copy[i] = target_exe; // replace by changing pointer + break; + } + i++; + } + } - *child_pid = fork (); - if (*child_pid == 0) { - gchar *error_message; - struct rlimit core_limit; + /* copy argv string array into rpc argument */ + i=0; + unsigned int length=0; + for (i=0;iinferior->output_fd[0] = stdoutsock; + handle->inferior->error_fd[0] = stderrsock; + + if (result->servercommanderror != COMMAND_ERROR_NONE) + return result->servercommanderror; + + handle->inferior->output_fd[1] = result->output_fd1; /* just store them on host; they're not used */ + handle->inferior->error_fd[1] = result->error_fd1; + handle->inferior->pid = result->pid; + *child_pid = result->pid; + handle->inferior->mem_fd = result->mem_fd; + if (result->error.error_len > 0) { + *error = calloc(result->error.error_len + 1, 1); + memcpy (*error, result->error.error_val, result->error.error_len); + } + + return result->servercommanderror; - getrlimit (RLIMIT_CORE, &core_limit); - core_limit.rlim_cur = 0; - setrlimit (RLIMIT_CORE, &core_limit); + } - child_setup_func (inferior); - execve (argv [0], (char **) argv, (char **) envp); + else - error_message = g_strdup_printf ("Cannot exec `%s': %s", argv [0], g_strerror (errno)); - len = strlen (error_message) + 1; - write (fd [1], &len, sizeof (len)); - write (fd [1], error_message, len); - _exit (1); + { + InferiorHandle *inferior = handle->inferior; + IOThreadData *io_data = g_new0 (IOThreadData, 1); + int fd[2], open_max, ret, len, i; + ServerCommandError result; + + *error = NULL; + + pipe (fd); + + pipe (inferior->output_fd); + pipe (inferior->error_fd); + + io_data->output_fd = inferior->output_fd[0]; + io_data->error_fd = inferior->error_fd[0]; + + io_data->stdout_handler = stdout_handler; + io_data->stderr_handler = stderr_handler; + *child_pid = fork (); + if (*child_pid == 0) { + gchar *error_message; + struct rlimit core_limit; + + open_max = sysconf (_SC_OPEN_MAX); + for (i = 3; i < open_max; i++) + fcntl (i, F_SETFD, FD_CLOEXEC); + + setsid (); + + getrlimit (RLIMIT_CORE, &core_limit); + core_limit.rlim_cur = 0; + setrlimit (RLIMIT_CORE, &core_limit); + + child_setup_func (inferior); + execve (argv [0], (char **) argv, (char **) envp); + + error_message = g_strdup_printf ("Cannot exec `%s': %s", argv [0], g_strerror (errno)); + len = strlen (error_message) + 1; + write (fd [1], &len, sizeof (len)); + write (fd [1], error_message, len); + _exit (1); + } + + close (inferior->output_fd[1]); + close (inferior->error_fd[1]); + close (fd [1]); + + ret = read (fd [0], &len, sizeof (len)); + + if (ret != 0) { + g_assert (ret == 4); + + *error = g_malloc0 (len); + read (fd [0], *error, len); + close (fd [0]); + close (inferior->output_fd[0]); + close (inferior->error_fd[0]); + return COMMAND_ERROR_CANNOT_START_TARGET; + } + + inferior->pid = *child_pid; + + result = _server_ptrace_setup_inferior (handle); + if (result != COMMAND_ERROR_NONE) + return result; + + mono_thread_create (mono_domain_get (), io_thread, io_data); + + return COMMAND_ERROR_NONE; } +} - close (inferior->output_fd[1]); - close (inferior->error_fd[1]); - close (fd [1]); - ret = read (fd [0], &len, sizeof (len)); +/// This function makes an RPC call if remote debugging is enabled +static ServerCommandError +server_ptrace_initialize_thread (ServerHandle *handle, guint32 pid) +{ + INFO; - if (ret != 0) { - g_assert (ret == 4); + if (remote_debug_flag) + { + struct initialize_thread_struct_out *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = pid; + + result = initialize_thread_1(&arg, clnt); + rpc_put_client(); + if (result == (struct initialize_thread_struct_out *) NULL) { + clnt_perror (clnt, "initialize_thread_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + handle->inferior->mem_fd = result->mem_fd; + handle->inferior->pid = result->pid; + handle->inferior->is_thread = result->is_thread; + + return result->servercommanderror; - *error = g_malloc0 (len); - read (fd [0], *error, len); - close (fd [0]); - close (inferior->output_fd[0]); - close (inferior->error_fd[0]); - return COMMAND_ERROR_CANNOT_START_TARGET; } - inferior->pid = *child_pid; + else - result = _server_ptrace_setup_inferior (handle); - if (result != COMMAND_ERROR_NONE) - return result; + { - mono_thread_create (mono_domain_get (), io_thread, io_data); + InferiorHandle *inferior = handle->inferior; + + inferior->pid = pid; + inferior->is_thread = TRUE; + + return _server_ptrace_setup_inferior (handle); - return COMMAND_ERROR_NONE; + } } -static ServerCommandError -server_ptrace_initialize_thread (ServerHandle *handle, guint32 pid) -{ - InferiorHandle *inferior = handle->inferior; - - inferior->pid = pid; - inferior->is_thread = TRUE; - - return _server_ptrace_setup_inferior (handle); -} +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_attach (ServerHandle *handle, guint32 pid) { - InferiorHandle *inferior = handle->inferior; + INFO; - if (ptrace (PT_ATTACH, pid, NULL, 0) != 0) { - g_warning (G_STRLOC ": Can't attach to %d - %s", pid, - g_strerror (errno)); - return COMMAND_ERROR_CANNOT_START_TARGET; + if (remote_debug_flag) + { + struct attach_struct_out *result; + u_int arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg = pid; + + result = attach_1(&arg, clnt); + rpc_put_client(); + if (result == (struct attach_struct_out *) NULL) { + clnt_perror (clnt, "attach_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + + handle->inferior->pid = result->pid; + handle->inferior->mem_fd = result->mem_fd; + handle->inferior->is_thread = result->is_thread; + + return result->servercommanderror; } + else + { - inferior->pid = pid; - inferior->is_thread = TRUE; - - return _server_ptrace_setup_inferior (handle); + InferiorHandle *inferior = handle->inferior; + + if (ptrace (PT_ATTACH, pid, NULL, 0) != 0) { + g_warning (G_STRLOC ": Can't attach to %d - %s", pid, + g_strerror (errno)); + return COMMAND_ERROR_CANNOT_START_TARGET; + } + + inferior->pid = pid; + inferior->is_thread = TRUE; + + return _server_ptrace_setup_inferior (handle); + } } + static void process_output (int fd, ChildOutputFunc func) { char buffer [BUFSIZ + 1]; int count; - + count = read (fd, buffer, BUFSIZ); if (count < 0) return; - + buffer [count] = 0; - func (buffer); + func (buffer); /* call the ChildOutputFunc with the received string */ } + static guint32 io_thread (gpointer data) { IOThreadData *io_data = (IOThreadData*)data; + + if (remote_debug_flag) + { + int sock_stdout, sock_stderr; + + sock_stdout = accept(stdoutsock,NULL,NULL); + close(stdoutsock); + stdoutsock = sock_stdout; /* to be able to store it in inferior handle */ + io_data->output_fd = sock_stdout; + + sock_stderr = accept(stderrsock,NULL,NULL); + close(stderrsock); + stderrsock = sock_stderr; /* to be able to store it in inferior handle */ + io_data->error_fd = sock_stderr; + } + struct pollfd fds [2]; int ret; - fds [0].fd = io_data->output_fd; - fds [0].events = POLLIN | POLLHUP | POLLERR; - fds [0].revents = 0; + if (remote_debug_flag) + { + fds [0].events = POLLIN | POLLHUP | POLLERR | POLLRDHUP; + /* data to read | hang up | error condition | stream socket peer closed connection */ + fds [1].events = POLLIN | POLLHUP | POLLERR | POLLRDHUP; + } + else + { + fds [0].events = POLLIN | POLLHUP | POLLERR; /* data to read | hang up | error condition */ + fds [1].events = POLLIN | POLLHUP | POLLERR; + } + fds [0].fd = io_data->output_fd; /* file descriptor */ fds [1].fd = io_data->error_fd; - fds [1].events = POLLIN | POLLHUP | POLLERR; + fds [0].revents = 0; /* returned events */ fds [1].revents = 0; while (1) { - ret = poll (fds, 2, -1); + ret = poll (fds, 2, -1); /* array with 2 pollfd element; timeout -1 */ - if ((ret < 0) && (errno != EINTR)) + if ((ret < 0) && (errno != EINTR)) /* signal occured */ break; if (fds [0].revents & POLLIN) - process_output (io_data->output_fd, io_data->stdout_handler); - if (fds [1].revents & POLLIN) + process_output (io_data->output_fd, io_data->stdout_handler); /* effectively reads and calls + a ChildOutputFunc function */ + if (fds [1].revents & POLLIN) /* same */ process_output (io_data->error_fd, io_data->stderr_handler); - if ((fds [0].revents & (POLLHUP | POLLERR)) - || (fds [1].revents & (POLLHUP | POLLERR))) - break; + if (remote_debug_flag) + { + if ((fds [0].revents & (POLLHUP | POLLERR | POLLRDHUP)) || (fds [1].revents & (POLLHUP | POLLERR | POLLRDHUP))) + break; + } + else + { + if ((fds [0].revents & (POLLHUP | POLLERR)) || (fds [1].revents & (POLLHUP | POLLERR))) + break; + } } + if (mono_debugger_server_get_remote_debug() == 1) + { + close(io_data->output_fd); /* close TCP connections */ + close(io_data->error_fd); + } g_free (io_data); return 0; } + +/// This function makes an RPC call if remote debugging is enabled static ServerCommandError server_ptrace_set_signal (ServerHandle *handle, guint32 sig, guint32 send_it) { + INFO; + if (send_it) - kill (handle->inferior->pid, sig); + { + if (remote_debug_flag) + { + void *result; + struct do_kill_struct_in arg; + + CLIENT *clnt; + if ((clnt = rpc_get_client()) == NULL) + return COMMAND_ERROR_UNKNOWN_ERROR; + + arg.pid = handle->inferior->pid; + arg.sig = sig; + + result = do_kill_1(&arg, clnt); + rpc_put_client(); + if (result == (void *) NULL) { + clnt_perror (clnt, "do_kill_1() call failed"); + return COMMAND_ERROR_UNKNOWN_ERROR; + } + } + else + { + kill (handle->inferior->pid, sig); + } + } else handle->inferior->last_signal = sig; + return COMMAND_ERROR_NONE; } + static void server_ptrace_set_runtime_info (ServerHandle *handle, MonoRuntimeInfo *mono_runtime) { @@ -527,6 +1123,15 @@ extern void GC_start_blocking (void); extern void GC_end_blocking (void); +/* include this before x86-linux-ptrace.c because we need to have "struct ArchInfo" defined already */ +#if defined(__i386__) +#include "i386-arch.c" +#elif defined(__x86_64__) +#include "x86_64-arch.c" +#else +#error "Unknown architecture" +#endif + #ifdef __linux__ #include "x86-linux-ptrace.c" #endif @@ -535,13 +1140,13 @@ #include "x86-freebsd-ptrace.c" #endif -#if defined(__i386__) -#include "i386-arch.c" -#elif defined(__x86_64__) -#include "x86_64-arch.c" -#else -#error "Unknown architecture" -#endif +/* #if defined(__i386__) */ +/* #include "i386-arch.c" */ +/* #elif defined(__x86_64__) */ +/* #include "x86_64-arch.c" */ +/* #else */ +/* #error "Unknown architecture" */ +/* #endif */ InferiorVTable i386_ptrace_inferior = { server_ptrace_global_init, diff -Naur MDB-v0.60-r91325/backend/ThreadDB.cs MDB-v0.60-r91325-RemoteDebug/backend/ThreadDB.cs --- MDB-v0.60-r91325/backend/ThreadDB.cs 2007-12-08 00:47:54.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/backend/ThreadDB.cs 2008-03-03 17:25:16.000000000 +0100 @@ -31,14 +31,23 @@ static extern IntPtr mono_debugger_thread_db_init (GlobalLookupFunc lookup_func, ReadMemoryFunc read_memory_func, WriteMemoryFunc write_memory_func); [DllImport("monodebuggerserver")] + static extern IntPtr mono_debugger_thread_db_init_remote (IntPtr serverhandle, string[] symNames, long[] symAddrs, int symCount); + + [DllImport("monodebuggerserver")] static extern void mono_debugger_thread_db_destroy (IntPtr handle); [DllImport("monodebuggerserver")] static extern bool mono_debugger_thread_db_iterate_over_threads (IntPtr handle, IterateOverThreadsFunc func); [DllImport("monodebuggerserver")] + static extern bool mono_debugger_thread_db_iterate_over_threads_remote (IntPtr handle, IntPtr serverhandle, string[] symNames, long[] symAddrs, int symCount, out IntPtr lwp, out IntPtr tid, out int threadCount); + + [DllImport("monodebuggerserver")] static extern bool mono_debugger_thread_db_get_thread_info (IntPtr th, out long tid, out long tls, out long lwp); + [DllImport("monodebuggerserver")] + static extern int mono_debugger_server_get_remote_debug (); + GlobalLookupFunc global_lookup_func; ReadMemoryFunc read_memory_func; WriteMemoryFunc write_memory_func; @@ -59,9 +68,20 @@ try { mutex.Lock (); this.target = target; - - handle = mono_debugger_thread_db_init ( - global_lookup_func, read_memory_func, write_memory_func); + + if (mono_debugger_server_get_remote_debug() == 1) { + string[] symNames = null; + long[] symAddrs = null; + int symCount = 0; + Bfd bfd = process.BfdContainer.FindLibrary ("libpthread.so.0"); + if (bfd != null) + symCount = bfd.GetLocalSymbols (out symNames, out symAddrs); + handle = mono_debugger_thread_db_init_remote(((Inferior)target).ServerHandle, + symNames, symAddrs, symCount); + } else { + handle = mono_debugger_thread_db_init ( + global_lookup_func, read_memory_func, write_memory_func); + } return handle != IntPtr.Zero; } finally { this.target = null; @@ -78,6 +98,8 @@ return db; } + /* This function is never called! */ + /* bool get_thread_info (IntPtr th) { long tid, tls, lwp; @@ -86,25 +108,51 @@ return true; } + */ public void GetThreadInfo (TargetMemoryAccess target, GetThreadInfoFunc func) { try { - mutex.Lock (); + mutex.Lock(); this.target = target; - mono_debugger_thread_db_iterate_over_threads ( - handle, delegate (IntPtr th) { - long tid, tls, lwp; - if (!mono_debugger_thread_db_get_thread_info ( - th, out tid, out tls, out lwp)) - return false; - - func ((int) lwp, tid); - return true; - }); + + if (mono_debugger_server_get_remote_debug() == 1) + { + string[] symNames = null; + long[] symAddrs = null; + int symCount = 0; + Bfd bfd = process.BfdContainer.FindLibrary ("libpthread.so.0"); + if (bfd != null) + symCount = bfd.GetLocalSymbols (out symNames, out symAddrs); + IntPtr lwp = IntPtr.Zero; + IntPtr tid = IntPtr.Zero; + int threadCount = 0; + mono_debugger_thread_db_iterate_over_threads_remote ( + handle, ((Inferior)target).ServerHandle, symNames, symAddrs, + symCount, out lwp, out tid, out threadCount); + long[] managedLwp = new long[threadCount]; + long[] managedTid = new long[threadCount]; + Marshal.Copy(lwp,managedLwp,0,threadCount); + Marshal.Copy(tid,managedTid,0,threadCount); + for(int i=0; i + /// For remote debugging: In this destructor, the last RPC call is made so that + /// mdbserver also quits when MDB quits. + /// + ~CommandLineInterpreter() + { + mdbserver_quit(); + } + public CommandLineInterpreter (Interpreter interpreter) { this.interpreter = interpreter; this.engine = interpreter.DebuggerEngine; parser = new LineParser (engine); - + main_thread = new ST.Thread (new ST.ThreadStart (main_thread_main)); main_thread.IsBackground = true; - + command_thread = new ST.Thread (new ST.ThreadStart (command_thread_main)); command_thread.IsBackground = true; } - + public void MainLoop () { string s; @@ -99,7 +118,7 @@ protected void RunMainLoop () { is_inferior_main = false; - + command_thread.Start (); try { @@ -118,37 +137,37 @@ interpreter.Exit (); } } - + public void RunInferiorMainLoop () { is_inferior_main = true; - + command_thread.Start (); - + TextReader old_stdin = Console.In; TextWriter old_stdout = Console.Out; TextWriter old_stderr = Console.Error; - + StreamReader stdin_reader = new StreamReader (Console.OpenStandardInput ()); - + StreamWriter stdout_writer = new StreamWriter (Console.OpenStandardOutput ()); stdout_writer.AutoFlush = true; - + StreamWriter stderr_writer = new StreamWriter (Console.OpenStandardError ()); stderr_writer.AutoFlush = true; - + Console.SetIn (stdin_reader); Console.SetOut (stdout_writer); Console.SetError (stderr_writer); - + bool old_is_script = interpreter.IsScript; bool old_is_interactive = interpreter.IsInteractive; - + interpreter.IsScript = false; interpreter.IsInteractive = true; - + Console.WriteLine (); - + try { main_thread.Start (); main_thread.Join (); @@ -160,17 +179,17 @@ interpreter.Error ("ERROR: {0}", ex); } finally { Console.WriteLine (); - + Console.SetIn (old_stdin); Console.SetOut (old_stdout); Console.SetError (old_stderr); interpreter.IsScript = old_is_script; interpreter.IsInteractive = old_is_interactive; } - + command_thread.Abort (); } - + public string ReadInput (bool is_complete) { ++line; @@ -240,6 +259,30 @@ DebuggerOptions options = DebuggerOptions.ParseCommandLine (args); + switch (mono_debugger_server_set_debug_opts (options.HasRemote, options.RemoteTarget, + options.File, options.RemoteExe, + Environment.GetCommandLineArgs()[0], + options.MonoPath)) + { + case 0: + /* no error */ + break; + case 1: + /* no valid IP address given */ + Console.WriteLine("Error: No valid IP address given!\n"); + return; + break; + case 2: + /* could not connect to mdbserver */ + Console.WriteLine("Error: Could not connect to MDBSERVER on target.\n"); + return; + break; + + default: + Debug.Assert(false); + break; + } + Console.WriteLine ("Mono Debugger"); CommandLineInterpreter interpreter = new CommandLineInterpreter ( diff -Naur MDB-v0.60-r91325/languages/mono/MonoSymbolFile.cs MDB-v0.60-r91325-RemoteDebug/languages/mono/MonoSymbolFile.cs --- MDB-v0.60-r91325/languages/mono/MonoSymbolFile.cs 2007-11-28 14:03:17.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/languages/mono/MonoSymbolFile.cs 2008-03-03 17:25:16.000000000 +0100 @@ -2,6 +2,7 @@ using System.Collections; using System.Globalization; using System.Text; +using System.Runtime.InteropServices; using C = Mono.CompilerServices.SymbolWriter; using Mono.Debugger; using Mono.Debugger.Backend; @@ -230,6 +231,9 @@ Hashtable method_index_hash; Hashtable function_hash; + [DllImport("monodebuggerserver")] + static extern string adjust_pathname(string path); + internal MonoSymbolFile (MonoLanguageBackend language, ProcessServant process, TargetMemoryAccess memory, TargetAddress address) { @@ -253,7 +257,19 @@ address += int_size; TargetAddress image_file_addr = memory.ReadAddress (address); address += address_size; - ImageFile = memory.ReadString (image_file_addr); + + /* Remote debugging: + Because the paths for mono libraries and the mono application are read out + via BFD remotely, they are different from the local installation. So we must + replace the remote paths by the local paths. The following (Cecil stuff) cannot + be executed on the target, since we have no mono there for mdbserver! + */ + // ImageFile = memory.ReadString (image_file_addr); + string ImageFileToTest = memory.ReadString(image_file_addr); + ImageFile = adjust_pathname(ImageFileToTest); + if (ImageFile == null) + ImageFile = ImageFileToTest; + MonoImage = memory.ReadAddress (address); address += address_size; TargetAddress type_table_ptr = memory.ReadAddress (address); diff -Naur MDB-v0.60-r91325/Makefile.am MDB-v0.60-r91325-RemoteDebug/Makefile.am --- MDB-v0.60-r91325/Makefile.am 2006-10-25 23:10:29.000000000 +0100 +++ MDB-v0.60-r91325-RemoteDebug/Makefile.am 2008-03-06 15:17:39.000000000 +0100 @@ -1,4 +1,4 @@ -SUBDIRS = interface languages classes backend frontend test build +SUBDIRS = interface languages classes backend frontend test build mdbserver DIST_SUBDIRS= doc $(SUBDIRS) diff -Naur MDB-v0.60-r91325/mdbserver/Makefile.am MDB-v0.60-r91325-RemoteDebug/mdbserver/Makefile.am --- MDB-v0.60-r91325/mdbserver/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ MDB-v0.60-r91325-RemoteDebug/mdbserver/Makefile.am 2008-03-06 15:17:39.000000000 +0100 @@ -0,0 +1,18 @@ +RPCDIR = rpc + +INCLUDES = @SERVER_DEPENDENCIES_CFLAGS@ + +bin_PROGRAMS = mdbserver + +mdbserver_SOURCES = \ + remotedebug_server.c \ + remotedebug_server.h \ + remotedebug_thread-db.c \ + remotedebug_thread-db.h \ + remotedebug_bfd.c \ + ${RPCDIR}/remotedebug_svc.c \ + ${RPCDIR}/remotedebug_xdr.c \ + ${RPCDIR}/remotedebug.h + +mdbserver_LDADD = \ + -lglib-2.0 -lthread_db -lgthread-2.0 diff -Naur MDB-v0.60-r91325/mdbserver/remotedebug_bfd.c MDB-v0.60-r91325-RemoteDebug/mdbserver/remotedebug_bfd.c --- MDB-v0.60-r91325/mdbserver/remotedebug_bfd.c 1970-01-01 00:00:00.000000000 +0000 +++ MDB-v0.60-r91325-RemoteDebug/mdbserver/remotedebug_bfd.c 2008-03-18 11:45:15.000000000 +0100 @@ -0,0 +1,123 @@ +/* + * Remote debugging extension for the Mono Debugger. + * Developed within the ViMEM project - visit + * http://www.streamunlimited.com/vimem for details. + * + * Copyright (C) 2008 TU Vienna, Institute of Computer Technology + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated docum