Blame sysdeps/freebsd/procmap.c

Packit Service 407539
/* Copyright (C) 1998 Joshua Sled
Packit Service 407539
   This file is part of LibGTop 1.0.
Packit Service 407539
Packit Service 407539
   Contributed by Joshua Sled <jsled@xcf.berkeley.edu>, July 1998.
Packit Service 407539
Packit Service 407539
   LibGTop is free software; you can redistribute it and/or modify it
Packit Service 407539
   under the terms of the GNU General Public License as published by
Packit Service 407539
   the Free Software Foundation; either version 2 of the License,
Packit Service 407539
   or (at your option) any later version.
Packit Service 407539
Packit Service 407539
   LibGTop is distributed in the hope that it will be useful, but WITHOUT
Packit Service 407539
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit Service 407539
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit Service 407539
   for more details.
Packit Service 407539
Packit Service 407539
   You should have received a copy of the GNU General Public License
Packit Service 407539
   along with LibGTop; see the file COPYING. If not, write to the
Packit Service 407539
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit Service 407539
   Boston, MA 02110-1301, USA.
Packit Service 407539
*/
Packit Service 407539
Packit Service 407539
#include <config.h>
Packit Service 407539
#include <glibtop.h>
Packit Service 407539
#include <glibtop/error.h>
Packit Service 407539
#include <glibtop/procmap.h>
Packit Service 407539
Packit Service 407539
#include <glibtop_suid.h>
Packit Service 407539
Packit Service 407539
#include <kvm.h>
Packit Service 407539
#include <sys/param.h>
Packit Service 407539
#include <sys/proc.h>
Packit Service 407539
#include <sys/resource.h>
Packit Service 407539
#include <vm/vm_object.h>
Packit Service 407539
#include <vm/vm_map.h>
Packit Service 407539
#include <vm/vm.h>
Packit Service 407539
Packit Service 407539
#define _KVM_VNODE
Packit Service 407539
#include <sys/vnode.h>
Packit Service 407539
#undef _KVM_VNODE
Packit Service 407539
Packit Service 407539
#include <sys/conf.h>
Packit Service 407539
#if (__FreeBSD_version >= 800038) || (__FreeBSD_kernel_version >= 800038)
Packit Service 407539
#define _WANT_FILE
Packit Service 407539
#include <sys/file.h>
Packit Service 407539
#undef _WANT_FILE
Packit Service 407539
#else
Packit Service 407539
#define _KERNEL
Packit Service 407539
#include <sys/file.h>
Packit Service 407539
#undef _KERNEL
Packit Service 407539
#endif
Packit Service 407539
#define _KERNEL
Packit Service 407539
#include <sys/mount.h>
Packit Service 407539
#include <ufs/ufs/quota.h>
Packit Service 407539
#include <ufs/ufs/inode.h>
Packit Service 407539
#include <fs/devfs/devfs.h>
Packit Service 407539
#if (__FreeBSD_version >= 600006) || defined(__FreeBSD_kernel__)
Packit Service 407539
#include <fs/devfs/devfs_int.h>
Packit Service 407539
#endif
Packit Service 407539
#undef _KERNEL
Packit Service 407539
Packit Service 407539
Packit Service 407539
#if (__FreeBSD_version >= 1101001)
Packit Service 407539
#define _KERNEL
Packit Service 407539
#include <ufs/ufs/extattr.h>
Packit Service 407539
#include <ufs/ufs/ufsmount.h>
Packit Service 407539
#undef _KERNEL
Packit Service 407539
#endif
Packit Service 407539
Packit Service 407539
Packit Service 407539
#include <sys/ucred.h>
Packit Service 407539
#include <sys/sysctl.h>
Packit Service 407539
Packit Service 407539
static const unsigned long _glibtop_sysdeps_proc_map =
Packit Service 407539
        (1L << GLIBTOP_PROC_MAP_TOTAL) + (1L << GLIBTOP_PROC_MAP_NUMBER) +
Packit Service 407539
        (1L << GLIBTOP_PROC_MAP_SIZE);
Packit Service 407539
Packit Service 407539
static const unsigned long _glibtop_sysdeps_map_entry =
Packit Service 407539
        (1L << GLIBTOP_MAP_ENTRY_START) + (1L << GLIBTOP_MAP_ENTRY_END) +
Packit Service 407539
        (1L << GLIBTOP_MAP_ENTRY_OFFSET) + (1L << GLIBTOP_MAP_ENTRY_PERM) +
Packit Service 407539
        (1L << GLIBTOP_MAP_ENTRY_INODE) + (1L << GLIBTOP_MAP_ENTRY_DEVICE);
Packit Service 407539
Packit Service 407539
#if (__FreeBSD_version >= 600006) || defined(__FreeBSD_kernel__)
Packit Service 407539
void _glibtop_sysdeps_freebsd_dev_inode (glibtop *server, struct vnode *vnode, struct vnode *vn, guint64 *inum, guint64 *dev);
Packit Service 407539
Packit Service 407539
void
Packit Service 407539
_glibtop_sysdeps_freebsd_dev_inode (glibtop *server, struct vnode *vnode,
Packit Service 407539
                                    struct vnode *vn, guint64 *inum,
Packit Service 407539
                                    guint64 *dev)
Packit Service 407539
{
Packit Service 407539
        char *tagptr;
Packit Service 407539
        char tagstr[12];
Packit Service 407539
        enum FS_TYPE { UNKNOWN, IS_UFS, IS_ZFS };
Packit Service 407539
        int fs_type = UNKNOWN;
Packit Service 407539
        struct inode inode;
Packit Service 407539
        struct cdev_priv priv;
Packit Service 407539
#if __FreeBSD_version < 800039
Packit Service 407539
        struct cdev si;
Packit Service 407539
#endif
Packit Service 407539
Packit Service 407539
        *inum = 0;
Packit Service 407539
        *dev = 0;
Packit Service 407539
Packit Service 407539
        if (kvm_read (server->machine->kd, (gulong) &vnode->v_tag,
Packit Service 407539
 	             (char *) &tagptr, sizeof (tagptr)) != sizeof (tagptr) ||
Packit Service 407539
            kvm_read (server->machine->kd, (gulong) tagptr,
Packit Service 407539
		     (char *) tagstr, sizeof (tagstr)) != sizeof (tagstr))
Packit Service 407539
        {
Packit Service 407539
                glibtop_warn_io_r (server, "kvm_read (tagptr)");
Packit Service 407539
                return;
Packit Service 407539
        }
Packit Service 407539
Packit Service 407539
        tagstr[sizeof(tagstr) - 1] = '\0';
Packit Service 407539
Packit Service 407539
        if (!strcmp(tagstr, "ufs")) {
Packit Service 407539
                fs_type = IS_UFS;
Packit Service 407539
        } else if (!strcmp(tagstr, "zfs")) {
Packit Service 407539
                fs_type = IS_ZFS;
Packit Service 407539
        } else {
Packit Service 407539
                glibtop_warn_io_r (server, "ignoring fstype %s", tagstr);
Packit Service 407539
                return;
Packit Service 407539
        }
Packit Service 407539
Packit Service 407539
        if (kvm_read (server->machine->kd, (gulong) VTOI(vn), (char *) &inode,
Packit Service 407539
 	              sizeof (inode)) != sizeof (inode))
Packit Service 407539
        {
Packit Service 407539
                glibtop_warn_io_r (server, "kvm_read (inode)");
Packit Service 407539
                return;
Packit Service 407539
        }
Packit Service 407539
Packit Service 407539
Packit Service 407539
        if (fs_type == IS_ZFS) {
Packit Service 407539
		/* FIXME: I have no idea about what is the actual layout of what we've read
Packit Service 407539
		   but the inode number is definitely at offset 16, 8 bytes of amd64.
Packit Service 407539
		   *inum = *(guint64*) ((unsigned char*)&inode + 16);
Packit Service 407539
		   So this is really hugly, but I don't have anything better for now.
Packit Service 407539
Packit Service 407539
                   Actually, this looks like a znode_t as described in kernel's zfs_znode.h.
Packit Service 407539
                   I don't have that header file, so let's just mimic that.
Packit Service 407539
                */
Packit Service 407539
Packit Service 407539
                struct my_zfsvfs {
Packit Service 407539
                        /* vfs_t */ void *z_vfs;
Packit Service 407539
                        /* zfsvfs_t */ void *z_parent;
Packit Service 407539
                        /* objset_t */ void *z_os;
Packit Service 407539
                        uint64_t z_root;
Packit Service 407539
                        /* ... */
Packit Service 407539
                };
Packit Service 407539
Packit Service 407539
                typedef struct my_znode {
Packit Service 407539
                        struct my_zfsvfs *z_zfsvfs;
Packit Service 407539
                        /* vnode_t */ void *z_vnode;
Packit Service 407539
                        uint64_t z_id;
Packit Service 407539
                        /* ... */
Packit Service 407539
                } my_znode_t;
Packit Service 407539
Packit Service 407539
                G_STATIC_ASSERT(sizeof(my_znode_t) <= sizeof(struct inode));
Packit Service 407539
Packit Service 407539
                my_znode_t* znode = (my_znode_t*)&inode;
Packit Service 407539
                *inum = znode->z_id;
Packit Service 407539
Packit Service 407539
                struct my_zfsvfs zvfs;
Packit Service 407539
Packit Service 407539
                if (kvm_read(server->machine->kd,
Packit Service 407539
                             (unsigned long)(znode->z_zfsvfs),
Packit Service 407539
                             &zvfs, sizeof zvfs) != sizeof zvfs) {
Packit Service 407539
                        glibtop_warn_io_r(server, "kvm_read (z_zfsvfs)");
Packit Service 407539
                        return;
Packit Service 407539
                }
Packit Service 407539
Packit Service 407539
                *dev = zvfs.z_root;
Packit Service 407539
        }
Packit Service 407539
        else if (fs_type == IS_UFS) {
Packit Service 407539
		/* Set inum as soon as possible, so that if the next kvm_reads fail
Packit Service 407539
		   we still have something */
Packit Service 407539
                *inum = inode.i_number;
Packit Service 407539
Packit Service 407539
Packit Service 407539
#if (__FreeBSD_version >= 1101001)
Packit Service 407539
/*
Packit Service 407539
  The ufs struct inode changed between 11.0 and 11.1.
Packit Service 407539
Packit Service 407539
  commit 20f1e8ac63b58708989267ea34a6aefa90b46577
Packit Service 407539
  Author: kib <kib@FreeBSD.org>
Packit Service 407539
  Date:   Sat Sep 17 16:47:34 2016 +0000
Packit Service 407539
Packit Service 407539
  Reduce size of ufs inode.
Packit Service 407539
  [...]
Packit Service 407539
*/
Packit Service 407539
		struct ufsmount um;
Packit Service 407539
Packit Service 407539
		if (kvm_read(server->machine->kd, (gulong)inode.i_ump, &um, sizeof um) != sizeof um) {
Packit Service 407539
			glibtop_warn_io_r (server, "kvm_read (ufsmount)");
Packit Service 407539
			return;
Packit Service 407539
		}
Packit Service 407539
Packit Service 407539
		if (kvm_read(server->machine->kd, (gulong)cdev2priv(um.um_dev), &priv, sizeof priv) != sizeof priv) {
Packit Service 407539
			glibtop_warn_io_r (server, "kvm_read (priv)");
Packit Service 407539
			return;
Packit Service 407539
		}
Packit Service 407539
Packit Service 407539
		*dev = priv.cdp_inode;
Packit Service 407539
Packit Service 407539
#else /* older versions */
Packit Service 407539
#if (__FreeBSD_version >= 800039) || (__FreeBSD_kernel_version >= 800039)
Packit Service 407539
        if (kvm_read (server->machine->kd, (gulong) cdev2priv(inode.i_dev), (char *) &priv,
Packit Service 407539
		      sizeof (priv))
Packit Service 407539
#else
Packit Service 407539
        if (kvm_read (server->machine->kd, (gulong) inode.i_dev, (char *) &si,
Packit Service 407539
	              sizeof (si)) != sizeof (si) ||
Packit Service 407539
            kvm_read (server->machine->kd, (gulong) si.si_priv, (char *) &priv,
Packit Service 407539
		      sizeof (priv))
Packit Service 407539
#endif
Packit Service 407539
	    != sizeof (priv))
Packit Service 407539
        {
Packit Service 407539
                glibtop_warn_io_r (server, "kvm_read (priv)");
Packit Service 407539
                return;
Packit Service 407539
        }
Packit Service 407539
Packit Service 407539
        *dev = (guint64) priv.cdp_inode;
Packit Service 407539
#endif /* older versions */
Packit Service 407539
Packit Service 407539
	    } /* end-if IS_UFS */
Packit Service 407539
}
Packit Service 407539
#endif
Packit Service 407539
Packit Service 407539
/* Init function. */
Packit Service 407539
Packit Service 407539
void
Packit Service 407539
_glibtop_init_proc_map_p (glibtop *server)
Packit Service 407539
{
Packit Service 407539
        server->sysdeps.proc_map = _glibtop_sysdeps_proc_map;
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
/* Provides detailed information about a process. */
Packit Service 407539
Packit Service 407539
glibtop_map_entry *
Packit Service 407539
glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf,
Packit Service 407539
                        pid_t pid)
Packit Service 407539
{
Packit Service 407539
        struct kinfo_proc *pinfo;
Packit Service 407539
        struct vm_map_entry entry, *first;
Packit Service 407539
        struct vmspace vmspace;
Packit Service 407539
        struct vm_object object;
Packit Service 407539
        GArray *maps;
Packit Service 407539
        struct vnode vnode;
Packit Service 407539
        int count;
Packit Service 407539
        int update = 0;
Packit Service 407539
Packit Service 407539
        memset (buf, 0, sizeof (glibtop_proc_map));
Packit Service 407539
Packit Service 407539
        /* It does not work for the swapper task. */
Packit Service 407539
        if (pid == 0) return NULL;
Packit Service 407539
Packit Service 407539
        /*return (glibtop_map_entry*) g_array_free(maps, TRUE);*/
Packit Service 407539
Packit Service 407539
        glibtop_suid_enter (server);
Packit Service 407539
Packit Service 407539
        /* Get the process data */
Packit Service 407539
        pinfo = kvm_getprocs (server->machine->kd, KERN_PROC_PID, pid, &count);
Packit Service 407539
        if ((pinfo == NULL) || (count < 1)) {
Packit Service 407539
                glibtop_warn_io_r (server, "kvm_getprocs (%d)", pid);
Packit Service 407539
		glibtop_suid_leave (server);
Packit Service 407539
                return NULL;
Packit Service 407539
        }
Packit Service 407539
Packit Service 407539
        /* Now we get the memory maps. */
Packit Service 407539
Packit Service 407539
        if (kvm_read (server->machine->kd,
Packit Service 407539
                        (gulong) pinfo [0].ki_vmspace,
Packit Service 407539
                        (char *) &vmspace, sizeof (vmspace)) != sizeof (vmspace)) {
Packit Service 407539
                glibtop_warn_io_r (server, "kvm_read (vmspace)");
Packit Service 407539
		glibtop_suid_leave (server);
Packit Service 407539
                return NULL;
Packit Service 407539
        }
Packit Service 407539
Packit Service 407539
        first = vmspace.vm_map.header.next;
Packit Service 407539
Packit Service 407539
        if (kvm_read (server->machine->kd,
Packit Service 407539
                        (gulong) vmspace.vm_map.header.next,
Packit Service 407539
                        (char *) &entry, sizeof (entry)) != sizeof (entry)) {
Packit Service 407539
                glibtop_warn_io_r (server, "kvm_read (entry)");
Packit Service 407539
		glibtop_suid_leave (server);
Packit Service 407539
                return NULL;
Packit Service 407539
        }
Packit Service 407539
Packit Service 407539
        /* Walk through the `vm_map_entry' list ... */
Packit Service 407539
Packit Service 407539
        /* I tested this a few times with `mmap'; as soon as you write
Packit Service 407539
         * to the mmap'ed area, the object type changes from OBJT_VNODE
Packit Service 407539
         * to OBJT_DEFAULT so if seems this really works. */
Packit Service 407539
Packit Service 407539
        maps = g_array_sized_new(FALSE, FALSE, sizeof(glibtop_map_entry),
Packit Service 407539
                                 vmspace.vm_map.nentries);
Packit Service 407539
Packit Service 407539
        do {
Packit Service 407539
                glibtop_map_entry *mentry;
Packit Service 407539
                guint64 inum, dev;
Packit Service 407539
                guint len;
Packit Service 407539
Packit Service 407539
                if (update) {
Packit Service 407539
                        if (kvm_read (server->machine->kd,
Packit Service 407539
                                        (gulong) entry.next,
Packit Service 407539
                                        (char *) &entry, sizeof (entry)) != sizeof (entry)) {
Packit Service 407539
                                glibtop_warn_io_r (server, "kvm_read (entry)");
Packit Service 407539
                                continue;
Packit Service 407539
                        }
Packit Service 407539
                } else {
Packit Service 407539
                        update = 1;
Packit Service 407539
                }
Packit Service 407539
Packit Service 407539
                if (entry.eflags & (MAP_ENTRY_IS_SUB_MAP))
Packit Service 407539
                        continue;
Packit Service 407539
Packit Service 407539
                if (!entry.object.vm_object)
Packit Service 407539
                        continue;
Packit Service 407539
Packit Service 407539
                /* We're only interested in `vm_object's */
Packit Service 407539
Packit Service 407539
                if (kvm_read (server->machine->kd,
Packit Service 407539
                                (gulong) entry.object.vm_object,
Packit Service 407539
                                (char *) &object, sizeof (object)) != sizeof (object)) {
Packit Service 407539
                        glibtop_warn_io_r (server, "kvm_read (object)");
Packit Service 407539
                        continue;
Packit Service 407539
                }
Packit Service 407539
Packit Service 407539
                /* If the object is of type vnode, add its size */
Packit Service 407539
Packit Service 407539
                if (object.type != OBJT_VNODE)
Packit Service 407539
                        continue;
Packit Service 407539
Packit Service 407539
                if (!object.handle)
Packit Service 407539
                        continue;
Packit Service 407539
Packit Service 407539
                if (kvm_read (server->machine->kd,
Packit Service 407539
                                (gulong) object.handle,
Packit Service 407539
                                (char *) &vnode, sizeof (vnode)) != sizeof (vnode)) {
Packit Service 407539
                        glibtop_warn_io_r (server, "kvm_read (vnode)");
Packit Service 407539
                        continue;
Packit Service 407539
                }
Packit Service 407539
Packit Service 407539
                switch (vnode.v_type) {
Packit Service 407539
                case VNON:
Packit Service 407539
                case VBAD:
Packit Service 407539
                        continue;
Packit Service 407539
                default:
Packit Service 407539
#if (__FreeBSD_version < 600006) && !defined(__FreeBSD_kernel__)
Packit Service 407539
                        inum = vnode.v_cachedid;
Packit Service 407539
                        dev = vnode.v_cachedfs;
Packit Service 407539
Packit Service 407539
#else
Packit Service 407539
                        _glibtop_sysdeps_freebsd_dev_inode (server,
Packit Service 407539
					(struct vnode *) object.handle,
Packit Service 407539
					&vnode, &inum, &dev;;
Packit Service 407539
#endif
Packit Service 407539
                        break;
Packit Service 407539
                }
Packit Service 407539
Packit Service 407539
                len = maps->len;
Packit Service 407539
                g_array_set_size(maps, len + 1);
Packit Service 407539
                mentry = &g_array_index(maps, glibtop_map_entry, len);
Packit Service 407539
Packit Service 407539
                memset (mentry, 0, sizeof (glibtop_map_entry));
Packit Service 407539
Packit Service 407539
                mentry->flags  = _glibtop_sysdeps_map_entry;
Packit Service 407539
                mentry->start  = (guint64) entry.start;
Packit Service 407539
                mentry->end    = (guint64) entry.end;
Packit Service 407539
                mentry->offset = (guint64) entry.offset;
Packit Service 407539
                mentry->device = (guint64) dev;
Packit Service 407539
                mentry->inode  = (guint64) inum;
Packit Service 407539
Packit Service 407539
                mentry->perm   = (guint64) 0;
Packit Service 407539
Packit Service 407539
                if (entry.protection & VM_PROT_READ)
Packit Service 407539
                        mentry->perm |= GLIBTOP_MAP_PERM_READ;
Packit Service 407539
                if (entry.protection & VM_PROT_WRITE)
Packit Service 407539
                        mentry->perm |= GLIBTOP_MAP_PERM_WRITE;
Packit Service 407539
                if (entry.protection & VM_PROT_EXECUTE)
Packit Service 407539
                        mentry->perm |= GLIBTOP_MAP_PERM_EXECUTE;
Packit Service 407539
Packit Service 407539
        } while (entry.next != first);
Packit Service 407539
Packit Service 407539
        glibtop_suid_leave (server);
Packit Service 407539
Packit Service 407539
        buf->flags = _glibtop_sysdeps_proc_map;
Packit Service 407539
Packit Service 407539
        buf->number = (guint64) maps->len;
Packit Service 407539
        buf->size   = (guint64) sizeof (glibtop_map_entry);
Packit Service 407539
        buf->total  = (guint64) (buf->number * buf->size);
Packit Service 407539
Packit Service 407539
        return (glibtop_map_entry*) g_array_free(maps, FALSE);
Packit Service 407539
}