version 1.35, 2013/10/21 02:59:52 |
version 1.36, 2013/10/24 18:28:03 |
|
|
#include <sys/mman.h> |
#include <sys/mman.h> |
#include <a.out.h> |
#include <a.out.h> |
#include <elf_abi.h> |
#include <elf_abi.h> |
|
#include <stab.h> |
#include <ar.h> |
#include <ar.h> |
#include <ranlib.h> |
#include <ranlib.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
#include <errno.h> |
#include <errno.h> |
#include <ctype.h> |
#include <ctype.h> |
#include <link.h> |
#include <link.h> |
|
#ifdef __ELF__ |
|
#include <link_aout.h> |
|
#endif |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
#define STRTABMAG "//" |
#define STRTABMAG "//" |
|
|
union hdr { |
union hdr { |
|
struct exec aout; |
Elf32_Ehdr elf32; |
Elf32_Ehdr elf32; |
Elf64_Ehdr elf64; |
Elf64_Ehdr elf64; |
}; |
}; |
|
|
int fname(const void *, const void *); |
int fname(const void *, const void *); |
int rname(const void *, const void *); |
int rname(const void *, const void *); |
int value(const void *, const void *); |
int value(const void *, const void *); |
char *otherstring(struct nlist *); |
|
int (*sfunc)(const void *, const void *) = fname; |
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 */ |
/* 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 IS_EXTERNAL(x) ((x) & N_EXT) |
#define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB)) |
#define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB)) |
|
|
void pipe2cppfilt(void); |
void pipe2cppfilt(void); |
void usage(void); |
void usage(void); |
char *symname(struct nlist *); |
char *symname(struct nlist *, int); |
int process_file(int, const char *); |
int process_file(int, const char *); |
int show_archive(int, const char *, FILE *); |
int show_archive(int, const char *, FILE *); |
int show_file(int, int, const char *, FILE *fp, off_t, union hdr *); |
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" |
#define OPTSTRING_NM "aABCegnoprsuvw" |
const struct option longopts_nm[] = { |
const struct option longopts_nm[] = { |
|
|
bzero(&exec_head, sizeof(exec_head)); |
bzero(&exec_head, sizeof(exec_head)); |
bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp); |
bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp); |
if (bytes < sizeof(exec_head)) { |
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); |
warnx("%s: bad format", fname); |
(void)fclose(fp); |
(void)fclose(fp); |
return(1); |
return(1); |
|
|
rewind(fp); |
rewind(fp); |
|
|
/* this could be an archive */ |
/* 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 || |
if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || |
strncmp(magic, ARMAG, SARMAG)) { |
strncmp(magic, ARMAG, SARMAG)) { |
warnx("%s: not object file or archive", fname); |
warnx("%s: not object file or archive", fname); |
|
|
{ |
{ |
u_long text, data, bss, total; |
u_long text, data, bss, total; |
struct nlist *np, *names, **snames; |
struct nlist *np, *names, **snames; |
int i, nrawnames, nnames; |
int i, aout, nrawnames, nnames; |
size_t stabsize; |
size_t stabsize; |
off_t staboff; |
off_t staboff; |
|
|
|
aout = 0; |
if (IS_ELF(head->elf32) && |
if (IS_ELF(head->elf32) && |
head->elf32.e_ident[EI_CLASS] == ELFCLASS32 && |
head->elf32.e_ident[EI_CLASS] == ELFCLASS32 && |
head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) { |
head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) { |
|
|
free(shdr); |
free(shdr); |
if (i) |
if (i) |
return (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) { |
if (issize) { |
static int first = 1; |
static int first = 1; |
|
|
|
|
np->n_un.n_name = stab + np->n_un.n_strx; |
np->n_un.n_name = stab + np->n_un.n_strx; |
else |
else |
np->n_un.n_name = ""; |
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)) |
if (print_only_external_symbols && !IS_EXTERNAL(np->n_type)) |
continue; |
continue; |
if (print_only_undefined_symbols && |
if (print_only_undefined_symbols && |
|
|
if (show_extensions && snames[i] != names && |
if (show_extensions && snames[i] != names && |
SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR) |
SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR) |
continue; |
continue; |
print_symbol(name, snames[i]); |
print_symbol(name, snames[i], aout); |
} |
} |
|
|
free(snames); |
free(snames); |
|
|
} |
} |
|
|
char * |
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; |
} |
} |
|
|
/* |
/* |
|
|
* show one symbol |
* show one symbol |
*/ |
*/ |
void |
void |
print_symbol(const char *name, struct nlist *sym) |
print_symbol(const char *name, struct nlist *sym, int aout) |
{ |
{ |
if (print_file_each_line) |
if (print_file_each_line) |
(void)printf("%s:", name); |
(void)printf("%s:", name); |
|
|
(void)printf("%08lx", sym->n_value); |
(void)printf("%08lx", sym->n_value); |
|
|
/* print type information */ |
/* print type information */ |
if (show_extensions) |
if (IS_DEBUGGER_SYMBOL(sym->n_type)) |
(void)printf(" %c ", typeletter(sym)); |
(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 |
else |
(void)printf(" %c ", typeletter(sym)); |
(void)printf(" %c ", typeletter(sym, aout)); |
} |
} |
|
|
if (SYMBOL_TYPE(sym->n_type) == N_INDR && show_extensions) |
if (SYMBOL_TYPE(sym->n_type) == N_INDR && show_extensions) { |
printf("%s -> %s\n", symname(sym), symname(sym+1)); |
printf("%s -> %s\n", symname(sym, aout), symname(sym+1, aout)); |
|
} |
else |
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("???"); |
|
} |
|
|
|
/* |
* typeletter() |
* typeletter() |
* return a description letter for the given basic type code of an |
* return a description letter for the given basic type code of an |
* symbol table entry. The return value will be upper case for |
* symbol table entry. The return value will be upper case for |
* external, lower case for internal symbols. |
* external, lower case for internal symbols. |
*/ |
*/ |
char |
char |
typeletter(struct nlist *np) |
typeletter(struct nlist *np, int aout) |
{ |
{ |
int ext = IS_EXTERNAL(np->n_type); |
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; |
return np->n_other; |
|
|
switch(SYMBOL_TYPE(np->n_type)) { |
switch(SYMBOL_TYPE(np->n_type)) { |