Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Feb 2012 05:31:31 GMT
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 207068 for review
Message-ID:  <201202290531.q1T5VVXw084788@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@207068?ac=10

Change 207068 by gonzo@gonzo_thinkpad on 2012/02/29 05:30:44

	Implement userland backtrace

Affected files ...

.. //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/dtrace_isa.c#4 edit
.. //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/regset.h#2 edit

Differences ...

==== //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/dtrace_isa.c#4 (text+ko) ====

@@ -42,12 +42,17 @@
 #include <vm/pmap.h>
 
 #include <machine/db_machdep.h>
+#include <machine/md_var.h>
+#include <machine/mips_opcode.h>
 #include <ddb/db_sym.h>
 #include <ddb/ddb.h>
 #include <sys/kdb.h>
 
 #include "regset.h"
 
+#define	MAX_FUNCTION_SIZE 0x1000
+#define	MAX_PROLOGUE_SIZE 0x100
+
 int next_frame(register_t *pc, register_t *sp,
         uintptr_t *args, int *valid_args);
 
@@ -108,8 +113,151 @@
 void
 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
 {
+	proc_t *p = curproc;
+	struct trapframe *tf;
+	InstFmt i;
+	int offset, registers_on_stack;
+	uint32_t opcode, mask;
+	register_t sp, ra, pc;
+	register_t function_start;
+	int stksize;
+	volatile uint16_t *flags =
+	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
+
+	if (*flags & CPU_DTRACE_FAULT)
+		return;
+
+	if (pcstack_limit <= 0)
+		return;
+
+	/*
+	 * If there's no user context we still need to zero the stack.
+	 */
+	if (p == NULL || (tf = curthread->td_frame) == NULL)
+		goto zero;
+
+	*pcstack++ = (uint64_t)p->p_pid;
+	pcstack_limit--;
+
+	if (pcstack_limit <= 0)
+		return;
+
+	pc = (uint64_t)tf->pc;
+	sp = (uint64_t)tf->sp;
+	ra = (uint64_t)tf->ra;
+	*pcstack++ = (uint64_t)tf->pc;
+	
+	/*
+	 * Unwind, and unwind, and unwind
+	 */
+	while (1) {
+		registers_on_stack = 0;
+		mask = 0;
+		function_start = 0;
+		offset = 0;
+		stksize = 0;
+
+		while (offset < MAX_FUNCTION_SIZE) {
+			opcode = dtrace_fuword32((void *)(pc - offset));
+
+			/* [d]addiu sp, sp, -X*/
+			if (((opcode & 0xffff8000) == 0x27bd8000)
+			    || ((opcode & 0xffff8000) == 0x67bd8000)) {
+				function_start = pc - offset;
+				registers_on_stack = 1;
+				break;
+			}
+
+			/* lui gp, X */
+			if ((opcode & 0xffff8000) == 0x3c1c0000) {
+				/*
+				 * Function might start with this instruction
+				 * Keep an eye on "jr ra" and sp correction
+				 * with positive value further on
+				 */
+				function_start = pc - offset;
+			}
+
+			if (function_start) {
+				/* 
+				 * Stop looking further. Possible end of
+				 * function instruction: it means there is no
+				 * stack modifications, sp is unchanged
+				 */
+
+				/* [d]addiu sp,sp,X */
+				if (((opcode & 0xffff8000) == 0x27bd0000)
+				    || ((opcode & 0xffff8000) == 0x67bd0000))
+					break;
+
+				if (opcode == 0x03e00008)
+					break;
+			}
+
+			offset += sizeof(int);
+		}
+
+		if (!function_start)
+			break;
+
+		if (registers_on_stack) {
+			offset = 0;
+			while ((offset < MAX_PROLOGUE_SIZE) 
+			    && ((function_start + offset) < pc)) {
+				i.word = 
+				    dtrace_fuword32((void *)(function_start + offset));
+				switch (i.JType.op) {
+				case OP_SW:
+					/* look for saved registers on the stack */
+					if (i.IType.rs != 29)
+						break;
+					/* only restore the first one */
+					if (mask & (1 << i.IType.rt))
+						break;
+					mask |= (1 << i.IType.rt);
+					if (i.IType.rt == 31)
+						ra = dtrace_fuword32((void *)(sp + (short)i.IType.imm));
+					break;
 
-	printf("IMPLEMENT ME: %s\n", __func__);
+				case OP_SD:
+					/* look for saved registers on the stack */
+					if (i.IType.rs != 29)
+						break;
+					/* only restore the first one */
+					if (mask & (1 << i.IType.rt))
+						break;
+					mask |= (1 << i.IType.rt);
+					/* ra */
+					if (i.IType.rt == 31)
+						ra = dtrace_fuword64((void *)(sp + (short)i.IType.imm));
+				break;
+
+				case OP_ADDI:
+				case OP_ADDIU:
+				case OP_DADDI:
+				case OP_DADDIU:
+					/* look for stack pointer adjustment */
+					if (i.IType.rs != 29 || i.IType.rt != 29)
+						break;
+					stksize = -((short)i.IType.imm);
+				}
+
+				offset += sizeof(int);
+			}
+		}
+
+		pc = ra;
+		sp += stksize;
+
+		*pcstack++ = pc;
+		pcstack_limit--;
+		if (pcstack_limit <= 0)
+			goto zero;
+	}
+
+zero:
+	while (pcstack_limit-- > 0)
+		*pcstack++ = 0;
 }
 
 int

==== //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/regset.h#2 (text+ko) ====




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202290531.q1T5VVXw084788>