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 } 327