The Go Programming Language

Text file src/cmd/nm/nm.c

     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[]="__.SYMDEF";	/* 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		case 'f':	/* we only see a 'z' when the following is true*/
   279			if(!aflag || uflag || gflag)
   280				return;
   281			if (strcmp(s->name, ".frame"))
   282				zenter(s);
   283			break;
   284		case 'a':
   285		case 'p':
   286		case 'z':
   287		default:
   288			if(!aflag || uflag || gflag)
   289				return;
   290			break;
   291		}
   292		symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
   293		if (symptr == 0) {
   294			error("out of memory");
   295			exits("memory");
   296		}
   297		symptr[nsym++] = s;
   298	}
   299	
   300	void
   301	printsyms(Sym **symptr, long nsym)
   302	{
   303		int i, j, wid;
   304		Sym *s;
   305		char *cp;
   306		char path[512];
   307	
   308		qsort(symptr, nsym, sizeof(*symptr), (void*)cmp);
   309	
   310		wid = 0;
   311		for (i=0; i<nsym; i++) {
   312			s = symptr[i];
   313			if (s->value && wid == 0)
   314				wid = 8;
   315			else if (s->value >= 0x100000000LL && wid == 8)
   316				wid = 16;
   317		}
   318		for (i=0; i<nsym; i++) {
   319			s = symptr[i];
   320			if (multifile && !hflag)
   321				Bprint(&bout, "%s:", filename);
   322			if (s->type == 'z') {
   323				fileelem(fnames, (uchar *) s->name, path, 512);
   324				cp = path;
   325			} else
   326				cp = s->name;
   327			if (Tflag)
   328				Bprint(&bout, "%8ux ", s->sig);
   329			if (s->value || s->type == 'a' || s->type == 'p')
   330				Bprint(&bout, "%*llux ", wid, s->value);
   331			else
   332				Bprint(&bout, "%*s ", wid, "");
   333			if(Sflag) {
   334				vlong siz;
   335	
   336				siz = 0;
   337				for(j=i+1; j<nsym; j++) {
   338					if(symptr[j]->type != 'a' && symptr[j]->type != 'p') {
   339						siz = symptr[j]->value - s->value;
   340						break;
   341					}
   342				}
   343				if(siz > 0)
   344					Bprint(&bout, "%*llud ", wid, siz);
   345			}
   346			Bprint(&bout, "%c %s", s->type, cp);
   347			if(tflag && s->gotype)
   348				Bprint(&bout, " %*llux", wid, s->gotype);
   349			Bprint(&bout, "\n");
   350		}
   351	}
   352	
   353	void
   354	error(char *fmt, ...)
   355	{
   356		Fmt f;
   357		char buf[128];
   358		va_list arg;
   359	
   360		fmtfdinit(&f, 2, buf, sizeof buf);
   361		fmtprint(&f, "%s: ", argv0);
   362		va_start(arg, fmt);
   363		fmtvprint(&f, fmt, arg);
   364		va_end(arg);
   365		fmtprint(&f, "\n");
   366		fmtfdflush(&f);
   367		errs = "errors";
   368	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.