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