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