summaryrefslogtreecommitdiff
path: root/usr.bin/nm/nm.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2013-10-24 18:28:04 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2013-10-24 18:28:04 +0000
commit888df9bfd01b6ab53f1915859a6d141c65feda8c (patch)
tree40fb0962515139f9ebfdf5508ce1b9b6f71aeed9 /usr.bin/nm/nm.c
parent478b92caedd6d18aa8a97d5b479d856e6252ddd7 (diff)
back out to 1.33, subtle bug being hunted...
Diffstat (limited to 'usr.bin/nm/nm.c')
-rw-r--r--usr.bin/nm/nm.c234
1 files changed, 212 insertions, 22 deletions
diff --git a/usr.bin/nm/nm.c b/usr.bin/nm/nm.c
index 1fa97d88615..90d5362685a 100644
--- a/usr.bin/nm/nm.c
+++ b/usr.bin/nm/nm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nm.c,v 1.35 2013/10/21 02:59:52 deraadt Exp $ */
+/* $OpenBSD: nm.c,v 1.36 2013/10/24 18:28:03 deraadt Exp $ */
/* $NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $ */
/*
@@ -37,6 +37,7 @@
#include <sys/mman.h>
#include <a.out.h>
#include <elf_abi.h>
+#include <stab.h>
#include <ar.h>
#include <ranlib.h>
#include <unistd.h>
@@ -44,7 +45,9 @@
#include <errno.h>
#include <ctype.h>
#include <link.h>
-
+#ifdef __ELF__
+#include <link_aout.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -59,6 +62,7 @@
#define STRTABMAG "//"
union hdr {
+ struct exec aout;
Elf32_Ehdr elf32;
Elf64_Ehdr elf64;
};
@@ -91,21 +95,23 @@ int rev;
int fname(const void *, const void *);
int rname(const void *, const void *);
int value(const void *, const void *);
-char *otherstring(struct nlist *);
int (*sfunc)(const void *, const void *) = fname;
-char typeletter(struct nlist *);
+char *otherstring(struct nlist *);
+char *typestring(unsigned int);
+char typeletter(struct nlist *, int);
/* some macros for symbol type (nlist.n_type) handling */
+#define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB)
#define IS_EXTERNAL(x) ((x) & N_EXT)
#define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
void pipe2cppfilt(void);
void usage(void);
-char *symname(struct nlist *);
+char *symname(struct nlist *, int);
int process_file(int, const char *);
int show_archive(int, const char *, FILE *);
int show_file(int, int, const char *, FILE *fp, off_t, union hdr *);
-void print_symbol(const char *, struct nlist *);
+void print_symbol(const char *, struct nlist *, int);
#define OPTSTRING_NM "aABCegnoprsuvw"
const struct option longopts_nm[] = {
@@ -250,7 +256,7 @@ process_file(int count, const char *fname)
bzero(&exec_head, sizeof(exec_head));
bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp);
if (bytes < sizeof(exec_head)) {
- if (bytes < sizeof(exec_head.elf32) || IS_ELF(exec_head.elf32)) {
+ if (bytes < sizeof(exec_head.aout) || IS_ELF(exec_head.elf32)) {
warnx("%s: bad format", fname);
(void)fclose(fp);
return(1);
@@ -259,7 +265,7 @@ process_file(int count, const char *fname)
rewind(fp);
/* this could be an archive */
- if (!IS_ELF(exec_head.elf32)) {
+ if (!IS_ELF(exec_head.elf32) && N_BADMAG(exec_head.aout)) {
if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
strncmp(magic, ARMAG, SARMAG)) {
warnx("%s: not object file or archive", fname);
@@ -603,10 +609,11 @@ show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union
{
u_long text, data, bss, total;
struct nlist *np, *names, **snames;
- int i, nrawnames, nnames;
+ int i, aout, nrawnames, nnames;
size_t stabsize;
off_t staboff;
+ aout = 0;
if (IS_ELF(head->elf32) &&
head->elf32.e_ident[EI_CLASS] == ELFCLASS32 &&
head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) {
@@ -638,7 +645,108 @@ show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union
free(shdr);
if (i)
return (i);
- }
+
+ } else if (BAD_OBJECT(head->aout)) {
+ if (warn_fmt)
+ warnx("%s: bad format", name);
+ return (1);
+ } else do {
+ u_int32_t w;
+
+ aout++;
+
+ fix_header_order(&head->aout);
+
+ if (issize) {
+ text = head->aout.a_text;
+ data = head->aout.a_data;
+ bss = head->aout.a_bss;
+ break;
+ }
+
+ /* stop if the object file contains no symbol table */
+ if (!head->aout.a_syms) {
+ warnx("%s: no name list", name);
+ return(1);
+ }
+
+ if (fseeko(fp, foff + N_SYMOFF(head->aout), SEEK_SET)) {
+ warn("%s", name);
+ return(1);
+ }
+
+#ifdef __LP64__
+ nrawnames = head->aout.a_syms / sizeof(struct nlist32);
+#else
+ nrawnames = head->aout.a_syms / sizeof(*names);
+#endif
+ /* get memory for the symbol table */
+ if ((names = calloc(nrawnames, sizeof(struct nlist))) == NULL) {
+ warn("%s: malloc names", name);
+ return (1);
+ }
+
+ if ((snames = calloc(nrawnames, sizeof(struct nlist *))) == NULL) {
+ warn("%s: malloc snames", name);
+ free(names);
+ return (1);
+ }
+
+#ifdef __LP64__
+ for (np = names, i = nrawnames; i--; np++) {
+ struct nlist32 nl32;
+
+ if (fread(&nl32, sizeof(nl32), 1, fp) != 1) {
+ warnx("%s: cannot read symbol table", name);
+ free(snames);
+ free(names);
+ return (1);
+ }
+ np->n_type = nl32.type;
+ np->n_other = nl32.other;
+ if (byte_sex(N_GETMID(head->aout)) != BYTE_ORDER) {
+ np->n_un.n_strx = swap32(nl32.strx);
+ np->n_desc = swap16(nl32.desc);
+ np->n_value = swap32(nl32.value);
+ } else {
+ np->n_un.n_strx = nl32.strx;
+ np->n_desc = nl32.desc;
+ np->n_value = nl32.value;
+ }
+ }
+#else
+ if (fread(names, head->aout.a_syms, 1, fp) != 1) {
+ warnx("%s: cannot read symbol table", name);
+ free(snames);
+ free(names);
+ return (1);
+ }
+ fix_nlists_order(names, nrawnames, N_GETMID(head->aout));
+#endif
+
+ staboff = ftello(fp);
+ /*
+ * Following the symbol table comes the string table.
+ * The first 4-byte-integer gives the total size of the
+ * string table _including_ the size specification itself.
+ */
+ if (fread(&w, sizeof(w), (size_t)1, fp) != 1) {
+ warnx("%s: cannot read stab size", name);
+ free(snames);
+ free(names);
+ return(1);
+ }
+ stabsize = fix_32_order(w, N_GETMID(head->aout));
+ MMAP(stab, stabsize, PROT_READ, MAP_PRIVATE|MAP_FILE,
+ fileno(fp), staboff);
+ if (stab == MAP_FAILED) {
+ free(snames);
+ free(names);
+ return (1);
+ }
+
+ stabsize -= 4; /* we already have the size */
+ } while (0);
if (issize) {
static int first = 1;
@@ -691,6 +799,10 @@ show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union
np->n_un.n_name = stab + np->n_un.n_strx;
else
np->n_un.n_name = "";
+ if (aout && SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
+ np->n_type = N_COMM | (np->n_type & N_EXT);
+ if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
+ continue;
if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
continue;
if (print_only_undefined_symbols &&
@@ -712,7 +824,7 @@ show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union
if (show_extensions && snames[i] != names &&
SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR)
continue;
- print_symbol(name, snames[i]);
+ print_symbol(name, snames[i], aout);
}
free(snames);
@@ -722,9 +834,12 @@ show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union
}
char *
-symname(struct nlist *sym)
+symname(struct nlist *sym, int aout)
{
- return sym->n_un.n_name;
+ if (demangle && sym->n_un.n_name[0] == '_' && aout)
+ return sym->n_un.n_name + 1;
+ else
+ return sym->n_un.n_name;
}
/*
@@ -732,7 +847,7 @@ symname(struct nlist *sym)
* show one symbol
*/
void
-print_symbol(const char *name, struct nlist *sym)
+print_symbol(const char *name, struct nlist *sym, int aout)
{
if (print_file_each_line)
(void)printf("%s:", name);
@@ -751,16 +866,91 @@ print_symbol(const char *name, struct nlist *sym)
(void)printf("%08lx", sym->n_value);
/* print type information */
- if (show_extensions)
- (void)printf(" %c ", typeletter(sym));
+ if (IS_DEBUGGER_SYMBOL(sym->n_type))
+ (void)printf(" - %02x %04x %5s ", sym->n_other,
+ sym->n_desc&0xffff, typestring(sym->n_type));
+ else if (show_extensions)
+ (void)printf(" %c%2s ", typeletter(sym, aout),
+ otherstring(sym));
else
- (void)printf(" %c ", typeletter(sym));
+ (void)printf(" %c ", typeletter(sym, aout));
}
- if (SYMBOL_TYPE(sym->n_type) == N_INDR && show_extensions)
- printf("%s -> %s\n", symname(sym), symname(sym+1));
+ if (SYMBOL_TYPE(sym->n_type) == N_INDR && show_extensions) {
+ printf("%s -> %s\n", symname(sym, aout), symname(sym+1, aout));
+ }
else
- (void)puts(symname(sym));
+ (void)puts(symname(sym, aout));
+}
+
+char *
+otherstring(struct nlist *sym)
+{
+ static char buf[3];
+ char *result;
+
+ result = buf;
+
+ if (N_BIND(sym) == BIND_WEAK)
+ *result++ = 'w';
+ if (N_AUX(sym) == AUX_OBJECT)
+ *result++ = 'o';
+ else if (N_AUX(sym) == AUX_FUNC)
+ *result++ = 'f';
+ *result++ = 0;
+ return buf;
+}
+
+/*
+ * typestring()
+ * return the a description string for an STAB entry
+ */
+char *
+typestring(unsigned int type)
+{
+ switch(type) {
+ case N_BCOMM:
+ return("BCOMM");
+ case N_ECOML:
+ return("ECOML");
+ case N_ECOMM:
+ return("ECOMM");
+ case N_ENTRY:
+ return("ENTRY");
+ case N_FNAME:
+ return("FNAME");
+ case N_FUN:
+ return("FUN");
+ case N_GSYM:
+ return("GSYM");
+ case N_LBRAC:
+ return("LBRAC");
+ case N_LCSYM:
+ return("LCSYM");
+ case N_LENG:
+ return("LENG");
+ case N_LSYM:
+ return("LSYM");
+ case N_PC:
+ return("PC");
+ case N_PSYM:
+ return("PSYM");
+ case N_RBRAC:
+ return("RBRAC");
+ case N_RSYM:
+ return("RSYM");
+ case N_SLINE:
+ return("SLINE");
+ case N_SO:
+ return("SO");
+ case N_SOL:
+ return("SOL");
+ case N_SSYM:
+ return("SSYM");
+ case N_STSYM:
+ return("STSYM");
+ }
+ return("???");
}
/*
@@ -770,11 +960,11 @@ print_symbol(const char *name, struct nlist *sym)
* external, lower case for internal symbols.
*/
char
-typeletter(struct nlist *np)
+typeletter(struct nlist *np, int aout)
{
int ext = IS_EXTERNAL(np->n_type);
- if (np->n_other)
+ if (!aout && !IS_DEBUGGER_SYMBOL(np->n_type) && np->n_other)
return np->n_other;
switch(SYMBOL_TYPE(np->n_type)) {