📄 systrace.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)systrace.c 1.3 04/09/28 SMI"#include <sys/dtrace.h>#include <sys/systrace.h>#include <sys/stat.h>#include <sys/systm.h>#include <sys/conf.h>#include <sys/ddi.h>#include <sys/sunddi.h>#include <sys/atomic.h>#define SYSTRACE_ARTIFICIAL_FRAMES 1#define SYSTRACE_SHIFT 16#define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT)#define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1))#define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id))#define SYSTRACE_RETURN(id) (id)#if ((1 << SYSTRACE_SHIFT) <= NSYSCALL)#error 1 << SYSTRACE_SHIFT must exceed number of system calls#endifstatic dev_info_t *systrace_devi;static dtrace_provider_id_t systrace_id;static voidsystrace_init(struct sysent *actual, systrace_sysent_t **interposed){ systrace_sysent_t *sysent = *interposed; int i; if (sysent == NULL) { *interposed = sysent = kmem_zalloc(sizeof (systrace_sysent_t) * NSYSCALL, KM_SLEEP); } for (i = 0; i < NSYSCALL; i++) { struct sysent *a = &actual[i]; systrace_sysent_t *s = &sysent[i]; if (LOADABLE_SYSCALL(a) && !LOADED_SYSCALL(a)) continue; if (a->sy_callc == dtrace_systrace_syscall) continue;#ifdef _SYSCALL32_IMPL if (a->sy_callc == dtrace_systrace_syscall32) continue;#endif s->stsy_underlying = a->sy_callc; }}/*ARGSUSED*/static voidsystrace_provide(void *arg, const dtrace_probedesc_t *desc){ int i; if (desc != NULL) return; systrace_init(sysent, &systrace_sysent);#ifdef _SYSCALL32_IMPL systrace_init(sysent32, &systrace_sysent32);#endif for (i = 0; i < NSYSCALL; i++) { if (systrace_sysent[i].stsy_underlying == NULL) continue; if (dtrace_probe_lookup(systrace_id, NULL, syscallnames[i], "entry") != 0) continue; (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i], "entry", SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_ENTRY(i))); (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i], "return", SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_RETURN(i))); systrace_sysent[i].stsy_entry = DTRACE_IDNONE; systrace_sysent[i].stsy_return = DTRACE_IDNONE;#ifdef _SYSCALL32_IMPL systrace_sysent32[i].stsy_entry = DTRACE_IDNONE; systrace_sysent32[i].stsy_return = DTRACE_IDNONE;#endif }}/*ARGSUSED*/static voidsystrace_destroy(void *arg, dtrace_id_t id, void *parg){ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); /* * There's nothing to do here but assert that we have actually been * disabled. */ if (SYSTRACE_ISENTRY((uintptr_t)parg)) { ASSERT(systrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE);#ifdef _SYSCALL32_IMPL ASSERT(systrace_sysent32[sysnum].stsy_entry == DTRACE_IDNONE);#endif } else { ASSERT(systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE);#ifdef _SYSCALL32_IMPL ASSERT(systrace_sysent32[sysnum].stsy_return == DTRACE_IDNONE);#endif }}/*ARGSUSED*/static voidsystrace_enable(void *arg, dtrace_id_t id, void *parg){ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); int enabled = (systrace_sysent[sysnum].stsy_entry != DTRACE_IDNONE || systrace_sysent[sysnum].stsy_return != DTRACE_IDNONE); if (SYSTRACE_ISENTRY((uintptr_t)parg)) { systrace_sysent[sysnum].stsy_entry = id;#ifdef _SYSCALL32_IMPL systrace_sysent32[sysnum].stsy_entry = id;#endif } else { systrace_sysent[sysnum].stsy_return = id;#ifdef _SYSCALL32_IMPL systrace_sysent32[sysnum].stsy_return = id;#endif } if (enabled) { ASSERT(sysent[sysnum].sy_callc == dtrace_systrace_syscall); return; } (void) casptr(&sysent[sysnum].sy_callc, (void *)systrace_sysent[sysnum].stsy_underlying, (void *)dtrace_systrace_syscall);#ifdef _SYSCALL32_IMPL (void) casptr(&sysent32[sysnum].sy_callc, (void *)systrace_sysent32[sysnum].stsy_underlying, (void *)dtrace_systrace_syscall32);#endif}/*ARGSUSED*/static voidsystrace_disable(void *arg, dtrace_id_t id, void *parg){ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); int disable = (systrace_sysent[sysnum].stsy_entry == DTRACE_IDNONE || systrace_sysent[sysnum].stsy_return == DTRACE_IDNONE); if (disable) { (void) casptr(&sysent[sysnum].sy_callc, (void *)dtrace_systrace_syscall, (void *)systrace_sysent[sysnum].stsy_underlying);#ifdef _SYSCALL32_IMPL (void) casptr(&sysent32[sysnum].sy_callc, (void *)dtrace_systrace_syscall32, (void *)systrace_sysent32[sysnum].stsy_underlying);#endif } if (SYSTRACE_ISENTRY((uintptr_t)parg)) { systrace_sysent[sysnum].stsy_entry = DTRACE_IDNONE;#ifdef _SYSCALL32_IMPL systrace_sysent32[sysnum].stsy_entry = DTRACE_IDNONE;#endif } else { systrace_sysent[sysnum].stsy_return = DTRACE_IDNONE;#ifdef _SYSCALL32_IMPL systrace_sysent32[sysnum].stsy_return = DTRACE_IDNONE;#endif }}static dtrace_pattr_t systrace_attr = {{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },};static dtrace_pops_t systrace_pops = { systrace_provide, NULL, systrace_enable, systrace_disable, NULL, NULL, NULL, NULL, NULL, systrace_destroy};static intsystrace_attach(dev_info_t *devi, ddi_attach_cmd_t cmd){ switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: return (DDI_SUCCESS); default: return (DDI_FAILURE); } systrace_probe = dtrace_probe; membar_enter(); if (ddi_create_minor_node(devi, "systrace", S_IFCHR, 0, DDI_PSEUDO, NULL) == DDI_FAILURE || dtrace_register("syscall", &systrace_attr, DTRACE_PRIV_USER, 0, &systrace_pops, NULL, &systrace_id) != 0) { systrace_probe = systrace_stub; ddi_remove_minor_node(devi, NULL); return (DDI_FAILURE); } ddi_report_dev(devi); systrace_devi = devi; return (DDI_SUCCESS);}static intsystrace_detach(dev_info_t *devi, ddi_detach_cmd_t cmd){ switch (cmd) { case DDI_DETACH: break; case DDI_SUSPEND: return (DDI_SUCCESS); default: return (DDI_FAILURE); } if (dtrace_unregister(systrace_id) != 0) return (DDI_FAILURE); ddi_remove_minor_node(devi, NULL); systrace_probe = systrace_stub; return (DDI_SUCCESS);}/*ARGSUSED*/static intsystrace_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result){ int error; switch (infocmd) { case DDI_INFO_DEVT2DEVINFO: *result = (void *)systrace_devi; error = DDI_SUCCESS; break; case DDI_INFO_DEVT2INSTANCE: *result = (void *)0; error = DDI_SUCCESS; break; default: error = DDI_FAILURE; } return (error);}/*ARGSUSED*/static intsystrace_open(dev_t *devp, int flag, int otyp, cred_t *cred_p){ return (0);}static struct cb_ops systrace_cb_ops = { systrace_open, /* open */ nodev, /* close */ nulldev, /* strategy */ nulldev, /* print */ nodev, /* dump */ nodev, /* read */ nodev, /* write */ nodev, /* ioctl */ nodev, /* devmap */ nodev, /* mmap */ nodev, /* segmap */ nochpoll, /* poll */ ddi_prop_op, /* cb_prop_op */ 0, /* streamtab */ D_NEW | D_MP /* Driver compatibility flag */};static struct dev_ops systrace_ops = { DEVO_REV, /* devo_rev, */ 0, /* refcnt */ systrace_info, /* get_dev_info */ nulldev, /* identify */ nulldev, /* probe */ systrace_attach, /* attach */ systrace_detach, /* detach */ nodev, /* reset */ &systrace_cb_ops, /* driver operations */ NULL, /* bus operations */ nodev /* dev power */};/* * Module linkage information for the kernel. */static struct modldrv modldrv = { &mod_driverops, /* module type (this is a pseudo driver) */ "System Call Tracing", /* name of module */ &systrace_ops, /* driver ops */};static struct modlinkage modlinkage = { MODREV_1, (void *)&modldrv, NULL};int_init(void){ return (mod_install(&modlinkage));}int_info(struct modinfo *modinfop){ return (mod_info(&modlinkage, modinfop));}int_fini(void){ return (mod_remove(&modlinkage));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -