Line data Source code
1 : /* Standard libdwfl callbacks for debugging the running Linux kernel.
2 : Copyright (C) 2005-2011, 2013, 2014, 2015 Red Hat, Inc.
3 : This file is part of elfutils.
4 :
5 : This file is free software; you can redistribute it and/or modify
6 : it under the terms of either
7 :
8 : * the GNU Lesser General Public License as published by the Free
9 : Software Foundation; either version 3 of the License, or (at
10 : your option) any later version
11 :
12 : or
13 :
14 : * the GNU General Public License as published by the Free
15 : Software Foundation; either version 2 of the License, or (at
16 : your option) any later version
17 :
18 : or both in parallel, as here.
19 :
20 : elfutils is distributed in the hope that it will be useful, but
21 : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : General Public License for more details.
24 :
25 : You should have received copies of the GNU General Public License and
26 : the GNU Lesser General Public License along with this program. If
27 : not, see <http://www.gnu.org/licenses/>. */
28 :
29 : /* In case we have a bad fts we include this before config.h because it
30 : can't handle _FILE_OFFSET_BITS.
31 : Everything we need here is fine if its declarations just come first.
32 : Also, include sys/types.h before fts. On some systems fts.h is not self
33 : contained. */
34 : #ifdef BAD_FTS
35 : #include <sys/types.h>
36 : #include <fts.h>
37 : #endif
38 :
39 : #include <config.h>
40 : #include <system.h>
41 :
42 : #include "libdwflP.h"
43 : #include <inttypes.h>
44 : #include <errno.h>
45 : #include <stdio.h>
46 : #include <stdio_ext.h>
47 : #include <string.h>
48 : #include <stdlib.h>
49 : #include <sys/utsname.h>
50 : #include <fcntl.h>
51 : #include <unistd.h>
52 :
53 : /* If fts.h is included before config.h, its indirect inclusions may not
54 : give us the right LFS aliases of these functions, so map them manually. */
55 : #ifdef BAD_FTS
56 : #ifdef _FILE_OFFSET_BITS
57 : #define open open64
58 : #define fopen fopen64
59 : #endif
60 : #else
61 : #include <sys/types.h>
62 : #include <fts.h>
63 : #endif
64 :
65 :
66 : #define KERNEL_MODNAME "kernel"
67 :
68 : #define MODULEDIRFMT "/lib/modules/%s"
69 :
70 : #define KNOTESFILE "/sys/kernel/notes"
71 : #define MODNOTESFMT "/sys/module/%s/notes"
72 : #define KSYMSFILE "/proc/kallsyms"
73 : #define MODULELIST "/proc/modules"
74 : #define SECADDRDIRFMT "/sys/module/%s/sections/"
75 : #define MODULE_SECT_NAME_LEN 32 /* Minimum any linux/module.h has had. */
76 :
77 :
78 : static const char *vmlinux_suffixes[] =
79 : {
80 : ".gz",
81 : #ifdef USE_BZLIB
82 : ".bz2",
83 : #endif
84 : #ifdef USE_LZMA
85 : ".xz",
86 : #endif
87 : };
88 :
89 : /* Try to open the given file as it is or under the debuginfo directory. */
90 : static int
91 0 : try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug)
92 : {
93 0 : if (*fname == NULL)
94 : return -1;
95 :
96 : /* Don't bother trying *FNAME itself here if the path will cause it to be
97 : tried because we give its own basename as DEBUGLINK_FILE. */
98 0 : int fd = ((((dwfl->callbacks->debuginfo_path
99 0 : ? *dwfl->callbacks->debuginfo_path : NULL)
100 0 : ?: DEFAULT_DEBUGINFO_PATH)[0] == ':') ? -1
101 0 : : TEMP_FAILURE_RETRY (open (*fname, O_RDONLY)));
102 :
103 0 : if (fd < 0)
104 : {
105 0 : Dwfl_Module fakemod = { .dwfl = dwfl };
106 :
107 0 : if (try_debug)
108 : /* Passing NULL for DEBUGLINK_FILE searches for both the basenamer
109 : "vmlinux" and the default of basename + ".debug", to look for
110 : "vmlinux.debug" files. */
111 0 : fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
112 : *fname, NULL, 0,
113 : &fakemod.debug.name);
114 : else
115 : /* Try the file's unadorned basename as DEBUGLINK_FILE,
116 : to look only for "vmlinux" files. */
117 0 : fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
118 0 : *fname, basename (*fname),
119 : 0, &fakemod.debug.name);
120 :
121 0 : if (fakemod.debug.name != NULL)
122 : {
123 0 : free (*fname);
124 0 : *fname = fakemod.debug.name;
125 : }
126 : }
127 :
128 0 : if (fd < 0)
129 0 : for (size_t i = 0;
130 : i < sizeof vmlinux_suffixes / sizeof vmlinux_suffixes[0];
131 0 : ++i)
132 : {
133 : char *zname;
134 0 : if (asprintf (&zname, "%s%s", *fname, vmlinux_suffixes[i]) > 0)
135 : {
136 0 : fd = TEMP_FAILURE_RETRY (open (zname, O_RDONLY));
137 0 : if (fd < 0)
138 0 : free (zname);
139 : else
140 : {
141 0 : free (*fname);
142 0 : *fname = zname;
143 : }
144 : }
145 : }
146 :
147 0 : if (fd < 0)
148 : {
149 0 : free (*fname);
150 0 : *fname = NULL;
151 : }
152 :
153 : return fd;
154 : }
155 :
156 : static inline const char *
157 : kernel_release (void)
158 : {
159 : #ifdef __linux__
160 : /* Cache the `uname -r` string we'll use. */
161 : static struct utsname utsname;
162 0 : if (utsname.release[0] == '\0' && uname (&utsname) != 0)
163 : return NULL;
164 : return utsname.release;
165 : #else
166 : /* Used for finding the running linux kernel, which isn't supported
167 : on non-linux kernel systems. */
168 : errno = ENOTSUP;
169 : return NULL;
170 : #endif
171 : }
172 :
173 : static int
174 0 : find_kernel_elf (Dwfl *dwfl, const char *release, char **fname)
175 : {
176 0 : if ((release[0] == '/'
177 0 : ? asprintf (fname, "%s/vmlinux", release)
178 0 : : asprintf (fname, "/boot/vmlinux-%s", release)) < 0)
179 : return -1;
180 :
181 0 : int fd = try_kernel_name (dwfl, fname, true);
182 0 : if (fd < 0 && release[0] != '/')
183 : {
184 0 : free (*fname);
185 0 : if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0)
186 : return -1;
187 0 : fd = try_kernel_name (dwfl, fname, true);
188 : }
189 :
190 : return fd;
191 : }
192 :
193 : static int
194 0 : get_release (Dwfl *dwfl, const char **release)
195 : {
196 0 : if (dwfl == NULL)
197 : return -1;
198 :
199 0 : const char *release_string = release == NULL ? NULL : *release;
200 0 : if (release_string == NULL)
201 : {
202 0 : release_string = kernel_release ();
203 0 : if (release_string == NULL)
204 0 : return errno;
205 0 : if (release != NULL)
206 0 : *release = release_string;
207 : }
208 :
209 : return 0;
210 : }
211 :
212 : static int
213 0 : report_kernel (Dwfl *dwfl, const char **release,
214 : int (*predicate) (const char *module, const char *file))
215 : {
216 0 : int result = get_release (dwfl, release);
217 0 : if (unlikely (result != 0))
218 : return result;
219 :
220 : char *fname;
221 0 : int fd = find_kernel_elf (dwfl, *release, &fname);
222 :
223 0 : if (fd < 0)
224 0 : result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL))
225 0 : ? 0 : errno ?: ENOENT);
226 : else
227 : {
228 0 : bool report = true;
229 :
230 0 : if (predicate != NULL)
231 : {
232 : /* Let the predicate decide whether to use this one. */
233 0 : int want = (*predicate) (KERNEL_MODNAME, fname);
234 0 : if (want < 0)
235 0 : result = errno;
236 0 : report = want > 0;
237 : }
238 :
239 0 : if (report)
240 : {
241 : /* Note that on some architectures (e.g. x86_64) the vmlinux
242 : is ET_EXEC, while on others (e.g. ppc64) it is ET_DYN.
243 : In both cases the phdr p_vaddr load address will be non-zero.
244 : We want the image to be placed as if it was ET_DYN, so
245 : pass true for add_p_vaddr which will do the right thing
246 : (in combination with a zero base) in either case. */
247 0 : Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME,
248 : fname, fd, 0, true);
249 0 : if (mod == NULL)
250 : result = -1;
251 : else
252 : /* The kernel is ET_EXEC, but always treat it as relocatable. */
253 0 : mod->e_type = ET_DYN;
254 : }
255 :
256 0 : free (fname);
257 :
258 0 : if (!report || result < 0)
259 0 : close (fd);
260 : }
261 :
262 : return result;
263 : }
264 :
265 : /* Look for a kernel debug archive. If we find one, report all its modules.
266 : If not, return ENOENT. */
267 : static int
268 0 : report_kernel_archive (Dwfl *dwfl, const char **release,
269 : int (*predicate) (const char *module, const char *file))
270 : {
271 0 : int result = get_release (dwfl, release);
272 0 : if (unlikely (result != 0))
273 : return result;
274 :
275 : char *archive;
276 0 : int res = (((*release)[0] == '/')
277 0 : ? asprintf (&archive, "%s/debug.a", *release)
278 0 : : asprintf (&archive, MODULEDIRFMT "/debug.a", *release));
279 0 : if (unlikely (res < 0))
280 : return ENOMEM;
281 :
282 0 : int fd = try_kernel_name (dwfl, &archive, false);
283 0 : if (fd < 0)
284 0 : result = errno ?: ENOENT;
285 : else
286 : {
287 : /* We have the archive file open! */
288 0 : Dwfl_Module *last = __libdwfl_report_offline (dwfl, NULL, archive, fd,
289 : true, predicate);
290 0 : if (unlikely (last == NULL))
291 : result = -1;
292 : else
293 : {
294 : /* Find the kernel and move it to the head of the list. */
295 0 : Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
296 0 : for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
297 0 : if (!m->gc && m->e_type != ET_REL && !strcmp (m->name, "kernel"))
298 : {
299 0 : *prevp = m->next;
300 0 : m->next = *tailp;
301 0 : *tailp = m;
302 0 : break;
303 : }
304 : }
305 : }
306 :
307 0 : free (archive);
308 0 : return result;
309 : }
310 :
311 : static size_t
312 0 : check_suffix (const FTSENT *f, size_t namelen)
313 : {
314 : #define TRY(sfx) \
315 : if ((namelen ? f->fts_namelen == namelen + sizeof sfx - 1 \
316 : : f->fts_namelen >= sizeof sfx) \
317 : && !memcmp (f->fts_name + f->fts_namelen - (sizeof sfx - 1), \
318 : sfx, sizeof sfx)) \
319 : return sizeof sfx - 1
320 :
321 0 : TRY (".ko");
322 0 : TRY (".ko.gz");
323 : #if USE_BZLIB
324 0 : TRY (".ko.bz2");
325 : #endif
326 : #if USE_LZMA
327 0 : TRY (".ko.xz");
328 : #endif
329 :
330 0 : return 0;
331 :
332 : #undef TRY
333 : }
334 :
335 : /* Report a kernel and all its modules found on disk, for offline use.
336 : If RELEASE starts with '/', it names a directory to look in;
337 : if not, it names a directory to find under /lib/modules/;
338 : if null, /lib/modules/`uname -r` is used.
339 : Returns zero on success, -1 if dwfl_report_module failed,
340 : or an errno code if finding the files on disk failed. */
341 : int
342 0 : dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
343 : int (*predicate) (const char *module,
344 : const char *file))
345 : {
346 0 : int result = report_kernel_archive (dwfl, &release, predicate);
347 0 : if (result != ENOENT)
348 : return result;
349 :
350 : /* First report the kernel. */
351 0 : result = report_kernel (dwfl, &release, predicate);
352 0 : if (result == 0)
353 : {
354 : /* Do "find /lib/modules/RELEASE -name *.ko". */
355 :
356 0 : char *modulesdir[] = { NULL, NULL };
357 0 : if (release[0] == '/')
358 0 : modulesdir[0] = (char *) release;
359 : else
360 : {
361 0 : if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
362 0 : return errno;
363 : }
364 :
365 0 : FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
366 0 : if (modulesdir[0] == (char *) release)
367 0 : modulesdir[0] = NULL;
368 0 : if (fts == NULL)
369 : {
370 0 : free (modulesdir[0]);
371 0 : return errno;
372 : }
373 :
374 : FTSENT *f;
375 0 : while ((f = fts_read (fts)) != NULL)
376 : {
377 : /* Skip a "source" subtree, which tends to be large.
378 : This insane hard-coding of names is what depmod does too. */
379 0 : if (f->fts_namelen == sizeof "source" - 1
380 0 : && !strcmp (f->fts_name, "source"))
381 : {
382 0 : fts_set (fts, f, FTS_SKIP);
383 0 : continue;
384 : }
385 :
386 0 : switch (f->fts_info)
387 : {
388 : case FTS_F:
389 : case FTS_SL:
390 : case FTS_NSOK:;
391 : /* See if this file name matches "*.ko". */
392 0 : const size_t suffix = check_suffix (f, 0);
393 0 : if (suffix)
394 : {
395 : /* We have a .ko file to report. Following the algorithm
396 : by which the kernel makefiles set KBUILD_MODNAME, we
397 : replace all ',' or '-' with '_' in the file name and
398 : call that the module name. Modules could well be
399 : built using different embedded names than their file
400 : names. To handle that, we would have to look at the
401 : __this_module.name contents in the module's text. */
402 :
403 0 : char *name = strndup (f->fts_name, f->fts_namelen - suffix);
404 0 : if (unlikely (name == NULL))
405 : {
406 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
407 0 : result = -1;
408 0 : break;
409 : }
410 0 : for (size_t i = 0; i < f->fts_namelen - suffix; ++i)
411 0 : if (name[i] == '-' || name[i] == ',')
412 0 : name[i] = '_';
413 :
414 0 : if (predicate != NULL)
415 : {
416 : /* Let the predicate decide whether to use this one. */
417 0 : int want = (*predicate) (name, f->fts_path);
418 0 : if (want < 0)
419 : {
420 0 : result = -1;
421 0 : free (name);
422 0 : break;
423 : }
424 0 : if (!want)
425 : {
426 0 : free (name);
427 0 : continue;
428 : }
429 : }
430 :
431 0 : if (dwfl_report_offline (dwfl, name, f->fts_path, -1) == NULL)
432 : {
433 0 : free (name);
434 0 : result = -1;
435 0 : break;
436 : }
437 0 : free (name);
438 : }
439 0 : continue;
440 :
441 : case FTS_ERR:
442 : case FTS_DNR:
443 : case FTS_NS:
444 0 : result = f->fts_errno;
445 0 : break;
446 :
447 : case FTS_SLNONE:
448 : default:
449 0 : continue;
450 : }
451 :
452 : /* We only get here in error cases. */
453 : break;
454 : }
455 0 : fts_close (fts);
456 0 : free (modulesdir[0]);
457 : }
458 :
459 : return result;
460 : }
461 : INTDEF (dwfl_linux_kernel_report_offline)
462 :
463 :
464 : /* State of read_address used by intuit_kernel_bounds. */
465 : struct read_address_state {
466 : FILE *f;
467 : char *line;
468 : size_t linesz;
469 : size_t n;
470 : char *p;
471 : const char *type;
472 : };
473 :
474 : static inline bool
475 0 : read_address (struct read_address_state *state, Dwarf_Addr *addr)
476 : {
477 0 : if ((state->n = getline (&state->line, &state->linesz, state->f)) < 1 ||
478 0 : state->line[state->n - 2] == ']')
479 : return false;
480 0 : *addr = strtoull (state->line, &state->p, 16);
481 0 : state->p += strspn (state->p, " \t");
482 0 : state->type = strsep (&state->p, " \t\n");
483 0 : if (state->type == NULL)
484 : return false;
485 0 : return state->p != NULL && state->p != state->line;
486 : }
487 :
488 :
489 : /* Grovel around to guess the bounds of the runtime kernel image. */
490 : static int
491 0 : intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes)
492 : {
493 0 : struct read_address_state state = { NULL, NULL, 0, 0, NULL, NULL };
494 :
495 0 : state.f = fopen (KSYMSFILE, "r");
496 0 : if (state.f == NULL)
497 0 : return errno;
498 :
499 0 : (void) __fsetlocking (state.f, FSETLOCKING_BYCALLER);
500 :
501 0 : *notes = 0;
502 :
503 : int result;
504 : do
505 0 : result = read_address (&state, start) ? 0 : -1;
506 0 : while (result == 0 && strchr ("TtRr", *state.type) == NULL);
507 :
508 0 : if (result == 0)
509 : {
510 0 : *end = *start;
511 0 : while (read_address (&state, end))
512 0 : if (*notes == 0 && !strcmp (state.p, "__start_notes\n"))
513 0 : *notes = *end;
514 :
515 0 : Dwarf_Addr round_kernel = sysconf (_SC_PAGESIZE);
516 0 : *start &= -(Dwarf_Addr) round_kernel;
517 0 : *end += round_kernel - 1;
518 0 : *end &= -(Dwarf_Addr) round_kernel;
519 0 : if (*start >= *end || *end - *start < round_kernel)
520 0 : result = -1;
521 : }
522 0 : free (state.line);
523 :
524 0 : if (result == -1)
525 0 : result = ferror_unlocked (state.f) ? errno : ENOEXEC;
526 :
527 0 : fclose (state.f);
528 :
529 0 : return result;
530 : }
531 :
532 :
533 : /* Look for a build ID note in NOTESFILE and associate the ID with MOD. */
534 : static int
535 0 : check_notes (Dwfl_Module *mod, const char *notesfile,
536 : Dwarf_Addr vaddr, const char *secname)
537 : {
538 0 : int fd = open (notesfile, O_RDONLY);
539 0 : if (fd < 0)
540 : return 1;
541 :
542 : assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr));
543 : assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr));
544 : union
545 : {
546 : GElf_Nhdr nhdr;
547 : unsigned char data[8192];
548 : } buf;
549 :
550 0 : ssize_t n = read (fd, buf.data, sizeof buf);
551 0 : close (fd);
552 :
553 0 : if (n <= 0)
554 : return 1;
555 :
556 : unsigned char *p = buf.data;
557 0 : while (p < &buf.data[n])
558 : {
559 : /* No translation required since we are reading the native kernel. */
560 0 : GElf_Nhdr *nhdr = (void *) p;
561 0 : p += sizeof *nhdr;
562 0 : unsigned char *name = p;
563 0 : p += (nhdr->n_namesz + 3) & -4U;
564 0 : unsigned char *bits = p;
565 0 : p += (nhdr->n_descsz + 3) & -4U;
566 :
567 0 : if (p <= &buf.data[n]
568 0 : && nhdr->n_type == NT_GNU_BUILD_ID
569 0 : && nhdr->n_namesz == sizeof "GNU"
570 0 : && !memcmp (name, "GNU", sizeof "GNU"))
571 : {
572 : /* Found it. For a module we must figure out its VADDR now. */
573 :
574 0 : if (secname != NULL
575 0 : && (INTUSE(dwfl_linux_kernel_module_section_address)
576 0 : (mod, NULL, mod->name, 0, secname, 0, NULL, &vaddr) != 0
577 0 : || vaddr == (GElf_Addr) -1l))
578 0 : vaddr = 0;
579 :
580 0 : if (vaddr != 0)
581 0 : vaddr += bits - buf.data;
582 0 : return INTUSE(dwfl_module_report_build_id) (mod, bits,
583 0 : nhdr->n_descsz, vaddr);
584 : }
585 : }
586 :
587 : return 0;
588 : }
589 :
590 : /* Look for a build ID for the kernel. */
591 : static int
592 : check_kernel_notes (Dwfl_Module *kernelmod, GElf_Addr vaddr)
593 : {
594 0 : return check_notes (kernelmod, KNOTESFILE, vaddr, NULL) < 0 ? -1 : 0;
595 : }
596 :
597 : /* Look for a build ID for a loaded kernel module. */
598 : static int
599 0 : check_module_notes (Dwfl_Module *mod)
600 : {
601 0 : char *dirs[2] = { NULL, NULL };
602 0 : if (asprintf (&dirs[0], MODNOTESFMT, mod->name) < 0)
603 : return ENOMEM;
604 :
605 0 : FTS *fts = fts_open (dirs, FTS_NOSTAT | FTS_LOGICAL, NULL);
606 0 : if (fts == NULL)
607 : {
608 0 : free (dirs[0]);
609 0 : return 0;
610 : }
611 :
612 : int result = 0;
613 : FTSENT *f;
614 0 : while ((f = fts_read (fts)) != NULL)
615 : {
616 0 : switch (f->fts_info)
617 : {
618 : case FTS_F:
619 : case FTS_SL:
620 : case FTS_NSOK:
621 0 : result = check_notes (mod, f->fts_accpath, 0, f->fts_name);
622 0 : if (result > 0) /* Nothing found. */
623 : {
624 0 : result = 0;
625 0 : continue;
626 : }
627 : break;
628 :
629 : case FTS_ERR:
630 : case FTS_DNR:
631 0 : result = f->fts_errno;
632 0 : break;
633 :
634 : case FTS_NS:
635 : case FTS_SLNONE:
636 : default:
637 0 : continue;
638 : }
639 :
640 : /* We only get here when finished or in error cases. */
641 : break;
642 : }
643 0 : fts_close (fts);
644 0 : free (dirs[0]);
645 :
646 0 : return result;
647 : }
648 :
649 : int
650 0 : dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
651 : {
652 0 : Dwarf_Addr start = 0;
653 0 : Dwarf_Addr end = 0;
654 :
655 : #define report() \
656 : (INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end))
657 :
658 : /* This is a bit of a kludge. If we already reported the kernel,
659 : don't bother figuring it out again--it never changes. */
660 0 : for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
661 0 : if (!strcmp (m->name, KERNEL_MODNAME))
662 : {
663 0 : start = m->low_addr;
664 0 : end = m->high_addr;
665 0 : return report () == NULL ? -1 : 0;
666 : }
667 :
668 : /* Try to figure out the bounds of the kernel image without
669 : looking for any vmlinux file. */
670 : Dwarf_Addr notes;
671 : /* The compiler cannot deduce that if intuit_kernel_bounds returns
672 : zero NOTES will be initialized. Fake the initialization. */
673 0 : asm ("" : "=m" (notes));
674 0 : int result = intuit_kernel_bounds (&start, &end, ¬es);
675 0 : if (result == 0)
676 : {
677 0 : Dwfl_Module *mod = report ();
678 0 : return unlikely (mod == NULL) ? -1 : check_kernel_notes (mod, notes);
679 : }
680 0 : if (result != ENOENT)
681 : return result;
682 :
683 : /* Find the ELF file for the running kernel and dwfl_report_elf it. */
684 0 : return report_kernel (dwfl, NULL, NULL);
685 : }
686 : INTDEF (dwfl_linux_kernel_report_kernel)
687 :
688 :
689 : static inline bool
690 0 : subst_name (char from, char to,
691 : const char * const module_name,
692 : char * const alternate_name,
693 : const size_t namelen)
694 : {
695 0 : const char *n = memchr (module_name, from, namelen);
696 0 : if (n == NULL)
697 : return false;
698 0 : char *a = mempcpy (alternate_name, module_name, n - module_name);
699 0 : *a++ = to;
700 0 : ++n;
701 : const char *p;
702 0 : while ((p = memchr (n, from, namelen - (n - module_name))) != NULL)
703 : {
704 0 : a = mempcpy (a, n, p - n);
705 0 : *a++ = to;
706 0 : n = p + 1;
707 : }
708 0 : memcpy (a, n, namelen - (n - module_name) + 1);
709 0 : return true;
710 : }
711 :
712 : /* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules. */
713 :
714 : int
715 0 : dwfl_linux_kernel_find_elf (Dwfl_Module *mod,
716 : void **userdata __attribute__ ((unused)),
717 : const char *module_name,
718 : Dwarf_Addr base __attribute__ ((unused)),
719 : char **file_name, Elf **elfp)
720 : {
721 0 : if (mod->build_id_len > 0)
722 : {
723 0 : int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0,
724 : file_name, elfp);
725 0 : if (fd >= 0 || mod->main.elf != NULL || errno != 0)
726 : return fd;
727 : }
728 :
729 0 : const char *release = kernel_release ();
730 0 : if (release == NULL)
731 0 : return errno;
732 :
733 0 : if (!strcmp (module_name, KERNEL_MODNAME))
734 0 : return find_kernel_elf (mod->dwfl, release, file_name);
735 :
736 : /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */
737 :
738 0 : char *modulesdir[] = { NULL, NULL };
739 0 : if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
740 : return -1;
741 :
742 0 : FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
743 0 : if (fts == NULL)
744 : {
745 0 : free (modulesdir[0]);
746 0 : return -1;
747 : }
748 :
749 0 : size_t namelen = strlen (module_name);
750 :
751 : /* This is a kludge. There is no actual necessary relationship between
752 : the name of the .ko file installed and the module name the kernel
753 : knows it by when it's loaded. The kernel's only idea of the module
754 : name comes from the name embedded in the object's magic
755 : .gnu.linkonce.this_module section.
756 :
757 : In practice, these module names match the .ko file names except for
758 : some using '_' and some using '-'. So our cheap kludge is to look for
759 : two files when either a '_' or '-' appears in a module name, one using
760 : only '_' and one only using '-'. */
761 :
762 0 : char *alternate_name = malloc (namelen + 1);
763 0 : if (unlikely (alternate_name == NULL))
764 : {
765 0 : free (modulesdir[0]);
766 0 : return ENOMEM;
767 : }
768 0 : if (!subst_name ('-', '_', module_name, alternate_name, namelen) &&
769 0 : !subst_name ('_', '-', module_name, alternate_name, namelen))
770 0 : alternate_name[0] = '\0';
771 :
772 : FTSENT *f;
773 : int error = ENOENT;
774 0 : while ((f = fts_read (fts)) != NULL)
775 : {
776 : /* Skip a "source" subtree, which tends to be large.
777 : This insane hard-coding of names is what depmod does too. */
778 0 : if (f->fts_namelen == sizeof "source" - 1
779 0 : && !strcmp (f->fts_name, "source"))
780 : {
781 0 : fts_set (fts, f, FTS_SKIP);
782 0 : continue;
783 : }
784 :
785 0 : error = ENOENT;
786 0 : switch (f->fts_info)
787 : {
788 : case FTS_F:
789 : case FTS_SL:
790 : case FTS_NSOK:
791 : /* See if this file name is "MODULE_NAME.ko". */
792 0 : if (check_suffix (f, namelen)
793 0 : && (!memcmp (f->fts_name, module_name, namelen)
794 0 : || !memcmp (f->fts_name, alternate_name, namelen)))
795 : {
796 0 : int fd = open (f->fts_accpath, O_RDONLY);
797 0 : *file_name = strdup (f->fts_path);
798 0 : fts_close (fts);
799 0 : free (modulesdir[0]);
800 0 : free (alternate_name);
801 0 : if (fd < 0)
802 0 : free (*file_name);
803 0 : else if (*file_name == NULL)
804 : {
805 0 : close (fd);
806 0 : fd = -1;
807 : }
808 : return fd;
809 : }
810 : break;
811 :
812 : case FTS_ERR:
813 : case FTS_DNR:
814 : case FTS_NS:
815 0 : error = f->fts_errno;
816 0 : break;
817 :
818 : case FTS_SLNONE:
819 : default:
820 : break;
821 : }
822 : }
823 :
824 0 : fts_close (fts);
825 0 : free (modulesdir[0]);
826 0 : free (alternate_name);
827 0 : errno = error;
828 0 : return -1;
829 : }
830 : INTDEF (dwfl_linux_kernel_find_elf)
831 :
832 :
833 : /* Dwfl_Callbacks.section_address for kernel modules in the running Linux.
834 : We read the information from /sys/module directly. */
835 :
836 : int
837 0 : dwfl_linux_kernel_module_section_address
838 : (Dwfl_Module *mod __attribute__ ((unused)),
839 : void **userdata __attribute__ ((unused)),
840 : const char *modname, Dwarf_Addr base __attribute__ ((unused)),
841 : const char *secname, Elf32_Word shndx __attribute__ ((unused)),
842 : const GElf_Shdr *shdr __attribute__ ((unused)),
843 : Dwarf_Addr *addr)
844 : {
845 : char *sysfile;
846 0 : if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0)
847 : return DWARF_CB_ABORT;
848 :
849 0 : FILE *f = fopen (sysfile, "r");
850 0 : free (sysfile);
851 :
852 0 : if (f == NULL)
853 : {
854 0 : if (errno == ENOENT)
855 : {
856 : /* The .modinfo and .data.percpu sections are never kept
857 : loaded in the kernel. If the kernel was compiled without
858 : CONFIG_MODULE_UNLOAD, the .exit.* sections are not
859 : actually loaded at all.
860 :
861 : Setting *ADDR to -1 tells the caller this section is
862 : actually absent from memory. */
863 :
864 0 : if (!strcmp (secname, ".modinfo")
865 0 : || !strcmp (secname, ".data.percpu")
866 0 : || !strncmp (secname, ".exit", 5))
867 : {
868 0 : *addr = (Dwarf_Addr) -1l;
869 0 : return DWARF_CB_OK;
870 : }
871 :
872 : /* The goofy PPC64 module_frob_arch_sections function tweaks
873 : the section names as a way to control other kernel code's
874 : behavior, and this cruft leaks out into the /sys information.
875 : The file name for ".init*" may actually look like "_init*". */
876 :
877 0 : const bool is_init = !strncmp (secname, ".init", 5);
878 0 : if (is_init)
879 : {
880 0 : if (asprintf (&sysfile, SECADDRDIRFMT "_%s",
881 : modname, &secname[1]) < 0)
882 : return ENOMEM;
883 0 : f = fopen (sysfile, "r");
884 0 : free (sysfile);
885 0 : if (f != NULL)
886 : goto ok;
887 : }
888 :
889 : /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1.
890 : In case that size increases in the future, look for longer
891 : truncated names first. */
892 0 : size_t namelen = strlen (secname);
893 0 : if (namelen >= MODULE_SECT_NAME_LEN)
894 : {
895 0 : int len = asprintf (&sysfile, SECADDRDIRFMT "%s",
896 : modname, secname);
897 0 : if (len < 0)
898 : return DWARF_CB_ABORT;
899 0 : char *end = sysfile + len;
900 : do
901 : {
902 0 : *--end = '\0';
903 0 : f = fopen (sysfile, "r");
904 0 : if (is_init && f == NULL && errno == ENOENT)
905 : {
906 0 : sysfile[len - namelen] = '_';
907 0 : f = fopen (sysfile, "r");
908 0 : sysfile[len - namelen] = '.';
909 : }
910 : }
911 0 : while (f == NULL && errno == ENOENT
912 0 : && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN);
913 0 : free (sysfile);
914 :
915 0 : if (f != NULL)
916 : goto ok;
917 : }
918 : }
919 :
920 : return DWARF_CB_ABORT;
921 : }
922 :
923 : ok:
924 0 : (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
925 :
926 0 : int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0
927 0 : : ferror_unlocked (f) ? errno : ENOEXEC);
928 0 : fclose (f);
929 :
930 0 : if (result == 0)
931 : return DWARF_CB_OK;
932 :
933 0 : errno = result;
934 0 : return DWARF_CB_ABORT;
935 : }
936 : INTDEF (dwfl_linux_kernel_module_section_address)
937 :
938 : int
939 0 : dwfl_linux_kernel_report_modules (Dwfl *dwfl)
940 : {
941 0 : FILE *f = fopen (MODULELIST, "r");
942 0 : if (f == NULL)
943 0 : return errno;
944 :
945 0 : (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
946 :
947 0 : int result = 0;
948 : Dwarf_Addr modaddr;
949 : unsigned long int modsz;
950 : char modname[128];
951 0 : char *line = NULL;
952 0 : size_t linesz = 0;
953 : /* We can't just use fscanf here because it's not easy to distinguish \n
954 : from other whitespace so as to take the optional word following the
955 : address but always stop at the end of the line. */
956 0 : while (getline (&line, &linesz, f) > 0
957 0 : && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n",
958 : modname, &modsz, &modaddr) == 3)
959 : {
960 0 : Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, modname,
961 : modaddr, modaddr + modsz);
962 0 : if (mod == NULL)
963 : {
964 : result = -1;
965 : break;
966 : }
967 :
968 0 : result = check_module_notes (mod);
969 : }
970 0 : free (line);
971 :
972 0 : if (result == 0)
973 0 : result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
974 :
975 0 : fclose (f);
976 :
977 0 : return result;
978 : }
979 : INTDEF (dwfl_linux_kernel_report_modules)
|