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>

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/ctfdump/ctfdump.c
          +++ new/usr/src/cmd/ctfdump/ctfdump.c
↓ open down ↓ 2 lines elided ↑ open up ↑
   3    3   * Common Development and Distribution License ("CDDL"), version 1.0.
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13      - * Copyright (c) 2019, Joyent, Inc.
       13 + * Copyright 2019, Joyent, Inc.
  14   14   */
  15   15  
  16   16  /*
  17   17   * Dump information about CTF containers.
  18   18   */
  19   19  
  20   20  #include <stdio.h>
  21   21  #include <unistd.h>
  22   22  #include <libctf.h>
  23   23  #include <libgen.h>
↓ open down ↓ 654 lines elided ↑ open up ↑
 678  678   * C-style output. This is designed mainly for comparison purposes, and doesn't
 679  679   * produce directly valid C:
 680  680   *
 681  681   * - the declarations are sorted alphabetically not semantically
 682  682   * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT)
 683  683   * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t)
 684  684   * - anon unions declared within SOUs aren't expanded
 685  685   * - function arguments aren't expanded recursively
 686  686   */
 687  687  
 688      -static void
      688 +static const char *
 689  689  ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize)
 690  690  {
 691  691          ctf_id_t ref;
 692  692  
 693  693          if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) {
 694  694                  ctfdump_fatal("failed to get reference type for %ld: "
 695  695                      "%s\n", id, ctf_errmsg(ctf_errno(g_fp)));
 696  696          }
 697  697  
 698      -        (void) ctf_type_name(g_fp, ref, buf, bufsize);
      698 +        return (ctf_type_name(g_fp, ref, buf, bufsize));
 699  699  }
 700  700  
 701  701  static int
 702  702  ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
 703  703  {
 704  704          _NOTE(ARGUNUSED(arg));
 705  705          char name[MAX_NAMELEN];
 706  706  
 707  707          if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) {
 708  708                  if (ctf_errno(g_fp) != ECTF_NOPARENT) {
↓ open down ↓ 2 lines elided ↑ open up ↑
 711  711                  }
 712  712  
 713  713                  (void) snprintf(name, sizeof (name), "unknown_t %s", member);
 714  714          }
 715  715  
 716  716          /*
 717  717           * A byte offset is friendlier, but we'll print bits too if it's not
 718  718           * aligned (i.e. a bitfield).
 719  719           */
 720  720          if (off % NBBY != 0) {
 721      -                (void) printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
      721 +                printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
 722  722                      name, off / NBBY, off);
 723  723          } else {
 724      -                (void) printf("\t%s; /* offset: %lu bytes */\n",
      724 +                printf("\t%s; /* offset: %lu bytes */\n",
 725  725                      name, off / NBBY);
 726  726          }
 727  727          return (0);
 728  728  }
 729  729  
 730  730  static int
 731  731  ctfsrc_enum_cb(const char *name, int value, void *arg)
 732  732  {
 733  733          _NOTE(ARGUNUSED(arg));
 734      -        (void) printf("\t%s = %d,\n", name, value);
      734 +        printf("\t%s = %d,\n", name, value);
 735  735          return (0);
 736  736  }
 737  737  
 738  738  static int
 739  739  is_anon_refname(const char *refname)
 740  740  {
 741  741          return ((strcmp(refname, "struct ") == 0 ||
 742  742              strcmp(refname, "union ") == 0 ||
 743  743              strcmp(refname, "enum ") == 0));
 744  744  }
↓ open down ↓ 4 lines elided ↑ open up ↑
 749  749          _NOTE(ARGUNUSED(root, arg));
 750  750          (void) ctf_type_name(g_fp, id, idnames[id].ci_name,
 751  751              sizeof (idnames[id].ci_name));
 752  752          idnames[id].ci_id = id;
 753  753          return (0);
 754  754  }
 755  755  
 756  756  static void
 757  757  ctfsrc_type(ctf_id_t id, const char *name)
 758  758  {
 759      -        char refname[MAX_NAMELEN];
      759 +        char refname[MAX_NAMELEN] = "unknown_t";
 760  760          ctf_id_t ref;
 761  761          ssize_t size;
 762  762          int kind;
 763  763  
 764  764          if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
 765  765                  ctfdump_fatal("encountered malformed ctf, type %s does not "
 766  766                      "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 767  767          }
 768  768  
 769  769          switch (kind) {
↓ open down ↓ 4 lines elided ↑ open up ↑
 774  774                   * pick them up.
 775  775                   */
 776  776                  if (is_anon_refname(name))
 777  777                          break;
 778  778  
 779  779                  if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) {
 780  780                          ctfdump_fatal("failed to get size of %s: %s\n", name,
 781  781                              ctf_errmsg(ctf_errno(g_fp)));
 782  782                  }
 783  783  
 784      -                (void) printf("%s { /* 0x%x bytes */\n", name, size);
      784 +                printf("%s { /* 0x%x bytes */\n", name, size);
 785  785  
 786  786                  if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) {
 787  787                          ctfdump_fatal("failed to iterate members of %s: %s\n",
 788  788                              name, ctf_errmsg(ctf_errno(g_fp)));
 789  789                  }
 790  790  
 791      -                (void) printf("};\n\n");
      791 +                printf("};\n\n");
 792  792                  break;
 793  793          case CTF_K_ENUM:
 794  794                  /*
 795  795                   * This will throw away any anon enum that isn't followed by a
 796  796                   * typedef...
 797  797                   */
 798  798                  if (is_anon_refname(name))
 799  799                          break;
 800  800  
 801      -                (void) printf("%s {\n", name);
      801 +                printf("%s {\n", name);
 802  802  
 803  803                  if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) {
 804  804                          ctfdump_fatal("failed to iterate enumerators of %s: "
 805  805                              "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 806  806                  }
 807  807  
 808      -                (void) printf("};\n\n");
      808 +                printf("};\n\n");
 809  809                  break;
 810  810          case CTF_K_TYPEDEF:
 811      -                ctfsrc_refname(id, refname, sizeof (refname));
      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 +                }
 812  819  
 813  820                  if (!is_anon_refname(refname)) {
 814  821                          (void) ctf_type_cname(g_fp,
 815  822                              ctf_type_reference(g_fp, id), refname,
 816  823                              sizeof (refname), name);
 817  824  
 818      -                        (void) printf("typedef %s;\n\n", refname);
      825 +                        printf("typedef %s;\n\n", refname);
 819  826                          break;
 820  827                  }
 821  828  
 822  829                  ref = ctf_type_reference(g_fp, id);
 823  830  
 824  831                  if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
 825      -                        (void) printf("typedef enum {\n");
      832 +                        printf("typedef enum {\n");
 826  833  
 827  834                          if (ctf_enum_iter(g_fp, ref,
 828  835                              ctfsrc_enum_cb, NULL) != 0) {
 829  836                                  ctfdump_fatal("failed to iterate enumerators "
 830  837                                      "of %s: %s\n", refname,
 831  838                                      ctf_errmsg(ctf_errno(g_fp)));
 832  839                          }
 833  840  
 834      -                        (void) printf("} %s;\n\n", name);
      841 +                        printf("} %s;\n\n", name);
 835  842                  } else {
 836  843                          if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
 837  844                                  ctfdump_fatal("failed to get size of %s: %s\n",
 838  845                                      refname, ctf_errmsg(ctf_errno(g_fp)));
 839  846                          }
 840  847  
 841      -                        (void) printf("typedef %s{ /* 0x%zx bytes */\n",
      848 +                        printf("typedef %s{ /* 0x%zx bytes */\n",
 842  849                              refname, size);
 843  850  
 844  851                          if (ctf_member_iter(g_fp, ref,
 845  852                              ctfsrc_member_cb, NULL) != 0) {
 846  853                                  ctfdump_fatal("failed to iterate members "
 847  854                                      "of %s: %s\n", refname,
 848  855                                      ctf_errmsg(ctf_errno(g_fp)));
 849  856                          }
 850  857  
 851      -                        (void) printf("} %s;\n\n", name);
      858 +                        printf("} %s;\n\n", name);
 852  859                  }
 853  860  
 854  861                  break;
 855  862          case CTF_K_FORWARD:
 856      -                (void) printf("%s;\n\n", name);
      863 +                printf("%s;\n\n", name);
 857  864                  break;
 858  865          case CTF_K_UNKNOWN:
 859  866          case CTF_K_INTEGER:
 860  867          case CTF_K_FLOAT:
 861  868          case CTF_K_POINTER:
 862  869          case CTF_K_ARRAY:
 863  870          case CTF_K_FUNCTION:
 864  871          case CTF_K_VOLATILE:
 865  872          case CTF_K_CONST:
 866  873          case CTF_K_RESTRICT:
↓ open down ↓ 29 lines elided ↑ open up ↑
 896  903          char tname[MAX_NAMELEN];
 897  904  
 898  905          if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
 899  906                  if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 900  907                          ctfdump_fatal("type %ld missing name: %s\n", id,
 901  908                              ctf_errmsg(ctf_errno(g_fp)));
 902  909                  }
 903  910                  (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
 904  911          }
 905  912  
 906      -        (void) printf("extern %s;\n", tname);
      913 +        printf("extern %s;\n", tname);
 907  914  }
 908  915  
 909  916  static int
 910  917  ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
 911  918      ctf_funcinfo_t *ctc, void *arg)
 912  919  {
 913  920          size_t *count = arg;
 914  921  
 915  922          (void) strlcpy(idnames[*count].ci_name, name,
 916  923              sizeof (idnames[*count].ci_name));
↓ open down ↓ 5 lines elided ↑ open up ↑
 922  929  }
 923  930  
 924  931  static void
 925  932  ctfsrc_function(ctf_idname_t *idn)
 926  933  {
 927  934          ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
 928  935          char name[MAX_NAMELEN] = "unknown_t";
 929  936  
 930  937          (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
 931  938  
 932      -        (void) printf("extern %s %s(", name, idn->ci_name);
      939 +        printf("extern %s %s(", name, idn->ci_name);
 933  940  
 934  941          if (cfi->ctc_argc != 0) {
 935  942                  ctfdump_fargs_grow(cfi->ctc_argc);
 936  943                  if (ctf_func_args(g_fp, idn->ci_symidx,
 937  944                      g_nfargc, g_fargc) == CTF_ERR) {
 938  945                          ctfdump_fatal("failed to get arguments for function "
 939  946                              "%s: %s\n", idn->ci_name,
 940  947                              ctf_errmsg(ctf_errno(g_fp)));
 941  948                  }
 942  949  
 943  950                  for (size_t i = 0; i < cfi->ctc_argc; i++) {
 944  951                          ctf_id_t aid = g_fargc[i];
 945  952  
 946      -                        name[0] = '\0';
      953 +                        (void) strlcpy(name, "unknown_t", sizeof (name));
 947  954  
 948  955                          (void) ctf_type_name(g_fp, aid, name, sizeof (name));
 949  956  
 950      -                        (void) printf("%s%s", name,
      957 +                        printf("%s%s", name,
 951  958                              i + 1 == cfi->ctc_argc ? "" : ", ");
 952  959                  }
 953  960          } else {
 954  961                  if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
 955      -                        (void) printf("void");
      962 +                        printf("void");
 956  963          }
 957  964  
 958  965          if (cfi->ctc_flags & CTF_FUNC_VARARG)
 959      -                (void) printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
      966 +                printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
 960  967  
 961      -        (void) printf(");\n");
      968 +        printf(");\n");
 962  969  }
 963  970  
 964  971  static int
 965  972  idname_compare(const void *lhs, const void *rhs)
 966  973  {
 967  974          return (strcmp(((ctf_idname_t *)lhs)->ci_name,
 968  975              ((ctf_idname_t *)rhs)->ci_name));
 969  976  }
 970  977  
 971  978  static void
 972  979  ctfdump_source(void)
 973  980  {
 974  981          ulong_t nr_syms = ctf_nr_syms(g_fp);
 975  982          ctf_id_t max_id = ctf_max_id(g_fp);
 976  983          size_t count = 0;
 977  984  
 978      -        (void) printf("/* Types */\n\n");
      985 +        printf("/* Types */\n\n");
 979  986  
 980  987          if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
 981  988                  ctfdump_fatal("failed to alloc idnames: %s\n",
 982  989                      strerror(errno));
 983  990          }
 984  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 +
 985 1001          if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb,
 986 1002              idnames) == CTF_ERR) {
 987 1003                  warnx("failed to collect types: %s",
 988 1004                      ctf_errmsg(ctf_errno(g_fp)));
 989 1005                  g_exit = 1;
 990 1006          }
 991 1007  
 992 1008          qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
 993 1009  
 994      -        for (size_t i = 0; i < max_id; i++) {
     1010 +        for (size_t i = 0; i <= max_id; i++) {
 995 1011                  if (idnames[i].ci_id != 0)
 996 1012                          ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
 997 1013          }
 998 1014  
 999 1015          free(idnames);
1000 1016  
1001      -        (void) printf("\n\n/* Data Objects */\n\n");
     1017 +        printf("\n\n/* Data Objects */\n\n");
1002 1018  
1003 1019          if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1004 1020                  ctfdump_fatal("failed to alloc idnames: %s\n",
1005 1021                      strerror(errno));
1006 1022          }
1007 1023  
1008 1024          if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1009 1025              &count) == CTF_ERR) {
1010 1026                  warnx("failed to collect objects: %s",
1011 1027                      ctf_errmsg(ctf_errno(g_fp)));
1012 1028                  g_exit = 1;
1013 1029          }
1014 1030  
1015 1031          qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1016 1032  
1017 1033          for (size_t i = 0; i < count; i++)
1018 1034                  ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1019 1035  
1020 1036          free(idnames);
1021 1037  
1022      -        (void) printf("\n\n/* Functions */\n\n");
     1038 +        printf("\n\n/* Functions */\n\n");
1023 1039  
1024 1040          if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1025 1041                  ctfdump_fatal("failed to alloc idnames: %s\n",
1026 1042                      strerror(errno));
1027 1043          }
1028 1044  
1029 1045          count = 0;
1030 1046  
1031 1047          if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1032 1048              &count) == CTF_ERR) {
↓ open down ↓ 156 lines elided ↑ open up ↑
1189 1205                          if (explabel == NULL)
1190 1206                                  explabel = "<missing>";
1191 1207                          ctfdump_fatal("label mismatch between parent %s and "
1192 1208                              "child %s, parent has %s, child expects %s\n",
1193 1209                              parent, argv[0], label, explabel);
1194 1210                  }
1195 1211  
1196 1212                  if (ctf_import(g_fp, pfp) != 0)
1197 1213                          ctfdump_fatal("failed to import parent %s: %s\n",
1198 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 +                }
1199 1225          }
1200 1226  
1201 1227          if (g_dump & CTFDUMP_SOURCE) {
1202 1228                  ctfdump_source();
1203 1229                  return (0);
1204 1230          }
1205 1231  
1206 1232          /*
1207 1233           * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1208 1234           * We also do CTFDUMP_STATS last as a result.
↓ open down ↓ 27 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX