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