Fix and improve exception tracing:

1.  Name the kernel option XTRACE instead of EXCEPTION_TRACING
2.  Put support functions in ia64/ia64/xtrace.c
3.  Make it work with SMP by giving each CPU its own buffer
4.  Save 16 key registers in the buffer for every exception
5.  In ia64_handle_intr() and trap() transfer the trace record
    to the KTR trace buffer using CTRx() and with some basic
    information for now
6.  Use a tunable to anble tracing and stop tracing as soon as
    we enter the debugger

Room for improvements:
1.  Transferring exception-relevant information to KTR
2.  Add a sysctl to enable/disable tracing
This commit is contained in:
Marcel Moolenaar 2014-03-18 23:51:34 +00:00
parent 4feac03f2c
commit ac5c8b7c5b
12 changed files with 441 additions and 85 deletions

View File

@ -110,6 +110,7 @@ ia64/ia64/uma_machdep.c standard
ia64/ia64/unaligned.c standard
ia64/ia64/unwind.c standard
ia64/ia64/vm_machdep.c standard
ia64/ia64/xtrace.c optional xtrace
ia64/isa/isa.c optional isa
ia64/isa/isa_dma.c optional isa
ia64/pci/pci_cfgreg.c optional pci

View File

@ -13,7 +13,7 @@ COMPAT_FREEBSD32 opt_compat.h
PV_STATS opt_pmap.h
EXCEPTION_TRACING opt_xtrace.h
XTRACE
VGA_ALT_SEQACCESS opt_vga.h
VGA_DEBUG opt_vga.h

View File

@ -26,11 +26,11 @@
* SUCH DAMAGE.
*/
#include "opt_xtrace.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_xtrace.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cons.h>
@ -585,6 +585,10 @@ db_show_mdpcpu(struct pcpu *pc)
db_printf("MD: clock_load = %#lx\n", md->clock_load);
db_printf("MD: stats = %p\n", &md->stats);
db_printf("MD: pmap = %p\n", md->current_pmap);
#ifdef XTRACE
db_printf("MD: xtrace_buffer = %p\n", md->xtrace_buffer);
db_printf("MD: xtrace_tail = %#lx\n", md->xtrace_tail);
#endif
}
void
@ -604,29 +608,3 @@ db_trace_thread(struct thread *td, int count)
ctx = kdb_thr_ctx(td);
return (db_backtrace(td, ctx, count));
}
#ifdef EXCEPTION_TRACING
extern long xtrace[];
extern long *xhead;
DB_COMMAND(xtrace, db_xtrace)
{
long *p;
p = (*xhead == 0) ? xtrace : xhead;
db_printf("ITC\t\t IVT\t\t IIP\t\t IFA\t\t ISR\n");
if (*p == 0)
return;
do {
db_printf("%016lx %016lx %016lx %016lx %016lx\n", p[0], p[1],
p[2], p[3], p[4]);
p += 5;
if (p == (void *)&xhead)
p = xtrace;
} while (p != xhead);
}
#endif

View File

@ -50,63 +50,185 @@ __FBSDID("$FreeBSD$");
.section .ivt.data, "aw"
.align 8
.global ia64_kptdir
.size ia64_kptdir, 8
ia64_kptdir: data8 0
#ifdef EXCEPTION_TRACING
#ifdef XTRACE
.global xtrace, xhead
xtrace: .space 1024*5*8
xhead: data8 xtrace
.align 8
.global ia64_xtrace_mask
.size ia64_xtrace_mask, 8
ia64_xtrace_mask: data8 0
#define XTRACE(offset) \
{ .mmi ; \
mov r24=ar.itc ; \
mov r25=cr.iip ; \
mov r27=offset ; \
.align 4
.global ia64_xtrace_enabled
.size ia64_xtrace_enabled, 4
ia64_xtrace_enabled: data4 0
#define XTRACE_HOOK(offset) \
{ .mii ; \
nop 0 ; \
mov r31 = b7 ; \
mov r28 = pr ; \
} ; \
{ .mlx ; \
mov r28=cr.ifa ; \
movl r29=xhead ;; \
} ; \
{ .mmi ; \
ld8 r29=[r29] ;; \
st8 [r29]=r24,8 ; \
nop 0 ;; \
} ; \
{ .mmi ; \
st8 [r29]=r27,8 ;; \
mov r24=cr.isr ; \
add r27=8,r29 ;; \
} ; \
{ .mmi ; \
st8 [r29]=r25,16 ;; \
st8 [r27]=r28,16 ; \
mov r25=pr ;; \
} ; \
{ .mlx ; \
st8 [r29]=r24 ; \
movl r28=xhead ;; \
{ .mib ; \
nop 0 ; \
mov r25 = ip ; \
br.sptk ia64_xtrace_write ;; \
} ; \
{ .mii ; \
cmp.eq p15,p0=r27,r28 ; \
addl r29=1024*5*8,r0 ;; \
(p15) sub r27=r28,r29 ;; \
} ; \
{ .mmi ; \
st8 [r28]=r27 ; \
nop 0 ; \
mov pr=r25,0x1ffff ;; \
nop 0 ; \
mov b7 = r31 ; \
mov pr = r28, 0x1ffff ;; \
}
#else
.section .ivt.text, "ax"
#define XTRACE(offset)
// We can only use r25, r26 & r27
ENTRY_NOPROFILE(ia64_xtrace_write, 0)
{ .mlx
add r25 = 16, r25
movl r26 = ia64_xtrace_enabled
;;
}
{ .mmi
mov r27 = ar.k3
ld4 r26 = [r26]
mov b7 = r25
;;
}
{ .mib
add r25 = -32, r25
cmp.eq p15,p0 = r0, r26
(p15) br.dptk.few b7
;;
}
{ .mib
nop 0
cmp.eq p15,p0 = r0, r27
(p15) br.dptk.few b7
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x00 IVT
mov r26 = ar.itc
nop 0
;;
}
{ .mmi
st8 [r27] = r26, 8 // 0x08 ITC
mov r25 = cr.iip
nop 0
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x10 IIP
mov r26 = cr.ifa
nop 0
;;
}
{ .mmi
st8 [r27] = r26, 8 // 0x18 IFA
mov r25 = cr.isr
nop 0
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x20 ISR
mov r26 = cr.ipsr
nop 0
;;
}
{ .mmi
st8 [r27] = r26, 8 // 0x28 IPSR
mov r25 = cr.itir
nop 0
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x30 ITIR
mov r26 = cr.iipa
nop 0
;;
}
{ .mmi
st8 [r27] = r26, 8 // 0x38 IIPA
mov r25 = cr.ifs
nop 0
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x40 IFS
mov r26 = cr.iim
nop 0
;;
}
{ .mmi
st8 [r27] = r26, 8 // 0x48 IIM
mov r25 = cr.iha
nop 0
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x50 IHA
mov r26 = ar.unat
nop 0
;;
}
{ .mmi
st8 [r27] = r26, 8 // 0x58 UNAT
mov r25 = ar.rsc
nop 0
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x60 RSC
mov r26 = ar.bsp
nop 0
;;
}
{ .mmi
st8 [r27] = r26, 8 // 0x68 BSP
mov r25 = r13
nop 0
;;
}
{ .mmi
st8 [r27] = r25, 8 // 0x70 PCPU/TLS
mov r26 = r12
nop 0
;;
}
{ .mlx
st8 [r27] = r26, 8 // 0x78 SP
movl r25 = ia64_xtrace_mask
;;
}
{ .mmi
ld8 r26 = [r25]
;;
and r25 = r27, r26
nop 0
;;
}
{ .mib
mov ar.k3 = r25
nop 0
br.sptk b7
;;
}
END(ia64_xtrace_write)
#endif
#else /* XTRACE */
#define XTRACE_HOOK(offset)
.section .ivt.text, "ax"
#endif /* XTRACE */
/*
* exception_save: save interrupted state
*
@ -632,6 +754,7 @@ ENTRY_NOPROFILE(exception_restore, 0)
ssm psr.dt
;;
srlz.d
mov r16 = r25
exception_restore_restart:
{ .mmi
@ -649,20 +772,21 @@ exception_restore_restart:
;;
}
{ .mmi
mov cr.ifs=r16
mov ar.k6=r31
mov ar.rnat=r21
mov pr=r18,0x1ffff
;;
}
{ .mmi
mov cr.iip=r19
mov ar.unat=r17
nop 0
;;
}
{ .mmi
mov ar.unat=r17
mov cr.iip=r19
nop 0
}
{ .mmi
mov cr.ipsr=r24
mov cr.ifs=r25
mov pr=r18,0x1ffff
mov ar.rnat=r21
nop 0
;;
}
{ .mmb
@ -713,7 +837,7 @@ END(exception_restore)
.save rp, r0; \
.body; \
ivt_##name: \
XTRACE(offset)
XTRACE_HOOK(offset)
#define IVT_END(name) \
.endp ivt_##name

View File

@ -25,6 +25,7 @@
*/
#include "opt_ddb.h"
#include "opt_xtrace.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -305,6 +306,11 @@ ia64_handle_intr(struct trapframe *tf)
td = curthread;
ia64_set_fpsr(IA64_FPSR_DEFAULT);
#ifdef XTRACE
ia64_xtrace_save();
#endif
PCPU_INC(cnt.v_intr);
xiv = ia64_get_ivr();

View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ddb.h"
#include "opt_kstack_pages.h"
#include "opt_sched.h"
#include "opt_xtrace.h"
#include <sys/param.h>
#include <sys/proc.h>
@ -177,9 +178,6 @@ void (*cpu_idle_hook)(sbintime_t) = NULL;
struct kva_md_info kmi;
#define Mhz 1000000L
#define Ghz (1000L*Mhz)
static void
identifycpu(void)
{
@ -566,6 +564,9 @@ void
kdb_cpu_trap(int vector, int code __unused)
{
#ifdef XTRACE
ia64_xtrace_stop();
#endif
__asm __volatile("flushrs;;");
/* Restart after the break instruction. */
@ -892,6 +893,10 @@ ia64_init(void)
*/
pmap_bootstrap();
#ifdef XTRACE
ia64_xtrace_init_bsp();
#endif
/*
* Initialize debuggers, and break into them if appropriate.
*/

View File

@ -29,6 +29,7 @@
__FBSDID("$FreeBSD$");
#include "opt_kstack_pages.h"
#include "opt_xtrace.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -236,6 +237,10 @@ ia64_ap_startup(void)
ia64_set_fpsr(IA64_FPSR_DEFAULT);
#ifdef XTRACE
ia64_xtrace_init_ap(ia64_ap_state.as_xtrace_buffer);
#endif
/* Wait until it's time for us to be unleashed */
while (ia64_ap_state.as_spin)
cpu_spinwait();
@ -398,6 +403,10 @@ cpu_mp_start()
ia64_ap_state.as_kstack = stp;
ia64_ap_state.as_kstack_top = stp + KSTACK_PAGES * PAGE_SIZE;
#ifdef XTRACE
ia64_ap_state.as_xtrace_buffer = ia64_xtrace_alloc();
#endif
ia64_ap_state.as_trace = 0;
ia64_ap_state.as_delay = 2000;
ia64_ap_state.as_awake = 0;

View File

@ -354,6 +354,12 @@ trap(int vector, struct trapframe *tf)
ksiginfo_t ksi;
user = TRAPF_USERMODE(tf) ? 1 : 0;
if (user)
ia64_set_fpsr(IA64_FPSR_DEFAULT);
#ifdef XTRACE
ia64_xtrace_save();
#endif
PCPU_INC(cnt.v_trap);
@ -362,7 +368,6 @@ trap(int vector, struct trapframe *tf)
ucode = 0;
if (user) {
ia64_set_fpsr(IA64_FPSR_DEFAULT);
td->td_pticks = 0;
td->td_frame = tf;
if (td->td_ucred != p->p_ucred)

220
sys/ia64/ia64/xtrace.c Normal file
View File

@ -0,0 +1,220 @@
/*-
* Copyright (c) 2014 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "opt_ddb.h"
#include "opt_xtrace.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/malloc.h>
#include <sys/pcpu.h>
#include <machine/md_var.h>
#include <machine/pte.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/vm_kern.h>
#define XTRACE_LOG2SZ 14 /* 16KB trace buffers */
struct ia64_xtrace_record {
uint64_t ivt;
uint64_t itc;
uint64_t iip;
uint64_t ifa;
uint64_t isr;
uint64_t ipsr;
uint64_t itir;
uint64_t iipa;
uint64_t ifs;
uint64_t iim;
uint64_t iha;
uint64_t unat;
uint64_t rsc;
uint64_t bsp;
uint64_t tp;
uint64_t sp;
};
extern uint32_t ia64_xtrace_enabled;
extern uint64_t ia64_xtrace_mask;
static uint64_t ia64_xtrace_base;
static void
ia64_xtrace_init_common(vm_paddr_t pa)
{
uint64_t psr;
pt_entry_t pte;
pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
PTE_PL_KERN | PTE_AR_RW;
pte |= pa & PTE_PPN_MASK;
__asm __volatile("ptr.d %0,%1" :: "r"(ia64_xtrace_base),
"r"(XTRACE_LOG2SZ << 2));
__asm __volatile("mov %0=psr" : "=r"(psr));
__asm __volatile("rsm psr.ic|psr.i");
ia64_srlz_i();
ia64_set_ifa(ia64_xtrace_base);
ia64_set_itir(XTRACE_LOG2SZ << 2);
ia64_srlz_d();
__asm __volatile("itr.d dtr[%0]=%1" :: "r"(6), "r"(pte));
__asm __volatile("mov psr.l=%0" :: "r" (psr));
ia64_srlz_i();
PCPU_SET(md.xtrace_tail, ia64_xtrace_base);
ia64_set_k3(ia64_xtrace_base);
}
void *
ia64_xtrace_alloc(void)
{
uintptr_t buf;
size_t sz;
sz = 1UL << XTRACE_LOG2SZ;
buf = kmem_alloc_contig(kernel_arena, sz, M_WAITOK | M_ZERO,
0UL, ~0UL, sz, 0, VM_MEMATTR_DEFAULT);
return ((void *)buf);
}
void
ia64_xtrace_init_ap(void *buf)
{
vm_paddr_t pa;
if (buf == NULL) {
ia64_set_k3(0);
return;
}
PCPU_SET(md.xtrace_buffer, buf);
pa = ia64_tpa((uintptr_t)buf);
ia64_xtrace_init_common(pa);
}
void
ia64_xtrace_init_bsp(void)
{
void *buf;
vm_paddr_t pa;
size_t sz;
sz = 1UL << XTRACE_LOG2SZ;
ia64_xtrace_base = VM_MIN_KERNEL_ADDRESS + (sz << 1);
ia64_xtrace_mask = ~sz;
buf = ia64_physmem_alloc(sz, sz);
if (buf == NULL) {
ia64_set_k3(0);
return;
}
PCPU_SET(md.xtrace_buffer, buf);
pa = IA64_RR_MASK((uintptr_t)buf);
ia64_xtrace_init_common(pa);
}
static void
ia64_xtrace_init(void *dummy __unused)
{
TUNABLE_INT_FETCH("machdep.xtrace.enabled", &ia64_xtrace_enabled);
}
SYSINIT(xtrace, SI_SUB_CPU, SI_ORDER_ANY, ia64_xtrace_init, NULL);
void
ia64_xtrace_save(void)
{
struct ia64_xtrace_record *rec;
uint64_t head, tail;
critical_enter();
head = ia64_get_k3();
tail = PCPU_GET(md.xtrace_tail);
if (head == 0 || tail == 0) {
critical_exit();
return;
}
while (head != tail) {
rec = (void *)(uintptr_t)tail;
CTR6(KTR_TRAP, "XTRACE: itc=%lu, ticks=%d: "
"IVT=%#lx, IIP=%#lx, IFA=%#lx, ISR=%#lx",
rec->itc, ticks,
rec->ivt, rec->iip, rec->ifa, rec->isr);
tail += sizeof(*rec);
tail &= ia64_xtrace_mask;
}
PCPU_SET(md.xtrace_tail, tail);
critical_exit();
}
void
ia64_xtrace_stop(void)
{
ia64_xtrace_enabled = 0;
}
#if 0
#ifdef DDB
#include <ddb/ddb.h>
DB_SHOW_COMMAND(xtrace, db_xtrace)
{
struct ia64_xtrace_record *p, *r;
p = (ia64_xtptr == 0) ? ia64_xtptr1 : ia64_xtptr;
if (p == 0) {
db_printf("Exception trace buffer not allocated\n");
return;
}
r = (p->ivt == 0) ? ia64_xtbase : p;
if (r->ivt == 0) {
db_printf("No exception trace records written\n");
return;
}
db_printf("IVT\t\t ITC\t\t IIP\t\t IFA\n");
do {
db_printf("%016lx %016lx %016lx %016lx\n",
r->ivt, r->itc, r->iip, r->ifa);
r++;
if (r == ia64_xtlim)
r = ia64_xtbase;
} while (r != p);
}
#endif /* DDB */
#endif

View File

@ -102,6 +102,11 @@ int ia64_physmem_init(void);
int ia64_physmem_track(vm_paddr_t, vm_size_t);
void ia64_probe_sapics(void);
void ia64_sync_icache(vm_offset_t, vm_size_t);
void *ia64_xtrace_alloc(void);
void ia64_xtrace_init_ap(void *);
void ia64_xtrace_init_bsp(void);
void ia64_xtrace_save(void);
void ia64_xtrace_stop(void);
void interrupt(struct trapframe *);
void map_gateway_page(void);
void map_pal_code(void);

View File

@ -56,6 +56,8 @@ struct pcpu_md {
uint32_t clock_mode; /* Clock ET mode */
uint32_t awake:1; /* CPU is awake? */
struct pcpu_stats stats; /* Interrupt stats. */
void *xtrace_buffer;
uint64_t xtrace_tail;
#ifdef _KERNEL
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
@ -65,7 +67,7 @@ struct pcpu_md {
#define PCPU_MD_FIELDS \
uint32_t pc_acpi_id; /* ACPI CPU id. */ \
struct pcpu_md pc_md; /* MD fields. */ \
char __pad[1265]
char __pad[10*128]
#ifdef _KERNEL

View File

@ -32,6 +32,7 @@ struct ia64_ap_state {
void *as_kstack;
void *as_kstack_top;
struct pcpu *as_pcpu;
void *as_xtrace_buffer;
volatile int as_delay;
volatile u_int as_awake;
volatile u_int as_spin;