1159720Syar/*-
2159720Syar * Copyright (c) 2006 The FreeBSD Project
3159720Syar * All rights reserved.
4159720Syar *
5159720Syar * Redistribution and use in source and binary forms, with or without
6159720Syar * modification, are permitted provided that the following conditions
7159720Syar * are met:
8159720Syar * 1. Redistributions of source code must retain the above copyright
9159720Syar *    notice, this list of conditions and the following disclaimer.
10159720Syar * 2. Redistributions in binary form must reproduce the above copyright
11159720Syar *    notice, this list of conditions and the following disclaimer in the
12159720Syar *    documentation and/or other materials provided with the distribution.
13159720Syar *
14159720Syar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15159720Syar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16159720Syar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17159720Syar * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18159720Syar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19159720Syar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20159720Syar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21159720Syar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22159720Syar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23159720Syar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24159720Syar * SUCH DAMAGE.
25159720Syar */
26159720Syar
27159720Syar#include <sys/cdefs.h>
28159720Syar__FBSDID("$FreeBSD$");
29159720Syar
30159720Syar#include <sys/types.h>
31159720Syar#include <sys/param.h>
32159720Syar#include <sys/queue.h>	/* for <sys/linker.h> with _KERNEL defined */
33159720Syar#include <err.h>
34159720Syar#include <fcntl.h>
35159720Syar#include <kvm.h>
36159720Syar#include <limits.h>
37159720Syar#include <nlist.h>
38159720Syar#include <stdlib.h>
39159720Syar#include <string.h>
40159720Syar
41159720Syar#define _KERNEL
42159720Syar#include <sys/linker.h>
43159720Syar#undef	_KERNEL
44159720Syar
45159720Syar#include "asf.h"
46159720Syar
47159720Syar/* Name of the head of the linker file list in /sys/kern/kern_linker.c */
48159720Syar#define LINKER_HEAD	"linker_files"
49159720Syar
50159720Syar/*
51159720Syar * Get the list of linker files using kvm(3).
52159720Syar * Can work with a live kernel as well as with a crash dump.
53159720Syar */
54159720Syarvoid
55159720Syarasf_kvm(const char *kernfile, const char *corefile)
56159720Syar{
57159720Syar	char errbuf[LINE_MAX];
58159720Syar	char name[PATH_MAX];
59159720Syar	kvm_t *kd;
60159720Syar	struct nlist nl[2];
61159720Syar	struct linker_file lf;
62159720Syar	linker_file_list_t linker_files;
63159720Syar	ssize_t n;
64159720Syar	void *kp;
65159720Syar
66159720Syar	kd = kvm_openfiles(kernfile, corefile, NULL, O_RDONLY, errbuf);
67159720Syar	if (kd == NULL)
68159720Syar		errx(2, "open kernel memory: %s", errbuf);
69159720Syar
70159720Syar	/*
71159720Syar	 * Locate the head of the linker file list using kernel symbols.
72159720Syar	 */
73159720Syar	strcpy(name, LINKER_HEAD);
74159720Syar	nl[0].n_name = name; /* can't use LINKER_HEAD here because it's const */
75159720Syar	nl[1].n_name = NULL; /* terminate the array for kvm_nlist() */
76159720Syar	switch (kvm_nlist(kd, nl)) {
77159720Syar	case 0:
78159720Syar		break;
79159720Syar	case -1:
80159720Syar		warnx("%s: %s", LINKER_HEAD, kvm_geterr(kd));
81159720Syar		kvm_close(kd);
82159720Syar		exit(2);
83159720Syar	default:
84159720Syar		kvm_close(kd);
85159720Syar		errx(2, "%s: symbol not found", LINKER_HEAD);
86159720Syar	}
87159720Syar
88159720Syar	/*
89159720Syar	 * Read the head of the linker file list from kernel memory.
90159720Syar	 */
91159720Syar	n = kvm_read(kd, nl[0].n_value, &linker_files, sizeof(linker_files));
92159720Syar	if (n == -1)
93159720Syar		goto read_err;
94159720Syar	if (n != sizeof(linker_files)) {
95159720Syar		kvm_close(kd);
96159720Syar		errx(2, "%s: short read", LINKER_HEAD);
97159720Syar	}
98159720Syar
99159720Syar	/*
100159720Syar	 * Traverse the linker file list starting at its head.
101159720Syar	 */
102159720Syar	for (kp = linker_files.tqh_first; kp; kp = lf.link.tqe_next) {
103159720Syar		/* Read a linker file structure */
104159720Syar		n = kvm_read(kd, (u_long)kp, &lf, sizeof(lf));
105159720Syar		if (n == -1)
106159720Syar			goto read_err;
107159720Syar		if (n != sizeof(lf)) {
108159720Syar			kvm_close(kd);
109159720Syar			errx(2, "kvm: short read");
110159720Syar		}
111159720Syar		/* Read the name of the file stored separately */
112159720Syar		bzero(name, sizeof(name));
113159720Syar		n = kvm_read(kd, (u_long)lf.filename, name, sizeof(name) - 1);
114159720Syar		if (n == -1)
115159720Syar			goto read_err;
116159720Syar		if (strcmp(name, KERNFILE) == 0)
117159720Syar			continue;
118159720Syar		/* Add this file to our list of linker files */
119159720Syar		kfile_add(name, lf.address);
120159720Syar	}
121159720Syar	kvm_close(kd);
122159720Syar	return;
123159720Syar
124159720Syarread_err:	/* A common error case */
125159720Syar	warnx("read kernel memory: %s", kvm_geterr(kd));
126159720Syar	kvm_close(kd);
127159720Syar	exit(2);
128159720Syar}
129