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