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