1/*-
2 * Copyright (c) 2006 The FreeBSD Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/types.h>
31#include <sys/param.h>
32#include <sys/queue.h>	/* for <sys/linker.h> with _KERNEL defined */
33#include <err.h>
34#include <fcntl.h>
35#include <kvm.h>
36#include <limits.h>
37#include <nlist.h>
38#include <stdlib.h>
39#include <string.h>
40
41#define _KERNEL
42#include <sys/linker.h>
43#undef	_KERNEL
44
45#include "asf.h"
46
47/* Name of the head of the linker file list in /sys/kern/kern_linker.c */
48#define LINKER_HEAD	"linker_files"
49
50/*
51 * Get the list of linker files using kvm(3).
52 * Can work with a live kernel as well as with a crash dump.
53 */
54void
55asf_kvm(const char *kernfile, const char *corefile)
56{
57	char errbuf[LINE_MAX];
58	char name[PATH_MAX];
59	kvm_t *kd;
60	struct nlist nl[2];
61	struct linker_file lf;
62	linker_file_list_t linker_files;
63	ssize_t n;
64	void *kp;
65
66	kd = kvm_openfiles(kernfile, corefile, NULL, O_RDONLY, errbuf);
67	if (kd == NULL)
68		errx(2, "open kernel memory: %s", errbuf);
69
70	/*
71	 * Locate the head of the linker file list using kernel symbols.
72	 */
73	strcpy(name, LINKER_HEAD);
74	nl[0].n_name = name; /* can't use LINKER_HEAD here because it's const */
75	nl[1].n_name = NULL; /* terminate the array for kvm_nlist() */
76	switch (kvm_nlist(kd, nl)) {
77	case 0:
78		break;
79	case -1:
80		warnx("%s: %s", LINKER_HEAD, kvm_geterr(kd));
81		kvm_close(kd);
82		exit(2);
83	default:
84		kvm_close(kd);
85		errx(2, "%s: symbol not found", LINKER_HEAD);
86	}
87
88	/*
89	 * Read the head of the linker file list from kernel memory.
90	 */
91	n = kvm_read(kd, nl[0].n_value, &linker_files, sizeof(linker_files));
92	if (n == -1)
93		goto read_err;
94	if (n != sizeof(linker_files)) {
95		kvm_close(kd);
96		errx(2, "%s: short read", LINKER_HEAD);
97	}
98
99	/*
100	 * Traverse the linker file list starting at its head.
101	 */
102	for (kp = linker_files.tqh_first; kp; kp = lf.link.tqe_next) {
103		/* Read a linker file structure */
104		n = kvm_read(kd, (u_long)kp, &lf, sizeof(lf));
105		if (n == -1)
106			goto read_err;
107		if (n != sizeof(lf)) {
108			kvm_close(kd);
109			errx(2, "kvm: short read");
110		}
111		/* Read the name of the file stored separately */
112		bzero(name, sizeof(name));
113		n = kvm_read(kd, (u_long)lf.filename, name, sizeof(name) - 1);
114		if (n == -1)
115			goto read_err;
116		if (strcmp(name, KERNFILE) == 0)
117			continue;
118		/* Add this file to our list of linker files */
119		kfile_add(name, lf.address);
120	}
121	kvm_close(kd);
122	return;
123
124read_err:	/* A common error case */
125	warnx("read kernel memory: %s", kvm_geterr(kd));
126	kvm_close(kd);
127	exit(2);
128}
129