Print this page
10823 should ignore DW_TAG_subprogram with DW_AT_declaration tags
10824 GCC7-derived CTF can double qualifiers on arrays
10825 ctfdump -c drops last type
10826 ctfdump -c goes off the rails with a missing parent
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2019, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * Dump information about CTF containers.
  18  */
  19 
  20 #include <stdio.h>
  21 #include <unistd.h>
  22 #include <libctf.h>
  23 #include <libgen.h>
  24 #include <stdarg.h>
  25 #include <stdlib.h>
  26 #include <stddef.h>
  27 #include <sys/sysmacros.h>
  28 #include <sys/types.h>
  29 #include <sys/stat.h>
  30 #include <sys/note.h>
  31 #include <fcntl.h>
  32 #include <errno.h>
  33 #include <string.h>


 668         ctfdump_title(CTFDUMP_TYPES, "Types");
 669 
 670         if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) {
 671                 warnx("failed to dump types: %s",
 672                     ctf_errmsg(ctf_errno(g_fp)));
 673                 g_exit = 1;
 674         }
 675 }
 676 
 677 /*
 678  * C-style output. This is designed mainly for comparison purposes, and doesn't
 679  * produce directly valid C:
 680  *
 681  * - the declarations are sorted alphabetically not semantically
 682  * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT)
 683  * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t)
 684  * - anon unions declared within SOUs aren't expanded
 685  * - function arguments aren't expanded recursively
 686  */
 687 
 688 static void
 689 ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize)
 690 {
 691         ctf_id_t ref;
 692 
 693         if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) {
 694                 ctfdump_fatal("failed to get reference type for %ld: "
 695                     "%s\n", id, ctf_errmsg(ctf_errno(g_fp)));
 696         }
 697 
 698         (void) ctf_type_name(g_fp, ref, buf, bufsize);
 699 }
 700 
 701 static int
 702 ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
 703 {
 704         _NOTE(ARGUNUSED(arg));
 705         char name[MAX_NAMELEN];
 706 
 707         if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) {
 708                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 709                         ctfdump_fatal("type %ld missing name: %s\n", type,
 710                             ctf_errmsg(ctf_errno(g_fp)));
 711                 }
 712 
 713                 (void) snprintf(name, sizeof (name), "unknown_t %s", member);
 714         }
 715 
 716         /*
 717          * A byte offset is friendlier, but we'll print bits too if it's not
 718          * aligned (i.e. a bitfield).
 719          */
 720         if (off % NBBY != 0) {
 721                 (void) printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
 722                     name, off / NBBY, off);
 723         } else {
 724                 (void) printf("\t%s; /* offset: %lu bytes */\n",
 725                     name, off / NBBY);
 726         }
 727         return (0);
 728 }
 729 
 730 static int
 731 ctfsrc_enum_cb(const char *name, int value, void *arg)
 732 {
 733         _NOTE(ARGUNUSED(arg));
 734         (void) printf("\t%s = %d,\n", name, value);
 735         return (0);
 736 }
 737 
 738 static int
 739 is_anon_refname(const char *refname)
 740 {
 741         return ((strcmp(refname, "struct ") == 0 ||
 742             strcmp(refname, "union ") == 0 ||
 743             strcmp(refname, "enum ") == 0));
 744 }
 745 
 746 static int
 747 ctfsrc_collect_types_cb(ctf_id_t id, boolean_t root, void *arg)
 748 {
 749         _NOTE(ARGUNUSED(root, arg));
 750         (void) ctf_type_name(g_fp, id, idnames[id].ci_name,
 751             sizeof (idnames[id].ci_name));
 752         idnames[id].ci_id = id;
 753         return (0);
 754 }
 755 
 756 static void
 757 ctfsrc_type(ctf_id_t id, const char *name)
 758 {
 759         char refname[MAX_NAMELEN];
 760         ctf_id_t ref;
 761         ssize_t size;
 762         int kind;
 763 
 764         if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
 765                 ctfdump_fatal("encountered malformed ctf, type %s does not "
 766                     "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 767         }
 768 
 769         switch (kind) {
 770         case CTF_K_STRUCT:
 771         case CTF_K_UNION:
 772                 /*
 773                  * Delay printing anonymous SOUs; a later typedef will usually
 774                  * pick them up.
 775                  */
 776                 if (is_anon_refname(name))
 777                         break;
 778 
 779                 if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) {
 780                         ctfdump_fatal("failed to get size of %s: %s\n", name,
 781                             ctf_errmsg(ctf_errno(g_fp)));
 782                 }
 783 
 784                 (void) printf("%s { /* 0x%x bytes */\n", name, size);
 785 
 786                 if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) {
 787                         ctfdump_fatal("failed to iterate members of %s: %s\n",
 788                             name, ctf_errmsg(ctf_errno(g_fp)));
 789                 }
 790 
 791                 (void) printf("};\n\n");
 792                 break;
 793         case CTF_K_ENUM:
 794                 /*
 795                  * This will throw away any anon enum that isn't followed by a
 796                  * typedef...
 797                  */
 798                 if (is_anon_refname(name))
 799                         break;
 800 
 801                 (void) printf("%s {\n", name);
 802 
 803                 if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) {
 804                         ctfdump_fatal("failed to iterate enumerators of %s: "
 805                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 806                 }
 807 
 808                 (void) printf("};\n\n");
 809                 break;
 810         case CTF_K_TYPEDEF:
 811                 ctfsrc_refname(id, refname, sizeof (refname));







 812 
 813                 if (!is_anon_refname(refname)) {
 814                         (void) ctf_type_cname(g_fp,
 815                             ctf_type_reference(g_fp, id), refname,
 816                             sizeof (refname), name);
 817 
 818                         (void) printf("typedef %s;\n\n", refname);
 819                         break;
 820                 }
 821 
 822                 ref = ctf_type_reference(g_fp, id);
 823 
 824                 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
 825                         (void) printf("typedef enum {\n");
 826 
 827                         if (ctf_enum_iter(g_fp, ref,
 828                             ctfsrc_enum_cb, NULL) != 0) {
 829                                 ctfdump_fatal("failed to iterate enumerators "
 830                                     "of %s: %s\n", refname,
 831                                     ctf_errmsg(ctf_errno(g_fp)));
 832                         }
 833 
 834                         (void) printf("} %s;\n\n", name);
 835                 } else {
 836                         if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
 837                                 ctfdump_fatal("failed to get size of %s: %s\n",
 838                                     refname, ctf_errmsg(ctf_errno(g_fp)));
 839                         }
 840 
 841                         (void) printf("typedef %s{ /* 0x%zx bytes */\n",
 842                             refname, size);
 843 
 844                         if (ctf_member_iter(g_fp, ref,
 845                             ctfsrc_member_cb, NULL) != 0) {
 846                                 ctfdump_fatal("failed to iterate members "
 847                                     "of %s: %s\n", refname,
 848                                     ctf_errmsg(ctf_errno(g_fp)));
 849                         }
 850 
 851                         (void) printf("} %s;\n\n", name);
 852                 }
 853 
 854                 break;
 855         case CTF_K_FORWARD:
 856                 (void) printf("%s;\n\n", name);
 857                 break;
 858         case CTF_K_UNKNOWN:
 859         case CTF_K_INTEGER:
 860         case CTF_K_FLOAT:
 861         case CTF_K_POINTER:
 862         case CTF_K_ARRAY:
 863         case CTF_K_FUNCTION:
 864         case CTF_K_VOLATILE:
 865         case CTF_K_CONST:
 866         case CTF_K_RESTRICT:
 867                 break;
 868         default:
 869                 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
 870                     name, kind);
 871                 break;
 872         }
 873 }
 874 
 875 static int
 876 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id,


 886             sizeof (idnames[*count].ci_name));
 887         idnames[*count].ci_id = id;
 888         idnames[*count].ci_symidx = symidx;
 889         *count = *count + 1;
 890         return (0);
 891 }
 892 
 893 static void
 894 ctfsrc_object(ctf_id_t id, const char *name)
 895 {
 896         char tname[MAX_NAMELEN];
 897 
 898         if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
 899                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 900                         ctfdump_fatal("type %ld missing name: %s\n", id,
 901                             ctf_errmsg(ctf_errno(g_fp)));
 902                 }
 903                 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
 904         }
 905 
 906         (void) printf("extern %s;\n", tname);
 907 }
 908 
 909 static int
 910 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
 911     ctf_funcinfo_t *ctc, void *arg)
 912 {
 913         size_t *count = arg;
 914 
 915         (void) strlcpy(idnames[*count].ci_name, name,
 916             sizeof (idnames[*count].ci_name));
 917         bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc));
 918         idnames[*count].ci_id = 0;
 919         idnames[*count].ci_symidx = symidx;
 920         *count = *count + 1;
 921         return (0);
 922 }
 923 
 924 static void
 925 ctfsrc_function(ctf_idname_t *idn)
 926 {
 927         ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
 928         char name[MAX_NAMELEN] = "unknown_t";
 929 
 930         (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
 931 
 932         (void) printf("extern %s %s(", name, idn->ci_name);
 933 
 934         if (cfi->ctc_argc != 0) {
 935                 ctfdump_fargs_grow(cfi->ctc_argc);
 936                 if (ctf_func_args(g_fp, idn->ci_symidx,
 937                     g_nfargc, g_fargc) == CTF_ERR) {
 938                         ctfdump_fatal("failed to get arguments for function "
 939                             "%s: %s\n", idn->ci_name,
 940                             ctf_errmsg(ctf_errno(g_fp)));
 941                 }
 942 
 943                 for (size_t i = 0; i < cfi->ctc_argc; i++) {
 944                         ctf_id_t aid = g_fargc[i];
 945 
 946                         name[0] = '\0';
 947 
 948                         (void) ctf_type_name(g_fp, aid, name, sizeof (name));
 949 
 950                         (void) printf("%s%s", name,
 951                             i + 1 == cfi->ctc_argc ? "" : ", ");
 952                 }
 953         } else {
 954                 if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
 955                         (void) printf("void");
 956         }
 957 
 958         if (cfi->ctc_flags & CTF_FUNC_VARARG)
 959                 (void) printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
 960 
 961         (void) printf(");\n");
 962 }
 963 
 964 static int
 965 idname_compare(const void *lhs, const void *rhs)
 966 {
 967         return (strcmp(((ctf_idname_t *)lhs)->ci_name,
 968             ((ctf_idname_t *)rhs)->ci_name));
 969 }
 970 
 971 static void
 972 ctfdump_source(void)
 973 {
 974         ulong_t nr_syms = ctf_nr_syms(g_fp);
 975         ctf_id_t max_id = ctf_max_id(g_fp);
 976         size_t count = 0;
 977 
 978         (void) printf("/* Types */\n\n");
 979 
 980         if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
 981                 ctfdump_fatal("failed to alloc idnames: %s\n",
 982                     strerror(errno));
 983         }
 984 









 985         if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb,
 986             idnames) == CTF_ERR) {
 987                 warnx("failed to collect types: %s",
 988                     ctf_errmsg(ctf_errno(g_fp)));
 989                 g_exit = 1;
 990         }
 991 
 992         qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
 993 
 994         for (size_t i = 0; i < max_id; i++) {
 995                 if (idnames[i].ci_id != 0)
 996                         ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
 997         }
 998 
 999         free(idnames);
1000 
1001         (void) printf("\n\n/* Data Objects */\n\n");
1002 
1003         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1004                 ctfdump_fatal("failed to alloc idnames: %s\n",
1005                     strerror(errno));
1006         }
1007 
1008         if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1009             &count) == CTF_ERR) {
1010                 warnx("failed to collect objects: %s",
1011                     ctf_errmsg(ctf_errno(g_fp)));
1012                 g_exit = 1;
1013         }
1014 
1015         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1016 
1017         for (size_t i = 0; i < count; i++)
1018                 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1019 
1020         free(idnames);
1021 
1022         (void) printf("\n\n/* Functions */\n\n");
1023 
1024         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1025                 ctfdump_fatal("failed to alloc idnames: %s\n",
1026                     strerror(errno));
1027         }
1028 
1029         count = 0;
1030 
1031         if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1032             &count) == CTF_ERR) {
1033                 warnx("failed to collect functions: %s",
1034                     ctf_errmsg(ctf_errno(g_fp)));
1035                 g_exit = 1;
1036         }
1037 
1038         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1039 
1040         for (size_t i = 0; i < count; i++)
1041                 ctfsrc_function(&idnames[i]);
1042 


1179                  * labels match. While there is also the notion of the parent
1180                  * name, it's less straightforward to match that. Require that
1181                  * labels match.
1182                  */
1183                 explabel = ctf_parent_label(g_fp);
1184                 label = ctf_label_topmost(pfp);
1185                 if (explabel == NULL || label == NULL ||
1186                     strcmp(explabel, label) != 0) {
1187                         if (label == NULL)
1188                                 label = "<missing>";
1189                         if (explabel == NULL)
1190                                 explabel = "<missing>";
1191                         ctfdump_fatal("label mismatch between parent %s and "
1192                             "child %s, parent has %s, child expects %s\n",
1193                             parent, argv[0], label, explabel);
1194                 }
1195 
1196                 if (ctf_import(g_fp, pfp) != 0)
1197                         ctfdump_fatal("failed to import parent %s: %s\n",
1198                             parent, ctf_errmsg(ctf_errno(g_fp)));









1199         }

1200 
1201         if (g_dump & CTFDUMP_SOURCE) {
1202                 ctfdump_source();
1203                 return (0);
1204         }
1205 
1206         /*
1207          * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1208          * We also do CTFDUMP_STATS last as a result.
1209          */
1210         if (g_dump & CTFDUMP_HEADER)
1211                 ctfdump_header();
1212 
1213         if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
1214                 ctfdump_labels();
1215 
1216         if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
1217                 ctfdump_objects();
1218 
1219         if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2019, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * Dump information about CTF containers.
  18  */
  19 
  20 #include <stdio.h>
  21 #include <unistd.h>
  22 #include <libctf.h>
  23 #include <libgen.h>
  24 #include <stdarg.h>
  25 #include <stdlib.h>
  26 #include <stddef.h>
  27 #include <sys/sysmacros.h>
  28 #include <sys/types.h>
  29 #include <sys/stat.h>
  30 #include <sys/note.h>
  31 #include <fcntl.h>
  32 #include <errno.h>
  33 #include <string.h>


 668         ctfdump_title(CTFDUMP_TYPES, "Types");
 669 
 670         if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) {
 671                 warnx("failed to dump types: %s",
 672                     ctf_errmsg(ctf_errno(g_fp)));
 673                 g_exit = 1;
 674         }
 675 }
 676 
 677 /*
 678  * C-style output. This is designed mainly for comparison purposes, and doesn't
 679  * produce directly valid C:
 680  *
 681  * - the declarations are sorted alphabetically not semantically
 682  * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT)
 683  * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t)
 684  * - anon unions declared within SOUs aren't expanded
 685  * - function arguments aren't expanded recursively
 686  */
 687 
 688 static const char *
 689 ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize)
 690 {
 691         ctf_id_t ref;
 692 
 693         if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) {
 694                 ctfdump_fatal("failed to get reference type for %ld: "
 695                     "%s\n", id, ctf_errmsg(ctf_errno(g_fp)));
 696         }
 697 
 698         return (ctf_type_name(g_fp, ref, buf, bufsize));
 699 }
 700 
 701 static int
 702 ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
 703 {
 704         _NOTE(ARGUNUSED(arg));
 705         char name[MAX_NAMELEN];
 706 
 707         if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) {
 708                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 709                         ctfdump_fatal("type %ld missing name: %s\n", type,
 710                             ctf_errmsg(ctf_errno(g_fp)));
 711                 }
 712 
 713                 (void) snprintf(name, sizeof (name), "unknown_t %s", member);
 714         }
 715 
 716         /*
 717          * A byte offset is friendlier, but we'll print bits too if it's not
 718          * aligned (i.e. a bitfield).
 719          */
 720         if (off % NBBY != 0) {
 721                 printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
 722                     name, off / NBBY, off);
 723         } else {
 724                 printf("\t%s; /* offset: %lu bytes */\n",
 725                     name, off / NBBY);
 726         }
 727         return (0);
 728 }
 729 
 730 static int
 731 ctfsrc_enum_cb(const char *name, int value, void *arg)
 732 {
 733         _NOTE(ARGUNUSED(arg));
 734         printf("\t%s = %d,\n", name, value);
 735         return (0);
 736 }
 737 
 738 static int
 739 is_anon_refname(const char *refname)
 740 {
 741         return ((strcmp(refname, "struct ") == 0 ||
 742             strcmp(refname, "union ") == 0 ||
 743             strcmp(refname, "enum ") == 0));
 744 }
 745 
 746 static int
 747 ctfsrc_collect_types_cb(ctf_id_t id, boolean_t root, void *arg)
 748 {
 749         _NOTE(ARGUNUSED(root, arg));
 750         (void) ctf_type_name(g_fp, id, idnames[id].ci_name,
 751             sizeof (idnames[id].ci_name));
 752         idnames[id].ci_id = id;
 753         return (0);
 754 }
 755 
 756 static void
 757 ctfsrc_type(ctf_id_t id, const char *name)
 758 {
 759         char refname[MAX_NAMELEN] = "unknown_t";
 760         ctf_id_t ref;
 761         ssize_t size;
 762         int kind;
 763 
 764         if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
 765                 ctfdump_fatal("encountered malformed ctf, type %s does not "
 766                     "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 767         }
 768 
 769         switch (kind) {
 770         case CTF_K_STRUCT:
 771         case CTF_K_UNION:
 772                 /*
 773                  * Delay printing anonymous SOUs; a later typedef will usually
 774                  * pick them up.
 775                  */
 776                 if (is_anon_refname(name))
 777                         break;
 778 
 779                 if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) {
 780                         ctfdump_fatal("failed to get size of %s: %s\n", name,
 781                             ctf_errmsg(ctf_errno(g_fp)));
 782                 }
 783 
 784                 printf("%s { /* 0x%x bytes */\n", name, size);
 785 
 786                 if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) {
 787                         ctfdump_fatal("failed to iterate members of %s: %s\n",
 788                             name, ctf_errmsg(ctf_errno(g_fp)));
 789                 }
 790 
 791                 printf("};\n\n");
 792                 break;
 793         case CTF_K_ENUM:
 794                 /*
 795                  * This will throw away any anon enum that isn't followed by a
 796                  * typedef...
 797                  */
 798                 if (is_anon_refname(name))
 799                         break;
 800 
 801                 printf("%s {\n", name);
 802 
 803                 if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) {
 804                         ctfdump_fatal("failed to iterate enumerators of %s: "
 805                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 806                 }
 807 
 808                 printf("};\n\n");
 809                 break;
 810         case CTF_K_TYPEDEF:
 811                 /*
 812                  * If this fails, it's probably because the referent type is in
 813                  * a parent container that was not supplied via -p.
 814                  */
 815                 if (ctfsrc_refname(id, refname, sizeof (refname)) == NULL) {
 816                         printf("typedef %s %s;\n\n", refname, name);
 817                         break;
 818                 }
 819 
 820                 if (!is_anon_refname(refname)) {
 821                         (void) ctf_type_cname(g_fp,
 822                             ctf_type_reference(g_fp, id), refname,
 823                             sizeof (refname), name);
 824 
 825                         printf("typedef %s;\n\n", refname);
 826                         break;
 827                 }
 828 
 829                 ref = ctf_type_reference(g_fp, id);
 830 
 831                 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
 832                         printf("typedef enum {\n");
 833 
 834                         if (ctf_enum_iter(g_fp, ref,
 835                             ctfsrc_enum_cb, NULL) != 0) {
 836                                 ctfdump_fatal("failed to iterate enumerators "
 837                                     "of %s: %s\n", refname,
 838                                     ctf_errmsg(ctf_errno(g_fp)));
 839                         }
 840 
 841                         printf("} %s;\n\n", name);
 842                 } else {
 843                         if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
 844                                 ctfdump_fatal("failed to get size of %s: %s\n",
 845                                     refname, ctf_errmsg(ctf_errno(g_fp)));
 846                         }
 847 
 848                         printf("typedef %s{ /* 0x%zx bytes */\n",
 849                             refname, size);
 850 
 851                         if (ctf_member_iter(g_fp, ref,
 852                             ctfsrc_member_cb, NULL) != 0) {
 853                                 ctfdump_fatal("failed to iterate members "
 854                                     "of %s: %s\n", refname,
 855                                     ctf_errmsg(ctf_errno(g_fp)));
 856                         }
 857 
 858                         printf("} %s;\n\n", name);
 859                 }
 860 
 861                 break;
 862         case CTF_K_FORWARD:
 863                 printf("%s;\n\n", name);
 864                 break;
 865         case CTF_K_UNKNOWN:
 866         case CTF_K_INTEGER:
 867         case CTF_K_FLOAT:
 868         case CTF_K_POINTER:
 869         case CTF_K_ARRAY:
 870         case CTF_K_FUNCTION:
 871         case CTF_K_VOLATILE:
 872         case CTF_K_CONST:
 873         case CTF_K_RESTRICT:
 874                 break;
 875         default:
 876                 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
 877                     name, kind);
 878                 break;
 879         }
 880 }
 881 
 882 static int
 883 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id,


 893             sizeof (idnames[*count].ci_name));
 894         idnames[*count].ci_id = id;
 895         idnames[*count].ci_symidx = symidx;
 896         *count = *count + 1;
 897         return (0);
 898 }
 899 
 900 static void
 901 ctfsrc_object(ctf_id_t id, const char *name)
 902 {
 903         char tname[MAX_NAMELEN];
 904 
 905         if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
 906                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 907                         ctfdump_fatal("type %ld missing name: %s\n", id,
 908                             ctf_errmsg(ctf_errno(g_fp)));
 909                 }
 910                 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
 911         }
 912 
 913         printf("extern %s;\n", tname);
 914 }
 915 
 916 static int
 917 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
 918     ctf_funcinfo_t *ctc, void *arg)
 919 {
 920         size_t *count = arg;
 921 
 922         (void) strlcpy(idnames[*count].ci_name, name,
 923             sizeof (idnames[*count].ci_name));
 924         bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc));
 925         idnames[*count].ci_id = 0;
 926         idnames[*count].ci_symidx = symidx;
 927         *count = *count + 1;
 928         return (0);
 929 }
 930 
 931 static void
 932 ctfsrc_function(ctf_idname_t *idn)
 933 {
 934         ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
 935         char name[MAX_NAMELEN] = "unknown_t";
 936 
 937         (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
 938 
 939         printf("extern %s %s(", name, idn->ci_name);
 940 
 941         if (cfi->ctc_argc != 0) {
 942                 ctfdump_fargs_grow(cfi->ctc_argc);
 943                 if (ctf_func_args(g_fp, idn->ci_symidx,
 944                     g_nfargc, g_fargc) == CTF_ERR) {
 945                         ctfdump_fatal("failed to get arguments for function "
 946                             "%s: %s\n", idn->ci_name,
 947                             ctf_errmsg(ctf_errno(g_fp)));
 948                 }
 949 
 950                 for (size_t i = 0; i < cfi->ctc_argc; i++) {
 951                         ctf_id_t aid = g_fargc[i];
 952 
 953                         (void) strlcpy(name, "unknown_t", sizeof (name));
 954 
 955                         (void) ctf_type_name(g_fp, aid, name, sizeof (name));
 956 
 957                         printf("%s%s", name,
 958                             i + 1 == cfi->ctc_argc ? "" : ", ");
 959                 }
 960         } else {
 961                 if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
 962                         printf("void");
 963         }
 964 
 965         if (cfi->ctc_flags & CTF_FUNC_VARARG)
 966                 printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
 967 
 968         printf(");\n");
 969 }
 970 
 971 static int
 972 idname_compare(const void *lhs, const void *rhs)
 973 {
 974         return (strcmp(((ctf_idname_t *)lhs)->ci_name,
 975             ((ctf_idname_t *)rhs)->ci_name));
 976 }
 977 
 978 static void
 979 ctfdump_source(void)
 980 {
 981         ulong_t nr_syms = ctf_nr_syms(g_fp);
 982         ctf_id_t max_id = ctf_max_id(g_fp);
 983         size_t count = 0;
 984 
 985         printf("/* Types */\n\n");
 986 
 987         if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
 988                 ctfdump_fatal("failed to alloc idnames: %s\n",
 989                     strerror(errno));
 990         }
 991 
 992         /*
 993          * Prep for any unknown types (most likely, they exist in the parent,
 994          * but we weren't given the -p option).
 995          */
 996         for (size_t i = 0; i <= max_id; i++) {
 997                 (void) strlcpy(idnames[i].ci_name, "unknown_t",
 998                     sizeof (idnames[i].ci_name));
 999         }
1000 
1001         if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb,
1002             idnames) == CTF_ERR) {
1003                 warnx("failed to collect types: %s",
1004                     ctf_errmsg(ctf_errno(g_fp)));
1005                 g_exit = 1;
1006         }
1007 
1008         qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
1009 
1010         for (size_t i = 0; i <= max_id; i++) {
1011                 if (idnames[i].ci_id != 0)
1012                         ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
1013         }
1014 
1015         free(idnames);
1016 
1017         printf("\n\n/* Data Objects */\n\n");
1018 
1019         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1020                 ctfdump_fatal("failed to alloc idnames: %s\n",
1021                     strerror(errno));
1022         }
1023 
1024         if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1025             &count) == CTF_ERR) {
1026                 warnx("failed to collect objects: %s",
1027                     ctf_errmsg(ctf_errno(g_fp)));
1028                 g_exit = 1;
1029         }
1030 
1031         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1032 
1033         for (size_t i = 0; i < count; i++)
1034                 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1035 
1036         free(idnames);
1037 
1038         printf("\n\n/* Functions */\n\n");
1039 
1040         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1041                 ctfdump_fatal("failed to alloc idnames: %s\n",
1042                     strerror(errno));
1043         }
1044 
1045         count = 0;
1046 
1047         if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1048             &count) == CTF_ERR) {
1049                 warnx("failed to collect functions: %s",
1050                     ctf_errmsg(ctf_errno(g_fp)));
1051                 g_exit = 1;
1052         }
1053 
1054         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1055 
1056         for (size_t i = 0; i < count; i++)
1057                 ctfsrc_function(&idnames[i]);
1058 


1195                  * labels match. While there is also the notion of the parent
1196                  * name, it's less straightforward to match that. Require that
1197                  * labels match.
1198                  */
1199                 explabel = ctf_parent_label(g_fp);
1200                 label = ctf_label_topmost(pfp);
1201                 if (explabel == NULL || label == NULL ||
1202                     strcmp(explabel, label) != 0) {
1203                         if (label == NULL)
1204                                 label = "<missing>";
1205                         if (explabel == NULL)
1206                                 explabel = "<missing>";
1207                         ctfdump_fatal("label mismatch between parent %s and "
1208                             "child %s, parent has %s, child expects %s\n",
1209                             parent, argv[0], label, explabel);
1210                 }
1211 
1212                 if (ctf_import(g_fp, pfp) != 0)
1213                         ctfdump_fatal("failed to import parent %s: %s\n",
1214                             parent, ctf_errmsg(ctf_errno(g_fp)));
1215         } else {
1216                 if (g_dump & CTFDUMP_SOURCE) {
1217                         printf("/* Warning: parent \"%s\" not supplied: many "
1218                             "types will be unknown. */\n\n",
1219                             ctf_parent_name(g_fp));
1220                 } else {
1221                         fprintf(stderr, "warning: parent \"%s\" not supplied: "
1222                             "many types will be unknown\n\n",
1223                             ctf_parent_name(g_fp));
1224                 }
1225         }
1226 
1227         if (g_dump & CTFDUMP_SOURCE) {
1228                 ctfdump_source();
1229                 return (0);
1230         }
1231 
1232         /*
1233          * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1234          * We also do CTFDUMP_STATS last as a result.
1235          */
1236         if (g_dump & CTFDUMP_HEADER)
1237                 ctfdump_header();
1238 
1239         if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
1240                 ctfdump_labels();
1241 
1242         if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
1243                 ctfdump_objects();
1244 
1245         if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))