linux-kernel-modules.c revision 705364b2bfc805e0c07ea64ec01e3080e5609bc3
1/* Standard libdwfl callbacks for debugging the running Linux kernel.
2   Copyright (C) 2005-2009 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.  */
82static int
83try_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
116static inline const char *
117kernel_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
126static int
127find_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
146static int
147get_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
165static int
166report_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.  */
214static int
215report_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
257static size_t
258check_suffix (const FTSENT *f, size_t namelen)
259{
260#define TRY(sfx)							\
261  if ((namelen ? f->fts_namelen == namelen + sizeof sfx - 1		\
262       : f->fts_namelen >= sizeof sfx)					\
263      && !memcmp (f->fts_name + f->fts_namelen - (sizeof sfx - 1),	\
264		  sfx, sizeof sfx))					\
265    return sizeof sfx - 1
266
267  TRY (".ko");
268#if USE_ZLIB
269  TRY (".ko.gz");
270#endif
271#if USE_BZLIB
272  TRY (".ko.bz2");
273#endif
274
275  return 0;
276
277#undef	TRY
278}
279
280/* Report a kernel and all its modules found on disk, for offline use.
281   If RELEASE starts with '/', it names a directory to look in;
282   if not, it names a directory to find under /lib/modules/;
283   if null, /lib/modules/`uname -r` is used.
284   Returns zero on success, -1 if dwfl_report_module failed,
285   or an errno code if finding the files on disk failed.  */
286int
287dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
288				  int (*predicate) (const char *module,
289						    const char *file))
290{
291  int result = report_kernel_archive (dwfl, &release, predicate);
292  if (result != ENOENT)
293    return result;
294
295  /* First report the kernel.  */
296  result = report_kernel (dwfl, &release, predicate);
297  if (result == 0)
298    {
299      /* Do "find /lib/modules/RELEASE -name *.ko".  */
300
301      char *modulesdir[] = { NULL, NULL };
302      if (release[0] == '/')
303	modulesdir[0] = (char *) release;
304      else
305	{
306	  if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
307	    return errno;
308	}
309
310      FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
311      if (modulesdir[0] == (char *) release)
312	modulesdir[0] = NULL;
313      if (fts == NULL)
314	{
315	  free (modulesdir[0]);
316	  return errno;
317	}
318
319      FTSENT *f;
320      while ((f = fts_read (fts)) != NULL)
321	{
322	  switch (f->fts_info)
323	    {
324	    case FTS_F:
325	    case FTS_SL:
326	    case FTS_NSOK:;
327	      /* See if this file name matches "*.ko".  */
328	      const size_t suffix = check_suffix (f, 0);
329	      if (suffix)
330		{
331		  /* We have a .ko file to report.  Following the algorithm
332		     by which the kernel makefiles set KBUILD_MODNAME, we
333		     replace all ',' or '-' with '_' in the file name and
334		     call that the module name.  Modules could well be
335		     built using different embedded names than their file
336		     names.  To handle that, we would have to look at the
337		     __this_module.name contents in the module's text.  */
338
339		  char name[f->fts_namelen - suffix + 1];
340		  for (size_t i = 0; i < f->fts_namelen - 3U; ++i)
341		    if (f->fts_name[i] == '-' || f->fts_name[i] == ',')
342		      name[i] = '_';
343		    else
344		      name[i] = f->fts_name[i];
345		  name[f->fts_namelen - suffix] = '\0';
346
347		  if (predicate != NULL)
348		    {
349		      /* Let the predicate decide whether to use this one.  */
350		      int want = (*predicate) (name, f->fts_path);
351		      if (want < 0)
352			{
353			  result = -1;
354			  break;
355			}
356		      if (!want)
357			continue;
358		    }
359
360		  if (dwfl_report_offline (dwfl, name, f->fts_path, -1) == NULL)
361		    {
362		      result = -1;
363		      break;
364		    }
365		}
366	      continue;
367
368	    case FTS_ERR:
369	    case FTS_DNR:
370	    case FTS_NS:
371	      result = f->fts_errno;
372	      break;
373
374	    case FTS_SLNONE:
375	    default:
376	      continue;
377	    }
378
379	  /* We only get here in error cases.  */
380	  break;
381	}
382      fts_close (fts);
383      free (modulesdir[0]);
384    }
385
386  return result;
387}
388INTDEF (dwfl_linux_kernel_report_offline)
389
390
391/* Grovel around to guess the bounds of the runtime kernel image.  */
392static int
393intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes)
394{
395  FILE *f = fopen (KSYMSFILE, "r");
396  if (f == NULL)
397    return errno;
398
399  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
400
401  *notes = 0;
402
403  char *line = NULL;
404  size_t linesz = 0;
405  size_t n = getline (&line, &linesz, f);
406  Dwarf_Addr first;
407  char *p = NULL;
408  int result = 0;
409  if (n > 0 && (first = strtoull (line, &p, 16)) > 0 && p > line)
410    {
411      Dwarf_Addr last = 0;
412      while ((n = getline (&line, &linesz, f)) > 1 && line[n - 2] != ']')
413	{
414	  p = NULL;
415	  last = strtoull (line, &p, 16);
416	  if (p == NULL || p == line || last == 0)
417	    {
418	      result = -1;
419	      break;
420	    }
421
422	  if (*notes == 0)
423	    {
424	      const char *sym = (strsep (&p, " \t\n")
425				 ? strsep (&p, " \t\n") : NULL);
426	      if (sym != NULL && !strcmp (sym, "__start_notes"))
427		*notes = last;
428	    }
429	}
430      if ((n == 0 && feof_unlocked (f)) || (n > 1 && line[n - 2] == ']'))
431	{
432	  Dwarf_Addr round_kernel = sysconf (_SC_PAGE_SIZE);
433	  first &= -(Dwarf_Addr) round_kernel;
434	  last += round_kernel - 1;
435	  last &= -(Dwarf_Addr) round_kernel;
436	  *start = first;
437	  *end = last;
438	  result = 0;
439	}
440    }
441  free (line);
442
443  if (result == -1)
444    result = ferror_unlocked (f) ? errno : ENOEXEC;
445
446  fclose (f);
447
448  return result;
449}
450
451
452/* Look for a build ID note in NOTESFILE and associate the ID with MOD.  */
453static int
454check_notes (Dwfl_Module *mod, const char *notesfile,
455	     Dwarf_Addr vaddr, const char *secname)
456{
457  int fd = open64 (notesfile, O_RDONLY);
458  if (fd < 0)
459    return 1;
460
461  assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr));
462  assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr));
463  union
464  {
465    GElf_Nhdr nhdr;
466    unsigned char data[8192];
467  } buf;
468
469  ssize_t n = read (fd, buf.data, sizeof buf);
470  close (fd);
471
472  if (n <= 0)
473    return 1;
474
475  unsigned char *p = buf.data;
476  while (p < &buf.data[n])
477    {
478      /* No translation required since we are reading the native kernel.  */
479      GElf_Nhdr *nhdr = (void *) p;
480      p += sizeof *nhdr;
481      unsigned char *name = p;
482      p += (nhdr->n_namesz + 3) & -4U;
483      unsigned char *bits = p;
484      p += (nhdr->n_descsz + 3) & -4U;
485
486      if (p <= &buf.data[n]
487	  && nhdr->n_type == NT_GNU_BUILD_ID
488	  && nhdr->n_namesz == sizeof "GNU"
489	  && !memcmp (name, "GNU", sizeof "GNU"))
490	{
491	  /* Found it.  For a module we must figure out its VADDR now.  */
492
493	  if (secname != NULL
494	      && (INTUSE(dwfl_linux_kernel_module_section_address)
495		  (mod, NULL, mod->name, 0, secname, 0, NULL, &vaddr) != 0
496		  || vaddr == (GElf_Addr) -1l))
497	    vaddr = 0;
498
499	  if (vaddr != 0)
500	    vaddr += bits - buf.data;
501	  return INTUSE(dwfl_module_report_build_id) (mod, bits,
502						      nhdr->n_descsz, vaddr);
503	}
504    }
505
506  return 0;
507}
508
509/* Look for a build ID for the kernel.  */
510static int
511check_kernel_notes (Dwfl_Module *kernelmod, GElf_Addr vaddr)
512{
513  return check_notes (kernelmod, KNOTESFILE, vaddr, NULL) < 0 ? -1 : 0;
514}
515
516/* Look for a build ID for a loaded kernel module.  */
517static int
518check_module_notes (Dwfl_Module *mod)
519{
520  char *dirs[2] = { NULL, NULL };
521  if (asprintf (&dirs[0], MODNOTESFMT, mod->name) < 0)
522    return ENOMEM;
523
524  FTS *fts = fts_open (dirs, FTS_NOSTAT | FTS_LOGICAL, NULL);
525  if (fts == NULL)
526    {
527      free (dirs[0]);
528      return 0;
529    }
530
531  int result = 0;
532  FTSENT *f;
533  while ((f = fts_read (fts)) != NULL)
534    {
535      switch (f->fts_info)
536	{
537	case FTS_F:
538	case FTS_SL:
539	case FTS_NSOK:
540	  result = check_notes (mod, f->fts_accpath, 0, f->fts_name);
541	  if (result > 0)	/* Nothing found.  */
542	    {
543	      result = 0;
544	      continue;
545	    }
546	  break;
547
548	case FTS_ERR:
549	case FTS_DNR:
550	  result = f->fts_errno;
551	  break;
552
553	case FTS_NS:
554	case FTS_SLNONE:
555	default:
556	  continue;
557	}
558
559      /* We only get here when finished or in error cases.  */
560      break;
561    }
562  fts_close (fts);
563  free (dirs[0]);
564
565  return result;
566}
567
568int
569dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
570{
571  Dwarf_Addr start;
572  Dwarf_Addr end;
573  inline Dwfl_Module *report (void)
574    {
575      return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end);
576    }
577
578  /* This is a bit of a kludge.  If we already reported the kernel,
579     don't bother figuring it out again--it never changes.  */
580  for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
581    if (!strcmp (m->name, KERNEL_MODNAME))
582      {
583	start = m->low_addr;
584	end = m->high_addr;
585	return report () == NULL ? -1 : 0;
586      }
587
588  /* Try to figure out the bounds of the kernel image without
589     looking for any vmlinux file.  */
590  Dwarf_Addr notes;
591  /* The compiler cannot deduce that if intuit_kernel_bounds returns
592     zero NOTES will be initialized.  Fake the initialization.  */
593  asm ("" : "=m" (notes));
594  int result = intuit_kernel_bounds (&start, &end, &notes);
595  if (result == 0)
596    {
597      Dwfl_Module *mod = report ();
598      return unlikely (mod == NULL) ? -1 : check_kernel_notes (mod, notes);
599    }
600  if (result != ENOENT)
601    return result;
602
603  /* Find the ELF file for the running kernel and dwfl_report_elf it.  */
604  return report_kernel (dwfl, NULL, NULL);
605}
606INTDEF (dwfl_linux_kernel_report_kernel)
607
608
609/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules.  */
610
611int
612dwfl_linux_kernel_find_elf (Dwfl_Module *mod,
613			    void **userdata __attribute__ ((unused)),
614			    const char *module_name,
615			    Dwarf_Addr base __attribute__ ((unused)),
616			    char **file_name, Elf **elfp)
617{
618  if (mod->build_id_len > 0)
619    {
620      int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0,
621					       file_name, elfp);
622      if (fd >= 0 || errno != 0)
623	return fd;
624    }
625
626  const char *release = kernel_release ();
627  if (release == NULL)
628    return errno;
629
630  if (!strcmp (module_name, KERNEL_MODNAME))
631    return find_kernel_elf (mod->dwfl, release, file_name);
632
633  /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko".  */
634
635  char *modulesdir[] = { NULL, NULL };
636  if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
637    return -1;
638
639  FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
640  if (fts == NULL)
641    {
642      free (modulesdir[0]);
643      return -1;
644    }
645
646  size_t namelen = strlen (module_name);
647
648  /* This is a kludge.  There is no actual necessary relationship between
649     the name of the .ko file installed and the module name the kernel
650     knows it by when it's loaded.  The kernel's only idea of the module
651     name comes from the name embedded in the object's magic
652     .gnu.linkonce.this_module section.
653
654     In practice, these module names match the .ko file names except for
655     some using '_' and some using '-'.  So our cheap kludge is to look for
656     two files when either a '_' or '-' appears in a module name, one using
657     only '_' and one only using '-'.  */
658
659  char alternate_name[namelen + 1];
660  inline bool subst_name (char from, char to)
661    {
662      const char *n = memchr (module_name, from, namelen);
663      if (n == NULL)
664	return false;
665      char *a = mempcpy (alternate_name, module_name, n - module_name);
666      *a++ = to;
667      ++n;
668      const char *p;
669      while ((p = memchr (n, from, namelen - (n - module_name))) != NULL)
670	{
671	  a = mempcpy (a, n, p - n);
672	  *a++ = to;
673	  n = p + 1;
674	}
675      memcpy (a, n, namelen - (n - module_name) + 1);
676      return true;
677    }
678  if (!subst_name ('-', '_') && !subst_name ('_', '-'))
679    alternate_name[0] = '\0';
680
681  FTSENT *f;
682  int error = ENOENT;
683  while ((f = fts_read (fts)) != NULL)
684    {
685      error = ENOENT;
686      switch (f->fts_info)
687	{
688	case FTS_F:
689	case FTS_SL:
690	case FTS_NSOK:
691	  /* See if this file name is "MODULE_NAME.ko".  */
692	  if (check_suffix (f, namelen)
693	      && (!memcmp (f->fts_name, module_name, namelen)
694		  || !memcmp (f->fts_name, alternate_name, namelen)))
695	    {
696	      int fd = open64 (f->fts_accpath, O_RDONLY);
697	      *file_name = strdup (f->fts_path);
698	      fts_close (fts);
699	      free (modulesdir[0]);
700	      if (fd < 0)
701		free (*file_name);
702	      else if (*file_name == NULL)
703		{
704		  close (fd);
705		  fd = -1;
706		}
707	      return fd;
708	    }
709	  break;
710
711	case FTS_ERR:
712	case FTS_DNR:
713	case FTS_NS:
714	  error = f->fts_errno;
715	  break;
716
717	case FTS_SLNONE:
718	default:
719	  break;
720	}
721    }
722
723  fts_close (fts);
724  free (modulesdir[0]);
725  errno = error;
726  return -1;
727}
728INTDEF (dwfl_linux_kernel_find_elf)
729
730
731/* Dwfl_Callbacks.section_address for kernel modules in the running Linux.
732   We read the information from /sys/module directly.  */
733
734int
735dwfl_linux_kernel_module_section_address
736(Dwfl_Module *mod __attribute__ ((unused)),
737 void **userdata __attribute__ ((unused)),
738 const char *modname, Dwarf_Addr base __attribute__ ((unused)),
739 const char *secname, Elf32_Word shndx __attribute__ ((unused)),
740 const GElf_Shdr *shdr __attribute__ ((unused)),
741 Dwarf_Addr *addr)
742{
743  char *sysfile;
744  if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0)
745    return DWARF_CB_ABORT;
746
747  FILE *f = fopen (sysfile, "r");
748  free (sysfile);
749
750  if (f == NULL)
751    {
752      if (errno == ENOENT)
753	{
754	  /* The .modinfo and .data.percpu sections are never kept
755	     loaded in the kernel.  If the kernel was compiled without
756	     CONFIG_MODULE_UNLOAD, the .exit.* sections are not
757	     actually loaded at all.
758
759	     Setting *ADDR to -1 tells the caller this section is
760	     actually absent from memory.  */
761
762	  if (!strcmp (secname, ".modinfo")
763	      || !strcmp (secname, ".data.percpu")
764	      || !strncmp (secname, ".exit", 5))
765	    {
766	      *addr = (Dwarf_Addr) -1l;
767	      return DWARF_CB_OK;
768	    }
769
770	  /* The goofy PPC64 module_frob_arch_sections function tweaks
771	     the section names as a way to control other kernel code's
772	     behavior, and this cruft leaks out into the /sys information.
773	     The file name for ".init*" may actually look like "_init*".  */
774
775	  const bool is_init = !strncmp (secname, ".init", 5);
776	  if (is_init)
777	    {
778	      if (asprintf (&sysfile, SECADDRDIRFMT "_%s",
779			    modname, &secname[1]) < 0)
780		return ENOMEM;
781	      f = fopen (sysfile, "r");
782	      free (sysfile);
783	      if (f != NULL)
784		goto ok;
785	    }
786
787	  /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1.
788	     In case that size increases in the future, look for longer
789	     truncated names first.  */
790	  size_t namelen = strlen (secname);
791	  if (namelen >= MODULE_SECT_NAME_LEN)
792	    {
793	      int len = asprintf (&sysfile, SECADDRDIRFMT "%s",
794				  modname, secname);
795	      if (len < 0)
796		return DWARF_CB_ABORT;
797	      char *end = sysfile + len;
798	      do
799		{
800		  *--end = '\0';
801		  f = fopen (sysfile, "r");
802		  if (is_init && f == NULL && errno == ENOENT)
803		    {
804		      sysfile[len - namelen] = '_';
805		      f = fopen (sysfile, "r");
806		      sysfile[len - namelen] = '.';
807		    }
808		}
809	      while (f == NULL && errno == ENOENT
810		     && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN);
811	      free (sysfile);
812
813	      if (f != NULL)
814		goto ok;
815	    }
816	}
817
818      return DWARF_CB_ABORT;
819    }
820
821 ok:
822  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
823
824  int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0
825		: ferror_unlocked (f) ? errno : ENOEXEC);
826  fclose (f);
827
828  if (result == 0)
829    return DWARF_CB_OK;
830
831  errno = result;
832  return DWARF_CB_ABORT;
833}
834INTDEF (dwfl_linux_kernel_module_section_address)
835
836int
837dwfl_linux_kernel_report_modules (Dwfl *dwfl)
838{
839  FILE *f = fopen (MODULELIST, "r");
840  if (f == NULL)
841    return errno;
842
843  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
844
845  int result = 0;
846  Dwarf_Addr modaddr;
847  unsigned long int modsz;
848  char modname[128];
849  char *line = NULL;
850  size_t linesz = 0;
851  /* We can't just use fscanf here because it's not easy to distinguish \n
852     from other whitespace so as to take the optional word following the
853     address but always stop at the end of the line.  */
854  while (getline (&line, &linesz, f) > 0
855	 && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n",
856		    modname, &modsz, &modaddr) == 3)
857    {
858      Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, modname,
859						     modaddr, modaddr + modsz);
860      if (mod == NULL)
861	{
862	  result = -1;
863	  break;
864	}
865
866      result = check_module_notes (mod);
867    }
868  free (line);
869
870  if (result == 0)
871    result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
872
873  fclose (f);
874
875  return result;
876}
877INTDEF (dwfl_linux_kernel_report_modules)
878