asf.c revision 150410
1116014Sgrog/* 2116014Sgrog * Copyright (c) 2002, 2003 Greg Lehey 3116014Sgrog * All rights reserved. 4116014Sgrog * 5116014Sgrog * Redistribution and use in source and binary forms, with or without 6116014Sgrog * modification, are permitted provided that the following conditions 7116014Sgrog * are met: 8116014Sgrog * 1. Redistributions of source code must retain the above copyright 9116014Sgrog * notice, this list of conditions and the following disclaimer. 10116014Sgrog * 2. Redistributions in binary form must reproduce the above copyright 11116014Sgrog * notice, this list of conditions and the following disclaimer in the 12116014Sgrog * documentation and/or other materials provided with the distribution. 13116014Sgrog * 14116014Sgrog * This software is provided by the author ``as is'' and any express 15116014Sgrog * or implied warranties, including, but not limited to, the implied 16116014Sgrog * warranties of merchantability and fitness for a particular purpose 17116014Sgrog * are disclaimed. In no event shall the author be liable for any 18116014Sgrog * direct, indirect, incidental, special, exemplary, or consequential 19116014Sgrog * damages (including, but not limited to, procurement of substitute 20116014Sgrog * goods or services; loss of use, data, or profits; or business 21116014Sgrog * interruption) however caused and on any theory of liability, 22116014Sgrog * whether in contract, strict liability, or tort (including 23116014Sgrog * negligence or otherwise) arising in any way out of the use of this 24116014Sgrog * software, even if advised of the possibility of such damage. 25116014Sgrog */ 26116009Sgrog/* $Id: asf.c,v 1.4 2003/05/04 02:55:20 grog Exp grog $ */ 27116009Sgrog/* $FreeBSD: head/usr.sbin/asf/asf.c 150410 2005-09-21 05:20:03Z grog $ */ 28116009Sgrog 29116009Sgrog#define MAXLINE 1024 30116009Sgrog#include <ctype.h> 31116009Sgrog#include <errno.h> 32116009Sgrog#include <stdio.h> 33116009Sgrog#include <stdlib.h> 34116009Sgrog#include <string.h> 35116009Sgrog#include <sys/file.h> 36116009Sgrog#include <sys/param.h> 37116009Sgrog#include <sys/stat.h> 38116009Sgrog#include <sys/wait.h> 39116009Sgrog#include <sys/types.h> 40122033Sgreen#include <fts.h> 41116009Sgrog#include <unistd.h> 42116009Sgrog 43116009Sgrog#define MAXTOKEN 10 44116017Sjmallettconst char *modules_path; /* path relative to kernel 45116009Sgrog * build directory */ 46116017Sjmallettconst char *outfile; /* and where to write the output */ 47116009Sgrog 48116009Sgrog/* 49116009Sgrog * Take a blank separated list of tokens and turn it into a list of 50116009Sgrog * individual nul-delimited strings. Build a list of pointers at 51116009Sgrog * token, which must have enough space for the tokens. Return the 52116009Sgrog * number of tokens, or -1 on error (typically a missing string 53116009Sgrog * delimiter). 54116009Sgrog */ 55116017Sjmallettstatic int 56116009Sgrogtokenize(char *cptr, char *token[], int maxtoken) 57116009Sgrog{ 58116009Sgrog char delim; /* delimiter to search for */ 59116009Sgrog int tokennr; /* index of this token */ 60116009Sgrog 61116009Sgrog for (tokennr = 0; tokennr < maxtoken;) { 62116009Sgrog while (isspace(*cptr)) 63116009Sgrog cptr++; /* skip initial white space */ 64116009Sgrog if ((*cptr == '\0') || (*cptr == '\n') 65116009Sgrog || (*cptr == '#')) /* end of line */ 66116009Sgrog return tokennr; /* return number of tokens found */ 67116009Sgrog delim = *cptr; 68116009Sgrog token[tokennr] = cptr; /* point to it */ 69116009Sgrog tokennr++; /* one more */ 70116009Sgrog if (tokennr == maxtoken) /* run off the end? */ 71116009Sgrog return tokennr; 72116009Sgrog if ((delim == '\'') || (delim == '"')) { /* delimitered */ 73116009Sgrog for (;;) { 74116009Sgrog cptr++; 75116009Sgrog if ((*cptr == delim) 76116009Sgrog && (cptr[-1] != '\\')) { /* found the partner */ 77116009Sgrog cptr++; /* move on past */ 78116009Sgrog if (!isspace(*cptr)) /* no space after closing quote */ 79116009Sgrog return -1; 80116009Sgrog *cptr++ = '\0'; /* delimit */ 81116009Sgrog } else if ((*cptr == '\0') 82116009Sgrog || (*cptr == '\n')) /* end of line */ 83116009Sgrog return -1; 84116009Sgrog } 85116009Sgrog } else { /* not quoted */ 86116009Sgrog while ((*cptr != '\0') && (!isspace(*cptr)) && (*cptr != '\n')) 87116009Sgrog cptr++; 88116009Sgrog if (*cptr != '\0') /* not end of the line, */ 89116009Sgrog *cptr++ = '\0'; /* delimit and move to the next */ 90116009Sgrog } 91116009Sgrog } 92116009Sgrog return maxtoken; /* can't get here */ 93116009Sgrog} 94116009Sgrog 95122033Sgreenstatic char * 96122033Sgreenfindmodule(char *modules_path, const char *module_name) 97122033Sgreen{ 98122033Sgreen char *const path_argv[2] = { modules_path, NULL }; 99122033Sgreen char *module_path = NULL; 100122033Sgreen int module_name_len = strlen(module_name); 101122033Sgreen FTS *fts; 102122033Sgreen FTSENT *ftsent; 103122033Sgreen 104122033Sgreen if (modules_path == NULL) { 105122033Sgreen fprintf(stderr, 106122033Sgreen "Can't allocate memory to traverse a path: %s (%d)\n", 107122033Sgreen strerror(errno), 108122033Sgreen errno); 109122033Sgreen exit(1); 110122033Sgreen } 111122033Sgreen fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); 112122033Sgreen if (fts == NULL) { 113122033Sgreen fprintf(stderr, 114122033Sgreen "Can't begin traversing path %s: %s (%d)\n", 115122033Sgreen modules_path, 116122033Sgreen strerror(errno), 117122033Sgreen errno); 118122033Sgreen exit(1); 119122033Sgreen } 120122033Sgreen while ((ftsent = fts_read(fts)) != NULL) { 121122033Sgreen if (ftsent->fts_info == FTS_DNR || 122122033Sgreen ftsent->fts_info == FTS_ERR || 123122033Sgreen ftsent->fts_info == FTS_NS) { 124122033Sgreen fprintf(stderr, 125122033Sgreen "Error while traversing path %s: %s (%d)\n", 126122033Sgreen modules_path, 127122033Sgreen strerror(errno), 128122033Sgreen errno); 129122033Sgreen exit(1); 130122033Sgreen } 131122033Sgreen if (ftsent->fts_info != FTS_F || 132122033Sgreen ftsent->fts_namelen != module_name_len || 133122033Sgreen memcmp(module_name, ftsent->fts_name, module_name_len) != 0) 134122033Sgreen continue; 135122033Sgreen if (asprintf(&module_path, 136122033Sgreen "%.*s", 137122033Sgreen ftsent->fts_pathlen, 138122033Sgreen ftsent->fts_path) == -1) { 139122033Sgreen fprintf(stderr, 140122033Sgreen "Can't allocate memory traversing path %s: %s (%d)\n", 141122033Sgreen modules_path, 142122033Sgreen strerror(errno), 143122033Sgreen errno); 144122033Sgreen exit(1); 145122033Sgreen } 146122033Sgreen break; 147122033Sgreen } 148122033Sgreen if (ftsent == NULL && errno != 0) { 149122033Sgreen fprintf(stderr, 150122033Sgreen "Couldn't complete traversing path %s: %s (%d)\n", 151122033Sgreen modules_path, 152122033Sgreen strerror(errno), 153122033Sgreen errno); 154122033Sgreen exit(1); 155122033Sgreen } 156122033Sgreen fts_close(fts); 157122033Sgreen free(modules_path); 158122033Sgreen return (module_path); 159122033Sgreen} 160122033Sgreen 161116017Sjmallettstatic void 162116017Sjmallettusage(const char *myname) 163116009Sgrog{ 164116009Sgrog fprintf(stderr, 165116009Sgrog "Usage:\n" 166122033Sgreen "%s [-a] [-f] [-k] [-s] [-x] [modules-path [outfile]]\n\n" 167116009Sgrog "\t-a\tappend to outfile)\n" 168122033Sgreen "\t-f\tfind the module in any subdirectory of module-path\n" 169116016Sjmallett "\t-k\ttake input from kldstat(8)\n" 170122033Sgreen "\t-s\tdon't prepend subdir for module path\n" 171116009Sgrog "\t-x\tdon't append \".debug\" to module name\n", 172116009Sgrog myname); 173116009Sgrog} 174116009Sgrog 175116009Sgrogint 176116009Sgrogmain(int argc, char *argv[]) 177116009Sgrog{ 178116009Sgrog char buf[MAXLINE]; 179116009Sgrog FILE *kldstat; 180116009Sgrog FILE *objcopy; 181116009Sgrog FILE *out; /* output file */ 182116009Sgrog char ocbuf[MAXLINE]; 183116009Sgrog int tokens; /* number of tokens on line */ 184116009Sgrog char basetoken[MAXLINE]; 185116009Sgrog int i; 186116017Sjmallett const char *filemode = "w"; /* mode for outfile */ 187116009Sgrog char cwd[MAXPATHLEN]; /* current directory */ 188116017Sjmallett const char *debugname = ".debug"; /* some file names end in this */ 189116017Sjmallett char *token[MAXTOKEN]; 190120430Ssimokawa int nosubdir = 0; 191122033Sgreen int dofind = 0; 192116009Sgrog 193116009Sgrog getcwd(cwd, MAXPATHLEN); /* find where we are */ 194116009Sgrog kldstat = stdin; 195116009Sgrog for (i = 1; i < argc; i++) { 196116009Sgrog if (argv[i][0] == '-') { 197116009Sgrog if (strcmp(argv[i], "-k") == 0) { /* get input from kldstat(8) */ 198116009Sgrog if (!(kldstat = popen("kldstat", "r"))) { 199116009Sgrog perror("Can't start kldstat"); 200116009Sgrog return 1; 201116009Sgrog } 202116009Sgrog } else if (strcmp(argv[i], "-a") == 0) /* append to outfile */ 203116009Sgrog filemode = "a"; 204116009Sgrog else if (strcmp(argv[i], "-x") == 0) /* no .debug extension */ 205116009Sgrog debugname = ""; /* nothing */ 206120430Ssimokawa else if (strcmp(argv[i], "-s") == 0) /* no subdir */ 207120430Ssimokawa nosubdir = 1; /* nothing */ 208122033Sgreen else if (strcmp(argv[i], "-f") == 0) /* find .ko (recursively) */ 209122033Sgreen dofind = 1; 210116009Sgrog else { 211116009Sgrog fprintf(stderr, 212116009Sgrog "Invalid option: %s, aborting\n", 213116009Sgrog argv[i]); 214116009Sgrog usage(argv[0]); 215116009Sgrog return 1; 216116009Sgrog } 217116009Sgrog } else if (modules_path == NULL) 218116009Sgrog modules_path = argv[i]; 219116009Sgrog else if (outfile == NULL) 220116009Sgrog outfile = argv[i]; 221116009Sgrog else { 222116009Sgrog fprintf(stderr, 223116009Sgrog "Extraneous startup information: \"%s\", aborting\n", 224116009Sgrog argv[i]); 225116009Sgrog usage(argv[0]); 226116009Sgrog return 1; 227116009Sgrog } 228116009Sgrog } 229116009Sgrog if (modules_path == NULL) 230116009Sgrog modules_path = "modules"; 231116009Sgrog if (outfile == NULL) 232116009Sgrog outfile = ".asf"; 233116009Sgrog if ((out = fopen(outfile, filemode)) == NULL) { 234116009Sgrog fprintf(stderr, 235116009Sgrog "Can't open output file %s: %s (%d)\n", 236116009Sgrog outfile, 237116009Sgrog strerror(errno), 238116009Sgrog errno); 239116009Sgrog return 1; 240116009Sgrog } 241116009Sgrog while (fgets(buf, MAXLINE, kldstat)) { 242116009Sgrog if ((!(strstr(buf, "kernel"))) 243116009Sgrog && buf[0] != 'I') { 244116009Sgrog quad_t base; 245116009Sgrog quad_t textaddr; 246116009Sgrog quad_t dataaddr; 247116009Sgrog quad_t bssaddr; 248116009Sgrog 249116009Sgrog tokens = tokenize(buf, token, MAXTOKEN); 250150410Sgrog if (tokens < 4) 251150410Sgrog continue; 252116009Sgrog base = strtoll(token[2], NULL, 16); 253122033Sgreen if (!dofind) { 254122033Sgreen strcpy(basetoken, token[4]); 255122033Sgreen basetoken[strlen(basetoken) - 3] = '/'; 256122033Sgreen basetoken[strlen(basetoken) - 2] = '\0'; /* cut off the .ko */ 257122033Sgreen snprintf(ocbuf, 258122033Sgreen MAXLINE, 259122033Sgreen "/usr/bin/objdump --section-headers %s/%s%s%s", 260122033Sgreen modules_path, 261122033Sgreen nosubdir ? "" : basetoken, 262122033Sgreen token[4], 263122033Sgreen debugname); 264122033Sgreen } else { 265122033Sgreen char *modpath; 266150410Sgrog 267122033Sgreen modpath = findmodule(strdup(modules_path), token[4]); 268122033Sgreen if (modpath == NULL) 269122033Sgreen continue; 270122033Sgreen snprintf(ocbuf, 271122033Sgreen MAXLINE, 272122033Sgreen "/usr/bin/objdump --section-headers %s%s", 273122033Sgreen modpath, 274122033Sgreen debugname); 275122033Sgreen free(modpath); 276122033Sgreen } 277116009Sgrog if (!(objcopy = popen(ocbuf, "r"))) { 278116009Sgrog fprintf(stderr, 279116009Sgrog "Can't start %s: %s (%d)\n", 280116009Sgrog ocbuf, 281116009Sgrog strerror(errno), 282116009Sgrog errno); 283116009Sgrog return 1; 284116009Sgrog } 285116009Sgrog while (fgets(ocbuf, MAXLINE, objcopy)) { 286116009Sgrog int octokens; 287116009Sgrog char *octoken[MAXTOKEN]; 288116009Sgrog 289116009Sgrog octokens = tokenize(ocbuf, octoken, MAXTOKEN); 290116009Sgrog if (octokens > 1) { 291116009Sgrog if (!strcmp(octoken[1], ".text")) 292116009Sgrog textaddr = strtoll(octoken[3], NULL, 16) + base; 293116009Sgrog else if (!strcmp(octoken[1], ".data")) 294116009Sgrog dataaddr = strtoll(octoken[3], NULL, 16) + base; 295116009Sgrog else if (!strcmp(octoken[1], ".bss")) 296116009Sgrog bssaddr = strtoll(octoken[3], NULL, 16) + base; 297116009Sgrog } 298116009Sgrog } 299116009Sgrog if (textaddr) { /* we must have a text address */ 300122033Sgreen if (!dofind) { 301122033Sgreen fprintf(out, 302122033Sgreen "add-symbol-file %s/%s/%s%s%s 0x%llx", 303122033Sgreen cwd, 304122033Sgreen modules_path, 305122033Sgreen nosubdir ? "" : basetoken, 306122033Sgreen token[4], 307122033Sgreen debugname, 308122033Sgreen textaddr); 309122033Sgreen } else { 310122033Sgreen char *modpath; 311150410Sgrog 312122033Sgreen modpath = findmodule(strdup(modules_path), token[4]); 313122033Sgreen if (modpath == NULL) 314122033Sgreen continue; 315122033Sgreen fprintf(out, 316122033Sgreen "add-symbol-file %s%s 0x%llx", 317122033Sgreen modpath, 318122033Sgreen debugname, 319122033Sgreen textaddr); 320122033Sgreen free(modpath); 321122033Sgreen } 322116009Sgrog if (dataaddr) 323116009Sgrog fprintf(out, " -s .data 0x%llx", dataaddr); 324116009Sgrog if (bssaddr) 325116009Sgrog fprintf(out, " -s .bss 0x%llx", bssaddr); 326116009Sgrog fprintf(out, "\n"); 327116009Sgrog } 328116009Sgrog } 329116009Sgrog } 330116009Sgrog return 0; 331116009Sgrog} 332