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