115702Sphk/*- 22886Sphk * Copyright (c) 2006 The FreeBSD Project 36563Sphk * All rights reserved. 46563Sphk * 56563Sphk * Redistribution and use in source and binary forms, with or without 66563Sphk * modification, are permitted provided that the following conditions 76563Sphk * are met: 86563Sphk * 1. Redistributions of source code must retain the above copyright 96563Sphk * notice, this list of conditions and the following disclaimer. 106563Sphk * 2. Redistributions in binary form must reproduce the above copyright 116563Sphk * notice, this list of conditions and the following disclaimer in the 126563Sphk * documentation and/or other materials provided with the distribution. 136563Sphk * 146563Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156563Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166563Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176563Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 186563Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 196563Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 206563Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 216563Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226563Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236563Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2419813Sphk * SUCH DAMAGE. 2519813Sphk */ 266563Sphk 2718110Speter#include <sys/cdefs.h> 2818110Speter__FBSDID("$FreeBSD$"); 2918110Speter 3018110Speter#include <sys/types.h> 316563Sphk#include <sys/param.h> 326563Sphk#include <sys/queue.h> /* for <sys/linker.h> with _KERNEL defined */ 336563Sphk#include <err.h> 346563Sphk#include <fcntl.h> 356563Sphk#include <kvm.h> 366563Sphk#include <limits.h> 376563Sphk#include <nlist.h> 386777Sphk#include <stdlib.h> 397463Sphk#include <string.h> 407463Sphk 4119813Sphk#define _KERNEL 426563Sphk#include <sys/linker.h> 436563Sphk#undef _KERNEL 446563Sphk 456563Sphk#include "asf.h" 466563Sphk 4719813Sphk/* Name of the head of the linker file list in /sys/kern/kern_linker.c */ 486563Sphk#define LINKER_HEAD "linker_files" 496563Sphk 506563Sphk/* 516563Sphk * Get the list of linker files using kvm(3). 526563Sphk * Can work with a live kernel as well as with a crash dump. 536563Sphk */ 546563Sphkvoid 556563Sphkasf_kvm(const char *kernfile, const char *corefile) 566563Sphk{ 576563Sphk char errbuf[LINE_MAX]; 586563Sphk char name[PATH_MAX]; 596788Sphk kvm_t *kd; 606788Sphk struct nlist nl[2]; 6115702Sphk struct linker_file lf; 626788Sphk linker_file_list_t linker_files; 636788Sphk ssize_t n; 647463Sphk void *kp; 656788Sphk 666788Sphk kd = kvm_openfiles(kernfile, corefile, NULL, O_RDONLY, errbuf); 6719813Sphk if (kd == NULL) 686788Sphk errx(2, "open kernel memory: %s", errbuf); 696788Sphk 706788Sphk /* 716788Sphk * Locate the head of the linker file list using kernel symbols. 726563Sphk */ 736563Sphk strcpy(name, LINKER_HEAD); 742886Sphk nl[0].n_name = name; /* can't use LINKER_HEAD here because it's const */ 756777Sphk nl[1].n_name = NULL; /* terminate the array for kvm_nlist() */ 767463Sphk switch (kvm_nlist(kd, nl)) { 777463Sphk case 0: 787463Sphk break; 797463Sphk case -1: 807463Sphk warnx("%s: %s", LINKER_HEAD, kvm_geterr(kd)); 812886Sphk kvm_close(kd); 827463Sphk exit(2); 836563Sphk default: 846788Sphk kvm_close(kd); 8519813Sphk errx(2, "%s: symbol not found", LINKER_HEAD); 866563Sphk } 872886Sphk 886563Sphk /* 892886Sphk * Read the head of the linker file list from kernel memory. 906563Sphk */ 916563Sphk n = kvm_read(kd, nl[0].n_value, &linker_files, sizeof(linker_files)); 926788Sphk if (n == -1) 9319813Sphk goto read_err; 946563Sphk if (n != sizeof(linker_files)) { 952886Sphk kvm_close(kd); 966563Sphk errx(2, "%s: short read", LINKER_HEAD); 976563Sphk } 986563Sphk 996563Sphk /* 1003833Sphk * Traverse the linker file list starting at its head. 1016563Sphk */ 1026563Sphk for (kp = linker_files.tqh_first; kp; kp = lf.link.tqe_next) { 1036777Sphk /* Read a linker file structure */ 1046777Sphk n = kvm_read(kd, (u_long)kp, &lf, sizeof(lf)); 1056777Sphk if (n == -1) 1066563Sphk goto read_err; 1076563Sphk if (n != sizeof(lf)) { 1082886Sphk kvm_close(kd); 10919813Sphk errx(2, "kvm: short read"); 1102886Sphk } 11119813Sphk /* Read the name of the file stored separately */ 11219813Sphk bzero(name, sizeof(name)); 11319813Sphk n = kvm_read(kd, (u_long)lf.filename, name, sizeof(name) - 1); 11419813Sphk if (n == -1) 1155014Sphk goto read_err; 11619813Sphk if (strcmp(name, KERNFILE) == 0) 1175014Sphk continue; 11819813Sphk /* Add this file to our list of linker files */ 11919813Sphk kfile_add(name, lf.address); 12019813Sphk } 12119813Sphk kvm_close(kd); 1226788Sphk return; 12319813Sphk 1246563Sphkread_err: /* A common error case */ 12519813Sphk warnx("read kernel memory: %s", kvm_geterr(kd)); 12619813Sphk kvm_close(kd); 1272886Sphk exit(2); 1286563Sphk} 1296563Sphk