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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #include <stdlib.h> 31 #include <assert.h> 32 #include <errno.h> 33 #include <libelf.h> 34 #include "decl.h" 35 #include "msg.h" 36 37 38 /* 39 * Convert data from file format to memory format. 40 */ 41 42 43 static const size_t align32[ELF_T_NUM] = 44 { 45 1, /* ELF_T_BYTE */ 46 sizeof (Elf32), /* ELF_T_ADDR */ 47 sizeof (Elf32), /* ELF_T_DYN */ 48 sizeof (Elf32), /* ELF_T_EHDR */ 49 sizeof (Elf32_Half), /* ELF_T_HALF */ 50 sizeof (Elf32), /* ELF_T_OFF */ 51 sizeof (Elf32), /* ELF_T_PHDR */ 52 sizeof (Elf32), /* ELF_T_RELA */ 53 sizeof (Elf32), /* ELF_T_REL */ 54 sizeof (Elf32), /* ELF_T_SHDR */ 55 sizeof (Elf32), /* ELF_T_SWORD */ 56 sizeof (Elf32), /* ELF_T_SYM */ 57 sizeof (Elf32), /* ELF_T_WORD */ 58 sizeof (Elf32), /* ELF_T_VERDEF */ 59 sizeof (Elf32), /* ELF_T_VERNEED */ 60 sizeof (Elf64_Sxword), /* ELF_T_SXWORD */ 61 sizeof (Elf64), /* ELF_T_XWORD */ 62 sizeof (Elf32_Half), /* ELF_T_SYMINFO */ 63 sizeof (Elf32), /* ELF_T_NOTE */ 64 sizeof (Elf32_Lword), /* ELF_T_MOVE */ 65 sizeof (Elf32_Lword), /* ELF_T_MOVEP */ 66 sizeof (Elf32_Word) /* ELF_T_CAP */ 67 68 }; 69 70 #define Nalign32 (sizeof (align32)/sizeof (align32[0])) 71 72 static const size_t align64[ELF_T_NUM] = 73 { 74 1, /* ELF_T_BYTE */ 75 sizeof (Elf64), /* ELF_T_ADDR */ 76 sizeof (Elf64), /* ELF_T_DYN */ 77 sizeof (Elf64), /* ELF_T_EHDR */ 78 sizeof (Elf64_Half), /* ELF_T_HALF */ 79 sizeof (Elf64), /* ELF_T_OFF */ 80 sizeof (Elf64), /* ELF_T_PHDR */ 81 sizeof (Elf64), /* ELF_T_RELA */ 82 sizeof (Elf64), /* ELF_T_REL */ 83 sizeof (Elf64), /* ELF_T_SHDR */ 84 sizeof (Elf64_Word), /* ELF_T_SWORD */ 85 sizeof (Elf64), /* ELF_T_SYM */ 86 sizeof (Elf64_Word), /* ELF_T_WORD */ 87 sizeof (Elf64), /* ELF_T_VDEF */ 88 sizeof (Elf64), /* ELF_T_VNEED */ 89 sizeof (Elf64), /* ELF_T_SXWORD */ 90 sizeof (Elf64), /* ELF_T_XWORD */ 91 sizeof (Elf32_Half), /* ELF_T_SYMINFO */ 92 sizeof (Elf32), /* ELF_T_NOTE */ 93 sizeof (Elf64), /* ELF_T_MOVE */ 94 sizeof (Elf64), /* ELF_T_MOVEP */ 95 sizeof (Elf64_Word) /* ELF_T_CAP */ 96 }; 97 98 #define Nalign64 (sizeof (align64)/sizeof (align64[0])) 99 100 101 /* 102 * Could use an array indexed by ELFCLASS*, but I'd rather 103 * avoid .data over something this infrequently used. The 104 * next choice would be to add extra conditionals. 105 */ 106 #define NALIGN(elf) ((elf->ed_class == ELFCLASS32) ? Nalign32 : Nalign64) 107 #define ALIGN(elf) ((elf->ed_class == ELFCLASS32) ? align32 : align64) 108 109 110 Elf_Data * 111 _elf_locked_getdata(Elf_Scn * scn, Elf_Data * data) 112 { 113 Dnode * d = (Dnode *)data; 114 Elf * elf; 115 Elf_Data src; 116 unsigned work; 117 118 assert(!elf_threaded || RW_LOCK_HELD(&(scn->s_elf->ed_rwlock))); 119 assert(!elf_threaded || MUTEX_HELD(&(scn->s_mutex))); 120 elf = scn->s_elf; 121 122 if ((scn->s_myflags & SF_READY) == 0) { 123 UPGRADELOCKS(elf, scn) 124 /* 125 * make sure someone else didn't come along and cook 126 * this stuff. 127 */ 128 if ((scn->s_myflags & SF_READY) == 0) 129 (void) _elf_cookscn(scn); 130 DOWNGRADELOCKS(elf, scn) 131 } 132 133 if (d == 0) 134 d = scn->s_hdnode; 135 else 136 d = d->db_next; 137 138 if (scn->s_err != 0) { 139 /*LINTED*/ 140 _elf_seterr((Msg)scn->s_err, 0); 141 return (0); 142 } 143 144 if (d == 0) { 145 return (0); 146 } 147 148 if (d->db_scn != scn) { 149 _elf_seterr(EREQ_DATA, 0); 150 return (0); 151 } 152 153 if (d->db_myflags & DBF_READY) { 154 return (&d->db_data); 155 } 156 elf = scn->s_elf; 157 158 /* 159 * Prepare return buffer. The data comes from the memory 160 * image of the file. "Empty" regions get an empty buffer. 161 * 162 * Only sections of an ELF_C_READ file can be not READY here. 163 * Furthermore, the input file must have been cooked or 164 * frozen by now. Translate cooked files in place if possible. 165 */ 166 167 ELFACCESSDATA(work, _elf_work) 168 d->db_data.d_version = work; 169 if ((d->db_off == 0) || (d->db_fsz == 0)) { 170 d->db_myflags |= DBF_READY; 171 return (&d->db_data); 172 } 173 174 if (elf->ed_class == ELFCLASS32) { 175 Elf32_Shdr *sh = scn->s_shdr; 176 size_t sz = sh->sh_entsize; 177 Elf_Type t = d->db_data.d_type; 178 179 if ((t != ELF_T_BYTE) && 180 (sz > 1) && (sz != elf32_fsize(t, 1, elf->ed_version))) { 181 _elf_seterr(EFMT_ENTSZ, 0); 182 return (0); 183 } 184 } else if (elf->ed_class == ELFCLASS64) { 185 Elf64_Shdr *sh = scn->s_shdr; 186 Elf64_Xword sz = sh->sh_entsize; 187 Elf_Type t = d->db_data.d_type; 188 189 if (t != ELF_T_BYTE && sz > 1 && 190 sz != elf64_fsize(t, 1, elf->ed_version)) { 191 _elf_seterr(EFMT_ENTSZ, 0); 192 return (0); 193 } 194 } else { 195 _elf_seterr(EREQ_CLASS, 0); 196 return (0); 197 } 198 199 200 /* 201 * validate the region 202 */ 203 204 if ((d->db_off < 0) || (d->db_off >= elf->ed_fsz) || 205 (elf->ed_fsz - d->db_off < d->db_fsz)) { 206 _elf_seterr(EFMT_DATA, 0); 207 return (0); 208 } 209 210 /* 211 * set up translation buffers and validate 212 */ 213 214 src.d_buf = (Elf_Void *)(elf->ed_ident + d->db_off); 215 src.d_size = d->db_fsz; 216 src.d_type = d->db_data.d_type; 217 src.d_version = elf->ed_version; 218 if (elf->ed_vm) { 219 UPGRADELOCKS(elf, scn) 220 if (_elf_vm(elf, (size_t)d->db_off, d->db_fsz) != OK_YES) { 221 DOWNGRADELOCKS(elf, scn) 222 return (0); 223 } 224 DOWNGRADELOCKS(elf, scn) 225 } 226 227 /* 228 * decide where to put destination 229 */ 230 231 switch (elf->ed_status) { 232 case ES_COOKED: 233 if ((size_t)d->db_data.d_type >= NALIGN(elf)) { 234 _elf_seterr(EBUG_COOKTYPE, 0); 235 return (0); 236 } 237 238 /* 239 * If the destination size (memory) is at least as 240 * big as the source size (file), and has the necessary 241 * alignment, reuse the space. 242 * 243 * Note that it is not sufficient to check the alignment 244 * of the offset within the object. Rather, we must check 245 * the alignment of the actual data buffer. The offset is 246 * sufficient if the file is a plain object file, which 247 * will always be mapped on a page boundary. In an archive 248 * however, the only guarantee is that the object will start 249 * on an even boundary within the archive file. The 250 * Solaris ar(1) adds padding in most (but not all cases) 251 * which minimizes this issue, but it is still important 252 * for the remaining cases that do not get padded. It also 253 * matters with archives produced by other versions of 254 * ar(1), such as the GNU version, or one from another 255 * ELF based operating system. 256 */ 257 258 if (d->db_data.d_size <= src.d_size) { 259 d->db_data.d_buf = (Elf_Void *)(elf->ed_ident + 260 d->db_off); 261 if (((uintptr_t)d->db_data.d_buf 262 % ALIGN(elf)[d->db_data.d_type]) == 0) { 263 break; 264 } else { /* Failure: Restore NULL buffer pointer */ 265 d->db_data.d_buf = 0; 266 } 267 } 268 269 /*FALLTHRU*/ 270 case ES_FROZEN: 271 if ((d->db_buf = malloc(d->db_data.d_size)) == 0) { 272 _elf_seterr(EMEM_DATA, errno); 273 return (0); 274 } 275 d->db_data.d_buf = d->db_buf; 276 break; 277 278 default: 279 _elf_seterr(EBUG_COOKSTAT, 0); 280 return (0); 281 } 282 283 if (elf->ed_class == ELFCLASS32) { 284 if (elf32_xlatetom(&d->db_data, &src, elf->ed_encode) == 0) 285 return (0); 286 } else { /* ELFCLASS64 */ 287 if (elf64_xlatetom(&d->db_data, &src, elf->ed_encode) == 0) 288 return (0); 289 } 290 d->db_myflags |= DBF_READY; 291 292 return (&d->db_data); 293 } 294 295 Elf_Data * 296 elf_getdata(Elf_Scn * scn, Elf_Data * data) 297 { 298 Elf_Data * rc; 299 Elf * elf; 300 301 /* 302 * trap null args, end of list, previous buffer. 303 * SHT_NULL sections have no buffer list, so they 304 * fall out here too. 305 */ 306 if (scn == 0) 307 return (0); 308 309 elf = scn->s_elf; 310 READLOCKS(elf, scn); 311 rc = _elf_locked_getdata(scn, data); 312 READUNLOCKS(elf, scn); 313 return (rc); 314 } 315