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 /* 28 * Copyright (c) 1988 AT&T 29 * All Rights Reserved 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include <ar.h> 35 #include <stdlib.h> 36 #include <memory.h> 37 #include <errno.h> 38 #include <libelf.h> 39 #include "decl.h" 40 #include "msg.h" 41 #include "member.h" 42 43 #define MANGLE '\177' 44 45 46 /* 47 * Archive processing 48 * When processing an archive member, two things can happen 49 * that are a little tricky. 50 * 51 * Sliding 52 * Sliding support is left in for backward compatibility and for 53 * support of Archives produced on other systems. The bundled 54 * ar(1) produces archives with all members on a 4 byte boundry, 55 * so current archives should need no sliding. 56 * 57 * Archive members that are only 2-byte aligned within the file will 58 * be slid. To reuse the file's memory image, the library slides an 59 * archive member into its header to align the bytes. This means 60 * the header must be disposable. 61 * 62 * Header reuse 63 * Because the library can trample the header, it must be preserved to 64 * avoid restrictions on archive member reuse. That is, if the member 65 * header changes, the library may see garbage the next time it looks 66 * at the header. After extracting the original header, the library 67 * appends it to the parents `ed_memlist' list, thus future lookups first 68 * check this list to determine if a member has previously been processed 69 * and whether sliding occured. 70 */ 71 72 73 /* 74 * Size check 75 * If the header is too small, the following generates a negative 76 * subscript for x.x and fails to compile. 77 * 78 * The check is based on sizeof (Elf64) because that's always going 79 * to be at least as big as Elf32. 80 */ 81 82 struct x 83 { 84 char x[sizeof (struct ar_hdr) - 3 * sizeof (Elf64) - 1]; 85 }; 86 87 88 89 static const char fmag[] = ARFMAG; 90 91 92 /* 93 * Convert a string starting at 'p' and ending at 'end' into 94 * an integer. Base is the base of the number being converted 95 * (either 8 or 10). 96 * 97 * Returns the converted integer of the string being scaned. 98 */ 99 unsigned long 100 _elf_number(char *p, char *end, int base) 101 { 102 register unsigned c; 103 register unsigned long n = 0; 104 105 while (p < end) { 106 if ((c = *p - '0') >= base) { 107 while (*p++ == ' ') 108 if (p >= end) 109 return (n); 110 return (0); 111 } 112 n *= base; 113 n += c; 114 ++p; 115 } 116 return (n); 117 } 118 119 120 /* 121 * Convert ar_hdr to Member 122 * Converts ascii file representation to the binary memory values. 123 */ 124 Member * 125 _elf_armem(Elf *elf, char *file, size_t fsz) 126 { 127 register struct ar_hdr *f = (struct ar_hdr *)file; 128 register Member *m; 129 register Memlist *l, * ol; 130 register Memident *i; 131 132 if (fsz < sizeof (struct ar_hdr)) { 133 _elf_seterr(EFMT_ARHDRSZ, 0); 134 return (0); 135 } 136 137 /* 138 * Determine in this member has already been processed 139 */ 140 for (l = elf->ed_memlist, ol = l; l; ol = l, l = l->m_next) 141 for (i = (Memident *)(l + 1); i < l->m_free; i++) 142 if (i->m_offset == file) 143 return (i->m_member); 144 145 if (f->ar_fmag[0] != fmag[0] || f->ar_fmag[1] != fmag[1]) { 146 _elf_seterr(EFMT_ARFMAG, 0); 147 return (0); 148 } 149 150 /* 151 * Allocate a new member structure and assign it to the next free 152 * free memlist ident. 153 */ 154 if ((m = (Member *)malloc(sizeof (Member))) == 0) { 155 _elf_seterr(EMEM_ARMEM, errno); 156 return (0); 157 } 158 if ((elf->ed_memlist == 0) || (ol->m_free == ol->m_end)) { 159 if ((l = (Memlist *)malloc(sizeof (Memlist) + 160 (sizeof (Memident) * MEMIDENTNO))) == 0) { 161 _elf_seterr(EMEM_ARMEM, errno); 162 return (0); 163 } 164 l->m_next = 0; 165 l->m_free = (Memident *)(l + 1); 166 l->m_end = (Memident *)((uintptr_t)l->m_free + 167 (sizeof (Memident) * MEMIDENTNO)); 168 169 if (elf->ed_memlist == 0) 170 elf->ed_memlist = l; 171 else 172 ol->m_next = l; 173 ol = l; 174 } 175 ol->m_free->m_offset = file; 176 ol->m_free->m_member = m; 177 ol->m_free++; 178 179 m->m_err = 0; 180 (void) memcpy(m->m_name, f->ar_name, ARSZ(ar_name)); 181 m->m_name[ARSZ(ar_name)] = '\0'; 182 m->m_hdr.ar_name = m->m_name; 183 (void) memcpy(m->m_raw, f->ar_name, ARSZ(ar_name)); 184 m->m_raw[ARSZ(ar_name)] = '\0'; 185 m->m_hdr.ar_rawname = m->m_raw; 186 m->m_slide = 0; 187 188 /* 189 * Classify file name. 190 * If a name error occurs, delay until getarhdr(). 191 */ 192 193 if (f->ar_name[0] != '/') { /* regular name */ 194 register char *p; 195 196 p = &m->m_name[sizeof (m->m_name)]; 197 while (*--p != '/') 198 if (p <= m->m_name) 199 break; 200 *p = '\0'; 201 } else if (f->ar_name[1] >= '0' && f->ar_name[1] <= '9') { /* strtab */ 202 register unsigned long j; 203 204 j = _elf_number(&f->ar_name[1], 205 &f->ar_name[ARSZ(ar_name)], 10); 206 if (j < elf->ed_arstrsz) 207 m->m_hdr.ar_name = elf->ed_arstr + j; 208 else { 209 m->m_hdr.ar_name = 0; 210 /*LINTED*/ /* MSG_INTL(EFMT_ARSTRNM) */ 211 m->m_err = (int)EFMT_ARSTRNM; 212 } 213 } else if (f->ar_name[1] == ' ') /* "/" */ 214 m->m_name[1] = '\0'; 215 else if (f->ar_name[1] == '/' && f->ar_name[2] == ' ') /* "//" */ 216 m->m_name[2] = '\0'; 217 else { /* "/?" */ 218 m->m_hdr.ar_name = 0; 219 /*LINTED*/ /* MSG_INTL(EFMT_ARUNKNM) */ 220 m->m_err = (int)EFMT_ARUNKNM; 221 } 222 223 m->m_hdr.ar_date = (time_t)_elf_number(f->ar_date, 224 &f->ar_date[ARSZ(ar_date)], 10); 225 /* LINTED */ 226 m->m_hdr.ar_uid = (uid_t)_elf_number(f->ar_uid, 227 &f->ar_uid[ARSZ(ar_uid)], 10); 228 /* LINTED */ 229 m->m_hdr.ar_gid = (gid_t)_elf_number(f->ar_gid, 230 &f->ar_gid[ARSZ(ar_gid)], 10); 231 /* LINTED */ 232 m->m_hdr.ar_mode = (mode_t)_elf_number(f->ar_mode, 233 &f->ar_mode[ARSZ(ar_mode)], 8); 234 m->m_hdr.ar_size = (off_t)_elf_number(f->ar_size, 235 &f->ar_size[ARSZ(ar_size)], 10); 236 237 return (m); 238 } 239 240 241 /* 242 * Initial archive processing 243 * An archive may have two special members. 244 * A symbol table, named /, must be first if it is present. 245 * A string table, named //, must precede all "normal" members. 246 * 247 * This code "peeks" at headers but doesn't change them. 248 * Later processing wants original headers. 249 * 250 * String table is converted, changing '/' name terminators 251 * to nulls. The last byte in the string table, which should 252 * be '\n', is set to nil, guaranteeing null termination. That 253 * byte should be '\n', but this code doesn't check. 254 * 255 * The symbol table conversion is delayed until needed. 256 */ 257 void 258 _elf_arinit(Elf * elf) 259 { 260 char *base = elf->ed_ident; 261 register char *end = base + elf->ed_fsz; 262 register struct ar_hdr *a; 263 register char *hdr = base + SARMAG; 264 register char *mem; 265 int j; 266 size_t sz = SARMAG; 267 268 elf->ed_status = ES_COOKED; 269 elf->ed_nextoff = SARMAG; 270 for (j = 0; j < 2; ++j) { /* 2 special members */ 271 unsigned long n; 272 273 if (((end - hdr) < sizeof (struct ar_hdr)) || 274 (_elf_vm(elf, (size_t)(SARMAG), 275 sizeof (struct ar_hdr)) != OK_YES)) 276 return; 277 278 a = (struct ar_hdr *)hdr; 279 mem = (char *)a + sizeof (struct ar_hdr); 280 n = _elf_number(a->ar_size, &a->ar_size[ARSZ(ar_size)], 10); 281 if ((end - mem < n) || (a->ar_name[0] != '/') || 282 ((sz = n) != n)) { 283 return; 284 } 285 286 hdr = mem + sz; 287 if (a->ar_name[1] == ' ') { 288 elf->ed_arsym = mem; 289 elf->ed_arsymsz = sz; 290 elf->ed_arsymoff = (char *)a - base; 291 } else if (a->ar_name[1] == '/' && a->ar_name[2] == ' ') { 292 int k; 293 294 if (_elf_vm(elf, (size_t)(mem - elf->ed_ident), 295 sz) != OK_YES) 296 return; 297 if (elf->ed_vm == 0) { 298 char *nmem; 299 if ((nmem = malloc(sz)) == 0) { 300 _elf_seterr(EMEM_ARSTR, errno); 301 return; 302 } 303 (void) memcpy(nmem, mem, sz); 304 elf->ed_myflags |= EDF_ASTRALLOC; 305 mem = nmem; 306 } 307 308 elf->ed_arstr = mem; 309 elf->ed_arstrsz = sz; 310 elf->ed_arstroff = (char *)a - base; 311 for (k = 0; k < sz; k++) { 312 if (*mem == '/') 313 *mem = '\0'; 314 ++mem; 315 } 316 *(mem - 1) = '\0'; 317 } else { 318 return; 319 } 320 hdr += sz & 1; 321 } 322 } 323