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