Patches for mpatrol to support uClibc and MIPS full call stack tracing
by Dan Howell <dahowell@directv.com>

diff -urN mpatrol/src/config.h mpatrol-uclibc/src/config.h
--- mpatrol/src/config.h	2006-04-27 15:58:21.000000000 -0700
+++ mpatrol-uclibc/src/config.h	2006-05-05 20:32:58.000000000 -0700
@@ -795,6 +795,10 @@
  */
 
 #ifndef MP_INIT_SUPPORT
+/* Note that machine.c currently only implements MP_INIT_SUPPORT for
+ * x86, 68k, 88k, and Sparc architechtures. */
+#if ARCH == ARCH_IX86 || ARCH == ARCH_M68K || \
+    ARCH == ARCH_M88K || ARCH == ARCH_SPARC
 #if SYSTEM == SYSTEM_DGUX || SYSTEM == SYSTEM_DRSNX || \
     SYSTEM == SYSTEM_DYNIX || SYSTEM == SYSTEM_LINUX || \
     SYSTEM == SYSTEM_SOLARIS || SYSTEM == SYSTEM_UNIXWARE
@@ -809,6 +813,9 @@
 #else /* SYSTEM */
 #define MP_INIT_SUPPORT 0
 #endif /* SYSTEM */
+#else /* ARCH */
+#define MP_INIT_SUPPORT 0
+#endif
 #endif /* MP_INIT_SUPPORT */
 
 
diff -urN mpatrol/src/inter.c mpatrol-uclibc/src/inter.c
--- mpatrol/src/inter.c	2002-01-08 12:13:59.000000000 -0800
+++ mpatrol-uclibc/src/inter.c	2006-05-17 18:02:04.000000000 -0700
@@ -79,12 +79,24 @@
 
 #if TARGET == TARGET_UNIX
 #if SYSTEM == SYSTEM_LINUX
+#ifndef __UCLIBC__
 /* This contains a pointer to the environment variables for a process.  If
  * it is not set up yet then we must use sbrk() to allocate all memory since
  * we can't initialise mpatrol until the environment variable can be read.
  */
 
 extern char **__environ;
+#else /* __UCLIBC__ */
+/* In uClibc, the dynamic loader calls malloc() and related functions,
+ * and sets __environ before these calls, so we can't use it to determine
+ * if we can initialize mpatrol. Instead, we use __progname, which is set
+ * in __uClibc_main just before before uClibc transfers control to the
+ * application's main() function (and static constructors, if any). Before
+ * this, we must use sbrk() to allocate memory.
+ */
+
+extern const char *__progname;
+#endif /* __UCLIBC__ */
 #elif SYSTEM == SYSTEM_TRU64
 /* The exception support library on Tru64 always allocates some memory from
  * the heap in order to initialise the code address range tables.  We need
@@ -118,7 +130,11 @@
 
 #if TARGET == TARGET_UNIX
 #if SYSTEM == SYSTEM_LINUX
+#ifndef __UCLIBC__
 #define crt_initialised() (__environ)
+#else /* __UCLIBC__ */
+#define crt_initialised() (__progname)
+#endif /* __UCLIBC__ */
 #elif SYSTEM == SYSTEM_TRU64
 #define crt_initialised() (__exc_crd_list_head && init_flag)
 #else /* SYSTEM */
@@ -306,7 +322,7 @@
     alloctype t;
     int c;
 
-    if (memhead.fini || (memhead.astack.size == 0))
+    if (memhead.fini || (memhead.astack.size == 0) || memhead.recur != 1)
         return;
 #if MP_FULLSTACK
     /* Create the address nodes for the current call.  This is not necessarily
@@ -1307,7 +1323,7 @@
     loginfo v;
     int j;
 
-    if (!memhead.init || memhead.fini)
+    if (!memhead.init || memhead.fini || memhead.recur != 0)
     {
         __mp_memset(p, c, l);
         return p;
@@ -1371,7 +1387,7 @@
     loginfo v;
     int j;
 
-    if (!memhead.init || memhead.fini)
+    if (!memhead.init || memhead.fini || memhead.recur != 0)
         if (f == AT_MEMCCPY)
         {
             if (r = __mp_memfind(p, l, &c, 1))
diff -ur mpatrol/src/machine.c mpatrol-uclibc/src/machine.c
--- mpatrol/src/machine.c	2002-01-08 12:13:59.000000000 -0800
+++ mpatrol-uclibc/src/machine.c	2006-06-07 15:11:20.000000000 -0700
@@ -217,6 +217,19 @@
 	.end	__mp_stackpointer
 
 
+/* Obtain the frame pointer (s8) for the current function.
+ */
+
+	.text
+	.globl	__mp_framepointer
+	.ent	__mp_framepointer
+__mp_framepointer:
+	.frame	$29,0,$31
+	move	$2,$30
+	j	$31
+	.end	__mp_framepointer
+
+
 /* Obtain the return address for the current function.
  */
 
diff -urN mpatrol/src/memory.c mpatrol-uclibc/src/memory.c
--- mpatrol/src/memory.c	2002-01-08 12:13:59.000000000 -0800
+++ mpatrol-uclibc/src/memory.c	2006-05-12 18:12:39.000000000 -0700
@@ -47,7 +47,7 @@
 #endif /* SYSTEM */
 #include <setjmp.h>
 #include <signal.h>
-#if MP_SIGINFO_SUPPORT
+#if MP_SIGINFO_SUPPORT && SYSTEM != SYSTEM_LINUX
 #include <siginfo.h>
 #endif /* MP_SIGINFO_SUPPORT */
 #include <fcntl.h>
diff -urN mpatrol/src/signals.c mpatrol-uclibc/src/signals.c
--- mpatrol/src/signals.c	2002-01-08 12:13:59.000000000 -0800
+++ mpatrol-uclibc/src/signals.c	2006-05-12 18:12:19.000000000 -0700
@@ -36,7 +36,7 @@
 #include <stdlib.h>
 #include <signal.h>
 #if TARGET == TARGET_UNIX
-#if MP_SIGINFO_SUPPORT
+#if MP_SIGINFO_SUPPORT && SYSTEM != SYSTEM_LINUX
 #include <siginfo.h>
 #endif /* MP_SIGINFO_SUPPORT */
 #elif TARGET == TARGET_WINDOWS
diff -urN mpatrol/src/stack.c mpatrol-uclibc/src/stack.c
--- mpatrol/src/stack.c	2002-01-08 12:13:59.000000000 -0800
+++ mpatrol-uclibc/src/stack.c	2006-06-22 15:39:04.000000000 -0700
@@ -48,7 +48,7 @@
 #else /* MP_LIBRARYSTACK_SUPPORT */
 #if TARGET == TARGET_UNIX
 #include <setjmp.h>
-#if MP_SIGINFO_SUPPORT
+#if MP_SIGINFO_SUPPORT && SYSTEM != SYSTEM_LINUX
 #include <siginfo.h>
 #endif /* MP_SIGINFO_SUPPORT */
 #if SYSTEM == SYSTEM_DRSNX || SYSTEM == SYSTEM_SOLARIS
@@ -58,6 +58,17 @@
 #define R_SP REG_SP
 #endif /* R_SP */
 #endif /* ARCH */
+#elif SYSTEM == SYSTEM_LINUX
+#if ARCH == ARCH_MIPS
+#include <linux/unistd.h>
+/* We need the ucontext defined in asm/ucontext.h, but sys/ucontext.h
+ * has a conflicting definition of ucontext. So we'll trick the
+ * preprocessor into letting the include file define a non-conflicting
+ * name. */
+#define ucontext asm_ucontext
+#include <asm/ucontext.h>
+#undef ucontext
+#endif /* ARCH */
 #endif /* SYSTEM */
 #endif /* TARGET */
 #endif /* MP_LIBRARYSTACK_SUPPORT */
@@ -122,6 +133,15 @@
 #define SP_OFFSET 2 /* stack pointer offset has been set */
 #define SP_LOWER  4 /* lower part of stack pointer offset has been set */
 #define SP_UPPER  8 /* upper part of stack pointer offset has been set */
+#define BR_UNCOND 16 /* unconditional branch needs to be taken */
+#define BR_COND   32 /* conditional branch encountered */
+#define RA_NOFRAME 64 /* no frame - return address is in ra register */
+#define SP_IN_FP  128 /* stack pointer stored in frame pointer (s8) register */
+
+#if SYSTEM == SYSTEM_LINUX
+#define RA_SIGTRAMP  1 /* return address is a signal trampoline */
+#define RA_SIGRETURN 2 /* return address is in the signalled function */
+#endif /* SYSTEM */
 #endif /* TARGET && ARCH */
 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
 
@@ -152,6 +172,13 @@
 #endif /* SYSTEM */
 #endif /* SYSTEM */
 #else /* MP_LIBRARYSTACK_SUPPORT */
+/* On some systems, such as those using uClibc, the signal() function may
+ * call memcpy() or other memory related functions, so we need to guard
+ * against recursion.
+ */
+
+static unsigned char recursive;
+
 static jmp_buf environment;
 #if MP_SIGINFO_SUPPORT
 static struct sigaction bushandler;
@@ -261,23 +288,41 @@
 int
 unwind(frameinfo *f)
 {
-    long p, s;
-    unsigned long a, i, q;
+    long p, m, s;
+    unsigned long a, i, q, t, b, r;
     unsigned short l, u;
 
     s = -1;
-    p = 0;
+    p = m = 0;
     q = 0xFFFFFFFF;
     l = u = 0;
     a = 0;
+    t = b = 0;
     /* Determine the current stack pointer and return address if we are
      * initiating call stack traversal.
      */
     if (f->ra == 0)
     {
         f->sp = __mp_stackpointer();
+        f->fp = __mp_framepointer();
         f->ra = __mp_returnaddress();
     }
+#if SYSTEM == SYSTEM_LINUX
+    /* Handle signal frames.
+     */
+    if (f->ra & RA_SIGRETURN)
+    {
+        /* in case of frameless function, get ra and sp from sigcontext */
+        p = ((struct sigcontext *) f->sp)->sc_regs[31];
+        f->fp = ((struct sigcontext *) f->sp)->sc_regs[30];
+        f->sp = ((struct sigcontext *) f->sp)->sc_regs[29];
+        a |= RA_NOFRAME;
+    }
+    f->ra &= ~3;
+#endif
+    /* Save initial code-reading starting point.
+     */
+    r = f->ra;
     /* Search for the return address offset in the stack frame.
      */
     while (!((a & RA_OFFSET) && (a & SP_OFFSET)) && (f->ra < q))
@@ -294,6 +339,67 @@
             s = 0;
             a |= SP_OFFSET;
         }
+        else if (i == 0x03C0E821)
+        {
+            /* move sp,s8 */
+            a |= SP_IN_FP;
+        }
+        else if ((i >> 28 == 0x1) || (i >> 26 == 0x01))
+        {
+            /* branch */
+            t = f->ra + ((signed short)(i & 0xFFFF) * 4) + 4;
+            if ((i >> 16 == 0x1000) && !(a & BR_COND))
+            {
+                /* unconditional branch, if no conditional branch could
+                   branch past this code */
+                b = t;
+                a |= BR_UNCOND;
+            }
+            else
+            {
+                /* conditional branch, ignore if previous conditional branch
+                   is further forwards */
+                if ((t > b) && (t > f->ra))
+                {
+                    b = t;
+                    a |= BR_COND;
+                    /* can branch past an unconditional branch */
+                    if (b > q)
+                        q = 0xFFFFFFFF;
+                }
+                else if (t < r)
+                {
+                    /* but if branching backwards, set reverse branch target to
+                       lowest address target encountered so far */
+                    r = t;
+                    /* ensure a loop back */
+                    q = 0xFFFFFFFF;
+                }
+            }
+        }
+#if SYSTEM == SYSTEM_LINUX
+        else if (i == 0x0000000c)
+        {
+            /* syscall - check for signal handler trampolines */
+            if (*((unsigned long *) (f->ra - 4)) == 0x24020000 + __NR_sigreturn)
+            {
+                /* li v0,__NR_sigreturn */
+                /* get pointer to sigcontext */
+                f->sp = f->ra + 4;
+                f->ra = ((struct sigcontext *) f->sp)->sc_pc | RA_SIGRETURN;
+                return 1;
+            }
+            else if (*((unsigned long *) (f->ra - 4)) == 0x24020000 + __NR_rt_sigreturn)
+            {
+                /* li v0,__NR_rt_sigreturn */
+                /* get pointer to sigcontext */
+                f->sp = f->ra + 4 +
+                    sizeof(struct siginfo) + offsetof(struct asm_ucontext, uc_mcontext);
+                f->ra = ((struct sigcontext *) f->sp)->sc_pc | RA_SIGRETURN;
+                return 1;
+            }
+        }
+#endif
         else
             switch (i >> 16)
             {
@@ -319,6 +425,10 @@
                 u = i & 0xFFFF;
                 a |= SP_UPPER;
                 break;
+              case 0x8FBE:
+                /* lw s8,##(sp) */
+                m = i & 0xFFFF;
+                break;
               case 0x8FBF:
                 /* lw ra,##(sp) */
                 p = i & 0xFFFF;
@@ -326,9 +436,52 @@
                 break;
             }
         f->ra += 4;
+        /* Process branch instructions.
+         */
+        if (a & BR_COND)
+        {
+            if (f->ra >= b)
+            {
+                /* reached target of previous conditional branch */
+                a &= ~BR_COND;
+                b = 0;
+            }
+        }
+        else if (a & BR_UNCOND)
+            /* clear branch flag and process instruction in delay slot */
+            a &= ~BR_UNCOND;
+        else if (b != 0)
+        {
+            /* now follow the unconditional branch */
+            if (b < f->ra)
+            {
+                /* avoid infinite loops */
+                q = f->ra - 8;
+                /* go back as far as possible */
+                if (r < b)
+                    b = r;
+            }
+            f->ra = b;
+            b = 0;
+        }
     }
     if ((s == 0) && ((a & SP_LOWER) || (a & SP_UPPER)))
         s = (u << 16) | l;
+#if SYSTEM == SYSTEM_LINUX
+    if ((a & RA_NOFRAME) && !(a & RA_OFFSET) &&
+        ((*((unsigned long *) (p - 8)) == 0x0320F809) ||
+         (*((unsigned long *) (p - 8)) >> 16 == 0x0C10)))
+    {
+        /* jalr ra,t9 or jal ## */
+        /* f->sp already set */
+        f->ra = p;
+        return 1;
+    }
+#endif
+    if (a & SP_IN_FP)
+        f->sp = f->fp;
+    if (m > 0)
+        f->fp = ((unsigned long *) f->sp)[m >> 2];
     if ((s > 0) && (i = ((unsigned long *) f->sp)[p >> 2]) &&
         ((*((unsigned long *) (i - 8)) == 0x0320F809) ||
          (*((unsigned long *) (i - 8)) >> 16 == 0x0C10)))
@@ -338,6 +491,19 @@
         f->ra = i;
         return 1;
     }
+#if SYSTEM == SYSTEM_LINUX
+    else if ((s > 0) && (i != 0) &&
+             (*((unsigned long *) (i + 4)) == 0x0000000c) &&
+             ((*((unsigned long *) i) == 0x24020000 + __NR_sigreturn) ||
+              (*((unsigned long *) i) == 0x24020000 + __NR_rt_sigreturn)))
+    {
+        /* li v0,__NR_sigreturn or __NR_rt_sigreturn ; syscall */
+        /* signal trampoline */
+        f->sp += s;
+        f->ra = i | RA_SIGTRAMP;
+        return 1;
+    }
+#endif
     f->sp = f->ra = 0;
     return 0;
 }
@@ -573,16 +739,14 @@
     }
 #endif /* TARGET */
 #else /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
-#if (TARGET == TARGET_UNIX && (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || \
-      ARCH == ARCH_M88K || ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || \
-      ARCH == ARCH_SPARC)) || ((TARGET == TARGET_WINDOWS || \
-      TARGET == TARGET_NETWARE) && ARCH == ARCH_IX86)
-    /* This section is not complete in any way for the OS / processor
-     * combinations it supports, as it is intended to be as portable as possible
-     * without writing in assembler.  In particular, optimised code is likely
-     * to cause major problems for stack traversal on some platforms.
-     */
 #if TARGET == TARGET_UNIX
+    /* On some systems, such as those using uClibc, the signal() function may
+     * call memcpy() or other memory related functions, so we need to guard
+     * against recursion here.
+     */
+   if (!recursive)
+   {
+    recursive = 1;
 #if MP_SIGINFO_SUPPORT
     i.sa_flags = 0;
     (void *) i.sa_handler = (void *) stackhandler;
@@ -597,6 +761,15 @@
         __mp_newframe(p, p->first);
     else
 #endif /* TARGET */
+#if (TARGET == TARGET_UNIX && (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || \
+      ARCH == ARCH_M88K || ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || \
+      ARCH == ARCH_SPARC)) || ((TARGET == TARGET_WINDOWS || \
+      TARGET == TARGET_NETWARE) && ARCH == ARCH_IX86)
+    /* This section is not complete in any way for the OS / processor
+     * combinations it supports, as it is intended to be as portable as possible
+     * without writing in assembler.  In particular, optimised code is likely
+     * to cause major problems for stack traversal on some platforms.
+     */
     {
         if (p->frame == NULL)
             if (p->first == NULL)
@@ -640,32 +813,10 @@
             r = 1;
         }
     }
-#if TARGET == TARGET_UNIX
-#if MP_SIGINFO_SUPPORT
-    sigaction(SIGBUS, &bushandler, NULL);
-    sigaction(SIGSEGV, &segvhandler, NULL);
-#else /* MP_SIGINFO_SUPPORT */
-    signal(SIGBUS, bushandler);
-    signal(SIGSEGV, segvhandler);
-#endif /* MP_SIGINFO_SUPPORT */
-#endif /* TARGET */
 #elif TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
     /* For the MIPS architecture we perform code reading to determine the
      * frame pointers and the return addresses.
      */
-#if MP_SIGINFO_SUPPORT
-    i.sa_flags = 0;
-    (void *) i.sa_handler = (void *) stackhandler;
-    sigfillset(&i.sa_mask);
-    sigaction(SIGBUS, &i, &bushandler);
-    sigaction(SIGSEGV, &i, &segvhandler);
-#else /* MP_SIGINFO_SUPPORT */
-    bushandler = signal(SIGBUS, stackhandler);
-    segvhandler = signal(SIGSEGV, stackhandler);
-#endif /* MP_SIGINFO_SUPPORT */
-    if (setjmp(environment))
-        __mp_newframe(p, p->first);
-    else
     {
         if (p->frame == NULL)
             unwind(&p->next);
@@ -673,6 +824,10 @@
         {
             p->frame = (void *) p->next.sp;
             p->addr = (void *) (p->next.ra - 8);
+#if SYSTEM == SYSTEM_LINUX
+            if (p->next.ra & (RA_SIGTRAMP|RA_SIGRETURN))
+                p->addr = (void *) (p->next.ra & ~3);
+#endif /* SYSTEM */
             r = 1;
         }
         else
@@ -681,6 +836,8 @@
             p->addr = NULL;
         }
     }
+#endif /* TARGET && ARCH */
+#if TARGET == TARGET_UNIX
 #if MP_SIGINFO_SUPPORT
     sigaction(SIGBUS, &bushandler, NULL);
     sigaction(SIGSEGV, &segvhandler, NULL);
@@ -688,7 +845,9 @@
     signal(SIGBUS, bushandler);
     signal(SIGSEGV, segvhandler);
 #endif /* MP_SIGINFO_SUPPORT */
-#endif /* TARGET && ARCH */
+    recursive = 0;
+   } /* if (!bushandler) */
+#endif /* TARGET */
 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
     return r;
 }
diff -ur mpatrol/src/stack.h mpatrol-uclibc/src/stack.h
--- mpatrol/src/stack.h	2002-01-08 12:13:59.000000000 -0800
+++ mpatrol-uclibc/src/stack.h	2006-06-07 15:12:58.000000000 -0700
@@ -75,6 +75,7 @@
 typedef struct frameinfo
 {
     unsigned int sp; /* stack pointer */
+    unsigned int fp; /* frame pointer (s8) */
     unsigned int ra; /* return address */
 }
 frameinfo;
diff -urN mpatrol/src/symbol.c mpatrol-uclibc/src/symbol.c
--- mpatrol/src/symbol.c	2002-01-08 12:13:59.000000000 -0800
+++ mpatrol-uclibc/src/symbol.c	2006-05-24 15:43:04.000000000 -0700
@@ -1157,7 +1157,7 @@
             __mp_error(ET_MAX, AT_MAX, NULL, 0, "%s: %s\n", f, m);
         return 0;
     }
-    if (n == 0)
+    if (n <= sizeof(asymbol *))
     {
         /* If we couldn't find the symbol table then it is likely that the file
          * has been stripped.  However, if the file was dynamically linked then
@@ -1172,7 +1172,7 @@
                 __mp_error(ET_MAX, AT_MAX, NULL, 0, "%s: %s\n", f, m);
             return 0;
         }
-        if (n == 0)
+        if (n <= sizeof(asymbol *))
         {
             m = "missing symbol table";
             if (a != NULL)
@@ -1893,6 +1893,17 @@
                     l = (dynamiclink *) *((unsigned long *) d->d_un.d_ptr + 1);
                 break;
             }
+#if ARCH == ARCH_MIPS
+            else if (d->d_tag == DT_MIPS_RLD_MAP)
+            {
+                /* MIPS elf has DT_MIPS_RLD_MAP instead of DT_DEBUG. */
+                if (!d->d_un.d_ptr || !(*(unsigned long **) d->d_un.d_ptr))
+                    l = NULL;
+                else
+                    l = (dynamiclink *) *((*(unsigned long **) d->d_un.d_ptr) + 1);
+                break;
+            }
+#endif /* ARCH */
         /* We skip past the first item on the list since it represents the
          * executable file, but we may wish to record the name of the file
          * if we haven't already determined it.
