10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1558Sab196087 * Common Development and Distribution License (the "License"). 6*1558Sab196087 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 220Sstevel@tonic-gate /* All Rights Reserved */ 230Sstevel@tonic-gate 240Sstevel@tonic-gate 250Sstevel@tonic-gate /* 26*1558Sab196087 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 270Sstevel@tonic-gate * Use is subject to license terms. 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.16 */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate 340Sstevel@tonic-gate #pragma weak elf_getdata = _elf_getdata 350Sstevel@tonic-gate 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include "syn.h" 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <assert.h> 400Sstevel@tonic-gate #include <errno.h> 410Sstevel@tonic-gate #include <libelf.h> 420Sstevel@tonic-gate #include "decl.h" 430Sstevel@tonic-gate #include "msg.h" 440Sstevel@tonic-gate 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * Convert data from file format to memory format. 480Sstevel@tonic-gate */ 490Sstevel@tonic-gate 500Sstevel@tonic-gate 510Sstevel@tonic-gate static const size_t align32[ELF_T_NUM] = 520Sstevel@tonic-gate { 530Sstevel@tonic-gate 1, /* ELF_T_BYTE */ 540Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_ADDR */ 550Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_DYN */ 560Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_EHDR */ 570Sstevel@tonic-gate sizeof (Elf32_Half), /* ELF_T_HALF */ 580Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_OFF */ 590Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_PHDR */ 600Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_RELA */ 610Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_REL */ 620Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_SHDR */ 630Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_SWORD */ 640Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_SYM */ 650Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_WORD */ 660Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_VERDEF */ 670Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_VERNEED */ 680Sstevel@tonic-gate sizeof (Elf64_Sxword), /* ELF_T_SXWORD */ 690Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_XWORD */ 700Sstevel@tonic-gate sizeof (Elf32_Half), /* ELF_T_SYMINFO */ 710Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_NOTE */ 720Sstevel@tonic-gate sizeof (Elf32_Lword), /* ELF_T_MOVE */ 730Sstevel@tonic-gate sizeof (Elf32_Lword), /* ELF_T_MOVEP */ 740Sstevel@tonic-gate sizeof (Elf32_Word) /* ELF_T_CAP */ 750Sstevel@tonic-gate 760Sstevel@tonic-gate }; 770Sstevel@tonic-gate 780Sstevel@tonic-gate #define Nalign32 (sizeof (align32)/sizeof (align32[0])) 790Sstevel@tonic-gate 800Sstevel@tonic-gate static const size_t align64[ELF_T_NUM] = 810Sstevel@tonic-gate { 820Sstevel@tonic-gate 1, /* ELF_T_BYTE */ 830Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_ADDR */ 840Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_DYN */ 850Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_EHDR */ 860Sstevel@tonic-gate sizeof (Elf64_Half), /* ELF_T_HALF */ 870Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_OFF */ 880Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_PHDR */ 890Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_RELA */ 900Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_REL */ 910Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_SHDR */ 920Sstevel@tonic-gate sizeof (Elf64_Word), /* ELF_T_SWORD */ 930Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_SYM */ 940Sstevel@tonic-gate sizeof (Elf64_Word), /* ELF_T_WORD */ 950Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_VDEF */ 960Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_VNEED */ 970Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_SXWORD */ 980Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_XWORD */ 990Sstevel@tonic-gate sizeof (Elf32_Half), /* ELF_T_SYMINFO */ 1000Sstevel@tonic-gate sizeof (Elf32), /* ELF_T_NOTE */ 1010Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_MOVE */ 1020Sstevel@tonic-gate sizeof (Elf64), /* ELF_T_MOVEP */ 1030Sstevel@tonic-gate sizeof (Elf64_Word) /* ELF_T_CAP */ 1040Sstevel@tonic-gate }; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate #define Nalign64 (sizeof (align64)/sizeof (align64[0])) 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate /* 1100Sstevel@tonic-gate * Could use an array indexed by ELFCLASS*, but I'd rather 1110Sstevel@tonic-gate * avoid .data over something this infrequently used. The 1120Sstevel@tonic-gate * next choice would be to add extra conditionals. 1130Sstevel@tonic-gate */ 1140Sstevel@tonic-gate #define NALIGN(elf) ((elf->ed_class == ELFCLASS32) ? Nalign32 : Nalign64) 1150Sstevel@tonic-gate #define ALIGN(elf) ((elf->ed_class == ELFCLASS32) ? align32 : align64) 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate Elf_Data * 1190Sstevel@tonic-gate _elf_locked_getdata(Elf_Scn * scn, Elf_Data * data) 1200Sstevel@tonic-gate { 1210Sstevel@tonic-gate Dnode * d = (Dnode *)data; 1220Sstevel@tonic-gate Elf * elf; 1230Sstevel@tonic-gate Elf_Data src; 1240Sstevel@tonic-gate unsigned work; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate assert(!elf_threaded || RW_LOCK_HELD(&(scn->s_elf->ed_rwlock))); 1270Sstevel@tonic-gate assert(!elf_threaded || MUTEX_HELD(&(scn->s_mutex))); 1280Sstevel@tonic-gate elf = scn->s_elf; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate if ((scn->s_myflags & SF_READY) == 0) { 1310Sstevel@tonic-gate UPGRADELOCKS(elf, scn) 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * make sure someone else didn't come along and cook 1340Sstevel@tonic-gate * this stuff. 1350Sstevel@tonic-gate */ 1360Sstevel@tonic-gate if ((scn->s_myflags & SF_READY) == 0) 1370Sstevel@tonic-gate (void) _elf_cookscn(scn); 1380Sstevel@tonic-gate DOWNGRADELOCKS(elf, scn) 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate if (d == 0) 1420Sstevel@tonic-gate d = scn->s_hdnode; 1430Sstevel@tonic-gate else 1440Sstevel@tonic-gate d = d->db_next; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate if (scn->s_err != 0) { 1470Sstevel@tonic-gate /*LINTED*/ 1480Sstevel@tonic-gate _elf_seterr((Msg)scn->s_err, 0); 1490Sstevel@tonic-gate return (0); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate if (d == 0) { 1530Sstevel@tonic-gate return (0); 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate if (d->db_scn != scn) { 1570Sstevel@tonic-gate _elf_seterr(EREQ_DATA, 0); 1580Sstevel@tonic-gate return (0); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate if (d->db_myflags & DBF_READY) { 1620Sstevel@tonic-gate return (&d->db_data); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate elf = scn->s_elf; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate /* 1670Sstevel@tonic-gate * Prepare return buffer. The data comes from the memory 1680Sstevel@tonic-gate * image of the file. "Empty" regions get an empty buffer. 1690Sstevel@tonic-gate * 1700Sstevel@tonic-gate * Only sections of an ELF_C_READ file can be not READY here. 1710Sstevel@tonic-gate * Furthermore, the input file must have been cooked or 1720Sstevel@tonic-gate * frozen by now. Translate cooked files in place if possible. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate ELFACCESSDATA(work, _elf_work) 1760Sstevel@tonic-gate d->db_data.d_version = work; 1770Sstevel@tonic-gate if ((d->db_off == 0) || (d->db_fsz == 0)) { 1780Sstevel@tonic-gate d->db_myflags |= DBF_READY; 1790Sstevel@tonic-gate return (&d->db_data); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate if (elf->ed_class == ELFCLASS32) { 1830Sstevel@tonic-gate Elf32_Shdr *sh = scn->s_shdr; 1840Sstevel@tonic-gate size_t sz = sh->sh_entsize; 1850Sstevel@tonic-gate Elf_Type t = d->db_data.d_type; 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate if ((t != ELF_T_BYTE) && 1880Sstevel@tonic-gate (sz > 1) && (sz != elf32_fsize(t, 1, elf->ed_version))) { 1890Sstevel@tonic-gate _elf_seterr(EFMT_ENTSZ, 0); 1900Sstevel@tonic-gate return (0); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate } else if (elf->ed_class == ELFCLASS64) { 1930Sstevel@tonic-gate Elf64_Shdr *sh = scn->s_shdr; 1940Sstevel@tonic-gate Elf64_Xword sz = sh->sh_entsize; 1950Sstevel@tonic-gate Elf_Type t = d->db_data.d_type; 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate if (t != ELF_T_BYTE && sz > 1 && 1980Sstevel@tonic-gate sz != elf64_fsize(t, 1, elf->ed_version)) { 1990Sstevel@tonic-gate _elf_seterr(EFMT_ENTSZ, 0); 2000Sstevel@tonic-gate return (0); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate } else { 2030Sstevel@tonic-gate _elf_seterr(EREQ_CLASS, 0); 2040Sstevel@tonic-gate return (0); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * validate the region 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate if ((d->db_off < 0) || (d->db_off >= elf->ed_fsz) || 2130Sstevel@tonic-gate (elf->ed_fsz - d->db_off < d->db_fsz)) { 2140Sstevel@tonic-gate _elf_seterr(EFMT_DATA, 0); 2150Sstevel@tonic-gate return (0); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * set up translation buffers and validate 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate src.d_buf = (Elf_Void *)(elf->ed_ident + d->db_off); 2230Sstevel@tonic-gate src.d_size = d->db_fsz; 2240Sstevel@tonic-gate src.d_type = d->db_data.d_type; 2250Sstevel@tonic-gate src.d_version = elf->ed_version; 2260Sstevel@tonic-gate if (elf->ed_vm) { 2270Sstevel@tonic-gate UPGRADELOCKS(elf, scn) 2280Sstevel@tonic-gate if (_elf_vm(elf, (size_t)d->db_off, d->db_fsz) != OK_YES) { 2290Sstevel@tonic-gate DOWNGRADELOCKS(elf, scn) 2300Sstevel@tonic-gate return (0); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate DOWNGRADELOCKS(elf, scn) 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * decide where to put destination 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate switch (elf->ed_status) { 2400Sstevel@tonic-gate case ES_COOKED: 2410Sstevel@tonic-gate if ((size_t)d->db_data.d_type >= NALIGN(elf)) { 2420Sstevel@tonic-gate _elf_seterr(EBUG_COOKTYPE, 0); 2430Sstevel@tonic-gate return (0); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * If the destination size (memory) is at least as 248*1558Sab196087 * big as the source size (file), and has the necessary 249*1558Sab196087 * alignment, reuse the space. 250*1558Sab196087 * 251*1558Sab196087 * Note that it is not sufficient to check the alignment 252*1558Sab196087 * of the offset within the object. Rather, we must check 253*1558Sab196087 * the alignment of the actual data buffer. The offset is 254*1558Sab196087 * sufficient if the file is a plain object file, which 255*1558Sab196087 * will always be mapped on a page boundary. In an archive 256*1558Sab196087 * however, the only guarantee is that the object will start 257*1558Sab196087 * on an even boundary within the archive file. The 258*1558Sab196087 * Solaris ar(1) adds padding in most (but not all cases) 259*1558Sab196087 * which minimizes this issue, but it is still important 260*1558Sab196087 * for the remaining cases that do not get padded. It also 261*1558Sab196087 * matters with archives produced by other versions of 262*1558Sab196087 * ar(1), such as the GNU version, or one from another 263*1558Sab196087 * ELF based operating system. 2640Sstevel@tonic-gate */ 2650Sstevel@tonic-gate 266*1558Sab196087 if (d->db_data.d_size <= src.d_size) { 2670Sstevel@tonic-gate d->db_data.d_buf = (Elf_Void *)(elf->ed_ident + 2680Sstevel@tonic-gate d->db_off); 269*1558Sab196087 if (((uintptr_t)d->db_data.d_buf 270*1558Sab196087 % ALIGN(elf)[d->db_data.d_type]) == 0) { 271*1558Sab196087 break; 272*1558Sab196087 } else { /* Failure: Restore NULL buffer pointer */ 273*1558Sab196087 d->db_data.d_buf = 0; 274*1558Sab196087 } 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /*FALLTHRU*/ 2780Sstevel@tonic-gate case ES_FROZEN: 2790Sstevel@tonic-gate if ((d->db_buf = malloc(d->db_data.d_size)) == 0) { 2800Sstevel@tonic-gate _elf_seterr(EMEM_DATA, errno); 2810Sstevel@tonic-gate return (0); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate d->db_data.d_buf = d->db_buf; 2840Sstevel@tonic-gate break; 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate default: 2870Sstevel@tonic-gate _elf_seterr(EBUG_COOKSTAT, 0); 2880Sstevel@tonic-gate return (0); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate if (elf->ed_class == ELFCLASS32) { 2920Sstevel@tonic-gate if (elf32_xlatetom(&d->db_data, &src, elf->ed_encode) == 0) 2930Sstevel@tonic-gate return (0); 2940Sstevel@tonic-gate } else { /* ELFCLASS64 */ 2950Sstevel@tonic-gate if (elf64_xlatetom(&d->db_data, &src, elf->ed_encode) == 0) 2960Sstevel@tonic-gate return (0); 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate d->db_myflags |= DBF_READY; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate return (&d->db_data); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate Elf_Data * 3040Sstevel@tonic-gate elf_getdata(Elf_Scn * scn, Elf_Data * data) 3050Sstevel@tonic-gate { 3060Sstevel@tonic-gate Elf_Data * rc; 3070Sstevel@tonic-gate Elf * elf; 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate /* 3100Sstevel@tonic-gate * trap null args, end of list, previous buffer. 3110Sstevel@tonic-gate * SHT_NULL sections have no buffer list, so they 3120Sstevel@tonic-gate * fall out here too. 3130Sstevel@tonic-gate */ 3140Sstevel@tonic-gate if (scn == 0) 3150Sstevel@tonic-gate return (0); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate elf = scn->s_elf; 3180Sstevel@tonic-gate READLOCKS(elf, scn); 3190Sstevel@tonic-gate rc = _elf_locked_getdata(scn, data); 3200Sstevel@tonic-gate READUNLOCKS(elf, scn); 3210Sstevel@tonic-gate return (rc); 3220Sstevel@tonic-gate } 323