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