github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/nm/nm.c (about)

     1  // Inferno utils/nm/nm.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  /*
    32   * nm.c -- drive nm
    33   */
    34  #include <u.h>
    35  #include <libc.h>
    36  #include <ar.h>
    37  #include <bio.h>
    38  #include <mach.h>
    39  
    40  enum{
    41  	CHUNK	=	256	/* must be power of 2 */
    42  };
    43  
    44  char	*errs;			/* exit status */
    45  char	*filename;		/* current file */
    46  char	symname[]="__.GOSYMDEF";	/* table of contents file name */
    47  int	multifile;		/* processing multiple files */
    48  int	aflag;
    49  int	gflag;
    50  int	hflag;
    51  int	nflag;
    52  int	sflag;
    53  int	Sflag;
    54  int	uflag;
    55  int	Tflag;
    56  int	tflag;
    57  
    58  Sym	**fnames;		/* file path translation table */
    59  Sym	**symptr;
    60  int	nsym;
    61  Biobuf	bout;
    62  
    63  int	cmp(void*, void*);
    64  void	error(char*, ...);
    65  void	execsyms(int);
    66  void	psym(Sym*, void*);
    67  void	printsyms(Sym**, long);
    68  void	doar(Biobuf*);
    69  void	dofile(Biobuf*);
    70  void	zenter(Sym*);
    71  
    72  void
    73  usage(void)
    74  {
    75  	fprint(2, "usage: nm [-aghnsTu] file ...\n");
    76  	exits("usage");
    77  }
    78  
    79  void
    80  main(int argc, char *argv[])
    81  {
    82  	int i;
    83  	Biobuf	*bin;
    84  
    85  	Binit(&bout, 1, OWRITE);
    86  	argv0 = argv[0];
    87  	ARGBEGIN {
    88  	default:	usage();
    89  	case 'a':	aflag = 1; break;
    90  	case 'g':	gflag = 1; break;
    91  	case 'h':	hflag = 1; break;
    92  	case 'n':	nflag = 1; break;
    93  	case 's':	sflag = 1; break;
    94  	case 'S':	nflag = Sflag = 1; break;
    95  	case 'u':	uflag = 1; break;
    96  	case 't':	tflag = 1; break;
    97  	case 'T':	Tflag = 1; break;
    98  	} ARGEND
    99  	if (argc == 0)
   100  		usage();
   101  	if (argc > 1)
   102  		multifile++;
   103  	for(i=0; i<argc; i++){
   104  		filename = argv[i];
   105  		bin = Bopen(filename, OREAD);
   106  		if(bin == 0){
   107  			error("cannot open %s", filename);
   108  			continue;
   109  		}
   110  		if (isar(bin))
   111  			doar(bin);
   112  		else{
   113  			Bseek(bin, 0, 0);
   114  			dofile(bin);
   115  		}
   116  		Bterm(bin);
   117  	}
   118  	exits(errs);
   119  }
   120  
   121  /*
   122   * read an archive file,
   123   * processing the symbols for each intermediate file in it.
   124   */
   125  void
   126  doar(Biobuf *bp)
   127  {
   128  	int offset, size, obj;
   129  	char name[SARNAME];
   130  
   131  	multifile = 1;
   132  	for (offset = Boffset(bp);;offset += size) {
   133  		size = nextar(bp, offset, name);
   134  		if (size < 0) {
   135  			error("phase error on ar header %d", offset);
   136  			return;
   137  		}
   138  		if (size == 0)
   139  			return;
   140  		if (strcmp(name, symname) == 0)
   141  			continue;
   142  		obj = objtype(bp, 0);
   143  		if (obj < 0) {
   144  			// perhaps foreign object
   145  			if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0)
   146  				return;
   147  			error("inconsistent file %s in %s",
   148  					name, filename);
   149  			return;
   150  		}
   151  		if (!readar(bp, obj, offset+size, 1)) {
   152  			error("invalid symbol reference in file %s",
   153  					name);
   154  			return;
   155  		}
   156  		filename = name;
   157  		nsym=0;
   158  		objtraverse(psym, 0);
   159  		printsyms(symptr, nsym);
   160  	}
   161  }
   162  
   163  /*
   164   * process symbols in a file
   165   */
   166  void
   167  dofile(Biobuf *bp)
   168  {
   169  	int obj;
   170  
   171  	obj = objtype(bp, 0);
   172  	if (obj < 0)
   173  		execsyms(Bfildes(bp));
   174  	else
   175  	if (readobj(bp, obj)) {
   176  		nsym = 0;
   177  		objtraverse(psym, 0);
   178  		printsyms(symptr, nsym);
   179  	}
   180  }
   181  
   182  /*
   183   * comparison routine for sorting the symbol table
   184   *	this screws up on 'z' records when aflag == 1
   185   */
   186  int
   187  cmp(void *vs, void *vt)
   188  {
   189  	Sym **s, **t;
   190  
   191  	s = vs;
   192  	t = vt;
   193  	if(nflag)	// sort on address (numeric) order
   194  		if((*s)->value < (*t)->value)
   195  			return -1;
   196  		else
   197  			return (*s)->value > (*t)->value;
   198  	if(sflag)	// sort on file order (sequence)
   199  		return (*s)->sequence - (*t)->sequence;
   200  	return strcmp((*s)->name, (*t)->name);
   201  }
   202  /*
   203   * enter a symbol in the table of filename elements
   204   */
   205  void
   206  zenter(Sym *s)
   207  {
   208  	static int maxf = 0;
   209  
   210  	if (s->value > maxf) {
   211  		maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
   212  		fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
   213  		if(fnames == 0) {
   214  			error("out of memory", argv0);
   215  			exits("memory");
   216  		}
   217  	}
   218  	fnames[s->value] = s;
   219  }
   220  
   221  /*
   222   * get the symbol table from an executable file, if it has one
   223   */
   224  void
   225  execsyms(int fd)
   226  {
   227  	Fhdr f;
   228  	Sym *s;
   229  	int32 n;
   230  
   231  	seek(fd, 0, 0);
   232  	if (crackhdr(fd, &f) == 0) {
   233  		error("Can't read header for %s", filename);
   234  		return;
   235  	}
   236  	if (syminit(fd, &f) < 0)
   237  		return;
   238  	s = symbase(&n);
   239  	nsym = 0;
   240  	while(n--)
   241  		psym(s++, 0);
   242  
   243  	printsyms(symptr, nsym);
   244  }
   245  
   246  void
   247  psym(Sym *s, void* p)
   248  {
   249  	USED(p);
   250  	switch(s->type) {
   251  	case 'T':
   252  	case 'L':
   253  	case 'D':
   254  	case 'B':
   255  		if (uflag)
   256  			return;
   257  		if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
   258  			return;
   259  		break;
   260  	case 'b':
   261  	case 'd':
   262  	case 'l':
   263  	case 't':
   264  		if (uflag || gflag)
   265  			return;
   266  		if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
   267  			return;
   268  		break;
   269  	case 'U':
   270  		if (gflag)
   271  			return;
   272  		break;
   273  	case 'Z':
   274  		if (!aflag)
   275  			return;
   276  		break;
   277  	case 'm':
   278  		if(!aflag || uflag || gflag)
   279  			return;
   280  		break;
   281  	case 'f':	/* we only see a 'z' when the following is true*/
   282  		if(!aflag || uflag || gflag)
   283  			return;
   284  		zenter(s);
   285  		break;
   286  	case 'a':
   287  	case 'p':
   288  	case 'z':
   289  	default:
   290  		if(!aflag || uflag || gflag)
   291  			return;
   292  		break;
   293  	}
   294  	symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
   295  	if (symptr == 0) {
   296  		error("out of memory");
   297  		exits("memory");
   298  	}
   299  	symptr[nsym++] = s;
   300  }
   301  
   302  void
   303  printsyms(Sym **symptr, long nsym)
   304  {
   305  	int i, j, wid;
   306  	Sym *s;
   307  	char *cp;
   308  	char path[512];
   309  
   310  	qsort(symptr, nsym, sizeof(*symptr), (void*)cmp);
   311  
   312  	wid = 0;
   313  	for (i=0; i<nsym; i++) {
   314  		s = symptr[i];
   315  		if (s->value && wid == 0)
   316  			wid = 8;
   317  		else if (s->value >= 0x100000000LL && wid == 8)
   318  			wid = 16;
   319  	}
   320  	for (i=0; i<nsym; i++) {
   321  		s = symptr[i];
   322  		if (multifile && !hflag)
   323  			Bprint(&bout, "%s:", filename);
   324  		if (s->type == 'z') {
   325  			fileelem(fnames, (uchar *) s->name, path, 512);
   326  			cp = path;
   327  		} else
   328  			cp = s->name;
   329  		if (Tflag)
   330  			Bprint(&bout, "%8ux ", s->sig);
   331  		if (s->value || s->type == 'a' || s->type == 'p')
   332  			Bprint(&bout, "%*llux ", wid, s->value);
   333  		else
   334  			Bprint(&bout, "%*s ", wid, "");
   335  		if(Sflag) {
   336  			vlong siz;
   337  
   338  			siz = 0;
   339  			for(j=i+1; j<nsym; j++) {
   340  				if(symptr[j]->type != 'a' && symptr[j]->type != 'p') {
   341  					siz = symptr[j]->value - s->value;
   342  					break;
   343  				}
   344  			}
   345  			if(siz > 0)
   346  				Bprint(&bout, "%*llud ", wid, siz);
   347  		}
   348  		Bprint(&bout, "%c %s", s->type, cp);
   349  		if(tflag && s->gotype)
   350  			Bprint(&bout, " %*llux", wid, s->gotype);
   351  		Bprint(&bout, "\n");
   352  	}
   353  }
   354  
   355  void
   356  error(char *fmt, ...)
   357  {
   358  	Fmt f;
   359  	char buf[128];
   360  	va_list arg;
   361  
   362  	fmtfdinit(&f, 2, buf, sizeof buf);
   363  	fmtprint(&f, "%s: ", argv0);
   364  	va_start(arg, fmt);
   365  	fmtvprint(&f, fmt, arg);
   366  	va_end(arg);
   367  	fmtprint(&f, "\n");
   368  	fmtfdflush(&f);
   369  	errs = "errors";
   370  }