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