xref: /third_party/elfutils/libelf/elf_readall.c (revision da0c48c4)
1/* Read all of the file associated with the descriptor.
2   Copyright (C) 1998-2009, 2015 Red Hat, Inc.
3   This file is part of elfutils.
4   Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
5
6   This file is free software; you can redistribute it and/or modify
7   it under the terms of either
8
9     * the GNU Lesser General Public License as published by the Free
10       Software Foundation; either version 3 of the License, or (at
11       your option) any later version
12
13   or
14
15     * the GNU General Public License as published by the Free
16       Software Foundation; either version 2 of the License, or (at
17       your option) any later version
18
19   or both in parallel, as here.
20
21   elfutils is distributed in the hope that it will be useful, but
22   WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   General Public License for more details.
25
26   You should have received copies of the GNU General Public License and
27   the GNU Lesser General Public License along with this program.  If
28   not, see <http://www.gnu.org/licenses/>.  */
29
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <errno.h>
35#include <sys/stat.h>
36
37#include "libelfP.h"
38#include "common.h"
39
40
41static void
42set_address (Elf *elf, size_t offset)
43{
44  if (elf->kind == ELF_K_AR)
45    {
46      Elf *child = elf->state.ar.children;
47
48      while (child != NULL)
49	{
50	  if (child->map_address == NULL)
51	    {
52	      child->map_address = elf->map_address;
53	      child->start_offset -= offset;
54	      if (child->kind == ELF_K_AR)
55		child->state.ar.offset -= offset;
56
57	      set_address (child, offset);
58	    }
59
60	  child = child->next;
61	}
62    }
63}
64
65
66char *
67internal_function
68__libelf_readall (Elf *elf)
69{
70  /* Get the file.  */
71  rwlock_wrlock (elf->lock);
72
73  if (elf->map_address == NULL && unlikely (elf->fildes == -1))
74    {
75      __libelf_seterrno (ELF_E_INVALID_HANDLE);
76      rwlock_unlock (elf->lock);
77      return NULL;
78    }
79
80  /* If the file is not mmap'ed and not previously loaded, do it now.  */
81  if (elf->map_address == NULL)
82    {
83      char *mem = NULL;
84
85      /* If this is an archive and we have derived descriptors get the
86	 locks for all of them.  */
87      libelf_acquire_all (elf);
88
89      if (elf->maximum_size == ~((size_t) 0))
90	{
91	  /* We don't yet know how large the file is.   Determine that now.  */
92	  struct stat st;
93
94	  if (fstat (elf->fildes, &st) < 0)
95	    goto read_error;
96
97	  if (sizeof (size_t) >= sizeof (st.st_size)
98	      || st.st_size <= ~((size_t) 0))
99	    elf->maximum_size = (size_t) st.st_size;
100	  else
101	    {
102	      errno = EOVERFLOW;
103	      goto read_error;
104	    }
105	}
106
107      /* Allocate all the memory we need.  */
108      mem = malloc (elf->maximum_size);
109      if (mem != NULL)
110	{
111	  /* Read the file content.  */
112	  if (unlikely ((size_t) pread_retry (elf->fildes, mem,
113					      elf->maximum_size,
114					      elf->start_offset)
115			!= elf->maximum_size))
116	    {
117	      /* Something went wrong.  */
118	    read_error:
119	      __libelf_seterrno (ELF_E_READ_ERROR);
120	      free (mem);
121	    }
122	  else
123	    {
124	      /* Remember the address.  */
125	      elf->map_address = mem;
126
127	      /* Also remember that we allocated the memory.  */
128	      elf->flags |= ELF_F_MALLOCED;
129
130	      /* Propagate the information down to all children and
131		 their children.  */
132	      set_address (elf, elf->start_offset);
133
134	      /* Correct the own offsets.  */
135	      if (elf->kind == ELF_K_AR)
136		elf->state.ar.offset -= elf->start_offset;
137	      elf->start_offset = 0;
138	    }
139	}
140      else
141	__libelf_seterrno (ELF_E_NOMEM);
142
143      /* Free the locks on the children.  */
144      libelf_release_all (elf);
145    }
146
147  rwlock_unlock (elf->lock);
148
149  return (char *) elf->map_address;
150}
151