xref: /freebsd/usr.sbin/kldxref/kldxref.c (revision 63c6d3e283eb01d32f54e2a153e6719d19e4a80d)
1  /*-
2   * SPDX-License-Identifier: BSD-4-Clause
3   *
4   * Copyright (c) 2000, Boris Popov
5   * All rights reserved.
6   *
7   * Redistribution and use in source and binary forms, with or without
8   * modification, are permitted provided that the following conditions
9   * are met:
10   * 1. Redistributions of source code must retain the above copyright
11   *    notice, this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright
13   *    notice, this list of conditions and the following disclaimer in the
14   *    documentation and/or other materials provided with the distribution.
15   * 3. All advertising materials mentioning features or use of this software
16   *    must display the following acknowledgement:
17   *    This product includes software developed by Boris Popov.
18   * 4. Neither the name of the author nor the names of any co-contributors
19   *    may be used to endorse or promote products derived from this software
20   *    without specific prior written permission.
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32   * SUCH DAMAGE.
33   *
34   * $FreeBSD$
35   */
36  
37  #include <sys/types.h>
38  #include <sys/param.h>
39  #include <sys/endian.h>
40  #include <sys/exec.h>
41  #include <sys/queue.h>
42  #include <sys/kernel.h>
43  #include <sys/reboot.h>
44  #include <sys/linker.h>
45  #include <sys/stat.h>
46  #include <sys/module.h>
47  #define FREEBSD_ELF
48  
49  #include <ctype.h>
50  #include <err.h>
51  #include <errno.h>
52  #include <fts.h>
53  #include <stdbool.h>
54  #include <stdio.h>
55  #include <stdlib.h>
56  #include <string.h>
57  #include <unistd.h>
58  #include <machine/elf.h>
59  
60  #include "ef.h"
61  
62  #define	MAXRECSIZE	(64 << 10)	/* 64k */
63  #define check(val)	if ((error = (val)) != 0) break
64  
65  static bool dflag;	/* do not create a hint file, only write on stdout */
66  static int verbose;
67  
68  static FILE *fxref;	/* current hints file */
69  
70  static const char *xref_file = "linker.hints";
71  
72  /*
73   * A record is stored in the static buffer recbuf before going to disk.
74   */
75  static char recbuf[MAXRECSIZE];
76  static int recpos;	/* current write position */
77  static int reccnt;	/* total record written to this file so far */
78  
79  static void
80  intalign(void)
81  {
82  
83  	recpos = roundup2(recpos, sizeof(int));
84  }
85  
86  static void
87  record_start(void)
88  {
89  
90  	recpos = 0;
91  	memset(recbuf, 0, MAXRECSIZE);
92  }
93  
94  static int
95  record_end(void)
96  {
97  
98  	if (recpos == 0)
99  		return (0);
100  	reccnt++;
101  	intalign();
102  	fwrite(&recpos, sizeof(recpos), 1, fxref);
103  	return (fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0);
104  }
105  
106  static int
107  record_buf(const void *buf, size_t size)
108  {
109  
110  	if (MAXRECSIZE - recpos < size)
111  		errx(1, "record buffer overflow");
112  	memcpy(recbuf + recpos, buf, size);
113  	recpos += size;
114  	return (0);
115  }
116  
117  /*
118   * An int is stored in host order and aligned
119   */
120  static int
121  record_int(int val)
122  {
123  
124  	intalign();
125  	return (record_buf(&val, sizeof(val)));
126  }
127  
128  /*
129   * A string is stored as 1-byte length plus data, no padding
130   */
131  static int
132  record_string(const char *str)
133  {
134  	int error;
135  	size_t len;
136  	u_char val;
137  
138  	if (dflag)
139  		return (0);
140  	val = len = strlen(str);
141  	if (len > 255)
142  		errx(1, "string %s too long", str);
143  	error = record_buf(&val, sizeof(val));
144  	if (error != 0)
145  		return (error);
146  	return (record_buf(str, len));
147  }
148  
149  /* From sys/isa/pnp.c */
150  static char *
151  pnp_eisaformat(uint32_t id)
152  {
153  	uint8_t *data;
154  	static char idbuf[8];
155  	const char  hextoascii[] = "0123456789abcdef";
156  
157  	id = htole32(id);
158  	data = (uint8_t *)&id;
159  	idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
160  	idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
161  	idbuf[2] = '@' + (data[1] & 0x1f);
162  	idbuf[3] = hextoascii[(data[2] >> 4)];
163  	idbuf[4] = hextoascii[(data[2] & 0xf)];
164  	idbuf[5] = hextoascii[(data[3] >> 4)];
165  	idbuf[6] = hextoascii[(data[3] & 0xf)];
166  	idbuf[7] = 0;
167  	return (idbuf);
168  }
169  
170  struct pnp_elt
171  {
172  	int	pe_kind;	/* What kind of entry */
173  #define TYPE_SZ_MASK	0x0f
174  #define TYPE_FLAGGED	0x10	/* all f's is a wildcard */
175  #define	TYPE_INT	0x20	/* Is a number */
176  #define TYPE_PAIRED	0x40
177  #define TYPE_LE		0x80	/* Matches <= this value */
178  #define TYPE_GE		0x100	/* Matches >= this value */
179  #define TYPE_MASK	0x200	/* Specifies a mask to follow */
180  #define TYPE_U8		(1 | TYPE_INT)
181  #define TYPE_V8		(1 | TYPE_INT | TYPE_FLAGGED)
182  #define TYPE_G16	(2 | TYPE_INT | TYPE_GE)
183  #define TYPE_L16	(2 | TYPE_INT | TYPE_LE)
184  #define TYPE_M16	(2 | TYPE_INT | TYPE_MASK)
185  #define TYPE_U16	(2 | TYPE_INT)
186  #define TYPE_V16	(2 | TYPE_INT | TYPE_FLAGGED)
187  #define TYPE_U32	(4 | TYPE_INT)
188  #define TYPE_V32	(4 | TYPE_INT | TYPE_FLAGGED)
189  #define TYPE_W32	(4 | TYPE_INT | TYPE_PAIRED)
190  #define TYPE_D		7
191  #define TYPE_Z		8
192  #define TYPE_P		9
193  #define TYPE_E		10
194  #define TYPE_T		11
195  	int	pe_offset;	/* Offset within the element */
196  	char *	pe_key;		/* pnp key name */
197  	TAILQ_ENTRY(pnp_elt) next; /* Link */
198  };
199  typedef TAILQ_HEAD(pnp_head, pnp_elt) pnp_list;
200  
201  /*
202   * this function finds the data from the pnp table, as described by the
203   * the description and creates a new output (new_desc). This output table
204   * is a form that's easier for the agent that's automatically loading the
205   * modules.
206   *
207   * The format output is the simplified string from this routine in the
208   * same basic format as the pnp string, as documented in sys/module.h.
209   * First a string describing the format is output, the a count of the
210   * number of records, then each record. The format string also describes
211   * the length of each entry (though it isn't a fixed length when strings
212   * are present).
213   *
214   *	type	Output		Meaning
215   *	I	uint32_t	Integer equality comparison
216   *	J	uint32_t	Pair of uint16_t fields converted to native
217   *				byte order. The two fields both must match.
218   *	G	uint32_t	Greater than or equal to
219   *	L	uint32_t	Less than or equal to
220   *	M	uint32_t	Mask of which fields to test. Fields that
221   *				take up space increment the count. This
222   *				field must be first, and resets the count.
223   *	D	string		Description of the device this pnp info is for
224   *	Z	string		pnp string must match this
225   *	T	nothing		T fields set pnp values that must be true for
226   *				the entire table.
227   * Values are packed the same way that other values are packed in this file.
228   * Strings and int32_t's start on a 32-bit boundary and are padded with 0
229   * bytes. Objects that are smaller than uint32_t are converted, without
230   * sign extension to uint32_t to simplify parsing downstream.
231   */
232  static int
233  parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
234  {
235  	const char *walker, *ep;
236  	const char *colon, *semi;
237  	struct pnp_elt *elt;
238  	char type[8], key[32];
239  	int off;
240  	size_t new_desc_size;
241  	FILE *fp;
242  
243  	walker = desc;
244  	ep = desc + strlen(desc);
245  	off = 0;
246  	fp = open_memstream(new_desc, &new_desc_size);
247  	if (fp == NULL)
248  		err(1, "Could not open new memory stream");
249  	if (verbose > 1)
250  		printf("Converting %s into a list\n", desc);
251  	while (walker < ep) {
252  		colon = strchr(walker, ':');
253  		semi = strchr(walker, ';');
254  		if (semi != NULL && semi < colon)
255  			goto err;
256  		if (colon - walker > sizeof(type))
257  			goto err;
258  		strncpy(type, walker, colon - walker);
259  		type[colon - walker] = '\0';
260  		if (semi != NULL) {
261  			if (semi - colon >= sizeof(key))
262  				goto err;
263  			strncpy(key, colon + 1, semi - colon - 1);
264  			key[semi - colon - 1] = '\0';
265  			walker = semi + 1;
266  			/* Fail safe if we have spaces after ; */
267  			while (walker < ep && isspace(*walker))
268  				walker++;
269  		} else {
270  			if (strlen(colon + 1) >= sizeof(key))
271  				goto err;
272  			strcpy(key, colon + 1);
273  			walker = ep;
274  		}
275  		if (verbose > 1)
276  			printf("Found type %s for name %s\n", type, key);
277  		/* Skip pointer place holders */
278  		if (strcmp(type, "P") == 0) {
279  			off += sizeof(void *);
280  			continue;
281  		}
282  
283  		/*
284  		 * Add a node of the appropriate type
285  		 */
286  		elt = malloc(sizeof(struct pnp_elt) + strlen(key) + 1);
287  		TAILQ_INSERT_TAIL(list, elt, next);
288  		elt->pe_key = (char *)(elt + 1);
289  		elt->pe_offset = off;
290  		if (strcmp(type, "U8") == 0)
291  			elt->pe_kind = TYPE_U8;
292  		else if (strcmp(type, "V8") == 0)
293  			elt->pe_kind = TYPE_V8;
294  		else if (strcmp(type, "G16") == 0)
295  			elt->pe_kind = TYPE_G16;
296  		else if (strcmp(type, "L16") == 0)
297  			elt->pe_kind = TYPE_L16;
298  		else if (strcmp(type, "M16") == 0)
299  			elt->pe_kind = TYPE_M16;
300  		else if (strcmp(type, "U16") == 0)
301  			elt->pe_kind = TYPE_U16;
302  		else if (strcmp(type, "V16") == 0)
303  			elt->pe_kind = TYPE_V16;
304  		else if (strcmp(type, "U32") == 0)
305  			elt->pe_kind = TYPE_U32;
306  		else if (strcmp(type, "V32") == 0)
307  			elt->pe_kind = TYPE_V32;
308  		else if (strcmp(type, "W32") == 0)
309  			elt->pe_kind = TYPE_W32;
310  		else if (strcmp(type, "D") == 0)	/* description char * */
311  			elt->pe_kind = TYPE_D;
312  		else if (strcmp(type, "Z") == 0)	/* char * to match */
313  			elt->pe_kind = TYPE_Z;
314  		else if (strcmp(type, "P") == 0)	/* Pointer -- ignored */
315  			elt->pe_kind = TYPE_P;
316  		else if (strcmp(type, "E") == 0)	/* EISA PNP ID, as uint32_t */
317  			elt->pe_kind = TYPE_E;
318  		else if (strcmp(type, "T") == 0)
319  			elt->pe_kind = TYPE_T;
320  		else
321  			goto err;
322  		/*
323  		 * Maybe the rounding here needs to be more nuanced and/or somehow
324  		 * architecture specific. Fortunately, most tables in the system
325  		 * have sane ordering of types.
326  		 */
327  		if (elt->pe_kind & TYPE_INT) {
328  			elt->pe_offset = roundup2(elt->pe_offset, elt->pe_kind & TYPE_SZ_MASK);
329  			off = elt->pe_offset + (elt->pe_kind & TYPE_SZ_MASK);
330  		} else if (elt->pe_kind == TYPE_E) {
331  			/* Type E stored as Int, displays as string */
332  			elt->pe_offset = roundup2(elt->pe_offset, sizeof(uint32_t));
333  			off = elt->pe_offset + sizeof(uint32_t);
334  		} else if (elt->pe_kind == TYPE_T) {
335  			/* doesn't actually consume space in the table */
336  			off = elt->pe_offset;
337  		} else {
338  			elt->pe_offset = roundup2(elt->pe_offset, sizeof(void *));
339  			off = elt->pe_offset + sizeof(void *);
340  		}
341  		if (elt->pe_kind & TYPE_PAIRED) {
342  			char *word, *ctx, newtype;
343  
344  			for (word = strtok_r(key, "/", &ctx);
345  			     word; word = strtok_r(NULL, "/", &ctx)) {
346  				newtype = elt->pe_kind & TYPE_FLAGGED ? 'J' : 'I';
347  				fprintf(fp, "%c:%s;", newtype, word);
348  			}
349  		}
350  		else {
351  			char newtype;
352  
353  			if (elt->pe_kind & TYPE_FLAGGED)
354  				newtype = 'J';
355  			else if (elt->pe_kind & TYPE_GE)
356  				newtype = 'G';
357  			else if (elt->pe_kind & TYPE_LE)
358  				newtype = 'L';
359  			else if (elt->pe_kind & TYPE_MASK)
360  				newtype = 'M';
361  			else if (elt->pe_kind & TYPE_INT)
362  				newtype = 'I';
363  			else if (elt->pe_kind == TYPE_D)
364  				newtype = 'D';
365  			else if (elt->pe_kind == TYPE_Z || elt->pe_kind == TYPE_E)
366  				newtype = 'Z';
367  			else if (elt->pe_kind == TYPE_T)
368  				newtype = 'T';
369  			else
370  				errx(1, "Impossible type %x\n", elt->pe_kind);
371  			fprintf(fp, "%c:%s;", newtype, key);
372  		}
373  	}
374  	if (ferror(fp) != 0) {
375  		fclose(fp);
376  		errx(1, "Exhausted space converting description %s", desc);
377  	}
378  	if (fclose(fp) != 0)
379  		errx(1, "Failed to close memory stream");
380  	return (0);
381  err:
382  	errx(1, "Parse error of description string %s", desc);
383  }
384  
385  static int
386  parse_entry(struct mod_metadata *md, const char *cval,
387      struct elf_file *ef, const char *kldname)
388  {
389  	struct mod_depend mdp;
390  	struct mod_version mdv;
391  	struct mod_pnp_match_info pnp;
392  	char descr[1024];
393  	Elf_Off data;
394  	int error, i;
395  	size_t len;
396  	char *walker;
397  	void *table;
398  
399  	data = (Elf_Off)md->md_data;
400  	error = 0;
401  	record_start();
402  	switch (md->md_type) {
403  	case MDT_DEPEND:
404  		if (!dflag)
405  			break;
406  		check(EF_SEG_READ(ef, data, sizeof(mdp), &mdp));
407  		printf("  depends on %s.%d (%d,%d)\n", cval,
408  		    mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum);
409  		break;
410  	case MDT_VERSION:
411  		check(EF_SEG_READ(ef, data, sizeof(mdv), &mdv));
412  		if (dflag) {
413  			printf("  interface %s.%d\n", cval, mdv.mv_version);
414  		} else {
415  			record_int(MDT_VERSION);
416  			record_string(cval);
417  			record_int(mdv.mv_version);
418  			record_string(kldname);
419  		}
420  		break;
421  	case MDT_MODULE:
422  		if (dflag) {
423  			printf("  module %s\n", cval);
424  		} else {
425  			record_int(MDT_MODULE);
426  			record_string(cval);
427  			record_string(kldname);
428  		}
429  		break;
430  	case MDT_PNP_INFO:
431  		check(EF_SEG_READ_REL(ef, data, sizeof(pnp), &pnp));
432  		check(EF_SEG_READ_STRING(ef, (Elf_Off)pnp.descr, sizeof(descr), descr));
433  		descr[sizeof(descr) - 1] = '\0';
434  		if (dflag) {
435  			printf("  pnp info for bus %s format %s %d entries of %d bytes\n",
436  			    cval, descr, pnp.num_entry, pnp.entry_len);
437  		} else {
438  			pnp_list list;
439  			struct pnp_elt *elt, *elt_tmp;
440  			char *new_descr;
441  
442  			if (verbose > 1)
443  				printf("  pnp info for bus %s format %s %d entries of %d bytes\n",
444  				    cval, descr, pnp.num_entry, pnp.entry_len);
445  			/*
446  			 * Parse descr to weed out the chaff and to create a list
447  			 * of offsets to output.
448  			 */
449  			TAILQ_INIT(&list);
450  			parse_pnp_list(descr, &new_descr, &list);
451  			record_int(MDT_PNP_INFO);
452  			record_string(cval);
453  			record_string(new_descr);
454  			record_int(pnp.num_entry);
455  			len = pnp.num_entry * pnp.entry_len;
456  			walker = table = malloc(len);
457  			check(EF_SEG_READ_REL(ef, (Elf_Off)pnp.table, len, table));
458  
459  			/*
460  			 * Walk the list and output things. We've collapsed all the
461  			 * variant forms of the table down to just ints and strings.
462  			 */
463  			for (i = 0; i < pnp.num_entry; i++) {
464  				TAILQ_FOREACH(elt, &list, next) {
465  					uint8_t v1;
466  					uint16_t v2;
467  					uint32_t v4;
468  					int	value;
469  					char buffer[1024];
470  
471  					if (elt->pe_kind == TYPE_W32) {
472  						memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
473  						value = v4 & 0xffff;
474  						record_int(value);
475  						if (verbose > 1)
476  							printf("W32:%#x", value);
477  						value = (v4 >> 16) & 0xffff;
478  						record_int(value);
479  						if (verbose > 1)
480  							printf(":%#x;", value);
481  					} else if (elt->pe_kind & TYPE_INT) {
482  						switch (elt->pe_kind & TYPE_SZ_MASK) {
483  						case 1:
484  							memcpy(&v1, walker + elt->pe_offset, sizeof(v1));
485  							if ((elt->pe_kind & TYPE_FLAGGED) && v1 == 0xff)
486  								value = -1;
487  							else
488  								value = v1;
489  							break;
490  						case 2:
491  							memcpy(&v2, walker + elt->pe_offset, sizeof(v2));
492  							if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff)
493  								value = -1;
494  							else
495  								value = v2;
496  							break;
497  						case 4:
498  							memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
499  							if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff)
500  								value = -1;
501  							else
502  								value = v4;
503  							break;
504  						default:
505  							errx(1, "Invalid size somehow %#x", elt->pe_kind);
506  						}
507  						if (verbose > 1)
508  							printf("I:%#x;", value);
509  						record_int(value);
510  					} else if (elt->pe_kind == TYPE_T) {
511  						/* Do nothing */
512  					} else { /* E, Z or D -- P already filtered */
513  						if (elt->pe_kind == TYPE_E) {
514  							memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
515  							strcpy(buffer, pnp_eisaformat(v4));
516  						} else {
517  							char *ptr;
518  
519  							ptr = *(char **)(walker + elt->pe_offset);
520  							buffer[0] = '\0';
521  							if (ptr != NULL) {
522  								EF_SEG_READ_STRING(ef, (Elf_Off)ptr,
523  								    sizeof(buffer), buffer);
524  								buffer[sizeof(buffer) - 1] = '\0';
525  							}
526  						}
527  						if (verbose > 1)
528  							printf("%c:%s;", elt->pe_kind == TYPE_E ? 'E' : (elt->pe_kind == TYPE_Z ? 'Z' : 'D'), buffer);
529  						record_string(buffer);
530  					}
531  				}
532  				if (verbose > 1)
533  					printf("\n");
534  				walker += pnp.entry_len;
535  			}
536  			/* Now free it */
537  			TAILQ_FOREACH_SAFE(elt, &list, next, elt_tmp) {
538  				TAILQ_REMOVE(&list, elt, next);
539  				free(elt);
540  			}
541  			free(table);
542  		}
543  		break;
544  	default:
545  		warnx("unknown metadata record %d in file %s", md->md_type, kldname);
546  	}
547  	if (!error)
548  		record_end();
549  	return (error);
550  }
551  
552  static int
553  read_kld(char *filename, char *kldname)
554  {
555  	struct mod_metadata md;
556  	struct elf_file ef;
557  	void **p;
558  	int error, eftype;
559  	long start, finish, entries, i;
560  	char cval[MAXMODNAME + 1];
561  
562  	if (verbose || dflag)
563  		printf("%s\n", filename);
564  	error = ef_open(filename, &ef, verbose);
565  	if (error != 0) {
566  		error = ef_obj_open(filename, &ef, verbose);
567  		if (error != 0) {
568  			if (verbose)
569  				warnc(error, "elf_open(%s)", filename);
570  			return (error);
571  		}
572  	}
573  	eftype = EF_GET_TYPE(&ef);
574  	if (eftype != EFT_KLD && eftype != EFT_KERNEL)  {
575  		EF_CLOSE(&ef);
576  		return (0);
577  	}
578  	do {
579  		check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish,
580  		    &entries));
581  		check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries,
582  		    (void *)&p));
583  		/*
584  		 * Do a first pass to find MDT_MODULE.  It is required to be
585  		 * ordered first in the output linker.hints stream because it
586  		 * serves as an implicit record boundary between distinct klds
587  		 * in the stream.  Other MDTs only make sense in the context of
588  		 * a specific MDT_MODULE.
589  		 *
590  		 * Some compilers (e.g., GCC 6.4.0 xtoolchain) or binutils
591  		 * (e.g., GNU binutils 2.32 objcopy/ld.bfd) can reorder
592  		 * MODULE_METADATA set entries relative to the source ordering.
593  		 * This is permitted by the C standard; memory layout of
594  		 * file-scope objects is left implementation-defined.  There is
595  		 * no requirement that source code ordering is retained.
596  		 *
597  		 * Handle that here by taking two passes to ensure MDT_MODULE
598  		 * records are emitted to linker.hints before other MDT records
599  		 * in the same kld.
600  		 */
601  		for (i = 0; i < entries; i++) {
602  			check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md),
603  			    &md));
604  			check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval,
605  			    sizeof(cval), cval));
606  			if (md.md_type == MDT_MODULE) {
607  				parse_entry(&md, cval, &ef, kldname);
608  				break;
609  			}
610  		}
611  		if (error != 0) {
612  			warnc(error, "error while reading %s", filename);
613  			break;
614  		}
615  
616  		/*
617  		 * Second pass for all !MDT_MODULE entries.
618  		 */
619  		for (i = 0; i < entries; i++) {
620  			check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md),
621  			    &md));
622  			check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval,
623  			    sizeof(cval), cval));
624  			if (md.md_type != MDT_MODULE)
625  				parse_entry(&md, cval, &ef, kldname);
626  		}
627  		if (error != 0)
628  			warnc(error, "error while reading %s", filename);
629  		free(p);
630  	} while(0);
631  	EF_CLOSE(&ef);
632  	return (error);
633  }
634  
635  /*
636   * Create a temp file in directory root, make sure we don't
637   * overflow the buffer for the destination name
638   */
639  static FILE *
640  maketempfile(char *dest, const char *root)
641  {
642  	char *p;
643  	int n, fd;
644  
645  	p = strrchr(root, '/');
646  	n = p != NULL ? p - root + 1 : 0;
647  	if (snprintf(dest, MAXPATHLEN, "%.*slhint.XXXXXX", n, root) >=
648  	    MAXPATHLEN) {
649  		errno = ENAMETOOLONG;
650  		return (NULL);
651  	}
652  
653  	fd = mkstemp(dest);
654  	if (fd < 0)
655  		return (NULL);
656  	fchmod(fd, 0644);	/* nothing secret in the file */
657  	return (fdopen(fd, "w+"));
658  }
659  
660  static char xrefname[MAXPATHLEN], tempname[MAXPATHLEN];
661  
662  static void
663  usage(void)
664  {
665  
666  	fprintf(stderr, "%s\n",
667  	    "usage: kldxref [-Rdv] [-f hintsfile] path ..."
668  	);
669  	exit(1);
670  }
671  
672  static int
673  compare(const FTSENT *const *a, const FTSENT *const *b)
674  {
675  
676  	if ((*a)->fts_info == FTS_D && (*b)->fts_info != FTS_D)
677  		return (1);
678  	if ((*a)->fts_info != FTS_D && (*b)->fts_info == FTS_D)
679  		return (-1);
680  	return (strcmp((*a)->fts_name, (*b)->fts_name));
681  }
682  
683  int
684  main(int argc, char *argv[])
685  {
686  	FTS *ftsp;
687  	FTSENT *p;
688  	int opt, fts_options, ival;
689  	struct stat sb;
690  
691  	fts_options = FTS_PHYSICAL;
692  
693  	while ((opt = getopt(argc, argv, "Rdf:v")) != -1) {
694  		switch (opt) {
695  		case 'd':	/* no hint file, only print on stdout */
696  			dflag = true;
697  			break;
698  		case 'f':	/* use this name instead of linker.hints */
699  			xref_file = optarg;
700  			break;
701  		case 'v':
702  			verbose++;
703  			break;
704  		case 'R':	/* recurse on directories */
705  			fts_options |= FTS_COMFOLLOW;
706  			break;
707  		default:
708  			usage();
709  			/* NOTREACHED */
710  		}
711  	}
712  	if (argc - optind < 1)
713  		usage();
714  	argc -= optind;
715  	argv += optind;
716  
717  	if (stat(argv[0], &sb) != 0)
718  		err(1, "%s", argv[0]);
719  	if ((sb.st_mode & S_IFDIR) == 0 && !dflag) {
720  		errno = ENOTDIR;
721  		err(1, "%s", argv[0]);
722  	}
723  
724  	ftsp = fts_open(argv, fts_options, compare);
725  	if (ftsp == NULL)
726  		exit(1);
727  
728  	for (;;) {
729  		p = fts_read(ftsp);
730  		if ((p == NULL || p->fts_info == FTS_D) && fxref) {
731  			/* close and rename the current hint file */
732  			fclose(fxref);
733  			fxref = NULL;
734  			if (reccnt != 0) {
735  				rename(tempname, xrefname);
736  			} else {
737  				/* didn't find any entry, ignore this file */
738  				unlink(tempname);
739  				unlink(xrefname);
740  			}
741  		}
742  		if (p == NULL)
743  			break;
744  		if (p->fts_info == FTS_D && !dflag) {
745  			/* visiting a new directory, create a new hint file */
746  			snprintf(xrefname, sizeof(xrefname), "%s/%s",
747  			    ftsp->fts_path, xref_file);
748  			fxref = maketempfile(tempname, ftsp->fts_path);
749  			if (fxref == NULL)
750  				err(1, "can't create %s", tempname);
751  			ival = 1;
752  			fwrite(&ival, sizeof(ival), 1, fxref);
753  			reccnt = 0;
754  		}
755  		/* skip non-files and separate debug files */
756  		if (p->fts_info != FTS_F)
757  			continue;
758  		if (p->fts_namelen >= 6 &&
759  		    strcmp(p->fts_name + p->fts_namelen - 6, ".debug") == 0)
760  			continue;
761  		if (p->fts_namelen >= 8 &&
762  		    strcmp(p->fts_name + p->fts_namelen - 8, ".symbols") == 0)
763  			continue;
764  		read_kld(p->fts_path, p->fts_name);
765  	}
766  	fts_close(ftsp);
767  	return (0);
768  }
769