1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-03 06:45:37 -08:00

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@
This commit is contained in:
miod 2015-08-13 19:13:28 +00:00
parent ade61d9934
commit 1a0915b634
5 changed files with 163 additions and 95 deletions

View File

@ -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;

View File

@ -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 *);

View File

@ -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

View File

@ -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(" ");
if (print_file_each_line) {
if (posix_output)
(void)printf("%s: ", name);
else
(void)printf("%08lx", sym->n_value);
/* print type information */
if (show_extensions)
(void)printf(" %c ", typeletter(sym));
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);
}

View File

@ -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;
};