findfp.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <libgen.h>
#include <errno.h>
#include <libelf.h>
#include <gelf.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <findfp.h>
#include <util.h>
#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);
}