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	"%Z%%M%	%I%	%E% SMI"
31
32#include <stdlib.h>
33#include <memory.h>
34#include <errno.h>
35#include "decl.h"
36#include "msg.h"
37
38/*
39 * This module is compiled twice, the second time having
40 * -D_ELF64 defined.  The following set of macros, along
41 * with machelf.h, represent the differences between the
42 * two compilations.  Be careful *not* to add any class-
43 * dependent code (anything that has elf32 or elf64 in the
44 * name) to this code without hiding it behind a switch-
45 * able macro like these.
46 */
47#if	defined(_ELF64)
48
49#define	ELFCLASS	ELFCLASS64
50#define	elf_newphdr	elf64_newphdr
51#define	elf_getehdr	elf64_getehdr
52#define	_elf_msize	_elf64_msize
53#define	elf_fsize	elf64_fsize
54
55#else	/* else ELF32 */
56
57#define	ELFCLASS	ELFCLASS32
58#define	elf_newphdr	elf32_newphdr
59#define	elf_getehdr	elf32_getehdr
60#define	_elf_msize	_elf32_msize
61#define	elf_fsize	elf32_fsize
62
63#endif /* ELF64 */
64
65
66Phdr *
67elf_newphdr(Elf * elf, size_t count)
68{
69	Elf_Void *	ph;
70	size_t		sz;
71	Phdr *		rc;
72	unsigned	work;
73
74	if (elf == 0)
75		return (0);
76	ELFRLOCK(elf)
77	if (elf->ed_class != ELFCLASS) {
78		_elf_seterr(EREQ_CLASS, 0);
79		ELFUNLOCK(elf)
80		return (0);
81	}
82	ELFUNLOCK(elf)
83	if (elf_getehdr(elf) == 0) {		/* this cooks if necessary */
84		_elf_seterr(ESEQ_EHDR, 0);
85		return (0);
86	}
87
88	/*
89	 * Free the existing header if appropriate.  This could reuse
90	 * existing space if big enough, but that's unlikely, benefit
91	 * would be negligible, and code would be more complicated.
92	 */
93
94	ELFWLOCK(elf)
95	if (elf->ed_myflags & EDF_PHALLOC) {
96		elf->ed_myflags &= ~EDF_PHALLOC;
97		rc = elf->ed_phdr;
98		free(rc);
99	}
100
101	/*
102	 * Delete the header if count is zero.
103	 */
104
105	ELFACCESSDATA(work, _elf_work)
106	if ((sz = count * _elf_msize(ELF_T_PHDR, work)) == 0) {
107		elf->ed_phflags &= ~ELF_F_DIRTY;
108		elf->ed_phdr = 0;
109		((Ehdr*)elf->ed_ehdr)->e_phnum = 0;
110		((Ehdr*)elf->ed_ehdr)->e_phentsize = 0;
111		elf->ed_phdrsz = 0;
112		ELFUNLOCK(elf)
113		return (0);
114	}
115
116	if ((ph = malloc(sz)) == 0) {
117		_elf_seterr(EMEM_PHDR, errno);
118		elf->ed_phflags &= ~ELF_F_DIRTY;
119		elf->ed_phdr = 0;
120		((Ehdr*)elf->ed_ehdr)->e_phnum = 0;
121		((Ehdr*)elf->ed_ehdr)->e_phentsize = 0;
122		elf->ed_phdrsz = 0;
123		ELFUNLOCK(elf)
124		return (0);
125	}
126
127	elf->ed_myflags |= EDF_PHALLOC;
128	(void) memset(ph, 0, sz);
129	elf->ed_phflags |= ELF_F_DIRTY;
130	/* LINTED */
131	((Ehdr*)elf->ed_ehdr)->e_phnum = (Half)count;
132	((Ehdr*)elf->ed_ehdr)->e_phentsize
133	    /* LINTED */
134	    = (Half)elf_fsize(ELF_T_PHDR, 1, work);
135	elf->ed_phdrsz = sz;
136	elf->ed_phdr = rc = ph;
137
138	ELFUNLOCK(elf)
139	return (rc);
140}
141