# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. # This directory contains sample programs that demonstrate how to use libelf. Manual pages for libelf routines are located in section 3e: Library Functions. Each of these sample programs displays, or manipulates information from a ELF file. Each program uses libelf differently. To learn more about ELF files and their format refer to the "Linker & Libraries Guide", which is part of the "Software Developer Collection", and the "System V Application Binary Interface". The following source files are provided: pcom.c print comment: prints the .comment section of an ELF file. Demonstrates how to examine a file opened with elf_begin(ELF_C_READ) acom.c append comment: appends to, or creates a .comment section within an ELF file. Demonstrates the updating of a file with elf_begin(ELF_C_RDWR) dcom.c delete comment: deletes a .comment section from an ELF file. Demonstrates the creation of a ELF file with elf_begin(ELF_C_WRITE) tpcom.c threaded print comment: a threaded version of pcom.c. Demonstrates that libelf is MT-Safe and can be used by a threaded program. dispsyms.c print symbols: scans a ELF file for any symbol tables (SHT_SYMTAB, SHT_DYNSYM, or SHT_SUNW_LDYNSYM) and displays the symbol tables contents. Makefile make file to build the above programs. Building the demos ------------------ To build the programs: % make all To test the programs: % make test # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. # PROGS= pcom acom dcom tpcom dispsyms LDLIBS= -lelf OBJS= $(PROGS:%=%.o) .KEEP_STATE: all: libobj.a .WAIT $(PROGS) libobj.a: $(OBJS) ar -r $@ $(OBJS) %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< mcs -d -a "ELF demo: object comment: $@" $@ %: %.o $(CC) $(CFLAGS) -o $@ $< $(LDLIBS) mcs -d -a "ELF demo: executable comment: $@" $@ test: test1 test2 test3 test4 test5 test6 test1: pcom FRC @ echo "" @ echo "<<< Test 1 >>>" @ echo "Print comments of pcom" pcom pcom @ echo @ echo "Print comments from archive libobj.a" pcom libobj.a test2: dcom pcom FRC @ echo "" @ echo "<<< Test 2 >>>" @ echo "Delete the comment section from pcom" TMPDIR= dcom pcom pcom pcom test3: pcom acom test2 FRC @ echo "" @ echo "<<< Test 3 >>>" @ echo "update comments from pcom and then print them out." acom "Newly Updated Comments" pcom pcom pcom test4: acom pcom test3 FRC @ echo "" @ echo "<<< Test 4 >>>" @ echo "Append to the comment section of pcom." acom "This comment has been appended" pcom pcom pcom test5: $(PROGS) FRC @ echo "" @ echo "<<< Test 5 >>>" @ echo "Relabel the new utilities using the new utilities." TMPDIR= dcom $(PROGS) cp acom acom.safe acom.safe "libelf Demonstration Tools" $(PROGS) pcom $(PROGS) $(RM) acom.safe test6: dispsyms FRC @ echo "" @ echo "<<< Test 6 >>>" @ echo "Display symbols in dispsyms itself." dispsyms dispsyms | egrep -v "LOCL|ABS|SECT|UNDEF" test-extra: tpcom FRC @ echo "" @ echo "<<< Test-extra >>>" @ echo "Using the threaded tpcom, go through and examine all" @ echo "libraries in /lib. This is an output intensive test." tpcom /lib/lib*.so.? clean: FRC $(RM) $(OBJS) $(PROGS) libobj.a core FRC: /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * acom: Append Comment * * This program demonstrates the use of the libelf interface to * modify a ELF file. This program will open an ELF file and * either modify an existing .comment section and/or append * a new .comment section to an existing ELF file. */ #include #include #include #include #include #include #include static const char *CommentStr = ".comment"; static void update_comment(Elf *elf, const char *file, const char *comment) { Elf_Scn *scn = NULL; GElf_Shdr shdr; Elf_Data *data; size_t shstrndx; if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: gelf_getshdrstrdx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) break; } if (scn == NULL) { int ndx; (void) printf("%s has no .comment section. " "Creating one...\n", file); /* * First add the ".comment" string to the string table */ if ((scn = elf_getscn(elf, shstrndx)) == NULL) { (void) fprintf(stderr, "%s: elf_getscn() failed: %s\n", file, elf_errmsg(0)); return; } if ((data = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } ndx = data->d_off + data->d_size; if ((data = elf_newdata(scn)) == NULL) { (void) fprintf(stderr, "%s: elf_newdata() failed: %s\n", file, elf_errmsg(0)); return; } data->d_buf = (void *)CommentStr; data->d_size = strlen(CommentStr) + 1; data->d_align = 1; /* * Add the ".comment" section to the end of the file. * Initialize the fields in the Section Header that * libelf will not fill in. */ if ((scn = elf_newscn(elf)) == NULL) { (void) fprintf(stderr, "%s: elf_newscn() failed: %s\n", file, elf_errmsg(0)); return; } if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } shdr.sh_name = ndx; shdr.sh_type = SHT_PROGBITS; shdr.sh_flags = 0; shdr.sh_addr = 0; shdr.sh_link = 0; shdr.sh_info = 0; /* * Flush the changes to the underlying elf32 or elf64 * section header. */ (void) gelf_update_shdr(scn, &shdr); } if (shdr.sh_addr != 0) { (void) printf("%s: .comment section is part of a " "loadable segment, it cannot be changed.\n", file); return; } if ((data = elf_newdata(scn)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } data->d_buf = (void *)comment; data->d_size = strlen(comment) + 1; data->d_align = 1; if (elf_update(elf, ELF_C_WRITE) == -1) (void) fprintf(stderr, "%s: elf_update() failed: %s\n", file, elf_errmsg(0)); } int main(int argc, char **argv) { int i; char *new_comment; if (argc < 3) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } /* * The new comment is passed in through the command line. * This string will be used to update the .comment section of * the specified ELF files. */ new_comment = argv[1]; for (i = 2; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDWR)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_RDWR, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Determine what kind of elf file this is: */ if (elf_kind(elf) == ELF_K_ELF) update_comment(elf, elf_fname, new_comment); else (void) printf("%s not of type ELF_K_ELF. " "elf_kind == %d\n", elf_fname, elf_kind(elf)); (void) elf_end(elf); (void) close(fd); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * dcom: Delete Comment * * This program demonstrates the use of libelf interface to * copy the contents of one ELF file to create a new one. * dcom creates a new ELF file using elf_begin(ELF_C_WRITE). * * In order to delete a section from an ELF file you must * instead create a new ELF file and copy all but the 'selected' * sections to the new ELF file. This is because libelf is * unable to delete any sections from an ELF file, it can * only add them. * * NOTE: While this program works fine for simple ELF objects, * as they get more complex it may not properly update all of the * fields required. This program is *only* an example of how * to do this and not a complete program in itself. */ #include #include #include #include #include #include #include #include #include #include static const char *CommentStr = ".comment"; /* * Build a temporary file name that is in the * same directory as the elf file being processed. */ static char * mkname(const char *bname) { char *ptr; char buffer[MAXPATHLEN]; ptr = strcpy(buffer, bname); ptr += strlen(buffer); while (ptr >= buffer) { if (*ptr == '/') { *(ptr + 1) = '\0'; break; } ptr--; } if (ptr < buffer) { buffer[0] = '.'; buffer[1] = '\0'; } return (tempnam(buffer, 0)); } static void delete_comment(Elf *elf, int fd, const char *file) { Elf_Scn *scn = NULL; char *tfile; Elf *telf; GElf_Ehdr ehdr, tehdr; GElf_Phdr phdr, tphdr; size_t shstrndx, shnum, phnum; int tfd, *shndx, ndx = 1, off = 0; struct stat sbuf; if (gelf_getehdr(elf, &ehdr) == NULL) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrnum(elf, &shnum) == -1) { (void) fprintf(stderr, "%s: elf_getshdrnum() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getphdrnum(elf, &phnum) == -1) { (void) fprintf(stderr, "%s: elf_getphdrnum() failed: %s\n", file, elf_errmsg(0)); return; } /* * shndx is an array used to map the current section * indexes to the new section indexes. */ shndx = calloc(shnum, sizeof (int)); while ((scn = elf_nextscn(elf, scn)) != NULL) { GElf_Shdr shdr; /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) { shndx[ndx] = -1; off++; /* * If the .comment section is part of a loadable * segment then it can not be delted from the * ELF file. */ if (shdr.sh_addr != 0) { (void) printf("%s: .comment section is " "part of a loadable segment, it " "cannot be deleted.\n", file); free(shndx); return; } } else shndx[ndx] = ndx - off; ndx++; } /* * obtain a unique file name and open a file descriptor * pointing to that file. */ tfile = mkname(file); if ((tfd = open(tfile, O_RDWR | O_CREAT, 0600)) == -1) { perror("temp open"); return; } /* * Create a new ELF to duplicate the ELF file into. */ if ((telf = elf_begin(tfd, ELF_C_WRITE, 0)) == NULL) { (void) fprintf(stderr, "elf_begin(ELF_C_WRITE) failed: %s\n", elf_errmsg(0)); return; } if (gelf_newehdr(telf, gelf_getclass(elf)) == NULL) { (void) fprintf(stderr, "%s: elf_newehdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (gelf_getehdr(telf, &tehdr) == NULL) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } scn = NULL; ndx = 1; while ((scn = elf_nextscn(elf, scn)) != NULL) { Elf_Scn *tscn; Elf_Data *data, *tdata; GElf_Shdr shdr, tshdr; if (shndx[ndx] == -1) { ndx++; continue; } /* * Duplicate all but the .comment section in the * new file. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if ((tscn = elf_newscn(telf)) == NULL) { (void) fprintf(stderr, "%s: elf_newscn() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (gelf_getshdr(tscn, &tshdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } tshdr = shdr; tshdr.sh_link = shndx[shdr.sh_link]; /* * The relocation sections sh_info field also contains * a section index that needs to be adjusted. This is * the only section who's sh_info field contains * a section index according to the ABI. * * If their are non-ABI sections who's sh_info field * contains section indexes they will not properly * be updated by this routine. */ if (shdr.sh_type == SHT_REL) tshdr.sh_info = shndx[ndx]; /* * Flush the changes to the underlying elf32 or elf64 * section header. */ (void) gelf_update_shdr(tscn, &tshdr); if ((data = elf_getdata(scn, 0)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if ((tdata = elf_newdata(tscn)) == NULL) { (void) fprintf(stderr, "%s: elf_newdata() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } *tdata = *data; ndx++; } tehdr = ehdr; if (shndx[shstrndx] < SHN_LORESERVE) tehdr.e_shstrndx = shndx[shstrndx]; else { Elf_Scn *_scn; GElf_Shdr shdr0; /* * 'ELF Extended Sections' are enabled - we must * store the shstrndx in Shdr[0].sh_link */ if ((_scn = elf_getscn(telf, 0)) == NULL) { (void) fprintf(stderr, "%s: elf_getscn() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (gelf_getshdr(_scn, &shdr0) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } tehdr.e_shstrndx = SHN_XINDEX; shdr0.sh_link = shndx[shstrndx]; (void) gelf_update_shdr(_scn, &shdr0); } (void) gelf_update_ehdr(telf, &tehdr); free(shndx); /* * Duplicate all program headers contained in the ELF file. */ if (phnum != 0) { if (gelf_newphdr(telf, phnum) == NULL) { (void) fprintf(stderr, "%s: elf_newphdr() failed: %s\n", file, elf_errmsg(0)); return; } for (ndx = 0; ndx < (int)phnum; ndx++) { if (gelf_getphdr(elf, ndx, &phdr) == NULL || gelf_getphdr(telf, ndx, &tphdr) == NULL) { (void) fprintf(stderr, "%s: elf_getphdr() failed: %s\n", file, elf_errmsg(0)); return; } tphdr = phdr; (void) gelf_update_phdr(telf, ndx, &tphdr); } } /* * The new Elf file has now been fully described to libelf. * elf_update() will construct the new Elf file and write * it out to disk. */ if (elf_update(telf, ELF_C_WRITE) == -1) { (void) fprintf(stderr, "elf_update() failed: %s\n", elf_errmsg(0)); (void) elf_end(telf); (void) close(tfd); return; } (void) elf_end(telf); /* * set new files permissions to the original files * permissions. */ (void) fstat(fd, &sbuf); (void) fchmod(tfd, sbuf.st_mode); (void) close(tfd); /* * delete the original file and rename the new file * to the orignal file. */ (void) rename(tfile, file); } int main(int argc, char ** argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Determine what kind of elf file this is: */ if (elf_kind(elf) != ELF_K_ELF) { /* * can only delete comment sections from * ELF files. */ (void) printf("%s not of type ELF_K_ELF. " "elf_kind == %d\n", elf_fname, elf_kind(elf)); } else delete_comment(elf, fd, elf_fname); (void) elf_end(elf); (void) close(fd); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * dispsyms: Display Symbols * * This program demonstrates the use of the libelf interface to * read an ELF file. dispsyms will open an ELF file using * elf_begin(ELF_C_READ) and examine search the ELF file * for a symbol table (SHT_SYMTAB, SHT_DYNSYM, or SHT_SUNW_LDYNSYM). * It will display the contents of any symbol tables it finds. * * Note: This program also understands about the use * of 'Extended ELF Section indexes' and will * decode a corresponding SHT_SYMTAB_SHNDX * section if required. */ #include #include #include #include #include #include #include static const char *symbind[STB_NUM] = { /* STB_LOCL */ "LOCL", /* STB_GLOBAL */ "GLOB", /* STB_WEAK */ "WEAK" }; static const char *symtype[STT_NUM] = { /* STT_NOTYPE */ "NOTY", /* STT_OBJECT */ "OBJT", /* STT_FUNC */ "FUNC", /* STT_SECTION */ "SECT", /* STT_FILE */ "FILE", /* STT_COMMON */ "COMM", /* STT_TLS */ "TLS" }; #if STT_NUM != (STT_TLS + 1) #error "STT_NUM has grown. Update symtype[]." #endif #define INTSTRLEN 32 static void print_symtab(Elf *elf, const char *file) { Elf_Scn *scn = NULL; GElf_Shdr shdr; GElf_Ehdr ehdr; size_t shstrndx; if (gelf_getehdr(elf, &ehdr) == NULL) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { uint_t symcnt, ndx, nosymshndx; Elf_Data *symdata, *shndxdata; if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if ((shdr.sh_type != SHT_SYMTAB) && (shdr.sh_type != SHT_DYNSYM) && (shdr.sh_type != SHT_SUNW_LDYNSYM)) continue; /* * Get the data associated with the Symbol * section. */ if ((symdata = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } /* * Print symbol table title and header for symbol display */ (void) printf("\nSymTab: %s:%s\n", file, elf_strptr(elf, shstrndx, shdr.sh_name)); (void) printf(" index value size type " "bind oth shndx name\n"); /* * We now iterate over the full symbol table printing * the symbols as we go. */ shndxdata = 0; nosymshndx = 0; symcnt = shdr.sh_size / shdr.sh_entsize; for (ndx = 0; ndx < symcnt; ndx++) { GElf_Sym sym; Elf32_Word shndx; uint_t type, bind, specshndx; char bindbuf[INTSTRLEN]; char typebuf[INTSTRLEN]; char shndxbuf[INTSTRLEN]; const char *bindstr, *typestr, *shndxstr; /* * Get a symbol entry */ if (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL) { (void) fprintf(stderr, "%s: gelf_getsymshndx() failed: %s\n", file, elf_errmsg(0)); return; } /* * Check to see if this symbol's st_shndx is using * the 'Extended SHNDX table' for a SYMTAB. * * If it is - and we haven't searched before, go * find the associated SHT_SYMTAB_SHNDX section. */ if ((sym.st_shndx == SHN_XINDEX) && (shndxdata == 0) && (nosymshndx == 0)) { Elf_Scn *_scn = NULL; GElf_Shdr _shdr; GElf_Word symscnndx; specshndx = 0; symscnndx = elf_ndxscn(scn); while ((_scn = elf_nextscn(elf, _scn)) != NULL) { if (gelf_getshdr(_scn, &_shdr) == NULL) break; /* * We've found the Symtab SHNDX table * if it's of type SHT_SYMTAB_SHNDX * and it's shdr.sh_link points to the * section index for the current symbol * table. */ if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) && (_shdr.sh_link == symscnndx) && ((shndxdata = elf_getdata(_scn, NULL)) != NULL)) break; } /* * Get a symbol entry */ if (shndxdata && (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL)) { (void) fprintf(stderr, "%s: gelf_getsymshndx() " "failed: %s\n", file, elf_errmsg(0)); return; } /* * No Symtab SHNDX table was found. We could * give a fatal error here - instead we'll * just mark that fact and display as much of * the symbol table as we can. Any symbol * displayed with a XINDX section index has * a bogus value. */ if (shndxdata == 0) nosymshndx = 1; } /* * Decode the type & binding information */ type = GELF_ST_TYPE(sym.st_info); bind = GELF_ST_BIND(sym.st_info); if (type < STT_NUM) typestr = symtype[type]; else { (void) snprintf(typebuf, INTSTRLEN, "%d", type); typestr = typebuf; } if (bind < STB_NUM) bindstr = symbind[bind]; else { (void) snprintf(bindbuf, INTSTRLEN, "%d", bind); bindstr = bindbuf; } specshndx = 0; if (sym.st_shndx < SHN_LORESERVE) shndx = sym.st_shndx; else if ((sym.st_shndx != SHN_XINDEX) || (shndxdata == NULL)) { shndx = sym.st_shndx; specshndx = 1; } if (shndx == SHN_UNDEF) { shndxstr = (const char *)"UNDEF"; } else if (specshndx) { if (shndx == SHN_ABS) shndxstr = (const char *)"ABS"; else if (shndx == SHN_COMMON) shndxstr = (const char *)"COMM"; else if (shndx == SHN_XINDEX) shndxstr = (const char *)"XIND"; else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } } else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } /* * Display the symbol entry. */ (void) printf("[%3d] 0x%08llx 0x%08llx %-4s " "%-6s %2d %5s %s\n", ndx, sym.st_value, sym.st_size, typestr, bindstr, sym.st_other, shndxstr, elf_strptr(elf, shdr.sh_link, sym.st_name)); } } } static void process_elf(Elf *elf, char *file, int fd, int member) { Elf_Cmd cmd; Elf *_elf; switch (elf_kind(elf)) { case ELF_K_ELF: /* * This is an ELF file, now attempt to find it's * .comment section and to display it. */ print_symtab(elf, file); break; case ELF_K_AR: /* * Archives contain multiple ELF files, which can each * in turn be examined with libelf. * * The below loop will iterate over each member of the * archive and recursively call process_elf(). */ cmd = ELF_C_READ; while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { Elf_Arhdr *arhdr; char buffer[1024]; arhdr = elf_getarhdr(_elf); /* * Build up file names based off of * 'archivename(membername)'. */ (void) snprintf(buffer, 1024, "%s(%s)", file, arhdr->ar_name); /* * Recursively process the ELF members. */ process_elf(_elf, buffer, fd, 1); cmd = elf_next(_elf); (void) elf_end(_elf); } break; default: if (!member) (void) fprintf(stderr, "%s: unexpected elf_kind(): 0x%x\n", file, elf_kind(elf)); return; } } int main(int argc, char **argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read-Only * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Process each elf descriptor. */ process_elf(elf, elf_fname, fd, 0); (void) elf_end(elf); (void) close(fd); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * pcom: Print Comment * * This program demonstrates the use of the libelf interface to * read an ELF file. pcom will open an ELF file using * elf_begin(ELF_C_READ) and examine search the ELF file * for a .comment section. If a .comment section is found it's * contents will be displayed on stdout. */ #include #include #include #include #include #include #include static const char *CommentStr = ".comment"; static void print_comment(Elf *elf, const char *file) { Elf_Scn *scn = NULL; GElf_Shdr shdr; Elf_Data *data; size_t shstrndx; (void) printf("%s .comment:\n", file); if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) { int i; char *ptr; /* * Get the data associated with the .comment * section. */ if ((data = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } /* * Data in a .comment section is a list of 'null' * terminated strings. The following will print * one string per line. */ for (i = 0, ptr = (char *)data->d_buf; i < data->d_size; i++) if (ptr[i]) { (void) puts(&ptr[i]); i += strlen(&ptr[i]); } (void) putchar('\n'); } } } static void process_elf(Elf *elf, char *file, int fd, int member) { Elf_Cmd cmd; Elf *_elf; switch (elf_kind(elf)) { case ELF_K_ELF: /* * This is an ELF file, now attempt to find it's * .comment section and to display it. */ print_comment(elf, file); break; case ELF_K_AR: /* * Archives contain multiple ELF files, which can each * in turn be examined with libelf. * * The below loop will iterate over each member of the * archive and recursively call process_elf(). */ cmd = ELF_C_READ; while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { Elf_Arhdr *arhdr; char buffer[1024]; arhdr = elf_getarhdr(_elf); /* * Build up file names based off of * 'archivename(membername)'. */ (void) sprintf(buffer, "%s(%s)", file, arhdr->ar_name); /* * Recursively process the ELF members. */ process_elf(_elf, buffer, fd, 1); cmd = elf_next(_elf); (void) elf_end(_elf); } break; default: if (!member) (void) fprintf(stderr, "%s: unexpected elf_kind(): 0x%x\n", file, elf_kind(elf)); return; } } int main(int argc, char **argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Process each elf descriptor. */ process_elf(elf, elf_fname, fd, 0); (void) elf_end(elf); (void) close(fd); } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * tpcom: Threaded Print Comment * * tpcom is a threaded version of the pcom program. It will create * a new thread for each new ELF descriptor that it examines. It * will then examine each elf descriptor and print the .comment section * if found. * * This program demonstrates that libelf is MT-Safe and the usage * of elf_begin(ELF_C_READ). */ #include #include #include #include #include #include #include #include #define NUMLWPS 32 /* arbitrary number of LWPS */ static const char *CommentStr = ".comment"; /* * arguments to be passed into process_elf(). */ typedef struct { Elf *pe_elf; char *pe_file; /* elf member name */ int pe_fd; short pe_member; /* is this an archive member? */ } pe_args; static mutex_t printlock = DEFAULTMUTEX; /* printlock used to */ /* group output */ /* of comment sections */ static void print_comment(Elf *elf, const char *file) { Elf_Scn *scn = NULL; GElf_Shdr shdr; Elf_Data *data; size_t shstrndx; if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) { int i; char *ptr; (void) mutex_lock(&printlock); (void) printf("%s .comment:\n", file); /* * Get the data associated with the .comment * section. */ if ((data = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); (void) mutex_unlock(&printlock); return; } /* * Data in a .comment section is a list of 'null' * terminated strings. The following will print * one string per line. */ for (i = 0, ptr = (char *)data->d_buf; i < data->d_size; i++) if (ptr[i]) { (void) puts(&ptr[i]); i += strlen(&ptr[i]); } (void) putchar('\n'); (void) mutex_unlock(&printlock); } } } static void process_elf(pe_args *pep) { Elf_Cmd cmd; Elf *_elf; switch (elf_kind(pep->pe_elf)) { case ELF_K_ELF: print_comment(pep->pe_elf, pep->pe_file); break; case ELF_K_AR: cmd = ELF_C_READ; while ((_elf = elf_begin(pep->pe_fd, cmd, pep->pe_elf)) != NULL) { Elf_Arhdr *arhdr; pe_args *_pep; int rc; if ((arhdr = elf_getarhdr(_elf)) == NULL) { (void) fprintf(stderr, "%s: elf_getarhdr() failed: %s\n", pep->pe_file, elf_errmsg(0)); } cmd = elf_next(_elf); _pep = malloc(sizeof (pe_args)); _pep->pe_elf = _elf; _pep->pe_file = malloc(strlen(pep->pe_file) + strlen(arhdr->ar_name) + 5); (void) sprintf(_pep->pe_file, "%s(%s)", pep->pe_file, arhdr->ar_name); _pep->pe_fd = pep->pe_fd; _pep->pe_member = 1; if ((rc = thr_create(NULL, 0, (void *(*)(void *))process_elf, (void *)_pep, THR_DETACHED, 0)) != 0) { (void) fprintf(stderr, "thr_create() failed, rc = %d\n", rc); } } break; default: if (!pep->pe_member) { (void) mutex_lock(&printlock); (void) fprintf(stderr, "%s: unexpected elf_kind(): 0x%x\n", pep->pe_file, elf_kind(pep->pe_elf)); (void) mutex_unlock(&printlock); } } (void) elf_end(pep->pe_elf); if (pep->pe_member) free(pep->pe_file); free(pep); thr_exit(0); } int main(int argc, char ** argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } /* * create an arbitrary number of LWP's to run the * threads that will be created. */ if (thr_setconcurrency(NUMLWPS) != 0) { (void) fprintf(stderr, "thread setconcurrency failed\n"); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; pe_args *pep; int rc; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) mutex_lock(&printlock); (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) mutex_unlock(&printlock); (void) close(fd); continue; } pep = malloc(sizeof (pe_args)); pep->pe_elf = elf; pep->pe_file = elf_fname; pep->pe_fd = fd; pep->pe_member = 0; if ((rc = thr_create(NULL, 0, (void *(*)(void *))process_elf, (void *)pep, THR_DETACHED, 0)) != 0) { (void) mutex_lock(&printlock); (void) fprintf(stderr, "thr_create() failed with code: %d\n", rc); (void) mutex_unlock(&printlock); return (1); } } thr_exit(0); return (0); }