elf_strptr.c
1 /*- 2 * Copyright (c) 2006,2008 Joseph Koshy 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 29 #include <assert.h> 30 #include <gelf.h> 31 32 #include "_libelf.h" 33 34 #ifndef roundup2 35 #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 36 #endif 37 38 ELFTC_VCSID("$Id$"); 39 40 /* 41 * Convert an ELF section#,offset pair to a string pointer. 42 */ 43 44 char * 45 elf_strptr(Elf *e, size_t scndx, size_t offset) 46 { 47 Elf_Scn *s; 48 Elf_Data *d; 49 GElf_Shdr shdr; 50 uint64_t alignment, count; 51 52 if (e == NULL || e->e_kind != ELF_K_ELF) { 53 LIBELF_SET_ERROR(ARGUMENT, 0); 54 return (NULL); 55 } 56 57 if ((s = elf_getscn(e, scndx)) == NULL || 58 gelf_getshdr(s, &shdr) == NULL) 59 return (NULL); 60 61 if (shdr.sh_type != SHT_STRTAB || 62 offset >= shdr.sh_size) { 63 LIBELF_SET_ERROR(ARGUMENT, 0); 64 return (NULL); 65 } 66 67 d = NULL; 68 if (e->e_flags & ELF_F_LAYOUT) { 69 70 /* 71 * The application is taking responsibility for the 72 * ELF object's layout, so we can directly translate 73 * an offset to a `char *' address using the `d_off' 74 * members of Elf_Data descriptors. 75 */ 76 while ((d = elf_getdata(s, d)) != NULL) { 77 78 if (d->d_buf == 0 || d->d_size == 0) 79 continue; 80 81 if (d->d_type != ELF_T_BYTE) { 82 LIBELF_SET_ERROR(DATA, 0); 83 return (NULL); 84 } 85 86 if (offset >= d->d_off && 87 offset < d->d_off + d->d_size) 88 return ((char *) d->d_buf + offset - d->d_off); 89 } 90 } else { 91 /* 92 * Otherwise, the `d_off' members are not useable and 93 * we need to compute offsets ourselves, taking into 94 * account 'holes' in coverage of the section introduced 95 * by alignment requirements. 96 */ 97 count = (uint64_t) 0; /* cumulative count of bytes seen */ 98 while ((d = elf_getdata(s, d)) != NULL && count <= offset) { 99 100 if (d->d_buf == NULL || d->d_size == 0) 101 continue; 102 103 if (d->d_type != ELF_T_BYTE) { 104 LIBELF_SET_ERROR(DATA, 0); 105 return (NULL); 106 } 107 108 if ((alignment = d->d_align) > 1) { 109 if ((alignment & (alignment - 1)) != 0) { 110 LIBELF_SET_ERROR(DATA, 0); 111 return (NULL); 112 } 113 count = roundup2(count, alignment); 114 } 115 116 if (offset < count) { 117 /* offset starts in the 'hole' */ 118 LIBELF_SET_ERROR(ARGUMENT, 0); 119 return (NULL); 120 } 121 122 if (offset < count + d->d_size) { 123 if (d->d_buf != NULL) 124 return ((char *) d->d_buf + 125 offset - count); 126 LIBELF_SET_ERROR(DATA, 0); 127 return (NULL); 128 } 129 130 count += d->d_size; 131 } 132 } 133 134 LIBELF_SET_ERROR(ARGUMENT, 0); 135 return (NULL); 136 }