Print this page
10812 ctf tools shouldn't add blank labels
10813 ctf symbol mapping needs work
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
        
*** 26,36 ****
   * Copyright 2012 Jason King.  All rights reserved.
   * Use is subject to license terms.
   */
  
  /*
!  * Copyright 2018 Joyent, Inc.
   */
  
  /*
   * CTF DWARF conversion theory.
   *
--- 26,36 ----
   * Copyright 2012 Jason King.  All rights reserved.
   * Use is subject to license terms.
   */
  
  /*
!  * Copyright 2019 Joyent, Inc.
   */
  
  /*
   * CTF DWARF conversion theory.
   *
*** 280,292 ****
  static int ctf_dwarf_function_count(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *,
      boolean_t);
  static int ctf_dwarf_convert_fargs(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *,
      ctf_id_t *);
  
- typedef int (ctf_dwarf_symtab_f)(ctf_cu_t *, const GElf_Sym *, ulong_t,
-     const char *, const char *, void *);
- 
  /*
   * This is a generic way to set a CTF Conversion backend error depending on what
   * we were doing. Unless it was one of a specific set of errors that don't
   * indicate a programming / translation bug, eg. ENOMEM, then we transform it
   * into a CTF backend error and fill in the error buffer.
--- 280,289 ----
*** 2164,2293 ****
          }
  
          return (0);
  }
  
  static ctf_dwfunc_t *
  ctf_dwarf_match_func(ctf_cu_t *cup, const char *file, const char *name,
!     int bind)
  {
!         ctf_dwfunc_t *cdf;
  
          if (bind == STB_WEAK)
                  return (NULL);
  
-         /* Nothing we can do if we can't find a name to compare it to. */
          if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
                  return (NULL);
  
          for (cdf = ctf_list_next(&cup->cu_funcs); cdf != NULL;
              cdf = ctf_list_next(cdf)) {
!                 if (bind == STB_GLOBAL && cdf->cdf_global == B_FALSE)
                          continue;
!                 if (bind == STB_LOCAL && cdf->cdf_global == B_TRUE)
!                         continue;
!                 if (strcmp(name, cdf->cdf_name) != 0)
!                         continue;
!                 if (bind == STB_LOCAL && strcmp(file, cup->cu_name) != 0)
!                         continue;
                  return (cdf);
          }
  
!         return (NULL);
  }
  static ctf_dwvar_t *
  ctf_dwarf_match_var(ctf_cu_t *cup, const char *file, const char *name,
!     int bind)
  {
!         ctf_dwvar_t *cdv;
  
!         /* Nothing we can do if we can't find a name to compare it to. */
          if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
                  return (NULL);
-         ctf_dprintf("Still considering %s\n", name);
  
          for (cdv = ctf_list_next(&cup->cu_vars); cdv != NULL;
              cdv = ctf_list_next(cdv)) {
!                 if (bind == STB_GLOBAL && cdv->cdv_global == B_FALSE)
!                         continue;
!                 if (bind == STB_LOCAL && cdv->cdv_global == B_TRUE)
!                         continue;
!                 if (strcmp(name, cdv->cdv_name) != 0)
!                         continue;
!                 if (bind == STB_LOCAL && strcmp(file, cup->cu_name) != 0)
!                         continue;
!                 return (cdv);
!         }
  
!         return (NULL);
! }
! 
! static int
! ctf_dwarf_symtab_iter(ctf_cu_t *cup, ctf_dwarf_symtab_f *func, void *arg)
! {
!         int ret;
!         ulong_t i;
!         ctf_file_t *fp = cup->cu_ctfp;
!         const char *file = NULL;
!         uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
!         uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
! 
!         for (i = 0; i < fp->ctf_nsyms; i++) {
!                 const char *name;
!                 int type;
!                 GElf_Sym gsym;
!                 const GElf_Sym *gsymp;
! 
!                 if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
!                         const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
!                         type = ELF32_ST_TYPE(symp->st_info);
!                         if (type == STT_FILE) {
!                                 file = (char *)(strbase + symp->st_name);
!                                 continue;
                          }
-                         if (type != STT_OBJECT && type != STT_FUNC)
-                                 continue;
-                         if (ctf_sym_valid(strbase, type, symp->st_shndx,
-                             symp->st_value, symp->st_name) == B_FALSE)
-                                 continue;
-                         name = (char *)(strbase + symp->st_name);
-                         gsym.st_name = symp->st_name;
-                         gsym.st_value = symp->st_value;
-                         gsym.st_size = symp->st_size;
-                         gsym.st_info = symp->st_info;
-                         gsym.st_other = symp->st_other;
-                         gsym.st_shndx = symp->st_shndx;
-                         gsymp = &gsym;
                  } else {
!                         const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
!                         type = ELF64_ST_TYPE(symp->st_info);
!                         if (type == STT_FILE) {
!                                 file = (char *)(strbase + symp->st_name);
!                                 continue;
                          }
-                         if (type != STT_OBJECT && type != STT_FUNC)
-                                 continue;
-                         if (ctf_sym_valid(strbase, type, symp->st_shndx,
-                             symp->st_value, symp->st_name) == B_FALSE)
-                                 continue;
-                         name = (char *)(strbase + symp->st_name);
-                         gsymp = symp;
                  }
- 
-                 ret = func(cup, gsymp, i, file, name, arg);
-                 if (ret != 0)
-                         return (ret);
          }
  
!         return (0);
  }
  
  static int
! ctf_dwarf_conv_funcvars_cb(ctf_cu_t *cup, const GElf_Sym *symp, ulong_t idx,
!     const char *file, const char *name, void *arg)
  {
!         int ret, bind, type;
  
          bind = GELF_ST_BIND(symp->st_info);
          type = GELF_ST_TYPE(symp->st_info);
  
          /*
--- 2161,2296 ----
          }
  
          return (0);
  }
  
+ /*
+  * The DWARF information about a symbol and the information in the symbol table
+  * may not be the same due to symbol reduction that is performed by ld due to a
+  * mapfile or other such directive. We process weak symbols at a later time.
+  *
+  * The following are the rules that we employ:
+  *
+  * 1. A DWARF function that is considered exported matches STB_GLOBAL entries
+  * with the same name.
+  *
+  * 2. A DWARF function that is considered exported matches STB_LOCAL entries
+  * with the same name and the same file. This case may happen due to mapfile
+  * reduction.
+  *
+  * 3. A DWARF function that is not considered exported matches STB_LOCAL entries
+  * with the same name and the same file.
+  *
+  * 4. A DWARF function that has the same name as the symbol table entry, but the
+  * files do not match. This is considered a 'fuzzy' match. This may also happen
+  * due to a mapfile reduction. Fuzzy matching is only used when we know that the
+  * file in question refers to the primary object. This is because when a symbol
+  * is reduced in a mapfile, it's always going to be tagged as a local value in
+  * the generated output and it is considered as to belong to the primary file
+  * which is the first STT_FILE symbol we see.
+  */
+ static boolean_t
+ ctf_dwarf_symbol_match(const char *symtab_file, const char *symtab_name,
+     uint_t symtab_bind, const char *dwarf_file, const char *dwarf_name,
+     boolean_t dwarf_global, boolean_t *is_fuzzy)
+ {
+         *is_fuzzy = B_FALSE;
+ 
+         if (symtab_bind != STB_LOCAL && symtab_bind != STB_GLOBAL) {
+                 return (B_FALSE);
+         }
+ 
+         if (strcmp(symtab_name, dwarf_name) != 0) {
+                 return (B_FALSE);
+         }
+ 
+         if (symtab_bind == STB_GLOBAL) {
+                 return (dwarf_global);
+         }
+ 
+         if (strcmp(symtab_file, dwarf_file) == 0) {
+                 return (B_TRUE);
+         }
+ 
+         if (dwarf_global) {
+                 *is_fuzzy = B_TRUE;
+                 return (B_TRUE);
+         }
+ 
+         return (B_FALSE);
+ }
+ 
  static ctf_dwfunc_t *
  ctf_dwarf_match_func(ctf_cu_t *cup, const char *file, const char *name,
!     uint_t bind, boolean_t primary)
  {
!         ctf_dwfunc_t *cdf, *fuzzy = NULL;
  
          if (bind == STB_WEAK)
                  return (NULL);
  
          if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
                  return (NULL);
  
          for (cdf = ctf_list_next(&cup->cu_funcs); cdf != NULL;
              cdf = ctf_list_next(cdf)) {
!                 boolean_t is_fuzzy = B_FALSE;
! 
!                 if (ctf_dwarf_symbol_match(file, name, bind, cup->cu_name,
!                     cdf->cdf_name, cdf->cdf_global, &is_fuzzy)) {
!                         if (is_fuzzy) {
!                                 if (primary) {
!                                         fuzzy = cdf;
!                                 }
                                  continue;
!                         } else {
                                  return (cdf);
                          }
+                 }
+         }
  
!         return (fuzzy);
  }
+ 
  static ctf_dwvar_t *
  ctf_dwarf_match_var(ctf_cu_t *cup, const char *file, const char *name,
!     uint_t bind, boolean_t primary)
  {
!         ctf_dwvar_t *cdv, *fuzzy = NULL;
  
!         if (bind == STB_WEAK)
!                 return (NULL);
! 
          if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
                  return (NULL);
  
          for (cdv = ctf_list_next(&cup->cu_vars); cdv != NULL;
              cdv = ctf_list_next(cdv)) {
!                 boolean_t is_fuzzy = B_FALSE;
  
!                 if (ctf_dwarf_symbol_match(file, name, bind, cup->cu_name,
!                     cdv->cdv_name, cdv->cdv_global, &is_fuzzy)) {
!                         if (is_fuzzy) {
!                                 if (primary) {
!                                         fuzzy = cdv;
                                  }
                          } else {
!                                 return (cdv);
                          }
                  }
          }
  
!         return (fuzzy);
  }
  
  static int
! ctf_dwarf_conv_funcvars_cb(const Elf64_Sym *symp, ulong_t idx,
!     const char *file, const char *name, boolean_t primary, void *arg)
  {
!         int ret;
!         uint_t bind, type;
!         ctf_cu_t *cup = arg;
  
          bind = GELF_ST_BIND(symp->st_info);
          type = GELF_ST_TYPE(symp->st_info);
  
          /*
*** 2296,2318 ****
          if (bind == STB_WEAK)
                  return (0);
  
          if (type == STT_OBJECT) {
                  ctf_dwvar_t *cdv = ctf_dwarf_match_var(cup, file, name,
!                     bind);
!                 ctf_dprintf("match for %s (%d): %p\n", name, idx, cdv);
                  if (cdv == NULL)
                          return (0);
                  ret = ctf_add_object(cup->cu_ctfp, idx, cdv->cdv_type);
!                 ctf_dprintf("added object %s\n", name);
          } else {
                  ctf_dwfunc_t *cdf = ctf_dwarf_match_func(cup, file, name,
!                     bind);
                  if (cdf == NULL)
                          return (0);
                  ret = ctf_add_function(cup->cu_ctfp, idx, &cdf->cdf_fip,
                      cdf->cdf_argv);
          }
  
          if (ret == CTF_ERR) {
                  return (ctf_errno(cup->cu_ctfp));
          }
--- 2299,2321 ----
          if (bind == STB_WEAK)
                  return (0);
  
          if (type == STT_OBJECT) {
                  ctf_dwvar_t *cdv = ctf_dwarf_match_var(cup, file, name,
!                     bind, primary);
                  if (cdv == NULL)
                          return (0);
                  ret = ctf_add_object(cup->cu_ctfp, idx, cdv->cdv_type);
!                 ctf_dprintf("added object %s->%ld\n", name, cdv->cdv_type);
          } else {
                  ctf_dwfunc_t *cdf = ctf_dwarf_match_func(cup, file, name,
!                     bind, primary);
                  if (cdf == NULL)
                          return (0);
                  ret = ctf_add_function(cup->cu_ctfp, idx, &cdf->cdf_fip,
                      cdf->cdf_argv);
+                 ctf_dprintf("added function %s\n", name);
          }
  
          if (ret == CTF_ERR) {
                  return (ctf_errno(cup->cu_ctfp));
          }
*** 2321,2331 ****
  }
  
  static int
  ctf_dwarf_conv_funcvars(ctf_cu_t *cup)
  {
!         return (ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_funcvars_cb, NULL));
  }
  
  /*
   * If we have a weak symbol, attempt to find the strong symbol it will resolve
   * to.  Note: the code where this actually happens is in sym_process() in
--- 2324,2334 ----
  }
  
  static int
  ctf_dwarf_conv_funcvars(ctf_cu_t *cup)
  {
!         return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_funcvars_cb, cup));
  }
  
  /*
   * If we have a weak symbol, attempt to find the strong symbol it will resolve
   * to.  Note: the code where this actually happens is in sym_process() in
*** 2363,2385 ****
   *
   * What we really need here is a SUNW section containing weak<->strong mappings
   * that we can consume.
   */
  typedef struct ctf_dwarf_weak_arg {
!         const GElf_Sym *cweak_symp;
          const char *cweak_file;
          boolean_t cweak_candidate;
          ulong_t cweak_idx;
  } ctf_dwarf_weak_arg_t;
  
  static int
! ctf_dwarf_conv_check_weak(ctf_cu_t *cup, const GElf_Sym *symp,
!     ulong_t idx, const char *file, const char *name, void *arg)
  {
          ctf_dwarf_weak_arg_t *cweak = arg;
-         const GElf_Sym *wsymp = cweak->cweak_symp;
  
          ctf_dprintf("comparing weak to %s\n", name);
  
          if (GELF_ST_BIND(symp->st_info) == STB_WEAK) {
                  return (0);
          }
--- 2366,2389 ----
   *
   * What we really need here is a SUNW section containing weak<->strong mappings
   * that we can consume.
   */
  typedef struct ctf_dwarf_weak_arg {
!         const Elf64_Sym *cweak_symp;
          const char *cweak_file;
          boolean_t cweak_candidate;
          ulong_t cweak_idx;
  } ctf_dwarf_weak_arg_t;
  
  static int
! ctf_dwarf_conv_check_weak(const Elf64_Sym *symp, ulong_t idx, const char *file,
!     const char *name, boolean_t primary, void *arg)
  {
          ctf_dwarf_weak_arg_t *cweak = arg;
  
+         const Elf64_Sym *wsymp = cweak->cweak_symp;
+ 
          ctf_dprintf("comparing weak to %s\n", name);
  
          if (GELF_ST_BIND(symp->st_info) == STB_WEAK) {
                  return (0);
          }
*** 2474,2488 ****
  
          return (0);
  }
  
  static int
! ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
!     ulong_t idx, const char *file, const char *name, void *arg)
  {
          int ret, type;
          ctf_dwarf_weak_arg_t cweak;
  
          /*
           * We only care about weak symbols.
           */
          if (GELF_ST_BIND(symp->st_info) != STB_WEAK)
--- 2478,2493 ----
  
          return (0);
  }
  
  static int
! ctf_dwarf_conv_weaks_cb(const Elf64_Sym *symp, ulong_t idx, const char *file,
!     const char *name, boolean_t primary, void *arg)
  {
          int ret, type;
          ctf_dwarf_weak_arg_t cweak;
+         ctf_cu_t *cup = arg;
  
          /*
           * We only care about weak symbols.
           */
          if (GELF_ST_BIND(symp->st_info) != STB_WEAK)
*** 2501,2511 ****
          cweak.cweak_candidate = B_FALSE;
          cweak.cweak_idx = 0;
  
          ctf_dprintf("Trying to find weak equiv for %s\n", name);
  
!         ret = ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_check_weak, &cweak);
          VERIFY(ret == 0 || ret == 1);
  
          /*
           * Nothing was ever found, we're not going to add anything for this
           * entry.
--- 2506,2516 ----
          cweak.cweak_candidate = B_FALSE;
          cweak.cweak_idx = 0;
  
          ctf_dprintf("Trying to find weak equiv for %s\n", name);
  
!         ret = ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_check_weak, &cweak);
          VERIFY(ret == 0 || ret == 1);
  
          /*
           * Nothing was ever found, we're not going to add anything for this
           * entry.
*** 2516,2525 ****
--- 2521,2531 ----
          }
  
          /*
           * Now, finally go and add the type based on the match.
           */
+         ctf_dprintf("matched weak symbol %lu to %lu\n", idx, cweak.cweak_idx);
          if (type == STT_OBJECT) {
                  ret = ctf_dwarf_duplicate_sym(cup, idx, cweak.cweak_idx);
          } else {
                  ret = ctf_dwarf_duplicate_func(cup, idx, cweak.cweak_idx);
          }
*** 2528,2538 ****
  }
  
  static int
  ctf_dwarf_conv_weaks(ctf_cu_t *cup)
  {
!         return (ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_weaks_cb, NULL));
  }
  
  /* ARGSUSED */
  static int
  ctf_dwarf_convert_one(void *arg, void *unused)
--- 2534,2544 ----
  }
  
  static int
  ctf_dwarf_conv_weaks(ctf_cu_t *cup)
  {
!         return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_weaks_cb, cup));
  }
  
  /* ARGSUSED */
  static int
  ctf_dwarf_convert_one(void *arg, void *unused)
*** 2599,2622 ****
                          return (ctf_dwarf_error(cup, cup->cu_ctfp, 0,
                              "failed to update output ctf container"));
                  }
          }
  
!         ctf_phase_dump(cup->cu_ctfp, "pre-dedup");
          ctf_dprintf("adding inputs for dedup\n");
          if ((ret = ctf_merge_add(cup->cu_cmh, cup->cu_ctfp)) != 0) {
                  return (ctf_dwarf_error(cup, NULL, ret,
                      "failed to add inputs for merge"));
          }
  
!         ctf_dprintf("starting merge\n");
          if ((ret = ctf_merge_dedup(cup->cu_cmh, &dedup)) != 0) {
                  return (ctf_dwarf_error(cup, NULL, ret,
                      "failed to deduplicate die"));
          }
          ctf_close(cup->cu_ctfp);
          cup->cu_ctfp = dedup;
  
          return (0);
  }
  
  /*
--- 2605,2629 ----
                          return (ctf_dwarf_error(cup, cup->cu_ctfp, 0,
                              "failed to update output ctf container"));
                  }
          }
  
!         ctf_phase_dump(cup->cu_ctfp, "pre-dwarf-dedup", cup->cu_name);
          ctf_dprintf("adding inputs for dedup\n");
          if ((ret = ctf_merge_add(cup->cu_cmh, cup->cu_ctfp)) != 0) {
                  return (ctf_dwarf_error(cup, NULL, ret,
                      "failed to add inputs for merge"));
          }
  
!         ctf_dprintf("starting dedup of %s\n", cup->cu_name);
          if ((ret = ctf_merge_dedup(cup->cu_cmh, &dedup)) != 0) {
                  return (ctf_dwarf_error(cup, NULL, ret,
                      "failed to deduplicate die"));
          }
          ctf_close(cup->cu_ctfp);
          cup->cu_ctfp = dedup;
+         ctf_phase_dump(cup->cu_ctfp, "post-dwarf-dedup", cup->cu_name);
  
          return (0);
  }
  
  /*
*** 2902,2915 ****
                  ret = ctf_dwarf_init_die(fd, elf, &cdies[i], i, errmsg, errlen);
                  if (ret != 0) {
                          *errp = ret;
                          goto out;
                  }
                  cup->cu_doweaks = ndies > 1 ? B_FALSE : B_TRUE;
          }
  
!         ctf_dprintf("found %d DWARF die(s)\n", ndies);
  
          /*
           * If we only have one compilation unit, there's no reason to use
           * multiple threads, even if the user requested them. After all, they
           * just gave us an upper bound.
--- 2909,2923 ----
                  ret = ctf_dwarf_init_die(fd, elf, &cdies[i], i, errmsg, errlen);
                  if (ret != 0) {
                          *errp = ret;
                          goto out;
                  }
+ 
                  cup->cu_doweaks = ndies > 1 ? B_FALSE : B_TRUE;
          }
  
!         ctf_dprintf("found %d DWARF CUs\n", ndies);
  
          /*
           * If we only have one compilation unit, there's no reason to use
           * multiple threads, even if the user requested them. After all, they
           * just gave us an upper bound.
*** 2922,2932 ****
                  goto out;
          }
  
          for (i = 0; i < ndies; i++) {
                  cup = &cdies[i];
!                 ctf_dprintf("adding die %s: %p, %x %x\n", cup->cu_name,
                      cup->cu_cu, cup->cu_cuoff, cup->cu_maxoff);
                  if (workq_add(wqp, cup) == -1) {
                          *errp = errno;
                          goto out;
                  }
--- 2930,2940 ----
                  goto out;
          }
  
          for (i = 0; i < ndies; i++) {
                  cup = &cdies[i];
!                 ctf_dprintf("adding cu %s: %p, %x %x\n", cup->cu_name,
                      cup->cu_cu, cup->cu_cuoff, cup->cu_maxoff);
                  if (workq_add(wqp, cup) == -1) {
                          *errp = errno;
                          goto out;
                  }
*** 2940,2950 ****
                  ctf_dprintf("internal convert failed: %s\n",
                      ctf_errmsg(*errp));
                  goto out;
          }
  
!         ctf_dprintf("Determining next phase: have %d dies\n", ndies);
          if (ndies != 1) {
                  ctf_merge_t *cmp;
  
                  cmp = ctf_merge_init(fd, &ret);
                  if (cmp == NULL) {
--- 2948,2958 ----
                  ctf_dprintf("internal convert failed: %s\n",
                      ctf_errmsg(*errp));
                  goto out;
          }
  
!         ctf_dprintf("Determining next phase: have %d CUs\n", ndies);
          if (ndies != 1) {
                  ctf_merge_t *cmp;
  
                  cmp = ctf_merge_init(fd, &ret);
                  if (cmp == NULL) {
*** 2957,2969 ****
                          ctf_merge_fini(cmp);
                          *errp = ret;
                          goto out;
                  }
  
-                 ctf_dprintf("adding dies\n");
                  for (i = 0; i < ndies; i++) {
                          cup = &cdies[i];
                          if ((ret = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) {
                                  ctf_merge_fini(cmp);
                                  *errp = ret;
                                  goto out;
                          }
--- 2965,2978 ----
                          ctf_merge_fini(cmp);
                          *errp = ret;
                          goto out;
                  }
  
                  for (i = 0; i < ndies; i++) {
                          cup = &cdies[i];
+                         ctf_dprintf("adding cu %s (%p)\n", cup->cu_name,
+                             cup->cu_ctfp);
                          if ((ret = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) {
                                  ctf_merge_fini(cmp);
                                  *errp = ret;
                                  goto out;
                          }