asf.c revision 116009
1116009Sgrog/* $Id: asf.c,v 1.4 2003/05/04 02:55:20 grog Exp grog $ */
2116009Sgrog/* $FreeBSD: head/usr.sbin/asf/asf.c 116009 2003-06-08 06:18:13Z grog $ */
3116009Sgrog
4116009Sgrog#define MAXLINE 1024
5116009Sgrog#include <ctype.h>
6116009Sgrog#include <errno.h>
7116009Sgrog#include <stdio.h>
8116009Sgrog#include <stdlib.h>
9116009Sgrog#include <string.h>
10116009Sgrog#include <sys/file.h>
11116009Sgrog#include <sys/param.h>
12116009Sgrog#include <sys/stat.h>
13116009Sgrog#include <sys/wait.h>
14116009Sgrog#include <sys/types.h>
15116009Sgrog#include <unistd.h>
16116009Sgrog
17116009Sgrog#define MAXTOKEN 10
18116009Sgrogchar *token[MAXTOKEN];
19116009Sgrogchar *modules_path;			/* path relative to kernel
20116009Sgrog					 * build directory */
21116009Sgrogchar *outfile;				/* and where to write the output */
22116009Sgrog
23116009Sgrog/*
24116009Sgrog * Take a blank separated list of tokens and turn it into a list of
25116009Sgrog * individual nul-delimited strings.  Build a list of pointers at
26116009Sgrog * token, which must have enough space for the tokens.  Return the
27116009Sgrog * number of tokens, or -1 on error (typically a missing string
28116009Sgrog * delimiter).
29116009Sgrog */
30116009Sgrogint
31116009Sgrogtokenize(char *cptr, char *token[], int maxtoken)
32116009Sgrog{
33116009Sgrog    char delim;				/* delimiter to search for */
34116009Sgrog    int tokennr;			/* index of this token */
35116009Sgrog
36116009Sgrog    for (tokennr = 0; tokennr < maxtoken;) {
37116009Sgrog	while (isspace(*cptr))
38116009Sgrog	    cptr++;			/* skip initial white space */
39116009Sgrog	if ((*cptr == '\0') || (*cptr == '\n')
40116009Sgrog	    || (*cptr == '#'))		/* end of line */
41116009Sgrog	    return tokennr;		/* return number of tokens found */
42116009Sgrog	delim = *cptr;
43116009Sgrog	token[tokennr] = cptr;		/* point to it */
44116009Sgrog	tokennr++;			/* one more */
45116009Sgrog	if (tokennr == maxtoken)	/* run off the end? */
46116009Sgrog	    return tokennr;
47116009Sgrog	if ((delim == '\'') || (delim == '"')) { /* delimitered */
48116009Sgrog	    for (;;) {
49116009Sgrog		cptr++;
50116009Sgrog		if ((*cptr == delim)
51116009Sgrog		    && (cptr[-1] != '\\')) { /* found the partner */
52116009Sgrog		    cptr++;		/* move on past */
53116009Sgrog		    if (!isspace(*cptr)) /* no space after closing quote */
54116009Sgrog			return -1;
55116009Sgrog		    *cptr++ = '\0';	/* delimit */
56116009Sgrog		} else if ((*cptr == '\0')
57116009Sgrog		    || (*cptr == '\n'))	/* end of line */
58116009Sgrog		    return -1;
59116009Sgrog	    }
60116009Sgrog	} else {			/* not quoted */
61116009Sgrog	    while ((*cptr != '\0') && (!isspace(*cptr)) && (*cptr != '\n'))
62116009Sgrog		cptr++;
63116009Sgrog	    if (*cptr != '\0')		/* not end of the line, */
64116009Sgrog		*cptr++ = '\0';		/* delimit and move to the next */
65116009Sgrog	}
66116009Sgrog    }
67116009Sgrog    return maxtoken;			/* can't get here */
68116009Sgrog}
69116009Sgrog
70116009Sgrogvoid
71116009Sgrogusage(char *myname)
72116009Sgrog{
73116009Sgrog    fprintf(stderr,
74116009Sgrog	"Usage:\n"
75116009Sgrog	"%s [-a] [-k] [modules-path [outfile]]\n\n"
76116009Sgrog	"\t-a\tappend to outfile)\n"
77116009Sgrog	"\t-k\ttake input from kldstat(8)\n",
78116009Sgrog	"\t-x\tdon't append \".debug\" to module name\n",
79116009Sgrog	myname);
80116009Sgrog}
81116009Sgrog
82116009Sgrogint
83116009Sgrogmain(int argc, char *argv[])
84116009Sgrog{
85116009Sgrog    char buf[MAXLINE];
86116009Sgrog    FILE *kldstat;
87116009Sgrog    FILE *objcopy;
88116009Sgrog    FILE *out;				/* output file */
89116009Sgrog    char ocbuf[MAXLINE];
90116009Sgrog    int tokens;				/* number of tokens on line */
91116009Sgrog    char basetoken[MAXLINE];
92116009Sgrog    int i;
93116009Sgrog    char *filemode = "w";		/* mode for outfile */
94116009Sgrog    char cwd[MAXPATHLEN];		/* current directory */
95116009Sgrog    char *debugname = ".debug";		/* some file names end in this */
96116009Sgrog
97116009Sgrog    getcwd(cwd, MAXPATHLEN);		/* find where we are */
98116009Sgrog    kldstat = stdin;
99116009Sgrog    for (i = 1; i < argc; i++) {
100116009Sgrog	if (argv[i][0] == '-') {
101116009Sgrog	    if (strcmp(argv[i], "-k") == 0) { /* get input from kldstat(8) */
102116009Sgrog		if (!(kldstat = popen("kldstat", "r"))) {
103116009Sgrog		    perror("Can't start kldstat");
104116009Sgrog		    return 1;
105116009Sgrog		}
106116009Sgrog	    } else if (strcmp(argv[i], "-a") == 0) /* append to outfile */
107116009Sgrog		filemode = "a";
108116009Sgrog	    else if (strcmp(argv[i], "-x") == 0) /* no .debug extension */
109116009Sgrog		debugname = "";		/* nothing */
110116009Sgrog	    else {
111116009Sgrog		fprintf(stderr,
112116009Sgrog		    "Invalid option: %s, aborting\n",
113116009Sgrog		    argv[i]);
114116009Sgrog		usage(argv[0]);
115116009Sgrog		return 1;
116116009Sgrog	    }
117116009Sgrog	} else if (modules_path == NULL)
118116009Sgrog	    modules_path = argv[i];
119116009Sgrog	else if (outfile == NULL)
120116009Sgrog	    outfile = argv[i];
121116009Sgrog	else {
122116009Sgrog	    fprintf(stderr,
123116009Sgrog		"Extraneous startup information: \"%s\", aborting\n",
124116009Sgrog		argv[i]);
125116009Sgrog	    usage(argv[0]);
126116009Sgrog	    return 1;
127116009Sgrog	}
128116009Sgrog    }
129116009Sgrog    if (modules_path == NULL)
130116009Sgrog	modules_path = "modules";
131116009Sgrog    if (outfile == NULL)
132116009Sgrog	outfile = ".asf";
133116009Sgrog    if ((out = fopen(outfile, filemode)) == NULL) {
134116009Sgrog	fprintf(stderr,
135116009Sgrog	    "Can't open output file %s: %s (%d)\n",
136116009Sgrog	    outfile,
137116009Sgrog	    strerror(errno),
138116009Sgrog	    errno);
139116009Sgrog	return 1;
140116009Sgrog    }
141116009Sgrog    while (fgets(buf, MAXLINE, kldstat)) {
142116009Sgrog	if ((!(strstr(buf, "kernel")))
143116009Sgrog	    && buf[0] != 'I') {
144116009Sgrog	    quad_t base;
145116009Sgrog	    quad_t textaddr;
146116009Sgrog	    quad_t dataaddr;
147116009Sgrog	    quad_t bssaddr;
148116009Sgrog
149116009Sgrog	    tokens = tokenize(buf, token, MAXTOKEN);
150116009Sgrog	    base = strtoll(token[2], NULL, 16);
151116009Sgrog	    strcpy(basetoken, token[4]);
152116009Sgrog	    basetoken[strlen(basetoken) - 3] = '\0'; /* cut off the .ko */
153116009Sgrog	    snprintf(ocbuf,
154116009Sgrog		MAXLINE,
155116009Sgrog		"/usr/bin/objdump --section-headers %s/%s/%s%s",
156116009Sgrog		modules_path,
157116009Sgrog		basetoken,
158116009Sgrog		token[4],
159116009Sgrog		debugname);
160116009Sgrog	    if (!(objcopy = popen(ocbuf, "r"))) {
161116009Sgrog		fprintf(stderr,
162116009Sgrog		    "Can't start %s: %s (%d)\n",
163116009Sgrog		    ocbuf,
164116009Sgrog		    strerror(errno),
165116009Sgrog		    errno);
166116009Sgrog		return 1;
167116009Sgrog	    }
168116009Sgrog	    while (fgets(ocbuf, MAXLINE, objcopy)) {
169116009Sgrog		int octokens;
170116009Sgrog		char *octoken[MAXTOKEN];
171116009Sgrog
172116009Sgrog		octokens = tokenize(ocbuf, octoken, MAXTOKEN);
173116009Sgrog		if (octokens > 1) {
174116009Sgrog		    if (!strcmp(octoken[1], ".text"))
175116009Sgrog			textaddr = strtoll(octoken[3], NULL, 16) + base;
176116009Sgrog		    else if (!strcmp(octoken[1], ".data"))
177116009Sgrog			dataaddr = strtoll(octoken[3], NULL, 16) + base;
178116009Sgrog		    else if (!strcmp(octoken[1], ".bss"))
179116009Sgrog			bssaddr = strtoll(octoken[3], NULL, 16) + base;
180116009Sgrog		}
181116009Sgrog	    }
182116009Sgrog	    if (textaddr) {		/* we must have a text address */
183116009Sgrog		fprintf(out,
184116009Sgrog		    "add-symbol-file %s/%s/%s/%s%s 0x%llx",
185116009Sgrog		    cwd,
186116009Sgrog		    modules_path,
187116009Sgrog		    basetoken,
188116009Sgrog		    token[4],
189116009Sgrog		    debugname,
190116009Sgrog		    textaddr);
191116009Sgrog		if (dataaddr)
192116009Sgrog		    fprintf(out, " -s .data 0x%llx", dataaddr);
193116009Sgrog		if (bssaddr)
194116009Sgrog		    fprintf(out, " -s .bss 0x%llx", bssaddr);
195116009Sgrog		fprintf(out, "\n");
196116009Sgrog	    }
197116009Sgrog	}
198116009Sgrog    }
199116009Sgrog    return 0;
200116009Sgrog}
201