From owner-p4-projects@FreeBSD.ORG Sat Apr 12 15:32:55 2003 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BFF9A37B404; Sat, 12 Apr 2003 15:32:54 -0700 (PDT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4F97237B401 for ; Sat, 12 Apr 2003 15:32:54 -0700 (PDT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 9722B43F75 for ; Sat, 12 Apr 2003 15:32:53 -0700 (PDT) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.12.6/8.12.6) with ESMTP id h3CMWr0U063494 for ; Sat, 12 Apr 2003 15:32:53 -0700 (PDT) (envelope-from marcel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.12.6/8.12.6/Submit) id h3CMWrSs063491 for perforce@freebsd.org; Sat, 12 Apr 2003 15:32:53 -0700 (PDT) Date: Sat, 12 Apr 2003 15:32:53 -0700 (PDT) Message-Id: <200304122232.h3CMWrSs063491@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to marcel@freebsd.org using -f From: Marcel Moolenaar To: Perforce Change Reviews Subject: PERFORCE change 28844 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 12 Apr 2003 22:32:56 -0000 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 . 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 #include -#include #include #include ==== //depot/projects/ia64_epc/sys/ia64/ia64/db_trace.c#2 (text+ko) ==== @@ -31,7 +31,6 @@ #include #include #include -#include #include #include ==== //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 #include #include -#include #include #include @@ -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 #include #include -#include #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 #include -#include +#include #include -#include #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 + +/* + * 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_ */