11545Seschrock /* 21545Seschrock * CDDL HEADER START 31545Seschrock * 41545Seschrock * The contents of this file are subject to the terms of the 51545Seschrock * Common Development and Distribution License (the "License"). 61545Seschrock * You may not use this file except in compliance with the License. 71545Seschrock * 81545Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91545Seschrock * or http://www.opensolaris.org/os/licensing. 101545Seschrock * See the License for the specific language governing permissions 111545Seschrock * and limitations under the License. 121545Seschrock * 131545Seschrock * When distributing Covered Code, include this CDDL HEADER in each 141545Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151545Seschrock * If applicable, add the following below this CDDL HEADER, with the 161545Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 171545Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 181545Seschrock * 191545Seschrock * CDDL HEADER END 201545Seschrock */ 211545Seschrock 221545Seschrock /* 231545Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241545Seschrock * Use is subject to license terms. 251545Seschrock */ 261545Seschrock 271545Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 281545Seschrock 291545Seschrock #include <ctype.h> 301545Seschrock #include <getopt.h> 311545Seschrock #include <stdio.h> 321545Seschrock #include <stdlib.h> 331545Seschrock #include <string.h> 341545Seschrock #include <sys/sysmacros.h> 351545Seschrock #include <sys/elf_SPARC.h> 361545Seschrock 371545Seschrock #include <libdisasm.h> 381545Seschrock 391545Seschrock #include "dis_target.h" 401545Seschrock #include "dis_util.h" 411545Seschrock #include "dis_list.h" 421545Seschrock 431545Seschrock int g_demangle; /* Demangle C++ names */ 441545Seschrock int g_quiet; /* Quiet mode */ 451545Seschrock int g_numeric; /* Numeric mode */ 461545Seschrock int g_flags; /* libdisasm language flags */ 471545Seschrock int g_doall; /* true if no functions or sections were given */ 481545Seschrock 491545Seschrock dis_namelist_t *g_funclist; /* list of functions to disassemble, if any */ 501545Seschrock dis_namelist_t *g_seclist; /* list of sections to disassemble, if any */ 511545Seschrock 521545Seschrock /* 531545Seschrock * Section options for -d, -D, and -s 541545Seschrock */ 551545Seschrock #define DIS_DATA_RELATIVE 1 561545Seschrock #define DIS_DATA_ABSOLUTE 2 571545Seschrock #define DIS_TEXT 3 581545Seschrock 591545Seschrock /* 601545Seschrock * libdisasm callback data. Keeps track of current data (function or section) 611545Seschrock * and offset within that data. 621545Seschrock */ 631545Seschrock typedef struct dis_buffer { 641545Seschrock dis_tgt_t *db_tgt; /* current dis target */ 651545Seschrock void *db_data; /* function or section data */ 661545Seschrock uint64_t db_addr; /* address of function start */ 671545Seschrock size_t db_size; /* size of data */ 681545Seschrock uint64_t db_nextaddr; /* next address to be read */ 691545Seschrock } dis_buffer_t; 701545Seschrock 711545Seschrock #define MINSYMWIDTH 22 /* Minimum width of symbol portion of line */ 721545Seschrock 731545Seschrock /* 741545Seschrock * Given a symbol+offset as returned by dis_tgt_lookup(), print an appropriately 751545Seschrock * formatted symbol, based on the offset and current setttings. 761545Seschrock */ 771545Seschrock void 781545Seschrock getsymname(uint64_t addr, const char *symbol, off_t offset, char *buf, 791545Seschrock size_t buflen) 801545Seschrock { 81*2089Sdmick if (symbol == NULL || g_numeric) { 82*2089Sdmick if (g_flags & DIS_OCTAL) 83*2089Sdmick (void) snprintf(buf, buflen, "0%llo", addr); 84*2089Sdmick else 85*2089Sdmick (void) snprintf(buf, buflen, "0x%llx", addr); 86*2089Sdmick } else { 871545Seschrock if (g_demangle) 881545Seschrock symbol = dis_demangle(symbol); 891545Seschrock 901545Seschrock if (offset == 0) 911545Seschrock (void) snprintf(buf, buflen, "%s", symbol); 921545Seschrock else if (g_flags & DIS_OCTAL) 931545Seschrock (void) snprintf(buf, buflen, "%s+0%o", symbol, offset); 941545Seschrock else 951545Seschrock (void) snprintf(buf, buflen, "%s+0x%x", symbol, offset); 961545Seschrock } 971545Seschrock } 981545Seschrock 991545Seschrock /* 1001545Seschrock * The main disassembly routine. Given a fixed-sized buffer and starting 1011545Seschrock * address, disassemble the data using the supplied target and libdisasm handle. 1021545Seschrock */ 1031545Seschrock void 1041545Seschrock dis_data(dis_tgt_t *tgt, dis_handle_t *dhp, uint64_t addr, void *data, 1051545Seschrock size_t datalen) 1061545Seschrock { 1071545Seschrock dis_buffer_t db = { 0 }; 1081545Seschrock char buf[BUFSIZE]; 1091545Seschrock char symbuf[BUFSIZE]; 1101545Seschrock const char *symbol; 1111545Seschrock off_t symoffset; 1121545Seschrock int i; 1131545Seschrock int bytesperline; 1141545Seschrock size_t symsize; 1151545Seschrock int isfunc; 1161545Seschrock size_t symwidth = 0; 1171545Seschrock 1181545Seschrock db.db_tgt = tgt; 1191545Seschrock db.db_data = data; 1201545Seschrock db.db_addr = addr; 1211545Seschrock db.db_size = datalen; 1221545Seschrock 1231545Seschrock dis_set_data(dhp, &db); 1241545Seschrock 1251545Seschrock if ((bytesperline = dis_max_instrlen(dhp)) > 6) 1261545Seschrock bytesperline = 6; 1271545Seschrock 1281545Seschrock while (addr < db.db_addr + db.db_size) { 1291545Seschrock 1301545Seschrock if (dis_disassemble(dhp, addr, buf, BUFSIZE) != 0) { 1311545Seschrock /* 1321545Seschrock * If we encounter an invalid opcode, we just 1331545Seschrock * print "*** invalid opcode ***" at that first bad 1341545Seschrock * instruction and continue with printing the rest 1351545Seschrock * of the instruction stream as hex data, 1361545Seschrock * We then find the next valid symbol in the section, 1371545Seschrock * and disassemble from there. 1381545Seschrock */ 1391545Seschrock off_t next; 1401545Seschrock 1411545Seschrock (void) snprintf(buf, sizeof (buf), 1421545Seschrock "*** invalid opcode ***"); 1431545Seschrock 1441545Seschrock if ((next = dis_tgt_next_symbol(tgt, addr)) == 0) { 1451545Seschrock db.db_nextaddr = db.db_addr + db.db_size; 1461545Seschrock } else { 1471545Seschrock if (next > db.db_size) 1481545Seschrock db.db_nextaddr = db.db_addr + 1491545Seschrock db.db_size; 1501545Seschrock else 1511545Seschrock db.db_nextaddr = addr + next; 1521545Seschrock } 1531545Seschrock } 1541545Seschrock 1551545Seschrock /* 1561545Seschrock * Print out the line as: 1571545Seschrock * 1581545Seschrock * address: bytes text 1591545Seschrock * 1601545Seschrock * If there are more than 6 bytes in any given instruction, 1611545Seschrock * spread the bytes across two lines. We try to get symbolic 1621545Seschrock * information for the address, but if that fails we print out 1631545Seschrock * the numeric address instead. 1641545Seschrock * 1651545Seschrock * We try to keep the address portion of the text aligned at 1661545Seschrock * MINSYMWIDTH characters. If we are disassembling a function 1671545Seschrock * with a long name, this can be annoying. So we pick a width 1681545Seschrock * based on the maximum width that the current symbol can be. 1691545Seschrock * This at least produces text aligned within each function. 1701545Seschrock */ 1711545Seschrock symbol = dis_tgt_lookup(tgt, addr, &symoffset, 1, &symsize, 1721545Seschrock &isfunc); 1731545Seschrock /* Get the maximum length for this symbol */ 1741545Seschrock getsymname(addr, symbol, symsize, symbuf, sizeof (symbuf)); 1751545Seschrock symwidth = MAX(strlen(symbuf), MINSYMWIDTH); 1761545Seschrock 1771545Seschrock getsymname(addr, symbol, symoffset, symbuf, sizeof (symbuf)); 1781545Seschrock 1791545Seschrock /* 1801545Seschrock * If we've crossed a new function boundary, print out the 1811545Seschrock * function name on a blank line. 1821545Seschrock */ 1831545Seschrock if (!g_quiet && symoffset == 0 && symbol != NULL && isfunc) 1841545Seschrock (void) printf("%s()\n", symbol); 1851545Seschrock 1861545Seschrock (void) printf(" %s:%*s ", symbuf, 1871545Seschrock symwidth - strlen(symbuf), ""); 1881545Seschrock 1891545Seschrock /* print bytes */ 1901545Seschrock for (i = 0; i < MIN(bytesperline, (db.db_nextaddr - addr)); 1911545Seschrock i++) { 1921545Seschrock int byte = *((uchar_t *)data + (addr - db.db_addr) + i); 1931545Seschrock if (g_flags & DIS_OCTAL) 1941545Seschrock (void) printf("%03o ", byte); 1951545Seschrock else 1961545Seschrock (void) printf("%02x ", byte); 1971545Seschrock } 1981545Seschrock 1991545Seschrock /* trailing spaces for missing bytes */ 2001545Seschrock for (; i < bytesperline; i++) { 2011545Seschrock if (g_flags & DIS_OCTAL) 2021545Seschrock (void) printf(" "); 2031545Seschrock else 2041545Seschrock (void) printf(" "); 2051545Seschrock } 2061545Seschrock 2071545Seschrock /* contents of disassembly */ 2081545Seschrock (void) printf(" %s", buf); 2091545Seschrock 2101545Seschrock /* excess bytes that spill over onto subsequent lines */ 2111545Seschrock for (; i < db.db_nextaddr - addr; i++) { 2121545Seschrock int byte = *((uchar_t *)data + (addr - db.db_addr) + i); 2131545Seschrock if (i % bytesperline == 0) 2141545Seschrock (void) printf("\n %*s ", symwidth, ""); 2151545Seschrock if (g_flags & DIS_OCTAL) 2161545Seschrock (void) printf("%03o ", byte); 2171545Seschrock else 2181545Seschrock (void) printf("%02x ", byte); 2191545Seschrock } 2201545Seschrock 2211545Seschrock (void) printf("\n"); 2221545Seschrock 2231545Seschrock addr = db.db_nextaddr; 2241545Seschrock } 2251545Seschrock } 2261545Seschrock 2271545Seschrock /* 2281545Seschrock * libdisasm wrapper around symbol lookup. Invoke the target-specific lookup 2291545Seschrock * function, and convert the result using getsymname(). 2301545Seschrock */ 2311545Seschrock int 2321545Seschrock do_lookup(void *data, uint64_t addr, char *buf, size_t buflen, uint64_t *start, 2331545Seschrock size_t *symlen) 2341545Seschrock { 2351545Seschrock dis_buffer_t *db = data; 2361545Seschrock const char *symbol; 2371545Seschrock off_t offset; 2381545Seschrock size_t size; 2391545Seschrock 2401545Seschrock /* 2411545Seschrock * If NULL symbol is returned, getsymname takes care of 2421545Seschrock * printing appropriate address in buf instead of symbol. 2431545Seschrock */ 2441545Seschrock symbol = dis_tgt_lookup(db->db_tgt, addr, &offset, 0, &size, NULL); 2451545Seschrock 2461545Seschrock if (buf != NULL) 2471545Seschrock getsymname(addr, symbol, offset, buf, buflen); 2481545Seschrock 2491545Seschrock if (start != NULL) 2501545Seschrock *start = addr - offset; 2511545Seschrock if (symlen != NULL) 2521545Seschrock *symlen = size; 2531545Seschrock 254*2089Sdmick if (symbol == NULL) 255*2089Sdmick return (-1); 256*2089Sdmick 2571545Seschrock return (0); 2581545Seschrock } 2591545Seschrock 2601545Seschrock /* 2611545Seschrock * libdisasm wrapper around target reading. libdisasm will always read data 2621545Seschrock * in order, so update our current offset within the buffer appropriately. 2631545Seschrock * We only support reading from within the current object; libdisasm should 2641545Seschrock * never ask us to do otherwise. 2651545Seschrock */ 2661545Seschrock int 2671545Seschrock do_read(void *data, uint64_t addr, void *buf, size_t len) 2681545Seschrock { 2691545Seschrock dis_buffer_t *db = data; 2701545Seschrock size_t offset; 2711545Seschrock 2721545Seschrock if (addr < db->db_addr || addr >= db->db_addr + db->db_size) 2731545Seschrock return (-1); 2741545Seschrock 2751545Seschrock offset = addr - db->db_addr; 2761545Seschrock len = MIN(len, db->db_size - offset); 2771545Seschrock 2781545Seschrock (void) memcpy(buf, (char *)db->db_data + offset, len); 2791545Seschrock 2801545Seschrock db->db_nextaddr = addr + len; 2811545Seschrock 2821545Seschrock return (len); 2831545Seschrock } 2841545Seschrock 2851545Seschrock /* 2861545Seschrock * Routine to dump raw data in a human-readable format. Used by the -d and -D 2871545Seschrock * options. We model our output after the xxd(1) program, which gives nicely 2881545Seschrock * formatted output, along with an ASCII translation of the result. 2891545Seschrock */ 2901545Seschrock void 2911545Seschrock dump_data(uint64_t addr, void *data, size_t datalen) 2921545Seschrock { 2931545Seschrock uintptr_t curaddr = addr & (~0xf); 2941545Seschrock uint8_t *bytes = data; 2951545Seschrock int i; 2961545Seschrock int width; 2971545Seschrock 2981545Seschrock /* 2991545Seschrock * Determine if the address given to us fits in 32-bit range, in which 3001545Seschrock * case use a 4-byte width. 3011545Seschrock */ 3021545Seschrock if (((addr + datalen) & 0xffffffff00000000ULL) == 0ULL) 3031545Seschrock width = 8; 3041545Seschrock else 3051545Seschrock width = 16; 3061545Seschrock 3071545Seschrock while (curaddr < addr + datalen) { 3081545Seschrock /* 3091545Seschrock * Display leading address 3101545Seschrock */ 3111545Seschrock (void) printf("%0*x: ", width, curaddr); 3121545Seschrock 3131545Seschrock /* 3141545Seschrock * Print out data in two-byte chunks. If the current address 3151545Seschrock * is before the starting address or after the end of the 3161545Seschrock * section, print spaces. 3171545Seschrock */ 3181545Seschrock for (i = 0; i < 16; i++) { 3191545Seschrock if (curaddr + i < addr ||curaddr + i >= addr + datalen) 3201545Seschrock (void) printf(" "); 3211545Seschrock else 3221545Seschrock (void) printf("%02x", 3231545Seschrock bytes[curaddr + i - addr]); 3241545Seschrock 3251545Seschrock if (i & 1) 3261545Seschrock (void) printf(" "); 3271545Seschrock } 3281545Seschrock 3291545Seschrock (void) printf(" "); 3301545Seschrock 3311545Seschrock /* 3321545Seschrock * Print out the ASCII representation 3331545Seschrock */ 3341545Seschrock for (i = 0; i < 16; i++) { 3351545Seschrock if (curaddr + i < addr || 3361545Seschrock curaddr + i >= addr + datalen) { 3371545Seschrock (void) printf(" "); 3381545Seschrock } else { 3391545Seschrock uint8_t byte = bytes[curaddr + i - addr]; 3401545Seschrock if (isprint(byte)) 3411545Seschrock (void) printf("%c", byte); 3421545Seschrock else 3431545Seschrock (void) printf("."); 3441545Seschrock } 3451545Seschrock } 3461545Seschrock 3471545Seschrock (void) printf("\n"); 3481545Seschrock 3491545Seschrock curaddr += 16; 3501545Seschrock } 3511545Seschrock } 3521545Seschrock 3531545Seschrock /* 3541545Seschrock * Disassemble a section implicitly specified as part of a file. This function 3551545Seschrock * is called for all sections when no other flags are specified. We ignore any 3561545Seschrock * data sections, and print out only those sections containing text. 3571545Seschrock */ 3581545Seschrock void 3591545Seschrock dis_text_section(dis_tgt_t *tgt, dis_scn_t *scn, void *data) 3601545Seschrock { 3611545Seschrock dis_handle_t *dhp = data; 3621545Seschrock 3631545Seschrock /* ignore data sections */ 3641545Seschrock if (!dis_section_istext(scn)) 3651545Seschrock return; 3661545Seschrock 3671545Seschrock if (!g_quiet) 3681545Seschrock (void) printf("\nsection %s\n", dis_section_name(scn)); 3691545Seschrock 3701545Seschrock dis_data(tgt, dhp, dis_section_addr(scn), dis_section_data(scn), 3711545Seschrock dis_section_size(scn)); 3721545Seschrock } 3731545Seschrock 3741545Seschrock /* 3751545Seschrock * Structure passed to dis_named_{section,function} which keeps track of both 3761545Seschrock * the target and the libdisasm handle. 3771545Seschrock */ 3781545Seschrock typedef struct callback_arg { 3791545Seschrock dis_tgt_t *ca_tgt; 3801545Seschrock dis_handle_t *ca_handle; 3811545Seschrock } callback_arg_t; 3821545Seschrock 3831545Seschrock /* 3841545Seschrock * Disassemble a section explicitly named with -s, -d, or -D. The 'type' 3851545Seschrock * argument contains the type of argument given. Pass the data onto the 3861545Seschrock * appropriate helper routine. 3871545Seschrock */ 3881545Seschrock void 3891545Seschrock dis_named_section(dis_scn_t *scn, int type, void *data) 3901545Seschrock { 3911545Seschrock callback_arg_t *ca = data; 3921545Seschrock 3931545Seschrock if (!g_quiet) 3941545Seschrock (void) printf("\nsection %s\n", dis_section_name(scn)); 3951545Seschrock 3961545Seschrock switch (type) { 3971545Seschrock case DIS_DATA_RELATIVE: 3981545Seschrock dump_data(0, dis_section_data(scn), dis_section_size(scn)); 3991545Seschrock break; 4001545Seschrock case DIS_DATA_ABSOLUTE: 4011545Seschrock dump_data(dis_section_addr(scn), dis_section_data(scn), 4021545Seschrock dis_section_size(scn)); 4031545Seschrock break; 4041545Seschrock case DIS_TEXT: 4051545Seschrock dis_data(ca->ca_tgt, ca->ca_handle, dis_section_addr(scn), 4061545Seschrock dis_section_data(scn), dis_section_size(scn)); 4071545Seschrock break; 4081545Seschrock } 4091545Seschrock } 4101545Seschrock 4111545Seschrock /* 4121545Seschrock * Disassemble a function explicitly specified with '-F'. The 'type' argument 4131545Seschrock * is unused. 4141545Seschrock */ 4151545Seschrock /* ARGSUSED */ 4161545Seschrock void 4171545Seschrock dis_named_function(dis_func_t *func, int type, void *data) 4181545Seschrock { 4191545Seschrock callback_arg_t *ca = data; 4201545Seschrock 4211545Seschrock dis_data(ca->ca_tgt, ca->ca_handle, dis_function_addr(func), 4221545Seschrock dis_function_data(func), dis_function_size(func)); 4231545Seschrock } 4241545Seschrock 4251545Seschrock /* 4261545Seschrock * Disassemble a complete file. First, we determine the type of the file based 4271545Seschrock * on the ELF machine type, and instantiate a version of the disassembler 4281545Seschrock * appropriate for the file. We then resolve any named sections or functions 4291545Seschrock * against the file, and iterate over the results (or all sections if no flags 4301545Seschrock * were specified). 4311545Seschrock */ 4321545Seschrock void 4331545Seschrock dis_file(const char *filename) 4341545Seschrock { 4351545Seschrock dis_tgt_t *tgt, *current; 4361545Seschrock dis_scnlist_t *sections; 4371545Seschrock dis_funclist_t *functions; 4381545Seschrock dis_handle_t *dhp; 4391545Seschrock GElf_Ehdr ehdr; 4401545Seschrock 4411545Seschrock /* 4421545Seschrock * First, initialize the target 4431545Seschrock */ 4441545Seschrock if ((tgt = dis_tgt_create(filename)) == NULL) 4451545Seschrock return; 4461545Seschrock 4471545Seschrock if (!g_quiet) 4481545Seschrock (void) printf("disassembly for %s\n\n", filename); 4491545Seschrock 4501545Seschrock /* 4511545Seschrock * A given file may contain multiple targets (if it is an archive, for 4521545Seschrock * example). We iterate over all possible targets if this is the case. 4531545Seschrock */ 4541545Seschrock for (current = tgt; current != NULL; current = dis_tgt_next(current)) { 4551545Seschrock dis_tgt_ehdr(current, &ehdr); 4561545Seschrock 4571545Seschrock /* 4581545Seschrock * Eventually, this should probably live within libdisasm, and 4591545Seschrock * we should be able to disassemble targets from different 4601545Seschrock * architectures. For now, we only support objects as the 4611545Seschrock * native machine type. 4621545Seschrock */ 4631545Seschrock switch (ehdr.e_machine) { 4641545Seschrock #ifdef __sparc 4651545Seschrock case EM_SPARC: 4661545Seschrock if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || 4671545Seschrock ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { 4681545Seschrock warn("invalid E_IDENT field for SPARC object"); 4691545Seschrock return; 4701545Seschrock } 4711545Seschrock g_flags |= DIS_SPARC_V8; 4721545Seschrock break; 4731545Seschrock 4741545Seschrock case EM_SPARC32PLUS: 4751545Seschrock if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || 4761545Seschrock ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { 4771545Seschrock warn("invalid E_IDENT field for SPARC object"); 4781545Seschrock return; 4791545Seschrock } 4801545Seschrock 4811545Seschrock switch (ehdr.e_flags & EF_SPARC_32PLUS_MASK) { 4821545Seschrock case (EF_SPARC_32PLUS | EF_SPARC_SUN_US1 | 4831545Seschrock EF_SPARC_SUN_US3): 4841545Seschrock case (EF_SPARC_32PLUS | EF_SPARC_SUN_US1): 4851545Seschrock g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI; 4861545Seschrock default: 4871545Seschrock g_flags |= DIS_SPARC_V9; 4881545Seschrock } 4891545Seschrock break; 4901545Seschrock 4911545Seschrock case EM_SPARCV9: 4921545Seschrock if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 || 4931545Seschrock ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { 4941545Seschrock warn("invalid E_IDENT field for SPARC object"); 4951545Seschrock return; 4961545Seschrock } 4971545Seschrock 4981545Seschrock g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI; 4991545Seschrock break; 5001545Seschrock #endif /* __sparc */ 5011545Seschrock 5021545Seschrock #if defined(__i386) || defined(__amd64) 5031545Seschrock case EM_386: 5041545Seschrock g_flags |= DIS_X86_SIZE32; 5051545Seschrock break; 5061545Seschrock 5071545Seschrock case EM_AMD64: 5081545Seschrock g_flags |= DIS_X86_SIZE64; 5091545Seschrock break; 5101545Seschrock #endif /* __i386 || __amd64 */ 5111545Seschrock 5121545Seschrock default: 5131545Seschrock die("%s: unsupported ELF machine 0x%x", filename, 5141545Seschrock ehdr.e_machine); 5151545Seschrock } 5161545Seschrock 5171545Seschrock if (!g_quiet && dis_tgt_member(current) != NULL) 5181545Seschrock (void) printf("\narchive member %s\n", 5191545Seschrock dis_tgt_member(current)); 5201545Seschrock 5211545Seschrock /* 5221545Seschrock * Instantiate a libdisasm handle based on the file type. 5231545Seschrock */ 5241545Seschrock if ((dhp = dis_handle_create(g_flags, current, do_lookup, 5251545Seschrock do_read)) == NULL) 5261545Seschrock die("%s: failed to initialize disassembler: %s", 5271545Seschrock filename, dis_strerror(dis_errno())); 5281545Seschrock 5291545Seschrock if (g_doall) { 5301545Seschrock /* 5311545Seschrock * With no arguments, iterate over all sections and 5321545Seschrock * disassemble only those that contain text. 5331545Seschrock */ 5341545Seschrock dis_tgt_section_iter(current, dis_text_section, dhp); 5351545Seschrock } else { 5361545Seschrock callback_arg_t ca; 5371545Seschrock 5381545Seschrock ca.ca_tgt = current; 5391545Seschrock ca.ca_handle = dhp; 5401545Seschrock 5411545Seschrock /* 5421545Seschrock * If sections or functions were explicitly specified, 5431545Seschrock * resolve those names against the object, and iterate 5441545Seschrock * over just the resulting data. 5451545Seschrock */ 5461545Seschrock sections = dis_namelist_resolve_sections(g_seclist, 5471545Seschrock current); 5481545Seschrock functions = dis_namelist_resolve_functions(g_funclist, 5491545Seschrock current); 5501545Seschrock 5511545Seschrock dis_scnlist_iter(sections, dis_named_section, &ca); 5521545Seschrock dis_funclist_iter(functions, dis_named_function, &ca); 5531545Seschrock 5541545Seschrock dis_scnlist_destroy(sections); 5551545Seschrock dis_funclist_destroy(functions); 5561545Seschrock } 5571545Seschrock 5581545Seschrock dis_handle_destroy(dhp); 5591545Seschrock } 5601545Seschrock 5611545Seschrock dis_tgt_destroy(tgt); 5621545Seschrock } 5631545Seschrock 5641545Seschrock void 5651545Seschrock usage(void) 5661545Seschrock { 5671545Seschrock (void) fprintf(stderr, "usage: dis [-CVoqn] [-d sec] \n"); 5681545Seschrock (void) fprintf(stderr, "\t[-D sec] [-F function] [-t sec] file ..\n"); 5691545Seschrock exit(2); 5701545Seschrock } 5711545Seschrock 5721545Seschrock typedef struct lib_node { 5731545Seschrock char *path; 5741545Seschrock struct lib_node *next; 5751545Seschrock } lib_node_t; 5761545Seschrock 5771545Seschrock int 5781545Seschrock main(int argc, char **argv) 5791545Seschrock { 5801545Seschrock int optchar; 5811545Seschrock int i; 5821545Seschrock lib_node_t *libs = NULL; 5831545Seschrock 5841545Seschrock g_funclist = dis_namelist_create(); 5851545Seschrock g_seclist = dis_namelist_create(); 5861545Seschrock 5871545Seschrock while ((optchar = getopt(argc, argv, "Cd:D:F:l:Lot:Vqn")) != -1) { 5881545Seschrock switch (optchar) { 5891545Seschrock case 'C': 5901545Seschrock g_demangle = 1; 5911545Seschrock break; 5921545Seschrock case 'd': 5931545Seschrock dis_namelist_add(g_seclist, optarg, DIS_DATA_RELATIVE); 5941545Seschrock break; 5951545Seschrock case 'D': 5961545Seschrock dis_namelist_add(g_seclist, optarg, DIS_DATA_ABSOLUTE); 5971545Seschrock break; 5981545Seschrock case 'F': 5991545Seschrock dis_namelist_add(g_funclist, optarg, 0); 6001545Seschrock break; 6011545Seschrock case 'l': { 6021545Seschrock /* 6031545Seschrock * The '-l foo' option historically would attempt to 6041545Seschrock * disassemble '$LIBDIR/libfoo.a'. The $LIBDIR 6051545Seschrock * environment variable has never been supported or 6061545Seschrock * documented for our linker. However, until this 6071545Seschrock * option is formally EOLed, we have to support it. 6081545Seschrock */ 6091545Seschrock char *dir; 6101545Seschrock lib_node_t *node; 6111545Seschrock size_t len; 6121545Seschrock 6131545Seschrock if ((dir = getenv("LIBDIR")) == NULL || 6141545Seschrock dir[0] == '\0') 6151545Seschrock dir = "/usr/lib"; 6161545Seschrock node = safe_malloc(sizeof (lib_node_t)); 6171545Seschrock len = strlen(optarg) + strlen(dir) + sizeof ("/lib.a"); 6181545Seschrock node->path = safe_malloc(len); 6191545Seschrock 6201545Seschrock (void) snprintf(node->path, len, "%s/lib%s.a", dir, 6211545Seschrock optarg); 6221545Seschrock node->next = libs; 6231545Seschrock libs = node; 6241545Seschrock break; 6251545Seschrock } 6261545Seschrock case 'L': 6271545Seschrock /* 6281545Seschrock * The '-L' option historically would attempt to read 6291545Seschrock * the .debug section of the target to determine source 6301545Seschrock * line information in order to annotate the output. 6311545Seschrock * No compiler has emitted these sections in many years, 6321545Seschrock * and the option has never done what it purported to 6331545Seschrock * do. We silently consume the option for 6341545Seschrock * compatibility. 6351545Seschrock */ 6361545Seschrock break; 6371545Seschrock case 'n': 6381545Seschrock g_numeric = 1; 6391545Seschrock break; 6401545Seschrock case 'o': 6411545Seschrock g_flags |= DIS_OCTAL; 6421545Seschrock break; 6431545Seschrock case 'q': 6441545Seschrock g_quiet = 1; 6451545Seschrock break; 6461545Seschrock case 't': 6471545Seschrock dis_namelist_add(g_seclist, optarg, DIS_TEXT); 6481545Seschrock break; 6491545Seschrock case 'V': 6501545Seschrock (void) printf("Solaris disassembler version 1.0\n"); 6511545Seschrock return (0); 6521545Seschrock default: 6531545Seschrock usage(); 6541545Seschrock break; 6551545Seschrock } 6561545Seschrock } 6571545Seschrock 6581545Seschrock argc -= optind; 6591545Seschrock argv += optind; 6601545Seschrock 6611545Seschrock if (argc == 0 && libs == NULL) { 6621545Seschrock warn("no objects specified"); 6631545Seschrock usage(); 6641545Seschrock } 6651545Seschrock 6661545Seschrock if (dis_namelist_empty(g_funclist) && dis_namelist_empty(g_seclist)) 6671545Seschrock g_doall = 1; 6681545Seschrock 6691545Seschrock /* 6701545Seschrock * See comment for 'l' option, above. 6711545Seschrock */ 6721545Seschrock while (libs != NULL) { 6731545Seschrock lib_node_t *node = libs->next; 6741545Seschrock 6751545Seschrock dis_file(libs->path); 6761545Seschrock free(libs->path); 6771545Seschrock free(libs); 6781545Seschrock libs = node; 6791545Seschrock } 6801545Seschrock 6811545Seschrock for (i = 0; i < argc; i++) 6821545Seschrock dis_file(argv[i]); 6831545Seschrock 6841545Seschrock dis_namelist_destroy(g_funclist); 6851545Seschrock dis_namelist_destroy(g_seclist); 6861545Seschrock 6871545Seschrock return (g_error); 6881545Seschrock } 689