main.c (4846B)
1 static char sccsid[] = "@(#) ./nm/main.c"; 2 3 #include <errno.h> 4 #include <limits.h> 5 #include <stdint.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include "../inc/arg.h" 11 #include "../inc/scc.h" 12 #include "../inc/myro.h" 13 #include "../inc/ar.h" 14 15 char *argv0; 16 char *strings; 17 static int radix = 16; 18 static int Pflag; 19 static int Aflag; 20 static int vflag; 21 static int gflag; 22 static int uflag; 23 static int archflag; 24 25 static int 26 object(char *fname, FILE *fp) 27 { 28 char magic[MYROMAGIC_SIZ]; 29 fpos_t pos; 30 31 fgetpos(fp, &pos); 32 fread(magic, sizeof(magic), 1, fp); 33 if (!ferror(fp)) { 34 if (!strncmp(magic, MYROMAGIC, MYROMAGIC_SIZ)) 35 return 1; 36 } 37 38 fsetpos(fp, &pos); 39 return 0; 40 } 41 42 static int 43 archive(char *fname, FILE *fp) 44 { 45 char magic[ARMAGIC_SIZ]; 46 fpos_t pos; 47 48 fgetpos(fp, &pos); 49 fread(magic, sizeof(magic), 1, fp); 50 51 if (!ferror(fp)) { 52 if (!strncmp(magic, ARMAGIC, ARMAGIC_SIZ)) 53 return 1; 54 } 55 56 fsetpos(fp, &pos); 57 return 0; 58 } 59 60 static int 61 cmp(const void *p1, const void *p2) 62 { 63 const struct myrosym *s1 = p1, *s2 = p2; 64 65 if (vflag) 66 return s1->offset - s2->offset; 67 else 68 return strcmp(strings + s1->name, strings + s2->name); 69 } 70 71 static int 72 typeof(struct myrosym *sym) 73 { 74 return 'U'; 75 } 76 77 static void 78 print(char *file, char *member, struct myrosym *sym, FILE *fp) 79 { 80 char *fmt, *name = strings + sym->name; 81 int type = typeof(sym); 82 83 if (uflag && type != 'U') 84 return; 85 if (gflag && type != 'A' && type != 'B' && type != 'D') 86 return; 87 88 if (Aflag) 89 fprintf(fp, (archflag) ? "%s[%s]: " : "%s: ", file, member); 90 if (Pflag) { 91 fprintf(fp, "%s %c", name, type); 92 if (type != 'U') { 93 if (radix == 8) 94 fmt = "%llo %llo"; 95 else if (radix == 10) 96 fmt = "%llu %llu"; 97 else 98 fmt = "%llx %llx"; 99 fprintf(fp, fmt, sym->offset, sym->len); 100 } 101 } else { 102 if (type == 'U') 103 fmt = " "; 104 else if (radix == 8) 105 fmt = "%016.16llo"; 106 else if (radix == 8) 107 fmt = "%016.16lld"; 108 else 109 fmt = "%016.16llx"; 110 fprintf(fp, fmt, sym->offset); 111 fprintf(fp, " %c %s", type, name); 112 } 113 putc('\n', fp); 114 } 115 116 static void 117 nm(char *fname, char *member, FILE *fp) 118 { 119 struct myrohdr hdr; 120 struct myrosym *syms = NULL; 121 size_t n, i; 122 long off; 123 124 strings = NULL; 125 if (rdmyrohdr(fp, &hdr) < 0) { 126 fprintf(stderr, "nm: %s: incorrect header\n", member); 127 return; 128 } 129 130 n = hdr.symsize / MYROSYM_SIZ; 131 if (n == 0) { 132 fprintf(stderr, "nm: %s: no name list\n", member); 133 return; 134 } 135 if (n > SIZE_MAX / sizeof(struct myrosym) || 136 hdr.symsize / MYROSYM_SIZ > SIZE_MAX || 137 hdr.strsize > SIZE_MAX) { 138 goto offset_overflow; 139 } 140 141 syms = xmalloc(n * sizeof(struct myrosym)); 142 strings = xmalloc(hdr.strsize); 143 fread(strings, hdr.strsize, 1, fp); 144 if (feof(fp)) 145 goto free_arrays; 146 if ((off = ftell(fp)) < 0) 147 return; 148 if (off > LONG_MAX - hdr.secsize) 149 goto offset_overflow; 150 off += hdr.secsize; 151 152 if (fseek(fp, off, SEEK_SET) < 0) 153 goto free_arrays; 154 155 for (i = 0; i < n; ++i) { 156 if (rdmyrosym(fp, &syms[i]) < 0) 157 goto free_arrays; 158 if (syms[i].name >= hdr.strsize) 159 goto offset_overflow; 160 } 161 qsort(syms, n, sizeof(*syms), cmp); 162 for (i = 0; i < n; ++i) 163 print(fname, member, &syms[i], fp); 164 165 166 free_arrays: 167 free(syms); 168 free(strings); 169 return; 170 171 offset_overflow: 172 fprintf(stderr, "nm: %s: overflow in headers of archive\n", 173 fname); 174 goto free_arrays; 175 } 176 177 static void 178 ar(char *fname, FILE *fp) 179 { 180 struct arhdr hdr; 181 long pos; 182 183 archflag = 1; 184 while (rdarhdr(fp, &hdr) != EOF) { 185 pos = ftell(fp); 186 if (pos == -1 || pos > LONG_MAX - hdr.size) { 187 fprintf(stderr, 188 "nm: %s: overflow in size of archive\n", 189 fname); 190 return; 191 } 192 pos += hdr.size; 193 if (hdr.size & 1) 194 ++pos; 195 196 if (object(fname, fp)) { 197 nm(fname, hdr.name, fp); 198 } else { 199 fprintf(stderr, 200 "nm: skipping member %s in archive %s\n", 201 hdr.name, fname); 202 } 203 fseek(fp, pos, SEEK_SET); 204 } 205 } 206 207 void 208 doit(char *fname) 209 { 210 FILE *fp; 211 212 archflag = 0; 213 if ((fp = fopen(fname, "rb")) == NULL) 214 goto file_error; 215 216 if (object(fname, fp)) 217 nm(fname, fname, fp); 218 else if (archive(fname, fp)) 219 ar(fname, fp); 220 else 221 fprintf(stderr, "nm: %s: File format not recognized\n", fname); 222 223 if (fclose(fp) != EOF) 224 return; 225 226 file_error: 227 die("nm: %s: %s", fname, strerror(errno)); 228 } 229 230 void 231 usage(void) 232 { 233 fputs("nm [-APv][ -g| -u][-t format] [file...]\n", stderr); 234 exit(1); 235 } 236 237 int 238 main(int argc, char *argv[]) 239 { 240 char *t; 241 242 ARGBEGIN { 243 case 'P': 244 Pflag = 1; 245 break; 246 case 'A': 247 Aflag = 1; 248 break; 249 case 'g': 250 gflag = 1; 251 break; 252 case 'u': 253 uflag = 1; 254 break; 255 case 'v': 256 vflag = 1; 257 break; 258 case 't': 259 t = EARGF(usage()); 260 if (!strcmp(t, "o")) 261 radix = 8; 262 else if (!strcmp(t, "d")) 263 radix = 10; 264 else if (!strcmp(t, "x")) 265 radix = 16; 266 else 267 usage(); 268 break; 269 default: 270 usage(); 271 } ARGEND 272 273 if (argc == 0) { 274 doit("a.out"); 275 } else { 276 while (argc-- > 0) 277 doit(*++argv); 278 } 279 280 return 0; 281 }