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 (*)()) mdb_tgt_notsup,             /* t_setcontext */
 361         rf_activate,                            /* t_activate */
 362         rf_deactivate,                          /* t_deactivate */
 363         (void (*)()) 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 (*)()) mdb_tgt_notsup,             /* t_uname */
 369         (int (*)()) 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 (*)()) mdb_tgt_notsup,             /* t_vtop */
 381         (int (*)()) mdb_tgt_notsup,             /* t_lookup_by_name */
 382         (int (*)()) mdb_tgt_notsup,             /* t_lookup_by_addr */
 383         (int (*)()) 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 (*)()) mdb_tgt_notsup,             /* t_run */
 392         (int (*)()) mdb_tgt_notsup,             /* t_step */
 393         (int (*)()) mdb_tgt_notsup,             /* t_step_out */
 394         (int (*)()) mdb_tgt_notsup,             /* t_next */
 395         (int (*)()) mdb_tgt_notsup,             /* t_cont */
 396         (int (*)()) mdb_tgt_notsup,             /* t_signal */
 397         (int (*)()) mdb_tgt_null,               /* t_add_vbrkpt */
 398         (int (*)()) mdb_tgt_null,               /* t_add_sbrkpt */
 399         (int (*)()) mdb_tgt_null,               /* t_add_pwapt */
 400         (int (*)()) mdb_tgt_null,               /* t_add_vwapt */
 401         (int (*)()) mdb_tgt_null,               /* t_add_iowapt */
 402         (int (*)()) mdb_tgt_null,               /* t_add_sysenter */
 403         (int (*)()) mdb_tgt_null,               /* t_add_sysexit */
 404         (int (*)()) mdb_tgt_null,               /* t_add_signal */
 405         (int (*)()) mdb_tgt_null,               /* t_add_fault */
 406         (int (*)()) mdb_tgt_notsup,             /* t_getareg */
 407         (int (*)()) mdb_tgt_notsup,             /* t_putareg */
 408         (int (*)()) mdb_tgt_notsup,             /* t_stack_iter */
 409         (int (*)()) 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 }