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