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