Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 Apr 2003 15:32:53 -0700 (PDT)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 28844 for review
Message-ID:  <200304122232.h3CMWrSs063491@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=28844

Change 28844 by marcel@marcel_nfs on 2003/04/12 15:32:21

	Start of the new unwind logic. This is mostly a stripped down
	version of what we had, so that we can include it in the
	build again and have the ELF tables added/removed for modules.
	
	The intend here is to create an unwinder that returns the
	state at entry to some function only (maybe at the start of
	the body region of a function if that opens up more doors).
	We don't really need to have finegrained control (ie at the
	instruction level) because we're not a debugger. We only need
	to be able to create backtraces and unwind to the entry into
	the kernel so that we have the correct value for preserved
	registers). We're not even interested in scratch registers
	here, because we can grab them from the trapframe if we need
	them (eg for ptrace(2)). Note that we have keep track of the
	location of the register value, so that we can support setting
	the registers (eg for ptrace(2)). The location is either the
	register itself, some other general register or some memory
	location. 
	This all means that we have a new register state and different
	ways to create the initial state.
	
	Remove <machine/rse.h>. We move the RSE functions to the
	unwinder; either implicitly or explicitly.
	
	Converge on a fixed prefix for the unwinder so that we can
	drop 'ia64' from the names. This generally makes it more
	pleasing to read and write.

Affected files ...

.. //depot/projects/ia64_epc/sys/conf/files.ia64#6 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/db_interface.c#4 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/db_trace.c#2 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/elf_machdep.c#3 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/machdep.c#9 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/syscall.s#4 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/unaligned.c#2 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/unwind.c#2 edit
.. //depot/projects/ia64_epc/sys/ia64/include/rse.h#2 delete
.. //depot/projects/ia64_epc/sys/ia64/include/unwind.h#2 edit

Differences ...

==== //depot/projects/ia64_epc/sys/conf/files.ia64#6 (text+ko) ====

@@ -61,7 +61,7 @@
 ia64/ia64/syscall.s		standard
 ia64/ia64/trap.c		standard
 #ia64/ia64/unaligned.c		standard
-#ia64/ia64/unwind.c		standard
+ia64/ia64/unwind.c		standard
 ia64/ia64/vga_machdep.c		optional	vga
 ia64/ia64/vm_machdep.c		standard
 ia64/isa/isa.c			optional	isa

==== //depot/projects/ia64_epc/sys/ia64/ia64/db_interface.c#4 (text+ko) ====

@@ -51,7 +51,6 @@
 #include <vm/vm.h>
 
 #include <machine/inst.h>
-#include <machine/rse.h>
 #include <machine/db_machdep.h>
 #include <machine/mutex.h>
 

==== //depot/projects/ia64_epc/sys/ia64/ia64/db_trace.c#2 (text+ko) ====

@@ -31,7 +31,6 @@
 #include <machine/inst.h>
 #include <machine/db_machdep.h>
 #include <machine/unwind.h>
-#include <machine/rse.h>
 #include <machine/vmparam.h>
 
 #include <ddb/ddb.h>

==== //depot/projects/ia64_epc/sys/ia64/ia64/elf_machdep.c#3 (text+ko) ====

@@ -262,10 +262,8 @@
 
 		if (ph->p_type == PT_IA_64_UNWIND) {
 			vaddr = ph->p_vaddr + reloc;
-#if 0
-			ia64_add_unwind_table((vm_offset_t)lf->address, vaddr,
+			unw_table_add((vm_offset_t)lf->address, vaddr,
 			    vaddr + ph->p_memsz);
-#endif
 		}
 		++ph;
 	}
@@ -277,8 +275,6 @@
 elf_cpu_unload_file(linker_file_t lf)
 {
 
-#if 0
-	ia64_delete_unwind_table((vm_offset_t)lf->address);
-#endif
+	unw_table_remove((vm_offset_t)lf->address);
 	return (0);
 }

==== //depot/projects/ia64_epc/sys/ia64/ia64/machdep.c#9 (text+ko) ====

@@ -84,7 +84,6 @@
 #include <machine/sigframe.h>
 #include <machine/efi.h>
 #include <machine/inst.h>
-#include <machine/rse.h>
 #include <machine/unwind.h>
 #include <i386/include/specialreg.h>
 
@@ -1322,47 +1321,8 @@
 	*highp = high;
 }
 
-static int
-rse_slot(u_int64_t *bsp)
-{
-	return ((u_int64_t) bsp >> 3) & 0x3f;
-}
-
-/*
- * Return the address of register regno (regno >= 32) given that bsp
- * points at the base of the register stack frame.
- */
-u_int64_t *
-ia64_rse_register_address(u_int64_t *bsp, int regno)
-{
-	int off = regno - 32;
-	u_int64_t rnats = (rse_slot(bsp) + off) / 63;
-	return bsp + off + rnats;
-}
-
-/*
- * Calculate the base address of the previous frame given that the
- * current frame's locals area is 'size'.
- */
-u_int64_t *
-ia64_rse_previous_frame(u_int64_t *bsp, int size)
-{
-	int slot = rse_slot(bsp);
-	int rnats = 0;
-	int count = size;
-
-	while (count > slot) {
-		count -= 63;
-		rnats++;
-		slot = 63;
-	}
-	return bsp - size - rnats;
-}
-
-
 intptr_t
 casuptr(intptr_t *p, intptr_t old, intptr_t new)
 {
 	return (-1);
 }
-

==== //depot/projects/ia64_epc/sys/ia64/ia64/syscall.s#4 (text+ko) ====


==== //depot/projects/ia64_epc/sys/ia64/ia64/unaligned.c#2 (text+ko) ====

@@ -34,7 +34,6 @@
 #include <vm/vm_extern.h>
 #include <machine/frame.h>
 #include <machine/inst.h>
-#include <machine/rse.h>
 
 #define sign_extend(imm, w) (((int64_t)(imm) << (64 - (w))) >> (64 - (w)))
 

==== //depot/projects/ia64_epc/sys/ia64/ia64/unwind.c#2 (text+ko) ====

@@ -32,9 +32,8 @@
 #include <sys/malloc.h>
 #include <sys/queue.h>
 
-#include <machine/frame.h>
+#include <machine/pcb.h>
 #include <machine/unwind.h>
-#include <machine/rse.h>
 
 #ifdef UNWIND_DEBUG
 #define DPF(x)	printf x
@@ -44,157 +43,125 @@
 
 MALLOC_DEFINE(M_UNWIND, "Unwind table", "Unwind table information");
 
-struct ia64_unwind_table_entry {
-	u_int64_t	ue_start;	/* procedure start */
-	u_int64_t	ue_end;		/* procedure end */
-	u_int64_t	ue_info;	/* offset to procedure descriptors */
+struct unw_entry {
+	uint64_t	ue_start;	/* procedure start */
+	uint64_t	ue_end;		/* procedure end */
+	uint64_t	ue_info;	/* offset to procedure descriptors */
 };
 
-struct ia64_unwind_info {
-	u_int64_t	ui_length	: 32; /* length in 64bit units */
-	u_int64_t	ui_flags	: 16;
-	u_int64_t	ui_version	: 16;
+struct unw_table {
+	LIST_ENTRY(unw_table) ut_link;
+	uint64_t	ut_base;
+	uint64_t	ut_limit;
+	struct unw_entry *ut_start;
+	struct unw_entry *ut_end;
 };
 
-LIST_HEAD(ia64_unwind_table_list, ia64_unwind_table);
+LIST_HEAD(unw_table_list, unw_table);
 
-struct ia64_unwind_table {
-	LIST_ENTRY(ia64_unwind_table) ut_link;
-	u_int64_t	ut_base;
-	u_int64_t	ut_limit;
-	struct ia64_unwind_table_entry *ut_start;
-	struct ia64_unwind_table_entry *ut_end;
-};
+static struct unw_table_list unw_tables;
 
-struct unwind_reg {
-	u_int64_t	ur_value;	/* current value */
-	u_int64_t	*ur_save;	/* save location */
-	int		ur_when;	/* when the save happened */
-};
+static void
+unw_initialize(void *dummy __unused)
+{
 
-struct unwind_fpreg {
-	struct ia64_fpreg ur_value;	/* current value */
-	struct ia64_fpreg *ur_save;	/* save location */
-	int		ur_when;	/* when the save happened */
-};
+	LIST_INIT(&unw_tables);
+}
+SYSINIT(unwind, SI_SUB_KMEM, SI_ORDER_ANY, unw_initialize, 0);
 
-struct ia64_unwind_state {
-	LIST_ENTRY(ia64_unwind_state) us_link; /* free list */
-
-	/*
-	 * Current register state and location of saved register state
-	 */
-	struct register_state {
-		struct unwind_reg rs_psp;
-		struct unwind_reg rs_pfs;
-		struct unwind_reg rs_preds;
-		struct unwind_reg rs_unat;
-		struct unwind_reg rs_lc;
-		struct unwind_reg rs_rnat;
-		struct unwind_reg rs_bsp;
-		struct unwind_reg rs_bspstore;
-		struct unwind_reg rs_fpsr;
-		struct unwind_reg rs_priunat;
-		struct unwind_reg rs_br[8];
-		struct unwind_reg rs_gr[32];
-		struct unwind_fpreg rs_fr[32];
-		u_int64_t	rs_stack_size;
-	}		us_regs;
-
-	/*
-	 * Variables used while parsing unwind records.
-	 */
-	u_int64_t	us_ip;		/* value of IP for this frame */
-	int		us_ri;		/* RI field from cr.ipsr */
-	u_int64_t	us_pc;		/* slot offset in procedure */
-	u_int64_t	*us_bsp;	/* backing store for frame */
-	u_int64_t	us_cfm;		/* CFM value for frame */
-	u_int64_t	*us_spill;	/* spill_base location */
-	int		us_spilloff;	/* offset into spill area */
-	int		us_grmask;	/* mask of grs being spilled */
-	int		us_frmask;	/* mask of frs being spilled */
-	int		us_brmask;	/* mask of brs being spilled */
-};
-
-static int ia64_unwind_initialised;
-static struct ia64_unwind_table_list ia64_unwind_tables;
-#define MAX_UNWIND_STATES 4
-static struct ia64_unwind_state ia64_unwind_state_static[MAX_UNWIND_STATES];
-static LIST_HEAD(ia64_unwind_state_list, ia64_unwind_state) ia64_unwind_states;
-
-static void
-ia64_initialise_unwind(void *arg __unused)
+#if NOTYET
+static struct unw_entry *
+unw_entry_lookup(struct unw_table *ut, uint64_t ip)
 {
-	int i;
+	struct unw_entry *end, *mid, *start;
 
-	KASSERT(!ia64_unwind_initialised, ("foo"));
-
-	LIST_INIT(&ia64_unwind_tables);
-	LIST_INIT(&ia64_unwind_states);
-	for (i = 0; i < MAX_UNWIND_STATES; i++) {
-		LIST_INSERT_HEAD(&ia64_unwind_states,
-		    &ia64_unwind_state_static[i], us_link);
+	ip -= ut->ut_base;
+	start = ut->ut_start;
+	end = ut->ut_end - 1;
+	while (start < end) {
+		mid = start + ((end - start) >> 1);
+		if (ip < mid->ue_start)
+			end = mid;
+		else if (ip >= mid->ue_end)
+			start = mid + 1;
+		else
+			break;
 	}
-
-	ia64_unwind_initialised = 1;
+	return ((start < end) ? mid : NULL);
 }
-SYSINIT(unwind, SI_SUB_KMEM, SI_ORDER_ANY, ia64_initialise_unwind, 0);
+#endif
 
-static struct ia64_unwind_table *
-find_table(u_int64_t ip)
+static struct unw_table *
+unw_table_lookup(uint64_t ip)
 {
-	struct ia64_unwind_table *ut;
+	struct unw_table *ut;
 
-	LIST_FOREACH(ut, &ia64_unwind_tables, ut_link) {
+	LIST_FOREACH(ut, &unw_tables, ut_link) {
 		if (ip >= ut->ut_base && ip < ut->ut_limit)
-			return ut;
+			return (ut);
 	}
-	return 0;
+	return (NULL);
 }
 
-static struct ia64_unwind_table_entry *
-find_entry(struct ia64_unwind_table *ut, u_int64_t ip)
+int
+unw_state_create(struct unw_regstate *rs)
 {
-	struct ia64_unwind_table_entry *start;
-	struct ia64_unwind_table_entry *end;
-	struct ia64_unwind_table_entry *mid;
+	struct pcb pcb;
+
+	savectx(&pcb);
+	/* Cache the values. */
+	rs->rs_val.special = pcb.pcb_special;
+	rs->rs_val.preserved = pcb.pcb_preserved;
+	rs->rs_val.preserved_fp = pcb.pcb_preserved_fp;
+	/* Set the location to 'self' (ie in the register itself). */
+	memset(&rs->rs_loc.special, 0, sizeof(rs->rs_loc.special));
+	memset(&rs->rs_loc.preserved, 0, sizeof(rs->rs_loc.preserved));
+	memset(&rs->rs_loc.preserved_fp, 0, sizeof(rs->rs_loc.preserved_fp));
+	return (0);
+}
 
-	ip -= ut->ut_base;
-	start = ut->ut_start;
-	end = ut->ut_end - 1;
-	while (start < end) {
-		mid = start + (end - start) / 2;
-		if (ip < mid->ue_start) {
-			if (end == mid)
-				break;
-			end = mid;
-		} else if (ip >= mid->ue_end) {
-			if (start == mid)
-				break;
-			start = mid;
-		} else
-			return mid;
+static __inline void
+unw_set_loc(void *rs, void *pcb, int sz)
+{
+	while (sz > 0) {
+		*((uint64_t*)rs) = (uint64_t)pcb;
+		((uint64_t*)pcb)++, ((uint64_t*)rs)++;
+		sz -= sizeof(uint64_t);
 	}
+}
+
+int
+unw_state_create_from_pcb(struct unw_regstate *rs, struct pcb *pcb)
+{
 
-	return 0;
+	/* Cache the values. */
+	rs->rs_val.special = pcb->pcb_special;
+	rs->rs_val.preserved = pcb->pcb_preserved;
+	rs->rs_val.preserved_fp = pcb->pcb_preserved_fp;
+	/* Set the location to the memory address in the PCB. */
+	unw_set_loc(&rs->rs_loc.special, &pcb->pcb_special,
+	    sizeof(rs->rs_loc.special));
+	unw_set_loc(&rs->rs_loc.preserved, &pcb->pcb_preserved,
+	    sizeof(rs->rs_loc.preserved));
+	unw_set_loc(&rs->rs_loc.preserved_fp, &pcb->pcb_preserved_fp,
+	    sizeof(rs->rs_loc.preserved_fp));
+	return (0);
 }
 
 int
-ia64_add_unwind_table(vm_offset_t base, vm_offset_t start, vm_offset_t end)
+unw_table_add(uint64_t base, uint64_t start, uint64_t end)
 {
-	struct ia64_unwind_table *ut;
+	struct unw_table *ut;
 
-	KASSERT(ia64_unwind_initialised, ("foo"));
-
-	ut = malloc(sizeof(struct ia64_unwind_table), M_UNWIND, M_NOWAIT);
+	ut = malloc(sizeof(struct unw_table), M_UNWIND, M_NOWAIT);
 	if (ut == NULL)
 		return (ENOMEM);
 
 	ut->ut_base = base;
-	ut->ut_start = (struct ia64_unwind_table_entry*)start;
-	ut->ut_end = (struct ia64_unwind_table_entry*)end;
+	ut->ut_start = (struct unw_entry*)start;
+	ut->ut_end = (struct unw_entry*)end;
 	ut->ut_limit = base + ut->ut_end[-1].ue_end;
-	LIST_INSERT_HEAD(&ia64_unwind_tables, ut, ut_link);
+	LIST_INSERT_HEAD(&unw_tables, ut, ut_link);
 
 	if (bootverbose)
 		printf("UNWIND: table added: base=%lx, start=%lx, end=%lx\n",
@@ -204,13 +171,11 @@
 }
 
 void
-ia64_delete_unwind_table(vm_offset_t base)
+unw_table_remove(uint64_t base)
 {
-	struct ia64_unwind_table *ut;
+	struct unw_table *ut;
 
-	KASSERT(ia64_unwind_initialised, ("foo"));
-
-	ut = find_table(base);
+	ut = unw_table_lookup(base);
 	if (ut != NULL) {
 		LIST_REMOVE(ut, ut_link);
 		free(ut, M_UNWIND);
@@ -219,86 +184,7 @@
 	}
 }
 
-struct ia64_unwind_state *
-ia64_create_unwind_state(struct trapframe *framep)
-{
-	struct ia64_unwind_state *us;
-	int i;
-
-	if (!ia64_unwind_initialised)
-		return 0;
-
-	us = LIST_FIRST(&ia64_unwind_states);
-	if (us) {
-		LIST_REMOVE(us, us_link);
-	} else {
-		us = malloc(sizeof(struct ia64_unwind_state),
-			    M_UNWIND, M_NOWAIT);
-		if (!us)
-			return 0;
-	}
-
-	bzero(us, sizeof(*us));
-	us->us_regs.rs_psp.ur_value = framep->tf_r[FRAME_SP];
-	us->us_regs.rs_pfs.ur_value = framep->tf_ar_pfs;
-	us->us_regs.rs_preds.ur_value = framep->tf_pr;
-	us->us_regs.rs_unat.ur_value = framep->tf_ar_unat;
-	us->us_regs.rs_rnat.ur_value = framep->tf_ar_rnat;
-	us->us_regs.rs_bsp.ur_value =
-		(u_int64_t) (framep->tf_ar_bspstore + framep->tf_ndirty);
-	us->us_regs.rs_bspstore.ur_value = framep->tf_ar_bspstore;
-	us->us_regs.rs_fpsr.ur_value = framep->tf_ar_fpsr;
-	for (i = 0; i < 8; i++) {
-		us->us_regs.rs_br[i].ur_value = framep->tf_b[i];
-	}
-	us->us_regs.rs_gr[0].ur_value = 0;
-	for (i = 1; i < 32; i++) {
-		us->us_regs.rs_gr[i].ur_value = framep->tf_r[i-1];
-	}
-	for (i = 6; i < 16; i++) {
-		us->us_regs.rs_fr[i].ur_value = framep->tf_f[i-6];
-	}
-
-	us->us_ip = framep->tf_cr_iip;
-	us->us_ri = (framep->tf_cr_ipsr & IA64_PSR_RI) >> 41;
-	us->us_spill = (u_int64_t *) us->us_regs.rs_gr[12].ur_value;
-	us->us_cfm = framep->tf_cr_ifs;
-	us->us_bsp = ia64_rse_previous_frame
-		((u_int64_t *) us->us_regs.rs_bsp.ur_value, us->us_cfm & 0x7f);
-
-	return us;
-}
-
-void
-ia64_free_unwind_state(struct ia64_unwind_state *us)
-{
-	LIST_INSERT_HEAD(&ia64_unwind_states, us, us_link);
-}
-
-u_int64_t
-ia64_unwind_state_get_ip(struct ia64_unwind_state *us)
-{
-	return us->us_ip + us->us_ri;
-}
-
-u_int64_t
-ia64_unwind_state_get_sp(struct ia64_unwind_state *us)
-{
-	return us->us_regs.rs_gr[12].ur_value;
-}
-
-u_int64_t
-ia64_unwind_state_get_cfm(struct ia64_unwind_state *us)
-{
-	return us->us_cfm;
-}
-
-u_int64_t *
-ia64_unwind_state_get_bsp(struct ia64_unwind_state *us)
-{
-	return us->us_bsp;
-}
-
+#if 0
 static u_int64_t
 read_uleb128(u_int8_t **pp)
 {
@@ -1510,3 +1396,4 @@
 
 	return 0;
 }
+#endif

==== //depot/projects/ia64_epc/sys/ia64/include/unwind.h#2 (text+ko) ====

@@ -26,13 +26,37 @@
  * $FreeBSD: src/sys/ia64/include/unwind.h,v 1.2 2002/10/19 19:30:38 marcel Exp $
  */
 
-int ia64_add_unwind_table(vm_offset_t, vm_offset_t, vm_offset_t);
-void ia64_delete_unwind_table(vm_offset_t);
+#ifndef _MACHINE_UNWIND_H_
+#define	_MACHINE_UNWIND_H_
+
+#include <machine/_regset.h>
+
+/*
+ * The unwind register state (unw_regstate) consists of the special
+ * registers and all the preserved registers. For each register in
+ * the unwind register state we need to keep track of the value and
+ * the location of that value. We use the common register structures
+ * for both the value and the location. Encoding of the location is
+ * as follows:
+ *	0x0...00		- value is in the register itself
+ *	0x0...01-0x0...7F	- value is in the general register
+ *	0x2...00-0xF...F8	- value is at the memory address
+ */
+struct _unw_regs {
+	struct _special		special;
+	struct _callee_saved	preserved;
+	struct _callee_saved_fp	preserved_fp;
+};
+
+struct unw_regstate {
+	struct _unw_regs	rs_val;
+	struct _unw_regs	rs_loc;
+};
+
+int unw_state_create(struct unw_regstate *);
+int unw_state_create_from_pcb(struct unw_regstate *, struct pcb *);
+
+int unw_table_add(uint64_t, uint64_t, uint64_t);
+void unw_table_remove(uint64_t);
 
-struct ia64_unwind_state *ia64_create_unwind_state(struct trapframe *framep);
-void ia64_free_unwind_state(struct ia64_unwind_state *us);
-u_int64_t ia64_unwind_state_get_ip(struct ia64_unwind_state *us);
-u_int64_t ia64_unwind_state_get_sp(struct ia64_unwind_state *us);
-u_int64_t ia64_unwind_state_get_cfm(struct ia64_unwind_state *us);
-u_int64_t *ia64_unwind_state_get_bsp(struct ia64_unwind_state *us);
-int ia64_unwind_state_previous_frame(struct ia64_unwind_state *us);
+#endif /* _MACHINE_UNWIND_H_ */



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