Home | History | Annotate | Download | only in libdwfl
      1 /* Standard libdwfl callbacks for debugging the running Linux kernel.
      2    Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4 
      5    Red Hat elfutils is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; version 2 of the License.
      8 
      9    Red Hat elfutils is distributed in the hope that it will be useful, but
     10    WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with Red Hat elfutils; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     17 
     18    In addition, as a special exception, Red Hat, Inc. gives You the
     19    additional right to link the code of Red Hat elfutils with code licensed
     20    under any Open Source Initiative certified open source license
     21    (http://www.opensource.org/licenses/index.php) which requires the
     22    distribution of source code with any binary distribution and to
     23    distribute linked combinations of the two.  Non-GPL Code permitted under
     24    this exception must only link to the code of Red Hat elfutils through
     25    those well defined interfaces identified in the file named EXCEPTION
     26    found in the source code files (the "Approved Interfaces").  The files
     27    of Non-GPL Code may instantiate templates or use macros or inline
     28    functions from the Approved Interfaces without causing the resulting
     29    work to be covered by the GNU General Public License.  Only Red Hat,
     30    Inc. may make changes or additions to the list of Approved Interfaces.
     31    Red Hat's grant of this exception is conditioned upon your not adding
     32    any new exceptions.  If you wish to add a new Approved Interface or
     33    exception, please contact Red Hat.  You must obey the GNU General Public
     34    License in all respects for all of the Red Hat elfutils code and other
     35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
     36    covered by this exception.  If you modify this file, you may extend this
     37    exception to your version of the file, but you are not obligated to do
     38    so.  If you do not wish to provide this exception without modification,
     39    you must delete this exception statement from your version and license
     40    this file solely under the GPL without exception.
     41 
     42    Red Hat elfutils is an included package of the Open Invention Network.
     43    An included package of the Open Invention Network is a package for which
     44    Open Invention Network licensees cross-license their patents.  No patent
     45    license is granted, either expressly or impliedly, by designation as an
     46    included package.  Should you wish to participate in the Open Invention
     47    Network licensing program, please visit www.openinventionnetwork.com
     48    <http://www.openinventionnetwork.com>.  */
     49 
     50 /* We include this before config.h because it can't handle _FILE_OFFSET_BITS.
     51    Everything we need here is fine if its declarations just come first.  */
     52 
     53 #include <fts.h>
     54 
     55 #include <config.h>
     56 
     57 #include "libdwflP.h"
     58 #include <inttypes.h>
     59 #include <errno.h>
     60 #include <stdio.h>
     61 #include <stdio_ext.h>
     62 #include <string.h>
     63 #include <stdlib.h>
     64 #include <sys/utsname.h>
     65 #include <fcntl.h>
     66 #include <unistd.h>
     67 
     68 
     69 #define KERNEL_MODNAME	"kernel"
     70 
     71 #define MODULEDIRFMT	"/lib/modules/%s"
     72 
     73 #define KNOTESFILE	"/sys/kernel/notes"
     74 #define	MODNOTESFMT	"/sys/module/%s/notes"
     75 #define KSYMSFILE	"/proc/kallsyms"
     76 #define MODULELIST	"/proc/modules"
     77 #define	SECADDRDIRFMT	"/sys/module/%s/sections/"
     78 #define MODULE_SECT_NAME_LEN 32	/* Minimum any linux/module.h has had.  */
     79 
     80 
     81 /* Try to open the given file as it is or under the debuginfo directory.  */
     82 static int
     83 try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug)
     84 {
     85   if (*fname == NULL)
     86     return -1;
     87 
     88   /* Don't bother trying *FNAME itself here if the path will cause it to be
     89      tried because we give its own basename as DEBUGLINK_FILE.  */
     90   int fd = ((((dwfl->callbacks->debuginfo_path
     91 	       ? *dwfl->callbacks->debuginfo_path : NULL)
     92 	      ?: DEFAULT_DEBUGINFO_PATH)[0] == ':') ? -1
     93 	    : TEMP_FAILURE_RETRY (open64 (*fname, O_RDONLY)));
     94   if (fd < 0)
     95     {
     96       char *debugfname = NULL;
     97       Dwfl_Module fakemod = { .dwfl = dwfl };
     98       /* First try the file's unadorned basename as DEBUGLINK_FILE,
     99 	 to look for "vmlinux" files.  */
    100       fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
    101 						 *fname, basename (*fname), 0,
    102 						 &debugfname);
    103       if (fd < 0 && try_debug)
    104 	/* Next, let the call use the default of basename + ".debug",
    105 	   to look for "vmlinux.debug" files.  */
    106 	fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
    107 						   *fname, NULL, 0,
    108 						   &debugfname);
    109       free (*fname);
    110       *fname = debugfname;
    111     }
    112 
    113   return fd;
    114 }
    115 
    116 static inline const char *
    117 kernel_release (void)
    118 {
    119   /* Cache the `uname -r` string we'll use.  */
    120   static struct utsname utsname;
    121   if (utsname.release[0] == '\0' && uname (&utsname) != 0)
    122     return NULL;
    123   return utsname.release;
    124 }
    125 
    126 static int
    127 find_kernel_elf (Dwfl *dwfl, const char *release, char **fname)
    128 {
    129   if ((release[0] == '/'
    130        ? asprintf (fname, "%s/vmlinux", release)
    131        : asprintf (fname, "/boot/vmlinux-%s", release)) < 0)
    132     return -1;
    133 
    134   int fd = try_kernel_name (dwfl, fname, true);
    135   if (fd < 0 && release[0] != '/')
    136     {
    137       free (*fname);
    138       if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0)
    139 	return -1;
    140       fd = try_kernel_name (dwfl, fname, true);
    141     }
    142 
    143   return fd;
    144 }
    145 
    146 static int
    147 get_release (Dwfl *dwfl, const char **release)
    148 {
    149   if (dwfl == NULL)
    150     return -1;
    151 
    152   const char *release_string = release == NULL ? NULL : *release;
    153   if (release_string == NULL)
    154     {
    155       release_string = kernel_release ();
    156       if (release_string == NULL)
    157 	return errno;
    158       if (release != NULL)
    159 	*release = release_string;
    160     }
    161 
    162   return 0;
    163 }
    164 
    165 static int
    166 report_kernel (Dwfl *dwfl, const char **release,
    167 	       int (*predicate) (const char *module, const char *file))
    168 {
    169   int result = get_release (dwfl, release);
    170   if (unlikely (result != 0))
    171     return result;
    172 
    173   char *fname;
    174   int fd = find_kernel_elf (dwfl, *release, &fname);
    175 
    176   if (fd < 0)
    177     result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL))
    178 	      ? 0 : errno ?: ENOENT);
    179   else
    180     {
    181       bool report = true;
    182 
    183       if (predicate != NULL)
    184 	{
    185 	  /* Let the predicate decide whether to use this one.  */
    186 	  int want = (*predicate) (KERNEL_MODNAME, fname);
    187 	  if (want < 0)
    188 	    result = errno;
    189 	  report = want > 0;
    190 	}
    191 
    192       if (report)
    193 	{
    194 	  Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME,
    195 						      fname, fd, 0);
    196 	  if (mod == NULL)
    197 	    result = -1;
    198 	  else
    199 	    /* The kernel is ET_EXEC, but always treat it as relocatable.  */
    200 	    mod->e_type = ET_DYN;
    201 	}
    202 
    203       if (!report || result < 0)
    204 	close (fd);
    205     }
    206 
    207   free (fname);
    208 
    209   return result;
    210 }
    211 
    212 /* Look for a kernel debug archive.  If we find one, report all its modules.
    213    If not, return ENOENT.  */
    214 static int
    215 report_kernel_archive (Dwfl *dwfl, const char **release,
    216 		       int (*predicate) (const char *module, const char *file))
    217 {
    218   int result = get_release (dwfl, release);
    219   if (unlikely (result != 0))
    220     return result;
    221 
    222   char *archive;
    223   if (unlikely ((*release)[0] == '/'
    224 		? asprintf (&archive, "%s/debug.a", *release)
    225 		: asprintf (&archive, MODULEDIRFMT "/debug.a", *release)) < 0)
    226     return ENOMEM;
    227 
    228   int fd = try_kernel_name (dwfl, &archive, false);
    229   if (fd < 0)
    230     result = errno ?: ENOENT;
    231   else
    232     {
    233       /* We have the archive file open!  */
    234       Dwfl_Module *last = __libdwfl_report_offline (dwfl, NULL, archive, fd,
    235 						    true, predicate);
    236       if (unlikely (last == NULL))
    237 	result = -1;
    238       else
    239 	{
    240 	  /* Find the kernel and move it to the head of the list.  */
    241 	  Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
    242 	  for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
    243 	    if (!m->gc && m->e_type != ET_REL && !strcmp (m->name, "kernel"))
    244 	      {
    245 		*prevp = m->next;
    246 		m->next = *tailp;
    247 		*tailp = m;
    248 		break;
    249 	      }
    250 	}
    251     }
    252 
    253   free (archive);
    254   return result;
    255 }
    256 
    257 /* Report a kernel and all its modules found on disk, for offline use.
    258    If RELEASE starts with '/', it names a directory to look in;
    259    if not, it names a directory to find under /lib/modules/;
    260    if null, /lib/modules/`uname -r` is used.
    261    Returns zero on success, -1 if dwfl_report_module failed,
    262    or an errno code if finding the files on disk failed.  */
    263 int
    264 dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
    265 				  int (*predicate) (const char *module,
    266 						    const char *file))
    267 {
    268   int result = report_kernel_archive (dwfl, &release, predicate);
    269   if (result != ENOENT)
    270     return result;
    271 
    272   /* First report the kernel.  */
    273   result = report_kernel (dwfl, &release, predicate);
    274   if (result == 0)
    275     {
    276       /* Do "find /lib/modules/RELEASE -name *.ko".  */
    277 
    278       char *modulesdir[] = { NULL, NULL };
    279       if (release[0] == '/')
    280 	modulesdir[0] = (char *) release;
    281       else
    282 	{
    283 	  if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
    284 	    return errno;
    285 	}
    286 
    287       FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
    288       if (modulesdir[0] == (char *) release)
    289 	modulesdir[0] = NULL;
    290       if (fts == NULL)
    291 	{
    292 	  free (modulesdir[0]);
    293 	  return errno;
    294 	}
    295 
    296       FTSENT *f;
    297       while ((f = fts_read (fts)) != NULL)
    298 	{
    299 	  switch (f->fts_info)
    300 	    {
    301 	    case FTS_F:
    302 	    case FTS_SL:
    303 	    case FTS_NSOK:
    304 	      /* See if this file name matches "*.ko".  */
    305 	      if (f->fts_namelen > 3
    306 		  && !memcmp (f->fts_name + f->fts_namelen - 3, ".ko", 4))
    307 		{
    308 		  /* We have a .ko file to report.  Following the algorithm
    309 		     by which the kernel makefiles set KBUILD_MODNAME, we
    310 		     replace all ',' or '-' with '_' in the file name and
    311 		     call that the module name.  Modules could well be
    312 		     built using different embedded names than their file
    313 		     names.  To handle that, we would have to look at the
    314 		     __this_module.name contents in the module's text.  */
    315 
    316 		  char name[f->fts_namelen - 3 + 1];
    317 		  for (size_t i = 0; i < f->fts_namelen - 3U; ++i)
    318 		    if (f->fts_name[i] == '-' || f->fts_name[i] == ',')
    319 		      name[i] = '_';
    320 		    else
    321 		      name[i] = f->fts_name[i];
    322 		  name[f->fts_namelen - 3] = '\0';
    323 
    324 		  if (predicate != NULL)
    325 		    {
    326 		      /* Let the predicate decide whether to use this one.  */
    327 		      int want = (*predicate) (name, f->fts_path);
    328 		      if (want < 0)
    329 			{
    330 			  result = -1;
    331 			  break;
    332 			}
    333 		      if (!want)
    334 			continue;
    335 		    }
    336 
    337 		  if (dwfl_report_offline (dwfl, name,
    338 					   f->fts_path, -1) == NULL)
    339 		    {
    340 		      result = -1;
    341 		      break;
    342 		    }
    343 		}
    344 	      continue;
    345 
    346 	    case FTS_ERR:
    347 	    case FTS_DNR:
    348 	    case FTS_NS:
    349 	      result = f->fts_errno;
    350 	      break;
    351 
    352 	    case FTS_SLNONE:
    353 	    default:
    354 	      continue;
    355 	    }
    356 
    357 	  /* We only get here in error cases.  */
    358 	  break;
    359 	}
    360       fts_close (fts);
    361       free (modulesdir[0]);
    362     }
    363 
    364   return result;
    365 }
    366 INTDEF (dwfl_linux_kernel_report_offline)
    367 
    368 
    369 /* Grovel around to guess the bounds of the runtime kernel image.  */
    370 static int
    371 intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes)
    372 {
    373   FILE *f = fopen (KSYMSFILE, "r");
    374   if (f == NULL)
    375     return errno;
    376 
    377   (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
    378 
    379   *notes = 0;
    380 
    381   char *line = NULL;
    382   size_t linesz = 0;
    383   size_t n = getline (&line, &linesz, f);
    384   Dwarf_Addr first;
    385   char *p = NULL;
    386   int result = 0;
    387   if (n > 0 && (first = strtoull (line, &p, 16)) > 0 && p > line)
    388     {
    389       Dwarf_Addr last = 0;
    390       while ((n = getline (&line, &linesz, f)) > 1 && line[n - 2] != ']')
    391 	{
    392 	  p = NULL;
    393 	  last = strtoull (line, &p, 16);
    394 	  if (p == NULL || p == line || last == 0)
    395 	    {
    396 	      result = -1;
    397 	      break;
    398 	    }
    399 
    400 	  if (*notes == 0)
    401 	    {
    402 	      const char *sym = (strsep (&p, " \t\n")
    403 				 ? strsep (&p, " \t\n") : NULL);
    404 	      if (sym != NULL && !strcmp (sym, "__start_notes"))
    405 		*notes = last;
    406 	    }
    407 	}
    408       if ((n == 0 && feof_unlocked (f)) || (n > 1 && line[n - 2] == ']'))
    409 	{
    410 	  Dwarf_Addr round_kernel = sysconf (_SC_PAGE_SIZE);
    411 	  first &= -(Dwarf_Addr) round_kernel;
    412 	  last += round_kernel - 1;
    413 	  last &= -(Dwarf_Addr) round_kernel;
    414 	  *start = first;
    415 	  *end = last;
    416 	  result = 0;
    417 	}
    418     }
    419   free (line);
    420 
    421   if (result == -1)
    422     result = ferror_unlocked (f) ? errno : ENOEXEC;
    423 
    424   fclose (f);
    425 
    426   return result;
    427 }
    428 
    429 
    430 /* Look for a build ID note in NOTESFILE and associate the ID with MOD.  */
    431 static int
    432 check_notes (Dwfl_Module *mod, const char *notesfile,
    433 	     Dwarf_Addr vaddr, const char *secname)
    434 {
    435   int fd = open64 (notesfile, O_RDONLY);
    436   if (fd < 0)
    437     return 1;
    438 
    439   assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr));
    440   assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr));
    441   union
    442   {
    443     GElf_Nhdr nhdr;
    444     unsigned char data[8192];
    445   } buf;
    446 
    447   ssize_t n = read (fd, buf.data, sizeof buf);
    448   close (fd);
    449 
    450   if (n <= 0)
    451     return 1;
    452 
    453   unsigned char *p = buf.data;
    454   while (p < &buf.data[n])
    455     {
    456       /* No translation required since we are reading the native kernel.  */
    457       GElf_Nhdr *nhdr = (void *) p;
    458       p += sizeof *nhdr;
    459       unsigned char *name = p;
    460       p += (nhdr->n_namesz + 3) & -4U;
    461       unsigned char *bits = p;
    462       p += (nhdr->n_descsz + 3) & -4U;
    463 
    464       if (p <= &buf.data[n]
    465 	  && nhdr->n_type == NT_GNU_BUILD_ID
    466 	  && nhdr->n_namesz == sizeof "GNU"
    467 	  && !memcmp (name, "GNU", sizeof "GNU"))
    468 	{
    469 	  /* Found it.  For a module we must figure out its VADDR now.  */
    470 
    471 	  if (secname != NULL
    472 	      && (INTUSE(dwfl_linux_kernel_module_section_address)
    473 		  (mod, NULL, mod->name, 0, secname, 0, NULL, &vaddr) != 0
    474 		  || vaddr == (GElf_Addr) -1l))
    475 	    vaddr = 0;
    476 
    477 	  if (vaddr != 0)
    478 	    vaddr += bits - buf.data;
    479 	  return INTUSE(dwfl_module_report_build_id) (mod, bits,
    480 						      nhdr->n_descsz, vaddr);
    481 	}
    482     }
    483 
    484   return 0;
    485 }
    486 
    487 /* Look for a build ID for the kernel.  */
    488 static int
    489 check_kernel_notes (Dwfl_Module *kernelmod, GElf_Addr vaddr)
    490 {
    491   return check_notes (kernelmod, KNOTESFILE, vaddr, NULL) < 0 ? -1 : 0;
    492 }
    493 
    494 /* Look for a build ID for a loaded kernel module.  */
    495 static int
    496 check_module_notes (Dwfl_Module *mod)
    497 {
    498   char *dirs[2] = { NULL, NULL };
    499   if (asprintf (&dirs[0], MODNOTESFMT, mod->name) < 0)
    500     return ENOMEM;
    501 
    502   FTS *fts = fts_open (dirs, FTS_NOSTAT | FTS_LOGICAL, NULL);
    503   if (fts == NULL)
    504     {
    505       free (dirs[0]);
    506       return 0;
    507     }
    508 
    509   int result = 0;
    510   FTSENT *f;
    511   while ((f = fts_read (fts)) != NULL)
    512     {
    513       switch (f->fts_info)
    514 	{
    515 	case FTS_F:
    516 	case FTS_SL:
    517 	case FTS_NSOK:
    518 	  result = check_notes (mod, f->fts_accpath, 0, f->fts_name);
    519 	  if (result > 0)	/* Nothing found.  */
    520 	    {
    521 	      result = 0;
    522 	      continue;
    523 	    }
    524 	  break;
    525 
    526 	case FTS_ERR:
    527 	case FTS_DNR:
    528 	  result = f->fts_errno;
    529 	  break;
    530 
    531 	case FTS_NS:
    532 	case FTS_SLNONE:
    533 	default:
    534 	  continue;
    535 	}
    536 
    537       /* We only get here when finished or in error cases.  */
    538       break;
    539     }
    540   fts_close (fts);
    541   free (dirs[0]);
    542 
    543   return result;
    544 }
    545 
    546 int
    547 dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
    548 {
    549   Dwarf_Addr start;
    550   Dwarf_Addr end;
    551   inline Dwfl_Module *report (void)
    552     {
    553       return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end);
    554     }
    555 
    556   /* This is a bit of a kludge.  If we already reported the kernel,
    557      don't bother figuring it out again--it never changes.  */
    558   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
    559     if (!strcmp (m->name, KERNEL_MODNAME))
    560       {
    561 	start = m->low_addr;
    562 	end = m->high_addr;
    563 	return report () == NULL ? -1 : 0;
    564       }
    565 
    566   /* Try to figure out the bounds of the kernel image without
    567      looking for any vmlinux file.  */
    568   Dwarf_Addr notes;
    569   /* The compiler cannot deduce that if intuit_kernel_bounds returns
    570      zero NOTES will be initialized.  Fake the initialization.  */
    571   asm ("" : "=m" (notes));
    572   int result = intuit_kernel_bounds (&start, &end, &notes);
    573   if (result == 0)
    574     {
    575       Dwfl_Module *mod = report ();
    576       return unlikely (mod == NULL) ? -1 : check_kernel_notes (mod, notes);
    577     }
    578   if (result != ENOENT)
    579     return result;
    580 
    581   /* Find the ELF file for the running kernel and dwfl_report_elf it.  */
    582   return report_kernel (dwfl, NULL, NULL);
    583 }
    584 INTDEF (dwfl_linux_kernel_report_kernel)
    585 
    586 
    587 /* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules.  */
    588 
    589 int
    590 dwfl_linux_kernel_find_elf (Dwfl_Module *mod,
    591 			    void **userdata __attribute__ ((unused)),
    592 			    const char *module_name,
    593 			    Dwarf_Addr base __attribute__ ((unused)),
    594 			    char **file_name, Elf **elfp)
    595 {
    596   if (mod->build_id_len > 0)
    597     {
    598       int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0,
    599 					       file_name, elfp);
    600       if (fd >= 0 || errno != 0)
    601 	return fd;
    602     }
    603 
    604   const char *release = kernel_release ();
    605   if (release == NULL)
    606     return errno;
    607 
    608   if (!strcmp (module_name, KERNEL_MODNAME))
    609     return find_kernel_elf (mod->dwfl, release, file_name);
    610 
    611   /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko".  */
    612 
    613   char *modulesdir[] = { NULL, NULL };
    614   if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
    615     return -1;
    616 
    617   FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
    618   if (fts == NULL)
    619     {
    620       free (modulesdir[0]);
    621       return -1;
    622     }
    623 
    624   size_t namelen = strlen (module_name);
    625 
    626   /* This is a kludge.  There is no actual necessary relationship between
    627      the name of the .ko file installed and the module name the kernel
    628      knows it by when it's loaded.  The kernel's only idea of the module
    629      name comes from the name embedded in the object's magic
    630      .gnu.linkonce.this_module section.
    631 
    632      In practice, these module names match the .ko file names except for
    633      some using '_' and some using '-'.  So our cheap kludge is to look for
    634      two files when either a '_' or '-' appears in a module name, one using
    635      only '_' and one only using '-'.  */
    636 
    637   char alternate_name[namelen + 1];
    638   inline bool subst_name (char from, char to)
    639     {
    640       const char *n = memchr (module_name, from, namelen);
    641       if (n == NULL)
    642 	return false;
    643       char *a = mempcpy (alternate_name, module_name, n - module_name);
    644       *a++ = to;
    645       ++n;
    646       const char *p;
    647       while ((p = memchr (n, from, namelen - (n - module_name))) != NULL)
    648 	{
    649 	  a = mempcpy (a, n, p - n);
    650 	  *a++ = to;
    651 	  n = p + 1;
    652 	}
    653       memcpy (a, n, namelen - (n - module_name) + 1);
    654       return true;
    655     }
    656   if (!subst_name ('-', '_') && !subst_name ('_', '-'))
    657     alternate_name[0] = '\0';
    658 
    659   FTSENT *f;
    660   int error = ENOENT;
    661   while ((f = fts_read (fts)) != NULL)
    662     {
    663       error = ENOENT;
    664       switch (f->fts_info)
    665 	{
    666 	case FTS_F:
    667 	case FTS_SL:
    668 	case FTS_NSOK:
    669 	  /* See if this file name is "MODULE_NAME.ko".  */
    670 	  if (f->fts_namelen == namelen + 3
    671 	      && !memcmp (f->fts_name + namelen, ".ko", 4)
    672 	      && (!memcmp (f->fts_name, module_name, namelen)
    673 		  || !memcmp (f->fts_name, alternate_name, namelen)))
    674 	    {
    675 	      int fd = open64 (f->fts_accpath, O_RDONLY);
    676 	      *file_name = strdup (f->fts_path);
    677 	      fts_close (fts);
    678 	      free (modulesdir[0]);
    679 	      if (fd < 0)
    680 		free (*file_name);
    681 	      else if (*file_name == NULL)
    682 		{
    683 		  close (fd);
    684 		  fd = -1;
    685 		}
    686 	      return fd;
    687 	    }
    688 	  break;
    689 
    690 	case FTS_ERR:
    691 	case FTS_DNR:
    692 	case FTS_NS:
    693 	  error = f->fts_errno;
    694 	  break;
    695 
    696 	case FTS_SLNONE:
    697 	default:
    698 	  break;
    699 	}
    700     }
    701 
    702   fts_close (fts);
    703   free (modulesdir[0]);
    704   errno = error;
    705   return -1;
    706 }
    707 INTDEF (dwfl_linux_kernel_find_elf)
    708 
    709 
    710 /* Dwfl_Callbacks.section_address for kernel modules in the running Linux.
    711    We read the information from /sys/module directly.  */
    712 
    713 int
    714 dwfl_linux_kernel_module_section_address
    715 (Dwfl_Module *mod __attribute__ ((unused)),
    716  void **userdata __attribute__ ((unused)),
    717  const char *modname, Dwarf_Addr base __attribute__ ((unused)),
    718  const char *secname, Elf32_Word shndx __attribute__ ((unused)),
    719  const GElf_Shdr *shdr __attribute__ ((unused)),
    720  Dwarf_Addr *addr)
    721 {
    722   char *sysfile;
    723   if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0)
    724     return DWARF_CB_ABORT;
    725 
    726   FILE *f = fopen (sysfile, "r");
    727   free (sysfile);
    728 
    729   if (f == NULL)
    730     {
    731       if (errno == ENOENT)
    732 	{
    733 	  /* The .modinfo and .data.percpu sections are never kept
    734 	     loaded in the kernel.  If the kernel was compiled without
    735 	     CONFIG_MODULE_UNLOAD, the .exit.* sections are not
    736 	     actually loaded at all.
    737 
    738 	     Setting *ADDR to -1 tells the caller this section is
    739 	     actually absent from memory.  */
    740 
    741 	  if (!strcmp (secname, ".modinfo")
    742 	      || !strcmp (secname, ".data.percpu")
    743 	      || !strncmp (secname, ".exit", 5))
    744 	    {
    745 	      *addr = (Dwarf_Addr) -1l;
    746 	      return DWARF_CB_OK;
    747 	    }
    748 
    749 	  /* The goofy PPC64 module_frob_arch_sections function tweaks
    750 	     the section names as a way to control other kernel code's
    751 	     behavior, and this cruft leaks out into the /sys information.
    752 	     The file name for ".init*" may actually look like "_init*".  */
    753 
    754 	  const bool is_init = !strncmp (secname, ".init", 5);
    755 	  if (is_init)
    756 	    {
    757 	      if (asprintf (&sysfile, SECADDRDIRFMT "_%s",
    758 			    modname, &secname[1]) < 0)
    759 		return ENOMEM;
    760 	      f = fopen (sysfile, "r");
    761 	      free (sysfile);
    762 	      if (f != NULL)
    763 		goto ok;
    764 	    }
    765 
    766 	  /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1.
    767 	     In case that size increases in the future, look for longer
    768 	     truncated names first.  */
    769 	  size_t namelen = strlen (secname);
    770 	  if (namelen >= MODULE_SECT_NAME_LEN)
    771 	    {
    772 	      int len = asprintf (&sysfile, SECADDRDIRFMT "%s",
    773 				  modname, secname);
    774 	      if (len < 0)
    775 		return DWARF_CB_ABORT;
    776 	      char *end = sysfile + len;
    777 	      do
    778 		{
    779 		  *--end = '\0';
    780 		  f = fopen (sysfile, "r");
    781 		  if (is_init && f == NULL && errno == ENOENT)
    782 		    {
    783 		      sysfile[len - namelen] = '_';
    784 		      f = fopen (sysfile, "r");
    785 		      sysfile[len - namelen] = '.';
    786 		    }
    787 		}
    788 	      while (f == NULL && errno == ENOENT
    789 		     && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN);
    790 	      free (sysfile);
    791 
    792 	      if (f != NULL)
    793 		goto ok;
    794 	    }
    795 	}
    796 
    797       return DWARF_CB_ABORT;
    798     }
    799 
    800  ok:
    801   (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
    802 
    803   int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0
    804 		: ferror_unlocked (f) ? errno : ENOEXEC);
    805   fclose (f);
    806 
    807   if (result == 0)
    808     return DWARF_CB_OK;
    809 
    810   errno = result;
    811   return DWARF_CB_ABORT;
    812 }
    813 INTDEF (dwfl_linux_kernel_module_section_address)
    814 
    815 int
    816 dwfl_linux_kernel_report_modules (Dwfl *dwfl)
    817 {
    818   FILE *f = fopen (MODULELIST, "r");
    819   if (f == NULL)
    820     return errno;
    821 
    822   (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
    823 
    824   int result = 0;
    825   Dwarf_Addr modaddr;
    826   unsigned long int modsz;
    827   char modname[128];
    828   char *line = NULL;
    829   size_t linesz = 0;
    830   /* We can't just use fscanf here because it's not easy to distinguish \n
    831      from other whitespace so as to take the optional word following the
    832      address but always stop at the end of the line.  */
    833   while (getline (&line, &linesz, f) > 0
    834 	 && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n",
    835 		    modname, &modsz, &modaddr) == 3)
    836     {
    837       Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, modname,
    838 						     modaddr, modaddr + modsz);
    839       if (mod == NULL)
    840 	{
    841 	  result = -1;
    842 	  break;
    843 	}
    844 
    845       result = check_module_notes (mod);
    846     }
    847   free (line);
    848 
    849   if (result == 0)
    850     result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
    851 
    852   fclose (f);
    853 
    854   return result;
    855 }
    856 INTDEF (dwfl_linux_kernel_report_modules)
    857