1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 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 (c) 2011, Joyent, Inc. All rights reserved. 24 * Copyright (c) 2011, Robert Mustacchi, Inc. All rights reserved. 25 * Copyright 2013, Richard Lowe. 26 */ 27 28 #include <err.h> 29 #include <fcntl.h> 30 #include <gelf.h> 31 #include <libctf.h> 32 #include <saveargs.h> 33 #include <stdarg.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <unistd.h> 38 39 extern const char *__progname; 40 41 typedef struct symtab_sym { 42 GElf_Sym ss_sym; 43 char *ss_name; 44 ctf_funcinfo_t ss_finfo; 45 uint8_t *ss_data; 46 size_t ss_size; 47 } symtab_sym_t; 48 49 static void 50 walk_symtab(Elf *elf, char *fname, ctf_file_t *fp, 51 void (*callback)(ctf_file_t *, symtab_sym_t *)) 52 { 53 Elf_Scn *stab = NULL; 54 Elf_Scn *text = NULL; 55 Elf_Data *stabdata = NULL; 56 Elf_Data *textdata = NULL; 57 GElf_Ehdr ehdr; 58 GElf_Shdr stabshdr; 59 GElf_Shdr textshdr; 60 int foundtext = 0, foundstab = 0; 61 symtab_sym_t ss; 62 63 if ((gelf_getehdr(elf, &ehdr)) == NULL) 64 errx(1, "could not read ELF header from %s\n", 65 fname); 66 67 while ((stab = elf_nextscn(elf, stab)) != NULL) { 68 (void) gelf_getshdr(stab, &stabshdr); 69 70 if (stabshdr.sh_type == SHT_SYMTAB) { 71 foundstab = 1; 72 break; 73 } 74 } 75 76 while ((text = elf_nextscn(elf, text)) != NULL) { 77 (void) gelf_getshdr(text, &textshdr); 78 79 if (strcmp(".text", elf_strptr(elf, 80 ehdr.e_shstrndx, (size_t)textshdr.sh_name)) == 0) { 81 foundtext = 1; 82 break; 83 } 84 } 85 86 if (!foundstab || !foundtext) 87 return; 88 89 stabdata = elf_getdata(stab, NULL); 90 textdata = elf_rawdata(text, NULL); 91 for (unsigned symdx = 0; 92 symdx < (stabshdr.sh_size / stabshdr.sh_entsize); 93 symdx++) { 94 (void) gelf_getsym(stabdata, symdx, &ss.ss_sym); 95 96 if ((GELF_ST_TYPE(ss.ss_sym.st_info) != STT_FUNC) || 97 (ss.ss_sym.st_shndx == SHN_UNDEF)) 98 continue; 99 100 ss.ss_name = elf_strptr(elf, stabshdr.sh_link, 101 ss.ss_sym.st_name); 102 ss.ss_data = ((uint8_t *)(textdata->d_buf)) + 103 (ss.ss_sym.st_value - textshdr.sh_addr); 104 105 if (ctf_func_info(fp, symdx, &ss.ss_finfo) == CTF_ERR) { 106 fprintf(stderr, "failed to get funcinfo for: %s\n", 107 ss.ss_name); 108 continue; 109 } 110 111 (void) callback(fp, &ss); 112 } 113 } 114 115 void 116 check_sym(ctf_file_t *ctfp, symtab_sym_t *ss) 117 { 118 int rettype = ctf_type_kind(ctfp, ss->ss_finfo.ctc_return); 119 int start_index = 0; 120 121 if (ss->ss_finfo.ctc_argc == 0) /* No arguments, no point */ 122 return; 123 124 if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) && 125 ctf_type_size(ctfp, ss->ss_finfo.ctc_return) > 16) 126 start_index = 1; 127 128 if (saveargs_has_args(ss->ss_data, ss->ss_sym.st_size, 129 ss->ss_finfo.ctc_argc, start_index) != SAVEARGS_NO_ARGS) 130 printf("%s has %d saved args\n", ss->ss_name, 131 ss->ss_finfo.ctc_argc); 132 } 133 134 int 135 main(int argc, char **argv) 136 { 137 Elf *elf; 138 ctf_file_t *ctfp; 139 int errp, fd; 140 141 if (ctf_version(CTF_VERSION) == -1) 142 errx(1, "mismatched libctf versions\n"); 143 144 if (elf_version(EV_CURRENT) == EV_NONE) 145 errx(1, "mismatched libelf versions\n"); 146 147 if (argc != 2) 148 errx(2, "usage: %s <file>\n", __progname); 149 150 if ((ctfp = ctf_open(argv[1], &errp)) == NULL) 151 errx(1, "failed to ctf_open file: %s: %s\n", argv[1], 152 ctf_errmsg(errp)); 153 154 if ((fd = open(argv[1], O_RDONLY)) == -1) 155 errx(1, "could not open %s\n", argv[1]); 156 157 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 158 errx(1, "could not interpret ELF from %s\n", 159 argv[1]); 160 161 walk_symtab(elf, argv[1], ctfp, check_sym); 162 163 (void) elf_end(elf); 164 (void) close(fd); 165 166 return (0); 167 } 168