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 /* $DragonFly: src/usr.sbin/asf/asf.c,v 1.2 2006/01/11 02:00:13 corecode Exp $ */ 29 30 #define MAXLINE 1024 31 #include <ctype.h> 32 #include <errno.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/file.h> 37 #include <sys/param.h> 38 #include <sys/stat.h> 39 #include <sys/wait.h> 40 #include <sys/types.h> 41 #include <fts.h> 42 #include <unistd.h> 43 44 #define MAXTOKEN 10 45 const char *modules_path; /* path relative to kernel 46 * build directory */ 47 const char *outfile; /* and where to write the output */ 48 49 /* 50 * Take a blank separated list of tokens and turn it into a list of 51 * individual nul-delimited strings. Build a list of pointers at 52 * token, which must have enough space for the tokens. Return the 53 * number of tokens, or -1 on error (typically a missing string 54 * delimiter). 55 */ 56 static int 57 tokenize(char *cptr, char *token[], int maxtoken) 58 { 59 char delim; /* delimiter to search for */ 60 int tokennr; /* index of this token */ 61 62 for (tokennr = 0; tokennr < maxtoken;) { 63 while (isspace(*cptr)) 64 cptr++; /* skip initial white space */ 65 if ((*cptr == '\0') || (*cptr == '\n') 66 || (*cptr == '#')) /* end of line */ 67 return tokennr; /* return number of tokens found */ 68 delim = *cptr; 69 token[tokennr] = cptr; /* point to it */ 70 tokennr++; /* one more */ 71 if (tokennr == maxtoken) /* run off the end? */ 72 return tokennr; 73 if ((delim == '\'') || (delim == '"')) { /* delimitered */ 74 for (;;) { 75 cptr++; 76 if ((*cptr == delim) 77 && (cptr[-1] != '\\')) { /* found the partner */ 78 cptr++; /* move on past */ 79 if (!isspace(*cptr)) /* no space after closing quote */ 80 return -1; 81 *cptr++ = '\0'; /* delimit */ 82 } else if ((*cptr == '\0') 83 || (*cptr == '\n')) /* end of line */ 84 return -1; 85 } 86 } else { /* not quoted */ 87 while ((*cptr != '\0') && (!isspace(*cptr)) && (*cptr != '\n')) 88 cptr++; 89 if (*cptr != '\0') /* not end of the line, */ 90 *cptr++ = '\0'; /* delimit and move to the next */ 91 } 92 } 93 return maxtoken; /* can't get here */ 94 } 95 96 static char * 97 findmodule(char *modules_path, const char *module_name) 98 { 99 char *const path_argv[2] = { modules_path, NULL }; 100 char *module_path = NULL; 101 int module_name_len = strlen(module_name); 102 FTS *fts; 103 FTSENT *ftsent; 104 105 if (modules_path == NULL) { 106 fprintf(stderr, 107 "Can't allocate memory to traverse a path: %s (%d)\n", 108 strerror(errno), 109 errno); 110 exit(1); 111 } 112 fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); 113 if (fts == NULL) { 114 fprintf(stderr, 115 "Can't begin traversing path %s: %s (%d)\n", 116 modules_path, 117 strerror(errno), 118 errno); 119 exit(1); 120 } 121 while ((ftsent = fts_read(fts)) != NULL) { 122 if (ftsent->fts_info == FTS_DNR || 123 ftsent->fts_info == FTS_ERR || 124 ftsent->fts_info == FTS_NS) { 125 fprintf(stderr, 126 "Error while traversing path %s: %s (%d)\n", 127 modules_path, 128 strerror(errno), 129 errno); 130 exit(1); 131 } 132 if (ftsent->fts_info != FTS_F || 133 ftsent->fts_namelen != module_name_len || 134 memcmp(module_name, ftsent->fts_name, module_name_len) != 0) 135 continue; 136 if (asprintf(&module_path, 137 "%.*s", 138 ftsent->fts_pathlen, 139 ftsent->fts_path) == -1) { 140 fprintf(stderr, 141 "Can't allocate memory traversing path %s: %s (%d)\n", 142 modules_path, 143 strerror(errno), 144 errno); 145 exit(1); 146 } 147 break; 148 } 149 if (ftsent == NULL && errno != 0) { 150 fprintf(stderr, 151 "Couldn't complete traversing path %s: %s (%d)\n", 152 modules_path, 153 strerror(errno), 154 errno); 155 exit(1); 156 } 157 fts_close(fts); 158 free(modules_path); 159 return (module_path); 160 } 161 162 static void 163 usage(const char *myname) 164 { 165 fprintf(stderr, 166 "Usage:\n" 167 "%s [-a] [-f] [-k] [-s] [-x] [modules-path [outfile]]\n\n" 168 "\t-a\tappend to outfile)\n" 169 "\t-f\tfind the module in any subdirectory of module-path\n" 170 "\t-k\ttake input from kldstat(8)\n" 171 "\t-s\tdon't prepend subdir for module path\n" 172 "\t-x\tdon't append \".debug\" to module name\n", 173 myname); 174 } 175 176 int 177 main(int argc, char *argv[]) 178 { 179 char buf[MAXLINE]; 180 FILE *kldstat; 181 FILE *objcopy; 182 FILE *out; /* output file */ 183 char ocbuf[MAXLINE]; 184 int tokens; /* number of tokens on line */ 185 char basetoken[MAXLINE]; 186 int i, ch; 187 const char *filemode = "w"; /* mode for outfile */ 188 char cwd[MAXPATHLEN]; /* current directory */ 189 char *token[MAXTOKEN]; 190 int nosubdir = 0; 191 int dofind = 0; 192 193 getcwd(cwd, MAXPATHLEN); /* find where we are */ 194 kldstat = stdin; 195 while ((ch = getopt(argc, argv, "afks")) != -1) { 196 switch (ch) { 197 case 'k': /* get input from kldstat(8) */ 198 if (!(kldstat = popen("kldstat", "r"))) { 199 perror("Can't start kldstat"); 200 return 1; 201 } 202 break; 203 case 'a': /* append to outfile */ 204 filemode = "a"; 205 break; 206 case 's': /* no subdir */ 207 nosubdir = 1; /* nothing */ 208 break; 209 case 'f': /* find .ko (recursively) */ 210 dofind = 1; 211 break; 212 default: 213 fprintf(stderr, 214 "Invalid option: %s, aborting\n", 215 argv[i]); 216 usage(argv[0]); 217 return 1; 218 } 219 } 220 221 argv += optind; 222 argc -= optind; 223 224 if (argc >= 1) { 225 modules_path = argv[0]; 226 argc--; 227 argv++; 228 } 229 230 if (argc >= 1) { 231 outfile = argv[0]; 232 argc--; 233 argv++; 234 } 235 236 if (argc > 0) { 237 fprintf(stderr, 238 "Extraneous startup information: \"%s\", aborting\n", 239 argv[0]); 240 usage(getprogname()); 241 return 1; 242 } 243 if (modules_path == NULL) 244 modules_path = "modules"; 245 if (outfile == NULL) 246 outfile = ".asf"; 247 if ((out = fopen(outfile, filemode)) == NULL) { 248 fprintf(stderr, 249 "Can't open output file %s: %s (%d)\n", 250 outfile, 251 strerror(errno), 252 errno); 253 return 1; 254 } 255 while (fgets(buf, MAXLINE, kldstat)) { 256 if ((!(strstr(buf, "kernel"))) 257 && buf[0] != 'I') { 258 quad_t base; 259 quad_t textaddr; 260 quad_t dataaddr; 261 quad_t bssaddr; 262 263 tokens = tokenize(buf, token, MAXTOKEN); 264 base = strtoll(token[2], NULL, 16); 265 if (!dofind) { 266 strcpy(basetoken, token[4]); 267 basetoken[strlen(basetoken) - 3] = '/'; 268 basetoken[strlen(basetoken) - 2] = '\0'; /* cut off the .ko */ 269 snprintf(ocbuf, 270 MAXLINE, 271 "/usr/bin/objdump --section-headers %s/%s%s", 272 modules_path, 273 nosubdir ? "" : basetoken, 274 token[4]); 275 } else { 276 char *modpath; 277 278 modpath = findmodule(strdup(modules_path), token[4]); 279 if (modpath == NULL) 280 continue; 281 snprintf(ocbuf, 282 MAXLINE, 283 "/usr/bin/objdump --section-headers %s", 284 modpath); 285 free(modpath); 286 } 287 if (!(objcopy = popen(ocbuf, "r"))) { 288 fprintf(stderr, 289 "Can't start %s: %s (%d)\n", 290 ocbuf, 291 strerror(errno), 292 errno); 293 return 1; 294 } 295 while (fgets(ocbuf, MAXLINE, objcopy)) { 296 int octokens; 297 char *octoken[MAXTOKEN]; 298 299 octokens = tokenize(ocbuf, octoken, MAXTOKEN); 300 if (octokens > 1) { 301 if (!strcmp(octoken[1], ".text")) 302 textaddr = strtoll(octoken[3], NULL, 16) + base; 303 else if (!strcmp(octoken[1], ".data")) 304 dataaddr = strtoll(octoken[3], NULL, 16) + base; 305 else if (!strcmp(octoken[1], ".bss")) 306 bssaddr = strtoll(octoken[3], NULL, 16) + base; 307 } 308 } 309 if (textaddr) { /* we must have a text address */ 310 if (!dofind) { 311 fprintf(out, 312 "add-symbol-file %s%s%s/%s%s 0x%llx", 313 modules_path[0] != '/' ? cwd : "", 314 modules_path[0] != '/' ? "/" : "", 315 modules_path, 316 nosubdir ? "" : basetoken, 317 token[4], 318 textaddr); 319 } else { 320 char *modpath; 321 322 modpath = findmodule(strdup(modules_path), token[4]); 323 if (modpath == NULL) 324 continue; 325 fprintf(out, 326 "add-symbol-file %s 0x%llx", 327 modpath, 328 textaddr); 329 free(modpath); 330 } 331 if (dataaddr) 332 fprintf(out, " -s .data 0x%llx", dataaddr); 333 if (bssaddr) 334 fprintf(out, " -s .bss 0x%llx", bssaddr); 335 fprintf(out, "\n"); 336 } 337 } 338 } 339 return 0; 340 } 341