xref: /illumos-gate/usr/src/cmd/mdb/intel/modules/smbios/smbios.c (revision 379728489ed47862c4927c75771e767b9476c9c4)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2020 Oxide Computer Company
14  */
15 
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <sys/mdb_modapi.h>
21 #include <sys/smbios_impl.h>
22 #include <unistd.h>
23 
24 /*
25  * Unfortunately, we're in a bit of a bind. Because of the situation we're in,
26  * we cannot use string.h directly as it declares ffs() which is also declared
27  * in sys/systm.h. sys/systm.h is being pulled in because mdb is building with
28  * _KERNEL. Therefore we have to manually declare an extern delaration for
29  * strerror().
30  */
31 extern char *strerror(int);
32 
33 /*
34  * Take an existing smbios_hdl_t from a dump and slurp out its memory so we can
35  * open up a new smbios handle to perform operations on.
36  */
37 static int
38 smbios_mdb_write(const char *path, uintptr_t addr)
39 {
40 	smbios_hdl_t shp, *hdl;
41 	void *buf;
42 	int err, fd = -1;
43 	int ret = DCMD_ERR;
44 
45 	if (mdb_vread(&shp, sizeof (shp), addr) != sizeof (shp)) {
46 		mdb_warn("failed to read smbios_hdl_t at %p", addr);
47 		return (DCMD_ERR);
48 	}
49 
50 	buf = mdb_alloc(shp.sh_buflen, UM_NOSLEEP | UM_GC);
51 	if (buf == NULL) {
52 		mdb_warn("failed to allocate %zu bytes for the smbios "
53 		    "data buffer", shp.sh_buflen);
54 		return (DCMD_ERR);
55 	}
56 
57 	if (mdb_vread(buf, shp.sh_buflen, (uintptr_t)shp.sh_buf) !=
58 	    shp.sh_buflen) {
59 		mdb_warn("failed to copy smbios data at %p", shp.sh_buf);
60 		return (DCMD_ERR);
61 	}
62 
63 	hdl = smbios_bufopen(&shp.sh_ent, buf, shp.sh_buflen, SMB_VERSION, 0,
64 	    &err);
65 	if (hdl == NULL) {
66 		mdb_warn("failed to load smbios data: %s\n",
67 		    smbios_errmsg(err));
68 		return (DCMD_ERR);
69 	}
70 
71 	if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
72 		mdb_warn("failed to open output file %s: %s\n", path,
73 		    strerror(errno));
74 		goto out;
75 	}
76 
77 	if (smbios_write(hdl, fd) != 0) {
78 		mdb_warn("failed to write smbios data to %s: %s\n", path,
79 		    smbios_errmsg(smbios_errno(hdl)));
80 		ret = DCMD_ERR;
81 	} else {
82 		ret = DCMD_OK;
83 	}
84 out:
85 	if (fd != -1) {
86 		(void) close(fd);
87 	}
88 	smbios_close(hdl);
89 	return (ret);
90 }
91 
92 static int
93 smbios_mdb_smbios(uintptr_t addr, uint_t flags, int argc,
94     const mdb_arg_t *argv)
95 {
96 	const char *wpath = NULL;
97 
98 	if (!(flags & DCMD_ADDRSPEC)) {
99 		mdb_warn("missing required smbios_hdl_t\n");
100 		return (DCMD_USAGE);
101 	}
102 
103 	if (mdb_getopts(argc, argv, 'w', MDB_OPT_STR, &wpath, NULL) != argc) {
104 		return (DCMD_USAGE);
105 	}
106 
107 	if (wpath != NULL) {
108 		return (smbios_mdb_write(wpath, addr));
109 	}
110 
111 	return (DCMD_USAGE);
112 }
113 
114 static void
115 smbios_mdb_help(void)
116 {
117 	mdb_printf("Given a pointer to an smbios_hdl_t take the following "
118 	    "actions:\n\n"
119 	    "\t-w path\t\tWrite SMBIOS data out to path\n");
120 }
121 
122 static const mdb_dcmd_t smbios_dcmds[] = {
123 	{ "smbios", ":[-w path]", "Manipulate an smbios handle",
124 	    smbios_mdb_smbios, smbios_mdb_help },
125 	{ NULL }
126 };
127 
128 static const mdb_modinfo_t smbios_modinfo = {
129 	MDB_API_VERSION, smbios_dcmds, NULL
130 };
131 
132 const mdb_modinfo_t *
133 _mdb_init(void)
134 {
135 	return (&smbios_modinfo);
136 }
137