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 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2011 by Delphix. All rights reserved.
  25  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
  26  */
  27 
  28 #include <unistd.h>
  29 #include <strings.h>
  30 #include <stdlib.h>
  31 #include <errno.h>
  32 #include <assert.h>
  33 #include <ctype.h>
  34 #include <alloca.h>
  35 
  36 #include <dt_impl.h>
  37 #include <dt_program.h>
  38 #include <dt_printf.h>
  39 #include <dt_provider.h>
  40 
  41 dtrace_prog_t *
  42 dt_program_create(dtrace_hdl_t *dtp)
  43 {
  44         dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
  45 
  46         if (pgp != NULL) {
  47                 dt_list_append(&dtp->dt_programs, pgp);
  48         } else {
  49                 (void) dt_set_errno(dtp, EDT_NOMEM);
  50                 return (NULL);
  51         }
  52 
  53         /*
  54          * By default, programs start with DOF version 1 so that output files
  55          * containing DOF are backward compatible. If a program requires new
  56          * DOF features, the version is increased as needed.
  57          */
  58         pgp->dp_dofversion = DOF_VERSION_1;
  59 
  60         return (pgp);
  61 }
  62 
  63 void
  64 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
  65 {
  66         dt_stmt_t *stp, *next;
  67         uint_t i;
  68 
  69         for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
  70                 next = dt_list_next(stp);
  71                 dtrace_stmt_destroy(dtp, stp->ds_desc);
  72                 dt_free(dtp, stp);
  73         }
  74 
  75         for (i = 0; i < pgp->dp_xrefslen; i++)
  76                 dt_free(dtp, pgp->dp_xrefs[i]);
  77 
  78         dt_free(dtp, pgp->dp_xrefs);
  79         dt_list_delete(&dtp->dt_programs, pgp);
  80         dt_free(dtp, pgp);
  81 }
  82 
  83 /*ARGSUSED*/
  84 void
  85 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
  86     dtrace_proginfo_t *pip)
  87 {
  88         dt_stmt_t *stp;
  89         dtrace_actdesc_t *ap;
  90         dtrace_ecbdesc_t *last = NULL;
  91 
  92         if (pip == NULL)
  93                 return;
  94 
  95         bzero(pip, sizeof (dtrace_proginfo_t));
  96 
  97         if (dt_list_next(&pgp->dp_stmts) != NULL) {
  98                 pip->dpi_descattr = _dtrace_maxattr;
  99                 pip->dpi_stmtattr = _dtrace_maxattr;
 100         } else {
 101                 pip->dpi_descattr = _dtrace_defattr;
 102                 pip->dpi_stmtattr = _dtrace_defattr;
 103         }
 104 
 105         for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
 106                 dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
 107 
 108                 if (edp == last)
 109                         continue;
 110                 last = edp;
 111 
 112                 pip->dpi_descattr =
 113                     dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
 114 
 115                 pip->dpi_stmtattr =
 116                     dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
 117 
 118                 /*
 119                  * If there aren't any actions, account for the fact that
 120                  * recording the epid will generate a record.
 121                  */
 122                 if (edp->dted_action == NULL)
 123                         pip->dpi_recgens++;
 124 
 125                 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
 126                         if (ap->dtad_kind == DTRACEACT_SPECULATE) {
 127                                 pip->dpi_speculations++;
 128                                 continue;
 129                         }
 130 
 131                         if (DTRACEACT_ISAGG(ap->dtad_kind)) {
 132                                 pip->dpi_recgens -= ap->dtad_arg;
 133                                 pip->dpi_aggregates++;
 134                                 continue;
 135                         }
 136 
 137                         if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
 138                                 continue;
 139 
 140                         if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
 141                             ap->dtad_difo->dtdo_rtype.dtdt_kind ==
 142                             DIF_TYPE_CTF &&
 143                             ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
 144                                 continue;
 145 
 146                         pip->dpi_recgens++;
 147                 }
 148         }
 149 }
 150 
 151 int
 152 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
 153     dtrace_proginfo_t *pip)
 154 {
 155         void *dof;
 156         int n, err;
 157 
 158         if (!dtp->dt_optset) {
 159                 /*
 160                  * If we have not yet ioctl'd down our options DOF, we'll
 161                  * do that before enabling any probes (some options will
 162                  * affect which probes we match).
 163                  */
 164                 if ((dof = dtrace_getopt_dof(dtp)) == NULL)
 165                         return (-1); /* dt_errno has been set for us */
 166 
 167                 err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
 168                 dtrace_dof_destroy(dtp, dof);
 169 
 170                 if (err == -1)
 171                         return (-1);
 172 
 173                 dtp->dt_optset = B_TRUE;
 174         }
 175 
 176         dtrace_program_info(dtp, pgp, pip);
 177 
 178         if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
 179                 return (-1);
 180 
 181         n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
 182         dtrace_dof_destroy(dtp, dof);
 183 
 184         if (n == -1) {
 185                 switch (errno) {
 186                 case EINVAL:
 187                         err = EDT_DIFINVAL;
 188                         break;
 189                 case EFAULT:
 190                         err = EDT_DIFFAULT;
 191                         break;
 192                 case E2BIG:
 193                         err = EDT_DIFSIZE;
 194                         break;
 195                 case EBUSY:
 196                         err = EDT_ENABLING_ERR;
 197                         break;
 198                 default:
 199                         err = errno;
 200                 }
 201 
 202                 return (dt_set_errno(dtp, err));
 203         }
 204 
 205         if (pip != NULL)
 206                 pip->dpi_matches += n;
 207 
 208         return (0);
 209 }
 210 
 211 static void
 212 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
 213 {
 214         edp->dted_refcnt++;
 215 }
 216 
 217 void
 218 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
 219 {
 220         if (--edp->dted_refcnt > 0)
 221                 return;
 222 
 223         dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
 224         assert(edp->dted_action == NULL);
 225         dt_free(dtp, edp);
 226 }
 227 
 228 dtrace_ecbdesc_t *
 229 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
 230 {
 231         dtrace_ecbdesc_t *edp;
 232 
 233         if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
 234                 (void) dt_set_errno(dtp, EDT_NOMEM);
 235                 return (NULL);
 236         }
 237 
 238         edp->dted_probe = *pdp;
 239         dt_ecbdesc_hold(edp);
 240         return (edp);
 241 }
 242 
 243 dtrace_stmtdesc_t *
 244 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
 245 {
 246         dtrace_stmtdesc_t *sdp;
 247 
 248         if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
 249                 return (NULL);
 250 
 251         dt_ecbdesc_hold(edp);
 252         sdp->dtsd_ecbdesc = edp;
 253         sdp->dtsd_descattr = _dtrace_defattr;
 254         sdp->dtsd_stmtattr = _dtrace_defattr;
 255 
 256         return (sdp);
 257 }
 258 
 259 dtrace_actdesc_t *
 260 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
 261 {
 262         dtrace_actdesc_t *new;
 263         dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
 264 
 265         if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
 266                 return (NULL);
 267 
 268         if (sdp->dtsd_action_last != NULL) {
 269                 assert(sdp->dtsd_action != NULL);
 270                 assert(sdp->dtsd_action_last->dtad_next == NULL);
 271                 sdp->dtsd_action_last->dtad_next = new;
 272         } else {
 273                 dtrace_actdesc_t *ap = edp->dted_action;
 274 
 275                 assert(sdp->dtsd_action == NULL);
 276                 sdp->dtsd_action = new;
 277 
 278                 while (ap != NULL && ap->dtad_next != NULL)
 279                         ap = ap->dtad_next;
 280 
 281                 if (ap == NULL)
 282                         edp->dted_action = new;
 283                 else
 284                         ap->dtad_next = new;
 285         }
 286 
 287         sdp->dtsd_action_last = new;
 288         bzero(new, sizeof (dtrace_actdesc_t));
 289         new->dtad_uarg = (uintptr_t)sdp;
 290 
 291         return (new);
 292 }
 293 
 294 int
 295 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
 296 {
 297         dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
 298 
 299         if (stp == NULL)
 300                 return (-1); /* errno is set for us */
 301 
 302         dt_list_append(&pgp->dp_stmts, stp);
 303         stp->ds_desc = sdp;
 304 
 305         return (0);
 306 }
 307 
 308 int
 309 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
 310     dtrace_stmt_f *func, void *data)
 311 {
 312         dt_stmt_t *stp, *next;
 313         int status = 0;
 314 
 315         for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
 316                 next = dt_list_next(stp);
 317                 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
 318                         break;
 319         }
 320 
 321         return (status);
 322 }
 323 
 324 void
 325 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
 326 {
 327         dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
 328 
 329         /*
 330          * We need to remove any actions that we have on this ECB, and
 331          * remove our hold on the ECB itself.
 332          */
 333         if (sdp->dtsd_action != NULL) {
 334                 dtrace_actdesc_t *last = sdp->dtsd_action_last;
 335                 dtrace_actdesc_t *ap, *next;
 336 
 337                 assert(last != NULL);
 338 
 339                 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
 340                         if (ap == sdp->dtsd_action)
 341                                 break;
 342 
 343                         if (ap->dtad_next == sdp->dtsd_action)
 344                                 break;
 345                 }
 346 
 347                 assert(ap != NULL);
 348 
 349                 if (ap == edp->dted_action)
 350                         edp->dted_action = last->dtad_next;
 351                 else
 352                         ap->dtad_next = last->dtad_next;
 353 
 354                 /*
 355                  * We have now removed our action list from its ECB; we can
 356                  * safely destroy the list.
 357                  */
 358                 last->dtad_next = NULL;
 359 
 360                 for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
 361                         assert(ap->dtad_uarg == (uintptr_t)sdp);
 362                         dt_difo_free(dtp, ap->dtad_difo);
 363                         next = ap->dtad_next;
 364                         dt_free(dtp, ap);
 365                 }
 366         }
 367 
 368         if (sdp->dtsd_fmtdata != NULL)
 369                 dt_printf_destroy(sdp->dtsd_fmtdata);
 370         dt_free(dtp, sdp->dtsd_strdata);
 371 
 372         dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
 373         dt_free(dtp, sdp);
 374 }
 375 
 376 typedef struct dt_header_info {
 377         dtrace_hdl_t *dthi_dtp; /* consumer handle */
 378         FILE *dthi_out;         /* output file */
 379         char *dthi_pmname;      /* provider macro name */
 380         char *dthi_pfname;      /* provider function name */
 381         int dthi_empty;         /* should we generate empty macros */
 382 } dt_header_info_t;
 383 
 384 static void
 385 dt_header_fmt_macro(char *buf, const char *str)
 386 {
 387         for (;;) {
 388                 if (islower(*str)) {
 389                         *buf++ = *str++ + 'A' - 'a';
 390                 } else if (*str == '-') {
 391                         *buf++ = '_';
 392                         str++;
 393                 } else if (*str == '.') {
 394                         *buf++ = '_';
 395                         str++;
 396                 } else if ((*buf++ = *str++) == '\0') {
 397                         break;
 398                 }
 399         }
 400 }
 401 
 402 static void
 403 dt_header_fmt_func(char *buf, const char *str)
 404 {
 405         for (;;) {
 406                 if (*str == '-') {
 407                         *buf++ = '_';
 408                         *buf++ = '_';
 409                         str++;
 410                 } else if ((*buf++ = *str++) == '\0') {
 411                         break;
 412                 }
 413         }
 414 }
 415 
 416 /*ARGSUSED*/
 417 static int
 418 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
 419 {
 420         dt_header_info_t *infop = data;
 421         dtrace_hdl_t *dtp = infop->dthi_dtp;
 422         dt_probe_t *prp = idp->di_data;
 423         dt_node_t *dnp;
 424         char buf[DT_TYPE_NAMELEN];
 425         char *fname;
 426         const char *p;
 427         int i;
 428 
 429         p = prp->pr_name;
 430         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
 431                 p++;
 432 
 433         fname = alloca(strlen(prp->pr_name) + 1 + i);
 434         dt_header_fmt_func(fname, prp->pr_name);
 435 
 436         if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
 437             infop->dthi_pfname, fname) < 0)
 438                 return (dt_set_errno(dtp, errno));
 439 
 440         for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
 441                 if (fprintf(infop->dthi_out, "%s",
 442                     ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
 443                     buf, sizeof (buf))) < 0)
 444                         return (dt_set_errno(dtp, errno));
 445 
 446                 if (i + 1 != prp->pr_nargc &&
 447                     fprintf(infop->dthi_out, ", ") < 0)
 448                         return (dt_set_errno(dtp, errno));
 449         }
 450 
 451         if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
 452                 return (dt_set_errno(dtp, errno));
 453 
 454         if (fprintf(infop->dthi_out, ");\n") < 0)
 455                 return (dt_set_errno(dtp, errno));
 456 
 457         if (fprintf(infop->dthi_out,
 458             "#ifndef\t__sparc\n"
 459             "extern int __dtraceenabled_%s___%s(void);\n"
 460             "#else\n"
 461             "extern int __dtraceenabled_%s___%s(long);\n"
 462             "#endif\n",
 463             infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
 464                 return (dt_set_errno(dtp, errno));
 465 
 466         return (0);
 467 }
 468 
 469 /*ARGSUSED*/
 470 static int
 471 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
 472 {
 473         dt_header_info_t *infop = data;
 474         dtrace_hdl_t *dtp = infop->dthi_dtp;
 475         dt_probe_t *prp = idp->di_data;
 476         char *mname, *fname;
 477         const char *p;
 478         int i;
 479 
 480         p = prp->pr_name;
 481         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
 482                 p++;
 483 
 484         mname = alloca(strlen(prp->pr_name) + 1);
 485         dt_header_fmt_macro(mname, prp->pr_name);
 486 
 487         fname = alloca(strlen(prp->pr_name) + 1 + i);
 488         dt_header_fmt_func(fname, prp->pr_name);
 489 
 490         if (fprintf(infop->dthi_out, "#define\t%s_%s(",
 491             infop->dthi_pmname, mname) < 0)
 492                 return (dt_set_errno(dtp, errno));
 493 
 494         for (i = 0; i < prp->pr_nargc; i++) {
 495                 if (fprintf(infop->dthi_out, "arg%d", i) < 0)
 496                         return (dt_set_errno(dtp, errno));
 497 
 498                 if (i + 1 != prp->pr_nargc &&
 499                     fprintf(infop->dthi_out, ", ") < 0)
 500                         return (dt_set_errno(dtp, errno));
 501         }
 502 
 503         if (!infop->dthi_empty) {
 504                 if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
 505                         return (dt_set_errno(dtp, errno));
 506 
 507                 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
 508                     infop->dthi_pfname, fname) < 0)
 509                         return (dt_set_errno(dtp, errno));
 510 
 511                 for (i = 0; i < prp->pr_nargc; i++) {
 512                         if (fprintf(infop->dthi_out, "arg%d", i) < 0)
 513                                 return (dt_set_errno(dtp, errno));
 514 
 515                         if (i + 1 != prp->pr_nargc &&
 516                             fprintf(infop->dthi_out, ", ") < 0)
 517                                 return (dt_set_errno(dtp, errno));
 518                 }
 519         }
 520 
 521         if (fprintf(infop->dthi_out, ")\n") < 0)
 522                 return (dt_set_errno(dtp, errno));
 523 
 524         if (!infop->dthi_empty) {
 525                 if (fprintf(infop->dthi_out,
 526                     "#ifndef\t__sparc\n"
 527                     "#define\t%s_%s_ENABLED() \\\n"
 528                     "\t__dtraceenabled_%s___%s()\n"
 529                     "#else\n"
 530                     "#define\t%s_%s_ENABLED() \\\n"
 531                     "\t__dtraceenabled_%s___%s(0)\n"
 532                     "#endif\n",
 533                     infop->dthi_pmname, mname,
 534                     infop->dthi_pfname, fname,
 535                     infop->dthi_pmname, mname,
 536                     infop->dthi_pfname, fname) < 0)
 537                         return (dt_set_errno(dtp, errno));
 538 
 539         } else {
 540                 if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
 541                     infop->dthi_pmname, mname) < 0)
 542                         return (dt_set_errno(dtp, errno));
 543         }
 544 
 545         return (0);
 546 }
 547 
 548 static int
 549 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
 550 {
 551         dt_header_info_t info;
 552         const char *p;
 553         int i;
 554 
 555         if (pvp->pv_flags & DT_PROVIDER_IMPL)
 556                 return (0);
 557 
 558         /*
 559          * Count the instances of the '-' character since we'll need to double
 560          * those up.
 561          */
 562         p = pvp->pv_desc.dtvd_name;
 563         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
 564                 p++;
 565 
 566         info.dthi_dtp = dtp;
 567         info.dthi_out = out;
 568         info.dthi_empty = 0;
 569 
 570         info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
 571         dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
 572 
 573         info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
 574         dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
 575 
 576         if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
 577                 return (dt_set_errno(dtp, errno));
 578 
 579         if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
 580                 return (-1); /* dt_errno is set for us */
 581         if (fprintf(out, "\n\n") < 0)
 582                 return (dt_set_errno(dtp, errno));
 583         if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
 584                 return (-1); /* dt_errno is set for us */
 585 
 586         if (fprintf(out, "\n#else\n\n") < 0)
 587                 return (dt_set_errno(dtp, errno));
 588 
 589         info.dthi_empty = 1;
 590 
 591         if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
 592                 return (-1); /* dt_errno is set for us */
 593 
 594         if (fprintf(out, "\n#endif\n\n") < 0)
 595                 return (dt_set_errno(dtp, errno));
 596 
 597         return (0);
 598 }
 599 
 600 int
 601 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
 602 {
 603         dt_provider_t *pvp;
 604         char *mfname, *p;
 605 
 606         if (fname != NULL) {
 607                 if ((p = strrchr(fname, '/')) != NULL)
 608                         fname = p + 1;
 609 
 610                 mfname = alloca(strlen(fname) + 1);
 611                 dt_header_fmt_macro(mfname, fname);
 612                 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
 613                     mfname, mfname) < 0)
 614                         return (dt_set_errno(dtp, errno));
 615         }
 616 
 617         if (fprintf(out, "#include <unistd.h>\n\n") < 0)
 618                 return (-1);
 619 
 620         if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
 621                 return (-1);
 622 
 623         for (pvp = dt_list_next(&dtp->dt_provlist);
 624             pvp != NULL; pvp = dt_list_next(pvp)) {
 625                 if (dt_header_provider(dtp, pvp, out) != 0)
 626                         return (-1); /* dt_errno is set for us */
 627         }
 628 
 629         if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
 630                 return (dt_set_errno(dtp, errno));
 631 
 632         if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
 633                 return (dt_set_errno(dtp, errno));
 634 
 635         return (0);
 636 }