summaryrefslogtreecommitdiffstats
path: root/c/src/lib/librdbg
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/librdbg')
-rw-r--r--c/src/lib/librdbg/Makefile.in96
-rw-r--r--c/src/lib/librdbg/_servtgt.c360
-rw-r--r--c/src/lib/librdbg/awk.svc65
-rw-r--r--c/src/lib/librdbg/i386/excep.c233
-rw-r--r--c/src/lib/librdbg/i386/pc386/remdeb_f.x58
-rw-r--r--c/src/lib/librdbg/i386/rdbg_cpu_asm.s70
-rw-r--r--c/src/lib/librdbg/i386/rdbg_f.c130
-rw-r--r--c/src/lib/librdbg/ptrace.c335
-rw-r--r--c/src/lib/librdbg/rdbg.c139
-rw-r--r--c/src/lib/librdbg/remdeb.x544
-rw-r--r--c/src/lib/librdbg/servbkpt.c587
-rw-r--r--c/src/lib/librdbg/servcon.c136
-rw-r--r--c/src/lib/librdbg/servrpc.c720
-rw-r--r--c/src/lib/librdbg/servtgt.c550
-rw-r--r--c/src/lib/librdbg/servtsp.c329
-rw-r--r--c/src/lib/librdbg/servutil.c130
16 files changed, 4482 insertions, 0 deletions
diff --git a/c/src/lib/librdbg/Makefile.in b/c/src/lib/librdbg/Makefile.in
new file mode 100644
index 0000000000..8d4a72ca96
--- /dev/null
+++ b/c/src/lib/librdbg/Makefile.in
@@ -0,0 +1,96 @@
+#
+# $Id$
+#
+
+@SET_MAKE@
+srcdir = @srcdir@
+VPATH = @srcdir@:@srcdir@/$(RTEMS_CPU)
+RTEMS_ROOT = @top_srcdir@
+PROJECT_ROOT = @PROJECT_ROOT@
+
+LIBNAME=librdbg.a
+LIB=${ARCH}/${LIBNAME}
+
+# C and C++ source names, if any, go here -- minus the .c or .cc
+C_PIECES= rdbg servcon servbkpt servrpc excep \
+ servtgt servtsp servutil _servtgt rdbg_f \
+ ptrace
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+# Asm source names, if any, go here -- minus the .s
+ASM_PIECES= rdbg_cpu_asm
+ASM_FILES=$(ASM_PIECES:%=%.s)
+ASM_O_FILES=$(ASM_PIECES:%=${ARCH}/%.o)
+
+# Generated C source names, if any, go here -- minus the .c
+C_GEN_PIECES= remdeb_xdr remdeb_svc
+C_GEN_FILES=$(C_GEN_PIECES:%=%.c)
+C_GEN_O_FILES=$(C_GEN_PIECES:%=${ARCH}/%.o)
+
+# H source names, if any, go here -- minus the .h
+H_PIECES=remdeb
+H_FILES=$(H_PIECES:%=%.h)
+
+# X source names, if any, go here -- minus the .x
+X_FILE1=remdeb.x
+X_FILE2=remdeb_f.x
+X_FILES=$(X_FILE1) $(X_FILE2)
+
+SRCS=$(C_FILES) $(ASM_FILES)
+OBJS=$(X_FILES) $(H_FILES) $(C_GEN_FILES) $(C_GEN_O_FILES) $(C_O_FILES) $(ASM_O_FILES)
+
+RPCGEN=rpcgen
+AWK=awk
+
+include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
+include $(RTEMS_ROOT)/make/lib.cfg
+
+#
+# Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS += $(LIB) $(H_FILES) $(X_FILES) $(C_GEN_FILES)
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(LIB)
+ $(INSTALL_VARIANT) -m 644 $(LIB) ${PROJECT_RELEASE}/lib
+
+$(LIB): $(SRCS) ${OBJS}
+ $(make-library)
+
+remdeb.h: $(X_FILES)
+ @rm -f $@
+ $(RPCGEN) -h remdeb.x -o $@
+ @rm -f $(PROJECT_INCLUDE)/rdbg/$@
+ $(INSTALL) -m 444 $@ $(PROJECT_INCLUDE)/rdbg
+
+remdeb_xdr.c: $(X_FILES)
+ @rm -f $@
+ $(RPCGEN) -c remdeb.x -o $@
+
+remdeb_svc.c: $(X_FILES)
+ @rm -f $@ tmpSvc.c
+ $(RPCGEN) -s udp remdeb.x -o tmpSvc.c
+ $(AWK) -f @srcdir@/awk.svc THEPROG="remdeb.h" tmpSvc.c >$@
+ @rm -f tmpSvc.c
+
+preinstall:
+ @rm -f $(X_FILES)
+ @cp @srcdir@/$(X_FILE1) .
+ @cp @srcdir@/$(RTEMS_CPU)/$(RTEMS_BSP)/$(X_FILE2) .
+
+
+
+
diff --git a/c/src/lib/librdbg/_servtgt.c b/c/src/lib/librdbg/_servtgt.c
new file mode 100644
index 0000000000..184415a1e2
--- /dev/null
+++ b/c/src/lib/librdbg/_servtgt.c
@@ -0,0 +1,360 @@
+/*
+ ============================================================================
+ _SERVTGT
+ ============================================================================
+*/
+
+
+#include <string.h>
+#include <rtems.h>
+#include <rtems/error.h>
+
+#include <rdbg/rdbg.h>
+#include <rdbg/rdbg_f.h>
+#include <rdbg/servrpc.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <assert.h>
+#include <rtems/score/cpu.h>
+
+extern void rtems_exception_prologue_50();
+
+
+#ifdef DDEBUG
+#define Ptrace TgtDbgPtrace
+#else
+#define Ptrace TgtRealPtrace
+#endif
+
+extern int errno;
+
+rtems_id eventTaskId;
+rtems_id serializeSemId;
+rtems_id wakeupEventSemId;
+
+CPU_Exception_frame Idle_frame;
+
+cpuExcHandlerType old_currentExcHandler;
+
+/* -----------------------------------------------------------------
+ TgtRealPtrace - lowest level ptrace() wrapper
+ ----------------------------------------------------------------- */
+
+ int
+TgtRealPtrace(int req, PID aid, char* addr, int d, void* addr2)
+{
+ return ptrace(req, aid, addr, d, addr2);
+}
+
+
+/* -----------------------------------------------------------------
+ Maping of hardware exceptions into Unix-like signal numbers.
+ It is identical to the one used by the PM and the AM.
+ ----------------------------------------------------------------- */
+
+ int
+ExcepToSig (int excep)
+{
+ switch (excep) {
+
+ case I386_EXCEPTION_MATH_COPROC_UNAVAIL:
+ case I386_EXCEPTION_I386_COPROC_SEG_ERR:
+ case I386_EXCEPTION_FLOAT_ERROR:
+ case I386_EXCEPTION_BOUND:
+ return SIGFPE;
+
+ case I386_EXCEPTION_DEBUG:
+ case I386_EXCEPTION_BREAKPOINT:
+ case I386_EXCEPTION_ENTER_RDBG:
+ return SIGTRAP;
+
+ case I386_EXCEPTION_OVERFLOW:
+ case I386_EXCEPTION_DIVIDE_BY_ZERO:
+ case I386_EXCEPTION_ILLEGAL_INSTR:
+ return SIGILL;
+
+ case I386_EXCEPTION_SEGMENT_NOT_PRESENT:
+ case I386_EXCEPTION_STACK_SEGMENT_FAULT:
+ case I386_EXCEPTION_GENERAL_PROT_ERR:
+ case I386_EXCEPTION_PAGE_FAULT:
+ return SIGSEGV;
+
+ default:
+ break;
+ }
+ return SIGKILL;
+}
+
+/* -----------------------------------------------------------------------
+ TgtChange() is called when the system stops.
+ It informs the generic layers must be informed of
+ that fact.
+ ----------------------------------------------------------------------- */
+
+ static int
+TgtChange (PID pid, CPU_Exception_frame* ctx, int status)
+{
+
+ if (TgtHandleChildChange (pid, &status, NULL, ctx)) {
+ TgtNotifyWaitChange (pid, status, -1);
+ }
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------
+ eventTask
+ ----------------------------------------------------------------------- */
+
+rtems_task eventTask( rtems_task_argument pid)
+{
+ Exception_context *ctx;
+
+ DPRINTF (("event task: pid %d\n", pid));
+
+
+ /*
+ * we spend all our time waiting for a semaphore.
+ * If wait change, we send info
+ */
+
+ for (;;){
+ DPRINTF (("Event Task: wait event\n"));
+ rtems_semaphore_obtain(wakeupEventSemId, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ DPRINTF (("Event Task: wake up !!!!!!!!!!!!!\n"));
+
+ errno = 0;
+ ctx = GetExceptCtx(currentTargetThread);
+
+ CheckForSingleStep(ctx->ctx);
+
+ TgtChange(pid, ctx->ctx,STS_MAKESIG(ExcepToSig(ctx->ctx->idtIndex)));
+
+ }
+}
+
+/* -------------------------------------------------------------------
+ MyThreadIdle -
+
+ This task is used to initiate the exception mechanism:
+ It calls the enterDebug function with justSaveContext=1
+ only to push a first valid context in the list
+ ---------------------------------------------------------------------*/
+
+rtems_task MyThreadIdle(rtems_task_argument argument)
+{
+ enterRdbg();
+ rtems_task_delete( RTEMS_SELF );
+}
+
+/* -----------------------------------------------------------------------
+ TgtAttach - attach to a process that is running without control.
+
+ Notes:
+ - this function performs a ptrace ATTACH equivalent (attaching to a
+ process that we do not control now).
+ ----------------------------------------------------------------------- */
+
+Boolean TgtAttach(
+ int conn_idx, /* client that is requesting */
+ PID pid) /* process to attach to */
+{
+ rtems_name task_name;
+ rtems_status_code status;
+ rtems_id debugId;
+ interrupt_gate_descriptor *currentIdtEntry;
+ unsigned limit;
+ unsigned level;
+
+ errno = 0;
+
+ DPRINTF (("TgtAttach pid=%d\n",pid));
+
+ Ptrace(RPT_ATTACH, pid, NULL, 0, NULL);
+ if (errno)
+ return(False); /* failed */
+
+ TgtCreateNew(pid, conn_idx, 0, NULL, False);
+
+
+ /*
+ * Connect the Exception used to debug
+ */
+ i386_get_info_from_IDTR (&currentIdtEntry, &limit);
+
+ _CPU_ISR_Disable(level);
+ create_interrupt_gate_descriptor (&currentIdtEntry[50], rtems_exception_prologue_50);
+ _CPU_ISR_Enable(level);
+
+ old_currentExcHandler = _currentExcHandler;
+ _currentExcHandler = BreakPointExcHdl ;
+
+
+ /*
+ * Create the attach debuger task
+ */
+ task_name = rtems_build_name( 'E', 'v', 'n', 't' );
+ if ((status = rtems_task_create( task_name, 10, 24576,
+ RTEMS_INTERRUPT_LEVEL(0),
+ RTEMS_DEFAULT_ATTRIBUTES | RTEMS_SYSTEM_TASK,
+ &eventTaskId ))
+ != RTEMS_SUCCESSFUL){
+ printf("status = %d\n",status);
+ rtems_panic ("Can't create task.\n");
+ }
+
+ status = rtems_task_start(eventTaskId, eventTask, pid);
+
+ status = rtems_semaphore_create (rtems_build_name('D', 'B', 'G', 's'),
+ 1,
+ RTEMS_FIFO |
+ RTEMS_COUNTING_SEMAPHORE |
+ RTEMS_NO_INHERIT_PRIORITY |
+ RTEMS_NO_PRIORITY_CEILING |
+ RTEMS_LOCAL,
+ 0,
+ &serializeSemId);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't create serialize semaphore: `%s'\n",rtems_status_text(status));
+
+ status = rtems_semaphore_create (rtems_build_name('D', 'B', 'G', 'w'),
+ 0,
+ RTEMS_FIFO |
+ RTEMS_COUNTING_SEMAPHORE |
+ RTEMS_NO_INHERIT_PRIORITY |
+ RTEMS_NO_PRIORITY_CEILING |
+ RTEMS_LOCAL,
+ 0,
+ &wakeupEventSemId);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't create wakeup semaphore: `%s'\n",rtems_status_text(status));
+
+ /*
+ * Create the MyThreadIdle task to init Exception mechanism
+ */
+ task_name = rtems_build_name( 'R', 'i', 'n', 'i' );
+ if ((status = rtems_task_create( task_name, 10, 24576,
+ RTEMS_INTERRUPT_LEVEL(0),
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &debugId ))
+ != RTEMS_SUCCESSFUL){
+ printf("status = %d\n",status);
+ rtems_panic ("Can't create task.\n");
+ }
+
+ status = rtems_task_start(debugId, MyThreadIdle, pid);
+
+ return(True);
+}
+
+/* -----------------------------------------------------------------------
+ TgtPtrace - handle ptrace requests for server.
+ ----------------------------------------------------------------------- */
+
+int TgtPtrace(
+ int req,
+ PID pid,
+ char *addr,
+ int data,
+ void *addr2)
+{
+ if ((req == RPT_SINGLESTEP || req == RPT_CONT)
+ && addr2) /* clear then step */
+ { /* addr2 is the old value */
+ int ret;
+
+ errno = 0;
+ TgtBreakRestoreOrig (pid, addr, addr2);
+ ret = Ptrace(RPT_SINGLESTEP, pid, addr, data, NULL); /* step over */
+ if (ret) /* error, cannot single-step */
+ {
+ int pid_idx = FindPidEntry (pid);
+ TgtBreakCancelStep (&pid_list [pid_idx]);
+ }
+ return(ret); /* failed or done */
+ }
+ else
+ return(Ptrace(req, pid, addr, data, addr2)); /* normal call */
+}
+
+/* -----------------------------------------------------------------
+ TgtGetThreadName - get thread name
+ --------------------------------------------------------------- */
+
+int TgtGetThreadName (
+ PID_LIST *plst, /* Process entry */
+ unsigned Id, /* Thread ID */
+ char *ThrName) /* Thread name */
+{
+ int index;
+ unsigned name;
+
+ if ( Id <_Objects_Information_table[OBJECTS_RTEMS_TASKS]->maximum_id &&
+ Id >_Objects_Information_table[OBJECTS_RTEMS_TASKS]->minimum_id) {
+
+ index = Id - _Objects_Information_table[OBJECTS_RTEMS_TASKS]->minimum_id;
+ name = *(unsigned*)(_Objects_Information_table[OBJECTS_RTEMS_TASKS]->local_table[1+index]->name);
+ ThrName[0] = (char)((name >> 24) & 0xFF );
+ ThrName[1] = (char)((name >> 16) & 0xFF );
+ ThrName[2] = (char)((name >> 8) & 0xFF );
+ ThrName[3] = (char)( name & 0xFF );
+ ThrName[4] = 0x0;
+ return 0;
+ }
+
+ if ( Id <_Objects_Information_table[OBJECTS_POSIX_THREADS]->maximum_id &&
+ Id >_Objects_Information_table[OBJECTS_POSIX_THREADS]->minimum_id) {
+
+ index = Id - _Objects_Information_table[OBJECTS_POSIX_THREADS]->minimum_id;
+ name = *(unsigned*)(_Objects_Information_table[OBJECTS_POSIX_THREADS]->local_table[1+index]->name);
+ ThrName[0] = (char)((name >> 24) & 0xFF );
+ ThrName[1] = (char)((name >> 16) & 0xFF );
+ ThrName[2] = (char)((name >> 8) & 0xFF );
+ ThrName[3] = (char)( name & 0xFF );
+ ThrName[4] = 0x0;
+ return 0;
+ }
+
+
+ return -1;
+
+}
+
+/* -----------------------------------------------------------------
+ TgtThreadList - return all the threads in the system
+ ----------------------------------------------------------------- */
+
+ int
+TgtThreadList (
+ PID_LIST* plst, /* Process entry */
+ unsigned* threads, /* Output buffer */
+ unsigned size) /* Output buffer size */
+{
+ int curr = 0;
+ Objects_Id id;
+ unsigned index;
+
+ id = _Objects_Information_table[OBJECTS_RTEMS_TASKS]->minimum_id;
+
+ while (id < _Objects_Information_table[OBJECTS_RTEMS_TASKS]->maximum_id){
+ index = id - _Objects_Information_table[OBJECTS_RTEMS_TASKS]->minimum_id;
+ if ( _Objects_Information_table[OBJECTS_RTEMS_TASKS]->local_table[1+index] != NULL){
+ threads[curr] = (unsigned) id;
+ curr++;
+ }
+ id ++;
+ }
+
+ id = _Objects_Information_table[OBJECTS_POSIX_THREADS]->minimum_id;
+
+ while (id < _Objects_Information_table[OBJECTS_POSIX_THREADS]->maximum_id){
+ index = id - _Objects_Information_table[OBJECTS_POSIX_THREADS]->minimum_id;
+ if ( _Objects_Information_table[OBJECTS_POSIX_THREADS]->local_table[1+index] != NULL){
+ threads[curr] = (unsigned) id;
+ curr++;
+ }
+ id ++;
+ }
+
+ return curr;
+}
diff --git a/c/src/lib/librdbg/awk.svc b/c/src/lib/librdbg/awk.svc
new file mode 100644
index 0000000000..79e24a9d90
--- /dev/null
+++ b/c/src/lib/librdbg/awk.svc
@@ -0,0 +1,65 @@
+#########################################################################
+#
+# Component: RDBG
+# Module: awk.svc
+#
+# Synopsis: AWK script which transforms the server skeleton produced
+# by rpcgen(1) into something suitable for RDB servers.
+#
+#########################################################################
+
+BEGIN {
+ headerstarted = 0
+ withinproc = 0
+ brack = 0
+}
+
+$1 ~ /^\/\*HEADER_START\*\/$/ {
+ headerstarted = 1
+ printf("#include <rpc/types.h>\n");
+ printf("#include <rpc/rpc.h>\n");
+ printf("#include <stdio.h>\n");
+ printf("#include <stdlib.h>\n");
+ printf("#include <string.h>\n");
+ printf("#include <bsp.h>\n");
+ printf("#include <rdbg/servrpc.h>\n");
+ printf("#include <rdbg/%s>\n", THEPROG);
+ printf("#define fprintf(a,b) printf(b)\n");
+ printf("#define msgout(a) printf(a)\n")
+ printf("#define _msgout(a) fprintf(stderr,a)\n");
+}
+
+$1 ~ /^\/\*HEADER_END\*\/$/ {
+ headerstarted = 0
+}
+
+{
+ if (headerstarted == 1) {
+ print $0
+ } else if ($1 ~ /.*_2.*/) {
+ withinproc = 1
+ printf("void\n");
+ print $0
+ } else if (withinproc == 1) {
+ if ($1 == "switch") {
+ print "\tDPRINTF ((\"remotedeb_2: %s (%d)\\n\", "
+ print "\t\t(unsigned) rqstp->rq_proc < "
+ print "\t\t(unsigned) (sizeof names / sizeof names[0]) ?"
+ print "\t\tnames [rqstp->rq_proc] : \"???\", "
+ print "\t\t(int) rqstp->rq_proc));\n"
+ }
+ for (i = 1; i <= NF; i++) {
+ if ($i == "{") {
+ brack++;
+ } else if ($i == "}") {
+ brack--;
+ if (brack == 0) {
+ withinproc = 0;
+ }
+ }
+ }
+ if ($1 != "_rpcsvcdirty" ) {
+ print $0
+ }
+ }
+}
diff --git a/c/src/lib/librdbg/i386/excep.c b/c/src/lib/librdbg/i386/excep.c
new file mode 100644
index 0000000000..5ca1fd8df6
--- /dev/null
+++ b/c/src/lib/librdbg/i386/excep.c
@@ -0,0 +1,233 @@
+/*
+ **************************************************************************
+ *
+ * Component =
+ *
+ * Synopsis = rdbg/i386/excep.c
+ *
+ **************************************************************************
+ */
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rdbg/rdbg_f.h>
+#include <assert.h>
+#include <errno.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/servrpc.h>
+
+
+extern rtems_id serializeSemId;
+extern rtems_id wakeupEventSemId;
+
+
+unsigned int NbExceptCtx;
+volatile unsigned int NbSerializedCtx;
+Exception_context *FirstCtx = NULL;
+Exception_context *LastCtx = NULL;
+
+CPU_Exception_frame SavedContext;
+
+
+/********* Save an exception context at the end of a list *****/
+
+int PushExceptCtx ( Objects_Id Id, Objects_Id semId, CPU_Exception_frame *ctx ) {
+
+ Exception_context *SaveCtx;
+
+ SaveCtx = (Exception_context *)malloc(sizeof(Exception_context));
+ if (SaveCtx == NULL)
+ rtems_panic("Can't allocate memory to save Exception context");
+
+ SaveCtx->id = Id;
+ SaveCtx->ctx = ctx;
+ SaveCtx->semaphoreId = semId;
+ SaveCtx->previous = NULL;
+ SaveCtx->next = NULL;
+
+ if (FirstCtx == NULL){ /* initialization */
+ FirstCtx = SaveCtx;
+ LastCtx = SaveCtx;
+ NbExceptCtx = 1;
+ }
+ else {
+ NbExceptCtx ++;
+ LastCtx->next = SaveCtx;
+ SaveCtx->previous = LastCtx;
+ LastCtx = SaveCtx;
+ }
+ return 0;
+}
+
+/********* Save an temporary exception context in a ******/
+/********* global variable ******/
+
+int PushSavedExceptCtx ( Objects_Id Id, CPU_Exception_frame *ctx ) {
+
+ memcpy (&(SavedContext), ctx, sizeof(CPU_Exception_frame));
+ return 0;
+}
+
+
+/****** Remove the context of the specified Id thread *********/
+/****** If Id = -1, then return the first context *********/
+
+
+int PopExceptCtx ( Objects_Id Id ) {
+
+ Exception_context *ExtractCtx;
+
+ if (FirstCtx == NULL) return -1;
+
+ if (Id == -1) {
+ ExtractCtx = LastCtx;
+ LastCtx = LastCtx->previous;
+ free(ExtractCtx);
+ NbExceptCtx --;
+ return 0;
+ }
+
+ ExtractCtx = LastCtx;
+
+ while (ExtractCtx->id != Id && ExtractCtx != NULL) {
+ ExtractCtx = ExtractCtx->previous;
+ }
+
+ if (ExtractCtx == NULL)
+ return -1;
+
+ if ( ExtractCtx->previous != NULL)
+ (ExtractCtx->previous)->next = ExtractCtx->next;
+
+ if ( ExtractCtx->next != NULL)
+ (ExtractCtx->next)->previous = ExtractCtx->previous;
+
+ if (ExtractCtx == FirstCtx)
+ FirstCtx = FirstCtx->next;
+ else
+ if (ExtractCtx == LastCtx)
+ LastCtx = LastCtx->previous;
+
+ free(ExtractCtx);
+ NbExceptCtx --;
+ return 0;
+}
+
+/****** Return the context of the specified Id thread *********/
+/****** If Id = -1, then return the first context *********/
+
+
+Exception_context *GetExceptCtx ( Objects_Id Id ) {
+
+ Exception_context *ExtractCtx;
+
+ if (FirstCtx == NULL) return NULL;
+
+ if (Id == -1) {
+ return LastCtx;
+ }
+
+ ExtractCtx = LastCtx;
+
+ while (ExtractCtx->id != Id && ExtractCtx != NULL) {
+ ExtractCtx = ExtractCtx->previous;
+ }
+
+ if (ExtractCtx == NULL)
+ return NULL;
+
+ return ExtractCtx;
+}
+
+/*----- Breakpoint Exception management -----*/
+
+ /*
+ * Handler for Breakpoint Exceptions :
+ * software breakpoints.
+ */
+
+void
+BreakPointExcHdl(CPU_Exception_frame *ctx)
+{
+ rtems_status_code status;
+ rtems_id continueSemId;
+
+ if ( (justSaveContext) && (ctx->idtIndex == I386_EXCEPTION_ENTER_RDBG) ) {
+ PushSavedExceptCtx (_Thread_Executing->Object.id, ctx);
+ justSaveContext = 0;
+ }
+ else {
+ if (ctx->idtIndex != DEBUG){
+ NbSerializedCtx++;
+ rtems_semaphore_obtain(serializeSemId, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ NbSerializedCtx--;
+ }
+
+ currentTargetThread = _Thread_Executing->Object.id;
+
+#ifdef DDEBUG
+ printk("----------------------------------------------------------\n");
+ printk("Exception %d caught at PC %x by thread %d\n",
+ ctx->idtIndex,
+ ctx->eip,
+ _Thread_Executing->Object.id);
+ printk("----------------------------------------------------------\n");
+ printk("Processor execution context at time of the fault was :\n");
+ printk("----------------------------------------------------------\n");
+ printk(" EAX = %x EBX = %x ECX = %x EDX = %x\n",
+ ctx->eax, ctx->ebx, ctx->ecx, ctx->edx);
+ printk(" ESI = %x EDI = %x EBP = %x ESP = %x\n",
+ ctx->esi, ctx->edi, ctx->ebp, ctx->esp0);
+ printk("----------------------------------------------------------\n");
+ printk("Error code pushed by processor itself (if not 0) = %x\n",
+ ctx->faultCode);
+ printk("----------------------------------------------------------\n\n");
+#endif
+
+ status = rtems_semaphore_create (rtems_build_name('D', 'B', 'G', 'c'),
+ 0,
+ RTEMS_FIFO |
+ RTEMS_COUNTING_SEMAPHORE |
+ RTEMS_NO_INHERIT_PRIORITY |
+ RTEMS_NO_PRIORITY_CEILING |
+ RTEMS_LOCAL,
+ 0,
+ &continueSemId);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't create continue semaphore: `%s'\n",rtems_status_text(status));
+
+ PushExceptCtx (_Thread_Executing->Object.id, continueSemId, ctx);
+
+ switch (ctx->idtIndex){
+ case I386_EXCEPTION_DEBUG:
+ DPRINTF((" DEBUG EXCEPTION !!!\n"));
+ ctx->eflags &= ~EFLAGS_TF;
+ ExitForSingleStep-- ;
+ rtems_semaphore_release( wakeupEventSemId );
+ break;
+
+ case I386_EXCEPTION_BREAKPOINT:
+ DPRINTF((" BREAKPOINT EXCEPTION !!!\n"));
+ rtems_semaphore_release( wakeupEventSemId );
+ break;
+
+ case I386_EXCEPTION_ENTER_RDBG:
+ DPRINTF((" ENTER RDBG !!!\n"));
+ rtems_semaphore_release( wakeupEventSemId );
+ break;
+
+ default:
+ DPRINTF((" OTHER EXCEPTION !!!\n"));
+ rtems_semaphore_release( wakeupEventSemId );
+ break;
+ }
+
+ rtems_semaphore_obtain(continueSemId, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+ PopExceptCtx (_Thread_Executing->Object.id);
+ rtems_semaphore_delete(continueSemId);
+ }
+}
+
+
+
diff --git a/c/src/lib/librdbg/i386/pc386/remdeb_f.x b/c/src/lib/librdbg/i386/pc386/remdeb_f.x
new file mode 100644
index 0000000000..0ff52d1307
--- /dev/null
+++ b/c/src/lib/librdbg/i386/pc386/remdeb_f.x
@@ -0,0 +1,58 @@
+/*
+ **************************************************************************
+ *
+ * Component = rdblib
+ *
+ * Synopsis = remdeb_f.x
+ *
+ *
+ **************************************************************************
+ */
+
+struct xdr_regs
+{
+ unsigned int tabreg[19];
+};
+
+#ifdef RPC_HDR
+
+%/* now define register macros to apply to xdr_reg struct */
+%
+%#define GS 0
+%#define FS 1
+%#define ES 2
+%#define DS 3
+%#define EDI 4
+%#define ESI 5
+%#define EBP 6
+%#define ESP 7
+%#define EBX 8
+%#define EDX 9
+%#define ECX 10
+%#define EAX 11
+%#define TRAPNO 12
+%#define ERR 13
+%#define EIP 14
+%#define CS 15
+%#define EFL 16
+%#define UESP 17
+%#define SS 18
+%
+%#define REG_PC tabreg[EIP] /* PC (eip) register offset */
+%#define REG_SP tabreg[UESP] /* SP (uesp) register offset */
+%#define REG_FP tabreg[EBP] /* FP (ebp) register offset */
+
+%/* now define the BREAKPOINT mask technique to a long word */
+%#define SET_BREAK(l) ((l&0xFFFFFF00) | 0xCC)
+%#define IS_BREAK(l) (((l) & 0xFF) == 0xCC)
+%#define ORG_BREAK(c,p) (((c) & 0xFFFFFF00) | ((p) & 0xFF))
+%#define IS_STEP(regs) (regs.tabreg[TRAPNO] == 1) /* was step and not break */
+%#define BREAK_ADJ 1 /* must subtract one from address after bp */
+%#define BREAK_SIZE 1 /* Breakpoint occupies one byte */
+
+%#define TARGET_PROC_TYPE 0
+
+#endif
+
+
+
diff --git a/c/src/lib/librdbg/i386/rdbg_cpu_asm.s b/c/src/lib/librdbg/i386/rdbg_cpu_asm.s
new file mode 100644
index 0000000000..f0942310ce
--- /dev/null
+++ b/c/src/lib/librdbg/i386/rdbg_cpu_asm.s
@@ -0,0 +1,70 @@
+/* cpu_asm.s
+ *
+ * This file contains all assembly code for the Intel i386 implementation
+ * of RDBG.
+ *
+ */
+
+#include <asm.h>
+
+ BEGIN_CODE
+
+/*
+ * void copyback_data_cache_and_invalidate_instr_cache()
+ *
+ * This routine performs a copy of the data cache
+ * and invalidate the instruction cache
+ */
+
+ .p2align 1
+ PUBLIC (copyback_data_cache_and_invalidate_instr_cache)
+
+SYM (copyback_data_cache_and_invalidate_instr_cache):
+ wbinvd
+ ret
+
+
+
+/*
+ * void enterRdbg(void)
+ *
+ * This function perform a call to the exception 19
+ * It is used :
+ * 1 - in the user code, to simulate a Breakpoint.
+ * (with justSaveContext = 0)
+ * 2 - in the RDBG code, to push a ctx in the list.
+ * (with justSaveContext = 1)
+ *
+ * In most of case, it will be use as described in 1.
+ * The 2nd possibility will be used by RDBG to obtain
+ * its own ctx
+ */
+
+ PUBLIC (enterRdbg)
+
+SYM (enterRdbg):
+ int $50
+ ret
+
+
+/*
+ * void rtems_exception_prologue_50(void)
+ *
+ * Exception 50 is used to enter Rdbg
+ *
+ */
+
+ .p2align 4
+
+ PUBLIC (rtems_exception_prologue_50)
+ PUBLIC (_Exception_Handler)
+
+SYM (rtems_exception_prologue_50):
+ pushl $ 0
+ pushl $ 50
+ jmp SYM(_Exception_Handler) ;
+
+
+END_CODE
+
+END
diff --git a/c/src/lib/librdbg/i386/rdbg_f.c b/c/src/lib/librdbg/i386/rdbg_f.c
new file mode 100644
index 0000000000..aeb07fcbe8
--- /dev/null
+++ b/c/src/lib/librdbg/i386/rdbg_f.c
@@ -0,0 +1,130 @@
+/*
+ **************************************************************************
+ *
+ * Component =
+ *
+ * Synopsis = rdbg/i386/rdbg_f.c
+ *
+ **************************************************************************
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <rdbg/reg.h>
+#include <rdbg/remdeb.h>
+#include <rdbg/rdbg.h>
+#include <rtems/score/cpu.h>
+#include <rtems/score/thread.h>
+
+
+void
+CtxToRegs (const CPU_Exception_frame* ctx, xdr_regs* regs)
+{
+ regs->tabreg [GS] = 0;
+ regs->tabreg [FS] = 0;
+ regs->tabreg [ES] = 0;
+ regs->tabreg [DS] = 0;
+ regs->tabreg [EDI] = ctx->edi;
+ regs->tabreg [ESI] = ctx->esi;
+ regs->tabreg [EBP] = ctx->ebp;
+ regs->tabreg [ESP] = ctx->esp0;
+ regs->tabreg [EBX] = ctx->ebx;
+ regs->tabreg [EDX] = ctx->edx;
+ regs->tabreg [ECX] = ctx->ecx;
+ regs->tabreg [EAX] = ctx->eax;
+ regs->tabreg [TRAPNO] = ctx->idtIndex;
+ regs->tabreg [ERR] = ctx->faultCode;
+ regs->tabreg [EIP] = ctx->eip;
+ regs->tabreg [CS] = ctx->cs & 0xFFFF;
+ regs->tabreg [EFL] = ctx->eflags;
+}
+
+
+ void
+RegsToCtx (const xdr_regs* regs, CPU_Exception_frame* ctx)
+{
+ ctx->edi = regs->tabreg [EDI];
+ ctx->esi = regs->tabreg [ESI];
+ ctx->ebp = regs->tabreg [EBP];
+ ctx->esp0 = regs->tabreg [ESP];
+ ctx->ebx = regs->tabreg [EBX];
+ ctx->edx = regs->tabreg [EDX];
+ ctx->ecx = regs->tabreg [ECX];
+ ctx->eax = regs->tabreg [EAX];
+ ctx->idtIndex = regs->tabreg [TRAPNO];
+ ctx->faultCode = regs->tabreg [ERR];
+ ctx->eip = regs->tabreg [EIP];
+ ctx->cs = regs->tabreg [CS];
+ ctx->eflags = regs->tabreg [EFL];
+}
+
+void
+get_ctx_thread( Thread_Control *thread, CPU_Exception_frame* ctx)
+{
+ ctx->edi = thread->Registers.edi;
+ ctx->esi = thread->Registers.esi;
+ ctx->ebp = (unsigned32)(thread->Registers.ebp);
+ ctx->esp0 = (unsigned32)(thread->Registers.esp);
+ ctx->ebx = thread->Registers.ebx;
+ ctx->edx = 0;
+ ctx->ecx = 0;
+ ctx->eax = 0;
+ ctx->idtIndex = 0;
+ ctx->faultCode = 0;
+ ctx->eip = *(unsigned int*)(thread->Registers.esp);
+ ctx->cs = 0;
+ ctx->eflags = thread->Registers.eflags;
+}
+
+void
+set_ctx_thread( Thread_Control *thread, CPU_Exception_frame* ctx)
+{
+ thread->Registers.edi = ctx->edi;
+ thread->Registers.esi = ctx->esi;
+ thread->Registers.ebp = (void*)(ctx->ebp);
+ thread->Registers.esp = (void*)(ctx->esp0);
+ thread->Registers.ebx = ctx->ebx;
+ thread->Registers.eflags = ctx->eflags;
+}
+
+
+
+int
+Single_Step(CPU_Exception_frame* ctx)
+{
+ /* Check if not already set */
+ if ((ctx->eflags & EFLAGS_TF) != 0 || ExitForSingleStep != 0) {
+ /* Check coherency */
+ assert ((ctx->eflags & EFLAGS_TF) != 0);
+ assert (ExitForSingleStep != 0);
+ return 0;
+ }
+ ctx->eflags |= EFLAGS_TF; /* eflags */
+ ++ExitForSingleStep;
+
+ return 0;
+}
+
+ int
+CheckForSingleStep (CPU_Exception_frame* ctx)
+{
+ if (ExitForSingleStep) {
+ /*
+ * This functions can be called both from
+ * INT1 and INT3 handlers. In case it is
+ * called from INT3, need to clear TF.
+ */
+ ctx->eflags &= ~EFLAGS_TF;
+ ExitForSingleStep = 0;
+ return 1;
+ }
+ return 0;
+}
+
+void
+CancelSingleStep (CPU_Exception_frame* ctx)
+{
+ /* Cancel scheduled SS */
+ ctx->eflags &= ~EFLAGS_TF;
+ ExitForSingleStep-- ;
+}
diff --git a/c/src/lib/librdbg/ptrace.c b/c/src/lib/librdbg/ptrace.c
new file mode 100644
index 0000000000..158bd57cbb
--- /dev/null
+++ b/c/src/lib/librdbg/ptrace.c
@@ -0,0 +1,335 @@
+/*
+ **************************************************************************
+ *
+ * Component =
+ *
+ * Synopsis = rkdb/rkdb.c
+ *
+ **************************************************************************
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/rdbg_f.h>
+#include <rdbg/servrpc.h>
+
+extern rtems_id serializeSemId;
+extern rtems_id wakeupEventSemId;
+extern rtems_id eventTaskId;
+extern Exception_context *FirstCtx;
+extern Exception_context *LastCtx;
+extern CPU_Exception_frame SavedContext;
+extern unsigned int NbExceptCtx;
+extern unsigned int NbSerializedCtx;
+
+
+
+/* --------------------------------------------------------------------
+ return a pointeur to the Tread Control structure of the specified
+ Id
+ -------------------------------------------------------------------- */
+
+Thread_Control *Thread_Get_RDBG (
+ Objects_Id Id
+)
+{
+ unsigned index;
+
+ if ( Id <_Objects_Information_table[OBJECTS_RTEMS_TASKS]->maximum_id &&
+ Id >_Objects_Information_table[OBJECTS_RTEMS_TASKS]->minimum_id) {
+
+ index = Id - _Objects_Information_table[OBJECTS_RTEMS_TASKS]->minimum_id;
+ if ( _Objects_Information_table[OBJECTS_RTEMS_TASKS]->local_table[1+index] != NULL) {
+ return (Thread_Control *)(_Objects_Information_table[OBJECTS_RTEMS_TASKS]->local_table[1+index]);
+ }
+ }
+
+ if ( Id <_Objects_Information_table[OBJECTS_POSIX_THREADS]->maximum_id &&
+ Id >_Objects_Information_table[OBJECTS_POSIX_THREADS]->minimum_id) {
+
+ index = Id - _Objects_Information_table[OBJECTS_POSIX_THREADS]->minimum_id;
+ if ( _Objects_Information_table[OBJECTS_POSIX_THREADS]->local_table[1+index] != NULL)
+ return (Thread_Control *)(_Objects_Information_table[OBJECTS_POSIX_THREADS]->local_table[1+index]);
+ }
+
+ return 0;
+
+}
+
+
+/* --------------------------------------------------------------------
+ Memory read
+ -------------------------------------------------------------------- */
+
+int
+safeMemRead(void *src, void *dest, int nbBytes){
+
+ /*
+ * safe because if it generates an exception,
+ * it must return normally
+ * TBD
+ */
+
+ memcpy(dest, src, nbBytes);
+ return 0;
+}
+
+/* --------------------------------------------------------------------
+ Memory write
+ -------------------------------------------------------------------- */
+int
+safeMemWrite(void *src, void * dest, int nbBytes){
+
+ /*
+ * safe because if it generates an exception,
+ * it must return normally
+ * TBD
+ */
+
+ memcpy(dest, src, nbBytes);
+ return 0;
+}
+
+/* --------------------------------------------------------------------
+ Ptrace
+ -------------------------------------------------------------------- */
+
+int
+ptrace (int request, int pid, char* addr, int data, char* addr2)
+ {
+ int diag;
+ errno = 0 ;
+ if (pid != 1) {
+ errno = ESRCH;
+ return -1;
+ }
+ switch (request) {
+
+ case RPT_SINGLESTEP:{
+ Exception_context *ctx;
+
+ if (CannotRestart == 1){
+ setErrno(EIO);
+ return -1;
+ }
+
+ if ((ctx = GetExceptCtx (currentTargetThread)) != NULL) {
+ Single_Step(ctx->ctx);
+ rtems_semaphore_release( ctx->semaphoreId );
+ return 0;
+ }
+ break;
+ }
+
+ case RPT_PEEKTEXT:
+ case RPT_PEEKDATA: {
+ diag = safeMemRead(addr, &data, sizeof data);
+ if (diag == 0) return data;
+ mem_error:
+ return -1;
+ }
+
+ case RPT_POKETEXT: {
+ diag = safeMemWrite(&data, addr, sizeof data);
+
+ /*
+ * We must flush the INSTR and DATA cache to be sure the
+ * opcode modification is taken into account, because
+ * the breakpoint opcode is written via the data cache
+ * while execution code is fetched via the instruction
+ * cache
+ */
+
+ if (diag == 0) {
+ copyback_data_cache_and_invalidate_instr_cache();
+ return 0;
+ }
+ goto mem_error;
+ }
+ case RPT_POKEDATA: {
+ diag = safeMemWrite(&data, addr, sizeof data);
+ if (diag == 0) return 0;
+ goto mem_error;
+ }
+ case RPT_CONT: {
+ Exception_context *ctx;
+
+ if (CannotRestart == 1){
+ setErrno (EIO);
+ return -1;
+ }
+
+ ctx = GetExceptCtx (currentTargetThread);
+
+ if (
+ ctx->ctx->idtIndex != I386_EXCEPTION_DEBUG &&
+ ctx->ctx->idtIndex != I386_EXCEPTION_BREAKPOINT &&
+ ctx->ctx->idtIndex != I386_EXCEPTION_ENTER_RDBG
+ ) {
+ CannotRestart = 1;
+ setErrno (EIO);
+ return -1;
+ }
+
+ assert (data == 0);
+ assert (ExitForSingleStep == 0);
+
+ rtems_semaphore_release( serializeSemId );
+
+ if ((ctx = GetExceptCtx (currentTargetThread)) != NULL) {
+ rtems_semaphore_release( ctx->semaphoreId );
+ }
+ return 0;
+ }
+
+ case RPT_ATTACH:
+ return 0;
+
+ case RPT_DETACH:{
+ Exception_context *ctx;
+
+ if (NbExceptCtx || NbSerializedCtx) {
+ ctx = FirstCtx;
+ rtems_task_delete(eventTaskId);
+ rtems_semaphore_delete(serializeSemId);
+ rtems_semaphore_delete(wakeupEventSemId);
+ }
+ return 0;
+ }
+
+ case RPT_GETREGS:{
+ Exception_context *ctx;
+
+ if ((ctx = GetExceptCtx (currentTargetThread)) != NULL) {
+ CtxToRegs (ctx->ctx, (xdr_regs*) addr);
+ return 0;
+ }
+ break;
+ }
+
+ case RPT_SETREGS:{
+ Exception_context *ctx;
+
+ if ((ctx = GetExceptCtx (currentTargetThread)) != NULL) {
+ RegsToCtx ((xdr_regs*) addr, ctx->ctx);
+ return 0;
+ }
+ break;
+ }
+
+ case RPT_READTEXT:
+ case RPT_READDATA: {
+ diag = safeMemRead(addr, addr2, data);
+ if (diag == 0) return 0;
+ goto mem_error;
+ }
+ case RPT_WRITETEXT:
+ case RPT_WRITEDATA: {
+ diag = safeMemWrite(addr2, addr, data);
+ if (diag == 0) return 0;
+ goto mem_error;
+ }
+
+ case RPT_GETTARGETTHREAD:
+ if (!NbExceptCtx) {
+ errno = EBUSY;
+ return -1;
+ }
+ return currentTargetThread;
+
+ case RPT_SETTARGETTHREAD:
+ if (!NbExceptCtx) {
+ errno = EBUSY;
+ return -1;
+ }
+ currentTargetThread = data;
+ return 0;
+
+ case RPT_GETTHREADNAME: {
+ return TgtGetThreadName (NULL, (unsigned)(data), (char *) addr);
+ }
+
+ case RPT_THREADLIST: {
+ int count = TgtThreadList (NULL, (unsigned*) addr, UTHREAD_MAX
+ * sizeof (unsigned));
+ if (count < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return count;
+ }
+
+ case RPT_SETTHREADREGS: {
+ Exception_context *ctx;
+ CPU_Exception_frame Ectx;
+ Thread_Control *thread;
+ rtems_id id;
+
+ rtems_task_ident(RTEMS_SELF, RTEMS_SEARCH_ALL_NODES, &id);
+ if (data == (unsigned)id)
+ break;
+
+ if ((ctx = GetExceptCtx (data)) != NULL) {
+ RegsToCtx ((xdr_regs*) addr, ctx->ctx);
+ return 0;
+ }
+ thread = Thread_Get_RDBG ((Objects_Id)(data));
+ if (thread != NULL) {
+ RegsToCtx ((xdr_regs*) addr, &Ectx);
+ set_ctx_thread (thread, &Ectx);
+ return 0;
+ }
+ break;
+ }
+
+ case RPT_GETTHREADREGS: {
+ Exception_context *ctx;
+ CPU_Exception_frame Ectx;
+ Thread_Control *thread;
+ rtems_id id;
+
+ rtems_task_ident(RTEMS_SELF, RTEMS_SEARCH_ALL_NODES, &id);
+ if (data == (unsigned)id){
+ justSaveContext = 1;
+ enterRdbg();
+ CtxToRegs (&(SavedContext), (xdr_regs*) addr);
+ return 0;
+ }
+
+ if ((ctx = GetExceptCtx (data)) != NULL) {
+ CtxToRegs (ctx->ctx, (xdr_regs*) addr);
+ return 0;
+ }
+ thread = Thread_Get_RDBG ((Objects_Id)(data));
+ if (thread != NULL) {
+ get_ctx_thread (thread, &Ectx);
+ CtxToRegs (&Ectx, (xdr_regs*) addr);
+ return 0;
+ }
+ break;
+ }
+
+ case RPT_KILL:
+ TotalReboot = 1;
+ return 0;
+
+ case RPT_TRACEME:
+ case RPT_PEEKUSER:
+ case RPT_POKEUSER:
+ case RPT_GETFPREGS:
+ case RPT_SETFPREGS:
+ case RPT_GETFPAREGS:
+ case RPT_SETFPAREGS:
+ case RPT_SYSCALL:
+ case RPT_DUMPCORE:
+ case RPT_GETUCODE:
+ case RPT_THREADSUSPEND:
+ case RPT_THREADRESUME:
+ case RPT_SETTHREADNAME:
+ default:
+ break;
+ }
+ errno = EINVAL;
+ return -1;
+}
diff --git a/c/src/lib/librdbg/rdbg.c b/c/src/lib/librdbg/rdbg.c
new file mode 100644
index 0000000000..1f04119e8e
--- /dev/null
+++ b/c/src/lib/librdbg/rdbg.c
@@ -0,0 +1,139 @@
+/*
+ **************************************************************************
+ *
+ * Component =
+ *
+ * Synopsis = rkdb/rkdb.c
+ *
+ **************************************************************************
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/servrpc.h>
+
+u_short rtemsPort = RTEMS_PORT;
+int BackPort = RTEMS_BACK_PORT;
+int rtemsActive = 0;
+SVCXPRT* rtemsXprt;
+int rtemsSock;
+char ActName[] = "RTEMS";
+volatile int ExitForSingleStep = 0 ;
+volatile int Continue;
+volatile int justSaveContext;
+volatile Objects_Id currentTargetThread;
+volatile int CannotRestart = 0;
+volatile int TotalReboot = 0;
+int CONN_LIST_INC = 3;
+int PID_LIST_INC = 1;
+int TSP_RETRIES = 10;
+
+
+ int
+getId()
+{
+ rtems_id id;
+
+ rtems_task_ident(RTEMS_SELF, RTEMS_SEARCH_ALL_NODES, &id);
+ return (int)(id) ;
+}
+
+ static int
+rdbgInit (void)
+{
+ int sock;
+ struct sockaddr_in addr;
+
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock == -1) {
+ printf("%s: rkdbInit: cannot allocate socket\n", ActName);
+ return -1;
+ }
+
+ bzero( (void *)&addr, sizeof(struct sockaddr_in));
+ addr.sin_port = htons(rtemsPort);
+ if ((bind(sock, (struct sockaddr*) &addr, sizeof(addr))) == -1) {
+ printf("%s: rkdbInit: cannot bind socket\n", ActName);
+ return -2;
+ }
+ rtemsXprt = svcudp_create(sock);
+ if (svcudp_enablecache(rtemsXprt, 1) == 0) {
+ printf("%s: rkdbInit: cannot enable rpc cache\n", ActName);
+ return -3;
+ }
+ rtemsSock = sock;
+ return 0;
+}
+
+ rtems_task
+rdbgDaemon (rtems_task_argument argument)
+{
+ for (;;){
+
+ if (TotalReboot == 1){
+ rtemsReboot();
+ }
+
+ svc_processrequest( rtemsXprt, REMOTEDEB, REMOTEVERS, remotedeb_2);
+ }
+}
+
+ void
+rtems_rdbg_initialize (void)
+{
+ rtems_name task_name;
+ rtems_id tid;
+ rtems_status_code status;
+
+#ifdef DDEBUG
+ rdb_debug = 1; /* DPRINTF now will display */
+#endif
+
+ DPRINTF (("%s init starting\n", ActName));
+
+ /* Print version string */
+#ifdef DDEBUG
+ printk ("RDBG v.%d built on [%s %s]\n", SERVER_VERS, __DATE__, __TIME__);
+#else
+ printk ("RDBG v.%d\n", SERVER_VERS);
+#endif
+
+ /* Create socket and init UDP RPC server */
+ if (rdbgInit() != 0) goto error;
+
+ Continue = 1;
+ justSaveContext = 0;
+ currentTargetThread = 0;
+
+ task_name = rtems_build_name( 'R', 'D', 'B', 'G' );
+ if ((status = rtems_task_create( task_name, 5, 24576,
+ RTEMS_INTERRUPT_LEVEL(0),
+ RTEMS_DEFAULT_ATTRIBUTES | RTEMS_SYSTEM_TASK
+ , &tid ))
+ != RTEMS_SUCCESSFUL){
+ printf("status = %d\n",status);
+ rtems_panic ("Can't create task.\n");
+ }
+
+ status = rtems_task_start(tid, rdbgDaemon, 0);
+
+ return;
+
+error:
+ printf ("initialization failed.\n");
+}
+
+ void
+setErrno (int error)
+{
+ errno = error;
+}
+
+ int
+getErrno()
+{
+ return errno;
+}
diff --git a/c/src/lib/librdbg/remdeb.x b/c/src/lib/librdbg/remdeb.x
new file mode 100644
index 0000000000..e4cb998ebc
--- /dev/null
+++ b/c/src/lib/librdbg/remdeb.x
@@ -0,0 +1,544 @@
+/*
+ **********************************************************************
+ *
+ * Component: RDBG servers
+ * Module: remdeb.x
+ *
+ * Synopsis: XDR definitions for remote debug server RPC calls.
+ * XDR definitions for RPCGEN to build remote debug server.
+ *
+ **********************************************************************
+ */
+
+#ifdef RPC_SVC
+%/*HEADER_START*/
+#endif
+
+%#define RTEMS_PORT 2071
+%#define RTEMS_BACK_PORT 2073
+
+#ifdef RPC_HDR
+%#ifndef REMDEB_H
+%#define RPCGENSRVNAME(a) a
+#endif
+
+enum rpc_type {
+ SUNRPC = 0,
+ BADRPCTYPE = 25
+};
+
+
+const NET_SAFE = 1400; /* this is safe for UDP messages */
+
+struct UDP_MSG
+{ /* format of UDP messages (should be in .h) */
+ unsigned char type; /* type of message (BMSG_xx) */
+ unsigned char msg_num; /* ringed number for resend detect */
+ unsigned short spec; /* specific information for type */
+ long pid; /* process this affects */
+ unsigned long context; /* specific information to request */
+};
+
+ /* First we support the overhead structures and types needed for RPC
+ requests. Then, we have all RPC routines input/output args. */
+
+%/*
+% * Sun request values for the remote ptrace system call
+% */
+%
+enum ptracereq
+{ /* these match PTRACE_xxx numbers */
+ RPT_TRACEME = 0, /* 0, by tracee to begin tracing */
+ RPT_CHILDDONE = 0, /* 0, tracee is done with his half */
+ RPT_PEEKTEXT, /* 1, read word from text segment */
+ RPT_PEEKDATA, /* 2, read word from data segment */
+ RPT_PEEKUSER, /* 3, read word from user struct */
+ RPT_POKETEXT, /* 4, write word into text segment */
+ RPT_POKEDATA, /* 5, write word into data segment */
+ RPT_POKEUSER, /* 6, write word into user struct */
+ RPT_CONT, /* 7, continue process */
+ RPT_KILL, /* 8, terminate process */
+ RPT_SINGLESTEP, /* 9, single step process */
+ RPT_ATTACH, /* 10, attach to an existing process (returns 2 if not primary)*/
+ RPT_DETACH, /* 11, detach from a process */
+ RPT_GETREGS, /* 12, get all registers */
+ RPT_SETREGS, /* 13, set all registers */
+ RPT_GETFPREGS, /* 14, get all floating point regs */
+ RPT_SETFPREGS, /* 15, set all floating point regs */
+ RPT_READDATA, /* 16, read data segment */
+ RPT_WRITEDATA, /* 17, write data segment */
+ RPT_READTEXT, /* 18, read text segment */
+ RPT_WRITETEXT, /* 19, write text segment */
+ RPT_GETFPAREGS, /* 20, get all fpa regs */
+ RPT_SETFPAREGS, /* 21, set all fpa regs */
+ RPT_22, /* 22, filler */
+ RPT_23, /* 23, filler */
+ RPT_SYSCALL, /* 24, trap next sys call */
+ RPT_DUMPCORE, /* 25, dump process core */
+ RPT_26, /* 26, filler */
+ RPT_27, /* 27, filler */
+ RPT_28, /* 28, filler */
+ RPT_GETUCODE, /* 29, get u.u_code */
+ /* Begin specific ptrace options */
+ RPT_GETTARGETTHREAD = 50, /* get PM target thread identifier */
+ RPT_SETTARGETTHREAD = 51, /* set PM target thread identifier */
+ RPT_THREADSUSPEND = 52, /* suspend a thread */
+ RPT_THREADRESUME = 53, /* resume a thread */
+ RPT_THREADLIST = 54, /* get list of process's threads */
+ RPT_GETTHREADNAME = 55, /* get the name of the thread */
+ RPT_SETTHREADNAME = 56, /* set the name of the thread */
+ RPT_SETTHREADREGS = 57, /* set all registers for a specific thread*/
+ RPT_GETTHREADREGS = 58, /* get all registers for a specific thread*/
+ /* Begin extended ptrace options for remote debug server */
+ RPT_STEPRANGE = 75, /* step while in range (addr=start, data=len) */
+ RPT_CONTTO = 76, /* cont from PC to temp break in addr */
+ RPT_SETBREAK = 77, /* set a breakpoint (addr=break) */
+ RPT_CLRBREAK = 78, /* clear a breakpoint (data=handle or 0 for all) */
+ RPT_GETBREAK = 79, /* get breakpoint (data=handle, addr=buffer to
+ fill). Returns next break. If data=0,
+ returns number of breaks. */
+ RPT_GETNAME = 80, /* get name of process (data 0=name, 1=path
+ as started, 2=fullpath). Return in addr
+ as mem) */
+ RPT_STOP = 81, /* (C-actors) Stop the C-actor */
+ RPT_PGETREGS = 82, /* portable version */
+ RPT_PSETREGS = 83, /* portable version */
+ RPT_PSETTHREADREGS = 84, /* portable version */
+ RPT_PGETTHREADREGS = 85 /* portable version */
+};
+
+#include "remdeb_f.x"
+
+const MAXDEBUGGEE= 150;
+const NAMEMAX = 17;
+
+% /*
+% * Memory data for read/write text or data. The size is in data. The target
+% * addr is in the addr field.
+% * Be careful before modifying because this value goes into internal
+% * pipes and is allocated on stack too. Pipes and/or the stack could
+% * become too small if this value gets incremented.
+% */
+
+const MEM_DATA_MAX = 256;
+
+#ifndef RPC_XDR
+
+struct xdr_mem {
+ u_long addr;
+ u_int dataNb;
+ unsigned char data[MEM_DATA_MAX];
+};
+
+#else
+/* manually define best XDR function for this */
+%bool_t xdr_xdr_mem(xdrs, objp)
+% XDR *xdrs;
+% struct xdr_mem *objp;
+%{
+% if (!xdr_u_long(xdrs, &objp->addr)) {
+% return (FALSE);
+% }
+% if (!xdr_u_int(xdrs, &objp->dataNb)) {
+% return(FALSE);
+% }
+% return (xdr_opaque(xdrs, objp->data, objp->dataNb));
+%}
+
+#endif
+
+/* Breakpoint structure maps to same structure on host. Do not change one
+ without changing the other. */
+
+enum break_type
+{ /* types of breakpoints */
+ BRKT_NONE, /* unused entry */
+ BRKT_INSTR, /* general instruction break */
+ BRKT_READ, /* read break */
+ BRKT_WRITE, /* write breakpoint */
+ BRKT_ACCESS, /* read-or-write break */
+ BRKT_EXEC, /* execution HW breakpoint */
+ BRKT_OS_CALL, /* break on OS call, addr is call number */
+ BRKT_OS_SWITCH, /* dispatch breakpoint */
+ BRKT_STEPEMUL /* emulate hardware single-step */
+};
+const MAX_THRD_BRK = 4; /* enough for 128 threads per process */
+struct xdr_break
+{ /* one per process local breakpoint */
+ u_char type; /* BRKT_xxx type of break */
+ u_char thread_spec; /* 0=all, else count of threads it affects */
+ u_short handle; /* handle of breakpoint returned */
+ u_long ee_loc; /* address of start */
+ u_long ee_type; /* type/method of address */
+ u_short length; /* length of break if range, else 0 */
+ u_char pass_count; /* pass count to initialize to (0=none) */
+ u_char curr_pass; /* pass count current value */
+ u_long thread_list[MAX_THRD_BRK]; /* bit map for thread list */
+}; /* 20 bytes+4 per thread_list (4x4=16) = 36 */
+
+const UTHREAD_MAX = 64;
+
+const THREADNAMEMAX = 16;
+typedef string thread_name <THREADNAMEMAX>;
+
+struct KernThread {
+ unsigned int threadLi;
+};
+
+#ifndef RPC_XDR
+
+#ifdef RPC_HDR
+%typedef KernThread *ptThreadList;
+#endif
+
+struct thread_list {
+ unsigned int nbThread;
+ ptThreadList threads;
+};
+
+#else /* RPC_XDR */
+
+/* must write this function by hand */
+
+%bool_t xdr_thread_list(xdrs, objp)
+% XDR *xdrs;
+% struct thread_list *objp;
+%{
+% return (xdr_array(xdrs, (char**)&objp->threads, &objp->nbThread,
+% UTHREAD_MAX, sizeof(KernThread), xdr_KernThread));
+%}
+
+#endif /* not RPC_XDR */
+
+
+union ptrace_addr_data_in switch (ptracereq req) {
+ /*
+ * due to rpcgen poor features, we cannot put RPC_SETREGS
+ * AND RPC_SETTHREADREGS in the case list. So we use a hack (FIX rpcgen).
+ */
+#ifndef RPC_HDR
+ case RPT_SETTHREADREGS :
+ xdr_regs regs;
+#endif
+ case RPT_SETREGS:
+
+ xdr_regs regs;
+
+#ifndef RPC_HDR
+ case RPT_PSETTHREADREGS:
+ u_int pregs<>;
+#endif
+ case RPT_PSETREGS:
+ u_int pregs<>;
+
+#ifdef LATER
+ case RPT_SETFPREGS:
+ xdr_fp_status fpregs;
+#endif
+ case RPT_SETTHREADNAME:
+ thread_name name;
+#ifndef RPC_HDR
+ case RPT_WRITETEXT:
+ xdr_mem mem;
+#endif
+ case RPT_WRITEDATA:
+ xdr_mem mem;
+ case RPT_SETBREAK:
+ xdr_break breakp;
+ default:
+ u_int address;
+};
+
+union ptrace_addr_data_out switch (ptracereq req) {
+ case RPT_GETREGS:
+ xdr_regs regs;
+#ifndef RPC_HDR
+ case RPT_GETTHREADREGS:
+ xdr_regs regs;
+#endif
+
+ case RPT_PGETREGS:
+ u_int pregs<>;
+
+#ifndef RPC_HDR
+ case RPT_PGETTHREADREGS:
+ u_int pregs<>;
+#endif
+
+#ifdef LATER
+ case RPT_GETFPREGS:
+ xdr_fp_status fpregs;
+#endif
+ case RPT_THREADLIST:
+ thread_list threads;
+ case RPT_GETTHREADNAME:
+ thread_name name;
+#ifndef RPC_HDR
+ case RPT_READTEXT:
+ xdr_mem mem;
+ case RPT_GETNAME:
+ xdr_mem mem;
+#endif
+ case RPT_READDATA:
+ xdr_mem mem;
+ case RPT_GETBREAK:
+ xdr_break breakp;
+ default:
+ u_int addr;
+};
+
+typedef opaque CHAR_DATA <NET_SAFE>; /* variable sized data */
+
+const XRY_MAX_INST_BUFF = 128;
+const XRY_MAX_INSTANCES = 16;
+%#ifndef XRY_MAX_CMD_STR
+const XRY_MAX_CMD_STR = 320; /* XRY_MAX_INST_BUFF+(XRY_MAX_INSTANCES*12) */
+%#endif /* REMDEB_H */
+
+
+struct xry_inst
+{
+ unsigned char flags; /* value2 interp, etc. INFL_xxx */
+ unsigned char type; /* base type of data (str, val, etc) INST_xxx */
+ unsigned char sub_type; /* specific type (task, res, etc). This is
+ set and defined by the user defined instance
+ processor and not the auto-processor */
+ unsigned char res_type;
+ u_long value; /* pointer to value or value itself */
+ u_long value2; /* second value (optional - based on flags) */
+};
+
+struct instance
+{
+ struct xry_inst instances[XRY_MAX_INSTANCES];
+ unsigned char buffer[XRY_MAX_INST_BUFF];
+};
+
+union instance_union switch (bool instances)
+{
+ case TRUE:
+ instance inst;
+ case FALSE:
+ string buffer <XRY_MAX_CMD_STR>;
+};
+
+typedef string one_arg <NET_SAFE>;
+
+const XRY_MAX_OBJ_NAME = 32; /* objname in some commands */
+
+% /* now open_connex() routine which establishes a connection to server */
+
+enum debug_type
+{ /* type of connection requested */
+ DEBTYP_PROCESS = 0, /* process connection */
+ DEBTYP_C_ACTOR = 1, /* C-Actor connection */
+ DEBTYP_KERNEL = 2, /* kernel debug connection */
+ DEBTYP_OTHER = 3 /* other subsystem */
+};
+
+%#define DEBUGGER_IS_GDB 0x2 /* */
+
+struct open_in
+{ /* input args to open a connection */
+ u_char back_port[16]; /* opaque NET address format */
+ u_short debug_type; /* type of process DEBTYP_xxx */
+ u_short flags; /* connection information OPNFLG_xxx */
+ u_char destination[16];/* opaque address if to router */
+ one_arg user_name; /* name of user on host */
+};
+
+struct open_out
+{ /* return from open_connex */
+ u_long port; /* connection number to server or -1 if error */
+ u_int pad[4]; /* Planned to be KnIpcDest. Never used */
+ u_int fp; /* True if floating point processor. If error,
+ set to errno for open error. */
+ u_char cmd_table_num; /* command table used */
+ u_char cmd_table_vers; /* version of command table */
+ u_short server_vers; /* version number of server itself */
+};
+
+% /* now close_connex() routine which detaches from server */
+
+enum close_control
+{ /* choice of how to handle owned processes */
+ CLOSE_IGNORE = 0, /* ignore all controlled pids on close */
+ CLOSE_KILL = 1, /* kill all controlled pids on close */
+ CLOSE_DETACH = 2 /* detach free running all controlled pids */
+};
+
+struct close_in
+{ /* arg to close connection */
+ close_control control; /* shutdown of owned processes control */
+};
+
+% /* now send_signal() routine which sends signals to processes like kill(2) */
+
+struct signal_in
+{ /* input to send_signal */
+ int pid; /* process/actor to send signal to */
+ int sig; /* signal to send (from /usr/include/signal.h) */
+};
+
+struct signal_out
+{ /* return from send_signal */
+ int kill_return; /* return code from kill(2) call */
+ int errNo; /* error code if failed */
+};
+
+
+% /* now wait_info() routine which returns results of polling the wait status
+% of a process/actor. It may return 0 if running, else pid or -1 */
+
+enum stop_code
+{ /* stop code information */
+ STOP_ERROR = 0, /* error, errno set */
+ STOP_NONE = 1, /* not stopped */
+ STOP_UNKNOWN = 2, /* unknown stop reason */
+ STOP_BREAK = 3, /* stopped on breakpoint */
+ STOP_STEP = 4, /* stopped on step */
+ STOP_SIGNAL = 5, /* stopped on signal receieve */
+ STOP_TERM_EXIT = 6, /* terminated normally */
+ STOP_TERM_SIG = 7, /* terminated by signal */
+ STOP_DETACHED = 8, /* detached from server */
+ STOP_KILLED = 9, /* killed by ptrace KILL */
+ STOP_SPAWN_FAILED = 10 /* spawn failed in exec part, handle=errno */
+};
+
+struct wait_in
+{ /* input arg to wait is process */
+ int pid; /* process/actor id */
+};
+
+struct wait_out
+{ /* result of wait_info call */
+ int wait_return; /* -1=error,0=running,pid=stopped */
+ int errNo; /* error code if error */
+ int status; /* wait(2) status if stopped */
+ stop_code reason; /* reason in more abstracted terms */
+ int handle; /* handle of break if stopped on break,
+ or signal number or exit code */
+ u_long PC; /* program counter if stopped */
+ u_long SP; /* stack pointer if stopped */
+ u_long FP; /* frame pointer if stopped */
+ u_long thread; /* thread that stopped if applies (else -1) */
+};
+
+% /* now ptrace() routine. This matches the Sun UNIX ptrace as well as
+% some additions */
+
+const PTRFLG_FORCE = 1; /* when set and process running, forces process
+ to stop, make the request, then start again.
+ This is used for breakpoints and the like */
+const PTRFLG_NON_OWNER = 2; /* do request even if not primary owner (will
+ notify all owners including caller if owns) */
+const PTRFLG_FREE = 4; /* free pid_list after KILL/DETACH */
+
+const PTRDET_UNOWN = 0x100; /* data value in RPT_DETACH just disconnects
+ caller as an owner of process. */
+
+struct ptrace_in
+{ /* input args matches ptrace but for XDR */
+ int pid; /* process to act on */
+ ptrace_addr_data_in addr; /* mappings for addr and addr2 */
+ u_int data; /* simple data arg of ptrace */
+ u_int flags; /* mask of PTRFLG_xxx flags. */
+};
+
+struct ptrace_out
+{ /* return information from ptrace */
+ ptrace_addr_data_out addr; /* return through addr/addr2 */
+ int result; /* result of ptrace call (return value) */
+ int errNo; /* error code if error */
+};
+
+ /* Data for GET_GLOBAL_SYMBOLS */
+struct one_symbol { /* Must match common/src/lib/ctx/ctx.h */
+ string symbolName<>;
+ long symbolValue;
+};
+
+typedef one_symbol all_symbols<>;
+
+struct get_global_symbols_out {
+ all_symbols symbols;
+};
+
+ /* Data for GET_TEXT_DATA */
+struct get_text_data_in {
+ int pid; /* process/actor id if non-zero */
+ string actorName<16>; /* actor name for system mode */
+};
+
+struct get_text_data_out {
+ int result;
+ int errNo;
+ u_long textStart;
+ u_long textSize;
+ u_long dataStart;
+ u_long dataSize;
+};
+
+ /* Data for GET_SIGNAL_NAMES */
+struct one_signal {
+ u_int number;
+ string name<>;
+};
+
+typedef one_signal all_signals<>;
+
+struct get_signal_names_out {
+ all_signals signals;
+};
+
+% /* now define the actual calls we support */
+
+program REMOTEDEB {
+ version REMOTEVERS {
+
+ /* open a connection to server or router */
+ open_out
+ OPEN_CONNEX(open_in) = 1;
+
+ /* send a signal to a process */
+ signal_out
+ SEND_SIGNAL(signal_in) = 2;
+
+ /* all routines below require a connection first */
+
+ /* close the connection to the server */
+ void
+ CLOSE_CONNEX(close_in) = 10;
+
+ /* process ptrace request */
+ ptrace_out
+ PTRACE(ptrace_in) = 11;
+
+ /* poll for status of process */
+ wait_out
+ WAIT_INFO(wait_in) = 13;
+
+ get_signal_names_out
+ GET_SIGNAL_NAMES(void) = 17;
+
+ } = 2; /* now version 2 */
+} = 0x20000fff;
+
+#ifdef RPC_HDR
+%#define REMDEB_H
+%#endif
+#endif
+
+#ifdef RPC_SVC
+
+%const char* names [] = {
+% "NULLPROC", "OPEN_CONNEX", "SEND_SIGNAL", "name3",
+% "name4", "name5", "name6", "name7",
+% "name8", "name9", "CLOSE_CONNEX", "PTRACE",
+% "name12", "WAIT_INFO", "name14", "name15",
+% "name16", "GET_SIGNAL_NAMES", "name18"
+%};
+%
+
+%/*HEADER_END*/
+#endif
diff --git a/c/src/lib/librdbg/servbkpt.c b/c/src/lib/librdbg/servbkpt.c
new file mode 100644
index 0000000000..8d986751a2
--- /dev/null
+++ b/c/src/lib/librdbg/servbkpt.c
@@ -0,0 +1,587 @@
+/*
+ **********************************************************************
+ *
+ * Component: RDB servers
+ * Module: servbkpt.c
+ *
+ * Synopsis: Management of breakpoints
+ *
+ **********************************************************************
+ */
+
+#include <sys/errno.h>
+#include <assert.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/servrpc.h>
+
+/*----- Macros -----*/
+
+#define BKPT0(plst) ((BASE_BREAK*)(plst)->break_list)
+#define BKPT_INCR 5 /* how many bkpt slots alloc at a time */
+
+#define BKPT_OVER(plst,idx,addr,size) \
+ ((plst)->break_list[idx].ee_loc + BREAK_SIZE > (UINT32) (addr) \
+ && (plst)->break_list[idx].ee_loc < (UINT32) (addr) + (size))
+
+#define BKPT_SLOTS \
+ (sizeof ((xdr_break*) 0)->thread_list / \
+ sizeof ((xdr_break*) 0)->thread_list [0])
+
+
+ /*
+ * BreakAlloc - alloc a breakpoint entry.
+ *
+ * This is a generic routine to insert an entry in the
+ * breakpoint list. It returns the number of entry just
+ * created. It returns -1 if failed.
+ */
+
+ static int
+BreakAlloc (PID_LIST* plst, Boolean normal)
+{
+ int idx, len;
+ xdr_break* blst;
+
+ if (!normal) { /* want 0 entry */
+ if (plst->break_list) {
+ return(0); /* already there */
+ }
+ idx = 1; /* force alloc below */
+ } else {
+ for (idx = 1; idx < (int)plst->break_alloc; idx++) {
+ if (plst->break_list[idx].type == BRKT_NONE) {
+ /* got a free one */
+ memset(&plst->break_list[idx], 0, sizeof(xdr_break));
+ return(idx); /* found one */
+ }
+ }
+ }
+ /* idx is the requested entry */
+
+ if (idx >= (int)plst->break_alloc) { /* need more space */
+ len = plst->break_alloc + BKPT_INCR;
+ blst = (xdr_break*)Realloc(plst->break_list, len*sizeof(xdr_break));
+ if (!blst) {
+ return(-1); /* failed, no space */
+ }
+ plst->break_alloc = len; /* got more */
+ plst->break_list = blst;
+
+ /* Clear new space */
+ memset(blst + len - BKPT_INCR, 0, BKPT_INCR * sizeof(xdr_break));
+ idx = len - BKPT_INCR; /* next available */
+ if (!idx) {
+ idx = 1; /* for normal cases */
+ }
+ }
+ return(normal ? idx : 0); /* return it */
+}
+
+ /*
+ * BreakSet - set a breakpoint in process
+ *
+ * Returns the number or -1/errno.
+ */
+
+#ifdef DDEBUG
+static const char* BreakTypes[] = {
+ "NONE", "INSTR", "READ", "WRITE",
+ "ACCESS", "EXEC", "OS_CALL", "OS_SWITCH",
+ "STEPEMUL"
+};
+
+#define BN_MAX (sizeof BreakTypes / sizeof BreakTypes[0])
+#define BREAK_NAME(t) ((unsigned) (t) < BN_MAX ? BreakTypes[t] : "???")
+#endif
+
+ int
+BreakSet (PID_LIST* plst, int conn_idx, xdr_break* bkpt)
+{
+ int pid = plst->pid;
+ int type = bkpt->type;
+ void* addr = (void *) bkpt->ee_loc;
+ int idx;
+ int data;
+
+ DPRINTF(("BreakSet: type %d (%s) at 0x%x th %d ee_type %d len %d "
+ "pass %d curr %d list %d %d %d %d\n", type, BREAK_NAME(type),
+ (int) addr,
+ bkpt->thread_spec, bkpt->ee_type, bkpt->length, bkpt->pass_count,
+ bkpt->curr_pass, bkpt->thread_list [0], bkpt->thread_list [1],
+ bkpt->thread_list [2], bkpt->thread_list [3]));
+
+ idx = BreakAlloc(plst, True); /* get entry */
+ if (idx < 0) { /* no memory */
+ setErrno(ENOMEM); /* set for safety */
+ return -1; /* return the error */
+ }
+
+ data = TgtPtrace(RPT_PEEKTEXT, pid, addr, 0, NULL); /* current */
+ if (getErrno()) {
+ return -1; /* failed, return the error */
+ }
+ if (IS_BREAK(data)) { /* There is already a break here */
+ DPRINTF(("BreakSet: already have soft bkpt at %x\n", addr));
+ if (type == BRKT_STEPEMUL) {
+ ++BKPT0 (plst)->pad1;
+ return 1; /* Any non-error value is OK */
+ }
+ setErrno(EBUSY);
+ return -1;
+ }
+
+ TgtPtrace(RPT_POKETEXT, pid, addr, SET_BREAK(data), NULL);
+
+ if (getErrno()) {
+ return -1;
+ }
+
+ plst->break_list[idx] = *bkpt;
+ plst->break_list[idx].ee_type = data; /* saved data */
+
+ /* Inform other owners */
+ if (type != BRKT_STEPEMUL) {
+ TgtNotifyAll (plst - pid_list, BMSG_BREAK, 1 /*added*/, idx,
+ conn_idx, False);
+ } else {
+ ++BKPT0 (plst)->pad1;
+ }
+ /* Return the number */
+ setErrno(0); /* Just in case */
+ return idx;
+}
+
+ int
+BreakSetAt (PID_LIST* plst, int conn_idx, unsigned long addr, break_type type)
+{
+ xdr_break xb;
+
+ memset (&xb, 0, sizeof xb);
+ xb.type = type;
+ xb.ee_loc = addr;
+ return BreakSet (plst, conn_idx, &xb);
+}
+
+/*----- Find a breakpoint by address -----*/
+
+ int
+BreakGetIndex(PID_LIST* plst, void* addr)
+{
+ int idx;
+ int data = -1;
+
+ if (!plst->break_alloc) {
+ setErrno(EFAULT);
+ return -1;
+ }
+ for (idx = 1; idx < (int)plst->break_alloc; idx++) {
+ if ((u_long) addr == plst->break_list [idx].ee_loc) {
+ data = idx;
+ break;
+ }
+ }
+ return data;
+}
+
+/*----- Getting information about breakpoint -----*/
+
+ /*
+ * If data > 0, fill "bkpt" with information about breakpoint
+ * and return the number of the next one.
+ * If data == 0, return the count of breakpoints.
+ */
+
+ int
+BreakGet (const PID_LIST* plst, int data, xdr_break* bkpt)
+{
+ int idx;
+
+ if (!data) { /* just count them */
+ for (idx = 1; idx < (int)plst->break_alloc; idx++) {
+ if (plst->break_list[idx].type != BRKT_NONE) {
+ data++;
+ }
+ }
+ return data; /* count */
+ }
+ if ((unsigned) data >= plst->break_alloc) {
+ /* out of range */
+ setErrno(EFAULT); /* closest match */
+ return -1;
+ }
+ /* get it and say which is next */
+ *bkpt = plst->break_list[data];
+ for (idx = (int)data+1; idx < (int)plst->break_alloc; idx++) {
+ if (plst->break_list[idx].type != BRKT_NONE) {
+ return idx;
+ }
+ }
+ return 0; /* otherwise returns 0 for no more */
+}
+
+/*----- Clearing bkpts -----*/
+
+ /*
+ * BreakClear - clear one (if data != 0) or all breakpoints
+ * (if data == 0). Return the number of bkpts cleared.
+ * If (data == -1), remove step-emulation breakpoints.
+ */
+
+ int
+BreakClear (PID_LIST* plst, int conn_idx, int data)
+{
+ int pid_idx = plst - pid_list;
+ int idx;
+ int cleared = 0;
+ int clearStepEmul = 0;
+ int terminated = PROC_TERMINATED (plst);
+ int stepEmulCount = 0;
+
+ /* break handle in data */
+ if (!plst->break_alloc) { /* there are no breaks */
+ DPRINTF (("BreakClear: no bkpts defined.\n"));
+ setErrno(EFAULT); /* closest match */
+ return -1; /* return error */
+ }
+ if (!data) { /* clear all */
+ idx = 1;
+ data = plst->break_alloc-1;
+
+ /* Inform other owners */
+ DPRINTF (("BreakClear: clearing all bkpts.\n"));
+ TgtNotifyAll (pid_idx, BMSG_BREAK, 0 /*clr*/, 0, conn_idx, False);
+
+ } else if (data == -1) { /* clear all step-emul bkpts */
+ DPRINTF(("BreakClear: removing %d step-emul bkpts\n",
+ BKPT0 (plst)->pad1));
+
+ stepEmulCount = BKPT0 (plst)->pad1;
+ BKPT0 (plst)->pad1 = 0;
+
+ clearStepEmul = 1;
+ idx = 1;
+ data = plst->break_alloc-1;
+ } else if ((unsigned) data >= plst->break_alloc
+ || plst->break_list[data].type == BRKT_NONE) {
+
+ /* out of range */
+ DPRINTF (("BreakClear: invalid bkpt %d\n", data));
+ setErrno(EFAULT); /* closest match */
+ return -1; /* return error */
+ } else {
+ idx = data;
+ /* Inform other owners */
+ TgtNotifyAll (pid_idx, BMSG_BREAK, 0 /*clr*/, idx, conn_idx, False);
+ DPRINTF (("BreakClear: clearing bkpt %d\n", data));
+ }
+
+ for (; idx <= data; idx++) { /* clear each one */
+ int type = plst->break_list[idx].type;
+
+ if (clearStepEmul && type != BRKT_STEPEMUL) continue;
+
+ if (type == BRKT_INSTR || (clearStepEmul && type == BRKT_STEPEMUL)) {
+ /* just patch back */
+ char* addr = (char *)plst->break_list[idx].ee_loc;
+ int val;
+
+ if (BKPT0 (plst)->clr_step && BKPT0 (plst)->last_break == idx) {
+ BKPT0 (plst)->clr_step = 0; /* not needed */
+ }
+ /* Neighboring bytes can have breakpoints too... */
+ if (! terminated) {
+ setErrno (0);
+ val = TgtPtrace(RPT_PEEKTEXT, plst->pid, addr, 0, NULL);
+ if (getErrno()) {
+ DPRINTF (("BreakClear: addr %x not readable!\n", addr));
+ setErrno (0); /* Forget bkpt */
+ } else {
+ assert (IS_BREAK (val));
+ val = ORG_BREAK (val, (int)plst->break_list[idx].ee_type);
+ TgtPtrace(RPT_POKETEXT, plst->pid, addr, val, NULL);
+ if (getErrno()) {
+ DPRINTF (("BreakClear: addr %x not writable!\n", addr));
+ setErrno (0);
+ }
+ }
+ }
+ ++cleared; /* indicate cleared */
+ }
+ memset(&plst->break_list[idx], 0, sizeof(xdr_break));
+ }
+ assert (!clearStepEmul || cleared <= stepEmulCount);
+ if (stepEmulCount && cleared == 0) {
+ DPRINTF (("BreakClear: all STEPEMUL bkpts were shared\n"));
+ return 1;
+ }
+ return cleared;
+}
+
+/*----- Hiding of breakpoints -----*/
+
+ /*
+ * PatchBreak - patch original data from break into data buffer.
+ *
+ * Notes:
+ * - this routine patches the original data under a break into the data
+ * buffer from a ptrace read/peek.
+ */
+
+ static void
+PatchBreak (char* buff, UINT32 bstart, int bsize, UINT32 dstart, char* dvalue)
+{
+ int size = BREAK_SIZE; /* default size */
+
+ /* Must deal with all sorts of unalignments
+ * (3 full overlaps, 3 unaligns)
+ */
+ if (bsize < BREAK_SIZE) {
+ /* case where buffer is smaller than data */
+ memcpy(buff, dvalue+(bstart-dstart), bsize); /* copy over */
+ return;
+ }
+ /* buffer larger than data.
+ * we need to see where break fits in buffer and whether
+ * we have part of it off the end. We set bstart to be the
+ * buffer offset, dtart to be the break data offset, and
+ * size to be the amount to copy
+ */
+ if (dstart < bstart) {
+ /* break before actual buffer */
+ dstart = bstart-dstart; /* offset in data */
+ size -= dstart; /* amount to copy */
+ bstart = 0; /* offset in buffer */
+
+ } else if (dstart + size > bstart + bsize) {
+ /* off end */
+ bstart += bsize; /* end of buffer */
+ size -= (dstart + size) - bstart;
+ bstart = bsize - size; /* come back into buffer enough */
+ dstart = 0; /* start of data */
+
+ } else { /* normal case */
+ bstart = dstart - bstart; /* offset in buffer */
+ dstart = 0;
+ }
+ memcpy(buff+bstart, dvalue+dstart, size);
+}
+
+ void
+BreakHide (const PID_LIST* plst, void* addr, int data, void* addr2)
+{
+ int idx;
+
+ if (!plst->break_list) /* no breaks exist, so skip this */
+ return;
+
+ /* if breakpoints, replace */
+
+ for (idx = 1; idx < (int)plst->break_alloc; idx++) {
+ int type = plst->break_list[idx].type;
+
+ if (type != BRKT_INSTR && type != BRKT_STEPEMUL) {
+ continue;
+ }
+ /* break, see if overlaps */
+ if (BKPT_OVER (plst, idx, addr, data)) {
+
+ /* overlaps, patch in old value */
+ PatchBreak((char *)addr2, (UINT32)addr, data,
+ plst->break_list[idx].ee_loc,
+ (char *)&plst->break_list[idx].ee_type);
+ }
+ }
+}
+
+/*----- Checking of breakpoint overwrites -----*/
+
+ /*
+ * BreakOverwrite - check if memory write does not involve addresses
+ * having software breakpoints.
+ */
+
+ int
+BreakOverwrite (const PID_LIST* plst, const char* addr, unsigned int size)
+{
+ int idx;
+
+ if (!plst->break_list) { /* No breaks exist */
+ return 0;
+ }
+
+ for (idx = 1; idx < (int)plst->break_alloc; idx++) {
+ int type = plst->break_list[idx].type;
+
+ /* Consider only breakpoints involving modified memory */
+ if (type != BRKT_INSTR && type != BRKT_STEPEMUL) {
+ continue;
+ }
+ if (BKPT_OVER (plst, idx, addr, size)) {
+ return -1; /* overlaps */
+ }
+ }
+ return 0;
+}
+
+/*----- Execution support -----*/
+
+ /*
+ * BreakStepRange - Start stepping in a range.
+ *
+ * Range is saved in breakpoint 0.
+ */
+
+ int
+BreakStepRange (PID_LIST* plst, void* addr, int len)
+{
+ if (!plst->break_list) {
+ /* get list */
+ if (BreakAlloc (plst, False) == -1) { /* must not be any memory */
+ setErrno(ENOMEM); /* to be safe */
+ return -1; /* fails */
+ }
+ }
+ BKPT0 (plst)->range_start = (UINT32)addr;
+ BKPT0 (plst)->range_end = (UINT32)addr+(len-1);
+ return 0;
+}
+
+ /*
+ * If the Program Counter is changed, consider that the
+ * current breakpoint has not been reached yet.
+ */
+
+ void
+BreakPcChanged (PID_LIST* plst)
+{
+ if (plst->break_list) {
+ /* clear break stuff */
+ BKPT0 (plst)->clr_step = False;
+ }
+}
+
+ /*
+ * BreakStepOff - prepare stepping off a breakpoint.
+ */
+
+ int
+BreakStepOff (const PID_LIST* plst, void** paddr2)
+{
+ if (plst->break_list && BKPT0 (plst)->clr_step) {
+
+ /* need clear then step off break */
+ int last = BKPT0 (plst)->last_break;
+
+ /* clear break, step, then do exec */
+
+ *paddr2 = (void*) plst->break_list[last].ee_type;
+
+ /* Need to clr_step after TgtPtrace() when wait() returns */
+ return 1;
+ }
+ return 0;
+}
+
+ /*
+ * BreakSteppedOff - check if just stepped off a breakpoint
+ * and re-insert it into the code.
+ */
+
+ void
+BreakSteppedOff (PID_LIST* plst)
+{
+ if (plst->break_list && BKPT0 (plst)->clr_step) {
+ int idx = BKPT0 (plst)->last_break;
+ int data;
+
+ BKPT0 (plst)->clr_step = 0;
+
+ /*
+ * Re-insert the breakpoint.
+ */
+ data = TgtPtrace (RPT_PEEKTEXT, plst->pid,
+ (char *)plst->break_list [idx].ee_loc, 0, NULL);
+ assert (! IS_BREAK (data));
+ TgtPtrace (RPT_POKETEXT, plst->pid,
+ (char *)plst->break_list[idx].ee_loc,
+ (int) SET_BREAK (data), NULL);
+ }
+}
+
+
+ /*
+ * Returns whether a thread matches a breakpoint.
+ */
+
+ static int
+BreakThreadMatch (xdr_break* xb, int thread)
+{
+ int slot;
+
+ if (thread < 0) return 1; /* Break existence check only */
+
+ if (xb->thread_list [0] == 0) return 1; /* Universal break */
+
+ for (slot = 0; slot < BKPT_SLOTS; ++slot) {
+ if (xb->thread_list [slot] == 0) return 0; /* End of list */
+ if (xb->thread_list [slot] == thread) return 1; /* Match */
+ }
+ return 0; /* No matches found */
+}
+
+
+int
+BreakAdjustPC (PID_LIST* plst)
+{
+ /*
+ * BREAK_ADJ is the value by which the Program Counter
+ * has to be decremented after a software breakpoint
+ * is hit. It must be defined and can be zero.
+ */
+#if BREAK_ADJ
+ /* subtract back if necessary */
+ plst->regs.REG_PC -= BREAK_ADJ; /* now write back */
+ TgtPtrace(RPT_SETREGS, plst->pid, (char *)&plst->regs, 0, NULL);
+#else
+ (void) plst;
+#endif
+ return 0;
+}
+
+
+/*
+ * Identify the current breakpoint. The process just stopped.
+ */
+
+ int
+BreakIdentify (PID_LIST* plst, int adjust, int thread)
+{
+ int foreignBkpt = 0;
+ int bidx;
+
+ for (bidx = 1; bidx < (int) plst->break_alloc; bidx++) {
+ int type = plst->break_list[bidx].type;
+
+ if ((type == BRKT_INSTR || type == BRKT_STEPEMUL)
+ && plst->regs.REG_PC - BREAK_ADJ
+ == plst->break_list[bidx].ee_loc) { /* found matching */
+ if (!BreakThreadMatch (&plst->break_list[bidx], thread)) {
+ if (foreignBkpt == 0) {
+ foreignBkpt = bidx;
+ }
+ continue;
+ }
+ if (adjust) {
+ BreakAdjustPC (plst);
+ }
+ return bidx;
+ }
+ }
+ if (foreignBkpt) {
+ if (adjust) {
+ BreakAdjustPC (plst);
+ }
+ return -foreignBkpt;
+ }
+ return 0;
+}
diff --git a/c/src/lib/librdbg/servcon.c b/c/src/lib/librdbg/servcon.c
new file mode 100644
index 0000000000..a26bfd2c7b
--- /dev/null
+++ b/c/src/lib/librdbg/servcon.c
@@ -0,0 +1,136 @@
+/*
+ **************************************************************************
+ *
+ * Component: RDBG
+ * Module: servcon.c
+ *
+ * Synopsis: Management of RPC client connections.
+ *
+ **************************************************************************
+ */
+
+#include <sys/errno.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/servrpc.h>
+
+ /*
+ * ConnCreate - create a new connection entry for a client.
+ *
+ * This function finds an empty entry in the connection array
+ * or makes space. It fills in the fields that are passed to it.
+ * It does not do any validation on net addresses nor does it
+ * start a validation cycle on other clients. This is done by
+ * the caller.
+ */
+
+ int
+ConnCreate (struct svc_req* rqstp, open_in* in)
+{
+ NET_OPAQUE sender;
+ int idx;
+ CONN_LIST* clst;
+
+ setErrno (0);
+
+ /* Convert to valid Net address */
+ if (! TspTranslateRpcAddr (rqstp, &sender)) {
+ DPRINTF (("ConnCreate: TspTranslateRpcAddr failed\n"));
+ return -1;
+ }
+ if (! TspValidateAddr ((NET_OPAQUE*) in->back_port, &sender)) {
+ DPRINTF (("ConnCreate: TspValidateAddr failed\n"));
+ return -1; /* errno now setup with error */
+ }
+
+ /* look for an empty connection entry */
+ for (idx = 0; idx < conn_list_cnt; idx++) {
+ if (!conn_list[idx].in_use)
+ break; /* an empty one found */
+ }
+
+ if (idx >= conn_list_cnt) { /* no empties, create space */
+ CONN_LIST* tmp_conn_list = conn_list;
+
+ conn_list_cnt += CONN_LIST_INC;
+ if (conn_list) {
+ conn_list = (CONN_LIST *) Realloc (conn_list, /* extend */
+ conn_list_cnt * sizeof (CONN_LIST));
+ } else {
+ conn_list = (CONN_LIST *)Malloc(conn_list_cnt * sizeof(CONN_LIST));
+ }
+
+ if (!conn_list) { /* unable to get space */
+ if ((conn_list_cnt -= CONN_LIST_INC)) {
+ /* was realloc, restore space */
+ conn_list = tmp_conn_list;
+ }
+ return -1; /* errno set by failed alloc */
+ }
+ /* clear newly created memory */
+ memset (conn_list + idx, 0, CONN_LIST_INC * sizeof (CONN_LIST));
+ } else { /* clear new entry */
+ memset (conn_list + idx, 0, sizeof (CONN_LIST));
+ }
+ clst = conn_list + idx;
+
+ clst->in_use = True; /* now in use */
+ clst->sender = sender;
+ memcpy (&clst->back_port, &in->back_port, sizeof (NET_OPAQUE));
+ memcpy (&clst->route, &in->destination, sizeof (NET_OPAQUE));
+ clst->debug_type = (UCHAR) in->debug_type;
+ clst->flags = in->flags;
+ strncpy (clst->user_name, in->user_name, NAMEMAX-1);
+ clst->user_name [NAMEMAX-1] = 0;
+
+ return idx;
+}
+
+ /*
+ * ConnDelete - remove connection entry when shutdown.
+ *
+ */
+
+ void
+ConnDelete (int conn, struct svc_req* rqstp, close_control control)
+{
+ CONN_LIST* clst = conn_list + conn;
+ int idx;
+ Boolean prim;
+
+ if (! clst->in_use) return; /* not active */
+
+ for (idx = 0; idx < pid_list_cnt; idx++) {
+ PID_LIST* plst = pid_list + idx;
+
+ if (! PIDMAP_TEST (conn, idx)) continue;
+
+ /* found a controlled pid */
+ prim = (plst->primary_conn == conn) ? True : False;
+ TgtDetachCon (conn, idx, True);
+
+ /* if still running or alive, we use close control on it */
+ if (! plst->pid)
+ continue; /* entry gone */
+
+ if (prim && control == CLOSE_KILL) {
+ /* kill off process */
+ TgtKillAndDelete (plst, rqstp, True);
+ } else if (! plst->owners) {
+ /* no owners left */
+ if (control == CLOSE_DETACH) {
+ TgtKillAndDelete (plst, rqstp, False);
+ }
+ if (control == CLOSE_DETACH || PROC_TERMINATED (plst)) {
+ TgtDelete (plst, conn, (control==CLOSE_DETACH) ?
+ BMSG_DETACH : 0);
+ }
+ }
+ }
+ if (clst->list) {
+ Free (clst->list); /* free allocated memory */
+ }
+ DPRINTF (("ConnDelete: Connection closed for port %u\n",
+ HL_W(*((UINT16*) &clst->back_port.c[2]))));
+
+ clst->in_use = False; /* free it back */
+}
diff --git a/c/src/lib/librdbg/servrpc.c b/c/src/lib/librdbg/servrpc.c
new file mode 100644
index 0000000000..f62a2ecbb8
--- /dev/null
+++ b/c/src/lib/librdbg/servrpc.c
@@ -0,0 +1,720 @@
+/*
+ **********************************************************************
+ *
+ * Component: RDBG
+ * Module: servrpc.c
+ *
+ * Synopsis: support routines for RPC dispatch for remote debug server.
+ * Main server dispatch routines from RPC to support remote debug.
+ *
+ **********************************************************************
+ */
+
+#include <string.h>
+#include <sys/errno.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/remdeb.h>
+#include <rdbg/servrpc.h>
+
+/************************************************************************/
+
+/* -----------------------------------------------------------------------
+ open_connex_2_svc - setup a new connection from a client.
+
+ Notes:
+ - this function creates a new connection to a client. It allocates
+ an entry in the connection structure and fills in the information
+ sent and implied by the message.
+ - a client connection entry is needed for all further messages to work
+ properly.
+ ----------------------------------------------------------------------- */
+
+open_out* RPCGENSRVNAME(open_connex_2_svc) (open_in *in, struct svc_req *rqstp)
+{
+ static open_out out; /* output response. This could be heap local */
+ int idx;
+ static int one_time = 0; /* we do one-time setup on back port */
+
+ /* need to support in->debug_type, in->flags, and in->destination!!! */
+
+ if (!one_time)
+ { /* only setup one backport socket */
+ /* now setup signals and the like for handling process changes */
+ setErrno(0);
+ TspInit(rqstp->rq_xprt->xp_sock); /* init transport system */
+ if (getErrno())
+ { /* failed in setup */
+ out.port = (u_long)-1;
+ out.fp = getErrno(); /* error causing to fail */
+ return(&out); /* fail */
+ }
+ one_time = True; /* disable doing this again */
+ }
+
+ DPRINTF(("open_connex_2_svc: Opening connection from '%s'\n",
+ in->user_name));
+
+ /* now setup a validation of all other connections */
+ for (idx = 0; idx < conn_list_cnt; idx++)
+ if (conn_list[idx].in_use)
+ { /* setup retry timer */
+ DPRINTF(("open_connex_2_svc: Still have connection %d with port %d\n",
+ idx, HL_W(*((UINT16*)&conn_list[idx].back_port.c[2]))));
+ }
+
+ idx = ConnCreate(rqstp, in); /* setup the connection */
+ out.port = idx; /* connection number */
+ if (idx == -1)
+ out.fp = getErrno(); /* error causing to fail */
+ else
+ out.fp = TARGET_PROC_TYPE;
+
+ out.server_vers = SERVER_VERS;
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ send_signal_2_svc - send a kill/signal to the specified process.
+
+ Notes:
+ - this function sends a signal to the process specified. This process
+ does not have to be under debug nor attached by this server. The kill
+ may be refused on other grounds though.
+ - kill(pid, 0) can be used to validate the process still exists if
+ needed.
+ ----------------------------------------------------------------------- */
+
+signal_out *RPCGENSRVNAME(send_signal_2_svc) (signal_in *in, struct svc_req *rqstp)
+{
+ static signal_out out; /* return code from kill */
+
+ /* we do not care if connected */
+ setErrno(0);
+ out.kill_return = 0;
+ out.errNo = 0;
+ TotalReboot = 1;
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ close_connex_2_svc - close a connection from a client.
+ ----------------------------------------------------------------------- */
+
+void *RPCGENSRVNAME(close_connex_2_svc) (close_in *in, struct svc_req *rqstp)
+{
+ int conn_idx = TspConnGetIndex(rqstp);
+
+ if (conn_idx != -1) /* found it, clear out */
+ ConnDelete(conn_idx, rqstp, in->control);
+
+ return (void*) ""; /* need to return something */
+}
+
+/* -----------------------------------------------------------------------
+ ptrace_2_svc - control process under debug.
+ ----------------------------------------------------------------------- */
+
+#define REG_COUNT \
+ (sizeof (xdr_regs) / sizeof (int))
+
+ptrace_out *RPCGENSRVNAME(ptrace_2_svc) (ptrace_in *in, struct svc_req *rqstp)
+{
+ int conn_idx = rqstp ? TspConnGetIndex(rqstp) : -1;
+ static ptrace_out out; /* outut response (error or data) */
+ void *addr, *addr2; /* used for actual ptrace call */
+ unsigned int data;
+ int req, pid, ret, pid_idx, idx;
+ static union
+ { /* local buffer for returned data */
+ Objects_Id t_list[UTHREAD_MAX]; /* thread_list return */
+ char t_name[THREADNAMEMAX]; /* thread name return */
+ } local_buff; /* for return handling of strings and the like */
+ PID_LIST *plst = NULL; /* current pid_list entry */
+
+ DPRINTF (("ptrace_2_svc: entered (%s (%d), %d, XXXX, %d, XXXX)\n",
+ PtraceName (in->addr.req), in->addr.req, in->pid,
+ in->data));
+
+ out.addr.ptrace_addr_data_out_u.addr = 0;
+
+ /* validate the connection */
+ if (conn_idx == -1 && rqstp != NULL)
+ { /* no connection, error */
+ DPRINTF(("ptrace_2_svc: msg from unknown debugger!\n"));
+ out.result = -1;
+ out.errNo = ECHILD; /* closest error */
+ out.addr.req = 0; /* to avoid copies that should not occur */
+ return(&out);
+ }
+ /* Consider that the last back-message is acknowledged */
+ if (conn_idx >= 0 && conn_list[conn_idx].retry) {
+ TspMessageReceive(conn_idx, in->pid);
+ }
+
+ req = in->addr.req;
+ out.addr.req = req; /* needed for RPC */
+ pid = in->pid;
+ addr = addr2 = NULL;
+ data = in->data;
+ setErrno(0); /* assume works */
+ out.result = 0; /* assume worked ok */
+ out.errNo = 0;
+
+ /* lookup process to make sure we have under control */
+ pid_idx = FindPidEntry (in->pid);
+ if (pid_idx >= 0) /* found it */
+ {
+ plst = &pid_list[pid_idx];
+ if (conn_idx < 0)
+ conn_idx = plst->primary_conn;
+ }
+
+ /* now we handle the special case of ATTACH to a pid we already control */
+ if (req == RPT_ATTACH)
+ { /* look it up first */
+ if (plst)
+ { /* we have controlled , so return ok+show conn */
+ ret = 2; /* normally secondary connection */
+ if (! PIDMAP_TEST (conn_idx, pid_idx))
+ { /* mark as an owner if not already */
+ plst->owners++;
+ PIDMAP_SET (conn_idx, pid_idx); /* mask in */
+ }
+ else if (plst->primary_conn != NO_PRIMARY)
+ { /* regrab makes primary */
+ /* Only if not primary already */
+ if (plst->primary_conn != conn_idx) {
+ TspSendWaitChange(plst->primary_conn, BMSG_NOT_PRIM,
+ conn_idx, plst->pid, 0, False); /* tell old owner */
+ }
+ plst->primary_conn = NO_PRIMARY;
+ }
+
+ if (plst->primary_conn == NO_PRIMARY)
+ { /* none now, so take over */
+ plst->primary_conn = conn_idx; /* new primary */
+ ret = 1; /* primary */
+ }
+ out.result = ret; /* primary or secondary owner */
+ return(&out);
+ }
+ /* else attach process using target code */
+ setErrno(ESRCH); /* assume the worst */
+ if (!TgtAttach(conn_idx, pid))
+ { /* failed */
+ out.errNo = getErrno();
+ out.result = 0;
+ }
+ return(&out);
+ }
+ else if (req == RPT_DETACH)
+ { /* see which kind of detach */
+ if (data == PTRDET_UNOWN)
+ { /* only want to disconnect from */
+ TgtDetachCon(conn_idx, pid_idx, True); /* remove from control */
+ return(&out); /* done */
+ }
+ }
+ else if (plst && (req == RPT_GETNAME || req == RPT_GETBREAK))
+ {
+ /* do nothing */
+ }
+
+ else if (plst && req == RPT_CLRBREAK) {
+ /* To be able to remove breakpoints from a "running" system */
+ DPRINTF (("ptrace_2_svc: allowing RPT_CLRBREAK %d\n", data));
+ /* do nothing */
+ }
+
+ else if (plst && plst->running)
+ { /* error, process is running and not detach */
+ out.result = -1;
+ out.errNo = ETXTBSY; /* closest error */
+ DPRINTF (("ptrace_2_svc: failed, still running.\n"));
+ return(&out);
+ }
+ if (plst == NULL) {
+ out.result = -1;
+ out.errNo = ESRCH;
+ DPRINTF (("ptrace_2_svc: No such process.\n"));
+ return (&out);
+ }
+
+ /* now make sure secondary owner is not trying to modify */
+ if (!(in->flags & PTRFLG_NON_OWNER)) /* if not overriden */
+ if (conn_idx != plst->primary_conn
+ && ( (req >= RPT_POKETEXT && req <= RPT_SINGLESTEP)
+ || (req >= RPT_SETREGS && req <= RPT_SETFPAREGS && (req & 1))
+ || (req >= RPT_SYSCALL && req <= RPT_DUMPCORE)
+ || (req >= RPT_SETTARGETTHREAD && req <= RPT_THREADRESUME)
+ || (req >= RPT_SETTHREADNAME && req <= RPT_SETTHREADREGS)
+ || (req >= RPT_STEPRANGE && req <= RPT_CLRBREAK)
+ || (req == RPT_STOP)
+ || (req >= RPT_PSETREGS && req <= RPT_PSETTHREADREGS)))
+ { /* not owner */
+ out.result = -1;
+ out.errNo = EPERM; /* cannot alter as not primary */
+ DPRINTF (("ptrace_2_svc: refused, not owner, flags %d conn_idx %d primary_conn %d\n", in->flags, conn_idx,
+ plst->primary_conn));
+ return(&out);
+ }
+
+ addr = (void *)in->addr.ptrace_addr_data_in_u.address; /* default */
+ /* now setup normal ptrace request by unpacking. May execute here. */
+ switch (req)
+ { /* handle unpacking or setup for real call */
+ /* first the ones where addr points to input data */
+ case RPT_SETREGS:
+ case RPT_SETTHREADREGS:
+ addr = (void *)&in->addr.ptrace_addr_data_in_u.regs; /* reg list */
+ break;
+
+ case RPT_PSETREGS:
+ case RPT_PSETTHREADREGS:
+ if (in->addr.ptrace_addr_data_in_u.pregs.pregs_len != REG_COUNT) {
+ DPRINTF(("ptrace_2_svc: pid %d got %d expected %d\n", pid,
+ in->addr.ptrace_addr_data_in_u.pregs.pregs_len, REG_COUNT));
+ setErrno(EINVAL);
+ break;
+ }
+ req = req == RPT_PSETREGS ? RPT_SETREGS : RPT_SETTHREADREGS;
+ addr = (void *) in->addr.ptrace_addr_data_in_u.pregs.pregs_val;
+ break;
+
+ case RPT_SETTHREADNAME:
+ addr = (void *)in->addr.ptrace_addr_data_in_u.name;
+ break;
+ case RPT_WRITETEXT:
+ case RPT_WRITEDATA:
+ if ((int) data < 0) {
+ setErrno(EINVAL);
+ break;
+ }
+ addr = (void *)in->addr.ptrace_addr_data_in_u.mem.addr; /* targ addr */
+ addr2 = (void *)in->addr.ptrace_addr_data_in_u.mem.data; /* buff */
+
+ /* Forbid writing over breakpoints */
+ if (BreakOverwrite (plst, addr, data)) {
+ setErrno(EBUSY);
+ }
+ break;
+
+ case RPT_POKETEXT:
+ case RPT_POKEDATA:
+ /* Forbid writing over breakpoints */
+ if (BreakOverwrite (plst, addr, sizeof (int))) {
+ setErrno(EBUSY);
+ }
+ break;
+
+ /* now ones where we handle locally */
+ case RPT_GETTARGETTHREAD:
+ out.result = plst->thread;
+ req = 0; /* force exit */
+ break;
+
+ case RPT_PGETREGS: /* return from our buffer */
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT;
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_val = (u_int*) &plst->regs;
+ req = 0; /* force exit */
+ break;
+
+ case RPT_GETREGS:
+ /* return directly from our buffer */
+ /* this buffer is refreshed when changing target thread */
+ out.addr.ptrace_addr_data_out_u.regs = plst->regs;
+ req = 0; /* force exit */
+ break;
+
+ case RPT_SETBREAK:
+ idx = BreakSet (plst, conn_idx, &in->addr.ptrace_addr_data_in_u.breakp);
+ if (idx < 0) break;
+ req = 0; /* force exit */
+ out.result = idx; /* return break index (>0) */
+ break;
+
+ case RPT_CLRBREAK:
+ if (conn_list[conn_idx].flags & DEBUGGER_IS_GDB) {
+ data = BreakGetIndex (plst, addr);
+ }
+ out.result = BreakClear (plst, conn_idx, data);
+ /* if errored, errno will still be set */
+ req = 0;
+ break;
+
+ case RPT_GETBREAK:
+ /* data=handle, addr=in_buffer, returns next break. Data=0, returns cnt */
+ out.result = BreakGet (plst, data, &out.addr.
+ ptrace_addr_data_out_u.breakp);
+ req = 0; /* handle locally */
+ break;
+
+ case RPT_GETNAME: /* get the name of the process */
+ if (!plst->name)
+ out.addr.ptrace_addr_data_out_u.mem.dataNb = 0;
+ else
+ {
+ int maxLen = sizeof out.addr.ptrace_addr_data_out_u.mem.data - 1;
+ data = strlen(plst->name);
+ if (data > maxLen)
+ data = maxLen;
+ out.addr.ptrace_addr_data_out_u.mem.dataNb = data+1;
+ memcpy(out.addr.ptrace_addr_data_out_u.mem.data, plst->name, data+1);
+ out.addr.ptrace_addr_data_out_u.mem.data [maxLen] = '\0';
+ }
+ req = 0;
+ break;
+
+ case RPT_CONTTO:
+ if (BreakSetAt (plst, conn_idx, (u_long) addr, BRKT_STEPEMUL) < 0)
+ {
+ DPRINTF(("ptrace_2_svc: BreakSet failed at %x", addr));
+ break;
+ }
+ req = RPT_CONT;
+ /* data can contain a signal number, addr2 is unused */
+ goto case_RPT_CONT;
+
+ case RPT_STEPRANGE:
+ /* convert to step */
+ if (!data)
+ data = 1; /* should we give an error?? */
+ BreakStepRange (plst, addr, data);
+ if (getErrno()) break;
+
+ req = RPT_SINGLESTEP; /* do by stepping */
+ addr = (void*) 1; /* start from current PC */
+ data = -2; /* want non-atomic stepping */
+ /* fall through to other exec cases */
+
+ case RPT_CONT:
+ case_RPT_CONT:
+ case RPT_SINGLESTEP:
+
+ if (BreakStepOff (plst, &addr2))
+ { /* need clear then step off break */
+ /* clear break, step, then do exec */
+ if (addr == (void*) 1)
+ addr = (void*) plst->regs.REG_PC;/* need for patch */
+
+ /* data is always 0, so atomic single-step */
+ } else if (req == RPT_SINGLESTEP) {
+ data = -2; /* want non-atomic stepping */
+ }
+ break;
+
+ /* now ones where addr points to an output area */
+ case RPT_PGETTHREADREGS:
+ addr = (void*) out.addr.ptrace_addr_data_out_u.mem.data;
+ if (sizeof out.addr.ptrace_addr_data_out_u.mem.data <
+ REG_COUNT * sizeof(int)) {
+ setErrno(EINVAL);
+ break;
+ }
+ if (data == plst->thread) {
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT;
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_val = (u_int*) &plst->regs;
+ req = 0; /* force exit */
+ break;
+ }
+ req = RPT_GETTHREADREGS;
+ break;
+
+ case RPT_GETTHREADREGS:
+ addr = (void*) &out.addr.ptrace_addr_data_out_u.regs;
+ break;
+ case RPT_GETTHREADNAME:
+ out.addr.ptrace_addr_data_out_u.name = local_buff.t_name;
+ addr = (void*) out.addr.ptrace_addr_data_out_u.name;
+ break;
+ case RPT_THREADLIST:
+ out.addr.ptrace_addr_data_out_u.threads.threads =(ptThreadList) local_buff.t_list;
+ addr = (void*) out.addr.ptrace_addr_data_out_u.threads.threads;
+ break;
+ case RPT_READTEXT:
+ case RPT_READDATA:
+ if ((int) data < 0) {
+ setErrno(EINVAL);
+ break;
+ }
+ addr = (void *)in->addr.ptrace_addr_data_in_u.address;
+ addr2 = (void *)out.addr.ptrace_addr_data_out_u.mem.data;
+ out.addr.ptrace_addr_data_out_u.mem.dataNb = data;
+ break;
+ case RPT_DETACH:
+ /* Do not allow detaching if breakpoints still there */
+ if (BreakGet (plst, 0, NULL))
+ { /* some bkpts still set */
+ setErrno(EINVAL); /* cannot detach safely */
+ break;
+ }
+ /* fall through */
+ case RPT_KILL:
+ /* in the event they are trying to detach or kill a terminated process,
+ we just delete the entry. */
+ if (PROC_TERMINATED (plst))
+ {
+ TgtDelete(plst, -1, BMSG_KILLED); /* just blow off */
+ req = 0; /* now exit */
+ }
+ break;
+ }
+
+ if (getErrno())
+ { /* failed in code above */
+ out.result = -1;
+ out.errNo = getErrno();
+ DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo));
+ return(&out);
+ }
+ else if (!req)
+ { /* bail out now */
+ DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo));
+ return(&out);
+ }
+
+ /* OK, make the call */
+ out.result = TgtPtrace(req, pid, addr, data, addr2);
+ out.errNo = getErrno();
+
+ /* if no error, cleanup afterwards */
+ if (getErrno())
+ {
+ /* Remove step-emul breakpoints if any */
+ if (req == RPT_SINGLESTEP || req == RPT_CONT) {
+ BreakClear (plst, -1, -1);
+ }
+ DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo));
+ return(&out); /* return error */
+ }
+
+ switch (in->addr.req)
+ { /* handle some special calls that affect state */
+ case RPT_CONT:
+ case RPT_STEPRANGE:
+ /* change to running */
+ if (in->addr.req == RPT_STEPRANGE)
+ plst->last_start = LAST_RANGE; /* so range steps */
+ else if (addr2)
+ plst->last_start = LAST_STEPOFF; /* now continue after wait */
+ else
+ plst->last_start = LAST_CONT;
+ plst->running = 1; /* mark as running */
+ if (!rqstp) /* Called internally to restart bkpt, no msg to anybody */
+ break;
+ TgtNotifyAll(pid_idx, BMSG_WAIT, 0, 0, (in->flags & PTRFLG_NON_OWNER)
+ ? -1 : conn_idx, True);
+ break;
+ case RPT_SINGLESTEP:
+ /* mark as step */
+ plst->last_start = LAST_STEP; /* so we know how started */
+ plst->running = 1; /* mark as running (wait should catch fast) */
+ break;
+ case RPT_DETACH: /* mark as disconnected */
+ case RPT_KILL: /* mark as killed */
+ if (in->flags & PTRFLG_FREE) /* notify and delete entry */
+ TgtDelete(plst, -1, (in->addr.req==RPT_KILL) ? BMSG_KILLED : BMSG_DETACH);
+ else
+ { /* notify and mark */
+ plst->last_start = (in->addr.req==RPT_KILL) ?
+ LAST_KILLED : LAST_DETACHED;
+ plst->state = -1;
+ plst->running = False;
+ TgtNotifyAll(pid_idx, (in->addr.req==RPT_KILL) ?
+ BMSG_KILLED : BMSG_DETACH, 0, 0, -1, True);
+ }
+ break;
+ case RPT_SETTHREADREGS:
+ case RPT_PSETTHREADREGS:
+ if (data != plst->thread)
+ break;
+ DPRINTF(("ptrace_2_svc: pid %d target thread regs changed!\n", pid));
+
+ case RPT_SETREGS:
+ case RPT_PSETREGS:
+ /* change our buffer as well */
+ if (plst->regs.REG_PC != ((xdr_regs*)addr)->REG_PC)
+ BreakPcChanged (plst);
+ plst->regs = *(xdr_regs*) addr; /* copy in */
+ break;
+
+ /* case RPT_PGETREGS has been handled locally above */
+ case RPT_PGETTHREADREGS:
+ /* We need to update pointer so that XDR works on return */
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT;
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_val =
+ (void*) out.addr.ptrace_addr_data_out_u.mem.data;
+ break;
+
+ case RPT_PEEKTEXT:
+ case RPT_PEEKDATA:
+ case RPT_READDATA:
+ case RPT_READTEXT:
+ if (req < RPT_READDATA)
+ { /* peek */
+ /* addr is start */
+ data = sizeof(int);
+ addr2 = &out.result; /* data buffer */
+ /* Like read: addr is start, data is length, addr2 is buffer */
+ }
+ BreakHide (plst, addr, data, addr2);
+ break;
+
+ case RPT_SETTARGETTHREAD:
+ DPRINTF(("ptrace_2_svc: pid %d new target thread %d\n", pid, data));
+ TgtPtrace (RPT_GETREGS, pid, (char*) &plst->regs, 0, NULL);
+ plst->thread = data;
+ if (plst->break_list) { /* Forget we had to step off breakpoint */
+ BASE_BREAK* base = (BASE_BREAK*) plst->break_list;
+ DPRINTF(("ptrace_2_svc: clr_step %d last_break %d\n", base->clr_step,
+ base->last_break));
+ base->clr_step = 0; /* Not stopped on break */
+ base->last_break = 0;
+ }
+ break;
+
+ case RPT_THREADLIST:
+ out.addr.ptrace_addr_data_out_u.threads.nbThread = out.result;
+ break;
+
+ default:
+ break;
+ } /* end switch */
+ DPRINTF(("ptrace_2_svc 2: result %d errNo %d\n", out.result, out.errNo));
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ wait_info_2_svc - non-blocking wait request to check status.
+ ----------------------------------------------------------------------- */
+
+wait_out *RPCGENSRVNAME(wait_info_2_svc) (in, rqstp)
+ wait_in *in;
+ struct svc_req *rqstp; /* server info */
+{
+ int conn_idx = TspConnGetIndex(rqstp);
+ static wait_out out; /* output of pid and status */
+ int idx;
+ PID_LIST *plst;
+
+ memset(&out, 0, sizeof(out)); /* zero for safety */
+ out.reason = STOP_ERROR; /* assume the worst */
+
+ if (conn_idx == -1)
+ { /* no connection, error */
+ DPRINTF(("wait_info_2_svc: msg from unknown debugger!\n"));
+ out.wait_return = -1;
+ out.errNo = ECHILD; /* closest error */
+ return(&out);
+ }
+ else
+ { /* see if confirming message received */
+ if (conn_list[conn_idx].retry)
+ TspMessageReceive(conn_idx, in->pid);
+ }
+
+ if (!in->pid)
+ { /* warm test verify only */
+ /* this call (pid==0) is made to confirm that that connection is still
+ active. */
+ /* we let it fall through as an error since any use other than connection
+ reset would be an error (there is no pid0). */
+ }
+ else
+ { /* normal request */
+ idx = FindPidEntry (in->pid);
+ if (idx >= 0)
+ { /* found process they requested on */
+ plst = &pid_list[idx];
+ out.wait_return = plst->running ? 0 : in->pid;
+ /* return: 0 is running, pid is stopped/term */
+ out.errNo = 0;
+ out.status = plst->state; /* last stopped reason if stopped */
+ out.thread = plst->thread;/* current thread (or -1 if none) from stop */
+ if (!out.wait_return)
+ out.reason = STOP_NONE; /* running, no action */
+ else if (STS_SIGNALLED (out.status))
+ { /* stopped on signal */
+ out.handle = STS_GETSIG (out.status); /* signal number */
+ if (out.handle == SIGTRAP)
+ if (plst->is_step)
+ { /* single step with hitting a break */
+ out.reason = STOP_STEP;
+ out.handle = 0; /* no information */
+ }
+ else
+ { /* stopped on break */
+ out.reason = STOP_BREAK;
+ if (plst->break_list)
+ out.handle = ((BASE_BREAK*)plst->break_list)->last_break;
+ else
+ out.handle = 0; /* no break */
+ }
+ else
+ out.reason = STOP_SIGNAL;
+ out.PC = plst->regs.REG_PC; /* copy standard regs */
+ out.SP = plst->regs.REG_SP;
+ out.FP = plst->regs.REG_FP;
+ }
+ else
+ { /* terminated, so lower use count */
+ if (plst->last_start == LAST_KILLED)
+ out.reason = STOP_KILLED;
+ else if (plst->last_start == LAST_DETACHED)
+ out.reason = STOP_DETACHED;
+ else if (plst->last_start == LAST_START)
+ { /* failed in exec */
+ out.reason = STOP_SPAWN_FAILED;
+ out.handle = STS_GETCODE (out.status); /* errno reason */
+ }
+ else if (STS_TERMONSIG (out.status))
+ { /* terminated on signal */
+ out.reason = STOP_TERM_SIG;
+ /* mask off the core-dumped bit 7 */
+ out.handle = (int)(unsigned)(u_char) STS_TERMGETSIG (out.status);
+ }
+ else
+ { /* exit(2)ed */
+ out.reason = STOP_TERM_EXIT;
+ out.handle = STS_GETCODE (out.status); /* code */
+ }
+ }
+ DPRINTF(("wait_info_2_svc: pid %d return %d status %x errNo %d"
+ " reason %d handle %d pc %x sp %x fp %x thread %d\n",
+ in->pid, out.wait_return, out.status, out.errNo, out.reason,
+ out.handle, out.PC, out.SP, out.FP, out.thread));
+ return(&out);
+ }
+ }
+ /* if not found in list, we return error: no such process */
+ out.wait_return = -1;
+ out.errNo = ESRCH; /* no process */
+ out.status = 0;
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ get_signal_names_2_svc - return names for signals
+ ----------------------------------------------------------------------- */
+
+static one_signal SignalNames[] = {
+ {SIGILL, "SIGILL/EVT_ILL"},
+ {SIGTRAP, "SIGTRAP/EVT_BKPT"},
+ {SIGFPE, "SIGFPE/EVT_FPE"},
+ {SIGKILL, "SIGKILL/EVT_AKILL"},
+ {SIGSEGV, "SIGSEGV/EVT_SEGV"},
+ {17, "SIGSTOP"},
+ {23, "SIGSTOP"}
+};
+
+get_signal_names_out* RPCGENSRVNAME(get_signal_names_2_svc) (in, rqstp)
+ void* in;
+ struct svc_req *rqstp; /* server info */
+{
+ static get_signal_names_out out;
+
+ out.signals.all_signals_len = sizeof SignalNames / sizeof SignalNames[0];
+ out.signals.all_signals_val = SignalNames;
+
+ return(&out);
+}
diff --git a/c/src/lib/librdbg/servtgt.c b/c/src/lib/librdbg/servtgt.c
new file mode 100644
index 0000000000..7a8471e3e2
--- /dev/null
+++ b/c/src/lib/librdbg/servtgt.c
@@ -0,0 +1,550 @@
+/*
+ **************************************************************************
+ *
+ * Component: RDB servers
+ * Module: servtgt.c
+ *
+ **************************************************************************
+ */
+
+
+#include <string.h>
+#include <sys/errno.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/servrpc.h>
+#include <sys/socket.h>
+#include <assert.h>
+
+#ifdef DDEBUG
+#define Ptrace TgtDbgPtrace
+#else
+#define Ptrace TgtRealPtrace
+#endif
+
+/* ----------------------------------------------------------------
+ TgtBreakRestoreOrig - Restore original instruction at "addr"
+ just before single-stepping it.
+ ---------------------------------------------------------------- */
+
+int TgtBreakRestoreOrig (int pid, void *addr, void *addr2)
+ /* Process identifier */
+ /* Breakpoint address */
+ /* Original instruction or bkpt number */
+{
+ int ret;
+ int l;
+
+ l = (long)Ptrace(RPT_PEEKTEXT, pid, addr, 0, NULL); /* assume ok */
+ ret = ORG_BREAK (l, (UINT32) addr2); /* reconstruct old instr */
+ ret = Ptrace(RPT_POKETEXT, pid, addr, ret, NULL); /* poke back old */
+ return ret;
+}
+
+/* -----------------------------------------------------------------------
+ TgtBreakCancelStep - Restore the breakpoint at "addr" if the single-step
+ has failed at the ptrace level.
+ ----------------------------------------------------------------------- */
+
+#define BKPT0(plst) ((BASE_BREAK*)(plst)->break_list)
+
+void TgtBreakCancelStep (PID_LIST* plst)
+{
+ assert (plst->break_list);
+ assert (BKPT0 (plst)->clr_step);
+
+ if (plst->break_list && BKPT0 (plst)->clr_step) {
+ int idx = BKPT0 (plst)->last_break;
+ int data;
+
+ data = Ptrace (RPT_PEEKTEXT, plst->pid,
+ (char *)plst->break_list [idx].ee_loc, 0, NULL);
+ assert (! IS_BREAK (data));
+ Ptrace (RPT_POKETEXT, plst->pid,
+ (char *)plst->break_list[idx].ee_loc,
+ (int) SET_BREAK (data), NULL);
+ }
+}
+
+/* -----------------------------------------------------------------------
+ TgtCreateNew - add a new process into the process management lists.
+ ----------------------------------------------------------------------- */
+
+ void
+TgtCreateNew(PID pid, int conn, INT32 child, char *name, Boolean spawn)
+{
+ int idx;
+
+ for (idx = 0; idx < pid_list_cnt; idx++)
+ if (!pid_list[idx].pid)
+ break; /* find empty */
+
+ if (idx >= pid_list_cnt)
+ { /* no empties, add more */
+ PID_LIST *tmp_pid_list = pid_list;
+
+ pid_list_cnt += PID_LIST_INC;
+ pid_list = (PID_LIST*) Realloc(pid_list, /* get new or extend */
+ pid_list_cnt * sizeof(PID_LIST));
+ if (!pid_list)
+ { /* out of memory */
+ pid_list_cnt -= PID_LIST_INC;
+ if (pid_list_cnt)
+ { /* realloc failed - malloc again */
+ pid_list = tmp_pid_list;
+ /* above relies on old pointer being valid after failed realloc */
+ }
+ return; /* failed */
+ }
+ /* now clear newly added space */
+ memset(pid_list+pid_list_cnt-PID_LIST_INC, 0,
+ PID_LIST_INC * sizeof(PID_LIST));
+ idx = pid_list_cnt - PID_LIST_INC;
+ }
+ else /* clear entry we found */
+ memset(&pid_list[idx], 0, sizeof(PID_LIST));
+
+ /* now fill in empty entry */
+ pid_list[idx].pid = pid;
+ pid_list[idx].running = 1; /* we have not called wait yet */
+ pid_list[idx].primary_conn = (UCHAR)conn; /* primary owner */
+ if (conn != -1)
+ { /* found caller */
+ pid_list[idx].owners = 1;
+ PIDMAP_SET (conn, idx); /* mask in */
+ }
+ pid_list[idx].thread = (UINT32)-1; /* no thread for now */
+ pid_list[idx].last_start = LAST_START; /* handle MiX bug */
+
+ pid_list[idx].name = name ? (char *)StrDup(name) : (char *)NULL;
+
+}
+
+/* -----------------------------------------------------------------------
+ TgtNotifyWaitChange - send event to clients indicating child changed state.
+ ----------------------------------------------------------------------- */
+
+ void
+TgtNotifyWaitChange( PID pid, int status, Boolean exclude)
+{
+ int conn, idx;
+
+ idx = FindPidEntry (pid); /* locate the pid that changed */
+ if (idx < 0)
+ {
+ DPRINTF(("TgtNotifyWaitChange: pid %d not in our list\n",
+ (int) pid));
+ return; /* not in our list */
+ }
+ pid_list[idx].running = 0; /* not running */
+ pid_list[idx].state = status; /* save status of stop/term */
+ if (!pid_list[idx].owners && !STS_SIGNALLED(status))
+ TgtDelete(&pid_list[idx], -1, 0); /* terminated and no owners */
+ else
+ { /* normal cases */
+ for (conn = 0; conn < conn_list_cnt; conn++)
+ { /* now find all interested clients */
+ if (!conn_list[conn].in_use /* free entry */
+ || ! PIDMAP_TEST (conn, idx))
+ continue; /* not using this pid */
+ if (conn == exclude)
+ continue; /* do not do this one */
+ TspSendWaitChange(conn, BMSG_WAIT, 1, pid, 0, False);/* notify of change */
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------
+ TgtNotifyAll - send a message to all clients interested in process.
+ ----------------------------------------------------------------------- */
+
+ void
+ TgtNotifyAll( int pid_idx, BACK_MSG msg, UINT16 spec,
+ UINT32 context, int exclude, Boolean force)
+{
+ int conn;
+
+ DPRINTF(("TgtNotifyAll: msg %d (%s) for pid_idx=%d (%d,%d)\n",
+ msg, BmsgNames [msg], pid_idx, exclude, force));
+ for (conn = 0; conn < conn_list_cnt; conn++)
+ if (conn_list[conn].in_use /* not free */
+ && PIDMAP_TEST (conn, pid_idx))
+ {
+ if (conn != exclude)
+ TspSendWaitChange(conn, msg, spec, pid_list[pid_idx].pid, context,
+ force);
+ }
+}
+
+/* -----------------------------------------------------------------------
+ TgtDelete - mark process as now uncontrolled.
+
+ Notes:
+ - this function removes a process from the process list.
+ - the notify argument indicates a message to send if needed.
+ ----------------------------------------------------------------------- */
+
+void TgtDelete(PID_LIST *plst, int conn_idx, BACK_MSG notify)
+{
+ int idx = plst - pid_list, cnt, conn;
+
+ /* found */
+ cnt = pid_list[idx].owners;
+ if (cnt)
+ { /* some connections to break */
+ for (conn = 0; cnt && conn < conn_list_cnt; conn++)
+ if (conn_list[conn].in_use /* not free */
+ && PIDMAP_TEST (conn, idx))
+ { /* found one that uses it */
+ PIDMAP_CLEAR (conn, idx);
+ if (notify && conn != conn_idx)
+ TspSendWaitChange(conn, notify, 0, plst->pid, 0, True);
+ if (!--cnt)
+ break;
+ }
+ }
+ if (pid_list[idx].name)
+ Free(pid_list[idx].name); /* free string name back */
+ /* Free breakpoint list */
+ if (pid_list [idx].break_list != NULL) {
+ Free (pid_list [idx].break_list);
+ }
+ pid_list[idx].pid = 0; /* gone */
+}
+
+
+/* -----------------------------------------------------------------------
+ TgtKillAndDelete - kill or detach process and remove entry.
+ ----------------------------------------------------------------------- */
+
+ int
+TgtKillAndDelete( PID_LIST *plst, struct svc_req *rqstp, Boolean term)
+{
+ ptrace_in pin; /* used for ptrace call */
+ ptrace_out *pout;
+
+ /* Remove breakpoints */
+ if (plst->break_alloc > 0) {
+ pin.pid = plst->pid;
+ pin.addr.req = RPT_CLRBREAK;
+ pin.data = 0; /* clear all */
+ pin.flags = PTRFLG_NON_OWNER;
+ pout = RPCGENSRVNAME(ptrace_2_svc) (&pin, rqstp);
+ if (pout->result < 0) {
+ DPRINTF (("TgtKillAndDelete: RPT_CLRBREAK failed %d\n",
+ getErrno()));
+ return -1;
+ }
+ }
+
+ if (term)
+ { /* kill */
+ pin.addr.ptrace_addr_data_in_u.address = 0;
+ pin.data = -1; /* Don't want notification from slave */
+ pin.addr.req = RPT_KILL;
+ }
+ else
+ { /* detach */
+ pin.addr.ptrace_addr_data_in_u.address = 1;
+ pin.data = 0;
+ pin.addr.req = RPT_DETACH;
+ }
+ pin.pid = plst->pid;
+ pin.flags = PTRFLG_FREE | PTRFLG_NON_OWNER;
+
+ DPRINTF (("TgtKillAndDelete: ptrace_2_svc (%s (%d), %d)\n",
+ PtraceName (pin.addr.req), pin.addr.req, pin.pid));
+
+ pout = RPCGENSRVNAME(ptrace_2_svc) (&pin, rqstp);/* start it */
+ if (pout->errNo == ESRCH && plst->pid)
+ TgtDelete(plst, -1, BMSG_KILLED); /* only entry remains */
+ return 0;
+}
+
+/* -----------------------------------------------------------------------
+ TgtDetachCon - detach a connection's ownership of a process.
+ ----------------------------------------------------------------------- */
+
+ void
+TgtDetachCon( int conn_idx, int pid_idx, Boolean delete)
+{
+ if ((unsigned) pid_idx >= pid_list_cnt
+ || !pid_list[pid_idx].pid)
+ return; /* not valid */
+ if (PIDMAP_TEST (conn_idx, pid_idx))
+ { /* if an owner, release control */
+ PIDMAP_CLEAR (conn_idx, pid_idx);
+
+ if (pid_list[pid_idx].owners)
+ pid_list[pid_idx].owners--;
+ if (pid_list[pid_idx].primary_conn == conn_idx)
+ pid_list[pid_idx].primary_conn = NO_PRIMARY;
+ if (delete
+ && !pid_list[pid_idx].owners
+ && PROC_TERMINATED (pid_list + pid_idx))
+ TgtDelete(&pid_list[pid_idx], -1, 0); /* remove entry */
+ }
+}
+
+/* -----------------------------------------------------------------------
+ TgtHandleChildChange - decide what action to take after wait() returns.
+ Used in the master only.
+ ----------------------------------------------------------------------- */
+
+#ifdef DDEBUG
+static char* LastStartNames[] = {
+ "NONE", "STEP", "CONT", "RANGE",
+ "STEPOFF", "KILLED", "DETACHED"
+};
+
+char* GetLastStartName (int last_start)
+{
+ static char buf [32];
+
+ strcpy (buf, LastStartNames [last_start & ~LAST_START]);
+ if (last_start & LAST_START) {
+ strcat (buf, "+START");
+ }
+ return buf;
+}
+#endif
+
+Boolean TgtHandleChildChange(PID pid, int* status, int *unexp,
+ CPU_Exception_frame* ctx)
+{ /* return False if continue, else stop */
+ int idx, sig;
+ int bidx = 0;
+ PID_LIST *plst;
+ unsigned long PC;
+ BASE_BREAK *base = NULL; /* break_list[0] is really BASE_BREAK */
+ int hadStepEmul;
+ int origHadStepEmul;
+ int stopWanted;
+
+ DPRINTF (("TgtHandleChildChange: pid %d status %x cap\n",
+ (int) pid, *status));
+ if (unexp)
+ *unexp = 0; /* initialize to ok */
+
+ /* first, find pid in question */
+ idx = FindPidEntry (pid);
+ if (idx < 0)
+ { /* cannot locate this process */
+ DPRINTF (("TgtHandleChildChange: unknown process (%s pid)\n",
+ FindPidEntry (pid) >= 0 ? "stale" : "unknown"));
+ if (unexp)
+ *unexp = 1; /* Unexpected change */
+ return(False); /* unknown: ignore (used to stop and notify) */
+ }
+
+ /* found */
+ plst = &pid_list[idx]; /* pointer to entry */
+ /* first we see if just stopped */
+
+ /* copy ctxt */
+ CtxToRegs(ctx, &(plst->regs));
+
+ stopWanted = plst->stop_wanted;
+ plst->stop_wanted = 0; /* For the next time */
+
+ hadStepEmul = BreakClear (plst, -1, -1) > 0;
+ origHadStepEmul = hadStepEmul; /* hadStepEmul is cleared if real bkpt met */
+
+ if (STS_SIGNALLED (*status))
+ { /* stopped, not terminated */
+ sig = STS_GETSIG (*status); /* signal that stopped us */
+
+ /* now, we read the registers and see what to do next */
+ if (TgtPtrace(RPT_GETREGS, pid, (void *)&plst->regs, 0, NULL) < 0) {
+ memset (&plst->regs, 0, sizeof plst->regs);
+ }
+
+ /* Get current thread */
+ plst->thread = TgtPtrace(RPT_GETTARGETTHREAD, pid, NULL, 0, NULL);
+
+ if (sig == SIGTRAP)
+ { /* stopped from break/step */
+ PC = plst->regs.REG_PC;
+ /* Must check PC to see whether in situations where we had
+ step emulation we are on a breakpoint or just
+ have returned from an emulated single-step */
+ if (BreakIdentify (plst, 0 /*no adjust*/, -1 /*no thread*/) > 0) {
+ hadStepEmul = 0;
+ }
+ plst->is_step = hadStepEmul || IS_STEP(plst->regs)
+ || plst->last_start == LAST_START;
+ DPRINTF (("TgtHandleChildChange: %s last_start %s\n", plst->is_step
+ ? "step": "break", GetLastStartName (plst->last_start)));
+
+ if ((plst->is_step || origHadStepEmul || stopWanted)
+ && (plst->last_start == LAST_STEP
+ || plst->last_start == LAST_STEPOFF
+ || plst->last_start == LAST_RANGE))
+ {
+ DPRINTF (("TgtHandleChildChange: restoring stepped-off bkpt\n"));
+ BreakSteppedOff (plst);
+ }
+
+ if (plst->last_start == LAST_STEPOFF && (plst->is_step||origHadStepEmul))
+ { /* stepped off break and now need cont */
+ DPRINTF (("TgtHandleChildChange: auto-resuming after step-off\n"));
+ plst->last_start = LAST_CONT; /* convert to normal cont */
+ if (!stopWanted) {
+ if (TgtPtrace(RPT_CONT, pid, (char *)1, 0, NULL))
+ return True; /* tell people */
+ return(False); /* wait for change */
+ }
+ DPRINTF (("TgtHandleChildChange: stop_wanted %d in step-off\n",
+ stopWanted));
+ *status = STS_MAKESIG (stopWanted);
+ return True; /* Stop and notify */
+ }
+
+ base = plst->break_list ? ((BASE_BREAK*)plst->break_list) :
+ ((BASE_BREAK*)NULL);
+ /* now see if step in range */
+
+ if (plst->last_start == LAST_RANGE /* step in range */
+ && (plst->is_step || origHadStepEmul) /* not a breakpoint */
+ && PC >= base->range_start
+ && PC <= base->range_end)
+ { /* still in range, keep going */
+ if (stopWanted) {
+ DPRINTF (("TgtHandleChildChange: stop_wanted %d in step-range\n",
+ stopWanted));
+ } else {
+ DPRINTF (("TgtHandleChildChange: Reservation at %x\n",
+ plst->regs.REG_PC));
+ }
+ }
+ if (!plst->is_step) /* was break */
+ {
+ bidx = BreakIdentify (plst, 1 /*adjust*/, plst->thread);
+ if (bidx == 0) {
+ DPRINTF (("TgtHandleChildChange: forwarding bkpt to kernel\n"));
+ if (unexp) {
+ *unexp = 1;
+ }
+ return False;
+ }
+ if (bidx < 0) { /* Unwanted breakpoint, must step it off */
+ ptrace_in pin;
+ ptrace_out* out;
+ if (origHadStepEmul)
+ {
+ DPRINTF (("TgtHandleChildChange: bkpt %x becomes step\n",
+ plst->regs.REG_PC));
+ bidx = -bidx;
+ plst->is_step = 1;
+ base->clr_step = plst->break_list [bidx].type == BRKT_INSTR;
+ base->last_break = bidx;
+ return True;
+ }
+ if (stopWanted) {
+ DPRINTF (("TgtHandleChildChange: stop_wanted %d at bkpt %x\n",
+ stopWanted, plst->regs.REG_PC));
+ /* The PC has already been adjusted by BreakIdentify */
+ *status = STS_MAKESIG (stopWanted);
+ return True;
+ }
+ /* All the handling is done in ptrace_2_svc() so call it */
+ bidx = -bidx;
+ DPRINTF (("TgtHandleChildChange: last %d (%s) restarting bkpt %d\n",
+ plst->last_start, GetLastStartName (plst->last_start), bidx));
+ base->clr_step = 1;
+ base->last_break = bidx; /* remember which one */
+ plst->running = 0; /* So that ptrace is accepted */
+ pin.pid = plst->pid;
+
+ if (plst->last_start == LAST_STEP) {
+ pin.addr.req = RPT_SINGLESTEP;
+ } else {
+ pin.addr.req = RPT_CONT;
+ }
+ pin.addr.ptrace_addr_data_in_u.address = 1;
+ pin.data = 0;
+ pin.flags = PTRFLG_NON_OWNER;
+ out = RPCGENSRVNAME(ptrace_2_svc) (&pin, NULL);
+ if (out->result == 0) return False; /* Continue waiting */
+ DPRINTF(("TgtHandleChildChange: failed to restart bkpt!\n"));
+ /* If something went wrong, just stop on breakpoint */
+ }
+ }
+ } /* else sig != SIGTRAP */
+
+ /* finally, fill in stop info in break point array base */
+ if (bidx > 0)
+ { /* store break info */
+ /* will need to get off the break for SW breakpoints only */
+ base->clr_step = plst->break_list [bidx].type == BRKT_INSTR;
+ base->last_break = bidx; /* remember which one */
+ }
+ else if (base)
+ { /* clear break info */
+ base->clr_step = False; /* not stopped on break */
+ base->last_break = 0;
+ }
+ /* decision to notify owner based on last_start */
+ } /* stopped */
+ else /* terminated */
+ {
+ if (plst->last_start == LAST_START)
+ { /* spawn failed */
+ TgtNotifyAll(idx, BMSG_EXEC_FAIL, 0, 0, -1, True);
+ plst->running = False; /* not running - dead */
+ plst->state = *status; /* contains errno in high word */
+ return(False);
+ }
+
+ else if ((UCHAR)(plst->last_start & ~LAST_START) < (UCHAR)LAST_KILLED)
+ plst->last_start = LAST_NONE; /* doesn't matter anymore */
+ else
+ return(False); /* killed and detach already notified */
+ }
+ return(True); /* stop and notify */
+}
+
+#ifdef DDEBUG
+
+/* -----------------------------------------------------------------------
+ TgtDbgPtrace - debug version of ptrace.
+ ----------------------------------------------------------------------- */
+
+int TgtDbgPtrace(int request, PID pid, char *addr, int data, void *addr2)
+{
+ int diag;
+
+ DPRINTF (("TgtDbgPtrace: entered (%s (%d), %d, %x, %d, %x)\n",
+ PtraceName (request), request, pid, (int) addr, data,
+ (int) addr2));
+
+ if (request == RPT_WRITETEXT || request == RPT_WRITEDATA) {
+ int i;
+
+ DPRINTF (("TgtDbgPtrace:"));
+ if (rdb_debug) {
+ for (i = 0; i < data && i < 16; ++i) {
+ printf (" %02x", ((char*) addr2) [i] & 0xFF);
+ }
+ printf ("\n");
+ }
+ }
+
+ diag = TgtRealPtrace (request, pid, addr, data, addr2);
+
+ DPRINTF (("TgtDbgPtrace: returned %d (%x) errno %d\n",
+ diag, diag, getErrno()));
+
+ if (request == RPT_GETREGS || request == RPT_GETTHREADREGS
+ || request == RPT_SETREGS || request == RPT_SETTHREADREGS)
+ {
+ /* Use DPRINTF() so as to have the id prefix */
+ DPRINTF (("TgtDbgPtrace: (%s) PC = %x, SP = %x, FP = %x\n",
+ PtraceName (request),
+ ((xdr_regs*)addr)->REG_PC,
+ ((xdr_regs*)addr)->REG_SP,
+ ((xdr_regs*)addr)->REG_FP));
+ }
+
+ return(diag);
+}
+#endif /* DDEBUG */
diff --git a/c/src/lib/librdbg/servtsp.c b/c/src/lib/librdbg/servtsp.c
new file mode 100644
index 0000000000..6a83c6caf5
--- /dev/null
+++ b/c/src/lib/librdbg/servtsp.c
@@ -0,0 +1,329 @@
+/*
+ **************************************************************************
+ *
+ * Component: RDBG
+ * Module: servtsp.c
+ *
+ * Synopsis: Transport management for remote debug server.
+ *
+ **************************************************************************
+ */
+
+#include <sys/errno.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/servrpc.h>
+#include <signal.h>
+#include <rpc/rpc.h>
+#include <rpc/svc.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+static int out_sock;
+static int warm_test;
+
+static void TimeTestHandler();
+
+ /*
+ * TspInit - Initialize the transport system.
+ *
+ */
+
+ void
+TspInit (int id)
+{
+ struct sigaction sa;
+
+ /* setup a socket to send event messages back through */
+ out_sock = socket (PF_INET, SOCK_DGRAM, 0);
+ if (out_sock < 0) {
+ DPRINTF (("TspInit: socket() failed %d errno %d\n",
+ out_sock, getErrno()));
+ return; /* failed to open socket, let caller deal with */
+ }
+ {
+ struct sockaddr_in addr;
+
+ bzero ((void *)(&addr), sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (BackPort);
+ if (bind (out_sock, (struct sockaddr*) &addr, sizeof addr) < 0) {
+ DPRINTF (("TspInit: bind() failed\n"));
+ }
+ }
+ /* setup alarm timer for warm testing */
+ memset (&sa, 0, sizeof (sa));
+ sa.sa_handler = TimeTestHandler;
+ sigaction (SIGALRM, &sa, 0);
+}
+
+ /*
+ * TspTranslateRpcAddr - translate from an RPC handle to an
+ * opaque address.
+ *
+ * Converts the sender's address into the opaque data structure
+ * used for network addresses. This is used to look up the sender
+ * on each call.
+ */
+
+ Boolean
+TspTranslateRpcAddr (struct svc_req* rqstp, NET_OPAQUE* opaque)
+{
+ struct sockaddr_in* addr; /* used as template to extract net info */
+ unsigned char* up;
+
+ memset (opaque, 0, sizeof (NET_OPAQUE));
+ /*
+ * We interpret the remote address as a standard netbuf name.
+ * The format is 2 bytes of address family (normally AF_INET)
+ * and then a length (5) and then the IP address.
+ */
+ if (rqstp->rq_xprt->xp_addrlen != 16)
+ {
+ DPRINTF (("TspTranslateRpcAddr: Unknown remote address!!!\n"));
+ setErrno (EPROTONOSUPPORT);
+ return False; /* invalid, so fails */
+ }
+ /* addr = &rqstp->rq_xprt->xp_raddr; */
+ addr = svc_getcaller (rqstp->rq_xprt);
+ /* verify it is AF_INET */
+ if (addr->sin_family != AF_INET) { /* no, error */
+ DPRINTF (("TspTranslateRpcAddr: Not an internet address!!\n"));
+ setErrno (EAFNOSUPPORT);/* invalid addr family */
+ return False;
+ }
+ /* good address type */
+ up = (unsigned char *) &addr->sin_addr.s_addr;
+ DPRINTF (("TspTranslateRpcAddr: Sent by %u.%u.%u.%u port #%u\n",
+ up[0], up[1], up[2], up[3], htons (addr->sin_port)));
+ memcpy (opaque, addr, sizeof (struct sockaddr_in));
+ return True;
+}
+
+ /*
+ * TspValidateAddr - validate a passed in opaque address.
+ *
+ * Checks that the passed in address is in the format
+ * expected.
+ */
+
+ Boolean
+TspValidateAddr (NET_OPAQUE* opaque, NET_OPAQUE* sender)
+{
+ struct sockaddr_in* addr; /* used as template to extract net info */
+
+ addr = (struct sockaddr_in*) opaque;
+ /* Verify it is AF_INET. Should check against sender IP address too */
+ if (addr->sin_family != AF_INET) {
+ DPRINTF (("TspValidateAddr: Back port invalid: %d\n",
+ htons (addr->sin_port)));
+ return False; /* not valid */
+ }
+ /* otherwise, we copy in the IP address, since client may not know it */
+ addr->sin_addr.s_addr = ((struct sockaddr_in*) sender)->sin_addr.s_addr;
+ DPRINTF (("TspValidateAddr: Back port is %d\n", htons (addr->sin_port)));
+ return True;
+}
+
+ /*
+ * TspConnGetIndex - lookup an rpc caller's address as a connection entry.
+ *
+ * Looks up an ip address of a caller to locate the
+ * connection index in our connection array.
+ */
+
+ int
+TspConnGetIndex (struct svc_req* rqstp)
+{
+ int conn;
+ /* &rqstp->rq_xprt->xp_raddr; */
+ struct sockaddr_in *addr = svc_getcaller (rqstp->rq_xprt);
+
+ for (conn = 0; conn < conn_list_cnt; conn++) {
+ if (!conn_list[conn].in_use)
+ continue; /* not used */
+
+ if (addr->sin_addr.s_addr == ((struct sockaddr_in *)
+ &conn_list [conn].sender)->sin_addr.s_addr
+ && addr->sin_port == ((struct sockaddr_in *)
+ &conn_list[conn].sender)->sin_port) {
+ return conn;
+ }
+ }
+ return -1;
+}
+
+
+ /*
+ * TspSendWaitChange - send wait-change message to clients to
+ * notify change.
+ */
+
+ void
+TspSendWaitChange(
+ int conn, /* connection to send to */
+ BACK_MSG msg, /* BMSG type */
+ UINT16 spec, /* special information */
+ PID pid, /* pid it refers to */
+ UINT32 context, /* additional context for message */
+ Boolean force) /* force into being only message */
+{
+ int idx;
+ struct SEND_LIST* snd_ptr;
+
+ if (force) {
+ /* force to top, which means others gone */
+ idx = 0;
+ conn_list [conn].send_idx = 1;
+ conn_list[conn].retry = 0;
+ } else {
+ for (idx = 0; idx < (int) conn_list[conn].send_idx; idx++) {
+ if (conn_list[conn].send_list[idx].send_type == msg
+ && conn_list[conn].send_list[idx].pid == pid)
+ return; /* already pended for this pid */
+ }
+ idx = conn_list[conn].send_idx;
+ if (idx+1 > MAX_SEND)
+ return; /* we lose it, what should we do??? */
+ conn_list[conn].send_idx++;
+ }
+ snd_ptr = &conn_list[conn].send_list[idx];
+ snd_ptr->send_type = msg; /* message to send */
+ snd_ptr->retry = TSP_RETRIES; /* about 1 minute of retries */
+ snd_ptr->spec = htons ((u_short) spec);
+ snd_ptr->pid = htonl (pid);
+ snd_ptr->context = htonl (context);
+ TspSendMessage (conn, False); /* now do the send */
+}
+
+ /*
+ * TspSendMessage - send message at top of send list for connection.
+ */
+
+ void
+TspSendMessage( int conn, Boolean resend)
+{
+ struct sockaddr_in addr;
+ struct UDP_MSG msg;
+ int cnt;
+
+ if (!resend && conn_list[conn].retry)
+ return; /* already waiting for reply */
+
+ /*
+ * Note on above: if no back port we can't remove unless
+ * someone blows off.
+ */
+ if (!resend) {
+ /* first time, setup. Set retry count: */
+ conn_list[conn].retry = conn_list[conn].send_list[0].retry;
+ conn_list[conn].last_msg_num++; /* new sequence number */
+ if (!warm_test++) { /* starting, so enable timer */
+ alarm (2); /* resend every 2 seconds as needed */
+ }
+ }
+
+ msg.type = conn_list[conn].send_list[0].send_type;
+ msg.msg_num = conn_list[conn].last_msg_num;
+ msg.spec = conn_list[conn].send_list[0].spec;
+ msg.pid = conn_list[conn].send_list[0].pid;
+ msg.context = conn_list[conn].send_list[0].context;
+
+ memset (&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = ((struct sockaddr_in*)&conn_list[conn].back_port)->sin_port;
+ addr.sin_addr.s_addr =
+ ((struct sockaddr_in*)&conn_list[conn].back_port)->sin_addr.s_addr;
+
+ DPRINTF (("TspSendMessage: Sending msg %d (%s) to port %d\n",
+ msg.type, BmsgNames [msg.type], HL_W (addr.sin_port)));
+
+ cnt = sendto (out_sock, &msg, sizeof msg, 0, (struct sockaddr*) &addr,
+ sizeof addr);
+ if (cnt != sizeof msg) { /* failed on send */
+ printf ("%s: Failed to send msg %d to conn %d (%d vs. %d)\n",
+ ActName, msg.type, conn, cnt, sizeof msg);
+ }
+}
+
+ /*
+ * TspMessageReceive - confirmation received, now send next if any.
+ *
+ * - since UDP is connectionless, we batch up the sends and use
+ * one at a time until we get a message indicating ready for
+ * next (from ack).
+ */
+
+ void
+TspMessageReceive (int conn, PID pid)
+{
+ /* We remove the send list entry and use next if any */
+ conn_list[conn].retry = 0; /* reset */
+ if (!warm_test || !--warm_test) {
+ alarm (0); /* reset timer if not used */
+ }
+#ifdef DDEBUG
+ if (conn_list[conn].send_list[0].send_type == BMSG_WARM) {
+ DPRINTF (("TspMessageReceive: Connection reset for conn %d\n", conn));
+ }
+#endif
+ /* Move up by one if needed */
+ if (!--conn_list[conn].send_idx)
+ return; /* no more to do */
+
+ memcpy (conn_list[conn].send_list, conn_list[conn].send_list+1,
+ conn_list[conn].send_idx * sizeof(struct SEND_LIST)); /* copy down */
+ TspSendMessage (conn, 0);
+}
+
+ /*
+ * TspGetHostName - return client's host name.
+ *
+ * - this routine returns the name of the client's host or the net
+ * number of unknown.
+ */
+
+ char*
+TspGetHostName (conn_idx)
+ int conn_idx; /* client connection number */
+{
+ static char buff [30]; /* largest net num */
+ unsigned char* cp;
+
+ cp = conn_list[conn_idx].sender.c+4;
+ sprintf (buff, "%u.%u.%u.%u", cp[0], cp[1], cp[2], cp[3]);
+ return buff;
+}
+
+ /*
+ * TimeTestHandler - alarm timer handler to resend warm/wait test.
+ */
+
+ static void
+TimeTestHandler()
+{
+ int conn;
+
+ if (!warm_test)
+ return; /* no longer enabled */
+
+ for (conn = 0; conn < conn_list_cnt; conn++) {
+ /* locate all that are using this */
+ if (!conn_list[conn].in_use)
+ continue; /* not used */
+
+ if (!conn_list[conn].retry) continue;
+ /* found one that we are testing */
+ if (!--conn_list[conn].retry) {
+ /*
+ * Counted down the retries: blow off.
+ * Need to have connection flag to indicate not blowing
+ * off for cases where client is stopped due to being
+ * debugged.
+ */
+ ConnDelete (conn, NULL, CLOSE_IGNORE);
+ continue;
+ }
+ TspSendMessage (conn, True); /* send another message */
+ }
+ alarm (2); /* setup for 2 seconds from now */
+}
diff --git a/c/src/lib/librdbg/servutil.c b/c/src/lib/librdbg/servutil.c
new file mode 100644
index 0000000000..40187faead
--- /dev/null
+++ b/c/src/lib/librdbg/servutil.c
@@ -0,0 +1,130 @@
+/*
+ **********************************************************************
+ *
+ * Component: RDB
+ * Module: servutil.c
+ *
+ * Synopsis: Various utility routines
+ *
+ **********************************************************************
+ */
+
+#include <string.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/servrpc.h>
+
+/*----- Management of per-process list ----*/
+
+ /*
+ * ListAlloc - build up list entry.
+ *
+ * Notes:
+ * - this is a generic routine to build up entries in the per-connection
+ * list. The fields list, list_sz and list_alloc are affected.
+ */
+
+ Boolean
+ListAlloc(buff, clst)
+ char *buff;
+ CONN_LIST *clst; /* place to copy it */
+{
+ int tmp;
+ char* name;
+ int new_len;
+ int len;
+
+ tmp = strlen(buff);
+ new_len = (int)clst->list_sz + 1 + tmp;
+ if (clst->list_alloc < (unsigned)new_len) {
+ /* need more space */
+ name = (char *)Realloc(clst->list, len = new_len + MAX_FILENAME);
+ if (name == NULL) {
+ return(False); /* failed, no space */
+ }
+ clst->list_alloc = len;
+ clst->list = name;
+ }
+ strcpy(clst->list + clst->list_sz, buff);
+ clst->list_sz += tmp;
+ return(True);
+}
+
+/*----- Management of processes -----*/
+
+ /*
+ * FindPidEntry - locate pid_list entry from pid
+ */
+
+ int
+FindPidEntry (pid)
+ int pid; /* process identifier */
+{
+ int idx;
+
+ /* pid 0 is invalid, and signals a free slot */
+ if (pid_list == NULL || pid == 0) {
+ return -1;
+ }
+ for (idx = 0; idx < pid_list_cnt; idx++) {
+ if (pid_list [idx].pid == pid )
+ return idx;
+ }
+ return -1;
+}
+
+/*----- Debug suport -----*/
+
+#ifdef DDEBUG
+
+ /*
+ * Names of debug primitives
+ */
+
+const char* PtraceNames [] = {
+
+"RPT_TRACEME", "RPT_PEEKTEXT", "RPT_PEEKDATA", "RPT_PEEKUSER",
+"RPT_POKETEXT", "RPT_POKEDATA", "RPT_POKEUSER", "RPT_CONT",
+"RPT_KILL", "RPT_SINGLESTEP", "RPT_ATTACH", "RPT_DETACH",
+"RPT_GETREGS", "RPT_SETREGS", "RPT_GETFPREGS", "RPT_SETFPREGS",
+"RPT_READDATA", "RPT_WRITEDATA", "RPT_READTEXT", "RPT_WRITETEXT",
+"RPT_GETFPAREGS", "RPT_SETFPAREGS", "RPT_22", "RPT_23",
+"RPT_SYSCALL", "RPT_DUMPCORE", "RPT_26", "RPT_27",
+"RPT_28", "RPT_GETUCODE", "RPT_30", "RPT_31",
+"RPT_32", "RPT_33", "RPT_34", "RPT_35",
+"RPT_36", "RPT_37", "RPT_38", "RPT_39",
+"RPT_40", "RPT_41", "RPT_42", "RPT_43",
+"RPT_44", "RPT_45", "RPT_46", "RPT_47",
+"RPT_48", "RPT_49", "RPT_GETTARGETTHREAD", "RPT_SETTARGETTHREAD",
+"RPT_THREADSUSPEND", "RPT_THREADRESUME", "RPT_THREADLIST", "RPT_GETTHREADNAME",
+"RPT_SETTHREADNAME", "RPT_SETTHREADREGS", "RPT_GETTHREADREGS",
+ "RPT_59",
+"RPT_60", "RPT_61", "RPT_62", "RPT_63",
+"RPT_64", "RPT_65", "RPT_66", "RPT_67",
+"RPT_68", "RPT_69", "RPT_70", "RPT_71",
+"RPT_72", "RPT_73", "RPT_74", "RPT_STEPRANGE",
+"RPT_CONTTO", "RPT_SETBREAK", "RPT_CLRBREAK", "RPT_GETBREAK",
+"RPT_GETNAME", "RPT_STOP",
+"RPT_PGETREGS", "RPT_PSETREGS",
+"RPT_PSETTHREADREGS", "RPT_PGETTHREADREGS"
+};
+
+const char*
+PtraceName(req)
+ int req;
+{
+ static char bufret[40];
+
+ if ((req < 0) || (req >= sizeof(PtraceNames)/sizeof(char*))) {
+ sprintf(bufret, "BAD_REQ_%d", req);
+ return bufret;
+ }
+ return PtraceNames[req];
+}
+
+const char* BmsgNames [] = {
+ "?", "WARM", "WAIT", "BREAK",
+ "EXEC_FAIL", "DETACH", "KILLED", "NOT_PRIM",
+ "NEW_PID"
+};
+
+#endif /* DDEBUG */