unstack, sort: cleanup and improvement
[minix.git] / commands / acknm / acknm.c
blobcb043fffeb2eb1e522e9d70a73b5ebac39773574
1 /* nm - print name list. Author: Dick van Veen */
3 /* Dick van Veen: veench@cs.vu.nl */
5 #include <sys/types.h>
6 #include <a.out.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
13 /* Read the name list in memory, sort it, and print it. */
15 /* Nm [-gnopru] [file] ...
17 * flags:
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
29 * have symbol tables.
33 #define A_OUT "a.out"
35 int d_flag;
36 int g_flag;
37 int n_flag;
38 int o_flag;
39 int p_flag;
40 int r_flag;
41 int u_flag;
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);
49 void nm(char *file);
50 int read_header(int fd);
51 void nm_print(char *file, struct nlist *stbl);
53 int main(argc, argv)
54 int argc;
55 char **argv;
57 argv++;
58 while (*argv != 0 && **argv == '-') {
59 *argv += 1;
60 while (**argv != '\0') {
61 switch (**argv) {
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;
69 default:
70 fprintf(stderr, "illegal flag: -%c\n", **argv);
71 exit(-1);
73 *argv += 1;
75 argv++;
77 setbuf(stdin, io_buf);
78 if (*argv == 0)
79 nm(A_OUT);
80 else
81 while (*argv != 0) {
82 nm(*argv);
83 argv++;
85 return(0);
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;
94 int cmp;
96 if (n_flag) { /* sort numerically */
97 if ((stbl1->n_sclass & N_SECT) <
98 (stbl2->n_sclass & N_SECT))
99 cmp = -1;
100 else if ((stbl1->n_sclass & N_SECT) >
101 (stbl2->n_sclass & N_SECT))
102 cmp = 1;
103 else if (stbl1->n_value < stbl2->n_value)
104 cmp = -1;
105 else if (stbl1->n_value > stbl2->n_value)
106 cmp = 1;
107 else
108 cmp = strncmp(stbl1->n_name, stbl2->n_name, (size_t)8);
109 } else {
110 cmp = strncmp(stbl1->n_name, stbl2->n_name, (size_t)8);
111 if (cmp == 0) {
112 if (stbl1->n_value < stbl2->n_value)
113 cmp = -1;
114 else if (stbl1->n_value > stbl2->n_value)
115 cmp = 1;
119 if (r_flag) cmp = -cmp; /* reverse sort */
120 return(cmp);
123 void nm(file)
124 char *file;
126 struct nlist *stbl;
127 int fd;
129 fd = open(file, O_RDONLY);
130 if (fd == -1) {
131 fprintf(stderr, "can't open %s\n", file);
132 return;
134 if (read_header(fd)) {
135 fprintf(stderr, "%s: no executable file\n", file);
136 close(fd);
137 return;
139 if (header.a_syms == 0) {
140 close(fd);
141 return;
143 if ((size_t) header.a_syms != header.a_syms) {
144 fprintf(stderr, "%s: symbol table too large to allocate\n", file);
145 close(fd);
146 return;
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);
151 close(fd);
152 return;
154 stbl = (struct nlist *) malloc((size_t) header.a_syms);
155 if (stbl == NULL) {
156 fprintf(stderr, "%s: can't allocate symbol table\n", file);
157 close(fd);
158 return;
160 if (read(fd, (char *) stbl, (unsigned) header.a_syms) != header.a_syms) {
161 fprintf(stderr, "%s: can't read symbol table\n", file);
162 free(stbl);
163 close(fd);
164 return;
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);
169 free(stbl);
170 close(fd);
173 int read_header(fd)
174 int fd;
176 if (read(fd, (char *) &header, sizeof(struct exec)) != sizeof(struct exec))
177 return(1);
178 if (BADMAG(header)) return(1);
179 lseek(fd, A_SYMPOS(header), SEEK_SET);
181 return(0);
184 void nm_print(file, stbl)
185 char *file;
186 register struct nlist *stbl;
188 struct nlist *last;
189 char name[9];
190 int n_sclass;
191 char type;
193 name[8] = '\0';
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)
201 type = 'a';
202 else if (n_sclass == N_TEXT)
203 type = 't';
204 else if (n_sclass == N_DATA)
205 type = 'd';
206 else if (n_sclass == N_BSS)
207 type = 'b';
208 else
209 type = 'u';
210 if ((stbl->n_sclass & N_CLASS) == C_EXT) type += 'A' - 'a';
211 strncpy(name, stbl->n_name, (size_t)8);
212 if (d_flag) {
213 /* Offsets in decimal. */
214 if (o_flag)
215 printf("%s:%08ld %c %s\n",file,stbl->n_value,type,name);
216 else
217 printf("%08ld %c %s\n", stbl->n_value, type, name);
218 } else {
219 /* Offsets in hex. */
220 if (o_flag)
221 printf("%s:%08lx %c %s\n",file,stbl->n_value,type,name);
222 else
223 printf("%08lx %c %s\n", stbl->n_value, type, name);