Print this page
3317 dis(1) should support cross-target disassembly


   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                 /*