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