#include <cpus.h>
#include <kern/lock.h>
#include <kern/etap_macros.h>
#include <kern/misc_protos.h>
#include <kern/host.h>
#include <types.h>
#include <mach/kern_return.h>
#include <mach/port.h>
#include <vm/vm_map.h>
#include <vm/vm_kern.h>
#if ETAP_MONITOR
#include <machine/machine_tables.h>
#include <mach/clock.h>
#include <mach/clock_reply.h>
#include <mach/default_pager_object.h>
#include <device/device.h>
#include <device/device_reply.h>
#include <device/device_request.h>
#include <mach_debug/mach_debug.h>
#include <mach/mach_norma.h>
#include <mach/mach_port.h>
#include <mach/memory_object_default.h>
#include <mach/memory_object_user.h>
#include <mach/notify_server.h>
#include <mach/prof.h>
#include <machine/unix_map.h>
#endif
#if MACH_KDB
#include <ddb/db_output.h>
#include <ddb/db_sym.h>
#include <ddb/db_command.h>
#if 0
#include <i386/ipl.h>
#endif
#endif
kern_return_t
etap_get_info(host_priv_t, int*, int*, vm_offset_t*, vm_offset_t*,
int*, int*, int*, int*);
kern_return_t
etap_mon_reconfig(host_priv_t, int);
kern_return_t
etap_new_probe(host_priv_t, vm_address_t, vm_size_t, boolean_t, vm_address_t);
kern_return_t
etap_trace_thread(thread_act_t, boolean_t);
void
etap_trace_reset(int);
void
etap_interrupt_probe(int, int);
void
etap_machcall_probe1(int);
void
etap_machcall_probe2(void);
void
etap_print(void);
#if ETAP
#ifndef max
#define max(x,y) ((x > y) ? x : y)
#endif
event_table_t
etap_event_table_find(etap_event_t);
#if ETAP_LOCK_TRACE
#define etap_lock simple_lock_no_trace
#define etap_unlock simple_unlock_no_trace
#else
#define etap_lock simple_lock
#define etap_unlock simple_unlock
#endif
#define event_table_lock() etap_lock(&event_table_lock)
#define event_table_unlock() etap_unlock(&event_table_lock)
#define cumulative_buffer_lock(s) \
MACRO_BEGIN \
s = splhigh(); \
etap_lock(&cbuff_lock); \
MACRO_END
#define cumulative_buffer_unlock(s) \
MACRO_BEGIN \
etap_unlock(&cbuff_lock); \
splx(s); \
MACRO_END
#if ETAP_LOCK_ACCUMULATE
int cbuff_width = ETAP_CBUFF_WIDTH;
#define TWO_PAGES 16384
#define CBUFF_ALLOCATED_SIZE sizeof(struct cumulative_buffer)+TWO_PAGES
decl_simple_lock_data (,cbuff_lock)
#if MACH_LDEBUG
simple_lock_t cbuff_locks;
#else
simple_lock_data_t cbuff_locks;
#endif
char cbuff_allocated [CBUFF_ALLOCATED_SIZE];
cumulative_buffer_t cbuff = {0};
#endif
#if ETAP_MONITOR
int mbuff_entries = ETAP_MBUFF_ENTRIES;
struct monitor_buffer *mbuff[NCPUS];
#endif
decl_simple_lock_data(,event_table_lock)
const struct event_table_entry event_table_init[] =
{
#if ETAP_EVENT_MONITOR
{ETAP_P_USER_EVENT0 , ETAP_TRACE_OFF , "p_user_event0" , STATIC},
{ETAP_P_USER_EVENT1 , ETAP_TRACE_OFF , "p_user_event1" , STATIC},
{ETAP_P_USER_EVENT2 , ETAP_TRACE_OFF , "p_user_event2" , STATIC},
{ETAP_P_USER_EVENT3 , ETAP_TRACE_OFF , "p_user_event3" , STATIC},
{ETAP_P_USER_EVENT4 , ETAP_TRACE_OFF , "p_user_event4" , STATIC},
{ETAP_P_USER_EVENT5 , ETAP_TRACE_OFF , "p_user_event5" , STATIC},
{ETAP_P_USER_EVENT6 , ETAP_TRACE_OFF , "p_user_event6" , STATIC},
{ETAP_P_USER_EVENT7 , ETAP_TRACE_OFF , "p_user_event7" , STATIC},
{ETAP_P_USER_EVENT8 , ETAP_TRACE_OFF , "p_user_event8" , STATIC},
{ETAP_P_USER_EVENT9 , ETAP_TRACE_OFF , "p_user_event9" , STATIC},
{ETAP_P_USER_EVENT10 , ETAP_TRACE_OFF , "p_user_event10" , STATIC},
{ETAP_P_USER_EVENT11 , ETAP_TRACE_OFF , "p_user_event11" , STATIC},
{ETAP_P_USER_EVENT12 , ETAP_TRACE_OFF , "p_user_event12" , STATIC},
{ETAP_P_USER_EVENT13 , ETAP_TRACE_OFF , "p_user_event13" , STATIC},
{ETAP_P_USER_EVENT14 , ETAP_TRACE_OFF , "p_user_event14" , STATIC},
{ETAP_P_USER_EVENT15 , ETAP_TRACE_OFF , "p_user_event15" , STATIC},
{ETAP_P_USER_EVENT16 , ETAP_TRACE_OFF , "p_user_event16" , STATIC},
{ETAP_P_USER_EVENT17 , ETAP_TRACE_OFF , "p_user_event17" , STATIC},
{ETAP_P_USER_EVENT18 , ETAP_TRACE_OFF , "p_user_event18" , STATIC},
{ETAP_P_USER_EVENT19 , ETAP_TRACE_OFF , "p_user_event19" , STATIC},
{ETAP_P_USER_EVENT20 , ETAP_TRACE_OFF , "p_user_event20" , STATIC},
{ETAP_P_USER_EVENT21 , ETAP_TRACE_OFF , "p_user_event21" , STATIC},
{ETAP_P_USER_EVENT22 , ETAP_TRACE_OFF , "p_user_event22" , STATIC},
{ETAP_P_USER_EVENT23 , ETAP_TRACE_OFF , "p_user_event23" , STATIC},
{ETAP_P_USER_EVENT24 , ETAP_TRACE_OFF , "p_user_event24" , STATIC},
{ETAP_P_USER_EVENT25 , ETAP_TRACE_OFF , "p_user_event25" , STATIC},
{ETAP_P_USER_EVENT26 , ETAP_TRACE_OFF , "p_user_event26" , STATIC},
{ETAP_P_USER_EVENT27 , ETAP_TRACE_OFF , "p_user_event27" , STATIC},
{ETAP_P_USER_EVENT28 , ETAP_TRACE_OFF , "p_user_event28" , STATIC},
{ETAP_P_USER_EVENT29 , ETAP_TRACE_OFF , "p_user_event29" , STATIC},
{ETAP_P_USER_EVENT30 , ETAP_TRACE_OFF , "p_user_event30" , STATIC},
{ETAP_P_USER_EVENT31 , ETAP_TRACE_OFF , "p_user_event31" , STATIC},
{ETAP_P_SYSCALL_MACH , ETAP_TRACE_OFF , "p_syscall_mach" , STATIC},
{ETAP_P_SYSCALL_UNIX , ETAP_TRACE_OFF , "p_syscall_unix" , STATIC},
{ETAP_P_THREAD_LIFE , ETAP_TRACE_OFF , "p_thread_life" , STATIC},
{ETAP_P_THREAD_CTX , ETAP_TRACE_OFF , "p_thread_ctx" , STATIC},
{ETAP_P_RPC , ETAP_TRACE_OFF , "p_rpc" , STATIC},
{ETAP_P_INTERRUPT , ETAP_TRACE_OFF , "p_interrupt" , STATIC},
{ETAP_P_ACT_ABORT , ETAP_TRACE_OFF , "p_act_abort" , STATIC},
{ETAP_P_PRIORITY , ETAP_TRACE_OFF , "p_priority" , STATIC},
{ETAP_P_EXCEPTION , ETAP_TRACE_OFF , "p_exception" , STATIC},
{ETAP_P_DEPRESSION , ETAP_TRACE_OFF , "p_depression" , STATIC},
{ETAP_P_MISC , ETAP_TRACE_OFF , "p_misc" , STATIC},
{ETAP_P_DETAP , ETAP_TRACE_OFF , "p_detap" , STATIC},
#endif
#if ETAP_LOCK_TRACE
{ETAP_VM_BUCKET , ETAP_TRACE_OFF , "vm_bucket" , STATIC},
{ETAP_VM_HIMEM , ETAP_TRACE_OFF , "vm_himem" , STATIC},
{ETAP_VM_MAP , ETAP_TRACE_OFF , "vm_map" , 1},
{ETAP_VM_MAP_I , ETAP_TRACE_OFF , "vm_map_i" , 2},
{ETAP_VM_MEMMAN , ETAP_TRACE_OFF , "vm_memman" , STATIC},
{ETAP_VM_MSYNC , ETAP_TRACE_OFF , "vm_msync" , 3},
{ETAP_VM_OBJ , ETAP_TRACE_OFF , "vm_obj" , 4},
{ETAP_VM_OBJ_CACHE , ETAP_TRACE_OFF , "vm_obj_cache" , 5},
{ETAP_VM_PAGE_ALLOC , ETAP_TRACE_OFF , "vm_page_alloc" , STATIC},
{ETAP_VM_PAGEOUT , ETAP_TRACE_OFF , "vm_pageout" , STATIC},
{ETAP_VM_PAGEQ , ETAP_TRACE_OFF , "vm_pageq" , STATIC},
{ETAP_VM_PAGEQ_FREE , ETAP_TRACE_OFF , "vm_pageq_free" , STATIC},
{ETAP_VM_PMAP , ETAP_TRACE_OFF , "vm_pmap" , 6},
{ETAP_VM_PMAP_CACHE , ETAP_TRACE_OFF , "vm_pmap_cache" , STATIC},
{ETAP_VM_PMAP_FREE , ETAP_TRACE_OFF , "vm_pmap_free" , STATIC},
{ETAP_VM_PMAP_KERNEL , ETAP_TRACE_OFF , "vm_pmap_kern" , STATIC},
{ETAP_VM_PMAP_SYS , ETAP_TRACE_OFF , "vm_pmap_sys" , 7},
{ETAP_VM_PMAP_SYS_I , ETAP_TRACE_OFF , "vm_pmap_sys_i" , 8},
{ETAP_VM_PMAP_UPDATE , ETAP_TRACE_OFF , "vm_pmap_update" , STATIC},
{ETAP_VM_PREPPIN , ETAP_TRACE_OFF , "vm_preppin" , STATIC},
{ETAP_VM_RESULT , ETAP_TRACE_OFF , "vm_result" , 9},
{ETAP_VM_TEST , ETAP_TRACE_OFF , "vm_tes" , STATIC},
{ETAP_VM_PMAP_PHYSENTRIES, ETAP_TRACE_OFF , "vm_pmap_physentries", STATIC},
{ETAP_VM_PMAP_SID , ETAP_TRACE_OFF , "vm_pmap_sid" , STATIC},
{ETAP_VM_PMAP_PTE , ETAP_TRACE_OFF , "vm_pmap_pte" , STATIC},
{ETAP_VM_PMAP_PTE_OVFLW , ETAP_TRACE_OFF , "vm_pmap_pte_ovflw", STATIC},
{ETAP_VM_PMAP_TLB , ETAP_TRACE_OFF , "vm_pmap_tlb" , STATIC},
{ETAP_IPC_IHGB , ETAP_TRACE_OFF , "ipc_ihgb" , 10},
{ETAP_IPC_IS , ETAP_TRACE_OFF , "ipc_is" , 11},
{ETAP_IPC_IS_REF , ETAP_TRACE_OFF , "ipc_is_ref" , 12},
{ETAP_IPC_MQUEUE , ETAP_TRACE_OFF , "ipc_mqueue" , STATIC},
{ETAP_IPC_OBJECT , ETAP_TRACE_OFF , "ipc_object" , STATIC},
{ETAP_IPC_PORT_MULT , ETAP_TRACE_OFF , "ipc_port_mult" , 13},
{ETAP_IPC_PORT_TIME , ETAP_TRACE_OFF , "ipc_port_time" , 14},
{ETAP_IPC_RPC , ETAP_TRACE_OFF , "ipc_rpc" , 15},
{ETAP_IPC_PORT_ALLOCQ , ETAP_TRACE_OFF , "ipc_port_allocq" , STATIC},
{ETAP_IO_AHA , ETAP_TRACE_OFF , "io_aha" , STATIC},
{ETAP_IO_CHIP , ETAP_TRACE_OFF , "io_chip" , STATIC},
{ETAP_IO_DEV , ETAP_TRACE_OFF , "io_dev" , 16},
{ETAP_IO_DEV_NUM , ETAP_TRACE_OFF , "io_dev_num" , STATIC},
{ETAP_IO_DEV_PAGEH , ETAP_TRACE_OFF , "io_dev_pageh" , STATIC},
{ETAP_IO_DEV_PAGER , ETAP_TRACE_OFF , "io_dev_pager" , STATIC},
{ETAP_IO_DEV_PORT , ETAP_TRACE_OFF , "io_dev_port" , STATIC},
{ETAP_IO_DEV_REF , ETAP_TRACE_OFF , "io_dev_new" , 17},
{ETAP_IO_DEVINS , ETAP_TRACE_OFF , "io_devins" , STATIC},
{ETAP_IO_DONE_LIST , ETAP_TRACE_OFF , "io_done_list" , STATIC},
{ETAP_IO_DONE_Q , ETAP_TRACE_OFF , "io_doneq" , 18},
{ETAP_IO_DONE_REF , ETAP_TRACE_OFF , "io_done_ref" , 19},
{ETAP_IO_EAHA , ETAP_TRACE_OFF , "io_eaha" , STATIC},
{ETAP_IO_HD_PROBE , ETAP_TRACE_OFF , "io_hd_probe" , STATIC},
{ETAP_IO_IOPB , ETAP_TRACE_OFF , "io_iopb" , STATIC},
{ETAP_IO_KDQ , ETAP_TRACE_OFF , "io_kdq" , STATIC},
{ETAP_IO_KDTTY , ETAP_TRACE_OFF , "io_kdtty" , STATIC},
{ETAP_IO_REQ , ETAP_TRACE_OFF , "io_req" , 20},
{ETAP_IO_TARGET , ETAP_TRACE_OFF , "io_target" , STATIC},
{ETAP_IO_TTY , ETAP_TRACE_OFF , "io_tty" , STATIC},
{ETAP_IO_IOP_LOCK , ETAP_TRACE_OFF , "io_iop" , STATIC},
{ETAP_IO_DEV_NAME , ETAP_TRACE_OFF , "io_dev_name" , STATIC},
{ETAP_IO_CDLI , ETAP_TRACE_OFF , "io_cdli" , STATIC},
{ETAP_IO_HIPPI_FILTER , ETAP_TRACE_OFF , "io_hippi_filter" , STATIC},
{ETAP_IO_HIPPI_SRC , ETAP_TRACE_OFF , "io_hippi_src" , STATIC},
{ETAP_IO_HIPPI_DST , ETAP_TRACE_OFF , "io_hippi_dst" , STATIC},
{ETAP_IO_HIPPI_PKT , ETAP_TRACE_OFF , "io_hippi_pkt" , STATIC},
{ETAP_IO_NOTIFY , ETAP_TRACE_OFF , "io_notify" , STATIC},
{ETAP_IO_DATADEV , ETAP_TRACE_OFF , "io_data_device" , STATIC},
{ETAP_IO_OPEN , ETAP_TRACE_OFF , "io_open" , STATIC},
{ETAP_IO_OPEN_I , ETAP_TRACE_OFF , "io_open_i" , STATIC},
{ETAP_THREAD_ACT , ETAP_TRACE_OFF , "th_act" , 21},
{ETAP_THREAD_ACTION , ETAP_TRACE_OFF , "th_action" , STATIC},
{ETAP_THREAD_LOCK , ETAP_TRACE_OFF , "th_lock" , 22},
{ETAP_THREAD_LOCK_SET , ETAP_TRACE_OFF , "th_lock_set" , 23},
{ETAP_THREAD_NEW , ETAP_TRACE_OFF , "th_new" , 24},
{ETAP_THREAD_PSET , ETAP_TRACE_OFF , "th_pset" , STATIC},
{ETAP_THREAD_PSET_ALL , ETAP_TRACE_OFF , "th_pset_all" , STATIC},
{ETAP_THREAD_PSET_RUNQ , ETAP_TRACE_OFF , "th_pset_runq" , STATIC},
{ETAP_THREAD_PSET_IDLE , ETAP_TRACE_OFF , "th_pset_idle" , STATIC},
{ETAP_THREAD_PSET_QUANT , ETAP_TRACE_OFF , "th_pset_quant" , STATIC},
{ETAP_THREAD_PROC , ETAP_TRACE_OFF , "th_proc" , STATIC},
{ETAP_THREAD_PROC_RUNQ , ETAP_TRACE_OFF , "th_proc_runq" , STATIC},
{ETAP_THREAD_REAPER , ETAP_TRACE_OFF , "th_reaper" , STATIC},
{ETAP_THREAD_RPC , ETAP_TRACE_OFF , "th_rpc" , 25},
{ETAP_THREAD_SEMA , ETAP_TRACE_OFF , "th_sema" , 26},
{ETAP_THREAD_STACK , ETAP_TRACE_OFF , "th_stack" , STATIC},
{ETAP_THREAD_STACK_USAGE , ETAP_TRACE_OFF , "th_stack_usage" , STATIC},
{ETAP_THREAD_TASK_NEW , ETAP_TRACE_OFF , "th_task_new" , 27},
{ETAP_THREAD_TASK_ITK , ETAP_TRACE_OFF , "th_task_itk" , 28},
{ETAP_THREAD_ULOCK , ETAP_TRACE_OFF , "th_ulock" , 29},
{ETAP_THREAD_WAIT , ETAP_TRACE_OFF , "th_wait" , STATIC},
{ETAP_THREAD_WAKE , ETAP_TRACE_OFF , "th_wake" , 30},
{ETAP_THREAD_ACT_LIST , ETAP_TRACE_OFF , "th_act_list" , 31},
{ETAP_THREAD_TASK_SWAP , ETAP_TRACE_OFF , "th_task_swap" , 32},
{ETAP_THREAD_TASK_SWAPOUT, ETAP_TRACE_OFF , "th_task_swapout" , 33},
{ETAP_THREAD_SWAPPER , ETAP_TRACE_OFF , "th_swapper" , STATIC},
{ETAP_NET_IFQ , ETAP_TRACE_OFF , "net_ifq" , STATIC},
{ETAP_NET_KMSG , ETAP_TRACE_OFF , "net_kmsg" , STATIC},
{ETAP_NET_MBUF , ETAP_TRACE_OFF , "net_mbuf" , STATIC},
{ETAP_NET_POOL , ETAP_TRACE_OFF , "net_pool" , STATIC},
{ETAP_NET_Q , ETAP_TRACE_OFF , "net_q" , STATIC},
{ETAP_NET_QFREE , ETAP_TRACE_OFF , "net_qfree" , STATIC},
{ETAP_NET_RCV , ETAP_TRACE_OFF , "net_rcv" , STATIC},
{ETAP_NET_RCV_PLIST , ETAP_TRACE_OFF , "net_rcv_plist" , STATIC},
{ETAP_NET_THREAD , ETAP_TRACE_OFF , "net_thread" , STATIC},
{ETAP_NORMA_XMM , ETAP_TRACE_OFF , "norma_xmm" , STATIC},
{ETAP_NORMA_XMMOBJ , ETAP_TRACE_OFF , "norma_xmmobj" , STATIC},
{ETAP_NORMA_XMMCACHE , ETAP_TRACE_OFF , "norma_xmmcache" , STATIC},
{ETAP_NORMA_MP , ETAP_TRACE_OFF , "norma_mp" , STATIC},
{ETAP_NORMA_VOR , ETAP_TRACE_OFF , "norma_vor" , STATIC},
{ETAP_NORMA_TASK , ETAP_TRACE_OFF , "norma_task" , 38},
{ETAP_DIPC_CLEANUP , ETAP_TRACE_OFF , "dipc_cleanup" , STATIC},
{ETAP_DIPC_MSG_PROG , ETAP_TRACE_OFF , "dipc_msgp_prog" , STATIC},
{ETAP_DIPC_PREP_QUEUE , ETAP_TRACE_OFF , "dipc_prep_queue" , STATIC},
{ETAP_DIPC_PREP_FILL , ETAP_TRACE_OFF , "dipc_prep_fill" , STATIC},
{ETAP_DIPC_MIGRATE , ETAP_TRACE_OFF , "dipc_migrate" , STATIC},
{ETAP_DIPC_DELIVER , ETAP_TRACE_OFF , "dipc_deliver" , STATIC},
{ETAP_DIPC_RECV_SYNC , ETAP_TRACE_OFF , "dipc_recv_sync" , STATIC},
{ETAP_DIPC_RPC , ETAP_TRACE_OFF , "dipc_rpc" , STATIC},
{ETAP_DIPC_MSG_REQ , ETAP_TRACE_OFF , "dipc_msg_req" , STATIC},
{ETAP_DIPC_MSG_ORDER , ETAP_TRACE_OFF , "dipc_msg_order" , STATIC},
{ETAP_DIPC_MSG_PREPQ , ETAP_TRACE_OFF , "dipc_msg_prepq" , STATIC},
{ETAP_DIPC_MSG_FREE , ETAP_TRACE_OFF , "dipc_msg_free" , STATIC},
{ETAP_DIPC_KMSG_AST , ETAP_TRACE_OFF , "dipc_kmsg_ast" , STATIC},
{ETAP_DIPC_TEST_LOCK , ETAP_TRACE_OFF , "dipc_test_lock" , STATIC},
{ETAP_DIPC_SPINLOCK , ETAP_TRACE_OFF , "dipc_spinlock" , STATIC},
{ETAP_DIPC_TRACE , ETAP_TRACE_OFF , "dipc_trace" , STATIC},
{ETAP_DIPC_REQ_CALLBACK , ETAP_TRACE_OFF , "dipc_req_clbck" , STATIC},
{ETAP_DIPC_PORT_NAME , ETAP_TRACE_OFF , "dipc_port_name" , STATIC},
{ETAP_DIPC_RESTART_PORT , ETAP_TRACE_OFF , "dipc_restart_port", STATIC},
{ETAP_DIPC_ZERO_PAGE , ETAP_TRACE_OFF , "dipc_zero_page" , STATIC},
{ETAP_DIPC_BLOCKED_NODE , ETAP_TRACE_OFF , "dipc_blocked_node", STATIC},
{ETAP_DIPC_TIMER , ETAP_TRACE_OFF , "dipc_timer" , STATIC},
{ETAP_DIPC_SPECIAL_PORT , ETAP_TRACE_OFF , "dipc_special_port", STATIC},
{ETAP_KKT_TEST_WORK , ETAP_TRACE_OFF , "kkt_test_work" , STATIC},
{ETAP_KKT_TEST_MP , ETAP_TRACE_OFF , "kkt_work_mp" , STATIC},
{ETAP_KKT_NODE , ETAP_TRACE_OFF , "kkt_node" , STATIC},
{ETAP_KKT_CHANNEL_LIST , ETAP_TRACE_OFF , "kkt_channel_list" , STATIC},
{ETAP_KKT_CHANNEL , ETAP_TRACE_OFF , "kkt_channel" , STATIC},
{ETAP_KKT_HANDLE , ETAP_TRACE_OFF , "kkt_handle" , STATIC},
{ETAP_KKT_MAP , ETAP_TRACE_OFF , "kkt_map" , STATIC},
{ETAP_KKT_RESOURCE , ETAP_TRACE_OFF , "kkt_resource" , STATIC},
{ETAP_XKERNEL_MASTER , ETAP_TRACE_OFF , "xkernel_master" , STATIC},
{ETAP_XKERNEL_EVENT , ETAP_TRACE_OFF , "xkernel_event" , STATIC},
{ETAP_XKERNEL_ETHINPUT , ETAP_TRACE_OFF , "xkernel_input" , STATIC},
{ETAP_MISC_AST , ETAP_TRACE_OFF , "m_ast" , STATIC},
{ETAP_MISC_CLOCK , ETAP_TRACE_OFF , "m_clock" , STATIC},
{ETAP_MISC_EMULATE , ETAP_TRACE_OFF , "m_emulate" , 34},
{ETAP_MISC_EVENT , ETAP_TRACE_OFF , "m_event" , STATIC},
{ETAP_MISC_KDB , ETAP_TRACE_OFF , "m_kdb" , STATIC},
{ETAP_MISC_PCB , ETAP_TRACE_OFF , "m_pcb" , 35},
{ETAP_MISC_PRINTF , ETAP_TRACE_OFF , "m_printf" , STATIC},
{ETAP_MISC_Q , ETAP_TRACE_OFF , "m_q" , STATIC},
{ETAP_MISC_RPC_SUBSYS , ETAP_TRACE_OFF , "m_rpc_sub" , 36},
{ETAP_MISC_RT_CLOCK , ETAP_TRACE_OFF , "m_rt_clock" , STATIC},
{ETAP_MISC_SD_POOL , ETAP_TRACE_OFF , "m_sd_pool" , STATIC},
{ETAP_MISC_TIMER , ETAP_TRACE_OFF , "m_timer" , STATIC},
{ETAP_MISC_UTIME , ETAP_TRACE_OFF , "m_utime" , STATIC},
{ETAP_MISC_XPR , ETAP_TRACE_OFF , "m_xpr" , STATIC},
{ETAP_MISC_ZONE , ETAP_TRACE_OFF , "m_zone" , 37},
{ETAP_MISC_ZONE_ALL , ETAP_TRACE_OFF , "m_zone_all" , STATIC},
{ETAP_MISC_ZONE_GET , ETAP_TRACE_OFF , "m_zone_get" , STATIC},
{ETAP_MISC_ZONE_PTABLE , ETAP_TRACE_OFF , "m_zone_ptable" , STATIC},
{ETAP_MISC_LEDGER , ETAP_TRACE_OFF , "m_ledger" , STATIC},
{ETAP_MISC_SCSIT_TGT , ETAP_TRACE_OFF , "m_scsit_tgt_lock" , STATIC},
{ETAP_MISC_SCSIT_SELF , ETAP_TRACE_OFF , "m_scsit_self_lock", STATIC},
{ETAP_MISC_SPL , ETAP_TRACE_OFF , "m_spl_lock" , STATIC},
{ETAP_MISC_MASTER , ETAP_TRACE_OFF , "m_master" , STATIC},
{ETAP_MISC_FLOAT , ETAP_TRACE_OFF , "m_float" , STATIC},
{ETAP_MISC_GROUP , ETAP_TRACE_OFF , "m_group" , STATIC},
{ETAP_MISC_FLIPC , ETAP_TRACE_OFF , "m_flipc" , STATIC},
{ETAP_MISC_MP_IO , ETAP_TRACE_OFF , "m_mp_io" , STATIC},
{ETAP_MISC_KERNEL_TEST , ETAP_TRACE_OFF , "m_kernel_test" , STATIC},
{ETAP_NO_TRACE , ETAP_TRACE_OFF , "NEVER_TRACE" , STATIC},
#endif
};
event_table_t event_table = (event_table_t) event_table_init;
struct event_table_chain *event_table_chain;
int event_table_max = sizeof(event_table_init)/sizeof(struct event_table_entry);
const struct subs_table_entry subs_table_init[] =
{
#if ETAP_EVENT_MONITOR
{ETAP_SUBS_PROBE , "event_probes" },
#endif
#if ETAP_LOCK_TRACE
{ETAP_SUBS_LOCK_DIPC , "lock_dipc" },
{ETAP_SUBS_LOCK_IO , "lock_io" },
{ETAP_SUBS_LOCK_IPC , "lock_ipc" },
{ETAP_SUBS_LOCK_KKT , "lock_kkt" },
{ETAP_SUBS_LOCK_MISC , "lock_misc" },
{ETAP_SUBS_LOCK_NET , "lock_net" },
{ETAP_SUBS_LOCK_NORMA , "lock_norma" },
{ETAP_SUBS_LOCK_THREAD , "lock_thread" },
{ETAP_SUBS_LOCK_VM , "lock_vm" },
{ETAP_SUBS_LOCK_XKERNEL , "lock_xkernel" },
#endif
};
subs_table_t subs_table = (subs_table_t) subs_table_init;
int subs_table_max = sizeof(subs_table_init)/sizeof(struct subs_table_entry);
#if ETAP_MONITOR
#define MAX_NAME_SIZE 35
#define SYS_TABLE_MACH_TRAP 0
#define SYS_TABLE_MACH_MESSAGE 1
#define SYS_TABLE_UNIX_SYSCALL 2
#define SYS_TABLE_INTERRUPT 3
#define SYS_TABLE_EXCEPTION 4
extern char *system_table_lookup (unsigned int table,
unsigned int number);
char *mach_trap_names[] = {
"undefined",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"mach_reply_port",
"mach_thread_self",
"mach_task_self",
"mach_host_self",
"vm_read_overwrite",
"vm_write",
"mach_msg_overwrite_trap",
NULL,
NULL,
#ifdef i386
"mach_rpc_trap",
"mach_rpc_return_trap",
#else
NULL,
NULL,
#endif
NULL,
NULL,
NULL,
NULL,
"init_process",
NULL,
"map_fd",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"swtch_pri",
"swtch",
"thread_switch",
"clock_sleep_trap",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
#define N_MACH_TRAP_NAMES (sizeof mach_trap_names / sizeof mach_trap_names[0])
#define mach_trap_name(nu) \
(((nu) < N_MACH_TRAP_NAMES) ? mach_trap_names[nu] : NULL)
struct table_entry {
char name[MAX_NAME_SIZE];
u_int number;
};
struct table_entry mach_message_table[] = {
subsystem_to_name_map_bootstrap,
subsystem_to_name_map_clock,
subsystem_to_name_map_clock_reply,
subsystem_to_name_map_default_pager_object,
subsystem_to_name_map_device,
subsystem_to_name_map_device_reply,
subsystem_to_name_map_device_request,
subsystem_to_name_map_exc,
subsystem_to_name_map_mach_debug,
subsystem_to_name_map_mach_norma,
subsystem_to_name_map_mach_port,
subsystem_to_name_map_memory_object,
subsystem_to_name_map_memory_object_default,
subsystem_to_name_map_notify,
subsystem_to_name_map_prof,
subsystem_to_name_map_sync
};
int mach_message_table_entries = sizeof(mach_message_table) /
sizeof(struct table_entry);
#endif
void
etap_init_phase1(void)
{
#if ETAP_LOCK_ACCUMULATE || MACH_ASSERT
int x;
#if MACH_ASSERT
boolean_t out_of_order;
#endif
#endif
#if ETAP_LOCK_ACCUMULATE
bzero(&cbuff_allocated[0], CBUFF_ALLOCATED_SIZE);
cbuff = (cumulative_buffer_t) round_page(&cbuff_allocated);
simple_lock_init(&cbuff_lock, ETAP_NO_TRACE);
for (x=0; x < event_table_max; x++)
if (event_table[x].dynamic > cbuff->static_start)
cbuff->static_start = event_table[x].dynamic;
cbuff->next = cbuff->static_start;
#endif
simple_lock_init(&event_table_lock, ETAP_NO_TRACE);
#if MACH_ASSERT
out_of_order = FALSE;
for (x = 1; x < event_table_max; x++) {
if (event_table[x - 1].event > event_table[x].event) {
printf("events out of order: %s > %s\n",
event_table[x - 1].name, event_table[x].name);
out_of_order = TRUE;
}
}
if (out_of_order)
panic("etap_init_phase1");
#endif
}
void
etap_init_phase2(void)
{
int size;
int x;
int ret;
vm_offset_t table_copy;
struct event_table_chain *chainp;
size = sizeof event_table_init + sizeof subs_table_init;
ret = kmem_alloc(kernel_map, &table_copy, size);
if (ret != KERN_SUCCESS)
panic("ETAP: error allocating table copies");
event_table = (event_table_t) table_copy;
subs_table = (subs_table_t) (table_copy + sizeof event_table_init);
bcopy((char *) event_table_init, (char *) event_table,
sizeof event_table_init);
bcopy((char *) subs_table_init, (char *) subs_table,
sizeof subs_table_init);
for (chainp = event_table_chain; chainp != NULL;
chainp = chainp->event_table_link) {
x = chainp->event_tablep - event_table_init;
assert(x < event_table_max);
chainp->event_tablep = event_table + x;
}
#if ETAP_LOCK_ACCUMULATE
#if MACH_LDEBUG
size = sizeof(simple_lock_t) * cbuff->static_start;
#else
size = sizeof(simple_lock_data_t) * cbuff->static_start;
#endif
ret = kmem_alloc(kernel_map, (vm_offset_t *) &cbuff_locks, size);
if (ret != KERN_SUCCESS)
panic("ETAP: error allocating cumulative write locks");
#if MACH_LDEBUG
for(x = 0; x < cbuff->static_start; ++x) {
simple_lock_init(&cbuff_locks[x], ETAP_NO_TRACE);
}
#else
bzero((const char *) cbuff_locks, size);
#endif
#endif
#if ETAP_MONITOR
size = ((mbuff_entries-1) * sizeof(struct mbuff_entry)) +
sizeof(struct monitor_buffer);
for (x=0; x < NCPUS; x++) {
ret = kmem_alloc(kernel_map,
(vm_offset_t *) &mbuff[x],
size);
if (ret != KERN_SUCCESS)
panic ("ETAP: error allocating monitor buffer\n");
bzero((char *) mbuff[x], size);
}
#endif
#if ETAP_LOCK_TRACE
init_start_data_pool();
#endif
}
#if ETAP_LOCK_ACCUMULATE
cbuff_entry_t
etap_cbuff_reserve(event_table_t etp)
{
cbuff_entry_t avail;
unsigned short de;
spl_t s;
if (etp == EVENT_TABLE_NULL || etp->event == ETAP_NO_TRACE)
return (CBUFF_ENTRY_NULL);
if (de = etp->dynamic) {
if (de <= cbuff->static_start)
return (&cbuff->entry[de-1]);
else {
printf("ETAP: dynamic lock index error [%lu]\n", de);
return (CBUFF_ENTRY_NULL);
}
}
cumulative_buffer_lock(s);
if (cbuff->next >= ETAP_CBUFF_ENTRIES) {
cumulative_buffer_unlock(s);
return (CBUFF_ENTRY_NULL);
}
avail = &cbuff->entry[cbuff->next++];
cumulative_buffer_unlock(s);
return (avail);
}
#endif
event_table_t
etap_event_table_find(etap_event_t event)
{
int last_before, first_after, try;
last_before = 0;
first_after = event_table_max;
while (last_before < first_after) {
try = (last_before + first_after) >> 1;
if (event_table[try].event == event)
return (&event_table[try]);
else if (event_table[try].event < event)
last_before = try;
else
first_after = try;
}
return EVENT_TABLE_NULL;
}
void
etap_event_table_assign(struct event_table_chain *chainp, etap_event_t event)
{
event_table_t event_tablep;
event_tablep = etap_event_table_find(event);
if (event_tablep == EVENT_TABLE_NULL)
printf("\nETAP: event not found in event table: %x\n", event);
else {
if (event_table == event_table_init) {
chainp->event_table_link = event_table_chain;
event_table_chain = chainp;
}
chainp->event_tablep = event_tablep;
}
}
#endif
kern_return_t
etap_get_info(
host_priv_t host_priv,
int *et_entries,
int *st_entries,
vm_offset_t *et_offset,
vm_offset_t *st_offset,
int *cb_width,
int *mb_size,
int *mb_entries,
int *mb_cpus)
{
if (host_priv == HOST_PRIV_NULL)
return KERN_INVALID_ARGUMENT;
#if ETAP
*et_entries = event_table_max;
*st_entries = subs_table_max;
*et_offset = (vm_offset_t) ((char*) event_table -
trunc_page((char*) event_table));
*st_offset = (vm_offset_t) ((char*) subs_table -
trunc_page((char*) subs_table));
#else
*et_entries = 0;
*st_entries = 0;
*et_offset = 0;
*st_offset = 0;
#endif
#if ETAP_LOCK_ACCUMULATE
*cb_width = cbuff_width;
#else
*cb_width = 0;
#endif
#if ETAP_MONITOR
*mb_size = ((mbuff_entries-1) * sizeof(struct mbuff_entry)) +
sizeof(struct monitor_buffer);
*mb_entries = mbuff_entries;
*mb_cpus = NCPUS;
#else
*mb_size = 0;
*mb_entries = 0;
*mb_cpus = 0;
#endif
return (KERN_SUCCESS);
}
kern_return_t
etap_trace_event (
unsigned short mode,
unsigned short type,
boolean_t enable,
unsigned int nargs,
unsigned short args[])
{
#if ETAP
event_table_t event_tablep;
kern_return_t ret;
int i, args_size;
unsigned short status_mask;
unsigned short *tmp_args;
if (mode == ETAP_RESET) {
etap_trace_reset(nargs);
return (KERN_SUCCESS);
}
status_mask = mode & type;
args_size = nargs * sizeof *args;
tmp_args = (unsigned short *) kalloc(args_size);
if (tmp_args == NULL)
return (KERN_NO_SPACE);
if (copyin((const char *) args, (char *) tmp_args, args_size))
return (KERN_INVALID_ADDRESS);
event_table_lock();
for (i = 0; i < nargs; i++) {
if (tmp_args[i] != ETAP_NO_TRACE) {
event_tablep = etap_event_table_find(tmp_args[i]);
if (event_tablep == EVENT_TABLE_NULL)
break;
if (enable)
event_tablep->status |= status_mask;
else
event_tablep->status &= ~status_mask;
}
}
ret = (i < nargs) ? KERN_INVALID_ARGUMENT : KERN_SUCCESS;
event_table_unlock();
kfree((vm_offset_t) tmp_args, args_size);
return (ret);
#else
return (KERN_FAILURE);
#endif
}
#if ETAP
void
etap_trace_reset(int new_interval)
{
event_table_t scan;
int x;
register s;
scan = event_table;
event_table_lock();
for (x=0; x < event_table_max; x++) {
scan->status = ETAP_TRACE_OFF;
scan++;
}
event_table_unlock();
#if ETAP_LOCK_ACCUMULATE
cumulative_buffer_lock(s);
for (x=0; x < ETAP_CBUFF_ENTRIES; x++) {
bzero ((char *) &cbuff->entry[x].hold,
sizeof(struct cbuff_data));
bzero ((char *) &cbuff->entry[x].wait,
sizeof(struct cbuff_data));
bzero ((char *) &cbuff->entry[x].hold_interval[0],
sizeof(unsigned long) * ETAP_CBUFF_IBUCKETS);
bzero ((char *) &cbuff->entry[x].wait_interval[0],
sizeof(unsigned long) * ETAP_CBUFF_IBUCKETS);
}
if (new_interval != 0)
cbuff_width = new_interval;
cumulative_buffer_unlock(s);
#endif
}
#endif
kern_return_t
etap_probe(
unsigned short event_type,
unsigned short event_id,
unsigned int data_size,
etap_data_t *data)
{
#if ETAP_MONITOR
mbuff_entry_t mbuff_entryp;
int cpu;
int free;
spl_t s;
if (data_size > ETAP_DATA_SIZE)
return (KERN_INVALID_ARGUMENT);
if (event_table[event_type].status == ETAP_TRACE_OFF ||
event_table[event_type].event != event_type)
return (KERN_NO_ACCESS);
mp_disable_preemption();
cpu = cpu_number();
s = splhigh();
free = mbuff[cpu]->free;
mbuff_entryp = &mbuff[cpu]->entry[free];
ETAP_TIMESTAMP(mbuff_entryp->time);
mbuff_entryp->event = event_id;
mbuff_entryp->flags = USER_EVENT;
mbuff_entryp->instance = (u_int) current_thread();
mbuff_entryp->pc = 0;
if (data != ETAP_DATA_NULL)
copyin((const char *) data,
(char *) mbuff_entryp->data,
data_size);
mbuff[cpu]->free = (free+1) % mbuff_entries;
if (mbuff[cpu]->free == 0)
mbuff[cpu]->timestamp++;
splx(s);
mp_enable_preemption();
return (KERN_SUCCESS);
#else
return (KERN_FAILURE);
#endif
}
kern_return_t
etap_trace_thread(
thread_act_t thr_act,
boolean_t trace_status)
{
#if ETAP_EVENT_MONITOR
thread_t thread;
boolean_t old_status;
etap_data_t probe_data;
spl_t s;
if (thr_act == THR_ACT_NULL)
return (KERN_INVALID_ARGUMENT);
thread = act_lock_thread(thr_act);
if (thread == THREAD_NULL) {
act_unlock_thread(thr_act);
return (KERN_INVALID_ARGUMENT);
}
s = splsched();
thread_lock(thread);
old_status = thread->etap_trace;
thread->etap_trace = trace_status;
ETAP_DATA_LOAD(probe_data[0],thr_act->task);
ETAP_DATA_LOAD(probe_data[1],thr_act);
ETAP_DATA_LOAD(probe_data[2],thread->sched_pri);
thread_unlock(thread);
splx(s);
act_unlock_thread(thr_act);
if (trace_status == TRUE && old_status == FALSE) {
ETAP_PROBE_DATA(ETAP_P_THREAD_LIFE,
EVENT_BEGIN,
thread,
&probe_data,
ETAP_DATA_ENTRY*3);
}
if (trace_status == FALSE && old_status == TRUE) {
ETAP_PROBE_DATA(ETAP_P_THREAD_LIFE,
EVENT_END,
thread,
&probe_data,
ETAP_DATA_ENTRY*3);
}
return (KERN_SUCCESS);
#else
return (KERN_FAILURE);
#endif
}
kern_return_t
etap_mon_reconfig(
host_priv_t host_priv,
int nentries)
{
#if ETAP_EVENT_MONITOR
struct monitor_buffer *nmbuff[NCPUS], *ombuff[NCPUS];
int s, size, osize, i, ret;
if (host_priv == HOST_PRIV_NULL)
return KERN_INVALID_ARGUMENT;
if (nentries <= 0)
return (KERN_FAILURE);
size = ((nentries-1) * sizeof(struct mbuff_entry)) +
sizeof(struct monitor_buffer);
for (i = 0; i < NCPUS; ++i) {
ret = kmem_alloc(kernel_map,
(vm_offset_t *)&nmbuff[i],
size);
if (ret != KERN_SUCCESS) {
if (i > 0) {
int j;
for (j = 0; j < i; ++j) {
kmem_free(kernel_map,
(vm_offset_t)nmbuff[j],
size);
}
}
return (ret);
}
bzero((char *) nmbuff[i], size);
}
osize = ((mbuff_entries-1) * sizeof (struct mbuff_entry)) +
sizeof (struct monitor_buffer);
s = splhigh();
event_table_lock();
for (i = 0; i < NCPUS; ++i) {
ombuff[i] = mbuff[i];
mbuff[i] = nmbuff[i];
}
mbuff_entries = nentries;
event_table_unlock();
splx(s);
for (i = 0; i < NCPUS; ++i) {
kmem_free(kernel_map,
(vm_offset_t)ombuff[i],
osize);
}
return (KERN_SUCCESS);
#else
return (KERN_FAILURE);
#endif
}
kern_return_t
etap_new_probe(
host_priv_t host_priv,
vm_address_t name,
vm_size_t namlen,
boolean_t trace_on,
vm_address_t id)
{
#if ETAP_EVENT_MONITOR
event_table_t newtable, oldtable;
unsigned short i, nid;
int s;
vm_size_t newsize = (event_table_max + 1) *
sizeof (struct event_table_entry);
boolean_t duplicate_name = FALSE;
kern_return_t ret;
if (host_priv == HOST_PRIV_NULL)
return KERN_INVALID_ARGUMENT;
if (namlen > EVENT_NAME_LENGTH - 1)
return (KERN_INVALID_ARGUMENT);
if ((ret = kmem_alloc(kernel_map, (vm_address_t *)&newtable,
newsize)) != KERN_SUCCESS)
return (ret);
bcopy((const char *)event_table, (char *)newtable, event_table_max *
sizeof (struct event_table_entry));
if (copyin((const char *)name,
(char *)&newtable[event_table_max].name, namlen))
return (KERN_INVALID_ADDRESS);
newtable[event_table_max].name[EVENT_NAME_LENGTH - 1] = '\0';
newtable[event_table_max].status = trace_on;
newtable[event_table_max].dynamic = 0;
for (nid = i = 0; i < event_table_max; ++i) {
if (strcmp((char *)newtable[event_table_max].name,
newtable[i].name) == 0) {
duplicate_name = TRUE;
printf("duplicate name\n");
}
nid = max(nid, newtable[i].event);
}
++nid;
if (nid >= ETAP_NO_TRACE || duplicate_name == TRUE) {
kmem_free(kernel_map, (vm_address_t)newtable, newsize);
if (nid >= ETAP_NO_TRACE) {
printf("KERN_RESOURCE_SHORTAGE\n");
return (KERN_RESOURCE_SHORTAGE);
}
else {
printf("KERN_NAME_EXISTS\n");
return (KERN_NAME_EXISTS);
}
}
newtable[event_table_max].event = nid;
s = splhigh();
event_table_lock();
oldtable = event_table;
event_table = newtable;
++event_table_max;
event_table_unlock();
splx(s);
if (oldtable != event_table_init)
kmem_free(kernel_map, (vm_address_t)oldtable,
(event_table_max - 1) *
sizeof (struct event_table_entry));
*(unsigned short *)id = nid;
return (KERN_SUCCESS);
#else
return (KERN_FAILURE);
#endif
}
void
etap_interrupt_probe(int interrupt, int flag_setting)
{
u_short flag;
if (flag_setting == 1)
flag = EVENT_BEGIN;
else
flag = EVENT_END;
ETAP_PROBE_DATA_COND(ETAP_P_INTERRUPT,
flag,
current_thread(),
&interrupt,
sizeof(int),
1);
}
void
etap_machcall_probe1(int syscall)
{
ETAP_PROBE_DATA(ETAP_P_SYSCALL_MACH,
EVENT_BEGIN | SYSCALL_TRAP,
current_thread(),
&syscall,
sizeof(int));
}
void
etap_machcall_probe2(void)
{
ETAP_PROBE_DATA(ETAP_P_SYSCALL_MACH,
EVENT_END | SYSCALL_TRAP,
current_thread(),
0,
0);
}
static void print_user_event(mbuff_entry_t);
static void print_kernel_event(mbuff_entry_t, boolean_t);
static void print_lock_event(mbuff_entry_t, const char *);
#if MACH_KDB
void db_show_etap_log(db_expr_t, boolean_t, db_expr_t, char *);
void
db_show_etap_log(
db_expr_t addr,
boolean_t have_addr,
db_expr_t count,
char * modif)
{
#if ETAP_MONITOR
int cpu = cpu_number(), last, i, first, step, end, restart;
boolean_t show_data = FALSE;
last = (mbuff[cpu]->free - 1) % mbuff_entries;
if(db_option(modif, 'r')) {
first = last;
step = -1;
end = -1;
restart = mbuff_entries - 1;
} else {
first = last + 1;
step = 1;
end = mbuff_entries;
restart = 0;
}
if(db_option(modif, 'd'))
show_data = TRUE;
for(i = first; i != end; i += step) {
if (mbuff[cpu]->entry[i].flags & USER_EVENT)
print_user_event(&mbuff[cpu]->entry[i]);
else
print_kernel_event(&mbuff[cpu]->entry[i], show_data);
}
for(i = restart; i != first; i += step) {
if (mbuff[cpu]->entry[i].flags & USER_EVENT)
print_user_event(&mbuff[cpu]->entry[i]);
else
print_kernel_event(&mbuff[cpu]->entry[i], show_data);
}
#else
printf("ETAP event monitor not configured\n");
#endif
}
#if ETAP_MONITOR
static
void
print_user_event(mbuff_entry_t record)
{
char *s, buf[256];
db_printf("%x: %x%08x: ", record->instance, record->time.tv_sec,
record->time.tv_nsec);
switch (record->pc)
{
case ETAP_P_USER_EVENT0: s = "0"; break;
case ETAP_P_USER_EVENT1: s = "1"; break;
case ETAP_P_USER_EVENT2: s = "2"; break;
case ETAP_P_USER_EVENT3: s = "3"; break;
case ETAP_P_USER_EVENT4: s = "4"; break;
case ETAP_P_USER_EVENT5: s = "5"; break;
case ETAP_P_USER_EVENT6: s = "6"; break;
case ETAP_P_USER_EVENT7: s = "7"; break;
case ETAP_P_USER_EVENT8: s = "8"; break;
case ETAP_P_USER_EVENT9: s = "9"; break;
case ETAP_P_USER_EVENT10: s = "10"; break;
case ETAP_P_USER_EVENT11: s = "11"; break;
case ETAP_P_USER_EVENT12: s = "12"; break;
case ETAP_P_USER_EVENT13: s = "13"; break;
case ETAP_P_USER_EVENT14: s = "14"; break;
case ETAP_P_USER_EVENT15: s = "15"; break;
case ETAP_P_USER_EVENT16: s = "16"; break;
case ETAP_P_USER_EVENT17: s = "17"; break;
case ETAP_P_USER_EVENT18: s = "18"; break;
case ETAP_P_USER_EVENT19: s = "19"; break;
case ETAP_P_USER_EVENT20: s = "20"; break;
case ETAP_P_USER_EVENT21: s = "21"; break;
case ETAP_P_USER_EVENT22: s = "22"; break;
case ETAP_P_USER_EVENT23: s = "23"; break;
case ETAP_P_USER_EVENT24: s = "24"; break;
case ETAP_P_USER_EVENT25: s = "25"; break;
case ETAP_P_USER_EVENT26: s = "26"; break;
case ETAP_P_USER_EVENT27: s = "27"; break;
case ETAP_P_USER_EVENT28: s = "28"; break;
case ETAP_P_USER_EVENT29: s = "29"; break;
case ETAP_P_USER_EVENT30: s = "30"; break;
case ETAP_P_USER_EVENT31: s = "31"; break;
default:
sprintf(buf, "dynamic %x", record->pc);
s = buf;
break;
}
db_printf("user probe %s: [%x] data = %x %x %x %x\n",
s,
record->event,
record->data[0],
record->data[1],
record->data[2],
record->data[3]);
}
static
void
print_kernel_event(mbuff_entry_t record, boolean_t data)
{
char *text_name;
int i;
if(record->event == 0)
return;
db_printf("%x: %x%08x: ", record->instance, record->time.tv_sec,
record->time.tv_nsec);
switch (record->event) {
case ETAP_P_THREAD_LIFE :
if (record->flags & EVENT_BEGIN)
db_printf("thread created [T:%x A:%x] P:%d\n",
record->data[0],
record->data[1],
record->data[2]);
else
db_printf("thread terminated [T:%x A:%x] P:%d\n",
record->data[0],
record->data[1],
record->data[2]);
break;
case ETAP_P_SYSCALL_MACH :
if (record->flags & SYSCALL_TRAP)
text_name = system_table_lookup(SYS_TABLE_MACH_TRAP,
record->data[0]);
else
text_name = system_table_lookup(SYS_TABLE_MACH_MESSAGE,
record->data[0]);
if (record->flags & EVENT_BEGIN)
db_printf("mach enter: %s [%x]\n",
text_name,
record->data[0]);
else
db_printf("mach exit :\n");
break;
case ETAP_P_SYSCALL_UNIX :
text_name = system_table_lookup(SYS_TABLE_UNIX_SYSCALL,
record->data[0]);
if (record->flags & EVENT_BEGIN)
db_printf("unix enter: %s\n", text_name);
else
db_printf("unix exit : %s\n", text_name);
break;
case ETAP_P_THREAD_CTX :
if (record->flags & EVENT_END)
db_printf("context switch to %x ",
record->data[0]);
else
db_printf("context switch from %x ",
record->data[0]);
switch (record->data[1]) {
case BLOCKED_ON_SEMAPHORE :
db_printf("R: semaphore\n"); break;
case BLOCKED_ON_LOCK :
db_printf("R: lock\n"); break;
case BLOCKED_ON_MUTEX_LOCK :
db_printf("R: mutex lock\n"); break;
case BLOCKED_ON_COMPLEX_LOCK :
db_printf("R: complex lock\n"); break;
case BLOCKED_ON_PORT_RCV :
db_printf("R: port receive\n"); break;
case BLOCKED_ON_REAPER_DONE :
db_printf("R: reaper thread done\n"); break;
case BLOCKED_ON_IDLE_DONE :
db_printf("R: idle thread done\n"); break;
case BLOCKED_ON_TERMINATION :
db_printf("R: termination\n"); break;
default :
if (record->data[2])
db_printf("R: ast %x\n", record->data[2]);
else
db_printf("R: undefined block\n");
};
break;
case ETAP_P_INTERRUPT :
if (record->flags & EVENT_BEGIN) {
text_name = system_table_lookup(SYS_TABLE_INTERRUPT,
record->data[0]);
db_printf("intr enter: %s\n", text_name);
} else
db_printf("intr exit\n");
break;
case ETAP_P_ACT_ABORT :
db_printf("activation abort [A %x : S %x]\n",
record->data[1],
record->data[0]);
break;
case ETAP_P_PRIORITY :
db_printf("priority changed for %x N:%d O:%d\n",
record->data[0],
record->data[1],
record->data[2]);
break;
case ETAP_P_EXCEPTION :
text_name = system_table_lookup(SYS_TABLE_EXCEPTION,
record->data[0]);
db_printf("exception: %s\n", text_name);
break;
case ETAP_P_DEPRESSION :
if (record->flags & EVENT_BEGIN)
db_printf("priority depressed\n");
else {
if (record->data[0] == 0)
db_printf("priority undepressed : timed out\n");
else
db_printf("priority undepressed : self inflicted\n");
}
break;
case ETAP_P_MISC :
db_printf("flags: %x data: %x %x %x %x\n", record->flags,
record->data[0], record->data[1], record->data[2],
record->data[3]);
break;
case ETAP_P_DETAP :
printf("flags: %x rtc: %x %09x dtime: %x %09x\n",
record->flags, record->data[0], record->data[1],
record->data[2], record->data[3]);
break;
default:
for(i = 0; event_table_init[i].event != ETAP_NO_TRACE; ++i)
if(record->event == event_table_init[i].event) {
print_lock_event(record, event_table_init[i].name);
return;
}
db_printf("Unknown event: %d\n", record->event);
break;
}
if(data)
db_printf(" Data: %08x %08x %08x %08x\n", record->data[0],
record->data[1], record->data[2], record->data[3]);
}
void print_lock_event(mbuff_entry_t record, const char *name)
{
char *sym1, *sym2;
db_addr_t offset1, offset2;
db_find_sym_and_offset(record->data[0], &sym1, &offset1);
db_printf("%15s", name);
if (record->flags & SPIN_LOCK)
printf(" spin ");
else if (record->flags & READ_LOCK)
printf(" read ");
else if (record->flags & WRITE_LOCK)
printf(" write ");
else
printf(" undef ");
if (record->flags & ETAP_CONTENTION) {
db_printf("wait lock %s+%x\n",
sym1, offset1);
}
else if (record->flags & ETAP_DURATION) {
db_find_sym_and_offset(record->data[1], &sym2, &offset2);
db_printf("lock %x+%x unlock %x+%x\n",
sym1, offset1, sym2, offset2);
} else {
db_printf("illegal op: neither HOLD or WAIT are specified\n");
}
}
char *
system_table_lookup(unsigned int table, unsigned int number)
{
int x;
char *name = NULL;
unsigned int offset;
switch (table) {
case SYS_TABLE_MACH_TRAP:
name = mach_trap_name(number >> 4);
break;
case SYS_TABLE_MACH_MESSAGE:
for (x=0; x < mach_message_table_entries; x++) {
if (mach_message_table[x].number == number) {
name = mach_message_table[x].name;
break;
}
}
break;
case SYS_TABLE_UNIX_SYSCALL:
number = -number;
name = syscall_name(number);
break;
case SYS_TABLE_INTERRUPT:
db_find_sym_and_offset((int)ivect[number], &name, &offset);
break;
case SYS_TABLE_EXCEPTION:
name = exception_name(number);
break;
}
return (name != NULL) ? name : "undefined";
}
#endif
#endif