• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
try_kernel_name(Dwfl * dwfl,char ** fname,bool try_debug)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 *
kernel_release(void)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
find_kernel_elf(Dwfl * dwfl,const char * release,char ** fname)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
get_release(Dwfl * dwfl,const char ** release)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
report_kernel(Dwfl * dwfl,const char ** release,int (* predicate)(const char * module,const char * file))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
report_kernel_archive(Dwfl * dwfl,const char ** release,int (* predicate)(const char * module,const char * file))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
dwfl_linux_kernel_report_offline(Dwfl * dwfl,const char * release,int (* predicate)(const char * module,const char * file))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 }
INTDEF(dwfl_linux_kernel_report_offline)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
check_notes(Dwfl_Module * mod,const char * notesfile,Dwarf_Addr vaddr,const char * secname)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
check_kernel_notes(Dwfl_Module * kernelmod,GElf_Addr vaddr)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
check_module_notes(Dwfl_Module * mod)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
dwfl_linux_kernel_report_kernel(Dwfl * dwfl)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 }
INTDEF(dwfl_linux_kernel_report_kernel)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 }
INTDEF(dwfl_linux_kernel_find_elf)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 }
INTDEF(dwfl_linux_kernel_module_section_address)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