summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2015-08-13 19:13:29 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2015-08-13 19:13:29 +0000
commit594f369c3083b9c5702508642f03f24299ca98de (patch)
treecd49e70d1620bac6b7199050caa7c64f0f77a4ba
parent661ac077c29d835753830294c6810b04625ad12f (diff)
Grow -P (POSIX output) and -t (POSIX output radix) support. Several 3rd-party
software depend upon this. Requested by feinerer@, ok millert@; manpage bits ok jmc@
-rw-r--r--usr.bin/nm/elf.c63
-rw-r--r--usr.bin/nm/elfuncs.h10
-rw-r--r--usr.bin/nm/nm.134
-rw-r--r--usr.bin/nm/nm.c144
-rw-r--r--usr.bin/nm/util.h7
5 files changed, 163 insertions, 95 deletions
diff --git a/usr.bin/nm/elf.c b/usr.bin/nm/elf.c
index c44a6babbe5..7458af512ce 100644
--- a/usr.bin/nm/elf.c
+++ b/usr.bin/nm/elf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: elf.c,v 1.32 2015/06/23 15:16:34 semarie Exp $ */
+/* $OpenBSD: elf.c,v 1.33 2015/08/13 19:13:28 miod Exp $ */
/*
* Copyright (c) 2003 Michael Shalayeff
@@ -37,8 +37,8 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#include "elfuncs.h"
#include "util.h"
+#include "elfuncs.h"
#if ELFSIZE == 32
#define swap_addr swap32
@@ -116,7 +116,7 @@
#endif
int elf_shn2type(Elf_Ehdr *, u_int, const char *);
-int elf2nlist(Elf_Sym *, Elf_Ehdr *, Elf_Shdr *, char *, struct nlist *);
+int elf2nlist(Elf_Sym *, Elf_Ehdr *, Elf_Shdr *, char *, struct xnlist *);
int
elf_fix_header(Elf_Ehdr *eh)
@@ -342,11 +342,12 @@ elf_shn2type(Elf_Ehdr *eh, u_int shn, const char *sn)
}
/*
- * Devise nlist's type from Elf_Sym.
+ * Devise xnlist's type from Elf_Sym.
* XXX this task is done as well in libc and kvm_mkdb.
*/
int
-elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr, struct nlist *np)
+elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr,
+ struct xnlist *np)
{
u_char stt;
const char *sn;
@@ -372,60 +373,61 @@ elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr, struct nlist
type = elf_shn2type(eh, sym->st_shndx, sn);
if (type < 0) {
if (sn == NULL)
- np->n_other = '?';
+ np->nl.n_other = '?';
else
- np->n_type = stt == STT_NOTYPE? N_COMM : N_DATA;
+ np->nl.n_type = stt == STT_NOTYPE ?
+ N_COMM : N_DATA;
} else {
/* a hack for .rodata check (; */
if (type == N_SIZE) {
- np->n_type = N_DATA;
- np->n_other = 'r';
+ np->nl.n_type = N_DATA;
+ np->nl.n_other = 'r';
} else
- np->n_type = type;
+ np->nl.n_type = type;
}
if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
- np->n_other = 'W';
+ np->nl.n_other = 'W';
break;
case STT_FUNC:
type = elf_shn2type(eh, sym->st_shndx, NULL);
- np->n_type = type < 0? N_TEXT : type;
+ np->nl.n_type = type < 0? N_TEXT : type;
if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
- np->n_other = 'W';
+ np->nl.n_other = 'W';
} else if (sn != NULL && *sn != 0 &&
strcmp(sn, ELF_INIT) &&
strcmp(sn, ELF_TEXT) &&
strcmp(sn, ELF_FINI)) /* XXX GNU compat */
- np->n_other = '?';
+ np->nl.n_other = '?';
break;
case STT_SECTION:
type = elf_shn2type(eh, sym->st_shndx, NULL);
if (type < 0)
- np->n_other = '?';
+ np->nl.n_other = '?';
else
- np->n_type = type;
+ np->nl.n_type = type;
break;
case STT_FILE:
- np->n_type = N_FN | N_EXT;
+ np->nl.n_type = N_FN | N_EXT;
break;
case STT_PARISC_MILLI:
if (eh->e_machine == EM_PARISC)
- np->n_type = N_TEXT;
+ np->nl.n_type = N_TEXT;
else
- np->n_other = '?';
+ np->nl.n_other = '?';
break;
default:
- np->n_other = '?';
+ np->nl.n_other = '?';
break;
}
- if (np->n_type != N_UNDF && ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
- np->n_type |= N_EXT;
- if (np->n_other)
- np->n_other = toupper((unsigned char)np->n_other);
+ if (np->nl.n_type != N_UNDF && ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
+ np->nl.n_type |= N_EXT;
+ if (np->nl.n_other)
+ np->nl.n_other = toupper((unsigned char)np->nl.n_other);
}
return (0);
@@ -456,12 +458,12 @@ elf_size(Elf_Ehdr *head, Elf_Shdr *shdr,
int
elf_symloadx(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
- Elf_Shdr *shdr, char *shstr, long shstrsize, struct nlist **pnames,
- struct nlist ***psnames, size_t *pstabsize, int *pnrawnames,
+ Elf_Shdr *shdr, char *shstr, long shstrsize, struct xnlist **pnames,
+ struct xnlist ***psnames, size_t *pstabsize, int *pnrawnames,
const char *strtab, const char *symtab)
{
long symsize;
- struct nlist *np;
+ struct xnlist *np;
Elf_Sym sbuf;
int i;
@@ -532,8 +534,9 @@ elf_symloadx(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
continue;
elf2nlist(&sbuf, eh, shdr, shstr, np);
- np->n_value = sbuf.st_value;
- np->n_un.n_strx = sbuf.st_name;
+ np->nl.n_value = sbuf.st_value;
+ np->nl.n_un.n_strx = sbuf.st_name;
+ np->n_size = sbuf.st_size;
np++;
}
*pnrawnames = np - *pnames;
@@ -544,7 +547,7 @@ elf_symloadx(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
int
elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
- Elf_Shdr *shdr, struct nlist **pnames, struct nlist ***psnames,
+ Elf_Shdr *shdr, struct xnlist **pnames, struct xnlist ***psnames,
size_t *pstabsize, int *pnrawnames)
{
long shstrsize;
diff --git a/usr.bin/nm/elfuncs.h b/usr.bin/nm/elfuncs.h
index 7121c75c75a..e1f1977c2f2 100644
--- a/usr.bin/nm/elfuncs.h
+++ b/usr.bin/nm/elfuncs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: elfuncs.h,v 1.4 2015/06/23 15:02:58 semarie Exp $ */
+/* $OpenBSD: elfuncs.h,v 1.5 2015/08/13 19:13:28 miod Exp $ */
/*
* Copyright (c) 2004 Michael Shalayeff
@@ -36,10 +36,10 @@ int elf32_fix_phdrs(Elf32_Ehdr *eh, Elf32_Phdr *phdr);
int elf32_fix_sym(Elf32_Ehdr *eh, Elf32_Sym *sym);
int elf32_size(Elf32_Ehdr *, Elf32_Shdr *, u_long *, u_long *, u_long *);
int elf32_symloadx(const char *, FILE *, off_t, Elf32_Ehdr *, Elf32_Shdr *,
- char *, long, struct nlist **, struct nlist ***, size_t *, int *,
+ char *, long, struct xnlist **, struct xnlist ***, size_t *, int *,
const char *, const char *);
int elf32_symload(const char *, FILE *, off_t, Elf32_Ehdr *, Elf32_Shdr *,
- struct nlist **, struct nlist ***, size_t *, int *);
+ struct xnlist **, struct xnlist ***, size_t *, int *);
int elf64_fix_header(Elf64_Ehdr *eh);
Elf64_Shdr*elf64_load_shdrs(const char *, FILE *, off_t, Elf64_Ehdr *);
@@ -49,7 +49,7 @@ int elf64_fix_phdrs(Elf64_Ehdr *eh, Elf64_Phdr *phdr);
int elf64_fix_sym(Elf64_Ehdr *eh, Elf64_Sym *sym);
int elf64_size(Elf64_Ehdr *, Elf64_Shdr *, u_long *, u_long *, u_long *);
int elf64_symloadx(const char *, FILE *, off_t, Elf64_Ehdr *, Elf64_Shdr *,
- char *, long, struct nlist **, struct nlist ***, size_t *, int *,
+ char *, long, struct xnlist **, struct xnlist ***, size_t *, int *,
const char *, const char *);
int elf64_symload(const char *, FILE *, off_t, Elf64_Ehdr *, Elf64_Shdr *,
- struct nlist **, struct nlist ***, size_t *, int *);
+ struct xnlist **, struct xnlist ***, size_t *, int *);
diff --git a/usr.bin/nm/nm.1 b/usr.bin/nm/nm.1
index 0d75aa531e0..f3a0c04e7dd 100644
--- a/usr.bin/nm/nm.1
+++ b/usr.bin/nm/nm.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: nm.1,v 1.27 2015/05/17 20:19:08 guenther Exp $
+.\" $OpenBSD: nm.1,v 1.28 2015/08/13 19:13:28 miod Exp $
.\" $NetBSD: nm.1,v 1.3 1995/08/31 23:41:58 jtc Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
@@ -30,7 +30,7 @@
.\"
.\" @(#)nm.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd $Mdocdate: May 17 2015 $
+.Dd $Mdocdate: August 13 2015 $
.Dt NM 1
.Os
.Sh NAME
@@ -38,7 +38,8 @@
.Nd display name list (symbol table)
.Sh SYNOPSIS
.Nm nm
-.Op Fl aCDegnoprsuw
+.Op Fl AaCDegnoPprsuw
+.Op Fl t d|o|x
.Op Ar
.Sh DESCRIPTION
The symbol table (name list) of each object in
@@ -58,6 +59,8 @@ and displays its symbol table if it exists.
.Pp
The options are as follows:
.Bl -tag -width Ds
+.It Fl A
+Display the full path or library name of object on every line.
.It Fl a
Display symbol table entries inserted for use by debuggers.
.It Fl C
@@ -73,13 +76,36 @@ Restrict display to external (global) symbols.
.It Fl n
Present results in numerical order.
.It Fl o
-Display full path or library name of object on every line.
+Display the full path or library name of object on every line
+.Pq this is similar to Fl A .
+.It Fl P
+Report information in POSIX format: full path or library name of object if
+either
+.Fl A
+or
+.Fl o
+has been specified; symbol name; symbol type;
+symbol value and size (unless the symbol is undefined).
+The radix of symbol values and sizes defaults to decimal, and may be changed
+with the
+.Fl t
+option.
.It Fl p
Do not sort at all.
.It Fl r
Reverse order sort.
.It Fl s
Show archive index.
+.It Fl t Ar d|o|x
+In POSIX format output, choose the numeric radix as follows:
+.Bl -tag -width 3n -compact
+.It d
+Decimal.
+.It o
+Octal.
+.It x
+Hexadecimal.
+.El
.It Fl u
Display undefined symbols only.
.It Fl w
diff --git a/usr.bin/nm/nm.c b/usr.bin/nm/nm.c
index bb80d03dc01..bc02f50d758 100644
--- a/usr.bin/nm/nm.c
+++ b/usr.bin/nm/nm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nm.c,v 1.46 2015/05/17 21:41:50 guenther Exp $ */
+/* $OpenBSD: nm.c,v 1.47 2015/08/13 19:13:28 miod Exp $ */
/* $NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $ */
/*
@@ -49,8 +49,8 @@
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
-#include "elfuncs.h"
#include "util.h"
+#include "elfuncs.h"
#define SYMTABMAG "/ "
#define STRTABMAG "//"
@@ -70,6 +70,9 @@ int print_all_symbols;
int print_file_each_line;
int show_extensions;
int issize;
+char posix_fmtstr[6];
+int posix_output;
+char posix_radix = 'x';
int usemmap = 1;
int dynamic_only;
@@ -81,9 +84,9 @@ int rev;
int fname(const void *, const void *);
int rname(const void *, const void *);
int value(const void *, const void *);
-char *otherstring(struct nlist *);
+char *otherstring(struct xnlist *);
int (*sfunc)(const void *, const void *) = fname;
-char typeletter(struct nlist *);
+char typeletter(struct xnlist *);
int mmbr_name(struct ar_hdr *, char **, int, int *, FILE *);
int show_symtab(off_t, u_long, const char *, FILE *);
int show_symdef(off_t, u_long, const char *, FILE *);
@@ -94,13 +97,13 @@ int show_symdef(off_t, u_long, const char *, FILE *);
void pipe2cppfilt(void);
void usage(void);
-char *symname(struct nlist *);
+char *symname(struct xnlist *);
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 xnlist *);
-#define OPTSTRING_NM "aABCDegnoprsuvw"
+#define OPTSTRING_NM "aABCDegnopPrst:uvw"
const struct option longopts_nm[] = {
{ "debug-syms", no_argument, 0, 'a' },
{ "demangle", no_argument, 0, 'C' },
@@ -171,6 +174,9 @@ main(int argc, char *argv[])
case 'p':
sfunc = NULL;
break;
+ case 'P':
+ posix_output = 1;
+ break;
case 'r':
rev = 1;
break;
@@ -186,14 +192,23 @@ main(int argc, char *argv[])
case 't':
if (issize) {
print_totals = 1;
- break;
+ } else {
+ posix_radix = *optarg;
+ if (strlen(optarg) != 1 ||
+ (posix_radix != 'd' && posix_radix != 'o' &&
+ posix_radix != 'x'))
+ usage();
}
+ break;
case '?':
default:
usage();
}
}
+ if (posix_output)
+ (void)snprintf(posix_fmtstr, sizeof posix_fmtstr, "%%%c %%%c",
+ posix_radix, posix_radix);
if (demangle)
pipe2cppfilt();
argv += optind;
@@ -468,6 +483,8 @@ show_archive(int count, const char *fname, FILE *fp)
u_long mmbrlen, symtablen;
baselen = strlen(fname) + 3;
+ if (posix_output)
+ baselen += 2;
namelen = sizeof(ar_head.ar_name);
if ((name = malloc(baselen + namelen)) == NULL)
err(1, NULL);
@@ -555,7 +572,9 @@ show_archive(int count, const char *fname, FILE *fp)
* on each output line
*/
*name = '\0';
- if (count > 1)
+ if (posix_output)
+ snprintf(name, baselen - 1, "%s[", fname);
+ else if (count > 1)
snprintf(name, baselen - 1, "%s:", fname);
if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) {
@@ -563,6 +582,9 @@ show_archive(int count, const char *fname, FILE *fp)
break;
}
+ if (posix_output)
+ strlcat(name, "]", baselen + namelen);
+
foff = ftello(fp);
/* get and check current object's header */
@@ -605,7 +627,7 @@ int
show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head)
{
u_long text, data, bss, total;
- struct nlist *np, *names, **snames;
+ struct xnlist *np, *names, **snames;
int i, nrawnames, nnames;
size_t stabsize;
@@ -693,14 +715,14 @@ show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union
*
* don't mess with zero offsets
*/
- if (np->n_un.n_strx)
- np->n_un.n_name = stab + np->n_un.n_strx;
+ if (np->nl.n_un.n_strx)
+ np->nl.n_un.n_name = stab + np->nl.n_un.n_strx;
else
- np->n_un.n_name = "";
- if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
+ np->nl.n_un.n_name = "";
+ if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type))
continue;
if (print_only_undefined_symbols &&
- SYMBOL_TYPE(np->n_type) != N_UNDF)
+ SYMBOL_TYPE(np->nl.n_type) != N_UNDF)
continue;
snames[nnames++] = np;
@@ -724,9 +746,9 @@ show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union
}
char *
-symname(struct nlist *sym)
+symname(struct xnlist *sym)
{
- return sym->n_un.n_name;
+ return sym->nl.n_un.n_name;
}
/*
@@ -734,30 +756,42 @@ symname(struct nlist *sym)
* show one symbol
*/
void
-print_symbol(const char *name, struct nlist *sym)
+print_symbol(const char *name, struct xnlist *sym)
{
- if (print_file_each_line)
- (void)printf("%s:", name);
-
- /*
- * handle undefined-only format especially (no space is
- * left for symbol values, no type field is printed)
- */
- if (!print_only_undefined_symbols) {
- /* print symbol's value */
- if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
- (void)printf(" ");
- else
- (void)printf("%08lx", sym->n_value);
-
- /* print type information */
- if (show_extensions)
- (void)printf(" %c ", typeletter(sym));
+ if (print_file_each_line) {
+ if (posix_output)
+ (void)printf("%s: ", name);
else
- (void)printf(" %c ", typeletter(sym));
+ (void)printf("%s:", name);
}
- (void)puts(symname(sym));
+ if (posix_output) {
+ (void)printf("%s %c ", symname(sym), typeletter(sym));
+ if (SYMBOL_TYPE(sym->nl.n_type) != N_UNDF)
+ (void)printf(posix_fmtstr, sym->nl.n_value,
+ sym->n_size);
+ (void)printf("\n");
+ } else {
+ /*
+ * handle undefined-only format especially (no space is
+ * left for symbol values, no type field is printed)
+ */
+ if (!print_only_undefined_symbols) {
+ /* print symbol's value */
+ if (SYMBOL_TYPE(sym->nl.n_type) == N_UNDF)
+ (void)printf(" ");
+ else
+ (void)printf("%08lx", sym->nl.n_value);
+
+ /* print type information */
+ if (show_extensions)
+ (void)printf(" %c ", typeletter(sym));
+ else
+ (void)printf(" %c ", typeletter(sym));
+ }
+
+ (void)puts(symname(sym));
+ }
}
/*
@@ -767,14 +801,14 @@ print_symbol(const char *name, struct nlist *sym)
* external, lower case for internal symbols.
*/
char
-typeletter(struct nlist *np)
+typeletter(struct xnlist *np)
{
- int ext = IS_EXTERNAL(np->n_type);
+ int ext = IS_EXTERNAL(np->nl.n_type);
- if (np->n_other)
- return np->n_other;
+ if (np->nl.n_other)
+ return np->nl.n_other;
- switch(SYMBOL_TYPE(np->n_type)) {
+ switch(SYMBOL_TYPE(np->nl.n_type)) {
case N_ABS:
return(ext? 'A' : 'a');
case N_BSS:
@@ -802,39 +836,39 @@ typeletter(struct nlist *np)
int
fname(const void *a0, const void *b0)
{
- struct nlist * const *a = a0, * const *b = b0;
+ struct xnlist * const *a = a0, * const *b = b0;
- return(strcmp((*a)->n_un.n_name, (*b)->n_un.n_name));
+ return(strcmp((*a)->nl.n_un.n_name, (*b)->nl.n_un.n_name));
}
int
rname(const void *a0, const void *b0)
{
- struct nlist * const *a = a0, * const *b = b0;
+ struct xnlist * const *a = a0, * const *b = b0;
- return(strcmp((*b)->n_un.n_name, (*a)->n_un.n_name));
+ return(strcmp((*b)->nl.n_un.n_name, (*a)->nl.n_un.n_name));
}
int
value(const void *a0, const void *b0)
{
- struct nlist * const *a = a0, * const *b = b0;
+ struct xnlist * const *a = a0, * const *b = b0;
- if (SYMBOL_TYPE((*a)->n_type) == N_UNDF)
- if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
+ if (SYMBOL_TYPE((*a)->nl.n_type) == N_UNDF)
+ if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF)
return(0);
else
return(-1);
- else if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
+ else if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF)
return(1);
if (rev) {
- if ((*a)->n_value == (*b)->n_value)
+ if ((*a)->nl.n_value == (*b)->nl.n_value)
return(rname(a0, b0));
- return((*b)->n_value > (*a)->n_value ? 1 : -1);
+ return((*b)->nl.n_value > (*a)->nl.n_value ? 1 : -1);
} else {
- if ((*a)->n_value == (*b)->n_value)
+ if ((*a)->nl.n_value == (*b)->nl.n_value)
return(fname(a0, b0));
- return((*a)->n_value > (*b)->n_value ? 1 : -1);
+ return((*a)->nl.n_value > (*b)->nl.n_value ? 1 : -1);
}
}
@@ -875,7 +909,7 @@ usage(void)
if (issize)
fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname);
else
- fprintf(stderr, "usage: %s [-aCDegnoprsuw] [file ...]\n",
+ fprintf(stderr, "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n",
__progname);
exit(1);
}
diff --git a/usr.bin/nm/util.h b/usr.bin/nm/util.h
index 622f2158972..f91fa432f23 100644
--- a/usr.bin/nm/util.h
+++ b/usr.bin/nm/util.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.h,v 1.4 2015/06/23 15:16:34 semarie Exp $ */
+/* $OpenBSD: util.h,v 1.5 2015/08/13 19:13:28 miod Exp $ */
/*
* Placed in the public domain by Todd C. Miller <Todd.Miller@courtesan.com>
@@ -31,3 +31,8 @@
extern int usemmap;
extern int dynamic_only;
+
+struct xnlist {
+ struct nlist nl;
+ unsigned long n_size;
+};