7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2011 Jason King. All rights reserved.
27 */
28
29 #include <ctype.h>
30 #include <getopt.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/sysmacros.h>
35 #include <sys/elf_SPARC.h>
36
37 #include <libdisasm.h>
38
39 #include "dis_target.h"
40 #include "dis_util.h"
41 #include "dis_list.h"
42
43 int g_demangle; /* Demangle C++ names */
44 int g_quiet; /* Quiet mode */
45 int g_numeric; /* Numeric mode */
46 int g_flags; /* libdisasm language flags */
80 {
81 if (symbol == NULL || g_numeric) {
82 if (g_flags & DIS_OCTAL)
83 (void) snprintf(buf, buflen, "0%llo", addr);
84 else
85 (void) snprintf(buf, buflen, "0x%llx", addr);
86 } else {
87 if (g_demangle)
88 symbol = dis_demangle(symbol);
89
90 if (offset == 0)
91 (void) snprintf(buf, buflen, "%s", symbol);
92 else if (g_flags & DIS_OCTAL)
93 (void) snprintf(buf, buflen, "%s+0%o", symbol, offset);
94 else
95 (void) snprintf(buf, buflen, "%s+0x%x", symbol, offset);
96 }
97 }
98
99 /*
100 * The main disassembly routine. Given a fixed-sized buffer and starting
101 * address, disassemble the data using the supplied target and libdisasm handle.
102 */
103 void
104 dis_data(dis_tgt_t *tgt, dis_handle_t *dhp, uint64_t addr, void *data,
105 size_t datalen)
106 {
107 dis_buffer_t db = { 0 };
108 char buf[BUFSIZE];
109 char symbuf[BUFSIZE];
110 const char *symbol;
111 const char *last_symbol;
112 off_t symoffset;
113 int i;
114 int bytesperline;
115 size_t symsize;
116 int isfunc;
117 size_t symwidth = 0;
118
119 db.db_tgt = tgt;
120 db.db_data = data;
121 db.db_addr = addr;
122 db.db_size = datalen;
123
124 dis_set_data(dhp, &db);
125
126 if ((bytesperline = dis_max_instrlen(dhp)) > 6)
127 bytesperline = 6;
128
129 symbol = NULL;
130
131 while (addr < db.db_addr + db.db_size) {
132
133 if (dis_disassemble(dhp, addr, buf, BUFSIZE) != 0) {
134 #if defined(__sparc)
135 /*
136 * Since sparc instructions are fixed size, we
137 * always know the address of the next instruction
138 */
139 (void) snprintf(buf, sizeof (buf),
140 "*** invalid opcode ***");
141 db.db_nextaddr = addr + 4;
142
143 #else
144 off_t next;
145
146 (void) snprintf(buf, sizeof (buf),
147 "*** invalid opcode ***");
148
149 /*
150 * On architectures with variable sized instructions
151 * we have no way to figure out where the next
152 * instruction starts if we encounter an invalid
153 * instruction. Instead we print the rest of the
154 * instruction stream as hex until we reach the
155 * next valid symbol in the section.
156 */
157 if ((next = dis_tgt_next_symbol(tgt, addr)) == 0) {
158 db.db_nextaddr = db.db_addr + db.db_size;
159 } else {
160 if (next > db.db_size)
161 db.db_nextaddr = db.db_addr +
162 db.db_size;
163 else
164 db.db_nextaddr = addr + next;
165 }
166 #endif
167 }
168
169 /*
170 * Print out the line as:
171 *
172 * address: bytes text
173 *
174 * If there are more than 6 bytes in any given instruction,
175 * spread the bytes across two lines. We try to get symbolic
176 * information for the address, but if that fails we print out
177 * the numeric address instead.
178 *
179 * We try to keep the address portion of the text aligned at
180 * MINSYMWIDTH characters. If we are disassembling a function
181 * with a long name, this can be annoying. So we pick a width
182 * based on the maximum width that the current symbol can be.
183 * This at least produces text aligned within each function.
184 */
185 last_symbol = symbol;
186 symbol = dis_tgt_lookup(tgt, addr, &symoffset, 1, &symsize,
465 if ((tgt = dis_tgt_create(filename)) == NULL)
466 return;
467
468 if (!g_quiet)
469 (void) printf("disassembly for %s\n\n", filename);
470
471 /*
472 * A given file may contain multiple targets (if it is an archive, for
473 * example). We iterate over all possible targets if this is the case.
474 */
475 for (current = tgt; current != NULL; current = dis_tgt_next(current)) {
476 dis_tgt_ehdr(current, &ehdr);
477
478 /*
479 * Eventually, this should probably live within libdisasm, and
480 * we should be able to disassemble targets from different
481 * architectures. For now, we only support objects as the
482 * native machine type.
483 */
484 switch (ehdr.e_machine) {
485 #ifdef __sparc
486 case EM_SPARC:
487 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
488 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
489 warn("invalid E_IDENT field for SPARC object");
490 return;
491 }
492 g_flags |= DIS_SPARC_V8;
493 break;
494
495 case EM_SPARC32PLUS:
496 {
497 uint64_t flags = ehdr.e_flags & EF_SPARC_32PLUS_MASK;
498
499 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
500 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
501 warn("invalid E_IDENT field for SPARC object");
502 return;
503 }
504
505 if (flags != 0 &&
506 (flags & (EF_SPARC_32PLUS | EF_SPARC_SUN_US1 |
507 EF_SPARC_SUN_US3)) != EF_SPARC_32PLUS)
508 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
509 else
510 g_flags |= DIS_SPARC_V9;
511 break;
512 }
513
514 case EM_SPARCV9:
515 if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
516 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
517 warn("invalid E_IDENT field for SPARC object");
518 return;
519 }
520
521 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
522 break;
523 #endif /* __sparc */
524
525 #if defined(__i386) || defined(__amd64)
526 case EM_386:
527 g_flags |= DIS_X86_SIZE32;
528 break;
529
530 case EM_AMD64:
531 g_flags |= DIS_X86_SIZE64;
532 break;
533 #endif /* __i386 || __amd64 */
534
535 default:
536 die("%s: unsupported ELF machine 0x%x", filename,
537 ehdr.e_machine);
538 }
539
540 /*
541 * If ET_REL (.o), printing immediate symbols is likely to
542 * result in garbage, as symbol lookups on unrelocated
543 * immediates find false and useless matches.
544 */
545
546 if (ehdr.e_type == ET_REL)
547 g_flags |= DIS_NOIMMSYM;
548
549 if (!g_quiet && dis_tgt_member(current) != NULL)
550 (void) printf("\narchive member %s\n",
551 dis_tgt_member(current));
552
553 /*
|
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2011 Jason King. All rights reserved.
27 * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
28 */
29
30 #include <ctype.h>
31 #include <getopt.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/sysmacros.h>
36 #include <sys/elf_SPARC.h>
37
38 #include <libdisasm.h>
39
40 #include "dis_target.h"
41 #include "dis_util.h"
42 #include "dis_list.h"
43
44 int g_demangle; /* Demangle C++ names */
45 int g_quiet; /* Quiet mode */
46 int g_numeric; /* Numeric mode */
47 int g_flags; /* libdisasm language flags */
81 {
82 if (symbol == NULL || g_numeric) {
83 if (g_flags & DIS_OCTAL)
84 (void) snprintf(buf, buflen, "0%llo", addr);
85 else
86 (void) snprintf(buf, buflen, "0x%llx", addr);
87 } else {
88 if (g_demangle)
89 symbol = dis_demangle(symbol);
90
91 if (offset == 0)
92 (void) snprintf(buf, buflen, "%s", symbol);
93 else if (g_flags & DIS_OCTAL)
94 (void) snprintf(buf, buflen, "%s+0%o", symbol, offset);
95 else
96 (void) snprintf(buf, buflen, "%s+0x%x", symbol, offset);
97 }
98 }
99
100 /*
101 * Determine if we are on an architecture with fixed-size instructions,
102 * and if so, what size they are.
103 */
104 static int
105 insn_size(dis_handle_t *dhp)
106 {
107 int min = dis_min_instrlen(dhp);
108 int max = dis_max_instrlen(dhp);
109
110 if (min == max)
111 return (min);
112
113 return (0);
114 }
115
116 /*
117 * The main disassembly routine. Given a fixed-sized buffer and starting
118 * address, disassemble the data using the supplied target and libdisasm handle.
119 */
120 void
121 dis_data(dis_tgt_t *tgt, dis_handle_t *dhp, uint64_t addr, void *data,
122 size_t datalen)
123 {
124 dis_buffer_t db = { 0 };
125 char buf[BUFSIZE];
126 char symbuf[BUFSIZE];
127 const char *symbol;
128 const char *last_symbol;
129 off_t symoffset;
130 int i;
131 int bytesperline;
132 size_t symsize;
133 int isfunc;
134 size_t symwidth = 0;
135 int ret;
136 int insz = insn_size(dhp);
137
138 db.db_tgt = tgt;
139 db.db_data = data;
140 db.db_addr = addr;
141 db.db_size = datalen;
142
143 dis_set_data(dhp, &db);
144
145 if ((bytesperline = dis_max_instrlen(dhp)) > 6)
146 bytesperline = 6;
147
148 symbol = NULL;
149
150 while (addr < db.db_addr + db.db_size) {
151
152 ret = dis_disassemble(dhp, addr, buf, BUFSIZE);
153 if (ret != 0 && insz > 0) {
154 /*
155 * Since we know instructions are fixed size, we
156 * always know the address of the next instruction
157 */
158 (void) snprintf(buf, sizeof (buf),
159 "*** invalid opcode ***");
160 db.db_nextaddr = addr + insz;
161
162 } else if (ret != 0) {
163 off_t next;
164
165 (void) snprintf(buf, sizeof (buf),
166 "*** invalid opcode ***");
167
168 /*
169 * On architectures with variable sized instructions
170 * we have no way to figure out where the next
171 * instruction starts if we encounter an invalid
172 * instruction. Instead we print the rest of the
173 * instruction stream as hex until we reach the
174 * next valid symbol in the section.
175 */
176 if ((next = dis_tgt_next_symbol(tgt, addr)) == 0) {
177 db.db_nextaddr = db.db_addr + db.db_size;
178 } else {
179 if (next > db.db_size)
180 db.db_nextaddr = db.db_addr +
181 db.db_size;
182 else
183 db.db_nextaddr = addr + next;
184 }
185 }
186
187 /*
188 * Print out the line as:
189 *
190 * address: bytes text
191 *
192 * If there are more than 6 bytes in any given instruction,
193 * spread the bytes across two lines. We try to get symbolic
194 * information for the address, but if that fails we print out
195 * the numeric address instead.
196 *
197 * We try to keep the address portion of the text aligned at
198 * MINSYMWIDTH characters. If we are disassembling a function
199 * with a long name, this can be annoying. So we pick a width
200 * based on the maximum width that the current symbol can be.
201 * This at least produces text aligned within each function.
202 */
203 last_symbol = symbol;
204 symbol = dis_tgt_lookup(tgt, addr, &symoffset, 1, &symsize,
483 if ((tgt = dis_tgt_create(filename)) == NULL)
484 return;
485
486 if (!g_quiet)
487 (void) printf("disassembly for %s\n\n", filename);
488
489 /*
490 * A given file may contain multiple targets (if it is an archive, for
491 * example). We iterate over all possible targets if this is the case.
492 */
493 for (current = tgt; current != NULL; current = dis_tgt_next(current)) {
494 dis_tgt_ehdr(current, &ehdr);
495
496 /*
497 * Eventually, this should probably live within libdisasm, and
498 * we should be able to disassemble targets from different
499 * architectures. For now, we only support objects as the
500 * native machine type.
501 */
502 switch (ehdr.e_machine) {
503 case EM_SPARC:
504 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
505 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
506 warn("invalid E_IDENT field for SPARC object");
507 return;
508 }
509 g_flags |= DIS_SPARC_V8;
510 break;
511
512 case EM_SPARC32PLUS:
513 {
514 uint64_t flags = ehdr.e_flags & EF_SPARC_32PLUS_MASK;
515
516 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 ||
517 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
518 warn("invalid E_IDENT field for SPARC object");
519 return;
520 }
521
522 if (flags != 0 &&
523 (flags & (EF_SPARC_32PLUS | EF_SPARC_SUN_US1 |
524 EF_SPARC_SUN_US3)) != EF_SPARC_32PLUS)
525 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
526 else
527 g_flags |= DIS_SPARC_V9;
528 break;
529 }
530
531 case EM_SPARCV9:
532 if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
533 ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
534 warn("invalid E_IDENT field for SPARC object");
535 return;
536 }
537
538 g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI;
539 break;
540
541 case EM_386:
542 g_flags |= DIS_X86_SIZE32;
543 break;
544
545 case EM_AMD64:
546 g_flags |= DIS_X86_SIZE64;
547 break;
548
549 default:
550 die("%s: unsupported ELF machine 0x%x", filename,
551 ehdr.e_machine);
552 }
553
554 /*
555 * If ET_REL (.o), printing immediate symbols is likely to
556 * result in garbage, as symbol lookups on unrelocated
557 * immediates find false and useless matches.
558 */
559
560 if (ehdr.e_type == ET_REL)
561 g_flags |= DIS_NOIMMSYM;
562
563 if (!g_quiet && dis_tgt_member(current) != NULL)
564 (void) printf("\narchive member %s\n",
565 dis_tgt_member(current));
566
567 /*
|