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_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 (*)())(uintptr_t) mdb_tgt_notsup, /* t_setcontext */ 361 rf_activate, /* t_activate */ 362 rf_deactivate, /* t_deactivate */ 363 (void (*)())(uintptr_t) 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 (*)())(uintptr_t) mdb_tgt_notsup, /* t_uname */ 369 (int (*)())(uintptr_t) 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 (*)())(uintptr_t) mdb_tgt_notsup, /* t_vtop */ 381 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_lookup_by_name */ 382 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_lookup_by_addr */ 383 (int (*)())(uintptr_t) 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 (*)())(uintptr_t) mdb_tgt_notsup, /* t_run */ 392 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_step */ 393 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_step_out */ 394 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_next */ 395 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_cont */ 396 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_signal */ 397 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_vbrkpt */ 398 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_sbrkpt */ 399 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_pwapt */ 400 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_vwapt */ 401 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_iowapt */ 402 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_sysenter */ 403 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_sysexit */ 404 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_signal */ 405 (int (*)())(uintptr_t) mdb_tgt_null, /* t_add_fault */ 406 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_getareg */ 407 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_putareg */ 408 (int (*)())(uintptr_t) mdb_tgt_notsup, /* t_stack_iter */ 409 (int (*)())(uintptr_t) mdb_tgt_notsup /* t_auxv */ 410 }; 411 412 int 413 mdb_rawfile_tgt_create(mdb_tgt_t *t, int argc, const char *argv[]) 414 { 415 mdb_io_t *io[2] = { NULL, NULL }; 416 rf_data_t *rf; 417 int oflags, i; 418 419 if (argc > 2) 420 return (set_errno(EINVAL)); 421 422 rf = mdb_zalloc(sizeof (rf_data_t), UM_SLEEP); 423 t->t_ops = &rawfile_ops; 424 t->t_data = rf; 425 426 if (t->t_flags & MDB_TGT_F_RDWR) 427 oflags = O_RDWR; 428 else 429 oflags = O_RDONLY; 430 431 for (i = 0; i < argc; i++) { 432 io[i] = mdb_fdio_create_path(NULL, argv[i], oflags, 0); 433 if (io[i] == NULL) { 434 warn("failed to open %s", argv[i]); 435 goto err; 436 } 437 } 438 439 rf->r_object_fio = io[0]; /* first file is the "object" */ 440 rf->r_core_fio = io[1]; /* second file is the "core" */ 441 t->t_flags |= MDB_TGT_F_ASIO; /* do i/o using aread and awrite */ 442 443 return (0); 444 445 err: 446 for (i = 0; i < argc; i++) { 447 if (io[i] != NULL) 448 mdb_io_destroy(io[i]); 449 } 450 451 452 mdb_free(rf, sizeof (rf_data_t)); 453 return (set_errno(EMDB_TGT)); 454 } 455