/ external / libelf / libelf_phdr.c
libelf_phdr.c
  1  /*-
  2   * Copyright (c) 2006,2008 Joseph Koshy
  3   * All rights reserved.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright
 11   *    notice, this list of conditions and the following disclaimer in the
 12   *    documentation and/or other materials provided with the distribution.
 13   *
 14   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 15   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 16   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 17   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 18   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 19   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 20   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 21   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 22   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 23   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 24   * SUCH DAMAGE.
 25   */
 26  
 27  #include <sys/cdefs.h>
 28  
 29  #include <assert.h>
 30  #include <gelf.h>
 31  #include <libelf.h>
 32  #include <stdlib.h>
 33  
 34  #include "_libelf.h"
 35  
 36  ELFTC_VCSID("$Id$");
 37  
 38  void *
 39  _libelf_getphdr(Elf *e, int ec)
 40  {
 41  	size_t phnum;
 42  	size_t fsz, msz;
 43  	uint64_t phoff;
 44  	Elf32_Ehdr *eh32;
 45  	Elf64_Ehdr *eh64;
 46  	void *ehdr, *phdr;
 47  	int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s,
 48  	    size_t _c, int _swap);
 49  
 50  	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
 51  
 52  	if (e == NULL) {
 53  		LIBELF_SET_ERROR(ARGUMENT, 0);
 54  		return (NULL);
 55  	}
 56  
 57  	if ((phdr = (ec == ELFCLASS32 ?
 58  		 (void *) e->e_u.e_elf.e_phdr.e_phdr32 :
 59  		 (void *) e->e_u.e_elf.e_phdr.e_phdr64)) != NULL)
 60  		return (phdr);
 61  
 62  	/*
 63  	 * Check the PHDR related fields in the EHDR for sanity.
 64  	 */
 65  
 66  	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
 67  		return (NULL);
 68  
 69  	phnum = e->e_u.e_elf.e_nphdr;
 70  
 71  	if (ec == ELFCLASS32) {
 72  		eh32      = (Elf32_Ehdr *) ehdr;
 73  		phoff     = (uint64_t) eh32->e_phoff;
 74  	} else {
 75  		eh64      = (Elf64_Ehdr *) ehdr;
 76  		phoff     = (uint64_t) eh64->e_phoff;
 77  	}
 78  
 79  	fsz = gelf_fsize(e, ELF_T_PHDR, phnum, e->e_version);
 80  
 81  	assert(fsz > 0);
 82  
 83  	if ((uint64_t) e->e_rawsize < (phoff + fsz)) {
 84  		LIBELF_SET_ERROR(HEADER, 0);
 85  		return (NULL);
 86  	}
 87  
 88  	msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT);
 89  
 90  	assert(msz > 0);
 91  
 92  	if ((phdr = calloc(phnum, msz)) == NULL) {
 93  		LIBELF_SET_ERROR(RESOURCE, 0);
 94  		return (NULL);
 95  	}
 96  
 97  	if (ec == ELFCLASS32)
 98  		e->e_u.e_elf.e_phdr.e_phdr32 = phdr;
 99  	else
100  		e->e_u.e_elf.e_phdr.e_phdr64 = phdr;
101  
102  
103  	xlator = _libelf_get_translator(ELF_T_PHDR, ELF_TOMEMORY, ec);
104  	(*xlator)(phdr, phnum * msz, e->e_rawfile + phoff, phnum,
105  	    e->e_byteorder != LIBELF_PRIVATE(byteorder));
106  
107  	return (phdr);
108  }
109  
110  void *
111  _libelf_newphdr(Elf *e, int ec, size_t count)
112  {
113  	void *ehdr, *newphdr, *oldphdr;
114  	size_t msz;
115  
116  	if (e == NULL) {
117  		LIBELF_SET_ERROR(ARGUMENT, 0);
118  		return (NULL);
119  	}
120  
121  	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) {
122  		LIBELF_SET_ERROR(SEQUENCE, 0);
123  		return (NULL);
124  	}
125  
126  	assert(e->e_class == ec);
127  	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
128  	assert(e->e_version == EV_CURRENT);
129  
130  	msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version);
131  
132  	assert(msz > 0);
133  
134  	newphdr = NULL;
135  	if (count > 0 && (newphdr = calloc(count, msz)) == NULL) {
136  		LIBELF_SET_ERROR(RESOURCE, 0);
137  		return (NULL);
138  	}
139  
140  	if (ec == ELFCLASS32) {
141  		if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr32) != NULL)
142  			free(oldphdr);
143  		e->e_u.e_elf.e_phdr.e_phdr32 = (Elf32_Phdr *) newphdr;
144  	} else {
145  		if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr64) != NULL)
146  			free(oldphdr);
147  		e->e_u.e_elf.e_phdr.e_phdr64 = (Elf64_Phdr *) newphdr;
148  	}
149  
150  	e->e_u.e_elf.e_nphdr = count;
151  
152  	elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY);
153  
154  	return (newphdr);
155  }