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 49typedef 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 57static void 58rf_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 69static int 70rf_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 98static void 99rf_destroy(mdb_tgt_t *t) 100{ 101 rf_data_destroy(t->t_data); 102} 103 104/*ARGSUSED*/ 105static const char * 106rf_name(mdb_tgt_t *t) 107{ 108 return ("raw"); 109} 110 111static ssize_t 112rf_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 128static ssize_t 129rf_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 140static ssize_t 141rf_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 159static ssize_t 160rf_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 178static ssize_t 179rf_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 187static ssize_t 188rf_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 196static ssize_t 197rf_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 205static ssize_t 206rf_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 214static ssize_t 215rf_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 220static ssize_t 221rf_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 227static int 228rf_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 246static int 247rf_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*/ 263static int 264rf_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*/ 277static int 278rf_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 299static const mdb_dcmd_t rf_dcmds[] = { 300 { "status", NULL, "print summary of current target", rf_status_dcmd }, 301 { NULL } 302}; 303 304static 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 313static void 314rf_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 351static void 352rf_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 362static 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 416int 417mdb_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 449err: 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