xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c (revision f875b4ebb1dd9fdbeb043557cab38ab3bf7f6e01)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Raw File Target
31  *
32  * The raw file target is invoked whenever a file of unrecognizable type is
33  * specified on the command line, or when raw file examination is forced using
34  * the -f option.  If one file is specified, that file will be opened as the
35  * "object" file.  If two files are specified, the second one will be opened
36  * as the "core" file.  Each file is opened using the fdio backend, which
37  * internally supports both byte-oriented i/o and block-oriented i/o as needed.
38  */
39 
40 #include <mdb/mdb_modapi.h>
41 #include <mdb/mdb_target_impl.h>
42 #include <mdb/mdb_io_impl.h>
43 #include <mdb/mdb_conf.h>
44 #include <mdb/mdb_err.h>
45 #include <mdb/mdb.h>
46 
47 #include <sys/dtrace.h>
48 #include <fcntl.h>
49 
50 typedef struct rf_data {
51 	mdb_io_t *r_object_fio;
52 	mdb_io_t *r_core_fio;
53 } rf_data_t;
54 
55 #define	RF_OBJECT(p)	(((rf_data_t *)(p))->r_object_fio)
56 #define	RF_CORE(p)	(((rf_data_t *)(p))->r_core_fio)
57 
58 static void
59 rf_data_destroy(rf_data_t *rf)
60 {
61 	if (rf->r_object_fio != NULL)
62 		mdb_io_destroy(rf->r_object_fio);
63 
64 	if (rf->r_core_fio != NULL)
65 		mdb_io_destroy(rf->r_core_fio);
66 
67 	mdb_free(rf, sizeof (rf_data_t));
68 }
69 
70 static int
71 rf_setflags(mdb_tgt_t *t, int flags)
72 {
73 	if ((flags ^ t->t_flags) & MDB_TGT_F_RDWR) {
74 		uint_t otflags = t->t_flags;
75 		rf_data_t *orf = t->t_data;
76 		const char *argv[2];
77 		int argc = 0;
78 
79 		if (orf->r_object_fio != NULL)
80 			argv[argc++] = IOP_NAME(orf->r_object_fio);
81 		if (orf->r_core_fio != NULL)
82 			argv[argc++] = IOP_NAME(orf->r_core_fio);
83 
84 		t->t_flags = (t->t_flags & ~MDB_TGT_F_RDWR) |
85 		    (flags & MDB_TGT_F_RDWR);
86 
87 		if (mdb_rawfile_tgt_create(t, argc, argv) == -1) {
88 			t->t_flags = otflags;
89 			t->t_data = orf;
90 			return (-1);
91 		}
92 
93 		rf_data_destroy(orf);
94 	}
95 
96 	return (0);
97 }
98 
99 static void
100 rf_destroy(mdb_tgt_t *t)
101 {
102 	rf_data_destroy(t->t_data);
103 }
104 
105 /*ARGSUSED*/
106 static const char *
107 rf_name(mdb_tgt_t *t)
108 {
109 	return ("raw");
110 }
111 
112 static ssize_t
113 rf_read(mdb_io_t *io, void *buf, size_t nbytes, uint64_t addr)
114 {
115 	ssize_t rbytes;
116 
117 	if (io == NULL)
118 		return (set_errno(EMDB_NOMAP));
119 
120 	if (IOP_SEEK(io, addr, SEEK_SET) == -1)
121 		return (-1); /* errno is set for us */
122 
123 	if ((rbytes = IOP_READ(io, buf, nbytes)) == 0)
124 		(void) set_errno(EMDB_EOF);
125 
126 	return (rbytes);
127 }
128 
129 static ssize_t
130 rf_write(mdb_io_t *io, const void *buf, size_t nbytes, uint64_t addr)
131 {
132 	if (io == NULL)
133 		return (set_errno(EMDB_NOMAP));
134 
135 	if (IOP_SEEK(io, addr, SEEK_SET) == -1)
136 		return (-1); /* errno is set for us */
137 
138 	return (IOP_WRITE(io, buf, nbytes));
139 }
140 
141 static ssize_t
142 rf_aread(mdb_tgt_t *t, mdb_tgt_as_t as, void *buf,
143     size_t len, mdb_tgt_addr_t addr)
144 {
145 	switch ((uintptr_t)as) {
146 	case (uintptr_t)MDB_TGT_AS_VIRT:
147 	case (uintptr_t)MDB_TGT_AS_PHYS:
148 		if (RF_CORE(t->t_data) != NULL)
149 			return (rf_read(RF_CORE(t->t_data), buf, len, addr));
150 		/*FALLTHRU*/
151 	case (uintptr_t)MDB_TGT_AS_FILE:
152 		return (rf_read(RF_OBJECT(t->t_data), buf, len, addr));
153 	default:
154 		return (set_errno(EMDB_NOMAP));
155 	}
156 }
157 
158 static ssize_t
159 rf_awrite(mdb_tgt_t *t, mdb_tgt_as_t as, const void *buf,
160     size_t len, mdb_tgt_addr_t addr)
161 {
162 	switch ((uintptr_t)as) {
163 	case (uintptr_t)MDB_TGT_AS_VIRT:
164 	case (uintptr_t)MDB_TGT_AS_PHYS:
165 		if (RF_CORE(t->t_data) != NULL)
166 			return (rf_write(RF_CORE(t->t_data), buf, len, addr));
167 		/*FALLTHRU*/
168 	case (uintptr_t)MDB_TGT_AS_FILE:
169 		return (rf_write(RF_OBJECT(t->t_data), buf, len, addr));
170 	default:
171 		return (set_errno(EMDB_NOMAP));
172 	}
173 }
174 
175 static ssize_t
176 rf_vread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
177 {
178 	if (RF_CORE(t->t_data) != NULL)
179 		return (rf_read(RF_CORE(t->t_data), buf, nbytes, addr));
180 
181 	return (rf_read(RF_OBJECT(t->t_data), buf, nbytes, addr));
182 }
183 
184 static ssize_t
185 rf_vwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
186 {
187 	if (RF_CORE(t->t_data) != NULL)
188 		return (rf_write(RF_CORE(t->t_data), buf, nbytes, addr));
189 
190 	return (rf_write(RF_OBJECT(t->t_data), buf, nbytes, addr));
191 }
192 
193 static ssize_t
194 rf_pread(mdb_tgt_t *t, void *buf, size_t nbytes, physaddr_t addr)
195 {
196 	if (RF_CORE(t->t_data) != NULL)
197 		return (rf_read(RF_CORE(t->t_data), buf, nbytes, addr));
198 
199 	return (rf_read(RF_OBJECT(t->t_data), buf, nbytes, addr));
200 }
201 
202 static ssize_t
203 rf_pwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, physaddr_t addr)
204 {
205 	if (RF_CORE(t->t_data) != NULL)
206 		return (rf_write(RF_CORE(t->t_data), buf, nbytes, addr));
207 
208 	return (rf_write(RF_OBJECT(t->t_data), buf, nbytes, addr));
209 }
210 
211 static ssize_t
212 rf_fread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
213 {
214 	return (rf_read(RF_OBJECT(t->t_data), buf, nbytes, addr));
215 }
216 
217 static ssize_t
218 rf_fwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
219 {
220 	return (rf_write(RF_OBJECT(t->t_data), buf, nbytes, addr));
221 }
222 
223 
224 static int
225 rf_print_map(mdb_io_t *io, const char *type, int tflags,
226     mdb_tgt_map_f *func, void *private)
227 {
228 	mdb_map_t map;
229 
230 	(void) mdb_iob_snprintf(map.map_name, MDB_TGT_MAPSZ,
231 	    "%s (%s)", IOP_NAME(io), type);
232 
233 	map.map_base = 0;
234 	map.map_size = IOP_SEEK(io, 0, SEEK_END);
235 	map.map_flags = MDB_TGT_MAP_R;
236 
237 	if (tflags & MDB_TGT_F_RDWR)
238 		map.map_flags |= MDB_TGT_MAP_W;
239 
240 	return (func(private, &map, map.map_name));
241 }
242 
243 static int
244 rf_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private)
245 {
246 	rf_data_t *rf = t->t_data;
247 
248 	if (rf->r_object_fio != NULL && rf_print_map(rf->r_object_fio,
249 	    "object file", t->t_flags, func, private) != 0)
250 		return (0);
251 
252 	if (rf->r_core_fio != NULL && rf_print_map(rf->r_core_fio,
253 	    "core file", t->t_flags, func, private) != 0)
254 		return (0);
255 
256 	return (0);
257 }
258 
259 /*ARGSUSED*/
260 static int
261 rf_status(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
262 {
263 	bzero(tsp, sizeof (mdb_tgt_status_t));
264 
265 	if (RF_CORE(t->t_data) != NULL)
266 		tsp->st_state = MDB_TGT_DEAD;
267 	else
268 		tsp->st_state = MDB_TGT_IDLE;
269 
270 	return (0);
271 }
272 
273 /*ARGSUSED*/
274 static int
275 rf_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
276 {
277 	rf_data_t *rf = mdb.m_target->t_data;
278 
279 	if (rf->r_object_fio != NULL) {
280 		mdb_printf("debugging file '%s' (object file)",
281 		    IOP_NAME(rf->r_object_fio));
282 
283 		if (rf->r_core_fio != NULL) {
284 			mdb_printf(" and file '%s' (core file)",
285 			    IOP_NAME(rf->r_core_fio));
286 		}
287 
288 		mdb_printf("\n");
289 	} else {
290 		mdb_printf("debugging empty target\n");
291 	}
292 
293 	return (DCMD_OK);
294 }
295 
296 static const mdb_dcmd_t rf_dcmds[] = {
297 	{ "status", NULL, "print summary of current target", rf_status_dcmd },
298 	{ NULL }
299 };
300 
301 static const struct rf_magic {
302 	const char *rfm_str;
303 	size_t rfm_len;
304 	const char *rfm_mod;
305 } rf_magic[] = {
306 	{ DOF_MAG_STRING, DOF_MAG_STRLEN, "dof" },
307 	{ NULL, 0, NULL }
308 };
309 
310 static void
311 rf_activate(mdb_tgt_t *t)
312 {
313 	rf_data_t *rf = t->t_data;
314 	const struct rf_magic *m;
315 	mdb_var_t *v;
316 	off64_t size;
317 
318 	(void) mdb_tgt_register_dcmds(t, &rf_dcmds[0], MDB_MOD_FORCE);
319 
320 	/*
321 	 * We set the legacy adb variable 'd' to be the size of the file (data
322 	 * segment).  To get this value, we call seek() on the underlying fdio.
323 	 */
324 	if (rf->r_object_fio != NULL) {
325 		size = IOP_SEEK(rf->r_object_fio, 0, SEEK_END);
326 		if ((v = mdb_nv_lookup(&mdb.m_nv, "d")) != NULL)
327 			mdb_nv_set_value(v, size);
328 	}
329 
330 	/*
331 	 * Load any debugging support modules that match the file type, as
332 	 * determined by our poor man's /etc/magic.  If many clients need
333 	 * to use this feature, rf_magic[] should be computed dynamically.
334 	 */
335 	for (m = rf_magic; m->rfm_str != NULL; m++) {
336 		char *buf = mdb_alloc(m->rfm_len, UM_SLEEP);
337 
338 		if (mdb_tgt_vread(t, buf, m->rfm_len, 0) == m->rfm_len &&
339 		    bcmp(buf, m->rfm_str, m->rfm_len) == 0) {
340 			(void) mdb_module_load(m->rfm_mod,
341 			    MDB_MOD_LOCAL | MDB_MOD_SILENT);
342 		}
343 
344 		mdb_free(buf, m->rfm_len);
345 	}
346 }
347 
348 static void
349 rf_deactivate(mdb_tgt_t *t)
350 {
351 	const mdb_dcmd_t *dcp;
352 
353 	for (dcp = &rf_dcmds[0]; dcp->dc_name != NULL; dcp++) {
354 		if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1)
355 			warn("failed to remove dcmd %s", dcp->dc_name);
356 	}
357 }
358 
359 static const mdb_tgt_ops_t rawfile_ops = {
360 	rf_setflags,				/* t_setflags */
361 	(int (*)()) mdb_tgt_notsup,		/* t_setcontext */
362 	rf_activate,				/* t_activate */
363 	rf_deactivate,				/* t_deactivate */
364 	(void (*)()) mdb_tgt_nop,		/* t_periodic */
365 	rf_destroy,				/* t_destroy */
366 	rf_name,				/* t_name */
367 	(const char *(*)()) mdb_conf_isa,	/* t_isa */
368 	(const char *(*)()) mdb_conf_platform,	/* t_platform */
369 	(int (*)()) mdb_tgt_notsup,		/* t_uname */
370 	(int (*)()) mdb_tgt_notsup,		/* t_dmodel */
371 	rf_aread,				/* t_aread */
372 	rf_awrite,				/* t_awrite */
373 	rf_vread,				/* t_vread */
374 	rf_vwrite,				/* t_vwrite */
375 	rf_pread,				/* t_pread */
376 	rf_pwrite,				/* t_pwrite */
377 	rf_fread,				/* t_fread */
378 	rf_fwrite,				/* t_fwrite */
379 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_ioread */
380 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_iowrite */
381 	(int (*)()) mdb_tgt_notsup,		/* t_vtop */
382 	(int (*)()) mdb_tgt_notsup,		/* t_lookup_by_name */
383 	(int (*)()) mdb_tgt_notsup,		/* t_lookup_by_addr */
384 	(int (*)()) mdb_tgt_notsup,		/* t_symbol_iter */
385 	rf_mapping_iter,			/* t_mapping_iter */
386 	rf_mapping_iter,			/* t_object_iter */
387 	(const mdb_map_t *(*)()) mdb_tgt_null,	/* t_addr_to_map */
388 	(const mdb_map_t *(*)()) mdb_tgt_null,	/* t_name_to_map */
389 	(struct ctf_file *(*)()) mdb_tgt_null,	/* t_addr_to_ctf */
390 	(struct ctf_file *(*)()) mdb_tgt_null,	/* t_name_to_ctf */
391 	rf_status,				/* t_status */
392 	(int (*)()) mdb_tgt_notsup,		/* t_run */
393 	(int (*)()) mdb_tgt_notsup,		/* t_step */
394 	(int (*)()) mdb_tgt_notsup,		/* t_step_out */
395 	(int (*)()) mdb_tgt_notsup,		/* t_step_branch */
396 	(int (*)()) mdb_tgt_notsup,		/* t_next */
397 	(int (*)()) mdb_tgt_notsup,		/* t_cont */
398 	(int (*)()) mdb_tgt_notsup,		/* t_signal */
399 	(int (*)()) mdb_tgt_null,		/* t_add_vbrkpt */
400 	(int (*)()) mdb_tgt_null,		/* t_add_sbrkpt */
401 	(int (*)()) mdb_tgt_null,		/* t_add_pwapt */
402 	(int (*)()) mdb_tgt_null,		/* t_add_vwapt */
403 	(int (*)()) mdb_tgt_null,		/* t_add_iowapt */
404 	(int (*)()) mdb_tgt_null,		/* t_add_sysenter */
405 	(int (*)()) mdb_tgt_null,		/* t_add_sysexit */
406 	(int (*)()) mdb_tgt_null,		/* t_add_signal */
407 	(int (*)()) mdb_tgt_null,		/* t_add_fault */
408 	(int (*)()) mdb_tgt_notsup,		/* t_getareg */
409 	(int (*)()) mdb_tgt_notsup,		/* t_putareg */
410 	(int (*)()) mdb_tgt_notsup,		/* t_stack_iter */
411 };
412 
413 int
414 mdb_rawfile_tgt_create(mdb_tgt_t *t, int argc, const char *argv[])
415 {
416 	mdb_io_t *io[2] = { NULL, NULL };
417 	rf_data_t *rf;
418 	int oflags, i;
419 
420 	if (argc > 2)
421 		return (set_errno(EINVAL));
422 
423 	rf = mdb_zalloc(sizeof (rf_data_t), UM_SLEEP);
424 	t->t_ops = &rawfile_ops;
425 	t->t_data = rf;
426 
427 	if (t->t_flags & MDB_TGT_F_RDWR)
428 		oflags = O_RDWR;
429 	else
430 		oflags = O_RDONLY;
431 
432 	for (i = 0; i < argc; i++) {
433 		io[i] = mdb_fdio_create_path(NULL, argv[i], oflags, 0);
434 		if (io[i] == NULL) {
435 			warn("failed to open %s", argv[i]);
436 			goto err;
437 		}
438 	}
439 
440 	rf->r_object_fio = io[0];	/* first file is the "object" */
441 	rf->r_core_fio = io[1];		/* second file is the "core" */
442 	t->t_flags |= MDB_TGT_F_ASIO;	/* do i/o using aread and awrite */
443 
444 	return (0);
445 
446 err:
447 	for (i = 0; i < argc; i++) {
448 		if (io[i] != NULL)
449 			mdb_io_destroy(io[i]);
450 	}
451 
452 
453 	mdb_free(rf, sizeof (rf_data_t));
454 	return (set_errno(EMDB_TGT));
455 }
456