/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OP(x) ((unsigned)(0x3 & x) << 30) /* general opcode */ #define OP2(x) ((0x7 & x) << 22) /* op2 opcode */ #define OP3(x) ((0x3f & x) << 19) /* op3 opcode */ #define OPMSK 0xC0000000 #define OP2MSK 0x01C00000 #define OP3MSK 0x01F80000 #define MAXEXCLUDES 5 typedef struct mask { uint32_t m_mask; uint32_t m_val; const char *m_name; } mask_t; static const mask_t masks[] = { { OPMSK|OP2MSK, OP(0) | OP2(5), "FBPfcc" }, { OPMSK|OP2MSK, OP(0) | OP2(6), "FBfcc" }, { OPMSK|OP3MSK, OP(2) | OP3(0x34), "FPop1" }, { OPMSK|OP3MSK, OP(2) | OP3(0x35), "FPop2" }, { OPMSK|OP3(0x38), OP(3) | OP3(0x20), "FPldst1" }, { OPMSK|OP3(0x38), OP(3) | OP3(0x30), "FPldst2" } }; const char *progname; static void usage(void) { (void) fprintf(stderr, "Usage: %s infile\n", progname); exit(2); } int main(int argc, char **argv) { Elf *elf; Elf_Scn *scn; GElf_Shdr shdr; Elf_Data *text; uint32_t *instrs; char *excludes[MAXEXCLUDES]; int fd, textidx, i, j, c; int shownames = 1; int nexcludes = 0; int found = 0; char *filename; progname = basename(argv[0]); while ((c = getopt(argc, argv, ":nx:")) != EOF) { switch (c) { case 'n': shownames = 0; break; case 'x': if (nexcludes == MAXEXCLUDES - 1) die("exclusion limit is %d", MAXEXCLUDES); excludes[nexcludes++] = optarg; break; default: usage(); } } if (argc - optind != 1) usage(); filename = argv[optind]; if ((fd = open(filename, O_RDONLY)) < 0) die("failed to open %s", filename); (void) elf_version(EV_CURRENT); if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) elfdie("failed to open %s as ELF", filename); if ((textidx = findelfsecidx(elf, ".text")) < 0) die("failed to find .text section in %s\n", filename); if ((scn = elf_getscn(elf, textidx)) == NULL || gelf_getshdr(scn, &shdr) == NULL || (text = elf_rawdata(scn, NULL)) == NULL) elfdie("failed to read .text"); instrs = text->d_buf; for (i = 0; i < shdr.sh_size / 4; i++) { for (j = 0; j < sizeof (masks) / sizeof (mask_t); j++) { char *symname = NULL; offset_t off; int len = 35; int xcl; if ((instrs[i] & masks[j].m_mask) != masks[j].m_val) continue; if (findelfsym(elf, i * 4, &symname, &off)) { if (nexcludes > 0) { for (xcl = 0; xcl < nexcludes; xcl++) { if (strcmp(symname, excludes[xcl]) == 0) break; } if (xcl < nexcludes) continue; /* exclude matched */ } } found++; if (!shownames || symname == NULL) { (void) printf("%-*x", len, i * 4); } else { len -= printf("%s+%llx", symname, off); (void) printf("%*s", (len > 0 ? len : 0), ""); } (void) printf(" %08x %s\n", instrs[i], masks[j].m_name); } } (void) elf_end(elf); (void) close(fd); return (found > 0); }