diff --git a/src/cmd/make.bash b/src/cmd/make.bash index d705a51ce5d..84332440d0e 100644 --- a/src/cmd/make.bash +++ b/src/cmd/make.bash @@ -50,3 +50,8 @@ echo; echo; echo %%%% making db %%%%; echo cd db make install cd .. + +echo; echo; echo %%%% making nm %%%%; echo +cd nm +make install +cd .. diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile new file mode 100644 index 00000000000..080d668c9a1 --- /dev/null +++ b/src/cmd/nm/Makefile @@ -0,0 +1,24 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include ../../Make.conf + +# The directory is nm because the source is portable and general. +# We call the binary 6nm to avoid confusion and because this binary +# is linked only with amd64 and x86 support. + +TARG=6nm +OFILES=\ + nm.$O\ + +$(TARG): $(OFILES) + $(LD) -o $(TARG) -L$(GOROOT)/lib $(OFILES) -lmach_amd64 -lbio -l9 + +clean: + rm -f $(OFILES) $(TARG) + +install: $(TARG) + cp $(TARG) $(BIN)/$(TARG) + +$(OFILES): $(HFILES) diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c new file mode 100644 index 00000000000..7c77f66c618 --- /dev/null +++ b/src/cmd/nm/nm.c @@ -0,0 +1,344 @@ +// Inferno utils/nm/nm.c +// http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * nm.c -- drive nm + */ +#include +#include +#include +#include +#include + +enum{ + CHUNK = 256 /* must be power of 2 */ +}; + +char *errs; /* exit status */ +char *filename; /* current file */ +char symname[]="__.SYMDEF"; /* table of contents file name */ +int multifile; /* processing multiple files */ +int aflag; +int gflag; +int hflag; +int nflag; +int sflag; +int uflag; +int Tflag; + +Sym **fnames; /* file path translation table */ +Sym **symptr; +int nsym; +Biobuf bout; + +int cmp(void*, void*); +void error(char*, ...); +void execsyms(int); +void psym(Sym*, void*); +void printsyms(Sym**, long); +void doar(Biobuf*); +void dofile(Biobuf*); +void zenter(Sym*); + +void +usage(void) +{ + fprint(2, "usage: nm [-aghnsTu] file ...\n"); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + int i; + Biobuf *bin; + + Binit(&bout, 1, OWRITE); + argv0 = argv[0]; + ARGBEGIN { + default: usage(); + case 'a': aflag = 1; break; + case 'g': gflag = 1; break; + case 'h': hflag = 1; break; + case 'n': nflag = 1; break; + case 's': sflag = 1; break; + case 'u': uflag = 1; break; + case 'T': Tflag = 1; break; + } ARGEND + if (argc == 0) + usage(); + if (argc > 1) + multifile++; + for(i=0; ivalue < (*t)->value) + return -1; + else + return (*s)->value > (*t)->value; + return strcmp((*s)->name, (*t)->name); +} +/* + * enter a symbol in the table of filename elements + */ +void +zenter(Sym *s) +{ + static int maxf = 0; + + if (s->value > maxf) { + maxf = (s->value+CHUNK-1) &~ (CHUNK-1); + fnames = realloc(fnames, (maxf+1)*sizeof(*fnames)); + if(fnames == 0) { + error("out of memory", argv0); + exits("memory"); + } + } + fnames[s->value] = s; +} + +/* + * get the symbol table from an executable file, if it has one + */ +void +execsyms(int fd) +{ + Fhdr f; + Sym *s; + int32 n; + + seek(fd, 0, 0); + if (crackhdr(fd, &f) == 0) { + error("Can't read header for %s", filename); + return; + } + if (syminit(fd, &f) < 0) + return; + s = symbase(&n); + nsym = 0; + while(n--) + psym(s++, 0); + + printsyms(symptr, nsym); +} + +void +psym(Sym *s, void* p) +{ + USED(p); + switch(s->type) { + case 'T': + case 'L': + case 'D': + case 'B': + if (uflag) + return; + if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) + return; + break; + case 'b': + case 'd': + case 'l': + case 't': + if (uflag || gflag) + return; + if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) + return; + break; + case 'U': + if (gflag) + return; + break; + case 'Z': + if (!aflag) + return; + break; + case 'm': + case 'f': /* we only see a 'z' when the following is true*/ + if(!aflag || uflag || gflag) + return; + if (strcmp(s->name, ".frame")) + zenter(s); + break; + case 'a': + case 'p': + case 'z': + default: + if(!aflag || uflag || gflag) + return; + break; + } + symptr = realloc(symptr, (nsym+1)*sizeof(Sym*)); + if (symptr == 0) { + error("out of memory"); + exits("memory"); + } + symptr[nsym++] = s; +} + +void +printsyms(Sym **symptr, long nsym) +{ + int i, wid; + Sym *s; + char *cp; + char path[512]; + + if(!sflag) + qsort(symptr, nsym, sizeof(*symptr), (void*)cmp); + + wid = 0; + for (i=0; ivalue && wid == 0) + wid = 8; + else if (s->value >= 0x100000000LL && wid == 8) + wid = 16; + } + for (i=0; itype == 'z') { + fileelem(fnames, (uchar *) s->name, path, 512); + cp = path; + } else + cp = s->name; + if (Tflag) + Bprint(&bout, "%8ux ", s->sig); + if (s->value || s->type == 'a' || s->type == 'p') + Bprint(&bout, "%*llux ", wid, s->value); + else + Bprint(&bout, "%*s ", wid, ""); + Bprint(&bout, "%c %s\n", s->type, cp); + } +} + +void +error(char *fmt, ...) +{ + Fmt f; + char buf[128]; + va_list arg; + + fmtfdinit(&f, 2, buf, sizeof buf); + fmtprint(&f, "%s: ", argv0); + va_start(arg, fmt); + fmtvprint(&f, fmt, arg); + va_end(arg); + fmtprint(&f, "\n"); + fmtfdflush(&f); + errs = "errors"; +}