Print this page
4054 dis sometimes decides random symbols are functions
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/dis/dis_main.c
+++ new/usr/src/cmd/dis/dis_main.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 *
26 26 * Copyright 2011 Jason King. All rights reserved.
27 27 */
28 28
29 29 #include <ctype.h>
30 30 #include <getopt.h>
31 31 #include <stdio.h>
32 32 #include <stdlib.h>
33 33 #include <string.h>
34 34 #include <sys/sysmacros.h>
35 35 #include <sys/elf_SPARC.h>
36 36
37 37 #include <libdisasm.h>
38 38
39 39 #include "dis_target.h"
40 40 #include "dis_util.h"
41 41 #include "dis_list.h"
42 42
43 43 int g_demangle; /* Demangle C++ names */
44 44 int g_quiet; /* Quiet mode */
45 45 int g_numeric; /* Numeric mode */
46 46 int g_flags; /* libdisasm language flags */
47 47 int g_doall; /* true if no functions or sections were given */
48 48
49 49 dis_namelist_t *g_funclist; /* list of functions to disassemble, if any */
50 50 dis_namelist_t *g_seclist; /* list of sections to disassemble, if any */
51 51
52 52 /*
53 53 * Section options for -d, -D, and -s
54 54 */
55 55 #define DIS_DATA_RELATIVE 1
56 56 #define DIS_DATA_ABSOLUTE 2
57 57 #define DIS_TEXT 3
58 58
59 59 /*
60 60 * libdisasm callback data. Keeps track of current data (function or section)
61 61 * and offset within that data.
62 62 */
63 63 typedef struct dis_buffer {
64 64 dis_tgt_t *db_tgt; /* current dis target */
65 65 void *db_data; /* function or section data */
66 66 uint64_t db_addr; /* address of function start */
67 67 size_t db_size; /* size of data */
68 68 uint64_t db_nextaddr; /* next address to be read */
69 69 } dis_buffer_t;
70 70
71 71 #define MINSYMWIDTH 22 /* Minimum width of symbol portion of line */
72 72
73 73 /*
74 74 * Given a symbol+offset as returned by dis_tgt_lookup(), print an appropriately
75 75 * formatted symbol, based on the offset and current setttings.
76 76 */
77 77 void
78 78 getsymname(uint64_t addr, const char *symbol, off_t offset, char *buf,
79 79 size_t buflen)
80 80 {
81 81 if (symbol == NULL || g_numeric) {
82 82 if (g_flags & DIS_OCTAL)
83 83 (void) snprintf(buf, buflen, "0%llo", addr);
84 84 else
85 85 (void) snprintf(buf, buflen, "0x%llx", addr);
86 86 } else {
87 87 if (g_demangle)
88 88 symbol = dis_demangle(symbol);
89 89
90 90 if (offset == 0)
91 91 (void) snprintf(buf, buflen, "%s", symbol);
92 92 else if (g_flags & DIS_OCTAL)
93 93 (void) snprintf(buf, buflen, "%s+0%o", symbol, offset);
94 94 else
95 95 (void) snprintf(buf, buflen, "%s+0x%x", symbol, offset);
96 96 }
97 97 }
98 98
99 99 /*
100 100 * The main disassembly routine. Given a fixed-sized buffer and starting
101 101 * address, disassemble the data using the supplied target and libdisasm handle.
102 102 */
103 103 void
104 104 dis_data(dis_tgt_t *tgt, dis_handle_t *dhp, uint64_t addr, void *data,
105 105 size_t datalen)
↓ open down ↓ |
105 lines elided |
↑ open up ↑ |
106 106 {
107 107 dis_buffer_t db = { 0 };
108 108 char buf[BUFSIZE];
109 109 char symbuf[BUFSIZE];
110 110 const char *symbol;
111 111 const char *last_symbol;
112 112 off_t symoffset;
113 113 int i;
114 114 int bytesperline;
115 115 size_t symsize;
116 - int isfunc;
116 + int isfunc = 0;
117 117 size_t symwidth = 0;
118 118
119 119 db.db_tgt = tgt;
120 120 db.db_data = data;
121 121 db.db_addr = addr;
122 122 db.db_size = datalen;
123 123
124 124 dis_set_data(dhp, &db);
125 125
126 126 if ((bytesperline = dis_max_instrlen(dhp)) > 6)
127 127 bytesperline = 6;
128 128
129 129 symbol = NULL;
130 130
131 131 while (addr < db.db_addr + db.db_size) {
132 132
133 133 if (dis_disassemble(dhp, addr, buf, BUFSIZE) != 0) {
134 134 #if defined(__sparc)
135 135 /*
136 136 * Since sparc instructions are fixed size, we
137 137 * always know the address of the next instruction
138 138 */
139 139 (void) snprintf(buf, sizeof (buf),
140 140 "*** invalid opcode ***");
141 141 db.db_nextaddr = addr + 4;
142 142
143 143 #else
144 144 off_t next;
145 145
146 146 (void) snprintf(buf, sizeof (buf),
147 147 "*** invalid opcode ***");
148 148
149 149 /*
150 150 * On architectures with variable sized instructions
151 151 * we have no way to figure out where the next
152 152 * instruction starts if we encounter an invalid
153 153 * instruction. Instead we print the rest of the
154 154 * instruction stream as hex until we reach the
155 155 * next valid symbol in the section.
156 156 */
157 157 if ((next = dis_tgt_next_symbol(tgt, addr)) == 0) {
158 158 db.db_nextaddr = db.db_addr + db.db_size;
159 159 } else {
160 160 if (next > db.db_size)
161 161 db.db_nextaddr = db.db_addr +
162 162 db.db_size;
163 163 else
164 164 db.db_nextaddr = addr + next;
165 165 }
166 166 #endif
167 167 }
168 168
169 169 /*
170 170 * Print out the line as:
171 171 *
172 172 * address: bytes text
173 173 *
174 174 * If there are more than 6 bytes in any given instruction,
175 175 * spread the bytes across two lines. We try to get symbolic
176 176 * information for the address, but if that fails we print out
177 177 * the numeric address instead.
178 178 *
179 179 * We try to keep the address portion of the text aligned at
180 180 * MINSYMWIDTH characters. If we are disassembling a function
181 181 * with a long name, this can be annoying. So we pick a width
182 182 * based on the maximum width that the current symbol can be.
183 183 * This at least produces text aligned within each function.
184 184 */
185 185 last_symbol = symbol;
186 186 symbol = dis_tgt_lookup(tgt, addr, &symoffset, 1, &symsize,
187 187 &isfunc);
188 188 if (symbol == NULL) {
189 189 symbol = dis_find_section(tgt, addr, &symoffset);
190 190 symsize = symoffset;
191 191 }
192 192
193 193 if (symbol != last_symbol)
194 194 getsymname(addr, symbol, symsize, symbuf,
195 195 sizeof (symbuf));
196 196
197 197 symwidth = MAX(symwidth, strlen(symbuf));
198 198 getsymname(addr, symbol, symoffset, symbuf, sizeof (symbuf));
199 199
200 200 /*
201 201 * If we've crossed a new function boundary, print out the
202 202 * function name on a blank line.
203 203 */
204 204 if (!g_quiet && symoffset == 0 && symbol != NULL && isfunc)
205 205 (void) printf("%s()\n", symbol);
206 206
207 207 (void) printf(" %s:%*s ", symbuf,
208 208 symwidth - strlen(symbuf), "");
209 209
210 210 /* print bytes */
211 211 for (i = 0; i < MIN(bytesperline, (db.db_nextaddr - addr));
212 212 i++) {
213 213 int byte = *((uchar_t *)data + (addr - db.db_addr) + i);
214 214 if (g_flags & DIS_OCTAL)
215 215 (void) printf("%03o ", byte);
216 216 else
217 217 (void) printf("%02x ", byte);
218 218 }
219 219
220 220 /* trailing spaces for missing bytes */
221 221 for (; i < bytesperline; i++) {
222 222 if (g_flags & DIS_OCTAL)
223 223 (void) printf(" ");
224 224 else
225 225 (void) printf(" ");
226 226 }
227 227
228 228 /* contents of disassembly */
229 229 (void) printf(" %s", buf);
230 230
231 231 /* excess bytes that spill over onto subsequent lines */
232 232 for (; i < db.db_nextaddr - addr; i++) {
233 233 int byte = *((uchar_t *)data + (addr - db.db_addr) + i);
234 234 if (i % bytesperline == 0)
235 235 (void) printf("\n %*s ", symwidth, "");
236 236 if (g_flags & DIS_OCTAL)
237 237 (void) printf("%03o ", byte);
238 238 else
239 239 (void) printf("%02x ", byte);
240 240 }
241 241
242 242 (void) printf("\n");
243 243
244 244 addr = db.db_nextaddr;
245 245 }
246 246 }
247 247
248 248 /*
249 249 * libdisasm wrapper around symbol lookup. Invoke the target-specific lookup
250 250 * function, and convert the result using getsymname().
251 251 */
252 252 int
253 253 do_lookup(void *data, uint64_t addr, char *buf, size_t buflen, uint64_t *start,
254 254 size_t *symlen)
255 255 {
256 256 dis_buffer_t *db = data;
257 257 const char *symbol;
258 258 off_t offset;
259 259 size_t size;
260 260
261 261 /*
262 262 * If NULL symbol is returned, getsymname takes care of
263 263 * printing appropriate address in buf instead of symbol.
264 264 */
265 265 symbol = dis_tgt_lookup(db->db_tgt, addr, &offset, 0, &size, NULL);
266 266
267 267 if (buf != NULL)
268 268 getsymname(addr, symbol, offset, buf, buflen);
269 269
270 270 if (start != NULL)
271 271 *start = addr - offset;
272 272 if (symlen != NULL)
273 273 *symlen = size;
274 274
275 275 if (symbol == NULL)
276 276 return (-1);
277 277
278 278 return (0);
279 279 }
280 280
281 281 /*
282 282 * libdisasm wrapper around target reading. libdisasm will always read data
283 283 * in order, so update our current offset within the buffer appropriately.
284 284 * We only support reading from within the current object; libdisasm should
285 285 * never ask us to do otherwise.
286 286 */
287 287 int
288 288 do_read(void *data, uint64_t addr, void *buf, size_t len)
289 289 {
290 290 dis_buffer_t *db = data;
291 291 size_t offset;
292 292
293 293 if (addr < db->db_addr || addr >= db->db_addr + db->db_size)
294 294 return (-1);
295 295
296 296 offset = addr - db->db_addr;
297 297 len = MIN(len, db->db_size - offset);
298 298
299 299 (void) memcpy(buf, (char *)db->db_data + offset, len);
300 300
301 301 db->db_nextaddr = addr + len;
302 302
303 303 return (len);
304 304 }
305 305
306 306 /*
307 307 * Routine to dump raw data in a human-readable format. Used by the -d and -D
308 308 * options. We model our output after the xxd(1) program, which gives nicely
309 309 * formatted output, along with an ASCII translation of the result.
310 310 */
311 311 void
312 312 dump_data(uint64_t addr, void *data, size_t datalen)
313 313 {
314 314 uintptr_t curaddr = addr & (~0xf);
315 315 uint8_t *bytes = data;
316 316 int i;
317 317 int width;
318 318
319 319 /*
320 320 * Determine if the address given to us fits in 32-bit range, in which
321 321 * case use a 4-byte width.
322 322 */
323 323 if (((addr + datalen) & 0xffffffff00000000ULL) == 0ULL)
324 324 width = 8;
325 325 else
326 326 width = 16;
327 327
328 328 while (curaddr < addr + datalen) {
329 329 /*
330 330 * Display leading address
331 331 */
332 332 (void) printf("%0*x: ", width, curaddr);
333 333
334 334 /*
335 335 * Print out data in two-byte chunks. If the current address
336 336 * is before the starting address or after the end of the
337 337 * section, print spaces.
338 338 */
339 339 for (i = 0; i < 16; i++) {
340 340 if (curaddr + i < addr ||curaddr + i >= addr + datalen)
341 341 (void) printf(" ");
342 342 else
343 343 (void) printf("%02x",
344 344 bytes[curaddr + i - addr]);
345 345
346 346 if (i & 1)
347 347 (void) printf(" ");
348 348 }
349 349
350 350 (void) printf(" ");
351 351
352 352 /*
353 353 * Print out the ASCII representation
354 354 */
355 355 for (i = 0; i < 16; i++) {
356 356 if (curaddr + i < addr ||
357 357 curaddr + i >= addr + datalen) {
358 358 (void) printf(" ");
359 359 } else {
360 360 uint8_t byte = bytes[curaddr + i - addr];
361 361 if (isprint(byte))
362 362 (void) printf("%c", byte);
363 363 else
364 364 (void) printf(".");
365 365 }
366 366 }
367 367
368 368 (void) printf("\n");
369 369
370 370 curaddr += 16;
371 371 }
372 372 }
373 373
374 374 /*
375 375 * Disassemble a section implicitly specified as part of a file. This function
376 376 * is called for all sections when no other flags are specified. We ignore any
377 377 * data sections, and print out only those sections containing text.
378 378 */
379 379 void
380 380 dis_text_section(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
381 381 {
382 382 dis_handle_t *dhp = data;
383 383
384 384 /* ignore data sections */
385 385 if (!dis_section_istext(scn))
386 386 return;
387 387
388 388 if (!g_quiet)
389 389 (void) printf("\nsection %s\n", dis_section_name(scn));
390 390
391 391 dis_data(tgt, dhp, dis_section_addr(scn), dis_section_data(scn),
392 392 dis_section_size(scn));
393 393 }
394 394
395 395 /*
396 396 * Structure passed to dis_named_{section,function} which keeps track of both
397 397 * the target and the libdisasm handle.
398 398 */
399 399 typedef struct callback_arg {
400 400 dis_tgt_t *ca_tgt;
401 401 dis_handle_t *ca_handle;
402 402 } callback_arg_t;
403 403
404 404 /*
405 405 * Disassemble a section explicitly named with -s, -d, or -D. The 'type'
406 406 * argument contains the type of argument given. Pass the data onto the
407 407 * appropriate helper routine.
408 408 */
409 409 void
410 410 dis_named_section(dis_scn_t *scn, int type, void *data)
411 411 {
412 412 callback_arg_t *ca = data;
413 413
414 414 if (!g_quiet)
415 415 (void) printf("\nsection %s\n", dis_section_name(scn));
416 416
417 417 switch (type) {
418 418 case DIS_DATA_RELATIVE:
419 419 dump_data(0, dis_section_data(scn), dis_section_size(scn));
420 420 break;
421 421 case DIS_DATA_ABSOLUTE:
422 422 dump_data(dis_section_addr(scn), dis_section_data(scn),
423 423 dis_section_size(scn));
424 424 break;
425 425 case DIS_TEXT:
426 426 dis_data(ca->ca_tgt, ca->ca_handle, dis_section_addr(scn),
427 427 dis_section_data(scn), dis_section_size(scn));
428 428 break;
429 429 }
430 430 }
431 431
432 432 /*
433 433 * Disassemble a function explicitly specified with '-F'. The 'type' argument
434 434 * is unused.
435 435 */
436 436 /* ARGSUSED */
437 437 void
438 438 dis_named_function(dis_func_t *func, int type, void *data)
439 439 {
440 440 callback_arg_t *ca = data;
441 441
442 442 dis_data(ca->ca_tgt, ca->ca_handle, dis_function_addr(func),
443 443 dis_function_data(func), dis_function_size(func));
444 444 }
445 445
446 446 /*
447 447 * Disassemble a complete file. First, we determine the type of the file based
448 448 * on the ELF machine type, and instantiate a version of the disassembler
449 449 * appropriate for the file. We then resolve any named sections or functions
450 450 * against the file, and iterate over the results (or all sections if no flags
451 451 * were specified).
452 452 */
453 453 void
454 454 dis_file(const char *filename)
455 455 {
456 456 dis_tgt_t *tgt, *current;
457 457 dis_scnlist_t *sections;
458 458 dis_funclist_t *functions;
459 459 dis_handle_t *dhp;
460 460 GElf_Ehdr ehdr;
461 461
462 462 /*
463 463 * First, initialize the target
464 464 */
465 465 if ((tgt = dis_tgt_create(filename)) == NULL)
466 466 return;
467 467
468 468 if (!g_quiet)
469 469 (void) printf("disassembly for %s\n\n", filename);
470 470
471 471 /*
472 472 * A given file may contain multiple targets (if it is an archive, for
473 473 * example). We iterate over all possible targets if this is the case.
474 474 */
475 475 for (current = tgt; current != NULL; current = dis_tgt_next(current)) {
476 476 dis_tgt_ehdr(current, &ehdr);
477 477
478 478 /*
479 479 * Eventually, this should probably live within libdisasm, and
480 480 * we should be able to disassemble targets from different
481 481 * architectures. For now, we only support objects as the
482 482 * native machine type.
483 483 */
484 484 switch (ehdr.e_machine) {
485 485 #ifdef __sparc
486 486 case EM_SPARC:
487 487 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
488 488 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
489 489 warn("invalid E_IDENT field for SPARC object");
490 490 return;
491 491 }
492 492 g_flags |= DIS_SPARC_V8;
493 493 break;
494 494
495 495 case EM_SPARC32PLUS:
496 496 {
497 497 uint64_t flags = ehdr.e_flags & EF_SPARC_32PLUS_MASK;
498 498
499 499 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
500 500 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
501 501 warn("invalid E_IDENT field for SPARC object");
502 502 return;
503 503 }
504 504
505 505 if (flags != 0 &&
506 506 (flags & (EF_SPARC_32PLUS | EF_SPARC_SUN_US1 |
507 507 EF_SPARC_SUN_US3)) != EF_SPARC_32PLUS)
508 508 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
509 509 else
510 510 g_flags |= DIS_SPARC_V9;
511 511 break;
512 512 }
513 513
514 514 case EM_SPARCV9:
515 515 if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
516 516 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
517 517 warn("invalid E_IDENT field for SPARC object");
518 518 return;
519 519 }
520 520
521 521 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
522 522 break;
523 523 #endif /* __sparc */
524 524
525 525 #if defined(__i386) || defined(__amd64)
526 526 case EM_386:
527 527 g_flags |= DIS_X86_SIZE32;
528 528 break;
529 529
530 530 case EM_AMD64:
531 531 g_flags |= DIS_X86_SIZE64;
532 532 break;
533 533 #endif /* __i386 || __amd64 */
534 534
535 535 default:
536 536 die("%s: unsupported ELF machine 0x%x", filename,
537 537 ehdr.e_machine);
538 538 }
539 539
540 540 /*
541 541 * If ET_REL (.o), printing immediate symbols is likely to
542 542 * result in garbage, as symbol lookups on unrelocated
543 543 * immediates find false and useless matches.
544 544 */
545 545
546 546 if (ehdr.e_type == ET_REL)
547 547 g_flags |= DIS_NOIMMSYM;
548 548
549 549 if (!g_quiet && dis_tgt_member(current) != NULL)
550 550 (void) printf("\narchive member %s\n",
551 551 dis_tgt_member(current));
552 552
553 553 /*
554 554 * Instantiate a libdisasm handle based on the file type.
555 555 */
556 556 if ((dhp = dis_handle_create(g_flags, current, do_lookup,
557 557 do_read)) == NULL)
558 558 die("%s: failed to initialize disassembler: %s",
559 559 filename, dis_strerror(dis_errno()));
560 560
561 561 if (g_doall) {
562 562 /*
563 563 * With no arguments, iterate over all sections and
564 564 * disassemble only those that contain text.
565 565 */
566 566 dis_tgt_section_iter(current, dis_text_section, dhp);
567 567 } else {
568 568 callback_arg_t ca;
569 569
570 570 ca.ca_tgt = current;
571 571 ca.ca_handle = dhp;
572 572
573 573 /*
574 574 * If sections or functions were explicitly specified,
575 575 * resolve those names against the object, and iterate
576 576 * over just the resulting data.
577 577 */
578 578 sections = dis_namelist_resolve_sections(g_seclist,
579 579 current);
580 580 functions = dis_namelist_resolve_functions(g_funclist,
581 581 current);
582 582
583 583 dis_scnlist_iter(sections, dis_named_section, &ca);
584 584 dis_funclist_iter(functions, dis_named_function, &ca);
585 585
586 586 dis_scnlist_destroy(sections);
587 587 dis_funclist_destroy(functions);
588 588 }
589 589
590 590 dis_handle_destroy(dhp);
591 591 }
592 592
593 593 dis_tgt_destroy(tgt);
594 594 }
595 595
596 596 void
597 597 usage(void)
598 598 {
599 599 (void) fprintf(stderr, "usage: dis [-CVoqn] [-d sec] \n");
600 600 (void) fprintf(stderr, "\t[-D sec] [-F function] [-t sec] file ..\n");
601 601 exit(2);
602 602 }
603 603
604 604 typedef struct lib_node {
605 605 char *path;
606 606 struct lib_node *next;
607 607 } lib_node_t;
608 608
609 609 int
610 610 main(int argc, char **argv)
611 611 {
612 612 int optchar;
613 613 int i;
614 614 lib_node_t *libs = NULL;
615 615
616 616 g_funclist = dis_namelist_create();
617 617 g_seclist = dis_namelist_create();
618 618
619 619 while ((optchar = getopt(argc, argv, "Cd:D:F:l:Lot:Vqn")) != -1) {
620 620 switch (optchar) {
621 621 case 'C':
622 622 g_demangle = 1;
623 623 break;
624 624 case 'd':
625 625 dis_namelist_add(g_seclist, optarg, DIS_DATA_RELATIVE);
626 626 break;
627 627 case 'D':
628 628 dis_namelist_add(g_seclist, optarg, DIS_DATA_ABSOLUTE);
629 629 break;
630 630 case 'F':
631 631 dis_namelist_add(g_funclist, optarg, 0);
632 632 break;
633 633 case 'l': {
634 634 /*
635 635 * The '-l foo' option historically would attempt to
636 636 * disassemble '$LIBDIR/libfoo.a'. The $LIBDIR
637 637 * environment variable has never been supported or
638 638 * documented for our linker. However, until this
639 639 * option is formally EOLed, we have to support it.
640 640 */
641 641 char *dir;
642 642 lib_node_t *node;
643 643 size_t len;
644 644
645 645 if ((dir = getenv("LIBDIR")) == NULL ||
646 646 dir[0] == '\0')
647 647 dir = "/usr/lib";
648 648 node = safe_malloc(sizeof (lib_node_t));
649 649 len = strlen(optarg) + strlen(dir) + sizeof ("/lib.a");
650 650 node->path = safe_malloc(len);
651 651
652 652 (void) snprintf(node->path, len, "%s/lib%s.a", dir,
653 653 optarg);
654 654 node->next = libs;
655 655 libs = node;
656 656 break;
657 657 }
658 658 case 'L':
659 659 /*
660 660 * The '-L' option historically would attempt to read
661 661 * the .debug section of the target to determine source
662 662 * line information in order to annotate the output.
663 663 * No compiler has emitted these sections in many years,
664 664 * and the option has never done what it purported to
665 665 * do. We silently consume the option for
666 666 * compatibility.
667 667 */
668 668 break;
669 669 case 'n':
670 670 g_numeric = 1;
671 671 break;
672 672 case 'o':
673 673 g_flags |= DIS_OCTAL;
674 674 break;
675 675 case 'q':
676 676 g_quiet = 1;
677 677 break;
678 678 case 't':
679 679 dis_namelist_add(g_seclist, optarg, DIS_TEXT);
680 680 break;
681 681 case 'V':
682 682 (void) printf("Solaris disassembler version 1.0\n");
683 683 return (0);
684 684 default:
685 685 usage();
686 686 break;
687 687 }
688 688 }
689 689
690 690 argc -= optind;
691 691 argv += optind;
692 692
693 693 if (argc == 0 && libs == NULL) {
694 694 warn("no objects specified");
695 695 usage();
696 696 }
697 697
698 698 if (dis_namelist_empty(g_funclist) && dis_namelist_empty(g_seclist))
699 699 g_doall = 1;
700 700
701 701 /*
702 702 * See comment for 'l' option, above.
703 703 */
704 704 while (libs != NULL) {
705 705 lib_node_t *node = libs->next;
706 706
707 707 dis_file(libs->path);
708 708 free(libs->path);
709 709 free(libs);
710 710 libs = node;
711 711 }
712 712
713 713 for (i = 0; i < argc; i++)
714 714 dis_file(argv[i]);
715 715
716 716 dis_namelist_destroy(g_funclist);
717 717 dis_namelist_destroy(g_seclist);
718 718
719 719 return (g_error);
720 720 }
↓ open down ↓ |
594 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX