kldxref.c revision 160982
1176771Sraj/*
2192532Sraj * Copyright (c) 2000, Boris Popov
3176771Sraj * All rights reserved.
4176771Sraj *
5176771Sraj * Redistribution and use in source and binary forms, with or without
6176771Sraj * modification, are permitted provided that the following conditions
7176771Sraj * are met:
8176771Sraj * 1. Redistributions of source code must retain the above copyright
9176771Sraj *    notice, this list of conditions and the following disclaimer.
10176771Sraj * 2. Redistributions in binary form must reproduce the above copyright
11176771Sraj *    notice, this list of conditions and the following disclaimer in the
12176771Sraj *    documentation and/or other materials provided with the distribution.
13176771Sraj * 3. All advertising materials mentioning features or use of this software
14176771Sraj *    must display the following acknowledgement:
15176771Sraj *    This product includes software developed by Boris Popov.
16176771Sraj * 4. Neither the name of the author nor the names of any co-contributors
17176771Sraj *    may be used to endorse or promote products derived from this software
18176771Sraj *    without specific prior written permission.
19176771Sraj *
20176771Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21176771Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22176771Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23176771Sraj * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24176771Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25176771Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26176771Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27176771Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28176771Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29176771Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30176771Sraj * SUCH DAMAGE.
31176771Sraj *
32176771Sraj * $FreeBSD: head/usr.sbin/kldxref/kldxref.c 160982 2006-08-04 21:28:42Z marcel $
33176771Sraj */
34176771Sraj
35176771Sraj#include <sys/types.h>
36176771Sraj#include <sys/param.h>
37176771Sraj#include <sys/exec.h>
38176771Sraj#include <sys/queue.h>
39187151Sraj#include <sys/kernel.h>
40187151Sraj#include <sys/reboot.h>
41187151Sraj#include <sys/linker.h>
42190701Smarcel#include <sys/stat.h>
43187151Sraj#include <sys/module.h>
44187151Sraj#define FREEBSD_ELF
45187151Sraj#include <link.h>
46187151Sraj#include <err.h>
47187151Sraj#include <fts.h>
48187151Sraj#include <string.h>
49176771Sraj#include <machine/elf.h>
50176771Sraj#include <stdio.h>
51176771Sraj#include <stdlib.h>
52176771Sraj#include <unistd.h>
53176771Sraj#include <errno.h>
54285627Szbb
55285627Szbb#include "ef.h"
56176771Sraj
57276772Smarkj#define	MAXRECSIZE	1024
58176771Sraj#define check(val)	if ((error = (val)) != 0) break
59187149Sraj
60176771Sraj#ifndef min
61176771Sraj#define	min(a,b)	(((a)<(b)) ? (a) : (b))
62176771Sraj#endif
63176771Sraj
64176771Srajstruct mod_info {
65276772Smarkj	char*	mi_name;
66224611Smarcel	int	mi_ver;
67176771Sraj	SLIST_ENTRY(mod_info) mi_next;
68176771Sraj};
69176771Sraj
70242535Salc#ifdef notnow
71222813Sattiliostruct kld_info {
72192532Sraj	char*	k_filename;
73176771Sraj	SLIST_HEAD(mod_list_head, mod_info) k_modules;
74176771Sraj	SLIST_ENTRY(kld_info) k_next;
75176771Sraj};
76176771Sraj
77176771SrajSLIST_HEAD(kld_list_head, kld_info) kldlist;
78176771Sraj#endif
79176771Sraj
80176771Srajstatic int dflag, verbose;
81176771Sraj
82176771SrajFILE *fxref;
83176771Sraj
84176771Srajstatic const char *xref_file = "linker.hints";
85176771Sraj
86176771Srajstatic char recbuf[MAXRECSIZE];
87176771Srajstatic int recpos, reccnt;
88192067Snwhitehorn
89176771SrajFILE *maketempfile(char *, const char *);
90176771Srajstatic void usage(void);
91176771Sraj
92176771Srajstatic void
93176771Srajintalign(void)
94176771Sraj{
95176771Sraj	recpos = (recpos + sizeof(int) - 1) & ~(sizeof(int) - 1);
96176771Sraj}
97176771Sraj
98176771Srajstatic void
99297784Sjhibbitsrecord_start(void)
100176771Sraj{
101176771Sraj	recpos = 0;
102176771Sraj	memset(recbuf, 0, MAXRECSIZE);
103176771Sraj}
104176771Sraj
105176771Srajstatic int
106176771Srajrecord_end(void)
107176771Sraj{
108190701Smarcel	if (dflag || recpos == 0)
109190701Smarcel		return 0;
110190701Smarcel	reccnt++;
111224611Smarcel	intalign();
112224611Smarcel	fwrite(&recpos, sizeof(recpos), 1, fxref);
113224611Smarcel	return fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0;
114190701Smarcel}
115190701Smarcel
116176771Srajstatic int
117190701Smarcelrecord_buf(const void *buf, int size)
118190701Smarcel{
119190701Smarcel	if (MAXRECSIZE - recpos < size)
120190701Smarcel		errx(1, "record buffer overflow");
121192067Snwhitehorn	memcpy(recbuf + recpos, buf, size);
122192067Snwhitehorn	recpos += size;
123192067Snwhitehorn	return 0;
124192067Snwhitehorn}
125192067Snwhitehorn
126176771Srajstatic int
127176771Srajrecord_int(int val)
128176771Sraj{
129176771Sraj	intalign();
130176771Sraj	return record_buf(&val, sizeof(val));
131187149Sraj}
132187149Sraj
133176771Srajstatic int
134176771Srajrecord_byte(u_char val)
135176771Sraj{
136176771Sraj	return record_buf(&val, sizeof(val));
137176771Sraj}
138176771Sraj
139176771Srajstatic int
140176771Srajrecord_string(const char *str)
141176771Sraj{
142176771Sraj	int len = strlen(str);
143176771Sraj	int error;
144176771Sraj
145176771Sraj	if (dflag)
146176771Sraj		return 0;
147176771Sraj	error = record_byte(len);
148269728Skib	if (error)
149269728Skib		return error;
150176771Sraj	return record_buf(str, len);
151176771Sraj}
152176771Sraj
153176771Srajstatic int
154176771Srajparse_entry(struct mod_metadata *md, const char *cval,
155176771Sraj    struct elf_file *ef, const char *kldname)
156176771Sraj{
157176771Sraj	struct mod_depend mdp;
158176771Sraj	struct mod_version mdv;
159176771Sraj	Elf_Off data = (Elf_Off)md->md_data;
160176771Sraj	int error = 0;
161279504Snwhitehorn
162176771Sraj	record_start();
163176771Sraj	switch (md->md_type) {
164176771Sraj	case MDT_DEPEND:
165176771Sraj		if (!dflag)
166176771Sraj			break;
167176771Sraj		check(EF_SEG_READ(ef, data, sizeof(mdp), &mdp));
168187149Sraj		printf("  depends on %s.%d (%d,%d)\n", cval,
169176771Sraj		    mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum);
170176771Sraj		break;
171187149Sraj	case MDT_VERSION:
172187149Sraj		check(EF_SEG_READ(ef, data, sizeof(mdv), &mdv));
173176771Sraj		record_int(MDT_VERSION);
174187149Sraj		record_string(cval);
175187149Sraj		record_int(mdv.mv_version);
176187149Sraj		record_string(kldname);
177287240Sjhibbits		if (!dflag)
178176771Sraj			break;
179187149Sraj		printf("  interface %s.%d\n", cval, mdv.mv_version);
180187149Sraj		break;
181187149Sraj	case MDT_MODULE:
182176771Sraj		record_int(MDT_MODULE);
183287240Sjhibbits		record_string(cval);
184287240Sjhibbits		record_string(kldname);
185176771Sraj		if (!dflag)
186297785Sjhibbits			break;
187176771Sraj		printf("  module %s\n", cval);
188176771Sraj		break;
189292900Sjhibbits	default:
190176771Sraj		warnx("unknown metadata record %d in file %s", md->md_type, kldname);
191187149Sraj	}
192176771Sraj	if (!error)
193298237Sjhibbits		record_end();
194298237Sjhibbits	return error;
195176771Sraj}
196224611Smarcel
197176771Srajstatic int
198176771Srajread_kld(char *filename, char *kldname)
199176771Sraj{
200176771Sraj	struct mod_metadata md;
201176771Sraj	struct elf_file ef;
202176771Sraj/*	struct kld_info *kip;
203176771Sraj	struct mod_info *mip;*/
204187149Sraj	void **p, **orgp;
205176771Sraj	int error, eftype, nmlen;
206176771Sraj	long start, finish, entries;
207176771Sraj	char kldmodname[MAXMODNAME + 1], cval[MAXMODNAME + 1], *cp;
208176771Sraj
209176771Sraj	if (verbose || dflag)
210176771Sraj		printf("%s\n", filename);
211242535Salc	error = ef_open(filename, &ef, verbose);
212242535Salc	if (error) {
213176771Sraj		error = ef_obj_open(filename, &ef, verbose);
214176771Sraj		if (error) {
215176771Sraj			if (verbose)
216176771Sraj				warnc(error, "elf_open(%s)", filename);
217176771Sraj			return error;
218176771Sraj		}
219176771Sraj	}
220176771Sraj	eftype = EF_GET_TYPE(&ef);
221176771Sraj	if (eftype != EFT_KLD && eftype != EFT_KERNEL)  {
222176771Sraj		EF_CLOSE(&ef);
223176771Sraj		return 0;
224176771Sraj	}
225176771Sraj	if (!dflag) {
226176771Sraj		cp = strrchr(kldname, '.');
227176771Sraj		nmlen = cp ? min(MAXMODNAME, cp - kldname) :
228269728Skib		    min(MAXMODNAME, strlen(kldname));
229176771Sraj		strncpy(kldmodname, kldname, nmlen);
230176771Sraj		kldmodname[nmlen] = '\0';
231176771Sraj/*		fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/
232176771Sraj	}
233176771Sraj	do {
234176771Sraj		check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish,
235269728Skib		    &entries));
236187149Sraj		check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries,
237294307Sjhibbits		    (void *)&p));
238294307Sjhibbits		orgp = p;
239176771Sraj		while(entries--) {
240187149Sraj			check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md),
241176771Sraj			    &md));
242176771Sraj			p++;
243176771Sraj			check(EF_SEG_READ(&ef, (Elf_Off)md.md_cval,
244176771Sraj			    sizeof(cval), cval));
245286296Sjah			cval[MAXMODNAME] = '\0';
246286296Sjah			parse_entry(&md, cval, &ef, kldname);
247176771Sraj		}
248176771Sraj		if (error)
249176771Sraj			warnc(error, "error while reading %s", filename);
250176771Sraj		free(orgp);
251176771Sraj	} while(0);
252176771Sraj	EF_CLOSE(&ef);
253176771Sraj	return error;
254176771Sraj}
255176771Sraj
256176771SrajFILE *
257176771Srajmaketempfile(char *dest, const char *root)
258176771Sraj{
259176771Sraj	char *p;
260176771Sraj	int fd;
261176771Sraj
262176771Sraj	strncpy(dest, root, MAXPATHLEN - 1);
263176771Sraj	dest[MAXPATHLEN-1] = '\0';
264176771Sraj
265280794Sjhibbits	if ((p = strrchr(dest, '/')) != 0)
266298237Sjhibbits		p++;
267192532Sraj	else
268280794Sjhibbits		p = dest;
269192532Sraj	strcpy(p, "lhint.XXXXXX");
270176771Sraj	fd = mkstemp(dest);
271176771Sraj	return ((fd == -1) ? NULL : fdopen(fd, "w+"));
272176771Sraj}
273176771Sraj
274194101Srajstatic char xrefname[MAXPATHLEN], tempname[MAXPATHLEN];
275194101Sraj
276176771Srajint
277248280Skibmain(int argc, char *argv[])
278248280Skib{
279269728Skib	FTS *ftsp;
280269728Skib	FTSENT *p;
281176771Sraj	int opt, fts_options, ival;
282176771Sraj	struct stat sb;
283176771Sraj
284176771Sraj	fts_options = FTS_PHYSICAL;
285176771Sraj/*	SLIST_INIT(&kldlist);*/
286176771Sraj
287176771Sraj	while ((opt = getopt(argc, argv, "Rdf:v")) != -1) {
288176771Sraj		switch (opt) {
289176771Sraj		case 'd':
290176771Sraj			dflag = 1;
291207155Salc			break;
292238357Salc		case 'f':
293235936Sraj			xref_file = optarg;
294176771Sraj			break;
295208504Salc		case 'v':
296208504Salc			verbose++;
297176771Sraj			break;
298176771Sraj		case 'R':
299176771Sraj			fts_options |= FTS_COMFOLLOW;
300176771Sraj			break;
301176771Sraj		default:
302176771Sraj			usage();
303176771Sraj			/* NOTREACHED */
304176771Sraj		}
305176771Sraj	}
306176771Sraj	if (argc - optind < 1)
307176771Sraj		usage();
308176771Sraj	argc -= optind;
309176771Sraj	argv += optind;
310176771Sraj
311176771Sraj	if (stat(argv[0], &sb) != 0)
312268591Salc		err(1, "%s", argv[0]);
313176771Sraj	if ((sb.st_mode & S_IFDIR) == 0) {
314176771Sraj		errno = ENOTDIR;
315176771Sraj		err(1, "%s", argv[0]);
316176771Sraj	}
317176771Sraj
318176771Sraj	ftsp = fts_open(argv, fts_options, 0);
319235936Sraj	if (ftsp == NULL)
320257161Snwhitehorn		exit(1);
321176771Sraj
322235936Sraj	for (;;) {
323235936Sraj		p = fts_read(ftsp);
324257161Snwhitehorn		if ((p == NULL || p->fts_info == FTS_D) && !dflag && fxref) {
325176771Sraj			fclose(fxref);
326235936Sraj			fxref = NULL;
327198341Smarcel			if (reccnt) {
328198341Smarcel				rename(tempname, xrefname);
329276772Smarkj			} else {
330276772Smarkj				unlink(tempname);
331276772Smarkj				unlink(xrefname);
332276772Smarkj			}
333276772Smarkj		}
334286296Sjah		if (p == NULL)
335286296Sjah			break;
336296142Sjhibbits		if (p && p->fts_info == FTS_D && !dflag) {
337296142Sjhibbits			snprintf(xrefname, sizeof(xrefname), "%s/%s",
338176771Sraj			    ftsp->fts_path, xref_file);
339176771Sraj			fxref = maketempfile(tempname, ftsp->fts_path);
340176771Sraj			if (fxref == NULL)
341176771Sraj				err(1, "can't create %s", tempname);
342176771Sraj			ival = 1;
343176771Sraj			fwrite(&ival, sizeof(ival), 1, fxref);
344248280Skib			reccnt = 0;
345176771Sraj		}
346176771Sraj		if (p->fts_info != FTS_F)
347176771Sraj			continue;
348176771Sraj		if (p->fts_namelen >= 8 &&
349176771Sraj		    strcmp(p->fts_name + p->fts_namelen - 8, ".symbols") == 0)
350176771Sraj			continue;
351176771Sraj		read_kld(p->fts_path, p->fts_name);
352176771Sraj	}
353207155Salc	fts_close(ftsp);
354176771Sraj	return 0;
355176771Sraj}
356176771Sraj
357176771Srajstatic void
358176771Srajusage(void)
359176771Sraj{
360176771Sraj
361176771Sraj	fprintf(stderr, "%s\n",
362176771Sraj	    "usage: kldxref [-Rdv] [-f hintsfile] path ..."
363176771Sraj	);
364176771Sraj	exit(1);
365176771Sraj}
366176771Sraj