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