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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1994, by Sun Microsytems, Inc. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Generic functions that know how to traverse elf sections in an object. 30 * Also functions that know how to traverse records in a section. 31 * 32 */ 33 34 #include <string.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <errno.h> 38 #include <sys/procfs.h> 39 #include <sys/stat.h> 40 41 #include "tnfctl_int.h" 42 #include "dbg.h" 43 44 45 /* 46 * _tnfctl_traverse_object() - traverses all of the elf sections in an object, 47 * calling the supplied function on each. 48 */ 49 tnfctl_errcode_t 50 _tnfctl_traverse_object(int objfd, uintptr_t addr, 51 tnfctl_elf_search_t *search_info_p) 52 { 53 Elf *elf; 54 GElf_Ehdr *ehdr, ehdr_obj; 55 char *strs; 56 GElf_Shdr *shdr, shdr_obj; 57 Elf_Data *data; 58 u_int idx; 59 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 60 61 DBG_TNF_PROBE_1(_tnfctl_traverse_object_1, "libtnfctl", 62 "sunw%verbosity 3", 63 tnf_opaque, obj_addr, addr); 64 65 if (elf_version(EV_CURRENT) == EV_NONE) 66 return (TNFCTL_ERR_INTERNAL); 67 68 /* open elf descriptor on the fd */ 69 elf = elf_begin(objfd, ELF_C_READ, NULL); 70 if (elf == NULL || elf_kind(elf) != ELF_K_ELF) { 71 DBG_TNF_PROBE_0(_tnfctl_traverse_object_2, "libtnfctl", 72 "sunw%verbosity 3; sunw%debug 'not elf object'"); 73 return (TNFCTL_ERR_INTERNAL); 74 } 75 /* get the elf header */ 76 if ((ehdr = gelf_getehdr(elf, &ehdr_obj)) == NULL) { 77 DBG((void) fprintf(stderr, 78 "_tnfctl_traverse_object: gelf_getehdr failed\n")); 79 (void) elf_end(elf); 80 return (TNFCTL_ERR_INTERNAL); 81 } 82 if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN)) { 83 DBG((void) fprintf(stderr, 84 "_tnfctl_traverse_object: not an " 85 "executable or a shared object\n")); 86 (void) elf_end(elf); 87 return (TNFCTL_ERR_INTERNAL); 88 } 89 /* if an executable file, the base address is 0 */ 90 if (ehdr->e_type == ET_EXEC) 91 addr = 0; 92 /* get a pointer to the elf header string table */ 93 strs = elf_strptr(elf, ehdr->e_shstrndx, NULL); 94 95 DBG_TNF_PROBE_1(_tnfctl_traverse_object_3, "libtnfctl", 96 "sunw%verbosity 3", 97 tnf_long, num_sections_found, ehdr->e_shnum); 98 99 for (idx = 1; idx < ehdr->e_shnum; idx++) { 100 Elf_Scn *scn; 101 102 if ((scn = elf_getscn(elf, idx)) == NULL) { 103 DBG((void) fprintf(stderr, 104 "_tnfctl_traverse_object: elf_getscn failed\n")); 105 prexstat = TNFCTL_ERR_INTERNAL; 106 break; 107 } 108 if ((shdr = gelf_getshdr(scn, &shdr_obj)) == NULL) { 109 DBG((void) fprintf(stderr, 110 "_tnfctl_traverse_obj:gelf_getshdr failed\n")); 111 prexstat = TNFCTL_ERR_INTERNAL; 112 break; 113 } 114 115 if ((data = elf_getdata(scn, NULL)) == NULL) { 116 DBG((void) fprintf(stderr, 117 "_tnfctl_traverse_obj:gelf_getdata failed\n")); 118 prexstat = TNFCTL_ERR_INTERNAL; 119 break; 120 } 121 /* call the supplied function */ 122 prexstat = search_info_p->section_func(elf, 123 strs, scn, shdr, data, addr, search_info_p); 124 if (prexstat) 125 break; 126 } 127 128 (void) elf_end(elf); 129 130 return (prexstat); 131 132 } /* end _tnfctl_traverse_object */ 133 134 135 /* 136 * _tnfctl_traverse_rela() - this function traverses a .rela section calling the 137 * supplied function on each relocation record. 138 */ 139 /*ARGSUSED*/ 140 tnfctl_errcode_t 141 _tnfctl_traverse_rela(Elf * elf, char *strs, Elf_Scn * rel_scn, 142 GElf_Shdr * rel_shdr, Elf_Data * rel_data, uintptr_t baseaddr, 143 tnfctl_elf_search_t * search_info_p) 144 { 145 Elf_Scn *sym_scn; 146 GElf_Shdr *sym_shdr, sym_shdr_obj; 147 Elf_Data *sym_data; 148 Elf3264_Sym *sym_table; 149 Elf_Scn *str_scn; 150 GElf_Shdr *str_shdr, str_shdr_obj; 151 Elf_Data *str_data; 152 char *str_table; 153 ulong_t nrels; 154 uint_t i; 155 boolean_t isrela; 156 size_t rela_sz; 157 char *ptr; 158 159 DBG_TNF_PROBE_0(_tnfctl_traverse_rela_1, "libtnfctl", 160 "sunw%verbosity 4"); 161 162 /* bail if this isn't a rela (or rel) section */ 163 if (rel_shdr->sh_type == SHT_RELA) { 164 isrela = B_TRUE; 165 } else if (rel_shdr->sh_type == SHT_REL) { 166 isrela = B_FALSE; 167 } else 168 return (TNFCTL_ERR_NONE); 169 170 /* find the symbol table section associated with this rela section */ 171 sym_scn = elf_getscn(elf, rel_shdr->sh_link); 172 if (sym_scn == NULL) { 173 DBG((void) fprintf(stderr, 174 "_tnfctl_traverse_rela:elf_getscn (sym) failed\n")); 175 return (TNFCTL_ERR_INTERNAL); 176 } 177 sym_shdr = gelf_getshdr(sym_scn, &sym_shdr_obj); 178 if (sym_shdr == NULL) { 179 DBG((void) fprintf(stderr, 180 "_tnfctl_traverse_rela:gelf_getshdr (sym) failed\n")); 181 return (TNFCTL_ERR_INTERNAL); 182 } 183 sym_data = elf_getdata(sym_scn, NULL); 184 if (sym_data == NULL) { 185 DBG((void) fprintf(stderr, 186 "_tnfctl_traverse_rela:elf_getdata (sym) failed\n")); 187 return (TNFCTL_ERR_INTERNAL); 188 } 189 sym_table = (Elf3264_Sym *) sym_data->d_buf; 190 191 /* find the string table associated with the symbol table */ 192 str_scn = elf_getscn(elf, sym_shdr->sh_link); 193 if (str_scn == NULL) { 194 DBG((void) fprintf(stderr, 195 "_tnfctl_traverse_rela:elf_getscn (str) failed\n")); 196 return (TNFCTL_ERR_INTERNAL); 197 } 198 str_shdr = gelf_getshdr(str_scn, &str_shdr_obj); 199 if (str_shdr == NULL) { 200 DBG((void) fprintf(stderr, 201 "_tnfctl_traverse_rela:gelf_getshdr (str) failed\n")); 202 return (TNFCTL_ERR_INTERNAL); 203 } 204 str_data = elf_getdata(str_scn, NULL); 205 if (str_data == NULL) { 206 DBG((void) fprintf(stderr, 207 "_tnfctl_traverse_rela: elf_getdata (str) failed\n")); 208 return (TNFCTL_ERR_INTERNAL); 209 } 210 str_table = (char *) str_data->d_buf; 211 212 /* loop over each relocation record */ 213 nrels = rel_shdr->sh_size / rel_shdr->sh_entsize; 214 215 DBG_TNF_PROBE_1(_tnfctl_traverse_rela_2, "libtnfctl", 216 "sunw%verbosity 3", 217 tnf_long, relocations_found, nrels); 218 219 ptr = rel_data->d_buf; 220 rela_sz = (isrela) ? sizeof (Elf3264_Rela) : sizeof (Elf3264_Rel); 221 for (i = 0; i < nrels; i++, ptr += rela_sz) { 222 Elf3264_Word syminfo; 223 Elf3264_Sym *sym; 224 Elf3264_Addr offset; 225 char *name; 226 uintptr_t addr; 227 tnfctl_errcode_t prexstat; 228 229 /* decode the r_info field of the relocation record */ 230 if (isrela) { 231 Elf3264_Rela *rela_p; 232 233 /*LINTED pointer cast may result in improper alignment*/ 234 rela_p = (Elf3264_Rela *) ptr; 235 syminfo = ELF3264_R_SYM(rela_p->r_info); 236 offset = rela_p->r_offset; 237 } else { 238 Elf3264_Rel *rel_p; 239 240 /*LINTED pointer cast may result in improper alignment*/ 241 rel_p = (Elf3264_Rel *) ptr; 242 syminfo = ELF3264_R_SYM(rel_p->r_info); 243 offset = rel_p->r_offset; 244 } 245 246 /* find the associated symbol table entry */ 247 if (!syminfo) 248 continue; 249 sym = sym_table + syminfo; 250 251 /* find the associated string table entry */ 252 if (!sym->st_name) 253 continue; 254 name = str_table + sym->st_name; 255 addr = offset + baseaddr; 256 257 prexstat = search_info_p->record_func(name, addr, ptr, 258 search_info_p); 259 if (prexstat) 260 break; 261 } 262 263 return (TNFCTL_ERR_NONE); 264 265 } /* end _tnfctl_traverse_rela */ 266 267 268 /* 269 * _tnfctl_traverse_dynsym() - this function traverses a dynsym section calling 270 * the supplied function on each symbol. 271 */ 272 273 /*ARGSUSED*/ 274 tnfctl_errcode_t 275 _tnfctl_traverse_dynsym(Elf * elf, 276 char *elfstrs, 277 Elf_Scn * scn, 278 GElf_Shdr * shdr, 279 Elf_Data * data, 280 uintptr_t baseaddr, 281 tnfctl_elf_search_t * search_info_p) 282 { 283 ulong_t nsyms; 284 int i; 285 char *strs; 286 tnfctl_errcode_t prexstat; 287 288 Elf3264_Sym *syms; 289 290 /* bail if this isn't a dynsym section */ 291 if (shdr->sh_type != SHT_DYNSYM) 292 return (TNFCTL_ERR_NONE); 293 #if 0 294 printf("### entering _tnfctl_traverse_dynsym...\n"); 295 #endif 296 syms = data->d_buf; 297 nsyms = shdr->sh_size / shdr->sh_entsize; 298 strs = elf_strptr(elf, shdr->sh_link, 0); 299 300 DBG_TNF_PROBE_1(_tnfctl_traverse_dynsym_1, "libtnfctl", 301 "sunw%verbosity 3", 302 tnf_long, symbols_found, nsyms); 303 304 for (i = 0; i < nsyms; i++) { 305 Elf3264_Sym *sym = &syms[i]; 306 char *name; 307 uintptr_t addr; 308 309 name = strs + sym->st_name; 310 addr = baseaddr + sym->st_value; 311 312 #if 0 313 if (name != 0) 314 printf("_tnfctl_traverse_dynsym: name = %s\n", name); 315 else 316 printf("_tnfctl_traverse_dynsym: name is 0\n"); 317 #endif 318 prexstat = search_info_p->record_func(name, 319 addr, sym, search_info_p); 320 if (prexstat) 321 break; 322 } 323 #if 0 324 printf("### leaving _tnfctl_traverse_dynsym...\n"); 325 #endif 326 return (prexstat); 327 328 } /* end _tnfctl_traverse_dynsym */ 329