plan9fox/sys/src/9/port/dtracysys.c
cinap_lenrek 4f0bfe0fb8 dtracy: avoid dmachlock() race
between being commited to a machno and having acquired the lock, the
scheduler could come in an schedule us on a different processor. the
solution is to have dtmachlock() take a special -1 argument to mean
"current mach" and return the actual mach number after the lock has
been acquired and interrupts being disabled.
2019-03-30 09:17:46 +01:00

268 lines
8.2 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "/sys/src/libc/9syscall/sys.h"
#include <dtracy.h>
#include <ctype.h>
static DTProbe **dtpsysentry, **dtpsysreturn;
typedef uintptr Syscall(va_list);
extern Syscall *systab[];
#define WRAP0(x,y,z)\
Syscall z; uintptr x(va_list va){\
uintptr rc;\
DTTrigInfo info;\
memset(&info, 0, sizeof(info));\
dtptrigger(dtpsysentry[y], &info);\
rc = z(va);\
info.arg[9] = (uvlong) rc;\
dtptrigger(dtpsysreturn[y], &info);\
return rc;\
}
#define WRAP1(x,y,z,type0)\
Syscall z; uintptr x(va_list va){\
uintptr rc;\
va_list vb = va;\
DTTrigInfo info;\
memset(&info, 0, sizeof(info));\
info.arg[0] = (uvlong) va_arg(vb, type0);\
dtptrigger(dtpsysentry[y], &info);\
rc = z(va);\
info.arg[9] = (uvlong) rc;\
dtptrigger(dtpsysreturn[y], &info);\
return rc;\
}
#define WRAP2(x,y,z,type0,type1)\
Syscall z; uintptr x(va_list va){\
uintptr rc;\
va_list vb = va;\
DTTrigInfo info;\
memset(&info, 0, sizeof(info));\
info.arg[0] = (uvlong) va_arg(vb, type0);\
info.arg[1] = (uvlong) va_arg(vb, type1);\
dtptrigger(dtpsysentry[y], &info);\
rc = z(va);\
info.arg[9] = (uvlong) rc;\
dtptrigger(dtpsysreturn[y], &info);\
return rc;\
}
#define WRAP3(x,y,z,type0,type1,type2)\
Syscall z; uintptr x(va_list va){\
uintptr rc;\
va_list vb = va;\
DTTrigInfo info;\
memset(&info, 0, sizeof(info));\
info.arg[0] = (uvlong) va_arg(vb, type0);\
info.arg[1] = (uvlong) va_arg(vb, type1);\
info.arg[2] = (uvlong) va_arg(vb, type2);\
dtptrigger(dtpsysentry[y], &info);\
rc = z(va);\
info.arg[9] = (uvlong) rc;\
dtptrigger(dtpsysreturn[y], &info);\
return rc;\
}
#define WRAP4(x,y,z,type0,type1,type2,type3)\
Syscall z; uintptr x(va_list va){\
uintptr rc;\
va_list vb = va;\
DTTrigInfo info;\
memset(&info, 0, sizeof(info));\
info.arg[0] = (uvlong) va_arg(vb, type0);\
info.arg[1] = (uvlong) va_arg(vb, type1);\
info.arg[2] = (uvlong) va_arg(vb, type2);\
info.arg[3] = (uvlong) va_arg(vb, type3);\
dtptrigger(dtpsysentry[y], &info);\
rc = z(va);\
info.arg[9] = (uvlong) rc;\
dtptrigger(dtpsysreturn[y], &info);\
return rc;\
}
/*TODO*/
#define WRAP5(x,y,z,type0,type1,type2,type3,type4)\
Syscall z; uintptr x(va_list va){\
uintptr rc;\
va_list vb = va;\
DTTrigInfo info;\
memset(&info, 0, sizeof(info));\
info.arg[0] = (uvlong) va_arg(vb, type0);\
info.arg[1] = (uvlong) va_arg(vb, type1);\
info.arg[2] = (uvlong) va_arg(vb, type2);\
info.arg[3] = (uvlong) va_arg(vb, type3);\
info.arg[4] = (uvlong) va_arg(vb, type4);\
dtptrigger(dtpsysentry[y], &info);\
rc = z(va);\
info.arg[9] = (uvlong) rc;\
dtptrigger(dtpsysreturn[y], &info);\
return rc;\
}
WRAP0(dtwrap_sysr1, SYSR1, sysr1)
WRAP1(dtwrap_sys_errstr, _ERRSTR, sys_errstr, char*)
WRAP3(dtwrap_sysbind, BIND, sysbind, char*, char*, int)
WRAP1(dtwrap_syschdir, CHDIR, syschdir, char*)
WRAP1(dtwrap_sysclose, CLOSE, sysclose, int)
WRAP2(dtwrap_sysdup, DUP, sysdup, int, int)
WRAP1(dtwrap_sysalarm, ALARM, sysalarm, ulong)
WRAP2(dtwrap_sysexec, EXEC, sysexec, char *, char **)
WRAP1(dtwrap_sysexits, EXITS, sysexits, char *)
WRAP3(dtwrap_sys_fsession, _FSESSION, sys_fsession, int, char *, uint)
WRAP2(dtwrap_sysfauth, FAUTH, sysfauth, int, char *)
WRAP2(dtwrap_sys_fstat, _FSTAT, sys_fstat, int, uchar *)
WRAP1(dtwrap_syssegbrk, SEGBRK, syssegbrk, void *)
WRAP4(dtwrap_sys_mount, _MOUNT, sys_mount, int, char *, int, char *)
WRAP2(dtwrap_sysopen, OPEN, sysopen, char *, int)
WRAP3(dtwrap_sys_read, _READ, sys_read, int, void*, long)
WRAP3(dtwrap_sysoseek, OSEEK, sysoseek, int, long, int)
WRAP1(dtwrap_syssleep, SLEEP, syssleep, long)
WRAP2(dtwrap_sys_stat, _STAT, sys_stat, char *, uchar *)
WRAP1(dtwrap_sysrfork, RFORK, sysrfork, int)
WRAP3(dtwrap_sys_write, _WRITE, sys_write, int, void *, long)
WRAP1(dtwrap_syspipe, PIPE, syspipe, int*)
WRAP3(dtwrap_syscreate, CREATE, syscreate, char*, int, int)
WRAP3(dtwrap_sysfd2path, FD2PATH, sysfd2path, int, char*, uint)
WRAP1(dtwrap_sysbrk_, BRK_, sysbrk_, uintptr)
WRAP1(dtwrap_sysremove, REMOVE, sysremove, char *)
WRAP0(dtwrap_sys_wstat, _WSTAT, sys_wstat)
WRAP0(dtwrap_sys_fwstat, _FWSTAT, sys_fwstat)
WRAP2(dtwrap_sysnotify, NOTIFY, sysnotify, char *, void *)
WRAP1(dtwrap_sysnoted, NOTED, sysnoted, int)
WRAP4(dtwrap_syssegattach, SEGATTACH, syssegattach, int, char *, uintptr, ulong)
WRAP1(dtwrap_syssegdetach, SEGDETACH, syssegdetach, uintptr)
WRAP2(dtwrap_syssegfree, SEGFREE, syssegfree, uintptr, ulong)
WRAP2(dtwrap_syssegflush, SEGFLUSH, syssegflush, void*, ulong)
WRAP2(dtwrap_sysrendezvous, RENDEZVOUS, sysrendezvous, uintptr, uintptr)
WRAP2(dtwrap_sysunmount, UNMOUNT, sysunmount, char *, char *)
WRAP1(dtwrap_sys_wait, _WAIT, sys_wait, void*)
WRAP2(dtwrap_syssemacquire, SEMACQUIRE, syssemacquire, long*, int)
WRAP2(dtwrap_syssemrelease, SEMRELEASE, syssemrelease, long*, long)
WRAP4(dtwrap_sysfversion, FVERSION, sysfversion, int, int, char *, int)
WRAP2(dtwrap_syserrstr, ERRSTR, syserrstr, char *, uint)
WRAP3(dtwrap_sysstat, STAT, sysstat, char *, uchar *, uint)
WRAP3(dtwrap_sysfstat, FSTAT, sysfstat, int, uchar *, uint)
WRAP3(dtwrap_syswstat, WSTAT, syswstat, char *, uchar *, uint)
WRAP3(dtwrap_sysfwstat, FWSTAT, sysfwstat, int, uchar *, uint)
WRAP5(dtwrap_sysmount, MOUNT, sysmount, int, int, char *, int, char *)
WRAP2(dtwrap_sysawait, AWAIT, sysawait, char *, uint)
WRAP4(dtwrap_syspread, PREAD, syspread, int, void *, long, vlong)
WRAP4(dtwrap_syspwrite, PWRITE, syspwrite, int, void *, long, vlong)
WRAP2(dtwrap_systsemacquire, TSEMACQUIRE, systsemacquire, long *, ulong)
/* TODO: amd64 */
WRAP4(dtwrap_sysseek, SEEK, sysseek, vlong*, int, vlong, int)
WRAP1(dtwrap_sys_nsec, _NSEC, sys_nsec, vlong*)
static Syscall *wraptab[]={
[SYSR1] dtwrap_sysr1,
[_ERRSTR] dtwrap_sys_errstr,
[BIND] dtwrap_sysbind,
[CHDIR] dtwrap_syschdir,
[CLOSE] dtwrap_sysclose,
[DUP] dtwrap_sysdup,
[ALARM] dtwrap_sysalarm,
[EXEC] dtwrap_sysexec,
[EXITS] dtwrap_sysexits,
[_FSESSION] dtwrap_sys_fsession,
[FAUTH] dtwrap_sysfauth,
[_FSTAT] dtwrap_sys_fstat,
[SEGBRK] dtwrap_syssegbrk,
[_MOUNT] dtwrap_sys_mount,
[OPEN] dtwrap_sysopen,
[_READ] dtwrap_sys_read,
[OSEEK] dtwrap_sysoseek,
[SLEEP] dtwrap_syssleep,
[_STAT] dtwrap_sys_stat,
[RFORK] dtwrap_sysrfork,
[_WRITE] dtwrap_sys_write,
[PIPE] dtwrap_syspipe,
[CREATE] dtwrap_syscreate,
[FD2PATH] dtwrap_sysfd2path,
[BRK_] dtwrap_sysbrk_,
[REMOVE] dtwrap_sysremove,
[_WSTAT] dtwrap_sys_wstat,
[_FWSTAT] dtwrap_sys_fwstat,
[NOTIFY] dtwrap_sysnotify,
[NOTED] dtwrap_sysnoted,
[SEGATTACH] dtwrap_syssegattach,
[SEGDETACH] dtwrap_syssegdetach,
[SEGFREE] dtwrap_syssegfree,
[SEGFLUSH] dtwrap_syssegflush,
[RENDEZVOUS] dtwrap_sysrendezvous,
[UNMOUNT] dtwrap_sysunmount,
[_WAIT] dtwrap_sys_wait,
[SEMACQUIRE] dtwrap_syssemacquire,
[SEMRELEASE] dtwrap_syssemrelease,
[SEEK] dtwrap_sysseek,
[FVERSION] dtwrap_sysfversion,
[ERRSTR] dtwrap_syserrstr,
[STAT] dtwrap_sysstat,
[FSTAT] dtwrap_sysfstat,
[WSTAT] dtwrap_syswstat,
[FWSTAT] dtwrap_sysfwstat,
[MOUNT] dtwrap_sysmount,
[AWAIT] dtwrap_sysawait,
[PREAD] dtwrap_syspread,
[PWRITE] dtwrap_syspwrite,
[TSEMACQUIRE] dtwrap_systsemacquire,
[_NSEC] dtwrap_sys_nsec,
};
static void
sysprovide(DTProvider *prov)
{
char buf[32], pname[32];
int i;
dtpsysentry = smalloc(sizeof(Syscall *) * nsyscall);
dtpsysreturn = smalloc(sizeof(Syscall *) * nsyscall);
for(i = 0; i < nsyscall; i++){
if(systab[i] == nil || sysctab[i] == nil) continue;
strecpy(buf, buf + sizeof(buf), sysctab[i]);
if(isupper(buf[0])) buf[0] += 'a' - 'A';
if(i == SYSR1) strcpy(buf, "r1");
snprint(pname, sizeof(pname), "sys:%s:entry", buf);
dtpsysentry[i] = dtpnew(pname, prov, (void *) i);
snprint(pname, sizeof(pname), "sys:%s:return", buf);
dtpsysreturn[i] = dtpnew(pname, prov, (void *) i);
}
}
static int
sysenable(DTProbe *p)
{
int i;
Syscall *z;
i = (int)(uintptr)p->aux;
assert(i >= 0 && i < nsyscall);
if(dtpsysentry[i]->nenable + dtpsysreturn[i]->nenable == 0)
z = systab[i], systab[i] = wraptab[i], wraptab[i] = z;
return 0;
}
static void
sysdisable(DTProbe *p)
{
int i;
Syscall *z;
i = (int)(uintptr)p->aux;
assert(i >= 0 && i < nsyscall);
if(dtpsysentry[i]->nenable + dtpsysreturn[i]->nenable == 0)
z = systab[i], systab[i] = wraptab[i], wraptab[i] = z;
}
DTProvider dtracysysprov = {
.name = "sys",
.provide = sysprovide,
.enable = sysenable,
.disable = sysdisable,
};