asf_kvm.c revision 159720
160484Sobrien/*-
2218822Sdim * Copyright (c) 2006 The FreeBSD Project
3218822Sdim * All rights reserved.
433965Sjdp *
533965Sjdp * Redistribution and use in source and binary forms, with or without
633965Sjdp * modification, are permitted provided that the following conditions
733965Sjdp * are met:
833965Sjdp * 1. Redistributions of source code must retain the above copyright
933965Sjdp *    notice, this list of conditions and the following disclaimer.
1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright
1133965Sjdp *    notice, this list of conditions and the following disclaimer in the
1233965Sjdp *    documentation and/or other materials provided with the distribution.
1333965Sjdp *
1433965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1733965Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1833965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19218822Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23130561Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2433965Sjdp * SUCH DAMAGE.
2533965Sjdp */
2633965Sjdp
2733965Sjdp#include <sys/cdefs.h>
2833965Sjdp__FBSDID("$FreeBSD: head/usr.sbin/asf/asf_kvm.c 159720 2006-06-18 11:14:40Z yar $");
2933965Sjdp
3033965Sjdp#include <sys/types.h>
3133965Sjdp#include <sys/param.h>
3233965Sjdp#include <sys/queue.h>	/* for <sys/linker.h> with _KERNEL defined */
3333965Sjdp#include <err.h>
3460484Sobrien#include <fcntl.h>
3533965Sjdp#include <kvm.h>
3633965Sjdp#include <limits.h>
3733965Sjdp#include <nlist.h>
3833965Sjdp#include <stdlib.h>
3960484Sobrien#include <string.h>
4033965Sjdp
4133965Sjdp#define _KERNEL
4233965Sjdp#include <sys/linker.h>
4333965Sjdp#undef	_KERNEL
4460484Sobrien
4533965Sjdp#include "asf.h"
4633965Sjdp
4760484Sobrien/* Name of the head of the linker file list in /sys/kern/kern_linker.c */
4833965Sjdp#define LINKER_HEAD	"linker_files"
4933965Sjdp
5089857Sobrien/*
5189857Sobrien * Get the list of linker files using kvm(3).
52130561Sobrien * Can work with a live kernel as well as with a crash dump.
5333965Sjdp */
5489857Sobrienvoid
5589857Sobrienasf_kvm(const char *kernfile, const char *corefile)
5689857Sobrien{
5733965Sjdp	char errbuf[LINE_MAX];
5860484Sobrien	char name[PATH_MAX];
5960484Sobrien	kvm_t *kd;
60218822Sdim	struct nlist nl[2];
6160484Sobrien	struct linker_file lf;
6260484Sobrien	linker_file_list_t linker_files;
63130561Sobrien	ssize_t n;
6433965Sjdp	void *kp;
6533965Sjdp
6633965Sjdp	kd = kvm_openfiles(kernfile, corefile, NULL, O_RDONLY, errbuf);
6733965Sjdp	if (kd == NULL)
6833965Sjdp		errx(2, "open kernel memory: %s", errbuf);
6933965Sjdp
7033965Sjdp	/*
7133965Sjdp	 * Locate the head of the linker file list using kernel symbols.
7233965Sjdp	 */
7333965Sjdp	strcpy(name, LINKER_HEAD);
7433965Sjdp	nl[0].n_name = name; /* can't use LINKER_HEAD here because it's const */
7533965Sjdp	nl[1].n_name = NULL; /* terminate the array for kvm_nlist() */
7633965Sjdp	switch (kvm_nlist(kd, nl)) {
7733965Sjdp	case 0:
7833965Sjdp		break;
7933965Sjdp	case -1:
8033965Sjdp		warnx("%s: %s", LINKER_HEAD, kvm_geterr(kd));
8133965Sjdp		kvm_close(kd);
8233965Sjdp		exit(2);
8333965Sjdp	default:
8433965Sjdp		kvm_close(kd);
8533965Sjdp		errx(2, "%s: symbol not found", LINKER_HEAD);
8633965Sjdp	}
8733965Sjdp
8860484Sobrien	/*
8933965Sjdp	 * Read the head of the linker file list from kernel memory.
9033965Sjdp	 */
9133965Sjdp	n = kvm_read(kd, nl[0].n_value, &linker_files, sizeof(linker_files));
9233965Sjdp	if (n == -1)
9333965Sjdp		goto read_err;
9433965Sjdp	if (n != sizeof(linker_files)) {
9533965Sjdp		kvm_close(kd);
9633965Sjdp		errx(2, "%s: short read", LINKER_HEAD);
9733965Sjdp	}
9833965Sjdp
9960484Sobrien	/*
10060484Sobrien	 * Traverse the linker file list starting at its head.
10133965Sjdp	 */
10233965Sjdp	for (kp = linker_files.tqh_first; kp; kp = lf.link.tqe_next) {
10360484Sobrien		/* Read a linker file structure */
10433965Sjdp		n = kvm_read(kd, (u_long)kp, &lf, sizeof(lf));
10560484Sobrien		if (n == -1)
10633965Sjdp			goto read_err;
10733965Sjdp		if (n != sizeof(lf)) {
10860484Sobrien			kvm_close(kd);
10933965Sjdp			errx(2, "kvm: short read");
11060484Sobrien		}
11133965Sjdp		/* Read the name of the file stored separately */
11233965Sjdp		bzero(name, sizeof(name));
11360484Sobrien		n = kvm_read(kd, (u_long)lf.filename, name, sizeof(name) - 1);
11433965Sjdp		if (n == -1)
11533965Sjdp			goto read_err;
11633965Sjdp		if (strcmp(name, KERNFILE) == 0)
117104834Sobrien			continue;
11860484Sobrien		/* Add this file to our list of linker files */
11933965Sjdp		kfile_add(name, lf.address);
12060484Sobrien	}
12133965Sjdp	kvm_close(kd);
12233965Sjdp	return;
12360484Sobrien
12433965Sjdpread_err:	/* A common error case */
12560484Sobrien	warnx("read kernel memory: %s", kvm_geterr(kd));
12633965Sjdp	kvm_close(kd);
12733965Sjdp	exit(2);
12860484Sobrien}
12933965Sjdp