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.  */
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
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.  */
263int
264dwfl_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}
366INTDEF (dwfl_linux_kernel_report_offline)
367
368
369/* Grovel around to guess the bounds of the runtime kernel image.  */
370static int
371intuit_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.  */
431static int
432check_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.  */
488static int
489check_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.  */
495static int
496check_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
546int
547dwfl_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}
584INTDEF (dwfl_linux_kernel_report_kernel)
585
586
587/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules.  */
588
589int
590dwfl_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}
707INTDEF (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
713int
714dwfl_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}
813INTDEF (dwfl_linux_kernel_module_section_address)
814
815int
816dwfl_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}
856INTDEF (dwfl_linux_kernel_report_modules)
857