asf.c revision 116017
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.4 2003/05/04 02:55:20 grog Exp grog $ */ 27/* $FreeBSD: head/usr.sbin/asf/asf.c 116017 2003-06-08 08:37:11Z jmallett $ */ 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 <unistd.h> 41 42#define MAXTOKEN 10 43const char *modules_path; /* path relative to kernel 44 * build directory */ 45const char *outfile; /* and where to write the output */ 46 47/* 48 * Take a blank separated list of tokens and turn it into a list of 49 * individual nul-delimited strings. Build a list of pointers at 50 * token, which must have enough space for the tokens. Return the 51 * number of tokens, or -1 on error (typically a missing string 52 * delimiter). 53 */ 54static int 55tokenize(char *cptr, char *token[], int maxtoken) 56{ 57 char delim; /* delimiter to search for */ 58 int tokennr; /* index of this token */ 59 60 for (tokennr = 0; tokennr < maxtoken;) { 61 while (isspace(*cptr)) 62 cptr++; /* skip initial white space */ 63 if ((*cptr == '\0') || (*cptr == '\n') 64 || (*cptr == '#')) /* end of line */ 65 return tokennr; /* return number of tokens found */ 66 delim = *cptr; 67 token[tokennr] = cptr; /* point to it */ 68 tokennr++; /* one more */ 69 if (tokennr == maxtoken) /* run off the end? */ 70 return tokennr; 71 if ((delim == '\'') || (delim == '"')) { /* delimitered */ 72 for (;;) { 73 cptr++; 74 if ((*cptr == delim) 75 && (cptr[-1] != '\\')) { /* found the partner */ 76 cptr++; /* move on past */ 77 if (!isspace(*cptr)) /* no space after closing quote */ 78 return -1; 79 *cptr++ = '\0'; /* delimit */ 80 } else if ((*cptr == '\0') 81 || (*cptr == '\n')) /* end of line */ 82 return -1; 83 } 84 } else { /* not quoted */ 85 while ((*cptr != '\0') && (!isspace(*cptr)) && (*cptr != '\n')) 86 cptr++; 87 if (*cptr != '\0') /* not end of the line, */ 88 *cptr++ = '\0'; /* delimit and move to the next */ 89 } 90 } 91 return maxtoken; /* can't get here */ 92} 93 94static void 95usage(const char *myname) 96{ 97 fprintf(stderr, 98 "Usage:\n" 99 "%s [-a] [-k] [-t] [modules-path [outfile]]\n\n" 100 "\t-a\tappend to outfile)\n" 101 "\t-k\ttake input from kldstat(8)\n" 102 "\t-x\tdon't append \".debug\" to module name\n", 103 myname); 104} 105 106int 107main(int argc, char *argv[]) 108{ 109 char buf[MAXLINE]; 110 FILE *kldstat; 111 FILE *objcopy; 112 FILE *out; /* output file */ 113 char ocbuf[MAXLINE]; 114 int tokens; /* number of tokens on line */ 115 char basetoken[MAXLINE]; 116 int i; 117 const char *filemode = "w"; /* mode for outfile */ 118 char cwd[MAXPATHLEN]; /* current directory */ 119 const char *debugname = ".debug"; /* some file names end in this */ 120 char *token[MAXTOKEN]; 121 122 getcwd(cwd, MAXPATHLEN); /* find where we are */ 123 kldstat = stdin; 124 for (i = 1; i < argc; i++) { 125 if (argv[i][0] == '-') { 126 if (strcmp(argv[i], "-k") == 0) { /* get input from kldstat(8) */ 127 if (!(kldstat = popen("kldstat", "r"))) { 128 perror("Can't start kldstat"); 129 return 1; 130 } 131 } else if (strcmp(argv[i], "-a") == 0) /* append to outfile */ 132 filemode = "a"; 133 else if (strcmp(argv[i], "-x") == 0) /* no .debug extension */ 134 debugname = ""; /* nothing */ 135 else { 136 fprintf(stderr, 137 "Invalid option: %s, aborting\n", 138 argv[i]); 139 usage(argv[0]); 140 return 1; 141 } 142 } else if (modules_path == NULL) 143 modules_path = argv[i]; 144 else if (outfile == NULL) 145 outfile = argv[i]; 146 else { 147 fprintf(stderr, 148 "Extraneous startup information: \"%s\", aborting\n", 149 argv[i]); 150 usage(argv[0]); 151 return 1; 152 } 153 } 154 if (modules_path == NULL) 155 modules_path = "modules"; 156 if (outfile == NULL) 157 outfile = ".asf"; 158 if ((out = fopen(outfile, filemode)) == NULL) { 159 fprintf(stderr, 160 "Can't open output file %s: %s (%d)\n", 161 outfile, 162 strerror(errno), 163 errno); 164 return 1; 165 } 166 while (fgets(buf, MAXLINE, kldstat)) { 167 if ((!(strstr(buf, "kernel"))) 168 && buf[0] != 'I') { 169 quad_t base; 170 quad_t textaddr; 171 quad_t dataaddr; 172 quad_t bssaddr; 173 174 tokens = tokenize(buf, token, MAXTOKEN); 175 base = strtoll(token[2], NULL, 16); 176 strcpy(basetoken, token[4]); 177 basetoken[strlen(basetoken) - 3] = '\0'; /* cut off the .ko */ 178 snprintf(ocbuf, 179 MAXLINE, 180 "/usr/bin/objdump --section-headers %s/%s/%s%s", 181 modules_path, 182 basetoken, 183 token[4], 184 debugname); 185 if (!(objcopy = popen(ocbuf, "r"))) { 186 fprintf(stderr, 187 "Can't start %s: %s (%d)\n", 188 ocbuf, 189 strerror(errno), 190 errno); 191 return 1; 192 } 193 while (fgets(ocbuf, MAXLINE, objcopy)) { 194 int octokens; 195 char *octoken[MAXTOKEN]; 196 197 octokens = tokenize(ocbuf, octoken, MAXTOKEN); 198 if (octokens > 1) { 199 if (!strcmp(octoken[1], ".text")) 200 textaddr = strtoll(octoken[3], NULL, 16) + base; 201 else if (!strcmp(octoken[1], ".data")) 202 dataaddr = strtoll(octoken[3], NULL, 16) + base; 203 else if (!strcmp(octoken[1], ".bss")) 204 bssaddr = strtoll(octoken[3], NULL, 16) + base; 205 } 206 } 207 if (textaddr) { /* we must have a text address */ 208 fprintf(out, 209 "add-symbol-file %s/%s/%s/%s%s 0x%llx", 210 cwd, 211 modules_path, 212 basetoken, 213 token[4], 214 debugname, 215 textaddr); 216 if (dataaddr) 217 fprintf(out, " -s .data 0x%llx", dataaddr); 218 if (bssaddr) 219 fprintf(out, " -s .bss 0x%llx", bssaddr); 220 fprintf(out, "\n"); 221 } 222 } 223 } 224 return 0; 225} 226