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 * Copyright 2018 Joyent, Inc. 26 */ 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_VIRT_I: 147 case (uintptr_t)MDB_TGT_AS_VIRT_S: 148 case (uintptr_t)MDB_TGT_AS_PHYS: 149 if (RF_CORE(t->t_data) != NULL) 150 return (rf_read(RF_CORE(t->t_data), buf, len, addr)); 151 /*FALLTHRU*/ 152 case (uintptr_t)MDB_TGT_AS_FILE: 153 return (rf_read(RF_OBJECT(t->t_data), buf, len, addr)); 154 default: 155 return (set_errno(EMDB_NOMAP)); 156 } 157 } 158 159 static ssize_t 160 rf_awrite(mdb_tgt_t *t, mdb_tgt_as_t as, const void *buf, 161 size_t len, mdb_tgt_addr_t addr) 162 { 163 switch ((uintptr_t)as) { 164 case (uintptr_t)MDB_TGT_AS_VIRT: 165 case (uintptr_t)MDB_TGT_AS_VIRT_I: 166 case (uintptr_t)MDB_TGT_AS_VIRT_S: 167 case (uintptr_t)MDB_TGT_AS_PHYS: 168 if (RF_CORE(t->t_data) != NULL) 169 return (rf_write(RF_CORE(t->t_data), buf, len, addr)); 170 /*FALLTHRU*/ 171 case (uintptr_t)MDB_TGT_AS_FILE: 172 return (rf_write(RF_OBJECT(t->t_data), buf, len, addr)); 173 default: 174 return (set_errno(EMDB_NOMAP)); 175 } 176 } 177 178 static ssize_t 179 rf_vread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 180 { 181 if (RF_CORE(t->t_data) != NULL) 182 return (rf_read(RF_CORE(t->t_data), buf, nbytes, addr)); 183 184 return (rf_read(RF_OBJECT(t->t_data), buf, nbytes, addr)); 185 } 186 187 static ssize_t 188 rf_vwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 189 { 190 if (RF_CORE(t->t_data) != NULL) 191 return (rf_write(RF_CORE(t->t_data), buf, nbytes, addr)); 192 193 return (rf_write(RF_OBJECT(t->t_data), buf, nbytes, addr)); 194 } 195 196 static ssize_t 197 rf_pread(mdb_tgt_t *t, void *buf, size_t nbytes, physaddr_t addr) 198 { 199 if (RF_CORE(t->t_data) != NULL) 200 return (rf_read(RF_CORE(t->t_data), buf, nbytes, addr)); 201 202 return (rf_read(RF_OBJECT(t->t_data), buf, nbytes, addr)); 203 } 204 205 static ssize_t 206 rf_pwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, physaddr_t addr) 207 { 208 if (RF_CORE(t->t_data) != NULL) 209 return (rf_write(RF_CORE(t->t_data), buf, nbytes, addr)); 210 211 return (rf_write(RF_OBJECT(t->t_data), buf, nbytes, addr)); 212 } 213 214 static ssize_t 215 rf_fread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 216 { 217 return (rf_read(RF_OBJECT(t->t_data), buf, nbytes, addr)); 218 } 219 220 static ssize_t 221 rf_fwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 222 { 223 return (rf_write(RF_OBJECT(t->t_data), buf, nbytes, addr)); 224 } 225 226 227 static int 228 rf_print_map(mdb_io_t *io, const char *type, int tflags, 229 mdb_tgt_map_f *func, void *private) 230 { 231 mdb_map_t map; 232 233 (void) mdb_iob_snprintf(map.map_name, MDB_TGT_MAPSZ, 234 "%s (%s)", IOP_NAME(io), type); 235 236 map.map_base = 0; 237 map.map_size = IOP_SEEK(io, 0, SEEK_END); 238 map.map_flags = MDB_TGT_MAP_R; 239 240 if (tflags & MDB_TGT_F_RDWR) 241 map.map_flags |= MDB_TGT_MAP_W; 242 243 return (func(private, &map, map.map_name)); 244 } 245 246 static int 247 rf_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private) 248 { 249 rf_data_t *rf = t->t_data; 250 251 if (rf->r_object_fio != NULL && rf_print_map(rf->r_object_fio, 252 "object file", t->t_flags, func, private) != 0) 253 return (0); 254 255 if (rf->r_core_fio != NULL && rf_print_map(rf->r_core_fio, 256 "core file", t->t_flags, func, private) != 0) 257 return (0); 258 259 return (0); 260 } 261 262 /*ARGSUSED*/ 263 static int 264 rf_status(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 265 { 266 bzero(tsp, sizeof (mdb_tgt_status_t)); 267 268 if (RF_CORE(t->t_data) != NULL) 269 tsp->st_state = MDB_TGT_DEAD; 270 else 271 tsp->st_state = MDB_TGT_IDLE; 272 273 return (0); 274 } 275 276 /*ARGSUSED*/ 277 static int 278 rf_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 279 { 280 rf_data_t *rf = mdb.m_target->t_data; 281 282 if (rf->r_object_fio != NULL) { 283 mdb_printf("debugging file '%s' (object file)", 284 IOP_NAME(rf->r_object_fio)); 285 286 if (rf->r_core_fio != NULL) { 287 mdb_printf(" and file '%s' (core file)", 288 IOP_NAME(rf->r_core_fio)); 289 } 290 291 mdb_printf("\n"); 292 } else { 293 mdb_printf("debugging empty target\n"); 294 } 295 296 return (DCMD_OK); 297 } 298 299 static const mdb_dcmd_t rf_dcmds[] = { 300 { "status", NULL, "print summary of current target", rf_status_dcmd }, 301 { NULL } 302 }; 303 304 static const struct rf_magic { 305 const char *rfm_str; 306 size_t rfm_len; 307 const char *rfm_mod; 308 } rf_magic[] = { 309 { DOF_MAG_STRING, DOF_MAG_STRLEN, "dof" }, 310 { NULL, 0, NULL } 311 }; 312 313 static void 314 rf_activate(mdb_tgt_t *t) 315 { 316 rf_data_t *rf = t->t_data; 317 const struct rf_magic *m; 318 mdb_var_t *v; 319 off64_t size; 320 321 (void) mdb_tgt_register_dcmds(t, &rf_dcmds[0], MDB_MOD_FORCE); 322 323 /* 324 * We set the legacy adb variable 'd' to be the size of the file (data 325 * segment). To get this value, we call seek() on the underlying fdio. 326 */ 327 if (rf->r_object_fio != NULL) { 328 size = IOP_SEEK(rf->r_object_fio, 0, SEEK_END); 329 if ((v = mdb_nv_lookup(&mdb.m_nv, "d")) != NULL) 330 mdb_nv_set_value(v, size); 331 } 332 333 /* 334 * Load any debugging support modules that match the file type, as 335 * determined by our poor man's /etc/magic. If many clients need 336 * to use this feature, rf_magic[] should be computed dynamically. 337 */ 338 for (m = rf_magic; m->rfm_str != NULL; m++) { 339 char *buf = mdb_alloc(m->rfm_len, UM_SLEEP); 340 341 if (mdb_tgt_vread(t, buf, m->rfm_len, 0) == m->rfm_len && 342 bcmp(buf, m->rfm_str, m->rfm_len) == 0) { 343 (void) mdb_module_load(m->rfm_mod, 344 MDB_MOD_LOCAL | MDB_MOD_SILENT); 345 } 346 347 mdb_free(buf, m->rfm_len); 348 } 349 } 350 351 static void 352 rf_deactivate(mdb_tgt_t *t) 353 { 354 const mdb_dcmd_t *dcp; 355 356 for (dcp = &rf_dcmds[0]; dcp->dc_name != NULL; dcp++) { 357 if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1) 358 warn("failed to remove dcmd %s", dcp->dc_name); 359 } 360 } 361 362 static const mdb_tgt_ops_t rawfile_ops = { 363 rf_setflags, /* t_setflags */ 364 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_setcontext */ 365 rf_activate, /* t_activate */ 366 rf_deactivate, /* t_deactivate */ 367 (void (*)())(uintptr_t) mdb_tgt_nop, /* t_periodic */ 368 rf_destroy, /* t_destroy */ 369 rf_name, /* t_name */ 370 (const char *(*)()) mdb_conf_isa, /* t_isa */ 371 (const char *(*)()) mdb_conf_platform, /* t_platform */ 372 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_uname */ 373 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_dmodel */ 374 rf_aread, /* t_aread */ 375 rf_awrite, /* t_awrite */ 376 rf_vread, /* t_vread */ 377 rf_vwrite, /* t_vwrite */ 378 rf_pread, /* t_pread */ 379 rf_pwrite, /* t_pwrite */ 380 rf_fread, /* t_fread */ 381 rf_fwrite, /* t_fwrite */ 382 (ssize_t (*)()) mdb_tgt_notsup, /* t_ioread */ 383 (ssize_t (*)()) mdb_tgt_notsup, /* t_iowrite */ 384 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_vtop */ 385 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_lookup_by_name */ 386 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_lookup_by_addr */ 387 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_symbol_iter */ 388 rf_mapping_iter, /* t_mapping_iter */ 389 rf_mapping_iter, /* t_object_iter */ 390 (const mdb_map_t *(*)()) mdb_tgt_null, /* t_addr_to_map */ 391 (const mdb_map_t *(*)()) mdb_tgt_null, /* t_name_to_map */ 392 (struct ctf_file *(*)()) mdb_tgt_null, /* t_addr_to_ctf */ 393 (struct ctf_file *(*)()) mdb_tgt_null, /* t_name_to_ctf */ 394 rf_status, /* t_status */ 395 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_run */ 396 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_step */ 397 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_step_out */ 398 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_next */ 399 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_cont */ 400 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_signal */ 401 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_vbrkpt */ 402 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_sbrkpt */ 403 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_pwapt */ 404 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_vwapt */ 405 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_iowapt */ 406 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_sysenter */ 407 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_sysexit */ 408 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_signal */ 409 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_fault */ 410 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_getareg */ 411 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_putareg */ 412 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_stack_iter */ 413 (int (*)())(uintptr_t) mdb_tgt_notsup /* t_auxv */ 414 }; 415 416 int 417 mdb_rawfile_tgt_create(mdb_tgt_t *t, int argc, const char *argv[]) 418 { 419 mdb_io_t *io[2] = { NULL, NULL }; 420 rf_data_t *rf; 421 int oflags, i; 422 423 if (argc > 2) 424 return (set_errno(EINVAL)); 425 426 rf = mdb_zalloc(sizeof (rf_data_t), UM_SLEEP); 427 t->t_ops = &rawfile_ops; 428 t->t_data = rf; 429 430 if (t->t_flags & MDB_TGT_F_RDWR) 431 oflags = O_RDWR; 432 else 433 oflags = O_RDONLY; 434 435 for (i = 0; i < argc; i++) { 436 io[i] = mdb_fdio_create_path(NULL, argv[i], oflags, 0); 437 if (io[i] == NULL) { 438 warn("failed to open %s", argv[i]); 439 goto err; 440 } 441 } 442 443 rf->r_object_fio = io[0]; /* first file is the "object" */ 444 rf->r_core_fio = io[1]; /* second file is the "core" */ 445 t->t_flags |= MDB_TGT_F_ASIO; /* do i/o using aread and awrite */ 446 447 return (0); 448 449 err: 450 for (i = 0; i < argc; i++) { 451 if (io[i] != NULL) 452 mdb_io_destroy(io[i]); 453 } 454 455 456 mdb_free(rf, sizeof (rf_data_t)); 457 return (set_errno(EMDB_TGT)); 458 } 459