1 /* Return section header. 2 Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014, 2015 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 1998. 5 6 This file is free software; you can redistribute it and/or modify 7 it under the terms of either 8 9 * the GNU Lesser General Public License as published by the Free 10 Software Foundation; either version 3 of the License, or (at 11 your option) any later version 12 13 or 14 15 * the GNU General Public License as published by the Free 16 Software Foundation; either version 2 of the License, or (at 17 your option) any later version 18 19 or both in parallel, as here. 20 21 elfutils is distributed in the hope that it will be useful, but 22 WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 General Public License for more details. 25 26 You should have received copies of the GNU General Public License and 27 the GNU Lesser General Public License along with this program. If 28 not, see <http://www.gnu.org/licenses/>. */ 29 30 #ifdef HAVE_CONFIG_H 31 # include <config.h> 32 #endif 33 34 #include <assert.h> 35 #include <errno.h> 36 #include <stdbool.h> 37 #include <unistd.h> 38 39 #include <system.h> 40 #include "libelfP.h" 41 #include "common.h" 42 43 #ifndef LIBELFBITS 44 # define LIBELFBITS 32 45 #endif 46 47 48 static ElfW2(LIBELFBITS,Shdr) * 49 load_shdr_wrlock (Elf_Scn *scn) 50 { 51 ElfW2(LIBELFBITS,Shdr) *result; 52 53 /* Read the section header table. */ 54 Elf *elf = scn->elf; 55 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; 56 57 /* Try again, maybe the data is there now. */ 58 result = scn->shdr.ELFW(e,LIBELFBITS); 59 if (result != NULL) 60 goto out; 61 62 size_t shnum; 63 if (__elf_getshdrnum_rdlock (elf, &shnum) != 0 64 || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr))) 65 goto out; 66 size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr)); 67 68 /* Allocate memory for the section headers. We know the number 69 of entries from the ELF header. */ 70 ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr = 71 (ElfW2(LIBELFBITS,Shdr) *) malloc (size); 72 if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) 73 { 74 __libelf_seterrno (ELF_E_NOMEM); 75 goto out; 76 } 77 elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1; 78 79 if (elf->map_address != NULL) 80 { 81 /* First see whether the information in the ELF header is 82 valid and it does not ask for too much. */ 83 if (unlikely (ehdr->e_shoff >= elf->maximum_size) 84 || unlikely (elf->maximum_size - ehdr->e_shoff < size)) 85 { 86 /* Something is wrong. */ 87 __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); 88 goto free_and_out; 89 } 90 91 ElfW2(LIBELFBITS,Shdr) *notcvt; 92 93 /* All the data is already mapped. If we could use it 94 directly this would already have happened. Unless 95 we allocated the memory ourselves and the ELF_F_MALLOCED 96 flag is set. */ 97 void *file_shdr = ((char *) elf->map_address 98 + elf->start_offset + ehdr->e_shoff); 99 100 assert ((elf->flags & ELF_F_MALLOCED) 101 || ehdr->e_ident[EI_DATA] != MY_ELFDATA 102 || elf->cmd == ELF_C_READ_MMAP 103 || (! ALLOW_UNALIGNED 104 && ((uintptr_t) file_shdr 105 & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0)); 106 107 /* Now copy the data and at the same time convert the byte order. */ 108 if (ehdr->e_ident[EI_DATA] == MY_ELFDATA) 109 { 110 assert ((elf->flags & ELF_F_MALLOCED) 111 || elf->cmd == ELF_C_READ_MMAP 112 || ! ALLOW_UNALIGNED); 113 memcpy (shdr, file_shdr, size); 114 } 115 else 116 { 117 bool copy = ! (ALLOW_UNALIGNED 118 || ((uintptr_t) file_shdr 119 & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) 120 == 0); 121 if (! copy) 122 notcvt = (ElfW2(LIBELFBITS,Shdr) *) 123 ((char *) elf->map_address 124 + elf->start_offset + ehdr->e_shoff); 125 else 126 { 127 notcvt = (ElfW2(LIBELFBITS,Shdr) *) malloc (size); 128 if (unlikely (notcvt == NULL)) 129 { 130 __libelf_seterrno (ELF_E_NOMEM); 131 goto out; 132 } 133 memcpy (notcvt, ((char *) elf->map_address 134 + elf->start_offset + ehdr->e_shoff), 135 size); 136 } 137 138 for (size_t cnt = 0; cnt < shnum; ++cnt) 139 { 140 CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name); 141 CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type); 142 CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags); 143 CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr); 144 CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset); 145 CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size); 146 CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link); 147 CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info); 148 CONVERT_TO (shdr[cnt].sh_addralign, 149 notcvt[cnt].sh_addralign); 150 CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize); 151 152 /* If this is a section with an extended index add a 153 reference in the section which uses the extended 154 index. */ 155 if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX 156 && shdr[cnt].sh_link < shnum) 157 elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index 158 = cnt; 159 160 /* Set the own shndx_index field in case it has not yet 161 been set. */ 162 if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0) 163 elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index 164 = -1; 165 } 166 167 if (copy) 168 free (notcvt); 169 } 170 } 171 else if (likely (elf->fildes != -1)) 172 { 173 /* Read the header. */ 174 ssize_t n = pread_retry (elf->fildes, 175 elf->state.ELFW(elf,LIBELFBITS).shdr, size, 176 elf->start_offset + ehdr->e_shoff); 177 if (unlikely ((size_t) n != size)) 178 { 179 /* Severe problems. We cannot read the data. */ 180 __libelf_seterrno (ELF_E_READ_ERROR); 181 goto free_and_out; 182 } 183 184 /* If the byte order of the file is not the same as the one 185 of the host convert the data now. */ 186 if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) 187 for (size_t cnt = 0; cnt < shnum; ++cnt) 188 { 189 CONVERT (shdr[cnt].sh_name); 190 CONVERT (shdr[cnt].sh_type); 191 CONVERT (shdr[cnt].sh_flags); 192 CONVERT (shdr[cnt].sh_addr); 193 CONVERT (shdr[cnt].sh_offset); 194 CONVERT (shdr[cnt].sh_size); 195 CONVERT (shdr[cnt].sh_link); 196 CONVERT (shdr[cnt].sh_info); 197 CONVERT (shdr[cnt].sh_addralign); 198 CONVERT (shdr[cnt].sh_entsize); 199 } 200 } 201 else 202 { 203 /* The file descriptor was already enabled and not all data was 204 read. Undo the allocation. */ 205 __libelf_seterrno (ELF_E_FD_DISABLED); 206 207 free_and_out: 208 free (shdr); 209 elf->state.ELFW(elf,LIBELFBITS).shdr = NULL; 210 elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0; 211 212 goto out; 213 } 214 215 /* Set the pointers in the `scn's. */ 216 for (size_t cnt = 0; cnt < shnum; ++cnt) 217 elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS) 218 = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt]; 219 220 result = scn->shdr.ELFW(e,LIBELFBITS); 221 assert (result != NULL); 222 223 out: 224 return result; 225 } 226 227 static bool 228 scn_valid (Elf_Scn *scn) 229 { 230 if (scn == NULL) 231 return false; 232 233 if (unlikely (scn->elf->state.elf.ehdr == NULL)) 234 { 235 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); 236 return false; 237 } 238 239 if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS))) 240 { 241 __libelf_seterrno (ELF_E_INVALID_CLASS); 242 return false; 243 } 244 245 return true; 246 } 247 248 ElfW2(LIBELFBITS,Shdr) * 249 internal_function 250 __elfw2(LIBELFBITS,getshdr_rdlock) (Elf_Scn *scn) 251 { 252 ElfW2(LIBELFBITS,Shdr) *result; 253 254 if (!scn_valid (scn)) 255 return NULL; 256 257 result = scn->shdr.ELFW(e,LIBELFBITS); 258 if (result == NULL) 259 { 260 rwlock_unlock (scn->elf->lock); 261 rwlock_wrlock (scn->elf->lock); 262 result = scn->shdr.ELFW(e,LIBELFBITS); 263 if (result == NULL) 264 result = load_shdr_wrlock (scn); 265 } 266 267 return result; 268 } 269 270 ElfW2(LIBELFBITS,Shdr) * 271 internal_function 272 __elfw2(LIBELFBITS,getshdr_wrlock) (Elf_Scn *scn) 273 { 274 ElfW2(LIBELFBITS,Shdr) *result; 275 276 if (!scn_valid (scn)) 277 return NULL; 278 279 result = scn->shdr.ELFW(e,LIBELFBITS); 280 if (result == NULL) 281 result = load_shdr_wrlock (scn); 282 283 return result; 284 } 285 286 ElfW2(LIBELFBITS,Shdr) * 287 elfw2(LIBELFBITS,getshdr) (Elf_Scn *scn) 288 { 289 ElfW2(LIBELFBITS,Shdr) *result; 290 291 if (!scn_valid (scn)) 292 return NULL; 293 294 rwlock_rdlock (scn->elf->lock); 295 result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn); 296 rwlock_unlock (scn->elf->lock); 297 298 return result; 299 } 300