1 /* nm - print name list. Author: Dick van Veen */
3 /* Dick van Veen: veench@cs.vu.nl */
13 /* Read the name list in memory, sort it, and print it. */
15 /* Nm [-gnopru] [file] ...
18 * -d address in decimal
19 * -g print only external symbols.
20 * -n sort numerically rather than alphabetically.
21 * -o prepend file name to each line rather than only once.
22 * -p don't sort, pint n symbol-table order.
23 * -r sort in reverse order.
24 * -u print only undefined symbols.
26 * - when no file name is present, a.out is assumed.
28 * NOTE: no archives are supported because assembly files don't
43 char io_buf
[BUFSIZ
]; /* io buffer */
44 struct exec header
; /* header of a.out file */
45 int stbl_elems
; /* #elements in symbol table */
47 int main(int argc
, char **argv
);
48 int nm_sort(const void *tmp_stbl1
, const void *tmp_stbl2
);
50 int read_header(int fd
);
51 void nm_print(char *file
, struct nlist
*stbl
);
58 while (*argv
!= 0 && **argv
== '-') {
60 while (**argv
!= '\0') {
62 case 'd': d_flag
= 1; break;
63 case 'g': g_flag
= 1; break;
64 case 'n': n_flag
= 1; break;
65 case 'o': o_flag
= 1; break;
66 case 'p': p_flag
= 1; break;
67 case 'r': r_flag
= 1; break;
68 case 'u': u_flag
= 1; break;
70 fprintf(stderr
, "illegal flag: -%c\n", **argv
);
77 setbuf(stdin
, io_buf
);
88 int nm_sort(tmp_stbl1
, tmp_stbl2
)
89 const void *tmp_stbl1
, *tmp_stbl2
;
92 struct nlist
*stbl1
= (struct nlist
*)tmp_stbl1
;
93 struct nlist
*stbl2
= (struct nlist
*)tmp_stbl2
;
96 if (n_flag
) { /* sort numerically */
97 if ((stbl1
->n_sclass
& N_SECT
) <
98 (stbl2
->n_sclass
& N_SECT
))
100 else if ((stbl1
->n_sclass
& N_SECT
) >
101 (stbl2
->n_sclass
& N_SECT
))
103 else if (stbl1
->n_value
< stbl2
->n_value
)
105 else if (stbl1
->n_value
> stbl2
->n_value
)
108 cmp
= strncmp(stbl1
->n_name
, stbl2
->n_name
, (size_t)8);
110 cmp
= strncmp(stbl1
->n_name
, stbl2
->n_name
, (size_t)8);
112 if (stbl1
->n_value
< stbl2
->n_value
)
114 else if (stbl1
->n_value
> stbl2
->n_value
)
119 if (r_flag
) cmp
= -cmp
; /* reverse sort */
129 fd
= open(file
, O_RDONLY
);
131 fprintf(stderr
, "can't open %s\n", file
);
134 if (read_header(fd
)) {
135 fprintf(stderr
, "%s: no executable file\n", file
);
139 if (header
.a_syms
== 0) {
143 if ((size_t) header
.a_syms
!= header
.a_syms
) {
144 fprintf(stderr
, "%s: symbol table too large to allocate\n", file
);
148 if ((int) header
.a_syms
!= header
.a_syms
) {
149 /* This is necessary because we are too lazy to iterate the read. */
150 fprintf(stderr
, "%s: symbol table too large to read\n", file
);
154 stbl
= (struct nlist
*) malloc((size_t) header
.a_syms
);
156 fprintf(stderr
, "%s: can't allocate symbol table\n", file
);
160 if (read(fd
, (char *) stbl
, (unsigned) header
.a_syms
) != header
.a_syms
) {
161 fprintf(stderr
, "%s: can't read symbol table\n", file
);
166 stbl_elems
= (int) header
.a_syms
/ sizeof(struct nlist
);
167 if (!p_flag
) qsort(stbl
, (size_t)stbl_elems
, sizeof(struct nlist
), nm_sort
);
168 nm_print(file
, stbl
);
176 if (read(fd
, (char *) &header
, sizeof(struct exec
)) != sizeof(struct exec
))
178 if (BADMAG(header
)) return(1);
179 lseek(fd
, A_SYMPOS(header
), SEEK_SET
);
184 void nm_print(file
, stbl
)
186 register struct nlist
*stbl
;
194 if (!o_flag
) printf("%s:\n", file
);
195 for (last
= &stbl
[stbl_elems
]; stbl
!= last
; stbl
++) {
196 if (g_flag
&& (stbl
->n_sclass
& N_CLASS
) != C_EXT
) continue;
197 if (u_flag
&& (stbl
->n_sclass
& N_SECT
) != N_UNDF
) continue;
199 n_sclass
= stbl
->n_sclass
& N_SECT
;
200 if (n_sclass
== N_ABS
)
202 else if (n_sclass
== N_TEXT
)
204 else if (n_sclass
== N_DATA
)
206 else if (n_sclass
== N_BSS
)
210 if ((stbl
->n_sclass
& N_CLASS
) == C_EXT
) type
+= 'A' - 'a';
211 strncpy(name
, stbl
->n_name
, (size_t)8);
213 /* Offsets in decimal. */
215 printf("%s:%08ld %c %s\n",file
,stbl
->n_value
,type
,name
);
217 printf("%08ld %c %s\n", stbl
->n_value
, type
, name
);
219 /* Offsets in hex. */
221 printf("%s:%08lx %c %s\n",file
,stbl
->n_value
,type
,name
);
223 printf("%08lx %c %s\n", stbl
->n_value
, type
, name
);