xref: /dragonfly/usr.sbin/asf/asf.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (c) 2002, 2003 Greg Lehey
3*86d7f5d3SJohn Marino  * All rights reserved.
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
6*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
7*86d7f5d3SJohn Marino  * are met:
8*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
9*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
10*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
11*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
12*86d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
13*86d7f5d3SJohn Marino  *
14*86d7f5d3SJohn Marino  * This software is provided by the author ``as is'' and any express
15*86d7f5d3SJohn Marino  * or implied warranties, including, but not limited to, the implied
16*86d7f5d3SJohn Marino  * warranties of merchantability and fitness for a particular purpose
17*86d7f5d3SJohn Marino  * are disclaimed.  In no event shall the author be liable for any
18*86d7f5d3SJohn Marino  * direct, indirect, incidental, special, exemplary, or consequential
19*86d7f5d3SJohn Marino  * damages (including, but not limited to, procurement of substitute
20*86d7f5d3SJohn Marino  * goods or services; loss of use, data, or profits; or business
21*86d7f5d3SJohn Marino  * interruption) however caused and on any theory of liability,
22*86d7f5d3SJohn Marino  * whether in contract, strict liability, or tort (including
23*86d7f5d3SJohn Marino  * negligence or otherwise) arising in any way out of the use of this
24*86d7f5d3SJohn Marino  * software, even if advised of the possibility of such damage.
25*86d7f5d3SJohn Marino  */
26*86d7f5d3SJohn Marino /* $Id: asf.c,v 1.6 2003/11/04 06:38:37 green Exp $ */
27*86d7f5d3SJohn Marino /* $FreeBSD: src/usr.sbin/asf/asf.c,v 1.6 2003/11/04 06:38:37 green Exp $ */
28*86d7f5d3SJohn Marino 
29*86d7f5d3SJohn Marino #define MAXLINE 1024
30*86d7f5d3SJohn Marino #include <ctype.h>
31*86d7f5d3SJohn Marino #include <errno.h>
32*86d7f5d3SJohn Marino #include <stdio.h>
33*86d7f5d3SJohn Marino #include <stdlib.h>
34*86d7f5d3SJohn Marino #include <string.h>
35*86d7f5d3SJohn Marino #include <sys/file.h>
36*86d7f5d3SJohn Marino #include <sys/param.h>
37*86d7f5d3SJohn Marino #include <sys/stat.h>
38*86d7f5d3SJohn Marino #include <sys/wait.h>
39*86d7f5d3SJohn Marino #include <sys/types.h>
40*86d7f5d3SJohn Marino #include <fts.h>
41*86d7f5d3SJohn Marino #include <unistd.h>
42*86d7f5d3SJohn Marino 
43*86d7f5d3SJohn Marino #define MAXTOKEN 10
44*86d7f5d3SJohn Marino const char *modules_path;		/* path relative to kernel
45*86d7f5d3SJohn Marino 					 * build directory */
46*86d7f5d3SJohn Marino const char *outfile;			/* and where to write the output */
47*86d7f5d3SJohn Marino 
48*86d7f5d3SJohn Marino /*
49*86d7f5d3SJohn Marino  * Take a blank separated list of tokens and turn it into a list of
50*86d7f5d3SJohn Marino  * individual nul-delimited strings.  Build a list of pointers at
51*86d7f5d3SJohn Marino  * token, which must have enough space for the tokens.  Return the
52*86d7f5d3SJohn Marino  * number of tokens, or -1 on error (typically a missing string
53*86d7f5d3SJohn Marino  * delimiter).
54*86d7f5d3SJohn Marino  */
55*86d7f5d3SJohn Marino static int
tokenize(char * cptr,char * token[],int maxtoken)56*86d7f5d3SJohn Marino tokenize(char *cptr, char *token[], int maxtoken)
57*86d7f5d3SJohn Marino {
58*86d7f5d3SJohn Marino     char delim;				/* delimiter to search for */
59*86d7f5d3SJohn Marino     int tokennr;			/* index of this token */
60*86d7f5d3SJohn Marino 
61*86d7f5d3SJohn Marino     for (tokennr = 0; tokennr < maxtoken;) {
62*86d7f5d3SJohn Marino 	while (isspace(*cptr))
63*86d7f5d3SJohn Marino 	    cptr++;			/* skip initial white space */
64*86d7f5d3SJohn Marino 	if ((*cptr == '\0') || (*cptr == '\n')
65*86d7f5d3SJohn Marino 	    || (*cptr == '#'))		/* end of line */
66*86d7f5d3SJohn Marino 	    return tokennr;		/* return number of tokens found */
67*86d7f5d3SJohn Marino 	delim = *cptr;
68*86d7f5d3SJohn Marino 	token[tokennr] = cptr;		/* point to it */
69*86d7f5d3SJohn Marino 	tokennr++;			/* one more */
70*86d7f5d3SJohn Marino 	if (tokennr == maxtoken)	/* run off the end? */
71*86d7f5d3SJohn Marino 	    return tokennr;
72*86d7f5d3SJohn Marino 	if ((delim == '\'') || (delim == '"')) { /* delimitered */
73*86d7f5d3SJohn Marino 	    for (;;) {
74*86d7f5d3SJohn Marino 		cptr++;
75*86d7f5d3SJohn Marino 		if ((*cptr == delim)
76*86d7f5d3SJohn Marino 		    && (cptr[-1] != '\\')) { /* found the partner */
77*86d7f5d3SJohn Marino 		    cptr++;		/* move on past */
78*86d7f5d3SJohn Marino 		    if (!isspace(*cptr)) /* no space after closing quote */
79*86d7f5d3SJohn Marino 			return -1;
80*86d7f5d3SJohn Marino 		    *cptr++ = '\0';	/* delimit */
81*86d7f5d3SJohn Marino 		} else if ((*cptr == '\0')
82*86d7f5d3SJohn Marino 		    || (*cptr == '\n'))	/* end of line */
83*86d7f5d3SJohn Marino 		    return -1;
84*86d7f5d3SJohn Marino 	    }
85*86d7f5d3SJohn Marino 	} else {			/* not quoted */
86*86d7f5d3SJohn Marino 	    while ((*cptr != '\0') && (!isspace(*cptr)) && (*cptr != '\n'))
87*86d7f5d3SJohn Marino 		cptr++;
88*86d7f5d3SJohn Marino 	    if (*cptr != '\0')		/* not end of the line, */
89*86d7f5d3SJohn Marino 		*cptr++ = '\0';		/* delimit and move to the next */
90*86d7f5d3SJohn Marino 	}
91*86d7f5d3SJohn Marino     }
92*86d7f5d3SJohn Marino     return maxtoken;			/* can't get here */
93*86d7f5d3SJohn Marino }
94*86d7f5d3SJohn Marino 
95*86d7f5d3SJohn Marino static char *
findmodule(char * mod_path,const char * module_name)96*86d7f5d3SJohn Marino findmodule(char *mod_path, const char *module_name)
97*86d7f5d3SJohn Marino {
98*86d7f5d3SJohn Marino     char *const path_argv[2] = { mod_path, NULL };
99*86d7f5d3SJohn Marino     char *module_path = NULL;
100*86d7f5d3SJohn Marino     size_t module_name_len = strlen(module_name);
101*86d7f5d3SJohn Marino     FTS *fts;
102*86d7f5d3SJohn Marino     FTSENT *ftsent;
103*86d7f5d3SJohn Marino 
104*86d7f5d3SJohn Marino     if (mod_path == NULL) {
105*86d7f5d3SJohn Marino 	fprintf(stderr,
106*86d7f5d3SJohn Marino 	    "Can't allocate memory to traverse a path: %s (%d)\n",
107*86d7f5d3SJohn Marino 	    strerror(errno),
108*86d7f5d3SJohn Marino 	    errno);
109*86d7f5d3SJohn Marino 	exit(1);
110*86d7f5d3SJohn Marino     }
111*86d7f5d3SJohn Marino     fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
112*86d7f5d3SJohn Marino     if (fts == NULL) {
113*86d7f5d3SJohn Marino 	fprintf(stderr,
114*86d7f5d3SJohn Marino 	    "Can't begin traversing path %s: %s (%d)\n",
115*86d7f5d3SJohn Marino 	    mod_path,
116*86d7f5d3SJohn Marino 	    strerror(errno),
117*86d7f5d3SJohn Marino 	    errno);
118*86d7f5d3SJohn Marino 	exit(1);
119*86d7f5d3SJohn Marino     }
120*86d7f5d3SJohn Marino     while ((ftsent = fts_read(fts)) != NULL) {
121*86d7f5d3SJohn Marino 	if (ftsent->fts_info == FTS_DNR ||
122*86d7f5d3SJohn Marino 	    ftsent->fts_info == FTS_ERR ||
123*86d7f5d3SJohn Marino 	    ftsent->fts_info == FTS_NS) {
124*86d7f5d3SJohn Marino 	    fprintf(stderr,
125*86d7f5d3SJohn Marino 		"Error while traversing path %s: %s (%d)\n",
126*86d7f5d3SJohn Marino 		mod_path,
127*86d7f5d3SJohn Marino 		strerror(errno),
128*86d7f5d3SJohn Marino 		errno);
129*86d7f5d3SJohn Marino 	    exit(1);
130*86d7f5d3SJohn Marino 	}
131*86d7f5d3SJohn Marino 	if (ftsent->fts_info != FTS_F ||
132*86d7f5d3SJohn Marino 	    ftsent->fts_namelen != module_name_len ||
133*86d7f5d3SJohn Marino 	    memcmp(module_name, ftsent->fts_name, module_name_len) != 0)
134*86d7f5d3SJohn Marino 		continue;
135*86d7f5d3SJohn Marino 	if (asprintf(&module_path,
136*86d7f5d3SJohn Marino 	    "%.*s",
137*86d7f5d3SJohn Marino 	    (int)ftsent->fts_pathlen,
138*86d7f5d3SJohn Marino 	    ftsent->fts_path) == -1) {
139*86d7f5d3SJohn Marino 	    fprintf(stderr,
140*86d7f5d3SJohn Marino 		"Can't allocate memory traversing path %s: %s (%d)\n",
141*86d7f5d3SJohn Marino 		mod_path,
142*86d7f5d3SJohn Marino 		strerror(errno),
143*86d7f5d3SJohn Marino 		errno);
144*86d7f5d3SJohn Marino 	    exit(1);
145*86d7f5d3SJohn Marino 	}
146*86d7f5d3SJohn Marino 	break;
147*86d7f5d3SJohn Marino     }
148*86d7f5d3SJohn Marino     if (ftsent == NULL && errno != 0) {
149*86d7f5d3SJohn Marino 	fprintf(stderr,
150*86d7f5d3SJohn Marino 	    "Couldn't complete traversing path %s: %s (%d)\n",
151*86d7f5d3SJohn Marino 	    mod_path,
152*86d7f5d3SJohn Marino 	    strerror(errno),
153*86d7f5d3SJohn Marino 	    errno);
154*86d7f5d3SJohn Marino 	exit(1);
155*86d7f5d3SJohn Marino     }
156*86d7f5d3SJohn Marino     fts_close(fts);
157*86d7f5d3SJohn Marino     free(mod_path);
158*86d7f5d3SJohn Marino     return (module_path);
159*86d7f5d3SJohn Marino }
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino static void
usage(const char * myname)162*86d7f5d3SJohn Marino usage(const char *myname)
163*86d7f5d3SJohn Marino {
164*86d7f5d3SJohn Marino     fprintf(stderr,
165*86d7f5d3SJohn Marino 	"Usage:\n"
166*86d7f5d3SJohn Marino 	"%s [-a] [-f] [-k] [modules-path [outfile]]\n\n"
167*86d7f5d3SJohn Marino 	"\t-a\tappend to outfile)\n"
168*86d7f5d3SJohn Marino 	"\t-f\tfind the module in any subdirectory of module-path\n"
169*86d7f5d3SJohn Marino 	"\t-k\ttake input from kldstat(8)\n",
170*86d7f5d3SJohn Marino 	myname);
171*86d7f5d3SJohn Marino }
172*86d7f5d3SJohn Marino 
173*86d7f5d3SJohn Marino int
main(int argc,char * argv[])174*86d7f5d3SJohn Marino main(int argc, char *argv[])
175*86d7f5d3SJohn Marino {
176*86d7f5d3SJohn Marino     char buf[MAXLINE];
177*86d7f5d3SJohn Marino     FILE *kldstat;
178*86d7f5d3SJohn Marino     FILE *objcopy;
179*86d7f5d3SJohn Marino     FILE *out;				/* output file */
180*86d7f5d3SJohn Marino     char ocbuf[MAXLINE];
181*86d7f5d3SJohn Marino     int tokens;				/* number of tokens on line */
182*86d7f5d3SJohn Marino     int ch;
183*86d7f5d3SJohn Marino     const char *filemode = "w";		/* mode for outfile */
184*86d7f5d3SJohn Marino     char cwd[MAXPATHLEN];		/* current directory */
185*86d7f5d3SJohn Marino     char *token[MAXTOKEN];
186*86d7f5d3SJohn Marino     int dofind = 0;
187*86d7f5d3SJohn Marino 
188*86d7f5d3SJohn Marino     getcwd(cwd, MAXPATHLEN);		/* find where we are */
189*86d7f5d3SJohn Marino     kldstat = stdin;
190*86d7f5d3SJohn Marino     while ((ch = getopt(argc, argv, "afk")) != -1) {
191*86d7f5d3SJohn Marino 	switch (ch) {
192*86d7f5d3SJohn Marino 	case 'k': /* get input from kldstat(8) */
193*86d7f5d3SJohn Marino 	    if (!(kldstat = popen("kldstat", "r"))) {
194*86d7f5d3SJohn Marino 		perror("Can't start kldstat");
195*86d7f5d3SJohn Marino 		return 1;
196*86d7f5d3SJohn Marino 	    }
197*86d7f5d3SJohn Marino 	    break;
198*86d7f5d3SJohn Marino 	case 'a': /* append to outfile */
199*86d7f5d3SJohn Marino 	    filemode = "a";
200*86d7f5d3SJohn Marino 	    break;
201*86d7f5d3SJohn Marino 	case 'f': /* find .ko (recursively) */
202*86d7f5d3SJohn Marino 	    dofind = 1;
203*86d7f5d3SJohn Marino 	    break;
204*86d7f5d3SJohn Marino 	default:
205*86d7f5d3SJohn Marino 	    usage(argv[0]);
206*86d7f5d3SJohn Marino 	    return 1;
207*86d7f5d3SJohn Marino 	}
208*86d7f5d3SJohn Marino     }
209*86d7f5d3SJohn Marino 
210*86d7f5d3SJohn Marino     argv += optind;
211*86d7f5d3SJohn Marino     argc -= optind;
212*86d7f5d3SJohn Marino 
213*86d7f5d3SJohn Marino     if (argc >= 1) {
214*86d7f5d3SJohn Marino 	modules_path = argv[0];
215*86d7f5d3SJohn Marino 	argc--;
216*86d7f5d3SJohn Marino 	argv++;
217*86d7f5d3SJohn Marino     }
218*86d7f5d3SJohn Marino 
219*86d7f5d3SJohn Marino     if (argc >= 1) {
220*86d7f5d3SJohn Marino 	outfile = argv[0];
221*86d7f5d3SJohn Marino 	argc--;
222*86d7f5d3SJohn Marino 	argv++;
223*86d7f5d3SJohn Marino     }
224*86d7f5d3SJohn Marino 
225*86d7f5d3SJohn Marino     if (argc > 0) {
226*86d7f5d3SJohn Marino 	fprintf(stderr,
227*86d7f5d3SJohn Marino 	    "Extraneous startup information: \"%s\", aborting\n",
228*86d7f5d3SJohn Marino 	    argv[0]);
229*86d7f5d3SJohn Marino 	usage(getprogname());
230*86d7f5d3SJohn Marino 	return 1;
231*86d7f5d3SJohn Marino     }
232*86d7f5d3SJohn Marino     if (modules_path == NULL)
233*86d7f5d3SJohn Marino 	modules_path = "/boot/kernel";
234*86d7f5d3SJohn Marino     if (outfile == NULL)
235*86d7f5d3SJohn Marino 	outfile = ".asf";
236*86d7f5d3SJohn Marino     if ((out = fopen(outfile, filemode)) == NULL) {
237*86d7f5d3SJohn Marino 	fprintf(stderr,
238*86d7f5d3SJohn Marino 	    "Can't open output file %s: %s (%d)\n",
239*86d7f5d3SJohn Marino 	    outfile,
240*86d7f5d3SJohn Marino 	    strerror(errno),
241*86d7f5d3SJohn Marino 	    errno);
242*86d7f5d3SJohn Marino 	return 1;
243*86d7f5d3SJohn Marino     }
244*86d7f5d3SJohn Marino     while (fgets(buf, MAXLINE, kldstat)) {
245*86d7f5d3SJohn Marino 	if ((!(strstr(buf, "kernel")))
246*86d7f5d3SJohn Marino 	    && buf[0] != 'I') {
247*86d7f5d3SJohn Marino 	    long long base;
248*86d7f5d3SJohn Marino 	    long long textaddr = 0;
249*86d7f5d3SJohn Marino 	    long long dataaddr = 0;
250*86d7f5d3SJohn Marino 	    long long bssaddr = 0;
251*86d7f5d3SJohn Marino 
252*86d7f5d3SJohn Marino 	    tokens = tokenize(buf, token, MAXTOKEN);
253*86d7f5d3SJohn Marino 	    if (tokens <= 1)
254*86d7f5d3SJohn Marino 		continue;
255*86d7f5d3SJohn Marino 	    base = strtoll(token[2], NULL, 16);
256*86d7f5d3SJohn Marino 	    if (!dofind) {
257*86d7f5d3SJohn Marino 		snprintf(ocbuf,
258*86d7f5d3SJohn Marino 		    MAXLINE,
259*86d7f5d3SJohn Marino 		    "/usr/bin/objdump --section-headers %s/%s",
260*86d7f5d3SJohn Marino 		    modules_path,
261*86d7f5d3SJohn Marino 		    token[4]);
262*86d7f5d3SJohn Marino 	    } else {
263*86d7f5d3SJohn Marino 		char *modpath;
264*86d7f5d3SJohn Marino 
265*86d7f5d3SJohn Marino 		modpath = findmodule(strdup(modules_path), token[4]);
266*86d7f5d3SJohn Marino 		if (modpath == NULL)
267*86d7f5d3SJohn Marino 		    continue;
268*86d7f5d3SJohn Marino 		snprintf(ocbuf,
269*86d7f5d3SJohn Marino 		    MAXLINE,
270*86d7f5d3SJohn Marino 		    "/usr/bin/objdump --section-headers %s",
271*86d7f5d3SJohn Marino 		    modpath);
272*86d7f5d3SJohn Marino 		free(modpath);
273*86d7f5d3SJohn Marino 	    }
274*86d7f5d3SJohn Marino 	    if (!(objcopy = popen(ocbuf, "r"))) {
275*86d7f5d3SJohn Marino 		fprintf(stderr,
276*86d7f5d3SJohn Marino 		    "Can't start %s: %s (%d)\n",
277*86d7f5d3SJohn Marino 		    ocbuf,
278*86d7f5d3SJohn Marino 		    strerror(errno),
279*86d7f5d3SJohn Marino 		    errno);
280*86d7f5d3SJohn Marino 		return 1;
281*86d7f5d3SJohn Marino 	    }
282*86d7f5d3SJohn Marino 	    while (fgets(ocbuf, MAXLINE, objcopy)) {
283*86d7f5d3SJohn Marino 		int octokens;
284*86d7f5d3SJohn Marino 		char *octoken[MAXTOKEN];
285*86d7f5d3SJohn Marino 
286*86d7f5d3SJohn Marino 		octokens = tokenize(ocbuf, octoken, MAXTOKEN);
287*86d7f5d3SJohn Marino 		if (octokens > 1) {
288*86d7f5d3SJohn Marino 		    if (!strcmp(octoken[1], ".text"))
289*86d7f5d3SJohn Marino 			textaddr = strtoll(octoken[3], NULL, 16) + base;
290*86d7f5d3SJohn Marino 		    else if (!strcmp(octoken[1], ".data"))
291*86d7f5d3SJohn Marino 			dataaddr = strtoll(octoken[3], NULL, 16) + base;
292*86d7f5d3SJohn Marino 		    else if (!strcmp(octoken[1], ".bss"))
293*86d7f5d3SJohn Marino 			bssaddr = strtoll(octoken[3], NULL, 16) + base;
294*86d7f5d3SJohn Marino 		}
295*86d7f5d3SJohn Marino 	    }
296*86d7f5d3SJohn Marino 	    if (textaddr) {		/* we must have a text address */
297*86d7f5d3SJohn Marino 		if (!dofind) {
298*86d7f5d3SJohn Marino 		    fprintf(out,
299*86d7f5d3SJohn Marino 			"add-symbol-file %s%s%s/%s 0x%llx",
300*86d7f5d3SJohn Marino 			modules_path[0] != '/' ? cwd : "",
301*86d7f5d3SJohn Marino 			modules_path[0] != '/' ? "/" : "",
302*86d7f5d3SJohn Marino 			modules_path,
303*86d7f5d3SJohn Marino 			token[4],
304*86d7f5d3SJohn Marino 			textaddr);
305*86d7f5d3SJohn Marino 		} else {
306*86d7f5d3SJohn Marino 		    char *modpath;
307*86d7f5d3SJohn Marino 
308*86d7f5d3SJohn Marino 		    modpath = findmodule(strdup(modules_path), token[4]);
309*86d7f5d3SJohn Marino 		    if (modpath == NULL)
310*86d7f5d3SJohn Marino 			continue;
311*86d7f5d3SJohn Marino 		    fprintf(out,
312*86d7f5d3SJohn Marino 			"add-symbol-file %s 0x%llx",
313*86d7f5d3SJohn Marino 			modpath,
314*86d7f5d3SJohn Marino 			textaddr);
315*86d7f5d3SJohn Marino 		    free(modpath);
316*86d7f5d3SJohn Marino 		}
317*86d7f5d3SJohn Marino 		if (dataaddr)
318*86d7f5d3SJohn Marino 		    fprintf(out, " -s .data 0x%llx", dataaddr);
319*86d7f5d3SJohn Marino 		if (bssaddr)
320*86d7f5d3SJohn Marino 		    fprintf(out, " -s .bss 0x%llx", bssaddr);
321*86d7f5d3SJohn Marino 		fprintf(out, "\n");
322*86d7f5d3SJohn Marino 	    }
323*86d7f5d3SJohn Marino 	}
324*86d7f5d3SJohn Marino     }
325*86d7f5d3SJohn Marino     return 0;
326*86d7f5d3SJohn Marino }
327