#ifndef _SYS_TRAPTRACE_H
#define _SYS_TRAPTRACE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/privregs.h>
#define TTR_STACK_DEPTH 10
#ifndef _ASM
#define TTR_PAD1_SIZE (sizeof (long) - 1)
typedef struct {
uintptr_t ttc_next;
uintptr_t ttc_first;
uintptr_t ttc_limit;
uintptr_t ttc_current;
} trap_trace_ctl_t;
typedef struct {
struct regs ttr_regs;
greg_t ttr_cr2;
union _ttr_info {
struct _idt_entry {
int cpuid;
short vector;
uchar_t ipl;
uchar_t spl;
uchar_t pri;
} idt_entry;
struct _gate_entry {
int sysnum;
} gate_entry;
} ttr_info;
uintptr_t ttr_curthread;
uchar_t ttr_pad[TTR_PAD1_SIZE];
uchar_t ttr_marker;
hrtime_t ttr_stamp;
int ttr_sdepth;
pc_t ttr_stack[TTR_STACK_DEPTH];
} trap_trace_rec_t;
#define ttr_cpuid ttr_info.idt_entry.cpuid
#define ttr_vector ttr_info.idt_entry.vector
#define ttr_ipl ttr_info.idt_entry.ipl
#define ttr_spl ttr_info.idt_entry.spl
#define ttr_pri ttr_info.idt_entry.pri
#define ttr_sysnum ttr_info.gate_entry.sysnum
#define TRAPTR_NENT 128
extern trap_trace_ctl_t trap_trace_ctl[NCPU];
extern size_t trap_trace_bufsize;
extern int trap_trace_freeze;
extern trap_trace_rec_t trap_trace_postmort;
#define TRAPTRACE_FREEZE trap_trace_freeze = 1;
#define TRAPTRACE_UNFREEZE trap_trace_freeze = 0;
#else
#ifdef TRAPTRACE
#if defined(__amd64)
#define TRACE_PTR(ptr, scr1, scr1_32, scr2, marker) \
leaq trap_trace_postmort(%rip), ptr; \
cmpl $0, trap_trace_freeze(%rip); \
jne 9f; \
LOADCPU(ptr); \
movl CPU_ID(ptr), scr1_32; \
shlq $TRAPTR_SIZE_SHIFT, scr1; \
leaq trap_trace_ctl(%rip), scr2; \
addq scr2, scr1; \
movq TRAPTR_NEXT(scr1), ptr; \
leaq TRAP_ENT_SIZE(ptr), scr2; \
cmpq TRAPTR_LIMIT(scr1), scr2; \
jl 8f; \
movq TRAPTR_FIRST(scr1), scr2; \
8: movq scr2, TRAPTR_NEXT(scr1); \
9: movb marker, TTR_MARKER(ptr);
#elif defined(__i386)
#define TRACE_PTR(ptr, scr1, scr1_32, scr2, marker) \
movl $trap_trace_postmort, ptr; \
cmpl $0, trap_trace_freeze; \
jne 9f; \
LOADCPU(ptr); \
movl CPU_ID(ptr), scr1_32; \
shll $TRAPTR_SIZE_SHIFT, scr1; \
addl $trap_trace_ctl, scr1; \
movl TRAPTR_NEXT(scr1), ptr; \
leal TRAP_ENT_SIZE(ptr), scr2; \
cmpl TRAPTR_LIMIT(scr1), scr2; \
jl 8f; \
movl TRAPTR_FIRST(scr1), scr2; \
8: movl scr2, TRAPTR_NEXT(scr1); \
9: movb marker, TTR_MARKER(ptr);
#endif
#if defined(__xpv)
#define __GETCR2(_mov, reg) \
_mov %gs:CPU_VCPU_INFO, reg; \
_mov VCPU_INFO_ARCH_CR2(reg), reg
#else
#define __GETCR2(_mov, reg) \
_mov %cr2, reg
#endif
#if defined(__amd64)
#define TRACE_REGS(ptr, reg, scr1, scr2) \
xorq scr1, scr1; \
\
9: movq (reg, scr1, 1), scr2; \
movq scr2, (ptr, scr1, 1); \
addq $CLONGSIZE, scr1; \
cmpq $REGSIZE, scr1; \
jl 9b; \
movq %gs:CPU_THREAD, scr2; \
movq scr2, TTR_CURTHREAD(ptr); \
__GETCR2(movq, scr2); \
movq scr2, TTR_CR2(ptr)
#elif defined(__i386)
#define TRACE_REGS(ptr, reg, scr1, scr2) \
xorl scr1, scr1; \
\
9: movl (reg, scr1, 1), scr2; \
movl scr2, (ptr, scr1, 1); \
addl $CLONGSIZE, scr1; \
cmpl $REGSIZE, scr1; \
jl 9b; \
movl %gs:CPU_THREAD, scr2; \
movl scr2, TTR_CURTHREAD(ptr); \
__GETCR2(movl, scr2); \
movl scr2, TTR_CR2(ptr)
#endif
#if defined(__amd64)
#define TRACE_STAMP(reg) \
rdtsc; \
movl %eax, TTR_STAMP(reg); \
movl %edx, TTR_STAMP+4(reg)
#define TRACE_STACK(tt) \
pushq %rdi; \
pushq %rsi; \
pushq %rdx; \
pushq %rcx; \
pushq %r8; \
pushq %r9; \
pushq %rax; \
pushq %r12; \
movq tt, %r12; \
leaq TTR_STACK(%r12), %rdi; \
movl $TTR_STACK_DEPTH, %esi; \
call getpcstack; \
movl %eax, TTR_SDEPTH(%r12); \
popq %r12; \
popq %rax; \
popq %r9; \
popq %r8; \
popq %rcx; \
popq %rdx; \
popq %rsi; \
popq %rdi
#elif defined(__i386)
#define TRACE_STAMP(reg) \
xorl %eax, %eax; \
xorl %edx, %edx; \
btl $X86FSET_TSC, x86_featureset; \
jnc 9f; \
rdtsc; \
9: movl %eax, TTR_STAMP(reg); \
movl %edx, TTR_STAMP+4(reg)
#define TRACE_STACK(tt) \
pushl %eax; \
pushl %ecx; \
pushl %edx; \
pushl %ebx; \
pushl $TTR_STACK_DEPTH; \
movl tt, %ebx; \
leal TTR_STACK(%ebx), %eax; \
pushl %eax; \
call getpcstack; \
addl $8, %esp; \
movl %eax, TTR_SDEPTH(%ebx); \
popl %ebx; \
popl %edx; \
popl %ecx; \
popl %eax
#endif
#else
#define TRACE_PTR(ptr, scr1, scr1_32, scr2, marker)
#define TRACE_REGS(ptr, reg, scr1, scr2)
#define TRACE_STAMP(reg)
#define TRACE_STACK(reg)
#endif
#endif
#define TT_SYSCALL 0xaa
#define TT_SYSENTER 0xab
#define TT_SYSC 0xad
#define TT_SYSC64 0xae
#define TT_INTERRUPT 0xbb
#define TT_TRAP 0xcc
#define TT_INTTRAP 0xdd
#define TT_EVENT 0xee
#ifdef __cplusplus
}
#endif
#endif