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