linux-kernel-modules.c revision e4c22ea004c02a58f5db5eb53794275344c17958
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 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/* Try to open the given file as it is or under the debuginfo directory. */ 79static int 80try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug) 81{ 82 if (*fname == NULL) 83 return -1; 84 85 /* Don't bother trying *FNAME itself here if the path will cause it to be 86 tried because we give its own basename as DEBUGLINK_FILE. */ 87 int fd = ((((dwfl->callbacks->debuginfo_path 88 ? *dwfl->callbacks->debuginfo_path : NULL) 89 ?: DEFAULT_DEBUGINFO_PATH)[0] == ':') ? -1 90 : TEMP_FAILURE_RETRY (open64 (*fname, O_RDONLY))); 91 if (fd < 0) 92 { 93 char *debugfname = NULL; 94 Dwfl_Module fakemod = { .dwfl = dwfl }; 95 /* First try the file's unadorned basename as DEBUGLINK_FILE, 96 to look for "vmlinux" files. */ 97 fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0, 98 *fname, basename (*fname), 0, 99 &debugfname); 100 if (fd < 0 && try_debug) 101 /* Next, let the call use the default of basename + ".debug", 102 to look for "vmlinux.debug" files. */ 103 fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0, 104 *fname, NULL, 0, 105 &debugfname); 106 free (*fname); 107 *fname = debugfname; 108 } 109 110 return fd; 111} 112 113static inline const char * 114kernel_release (void) 115{ 116 /* Cache the `uname -r` string we'll use. */ 117 static struct utsname utsname; 118 if (utsname.release[0] == '\0' && uname (&utsname) != 0) 119 return NULL; 120 return utsname.release; 121} 122 123static int 124find_kernel_elf (Dwfl *dwfl, const char *release, char **fname) 125{ 126 if ((release[0] == '/' 127 ? asprintf (fname, "%s/vmlinux", release) 128 : asprintf (fname, "/boot/vmlinux-%s", release)) < 0) 129 return -1; 130 131 int fd = try_kernel_name (dwfl, fname, true); 132 if (fd < 0 && release[0] != '/') 133 { 134 free (*fname); 135 if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0) 136 return -1; 137 fd = try_kernel_name (dwfl, fname, true); 138 } 139 140 return fd; 141} 142 143static int 144get_release (Dwfl *dwfl, const char **release) 145{ 146 if (dwfl == NULL) 147 return -1; 148 149 const char *release_string = release == NULL ? NULL : *release; 150 if (release_string == NULL) 151 { 152 release_string = kernel_release (); 153 if (release_string == NULL) 154 return errno; 155 if (release != NULL) 156 *release = release_string; 157 } 158 159 return 0; 160} 161 162static int 163report_kernel (Dwfl *dwfl, const char **release, 164 int (*predicate) (const char *module, const char *file)) 165{ 166 int result = get_release (dwfl, release); 167 if (unlikely (result != 0)) 168 return result; 169 170 char *fname; 171 int fd = find_kernel_elf (dwfl, *release, &fname); 172 173 if (fd < 0) 174 result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL)) 175 ? 0 : errno ?: ENOENT); 176 else 177 { 178 bool report = true; 179 180 if (predicate != NULL) 181 { 182 /* Let the predicate decide whether to use this one. */ 183 int want = (*predicate) (KERNEL_MODNAME, fname); 184 if (want < 0) 185 result = errno; 186 report = want > 0; 187 } 188 189 if (report) 190 { 191 Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME, 192 fname, fd, 0); 193 if (mod == NULL) 194 result = -1; 195 196 /* The kernel is ET_EXEC, but always treat it as relocatable. */ 197 mod->e_type = ET_DYN; 198 } 199 200 if (!report || result < 0) 201 close (fd); 202 } 203 204 free (fname); 205 206 return result; 207} 208 209/* Look for a kernel debug archive. If we find one, report all its modules. 210 If not, return ENOENT. */ 211static int 212report_kernel_archive (Dwfl *dwfl, const char **release, 213 int (*predicate) (const char *module, const char *file)) 214{ 215 int result = get_release (dwfl, release); 216 if (unlikely (result != 0)) 217 return result; 218 219 char *archive; 220 if (unlikely ((*release)[0] == '/' 221 ? asprintf (&archive, "%s/debug.a", *release) 222 : asprintf (&archive, MODULEDIRFMT "/debug.a", *release)) < 0) 223 return ENOMEM; 224 225 int fd = try_kernel_name (dwfl, &archive, false); 226 if (fd < 0) 227 result = errno ?: ENOENT; 228 else 229 { 230 /* We have the archive file open! */ 231 Dwfl_Module *last = __libdwfl_report_offline (dwfl, NULL, archive, fd, 232 true, predicate); 233 if (unlikely (last == NULL)) 234 result = -1; 235 else 236 { 237 /* Find the kernel and move it to the head of the list. */ 238 Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; 239 for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) 240 if (!m->gc && m->e_type != ET_REL && !strcmp (m->name, "kernel")) 241 { 242 *prevp = m->next; 243 m->next = *tailp; 244 *tailp = m; 245 break; 246 } 247 } 248 } 249 250 free (archive); 251 return result; 252} 253 254/* Report a kernel and all its modules found on disk, for offline use. 255 If RELEASE starts with '/', it names a directory to look in; 256 if not, it names a directory to find under /lib/modules/; 257 if null, /lib/modules/`uname -r` is used. 258 Returns zero on success, -1 if dwfl_report_module failed, 259 or an errno code if finding the files on disk failed. */ 260int 261dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, 262 int (*predicate) (const char *module, 263 const char *file)) 264{ 265 int result = report_kernel_archive (dwfl, &release, predicate); 266 if (result != ENOENT) 267 return result; 268 269 /* First report the kernel. */ 270 result = report_kernel (dwfl, &release, predicate); 271 if (result == 0) 272 { 273 /* Do "find /lib/modules/RELEASE -name *.ko". */ 274 275 char *modulesdir[] = { NULL, NULL }; 276 if (release[0] == '/') 277 modulesdir[0] = (char *) release; 278 else 279 { 280 if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0) 281 return errno; 282 } 283 284 FTS *fts = fts_open (modulesdir, FTS_NOSTAT, NULL); 285 if (modulesdir[0] == (char *) release) 286 modulesdir[0] = NULL; 287 if (fts == NULL) 288 { 289 free (modulesdir[0]); 290 return errno; 291 } 292 293 FTSENT *f; 294 while ((f = fts_read (fts)) != NULL) 295 { 296 switch (f->fts_info) 297 { 298 case FTS_F: 299 case FTS_NSOK: 300 /* See if this file name matches "*.ko". */ 301 if (f->fts_namelen > 3 302 && !memcmp (f->fts_name + f->fts_namelen - 3, ".ko", 4)) 303 { 304 /* We have a .ko file to report. Following the algorithm 305 by which the kernel makefiles set KBUILD_MODNAME, we 306 replace all ',' or '-' with '_' in the file name and 307 call that the module name. Modules could well be 308 built using different embedded names than their file 309 names. To handle that, we would have to look at the 310 __this_module.name contents in the module's text. */ 311 312 char name[f->fts_namelen - 3 + 1]; 313 for (size_t i = 0; i < f->fts_namelen - 3U; ++i) 314 if (f->fts_name[i] == '-' || f->fts_name[i] == ',') 315 name[i] = '_'; 316 else 317 name[i] = f->fts_name[i]; 318 name[f->fts_namelen - 3] = '\0'; 319 320 if (predicate != NULL) 321 { 322 /* Let the predicate decide whether to use this one. */ 323 int want = (*predicate) (name, f->fts_path); 324 if (want < 0) 325 { 326 result = -1; 327 break; 328 } 329 if (!want) 330 continue; 331 } 332 333 if (dwfl_report_offline (dwfl, name, 334 f->fts_path, -1) == NULL) 335 { 336 result = -1; 337 break; 338 } 339 } 340 continue; 341 342 case FTS_ERR: 343 case FTS_DNR: 344 case FTS_NS: 345 result = f->fts_errno; 346 break; 347 348 default: 349 continue; 350 } 351 352 /* We only get here in error cases. */ 353 break; 354 } 355 fts_close (fts); 356 free (modulesdir[0]); 357 } 358 359 return result; 360} 361INTDEF (dwfl_linux_kernel_report_offline) 362 363 364/* Grovel around to guess the bounds of the runtime kernel image. */ 365static int 366intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes) 367{ 368 FILE *f = fopen (KSYMSFILE, "r"); 369 if (f == NULL) 370 return errno; 371 372 (void) __fsetlocking (f, FSETLOCKING_BYCALLER); 373 374 *notes = 0; 375 376 char *line = NULL; 377 size_t linesz = 0; 378 size_t n = getline (&line, &linesz, f); 379 Dwarf_Addr first; 380 char *p = NULL; 381 int result = 0; 382 if (n > 0 && (first = strtoull (line, &p, 16)) > 0 && p > line) 383 { 384 Dwarf_Addr last = 0; 385 while ((n = getline (&line, &linesz, f)) > 1 && line[n - 2] != ']') 386 { 387 p = NULL; 388 last = strtoull (line, &p, 16); 389 if (p == NULL || p == line || last == 0) 390 { 391 result = -1; 392 break; 393 } 394 395 if (*notes == 0) 396 { 397 const char *sym = (strsep (&p, " \t\n") 398 ? strsep (&p, " \t\n") : NULL); 399 if (sym != NULL && !strcmp (sym, "__start_notes")) 400 *notes = last; 401 } 402 } 403 if ((n == 0 && feof_unlocked (f)) || (n > 1 && line[n - 2] == ']')) 404 { 405 Dwarf_Addr round_kernel = sysconf (_SC_PAGE_SIZE); 406 first &= -(Dwarf_Addr) round_kernel; 407 last += round_kernel - 1; 408 last &= -(Dwarf_Addr) round_kernel; 409 *start = first; 410 *end = last; 411 result = 0; 412 } 413 } 414 free (line); 415 416 if (result == -1) 417 result = ferror_unlocked (f) ? errno : ENOEXEC; 418 419 fclose (f); 420 421 return result; 422} 423 424 425/* Look for a build ID note in NOTESFILE and associate the ID with MOD. */ 426static int 427check_notes (Dwfl_Module *mod, const char *notesfile, 428 Dwarf_Addr vaddr, const char *secname) 429{ 430 int fd = open64 (notesfile, O_RDONLY); 431 if (fd < 0) 432 return 1; 433 434 assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr)); 435 assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr)); 436 union 437 { 438 GElf_Nhdr nhdr; 439 unsigned char data[8192]; 440 } buf; 441 442 ssize_t n = read (fd, buf.data, sizeof buf); 443 close (fd); 444 445 if (n <= 0) 446 return 1; 447 448 unsigned char *p = buf.data; 449 while (p < &buf.data[n]) 450 { 451 /* No translation required since we are reading the native kernel. */ 452 GElf_Nhdr *nhdr = (void *) p; 453 p += sizeof *nhdr; 454 unsigned char *name = p; 455 p += (nhdr->n_namesz + 3) & -4U; 456 unsigned char *bits = p; 457 p += (nhdr->n_descsz + 3) & -4U; 458 459 if (p <= &buf.data[n] 460 && nhdr->n_type == NT_GNU_BUILD_ID 461 && nhdr->n_namesz == sizeof "GNU" 462 && !memcmp (name, "GNU", sizeof "GNU")) 463 { 464 /* Found it. For a module we must figure out its VADDR now. */ 465 466 if (secname != NULL 467 && (INTUSE(dwfl_linux_kernel_module_section_address) 468 (mod, NULL, mod->name, 0, secname, 0, NULL, &vaddr) != 0 469 || vaddr == (GElf_Addr) -1l)) 470 vaddr = 0; 471 472 if (vaddr != 0) 473 vaddr += bits - buf.data; 474 return INTUSE(dwfl_module_report_build_id) (mod, bits, 475 nhdr->n_descsz, vaddr); 476 } 477 } 478 479 return 0; 480} 481 482/* Look for a build ID for the kernel. */ 483static int 484check_kernel_notes (Dwfl_Module *kernelmod, GElf_Addr vaddr) 485{ 486 return check_notes (kernelmod, KNOTESFILE, vaddr, NULL) < 0 ? -1 : 0; 487} 488 489/* Look for a build ID for a loaded kernel module. */ 490static int 491check_module_notes (Dwfl_Module *mod) 492{ 493 char *dirs[2] = { NULL, NULL }; 494 if (asprintf (&dirs[0], MODNOTESFMT, mod->name) < 0) 495 return ENOMEM; 496 497 FTS *fts = fts_open (dirs, FTS_NOSTAT, NULL); 498 if (fts == NULL) 499 { 500 free (dirs[0]); 501 return 0; 502 } 503 504 int result = 0; 505 FTSENT *f; 506 while ((f = fts_read (fts)) != NULL) 507 { 508 switch (f->fts_info) 509 { 510 case FTS_F: 511 case FTS_NSOK: 512 result = check_notes (mod, f->fts_accpath, 0, f->fts_name); 513 if (result > 0) /* Nothing found. */ 514 { 515 result = 0; 516 continue; 517 } 518 break; 519 520 case FTS_ERR: 521 case FTS_DNR: 522 result = f->fts_errno; 523 break; 524 525 case FTS_NS: 526 default: 527 continue; 528 } 529 530 /* We only get here when finished or in error cases. */ 531 break; 532 } 533 fts_close (fts); 534 free (dirs[0]); 535 536 return result; 537} 538 539int 540dwfl_linux_kernel_report_kernel (Dwfl *dwfl) 541{ 542 Dwarf_Addr start; 543 Dwarf_Addr end; 544 inline Dwfl_Module *report (void) 545 { 546 return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end); 547 } 548 549 /* This is a bit of a kludge. If we already reported the kernel, 550 don't bother figuring it out again--it never changes. */ 551 for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) 552 if (!strcmp (m->name, KERNEL_MODNAME)) 553 { 554 start = m->low_addr; 555 end = m->high_addr; 556 return report () == NULL ? -1 : 0; 557 } 558 559 /* Try to figure out the bounds of the kernel image without 560 looking for any vmlinux file. */ 561 Dwarf_Addr notes; 562 /* The compiler cannot deduce that if intuit_kernel_bounds returns 563 zero NOTES will be initialized. Fake the initialization. */ 564 asm ("" : "=m" (notes)); 565 int result = intuit_kernel_bounds (&start, &end, ¬es); 566 if (result == 0) 567 { 568 Dwfl_Module *mod = report (); 569 return unlikely (mod == NULL) ? -1 : check_kernel_notes (mod, notes); 570 } 571 if (result != ENOENT) 572 return result; 573 574 /* Find the ELF file for the running kernel and dwfl_report_elf it. */ 575 return report_kernel (dwfl, NULL, NULL); 576} 577INTDEF (dwfl_linux_kernel_report_kernel) 578 579 580/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules. */ 581 582int 583dwfl_linux_kernel_find_elf (Dwfl_Module *mod, 584 void **userdata __attribute__ ((unused)), 585 const char *module_name, 586 Dwarf_Addr base __attribute__ ((unused)), 587 char **file_name, Elf **elfp) 588{ 589 if (mod->build_id_len > 0) 590 { 591 int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0, 592 file_name, elfp); 593 if (fd >= 0 || errno != 0) 594 return fd; 595 } 596 597 const char *release = kernel_release (); 598 if (release == NULL) 599 return errno; 600 601 if (!strcmp (module_name, KERNEL_MODNAME)) 602 return find_kernel_elf (mod->dwfl, release, file_name); 603 604 /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */ 605 606 char *modulesdir[] = { NULL, NULL }; 607 if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0) 608 return -1; 609 610 FTS *fts = fts_open (modulesdir, FTS_NOSTAT, NULL); 611 if (fts == NULL) 612 { 613 free (modulesdir[0]); 614 return -1; 615 } 616 617 size_t namelen = strlen (module_name); 618 619 /* This is a kludge. There is no actual necessary relationship between 620 the name of the .ko file installed and the module name the kernel 621 knows it by when it's loaded. The kernel's only idea of the module 622 name comes from the name embedded in the object's magic 623 .gnu.linkonce.this_module section. 624 625 In practice, these module names match the .ko file names except for 626 some using '_' and some using '-'. So our cheap kludge is to look for 627 two files when either a '_' or '-' appears in a module name, one using 628 only '_' and one only using '-'. */ 629 630 char alternate_name[namelen + 1]; 631 inline bool subst_name (char from, char to) 632 { 633 const char *n = memchr (module_name, from, namelen); 634 if (n == NULL) 635 return false; 636 char *a = mempcpy (alternate_name, module_name, n - module_name); 637 *a++ = to; 638 ++n; 639 const char *p; 640 while ((p = memchr (n, from, namelen - (n - module_name))) != NULL) 641 { 642 a = mempcpy (a, n, p - n); 643 *a++ = to; 644 n = p + 1; 645 } 646 memcpy (a, n, namelen - (n - module_name) + 1); 647 return true; 648 } 649 if (!subst_name ('-', '_') && !subst_name ('_', '-')) 650 alternate_name[0] = '\0'; 651 652 FTSENT *f; 653 int error = ENOENT; 654 while ((f = fts_read (fts)) != NULL) 655 { 656 error = ENOENT; 657 switch (f->fts_info) 658 { 659 case FTS_F: 660 case FTS_NSOK: 661 /* See if this file name is "MODULE_NAME.ko". */ 662 if (f->fts_namelen == namelen + 3 663 && !memcmp (f->fts_name + namelen, ".ko", 4) 664 && (!memcmp (f->fts_name, module_name, namelen) 665 || !memcmp (f->fts_name, alternate_name, namelen))) 666 { 667 int fd = open64 (f->fts_accpath, O_RDONLY); 668 *file_name = strdup (f->fts_path); 669 fts_close (fts); 670 free (modulesdir[0]); 671 if (fd < 0) 672 free (*file_name); 673 else if (*file_name == NULL) 674 { 675 close (fd); 676 fd = -1; 677 } 678 return fd; 679 } 680 break; 681 682 case FTS_ERR: 683 case FTS_DNR: 684 case FTS_NS: 685 error = f->fts_errno; 686 break; 687 688 default: 689 break; 690 } 691 } 692 693 fts_close (fts); 694 free (modulesdir[0]); 695 errno = error; 696 return -1; 697} 698INTDEF (dwfl_linux_kernel_find_elf) 699 700 701/* Dwfl_Callbacks.section_address for kernel modules in the running Linux. 702 We read the information from /sys/module directly. */ 703 704int 705dwfl_linux_kernel_module_section_address 706(Dwfl_Module *mod __attribute__ ((unused)), 707 void **userdata __attribute__ ((unused)), 708 const char *modname, Dwarf_Addr base __attribute__ ((unused)), 709 const char *secname, Elf32_Word shndx __attribute__ ((unused)), 710 const GElf_Shdr *shdr __attribute__ ((unused)), 711 Dwarf_Addr *addr) 712{ 713 char *sysfile; 714 if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0) 715 return DWARF_CB_ABORT; 716 717 FILE *f = fopen (sysfile, "r"); 718 free (sysfile); 719 720 if (f == NULL) 721 { 722 if (errno == ENOENT) 723 { 724 /* The .modinfo and .data.percpu sections are never kept 725 loaded in the kernel. If the kernel was compiled without 726 CONFIG_MODULE_UNLOAD, the .exit.* sections are not 727 actually loaded at all. 728 729 Setting *ADDR to -1 tells the caller this section is 730 actually absent from memory. */ 731 732 if (!strcmp (secname, ".modinfo") 733 || !strcmp (secname, ".data.percpu") 734 || !strncmp (secname, ".exit", 5)) 735 { 736 *addr = (Dwarf_Addr) -1l; 737 return DWARF_CB_OK; 738 } 739 740 /* The goofy PPC64 module_frob_arch_sections function tweaks 741 the section names as a way to control other kernel code's 742 behavior, and this cruft leaks out into the /sys information. 743 The file name for ".init*" may actually look like "_init*". */ 744 745 const bool is_init = !strncmp (secname, ".init", 5); 746 if (is_init) 747 { 748 if (asprintf (&sysfile, SECADDRDIRFMT "_%s", 749 modname, &secname[1]) < 0) 750 return ENOMEM; 751 f = fopen (sysfile, "r"); 752 free (sysfile); 753 if (f != NULL) 754 goto ok; 755 } 756 757 /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1. 758 In case that size increases in the future, look for longer 759 truncated names first. */ 760 size_t namelen = strlen (secname); 761 if (namelen >= MODULE_SECT_NAME_LEN) 762 { 763 int len = asprintf (&sysfile, SECADDRDIRFMT "%s", 764 modname, secname); 765 if (len < 0) 766 return DWARF_CB_ABORT; 767 char *end = sysfile + len; 768 do 769 { 770 *--end = '\0'; 771 f = fopen (sysfile, "r"); 772 if (is_init && f == NULL && errno == ENOENT) 773 { 774 sysfile[len - namelen] = '_'; 775 f = fopen (sysfile, "r"); 776 sysfile[len - namelen] = '.'; 777 } 778 } 779 while (f == NULL && errno == ENOENT 780 && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN); 781 free (sysfile); 782 783 if (f != NULL) 784 goto ok; 785 } 786 } 787 788 return DWARF_CB_ABORT; 789 } 790 791 ok: 792 (void) __fsetlocking (f, FSETLOCKING_BYCALLER); 793 794 int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0 795 : ferror_unlocked (f) ? errno : ENOEXEC); 796 fclose (f); 797 798 if (result == 0) 799 return DWARF_CB_OK; 800 801 errno = result; 802 return DWARF_CB_ABORT; 803} 804INTDEF (dwfl_linux_kernel_module_section_address) 805 806int 807dwfl_linux_kernel_report_modules (Dwfl *dwfl) 808{ 809 FILE *f = fopen (MODULELIST, "r"); 810 if (f == NULL) 811 return errno; 812 813 (void) __fsetlocking (f, FSETLOCKING_BYCALLER); 814 815 int result = 0; 816 Dwarf_Addr modaddr; 817 unsigned long int modsz; 818 char modname[128]; 819 char *line = NULL; 820 size_t linesz = 0; 821 /* We can't just use fscanf here because it's not easy to distinguish \n 822 from other whitespace so as to take the optional word following the 823 address but always stop at the end of the line. */ 824 while (getline (&line, &linesz, f) > 0 825 && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n", 826 modname, &modsz, &modaddr) == 3) 827 { 828 Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, modname, 829 modaddr, modaddr + modsz); 830 if (mod == NULL) 831 { 832 result = -1; 833 break; 834 } 835 836 result = check_module_notes (mod); 837 } 838 free (line); 839 840 if (result == 0) 841 result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; 842 843 fclose (f); 844 845 return result; 846} 847INTDEF (dwfl_linux_kernel_report_modules) 848