xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision 68ec2949ad3411aa8a684dfca2cae90cbe202675)
13f6cab07SMatt Macy /*-
23f6cab07SMatt Macy  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
33f6cab07SMatt Macy  *
43f6cab07SMatt Macy  * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
53f6cab07SMatt Macy  *
63f6cab07SMatt Macy  * Redistribution and use in source and binary forms, with or without
73f6cab07SMatt Macy  * modification, are permitted provided that the following conditions
83f6cab07SMatt Macy  * are met:
93f6cab07SMatt Macy  * 1. Redistributions of source code must retain the above copyright
103f6cab07SMatt Macy  *    notice, this list of conditions and the following disclaimer.
113f6cab07SMatt Macy  * 2. Redistributions in binary form must reproduce the above copyright
123f6cab07SMatt Macy  *    notice, this list of conditions and the following disclaimer in the
133f6cab07SMatt Macy  *    documentation and/or other materials provided with the distribution.
143f6cab07SMatt Macy  *
153f6cab07SMatt Macy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163f6cab07SMatt Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173f6cab07SMatt Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183f6cab07SMatt Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193f6cab07SMatt Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203f6cab07SMatt Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213f6cab07SMatt Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223f6cab07SMatt Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233f6cab07SMatt Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243f6cab07SMatt Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253f6cab07SMatt Macy  * SUCH DAMAGE.
263f6cab07SMatt Macy  *
273f6cab07SMatt Macy  */
283f6cab07SMatt Macy 
293f6cab07SMatt Macy #include <sys/cdefs.h>
303f6cab07SMatt Macy __FBSDID("$FreeBSD$");
313f6cab07SMatt Macy 
323f6cab07SMatt Macy #include <sys/param.h>
333f6cab07SMatt Macy #include <sys/systm.h>
343f6cab07SMatt Macy #include <sys/queue.h>
353f6cab07SMatt Macy #include <sys/blist.h>
363f6cab07SMatt Macy #include <sys/conf.h>
373f6cab07SMatt Macy #include <sys/exec.h>
383f6cab07SMatt Macy #include <sys/filedesc.h>
393f6cab07SMatt Macy #include <sys/kernel.h>
403f6cab07SMatt Macy #include <sys/linker.h>
413f6cab07SMatt Macy #include <sys/malloc.h>
423f6cab07SMatt Macy #include <sys/mount.h>
433f6cab07SMatt Macy #include <sys/mutex.h>
443f6cab07SMatt Macy #include <sys/proc.h>
453f6cab07SMatt Macy #include <sys/resourcevar.h>
463f6cab07SMatt Macy #include <sys/sbuf.h>
473f6cab07SMatt Macy #include <sys/smp.h>
483f6cab07SMatt Macy #include <sys/socket.h>
493f6cab07SMatt Macy #include <sys/vnode.h>
503f6cab07SMatt Macy #include <sys/bus.h>
513f6cab07SMatt Macy #include <sys/pciio.h>
523f6cab07SMatt Macy 
533f6cab07SMatt Macy #include <dev/pci/pcivar.h>
543f6cab07SMatt Macy #include <dev/pci/pcireg.h>
553f6cab07SMatt Macy 
563f6cab07SMatt Macy #include <net/if.h>
573f6cab07SMatt Macy 
583f6cab07SMatt Macy #include <vm/vm.h>
593f6cab07SMatt Macy #include <vm/pmap.h>
603f6cab07SMatt Macy #include <vm/vm_map.h>
613f6cab07SMatt Macy #include <vm/vm_param.h>
623f6cab07SMatt Macy #include <vm/vm_object.h>
633f6cab07SMatt Macy #include <vm/swap_pager.h>
643f6cab07SMatt Macy 
653f6cab07SMatt Macy #include <machine/bus.h>
663f6cab07SMatt Macy 
673f6cab07SMatt Macy #include <compat/linux/linux_ioctl.h>
683f6cab07SMatt Macy #include <compat/linux/linux_mib.h>
693f6cab07SMatt Macy #include <compat/linux/linux_util.h>
703f6cab07SMatt Macy #include <fs/pseudofs/pseudofs.h>
713f6cab07SMatt Macy 
723f6cab07SMatt Macy #include <linux/debugfs.h>
733f6cab07SMatt Macy #include <linux/seq_file.h>
743f6cab07SMatt Macy #include <linux/compat.h>
753f6cab07SMatt Macy 
763f6cab07SMatt Macy MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
773f6cab07SMatt Macy 
783f6cab07SMatt Macy static struct pfs_node *debugfs_root;
793f6cab07SMatt Macy 
803f6cab07SMatt Macy #define DM_SYMLINK 0x1
813f6cab07SMatt Macy #define DM_DIR 0x2
823f6cab07SMatt Macy #define DM_FILE 0x3
833f6cab07SMatt Macy 
843f6cab07SMatt Macy struct dentry_meta {
853f6cab07SMatt Macy 	struct dentry dm_dnode;
863f6cab07SMatt Macy 	const struct file_operations *dm_fops;
873f6cab07SMatt Macy 	void *dm_data;
883f6cab07SMatt Macy 	umode_t dm_mode;
893f6cab07SMatt Macy 	int dm_type;
903f6cab07SMatt Macy };
913f6cab07SMatt Macy 
923f6cab07SMatt Macy static int
933f6cab07SMatt Macy debugfs_attr(PFS_ATTR_ARGS)
943f6cab07SMatt Macy {
953f6cab07SMatt Macy 	struct dentry_meta *dm;
963f6cab07SMatt Macy 
973f6cab07SMatt Macy 	dm = pn->pn_data;
983f6cab07SMatt Macy 
993f6cab07SMatt Macy 	vap->va_mode = dm->dm_mode;
1003f6cab07SMatt Macy 	return (0);
1013f6cab07SMatt Macy }
1023f6cab07SMatt Macy 
1033f6cab07SMatt Macy static int
1043f6cab07SMatt Macy debugfs_destroy(PFS_DESTROY_ARGS)
1053f6cab07SMatt Macy {
1063f6cab07SMatt Macy 	struct dentry_meta *dm;
1073f6cab07SMatt Macy 
1083f6cab07SMatt Macy 	dm = pn->pn_data;
1093f6cab07SMatt Macy 	if (dm->dm_type == DM_SYMLINK)
1103f6cab07SMatt Macy 		free(dm->dm_data, M_DFSINT);
1113f6cab07SMatt Macy 
1123f6cab07SMatt Macy 	free(dm, M_DFSINT);
1133f6cab07SMatt Macy 	return (0);
1143f6cab07SMatt Macy }
1153f6cab07SMatt Macy 
1163f6cab07SMatt Macy static int
1173f6cab07SMatt Macy debugfs_fill(PFS_FILL_ARGS)
1183f6cab07SMatt Macy {
1193f6cab07SMatt Macy 	struct dentry_meta *d;
12088a29d89SHans Petter Selasky 	struct linux_file lf = {};
1213f6cab07SMatt Macy 	struct seq_file *sf;
1223f6cab07SMatt Macy 	struct vnode vn;
1233f6cab07SMatt Macy 	void *buf;
1243f6cab07SMatt Macy 	int rc;
1253f6cab07SMatt Macy 	size_t len;
1263f6cab07SMatt Macy 	off_t off;
1273f6cab07SMatt Macy 
1283f6cab07SMatt Macy 	d = pn->pn_data;
1293f6cab07SMatt Macy 
1303f6cab07SMatt Macy 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
1313f6cab07SMatt Macy 		return (rc);
1323f6cab07SMatt Macy 	vn.v_data = d->dm_data;
133867b4decSEmmanuel Vadot 	if (uio->uio_rw == UIO_READ) {
1343f6cab07SMatt Macy 		buf = uio->uio_iov[0].iov_base;
1353f6cab07SMatt Macy 		len = min(uio->uio_iov[0].iov_len, uio->uio_resid);
136867b4decSEmmanuel Vadot 	} else {
137867b4decSEmmanuel Vadot 		sbuf_finish(sb);
138867b4decSEmmanuel Vadot 		buf = sbuf_data(sb);
139867b4decSEmmanuel Vadot 		len = sbuf_len(sb);
140867b4decSEmmanuel Vadot 	}
1413f6cab07SMatt Macy 	off = 0;
1423f6cab07SMatt Macy 	rc = d->dm_fops->open(&vn, &lf);
1433f6cab07SMatt Macy 	if (rc < 0) {
1443f6cab07SMatt Macy #ifdef INVARIANTS
1453f6cab07SMatt Macy 		printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
1463f6cab07SMatt Macy #endif
1473f6cab07SMatt Macy 		return (-rc);
1483f6cab07SMatt Macy 	}
1493f6cab07SMatt Macy 	sf = lf.private_data;
1503f6cab07SMatt Macy 	sf->buf = sb;
15103f1cf9fSJohannes Lundberg 	if (uio->uio_rw == UIO_READ) {
15203f1cf9fSJohannes Lundberg 		if (d->dm_fops->read)
1533f6cab07SMatt Macy 			rc = d->dm_fops->read(&lf, NULL, len, &off);
1543f6cab07SMatt Macy 		else
155*68ec2949SHans Petter Selasky 			rc = -ENODEV;
15603f1cf9fSJohannes Lundberg 	} else {
15703f1cf9fSJohannes Lundberg 		if (d->dm_fops->write)
1583f6cab07SMatt Macy 			rc = d->dm_fops->write(&lf, buf, len, &off);
15903f1cf9fSJohannes Lundberg 		else
160*68ec2949SHans Petter Selasky 			rc = -ENODEV;
16103f1cf9fSJohannes Lundberg 	}
1623f6cab07SMatt Macy 	if (d->dm_fops->release)
1633f6cab07SMatt Macy 		d->dm_fops->release(&vn, &lf);
1643f6cab07SMatt Macy 	else
1653f6cab07SMatt Macy 		single_release(&vn, &lf);
1663f6cab07SMatt Macy 
1673f6cab07SMatt Macy 	if (rc < 0) {
1683f6cab07SMatt Macy #ifdef INVARIANTS
1693f6cab07SMatt Macy 		printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
1703f6cab07SMatt Macy #endif
1713f6cab07SMatt Macy 		return (-rc);
1723f6cab07SMatt Macy 	}
1733f6cab07SMatt Macy 	return (0);
1743f6cab07SMatt Macy }
1753f6cab07SMatt Macy 
1763f6cab07SMatt Macy static int
1773f6cab07SMatt Macy debugfs_fill_data(PFS_FILL_ARGS)
1783f6cab07SMatt Macy {
1793f6cab07SMatt Macy 	struct dentry_meta *dm;
1803f6cab07SMatt Macy 
1813f6cab07SMatt Macy 	dm = pn->pn_data;
1823f6cab07SMatt Macy 	sbuf_printf(sb, "%s", (char *)dm->dm_data);
1833f6cab07SMatt Macy 	return (0);
1843f6cab07SMatt Macy }
1853f6cab07SMatt Macy 
1863f6cab07SMatt Macy struct dentry *
1873f6cab07SMatt Macy debugfs_create_file(const char *name, umode_t mode,
1883f6cab07SMatt Macy 		    struct dentry *parent, void *data,
1893f6cab07SMatt Macy 		    const struct file_operations *fops)
1903f6cab07SMatt Macy {
1913f6cab07SMatt Macy 	struct dentry_meta *dm;
1923f6cab07SMatt Macy 	struct dentry *dnode;
1933f6cab07SMatt Macy 	struct pfs_node *pnode;
1943f6cab07SMatt Macy 	int flags;
1953f6cab07SMatt Macy 
1963f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
1973f6cab07SMatt Macy 	if (dm == NULL)
1983f6cab07SMatt Macy 		return (NULL);
1993f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2003f6cab07SMatt Macy 	dm->dm_fops = fops;
2013f6cab07SMatt Macy 	dm->dm_data = data;
2023f6cab07SMatt Macy 	dm->dm_mode = mode;
2033f6cab07SMatt Macy 	dm->dm_type = DM_FILE;
2043f6cab07SMatt Macy 	if (parent != NULL)
2053f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2063f6cab07SMatt Macy 	else
2073f6cab07SMatt Macy 		pnode = debugfs_root;
2083f6cab07SMatt Macy 
2093f6cab07SMatt Macy 	flags = fops->write ? PFS_RDWR : PFS_RD;
2103f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
2113f6cab07SMatt Macy 	    debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
2123f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2133f6cab07SMatt Macy 		free(dm, M_DFSINT);
2143f6cab07SMatt Macy 		return (NULL);
2153f6cab07SMatt Macy 	}
2163f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2173f6cab07SMatt Macy 
2183f6cab07SMatt Macy 	return (dnode);
2193f6cab07SMatt Macy }
2203f6cab07SMatt Macy 
2213f6cab07SMatt Macy struct dentry *
2223f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2233f6cab07SMatt Macy {
2243f6cab07SMatt Macy 	struct dentry_meta *dm;
2253f6cab07SMatt Macy 	struct dentry *dnode;
2263f6cab07SMatt Macy 	struct pfs_node *pnode;
2273f6cab07SMatt Macy 
2283f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2293f6cab07SMatt Macy 	if (dm == NULL)
2303f6cab07SMatt Macy 		return (NULL);
2313f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2323f6cab07SMatt Macy 	dm->dm_mode = 0700;
2333f6cab07SMatt Macy 	dm->dm_type = DM_DIR;
2343f6cab07SMatt Macy 	if (parent != NULL)
2353f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2363f6cab07SMatt Macy 	else
2373f6cab07SMatt Macy 		pnode = debugfs_root;
2383f6cab07SMatt Macy 
2393f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2403f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2413f6cab07SMatt Macy 		free(dm, M_DFSINT);
2423f6cab07SMatt Macy 		return (NULL);
2433f6cab07SMatt Macy 	}
2443f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2453f6cab07SMatt Macy 	return (dnode);
2463f6cab07SMatt Macy }
2473f6cab07SMatt Macy 
2483f6cab07SMatt Macy struct dentry *
2493f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2503f6cab07SMatt Macy 	const char *dest)
2513f6cab07SMatt Macy {
2523f6cab07SMatt Macy 	struct dentry_meta *dm;
2533f6cab07SMatt Macy 	struct dentry *dnode;
2543f6cab07SMatt Macy 	struct pfs_node *pnode;
2553f6cab07SMatt Macy 	void *data;
2563f6cab07SMatt Macy 
2573f6cab07SMatt Macy 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
2583f6cab07SMatt Macy 	if (data == NULL)
2593f6cab07SMatt Macy 		return (NULL);
2603f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2613f6cab07SMatt Macy 	if (dm == NULL)
2623f6cab07SMatt Macy 		goto fail1;
2633f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2643f6cab07SMatt Macy 	dm->dm_mode = 0700;
2653f6cab07SMatt Macy 	dm->dm_type = DM_SYMLINK;
2663f6cab07SMatt Macy 	dm->dm_data = data;
2673f6cab07SMatt Macy 	if (parent != NULL)
2683f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2693f6cab07SMatt Macy 	else
2703f6cab07SMatt Macy 		pnode = debugfs_root;
2713f6cab07SMatt Macy 
2723f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
2733f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL)
2743f6cab07SMatt Macy 		goto fail;
2753f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2763f6cab07SMatt Macy 	return (dnode);
2773f6cab07SMatt Macy  fail:
2783f6cab07SMatt Macy 	free(dm, M_DFSINT);
2793f6cab07SMatt Macy  fail1:
2803f6cab07SMatt Macy 	free(data, M_DFSINT);
2813f6cab07SMatt Macy 	return (NULL);
2823f6cab07SMatt Macy }
2833f6cab07SMatt Macy 
2843f6cab07SMatt Macy void
2853f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
2863f6cab07SMatt Macy {
2873f6cab07SMatt Macy 	if (dnode == NULL)
2883f6cab07SMatt Macy 		return;
2893f6cab07SMatt Macy 
2903f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
2913f6cab07SMatt Macy }
2923f6cab07SMatt Macy 
2933f6cab07SMatt Macy void
2943f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
2953f6cab07SMatt Macy {
2963f6cab07SMatt Macy 	if (dnode == NULL)
2973f6cab07SMatt Macy 		return;
2983f6cab07SMatt Macy 
2993f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3003f6cab07SMatt Macy }
3013f6cab07SMatt Macy 
3023f6cab07SMatt Macy static int
3033f6cab07SMatt Macy debugfs_init(PFS_INIT_ARGS)
3043f6cab07SMatt Macy {
3053f6cab07SMatt Macy 
3063f6cab07SMatt Macy 	debugfs_root = pi->pi_root;
30746888dedSMark Johnston 
30846888dedSMark Johnston 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
30946888dedSMark Johnston 
3103f6cab07SMatt Macy 	return (0);
3113f6cab07SMatt Macy }
3123f6cab07SMatt Macy 
3133f6cab07SMatt Macy static int
3143f6cab07SMatt Macy debugfs_uninit(PFS_INIT_ARGS)
3153f6cab07SMatt Macy {
3163f6cab07SMatt Macy 	return (0);
3173f6cab07SMatt Macy }
3183f6cab07SMatt Macy 
3193f6cab07SMatt Macy #ifdef PR_ALLOW_MOUNT_LINSYSFS
3203f6cab07SMatt Macy PSEUDOFS(debugfs, 1, PR_ALLOW_MOUNT_LINSYSFS);
3213f6cab07SMatt Macy #else
3223f6cab07SMatt Macy PSEUDOFS(debugfs, 1, VFCF_JAIL);
3233f6cab07SMatt Macy #endif
32403f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
325