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