1/* Get ELF program header table.
2   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
3   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, version 2.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software Foundation,
16   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdlib.h>
23#include <unistd.h>
24
25#include "libelfP.h"
26#include "common.h"
27
28#ifndef LIBELFBITS
29# define LIBELFBITS 32
30#endif
31
32
33ElfW2(LIBELFBITS,Phdr) *
34elfw2(LIBELFBITS,getphdr) (elf)
35     Elf *elf;
36{
37  ElfW2(LIBELFBITS,Phdr) *result;
38
39  if (elf == NULL)
40    return NULL;
41
42  if (unlikely (elf->kind != ELF_K_ELF))
43    {
44      __libelf_seterrno (ELF_E_INVALID_HANDLE);
45      return NULL;
46    }
47
48  /* If the program header entry has already been filled in the code
49     below must already have been run.  So the class is set, too.  No
50     need to waste any more time here.  */
51  result = elf->state.ELFW(elf,LIBELFBITS).phdr;
52  if (likely (result != NULL))
53    return result;
54
55  rwlock_wrlock (elf->lock);
56
57  if (elf->class == 0)
58    elf->class = ELFW(ELFCLASS,LIBELFBITS);
59  else if (elf->class != ELFW(ELFCLASS,LIBELFBITS))
60    {
61      __libelf_seterrno (ELF_E_INVALID_CLASS);
62      result = NULL;
63      goto out;
64    }
65
66  if (likely (result == NULL))
67    {
68      /* Read the section header table.  */
69      ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
70      size_t phnum;
71      size_t size;
72
73      /* If no program header exists return NULL.  */
74      phnum = ehdr->e_phnum;
75      if (phnum == 0)
76	{
77	  __libelf_seterrno (ELF_E_NO_PHDR);
78	  goto out;
79	}
80
81      size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr));
82
83      if (elf->map_address != NULL)
84	{
85	  /* All the data is already mapped.  Use it.  */
86	  if (ehdr->e_ident[EI_DATA] == MY_ELFDATA
87	      && (ALLOW_UNALIGNED
88		  || (ehdr->e_phoff
89		      & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0))
90	    /* Simply use the mapped data.  */
91	    elf->state.ELFW(elf,LIBELFBITS).phdr = (ElfW2(LIBELFBITS,Phdr) *)
92	      ((char *) elf->map_address + elf->start_offset + ehdr->e_phoff);
93	  else
94	    {
95	      size_t cnt;
96	      ElfW2(LIBELFBITS,Phdr) *notcvt;
97	      ElfW2(LIBELFBITS,Phdr) *phdr;
98
99	      /* Allocate memory for the program headers.  We know the number
100		 of entries from the ELF header.  */
101	      phdr = elf->state.ELFW(elf,LIBELFBITS).phdr =
102		(ElfW2(LIBELFBITS,Phdr) *) malloc (size);
103	      if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
104		{
105		  __libelf_seterrno (ELF_E_NOMEM);
106		  goto out;
107		}
108	      elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
109		ELF_F_MALLOCED | ELF_F_DIRTY;
110
111	      /* Now copy the data and at the same time convert the
112		 byte order.  */
113	      if (ALLOW_UNALIGNED
114		  || (ehdr->e_phoff
115		      & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0)
116		notcvt = (ElfW2(LIBELFBITS,Phdr) *)
117		  ((char *) elf->map_address
118		   + elf->start_offset + ehdr->e_phoff);
119	      else
120		{
121		  notcvt = (ElfW2(LIBELFBITS,Phdr) *) alloca (size);
122		  memcpy (notcvt, ((char *) elf->map_address +
123				   elf->start_offset + ehdr->e_phoff),
124			  size);
125		}
126
127	      for (cnt = 0; cnt < phnum; ++cnt)
128		{
129		  CONVERT_TO (phdr[cnt].p_type, notcvt[cnt].p_type);
130		  CONVERT_TO (phdr[cnt].p_offset, notcvt[cnt].p_offset);
131		  CONVERT_TO (phdr[cnt].p_vaddr, notcvt[cnt].p_vaddr);
132		  CONVERT_TO (phdr[cnt].p_paddr, notcvt[cnt].p_paddr);
133		  CONVERT_TO (phdr[cnt].p_filesz, notcvt[cnt].p_filesz);
134		  CONVERT_TO (phdr[cnt].p_memsz, notcvt[cnt].p_memsz);
135		  CONVERT_TO (phdr[cnt].p_flags, notcvt[cnt].p_flags);
136		  CONVERT_TO (phdr[cnt].p_align, notcvt[cnt].p_align);
137		}
138	    }
139	}
140      else if (likely (elf->fildes != -1))
141	{
142	  /* Allocate memory for the program headers.  We know the number
143	     of entries from the ELF header.  */
144	  elf->state.ELFW(elf,LIBELFBITS).phdr =
145	    (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
146	  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
147	    {
148	      __libelf_seterrno (ELF_E_NOMEM);
149	      goto out;
150	    }
151	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_MALLOCED;
152
153	  /* Read the header.  */
154	  if ((size_t) pread (elf->fildes,
155			      elf->state.ELFW(elf,LIBELFBITS).phdr, size,
156			      (elf->start_offset + ehdr->e_phoff)) != size)
157	    {
158	      /* Severe problems.  We cannot read the data.  */
159	      __libelf_seterrno (ELF_E_READ_ERROR);
160	      free (elf->state.ELFW(elf,LIBELFBITS).phdr);
161	      elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
162	      goto out;
163	    }
164
165	  /* If the byte order of the file is not the same as the one
166	     of the host convert the data now.  */
167	  if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
168	    {
169	      ElfW2(LIBELFBITS,Phdr) *phdr;
170	      size_t cnt;
171
172	      phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
173	      for (cnt = 0; cnt < phnum; ++cnt)
174		{
175		  CONVERT (phdr[cnt].p_type);
176		  CONVERT (phdr[cnt].p_offset);
177		  CONVERT (phdr[cnt].p_vaddr);
178		  CONVERT (phdr[cnt].p_paddr);
179		  CONVERT (phdr[cnt].p_filesz);
180		  CONVERT (phdr[cnt].p_memsz);
181		  CONVERT (phdr[cnt].p_flags);
182		  CONVERT (phdr[cnt].p_align);
183		}
184	    }
185	}
186      else
187	{
188	  /* The file descriptor was already enabled and not all data was
189	     read.  */
190	  __libelf_seterrno (ELF_E_FD_DISABLED);
191	  goto out;
192	}
193
194      result = elf->state.ELFW(elf,LIBELFBITS).phdr;
195    }
196
197 out:
198  rwlock_unlock (elf->lock);
199
200  return result;
201}
202INTDEF(elfw2(LIBELFBITS,getphdr))
203