linux-kernel-modules.c revision 6258e7486eb3eed6e50005946795c5fbf73aa106
1/* Standard libdwfl callbacks for debugging the running Linux kernel.
2   Copyright (C) 2005, 2006, 2007 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#include <config.h>
51#undef	_FILE_OFFSET_BITS	/* Doesn't jibe with fts.  */
52
53#include "libdwflP.h"
54#include <inttypes.h>
55#include <errno.h>
56#include <stdio.h>
57#include <stdio_ext.h>
58#include <string.h>
59#include <stdlib.h>
60#include <sys/utsname.h>
61#include <fcntl.h>
62#include <unistd.h>
63#include <fts.h>
64
65
66#define KERNEL_MODNAME	"kernel"
67
68#define MODULEDIRFMT	"/lib/modules/%s"
69
70#define KSYMSFILE	"/proc/kallsyms"
71#define MODULELIST	"/proc/modules"
72#define	SECADDRDIRFMT	"/sys/module/%s/sections/"
73#define MODULE_SECT_NAME_LEN 32	/* Minimum any linux/module.h has had.  */
74
75
76/* Try to open the given file as it is or under the debuginfo directory.  */
77static int
78try_kernel_name (Dwfl *dwfl, char **fname)
79{
80  if (*fname == NULL)
81    return -1;
82
83  /* Don't bother trying *FNAME itself here if the path will cause it to be
84     tried because we give its own basename as DEBUGLINK_FILE.  */
85  int fd = ((((dwfl->callbacks->debuginfo_path
86	       ? *dwfl->callbacks->debuginfo_path : NULL)
87	      ?: DEFAULT_DEBUGINFO_PATH)[0] == ':') ? -1
88	    : TEMP_FAILURE_RETRY (open64 (*fname, O_RDONLY)));
89  if (fd < 0)
90    {
91      char *debugfname = NULL;
92      Dwfl_Module fakemod = { .dwfl = dwfl };
93      /* First try the file's unadorned basename as DEBUGLINK_FILE,
94	 to look for "vmlinux" files.  */
95      fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
96						 *fname, basename (*fname), 0,
97						 &debugfname);
98      if (fd < 0)
99	/* Next, let the call use the default of basename + ".debug",
100	   to look for "vmlinux.debug" files.  */
101	fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
102						   *fname, NULL, 0,
103						   &debugfname);
104      free (*fname);
105      *fname = debugfname;
106    }
107
108  return fd;
109}
110
111static inline const char *
112kernel_release (void)
113{
114  /* Cache the `uname -r` string we'll use.  */
115  static struct utsname utsname;
116  if (utsname.release[0] == '\0' && uname (&utsname) != 0)
117    return NULL;
118  return utsname.release;
119}
120
121static int
122find_kernel_elf (Dwfl *dwfl, const char *release, char **fname)
123{
124  if ((release[0] == '/'
125       ? asprintf (fname, "%s/vmlinux", release)
126       : asprintf (fname, "/boot/vmlinux-%s", release)) < 0)
127    return -1;
128
129  int fd = try_kernel_name (dwfl, fname);
130  if (fd < 0 && release[0] != '/')
131    {
132      free (*fname);
133      if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0)
134	return -1;
135      fd = try_kernel_name (dwfl, fname);
136    }
137
138  return fd;
139}
140
141static int
142report_kernel (Dwfl *dwfl, const char *release,
143	       int (*predicate) (const char *module, const char *file))
144{
145  if (dwfl == NULL)
146    return -1;
147
148  if (release == NULL)
149    {
150      release = kernel_release ();
151      if (release == NULL)
152	return errno;
153    }
154
155  char *fname;
156  int fd = find_kernel_elf (dwfl, release, &fname);
157
158  int result = 0;
159  if (fd < 0)
160    result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL))
161	      ? 0 : errno ?: ENOENT);
162  else
163    {
164      bool report = true;
165
166      if (predicate != NULL)
167	{
168	  /* Let the predicate decide whether to use this one.  */
169	  int want = (*predicate) (KERNEL_MODNAME, fname);
170	  if (want < 0)
171	    result = errno;
172	  report = want > 0;
173	}
174
175      if (report
176	  && INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME,
177				      fname, fd, 0) == NULL)
178	{
179	  close (fd);
180	  result = -1;
181	}
182    }
183
184  free (fname);
185
186  return result;
187}
188
189/* Report a kernel and all its modules found on disk, for offline use.
190   If RELEASE starts with '/', it names a directory to look in;
191   if not, it names a directory to find under /lib/modules/;
192   if null, /lib/modules/`uname -r` is used.
193   Returns zero on success, -1 if dwfl_report_module failed,
194   or an errno code if finding the files on disk failed.  */
195int
196dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
197				  int (*predicate) (const char *module,
198						    const char *file))
199{
200  /* First report the kernel.  */
201  int result = report_kernel (dwfl, release, predicate);
202  if (result == 0)
203    {
204      /* Do "find /lib/modules/RELEASE/kernel -name *.ko".  */
205
206      char *modulesdir[] = { NULL, NULL };
207      if (release[0] == '/')
208	modulesdir[0] = (char *) release;
209      else
210	{
211	  if (asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release) < 0)
212	    return errno;
213	}
214
215      FTS *fts = fts_open (modulesdir, FTS_LOGICAL | FTS_NOSTAT, NULL);
216      if (modulesdir[0] == (char *) release)
217	modulesdir[0] = NULL;
218      if (fts == NULL)
219	{
220	  free (modulesdir[0]);
221	  return errno;
222	}
223
224      FTSENT *f;
225      while ((f = fts_read (fts)) != NULL)
226	{
227	  switch (f->fts_info)
228	    {
229	    case FTS_F:
230	    case FTS_NSOK:
231	      /* See if this file name matches "*.ko".  */
232	      if (f->fts_namelen > 3
233		  && !memcmp (f->fts_name + f->fts_namelen - 3, ".ko", 4))
234		{
235		  /* We have a .ko file to report.  Following the algorithm
236		     by which the kernel makefiles set KBUILD_MODNAME, we
237		     replace all ',' or '-' with '_' in the file name and
238		     call that the module name.  Modules could well be
239		     built using different embedded names than their file
240		     names.  To handle that, we would have to look at the
241		     __this_module.name contents in the module's text.  */
242
243		  char name[f->fts_namelen - 3 + 1];
244		  for (size_t i = 0; i < f->fts_namelen - 3U; ++i)
245		    if (f->fts_name[i] == '-' || f->fts_name[i] == ',')
246		      name[i] = '_';
247		    else
248		      name[i] = f->fts_name[i];
249		  name[f->fts_namelen - 3] = '\0';
250
251		  if (predicate != NULL)
252		    {
253		      /* Let the predicate decide whether to use this one.  */
254		      int want = (*predicate) (name, f->fts_path);
255		      if (want < 0)
256			{
257			  result = -1;
258			  break;
259			}
260		      if (!want)
261			continue;
262		    }
263
264		  if (dwfl_report_offline (dwfl, name,
265					   f->fts_path, -1) == NULL)
266		    {
267		      result = -1;
268		      break;
269		    }
270		}
271	      continue;
272
273	    case FTS_ERR:
274	    case FTS_DNR:
275	    case FTS_NS:
276	      result = f->fts_errno;
277	      break;
278
279	    default:
280	      continue;
281	    }
282
283	  /* We only get here in error cases.  */
284	  break;
285	}
286      fts_close (fts);
287      free (modulesdir[0]);
288    }
289
290  return result;
291}
292INTDEF (dwfl_linux_kernel_report_offline)
293
294
295/* Grovel around to guess the bounds of the runtime kernel image.  */
296static int
297intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end)
298{
299  FILE *f = fopen (KSYMSFILE, "r");
300  if (f == NULL)
301    return errno;
302
303  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
304
305  char *line = NULL;
306  size_t linesz = 0;
307  size_t n = getline (&line, &linesz, f);
308  Dwarf_Addr first;
309  char *p = NULL;
310  int result = 0;
311  if (n > 0 && (first = strtoull (line, &p, 16)) > 0 && p > line)
312    {
313      Dwarf_Addr last = 0;
314      while ((n = getline (&line, &linesz, f)) > 1 && line[n - 2] != ']')
315	{
316	  p = NULL;
317	  last = strtoull (line, &p, 16);
318	  if (p == NULL || p == line || last == 0)
319	    {
320	      result = -1;
321	      break;
322	    }
323	}
324      if ((n == 0 && feof_unlocked (f)) || (n > 1 && line[n - 2] == ']'))
325	{
326	  Dwarf_Addr round_kernel = sysconf (_SC_PAGE_SIZE);
327	  first &= -(Dwarf_Addr) round_kernel;
328	  last += round_kernel - 1;
329	  last &= -(Dwarf_Addr) round_kernel;
330	  *start = first;
331	  *end = last;
332	  result = 0;
333	}
334    }
335  free (line);
336
337  if (result == -1)
338    result = ferror_unlocked (f) ? errno : ENOEXEC;
339
340  fclose (f);
341
342  return result;
343}
344
345int
346dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
347{
348  Dwarf_Addr start;
349  Dwarf_Addr end;
350  inline int report (void)
351    {
352      return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME,
353					 start, end) == NULL ? -1 : 0;
354    }
355
356  /* This is a bit of a kludge.  If we already reported the kernel,
357     don't bother figuring it out again--it never changes.  */
358  for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
359    if (!strcmp (m->name, KERNEL_MODNAME))
360      {
361	start = m->low_addr;
362	end = m->high_addr;
363	return report ();
364      }
365
366  /* Try to figure out the bounds of the kernel image without
367     looking for any vmlinux file.  */
368  int result = intuit_kernel_bounds (&start, &end);
369  if (result == 0)
370    return report ();
371  if (result != ENOENT)
372    return result;
373
374  /* Find the ELF file for the running kernel and dwfl_report_elf it.  */
375  return report_kernel (dwfl, NULL, NULL);
376}
377INTDEF (dwfl_linux_kernel_report_kernel)
378
379
380/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules.  */
381
382int
383dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
384			    void **userdata __attribute__ ((unused)),
385			    const char *module_name,
386			    Dwarf_Addr base __attribute__ ((unused)),
387			    char **file_name,
388			    Elf **elfp __attribute__ ((unused)))
389{
390  const char *release = kernel_release ();
391  if (release == NULL)
392    return errno;
393
394  if (!strcmp (module_name, KERNEL_MODNAME))
395    return find_kernel_elf (mod->dwfl, release, file_name);
396
397  /* Do "find /lib/modules/`uname -r`/kernel -name MODULE_NAME.ko".  */
398
399  char *modulesdir[] = { NULL, NULL };
400  if (asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release) < 0)
401    return -1;
402
403  FTS *fts = fts_open (modulesdir, FTS_LOGICAL | FTS_NOSTAT, NULL);
404  if (fts == NULL)
405    {
406      free (modulesdir[0]);
407      return -1;
408    }
409
410  size_t namelen = strlen (module_name);
411
412  /* This is a kludge.  There is no actual necessary relationship between
413     the name of the .ko file installed and the module name the kernel
414     knows it by when it's loaded.  The kernel's only idea of the module
415     name comes from the name embedded in the object's magic
416     .gnu.linkonce.this_module section.
417
418     In practice, these module names match the .ko file names except for
419     some using '_' and some using '-'.  So our cheap kludge is to look for
420     two files when either a '_' or '-' appears in a module name, one using
421     only '_' and one only using '-'.  */
422
423  char alternate_name[namelen + 1];
424  inline bool subst_name (char from, char to)
425    {
426      const char *n = memchr (module_name, from, namelen);
427      if (n == NULL)
428	return false;
429      char *a = mempcpy (alternate_name, module_name, n - module_name);
430      *a++ = to;
431      ++n;
432      const char *p;
433      while ((p = memchr (n, from, namelen - (n - module_name))) != NULL)
434	{
435	  a = mempcpy (a, n, p - n);
436	  *a++ = to;
437	  n = p + 1;
438	}
439      memcpy (a, n, namelen - (n - module_name) + 1);
440      return true;
441    }
442  if (!subst_name ('-', '_') && !subst_name ('_', '-'))
443    alternate_name[0] = '\0';
444
445  FTSENT *f;
446  int error = ENOENT;
447  while ((f = fts_read (fts)) != NULL)
448    {
449      error = ENOENT;
450      switch (f->fts_info)
451	{
452	case FTS_F:
453	case FTS_NSOK:
454	  /* See if this file name is "MODULE_NAME.ko".  */
455	  if (f->fts_namelen == namelen + 3
456	      && !memcmp (f->fts_name + namelen, ".ko", 4)
457	      && (!memcmp (f->fts_name, module_name, namelen)
458		  || !memcmp (f->fts_name, alternate_name, namelen)))
459	    {
460	      int fd = open64 (f->fts_accpath, O_RDONLY);
461	      *file_name = strdup (f->fts_path);
462	      fts_close (fts);
463	      free (modulesdir[0]);
464	      if (fd < 0)
465		free (*file_name);
466	      else if (*file_name == NULL)
467		{
468		  close (fd);
469		  fd = -1;
470		}
471	      return fd;
472	    }
473	  break;
474
475	case FTS_ERR:
476	case FTS_DNR:
477	case FTS_NS:
478	  error = f->fts_errno;
479	  break;
480
481	default:
482	  break;
483	}
484    }
485
486  fts_close (fts);
487  free (modulesdir[0]);
488  errno = error;
489  return -1;
490}
491INTDEF (dwfl_linux_kernel_find_elf)
492
493
494/* Dwfl_Callbacks.section_address for kernel modules in the running Linux.
495   We read the information from /sys/module directly.  */
496
497int
498dwfl_linux_kernel_module_section_address
499(Dwfl_Module *mod __attribute__ ((unused)),
500 void **userdata __attribute__ ((unused)),
501 const char *modname, Dwarf_Addr base __attribute__ ((unused)),
502 const char *secname, Elf32_Word shndx __attribute__ ((unused)),
503 const GElf_Shdr *shdr __attribute__ ((unused)),
504 Dwarf_Addr *addr)
505{
506  char *sysfile;
507  if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0)
508    return ENOMEM;
509
510  FILE *f = fopen (sysfile, "r");
511  free (sysfile);
512
513  if (f == NULL)
514    {
515      if (errno == ENOENT)
516	{
517	  /* The .modinfo and .data.percpu sections are never kept
518	     loaded in the kernel.  If the kernel was compiled without
519	     CONFIG_MODULE_UNLOAD, the .exit.* sections are not
520	     actually loaded at all.
521
522	     Setting *ADDR to -1 tells the caller this section is
523	     actually absent from memory.  */
524
525	  if (!strcmp (secname, ".modinfo")
526	      || !strcmp (secname, ".data.percpu")
527	      || !strncmp (secname, ".exit", 5))
528	    {
529	      *addr = (Dwarf_Addr) -1l;
530	      return DWARF_CB_OK;
531	    }
532
533	  /* The goofy PPC64 module_frob_arch_sections function tweaks
534	     the section names as a way to control other kernel code's
535	     behavior, and this cruft leaks out into the /sys information.
536	     The file name for ".init*" may actually look like "_init*".  */
537
538	  const bool is_init = !strncmp (secname, ".init", 5);
539	  if (is_init)
540	    {
541	      if (asprintf (&sysfile, SECADDRDIRFMT "_%s",
542			    modname, &secname[1]) < 0)
543		return ENOMEM;
544	      f = fopen (sysfile, "r");
545	      free (sysfile);
546	      if (f != NULL)
547		goto ok;
548	    }
549
550	  /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1.
551	     In case that size increases in the future, look for longer
552	     truncated names first.  */
553	  size_t namelen = strlen (secname);
554	  if (namelen >= MODULE_SECT_NAME_LEN)
555	    {
556	      int len = asprintf (&sysfile, SECADDRDIRFMT "%s",
557				  modname, secname);
558	      if (len < 0)
559		return ENOMEM;
560	      char *end = sysfile + len;
561	      do
562		{
563		  *--end = '\0';
564		  f = fopen (sysfile, "r");
565		  if (is_init && f == NULL && errno == ENOENT)
566		    {
567		      sysfile[len - namelen] = '_';
568		      f = fopen (sysfile, "r");
569		      sysfile[len - namelen] = '.';
570		    }
571		}
572	      while (f == NULL && errno == ENOENT
573		     && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN);
574	      free (sysfile);
575
576	      if (f != NULL)
577		goto ok;
578	    }
579	}
580
581      return DWARF_CB_ABORT;
582    }
583
584 ok:
585  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
586
587  int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0
588		: ferror_unlocked (f) ? errno : ENOEXEC);
589  fclose (f);
590
591  if (result == 0)
592    return DWARF_CB_OK;
593
594  errno = result;
595  return DWARF_CB_ABORT;
596}
597INTDEF (dwfl_linux_kernel_module_section_address)
598
599int
600dwfl_linux_kernel_report_modules (Dwfl *dwfl)
601{
602  FILE *f = fopen (MODULELIST, "r");
603  if (f == NULL)
604    return errno;
605
606  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
607
608  int result = 0;
609  Dwarf_Addr modaddr;
610  unsigned long int modsz;
611  char modname[128];
612  while (fscanf (f, "%128s %lu %*s %*s %*s %" PRIx64 "\n",
613		 modname, &modsz, &modaddr) == 3)
614    if (INTUSE(dwfl_report_module) (dwfl, modname,
615				    modaddr, modaddr + modsz) == NULL)
616      {
617	result = -1;
618	break;
619      }
620
621  if (result == 0)
622    result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
623
624  fclose (f);
625
626  return result;
627}
628INTDEF (dwfl_linux_kernel_report_modules)
629