+
+char *lookup_name(unsigned long addr)
+{
+ register int i;
+ register int start, last;
+
+
+ if (numFrameworks == 0 || addr < frameworkInfo[0].address || addr > frameworkInfo[numFrameworks].address)
+ return (0);
+
+ start = 0;
+ last = numFrameworks;
+
+ for (i = numFrameworks / 2; i >= 0 && i < numFrameworks; ) {
+
+ if (addr >= frameworkInfo[i].address && addr < frameworkInfo[i+1].address)
+ return(frameworkInfo[i].name);
+
+ if (addr >= frameworkInfo[i].address) {
+ start = i;
+ i = start + ((last - i) / 2);
+ } else {
+ last = i;
+ i = start + ((i - start) / 2);
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * Comparison routines for sorting
+ */
+static int compareFrameworkAddress(const void *aa, const void *bb)
+{
+ LibraryInfo *a = (LibraryInfo *)aa;
+ LibraryInfo *b = (LibraryInfo *)bb;
+
+ if (a->address < b->address) return -1;
+ if (a->address == b->address) return 0;
+ return 1;
+}
+
+
+int scanline(char *inputstring,char **argv)
+{
+ int n = 0;
+ char **ap = argv, *p, *val;
+
+ for (p = inputstring; p != NULL; )
+ {
+ while ((val = strsep(&p, " \t")) != NULL && *val == '\0');
+ *ap++ = val;
+ n++;
+ }
+ *ap = 0;
+ return n;
+}
+
+
+int ReadSegAddrTable()
+{
+ char buf[1024];
+
+ FILE *fd;
+ unsigned long frameworkAddress, frameworkDataAddress, previousFrameworkAddress;
+ char frameworkName[256];
+ char *tokens[64];
+ int ntokens;
+ char *substring,*ptr;
+ int founddylib = 0;
+
+
+ bzero(buf, sizeof(buf));
+ bzero(tokens, sizeof(tokens));
+
+ numFrameworks = 0;
+
+ if ((fd = fopen(seg_addr_table, "r")) == 0)
+ {
+ return 0;
+ }
+ fgets(buf, 1023, fd);
+
+ if (*buf == '#')
+ {
+ founddylib = 0;
+ frameworkName[0] = 0;
+ previousFrameworkAddress = 0;
+
+ while (fgets(buf, 1023, fd) && numFrameworks < (MAXINDEX - 2))
+ {
+ /*
+ * Get rid of EOL
+ */
+ buf[strlen(buf)-1] = 0;
+
+ if (strncmp(buf, "# dyld:", 7) == 0) {
+ /*
+ * the next line in the file will contain info about dyld
+ */
+ founddylib = 1;
+ continue;
+ }
+ /*
+ * This is a split library line: parse it into 3 tokens
+ */
+ ntokens = scanline(buf, tokens);
+
+ if (ntokens < 3)
+ continue;
+
+ frameworkAddress = strtoul(tokens[0], 0, 16);
+ frameworkDataAddress = strtoul(tokens[1], 0, 16);
+
+ if (founddylib) {
+ /*
+ * dyld entry is of a different form from the std split library
+ * it consists of a base address and a size instead of a code
+ * and data base address
+ */
+ frameworkInfo[numFrameworks].address = frameworkAddress;
+ frameworkInfo[numFrameworks+1].address = frameworkAddress + frameworkDataAddress;
+
+ frameworkInfo[numFrameworks].name = (char *)"dylib";
+ frameworkInfo[numFrameworks+1].name = (char *)0;
+
+ numFrameworks += 2;
+ founddylib = 0;
+
+ continue;
+ }
+
+ /*
+ * Make sure that we have 2 addresses and a path
+ */
+ if (!frameworkAddress)
+ continue;
+ if (!frameworkDataAddress)
+ continue;
+ if (*tokens[2] != '/')
+ continue;
+ if (frameworkAddress == previousFrameworkAddress)
+ continue;
+ previousFrameworkAddress = frameworkAddress;
+
+ /*
+ * Extract lib name from path name
+ */
+ if ((substring = strrchr(tokens[2], '.')))
+ {
+ /*
+ * There is a ".": name is whatever is between the "/" around the "."
+ */
+ while ( *substring != '/') { /* find "/" before "." */
+ substring--;
+ }
+ substring++;
+ strcpy(frameworkName, substring); /* copy path from "/" */
+ substring = frameworkName;
+
+ while ( *substring != '/' && *substring) /* find "/" after "." and stop string there */
+ substring++;
+ *substring = 0;
+ }
+ else
+ {
+ /*
+ * No ".": take segment after last "/"
+ */
+ ptr = tokens[2];
+ substring = ptr;
+
+ while (*ptr)
+ {
+ if (*ptr == '/')
+ substring = ptr + 1;
+ ptr++;
+ }
+ strcpy(frameworkName, substring);
+ }
+ frameworkInfo[numFrameworks].address = frameworkAddress;
+ frameworkInfo[numFrameworks+1].address = frameworkDataAddress;
+
+ frameworkInfo[numFrameworks].name = (char *)malloc(strlen(frameworkName) + 1);
+ strcpy(frameworkInfo[numFrameworks].name, frameworkName);
+ frameworkInfo[numFrameworks+1].name = frameworkInfo[numFrameworks].name;
+
+ numFrameworks += 2;
+ }
+ }
+ frameworkInfo[numFrameworks].address = frameworkInfo[numFrameworks - 1].address + 0x800000;
+ frameworkInfo[numFrameworks].name = (char *)0;
+
+ fclose(fd);
+
+ qsort(frameworkInfo, numFrameworks, sizeof(LibraryInfo), compareFrameworkAddress);
+
+ return 1;
+}
+
+
+struct diskio *insert_diskio(int type, int bp, int dev, int blkno, int io_size, int thread, double curtime)
+{
+ register struct diskio *dio;
+ register kd_threadmap *map;
+
+ if ((dio = free_diskios))
+ free_diskios = dio->next;
+ else {
+ if ((dio = (struct diskio *)malloc(sizeof(struct diskio))) == NULL)
+ return (NULL);
+ }
+ dio->prev = NULL;
+
+ dio->type = type;
+ dio->bp = bp;
+ dio->dev = dev;
+ dio->blkno = blkno;
+ dio->iosize = io_size;
+ dio->issued_time = curtime;
+ dio->issuing_thread = thread;
+
+ if ((map = find_thread_map(thread)))
+ {
+ strncpy(dio->issuing_command, map->command, MAXCOMLEN);
+ dio->issuing_command[MAXCOMLEN-1] = '\0';
+ }
+ else
+ strcpy(dio->issuing_command, "");
+
+ dio->next = busy_diskios;
+ if (dio->next)
+ dio->next->prev = dio;
+ busy_diskios = dio;
+
+ return (dio);
+}
+
+
+struct diskio *complete_diskio(int bp, int io_errno, int resid, int thread, double curtime)
+{
+ register struct diskio *dio;
+
+ for (dio = busy_diskios; dio; dio = dio->next) {
+ if (dio->bp == bp) {
+
+ if (dio == busy_diskios) {
+ if ((busy_diskios = dio->next))
+ dio->next->prev = NULL;
+ } else {
+ if (dio->next)
+ dio->next->prev = dio->prev;
+ dio->prev->next = dio->next;
+ }
+ dio->iosize -= resid;
+ dio->io_errno = io_errno;
+ dio->completed_time = curtime;
+ dio->completion_thread = thread;
+
+ return (dio);
+ }
+ }
+ return ((struct diskio *)0);
+}
+
+
+void free_diskio(struct diskio *dio)
+{
+ dio->next = free_diskios;
+ free_diskios = dio;
+}
+
+
+void print_diskio(struct diskio *dio)
+{
+ register char *p;
+
+ switch (dio->type) {
+
+ case P_RdMeta:
+ p = " RdMeta";
+ break;
+ case P_WrMeta:
+ p = " WrMeta";
+ break;
+ case P_RdData:
+ p = " RdData";
+ break;
+ case P_WrData:
+ p = " WrData";
+ break;
+ case P_PgIn:
+ p = " PgIn";
+ break;
+ case P_PgOut:
+ p = " PgOut";
+ break;
+ case P_RdMetaAsync:
+ p = " RdMeta[async]";
+ break;
+ case P_WrMetaAsync:
+ p = " WrMeta[async]";
+ break;
+ case P_RdDataAsync:
+ p = " RdData[async]";
+ break;
+ case P_WrDataAsync:
+ p = " WrData[async]";
+ break;
+ case P_PgInAsync:
+ p = " PgIn[async]";
+ break;
+ case P_PgOutAsync:
+ p = " PgOut[async]";
+ break;
+ default:
+ p = " ";
+ break;
+ }
+ if (check_filter_mode(NULL, dio->type,0, 0, p))
+ format_print(NULL, p, dio->issuing_thread, dio->type, 0, 0, 0, 7, dio->completed_time, dio->issued_time, 1, "", dio);
+}
+
+
+void cache_disk_names()
+{
+ struct stat st;
+ DIR *dirp = NULL;
+ struct dirent *dir;
+ struct diskrec *dnp;
+
+
+ if ((dirp = opendir("/dev")) == NULL)
+ return;
+
+ while ((dir = readdir(dirp)) != NULL) {
+ char nbuf[MAXPATHLEN];
+
+ if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
+ continue;
+ sprintf(nbuf, "%s/%s", "/dev", dir->d_name);
+
+ if (stat(nbuf, &st) < 0)
+ continue;
+
+ if ((dnp = (struct diskrec *)malloc(sizeof(struct diskrec))) == NULL)
+ continue;
+
+ if ((dnp->diskname = (char *)malloc(dir->d_namlen + 1)) == NULL) {
+ free(dnp);
+ continue;
+ }
+ strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
+ dnp->diskname[dir->d_namlen] = 0;
+ dnp->dev = st.st_rdev;
+
+ dnp->next = disk_list;
+ disk_list = dnp;
+ }
+ (void) closedir(dirp);
+}
+
+
+char *find_disk_name(int dev)
+{
+ struct diskrec *dnp;
+
+ if (dev == NFS_DEV)
+ return ("NFS");
+
+ for (dnp = disk_list; dnp; dnp = dnp->next) {
+ if (dnp->dev == dev)
+ return (dnp->diskname);
+ }
+ return ("NOTFOUND");
+}
+
+void
+fs_usage_fd_set(thread, fd)
+ unsigned int thread;
+ unsigned int fd;
+{
+ int n;
+ fd_threadmap *fdmap;
+
+ if(!(fdmap = find_fd_thread_map(thread)))
+ return;
+
+ /* If the map is not allocated, then now is the time */
+ if (fdmap->fd_setptr == (unsigned long *)0)
+ {
+ fdmap->fd_setptr = (unsigned long *)malloc(FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE));
+ if (fdmap->fd_setptr)
+ {
+ fdmap->fd_setsize = FS_USAGE_FD_SETSIZE;
+ bzero(fdmap->fd_setptr,(FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE)));
+ }
+ else
+ return;
+ }
+
+ /* If the map is not big enough, then reallocate it */
+ while (fdmap->fd_setsize < fd)
+ {
+ fprintf(stderr, "reallocating bitmap for threadid %d, fd = %d, setsize = %d\n",
+ thread, fd, fdmap->fd_setsize);
+ n = fdmap->fd_setsize * 2;
+ fdmap->fd_setptr = (unsigned long *)realloc(fdmap->fd_setptr, (FS_USAGE_NFDBYTES(n)));
+ bzero(&fdmap->fd_setptr[(fdmap->fd_setsize/FS_USAGE_NFDBITS)], (FS_USAGE_NFDBYTES(fdmap->fd_setsize)));
+ fdmap->fd_setsize = n;
+ }
+
+ /* set the bit */
+ fdmap->fd_setptr[fd/FS_USAGE_NFDBITS] |= (1 << ((fd) % FS_USAGE_NFDBITS));
+
+ return;
+}
+
+/*
+ Return values:
+ 0 : File Descriptor bit is not set
+ 1 : File Descriptor bit is set
+*/
+
+int
+fs_usage_fd_isset(thread, fd)
+ unsigned int thread;
+ unsigned int fd;
+{
+ int ret = 0;
+ fd_threadmap *fdmap;
+
+ if(!(fdmap = find_fd_thread_map(thread)))
+ return(ret);
+
+ if (fdmap->fd_setptr == (unsigned long *)0)
+ return (ret);
+
+ if (fd < fdmap->fd_setsize)
+ ret = fdmap->fd_setptr[fd/FS_USAGE_NFDBITS] & (1 << (fd % FS_USAGE_NFDBITS));
+
+ return (ret);
+}
+
+void
+fs_usage_fd_clear(thread, fd)
+ unsigned int thread;
+ unsigned int fd;
+{
+ fd_threadmap *map;
+
+ if (!(map = find_fd_thread_map(thread)))
+ return;
+
+ if (map->fd_setptr == (unsigned long *)0)
+ return;
+
+ /* clear the bit */
+ if (fd < map->fd_setsize)
+ map->fd_setptr[fd/FS_USAGE_NFDBITS] &= ~(1 << (fd % FS_USAGE_NFDBITS));
+
+ return;
+}
+
+
+/*
+ * ret = 1 means print the entry
+ * ret = 0 means don't print the entry
+ */
+int
+check_filter_mode(struct th_info * ti, int type, int error, int retval, char *sc_name)
+{
+ int ret = 0;
+ int network_fd_isset = 0;
+ unsigned int fd;
+
+ if (filter_mode == DEFAULT_DO_NOT_FILTER)
+ return(1);
+
+ if (!strcmp (sc_name, "CACHE_HIT")) {
+ if (filter_mode & CACHEHIT_FILTER)
+ /* Do not print if cachehit filter is set */
+ return(0);
+ return (1);
+ }
+
+ if (filter_mode & EXEC_FILTER)
+ {
+ if (!strcmp (sc_name, "execve"))
+ return(1);
+ return(0);
+ }
+ if ( !(filter_mode & (FILESYS_FILTER | NETWORK_FILTER)))
+ return(1);
+
+
+ if (ti == (struct th_info *)0)
+ {
+ if(filter_mode & FILESYS_FILTER)
+ ret = 1;
+ else
+ ret = 0;
+ return(ret);
+ }
+
+ switch (type) {
+ case BSC_close:
+ fd = ti->arg1;
+ network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
+ if (error == 0)
+ {
+ fs_usage_fd_clear(ti->thread,fd);
+ }
+
+ if (network_fd_isset)
+ {
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ }
+ else if (filter_mode & FILESYS_FILTER)
+ ret = 1;
+ break;
+ case BSC_read:
+ case BSC_write:
+ /* we don't care about error in this case */
+ fd = ti->arg1;
+ network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
+ if (network_fd_isset)
+ {
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ }
+ else if (filter_mode & FILESYS_FILTER)
+ ret = 1;
+ break;
+ case BSC_accept:
+ case BSC_socket:
+ fd = retval;
+ if (error == 0)
+ fs_usage_fd_set(ti->thread, fd);
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ break;
+ case BSC_recvfrom:
+ case BSC_sendto:
+ case BSC_recvmsg:
+ case BSC_sendmsg:
+ case BSC_connect:
+ case BSC_bind:
+ case BSC_listen:
+ fd = ti->arg1;
+ if (error == 0)
+ fs_usage_fd_set(ti->thread, fd);
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ break;
+ case BSC_select:
+ case BSC_socketpair:
+ /* Cannot determine info about file descriptors */
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ break;
+ case BSC_dup:
+ case BSC_dup2:
+ ret=0; /* We track these cases for fd state only */
+ fd = ti->arg1; /* oldd */
+ network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
+ if (error == 0 && network_fd_isset)
+ {
+ /* then we are duping a socket descriptor */
+ fd = retval; /* the new fd */
+ fs_usage_fd_set(ti->thread, fd);
+ }
+ break;
+
+ default:
+ if (filter_mode & FILESYS_FILTER)
+ ret = 1;
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ * Allocate a buffer that is large enough to hold the maximum arguments
+ * to execve(). This is used when getting the arguments to programs
+ * when we see LaunchCFMApps. If this fails, it is not fatal, we will
+ * simply not resolve the command name.
+ */
+
+void
+init_arguments_buffer()
+{
+
+ int mib[2];
+ size_t size;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+ size = sizeof(argmax);
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
+ return;
+
+#if 1
+ /* Hack to avoid kernel bug. */
+ if (argmax > 8192) {
+ argmax = 8192;
+ }
+#endif
+
+ arguments = (char *)malloc(argmax);
+
+ return;
+}
+
+
+int
+get_real_command_name(int pid, char *cbuf, int csize)
+{
+ /*
+ * Get command and arguments.
+ */
+ char *cp;
+ int mib[4];
+ char *command_beg, *command, *command_end;
+
+ if (cbuf == NULL) {
+ return(0);
+ }
+
+ if (arguments)
+ bzero(arguments, argmax);
+ else
+ return(0);
+
+ /*
+ * A sysctl() is made to find out the full path that the command
+ * was called with.
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS;
+ mib[2] = pid;
+ mib[3] = 0;
+
+ if (sysctl(mib, 3, arguments, (size_t *)&argmax, NULL, 0) < 0) {
+ return(0);
+ }
+
+ /* Skip the saved exec_path. */
+ for (cp = arguments; cp < &arguments[argmax]; cp++) {
+ if (*cp == '\0') {
+ /* End of exec_path reached. */
+ break;
+ }
+ }
+ if (cp == &arguments[argmax]) {
+ return(0);
+ }
+
+ /* Skip trailing '\0' characters. */
+ for (; cp < &arguments[argmax]; cp++) {
+ if (*cp != '\0') {
+ /* Beginning of first argument reached. */
+ break;
+ }
+ }
+ if (cp == &arguments[argmax]) {
+ return(0);
+ }
+ command_beg = cp;
+
+ /*
+ * Make sure that the command is '\0'-terminated. This protects
+ * against malicious programs; under normal operation this never
+ * ends up being a problem..
+ */
+ for (; cp < &arguments[argmax]; cp++) {
+ if (*cp == '\0') {
+ /* End of first argument reached. */
+ break;
+ }
+ }
+ if (cp == &arguments[argmax]) {
+ return(0);
+ }
+ command_end = command = cp;
+
+ /* Get the basename of command. */
+ for (command--; command >= command_beg; command--) {
+ if (*command == '/') {
+ command++;
+ break;
+ }
+ }
+
+ (void) strncpy(cbuf, (char *)command, csize);
+ cbuf[csize-1] = '\0';
+
+ return(1);
+}