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))
|