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