Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libelf / elf_readall.c
1 /* Read all of the file associated with the descriptor.
2    Copyright (C) 1998-2009 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 <unistd.h>
36 #include <sys/stat.h>
37
38 #include <system.h>
39 #include "libelfP.h"
40 #include "common.h"
41
42
43 static void
44 set_address (Elf *elf, size_t offset)
45 {
46   if (elf->kind == ELF_K_AR)
47     {
48       Elf *child = elf->state.ar.children;
49
50       while (child != NULL)
51         {
52           if (child->map_address == NULL)
53             {
54               child->map_address = elf->map_address;
55               child->start_offset -= offset;
56               if (child->kind == ELF_K_AR)
57                 child->state.ar.offset -= offset;
58
59               set_address (child, offset);
60             }
61
62           child = child->next;
63         }
64     }
65 }
66
67
68 char *
69 __libelf_readall (elf)
70      Elf *elf;
71 {
72   /* Get the file.  */
73   rwlock_wrlock (elf->lock);
74
75   if (elf->map_address == NULL && unlikely (elf->fildes == -1))
76     {
77       __libelf_seterrno (ELF_E_INVALID_HANDLE);
78       rwlock_unlock (elf->lock);
79       return NULL;
80     }
81
82   /* If the file is not mmap'ed and not previously loaded, do it now.  */
83   if (elf->map_address == NULL)
84     {
85       char *mem = NULL;
86
87       /* If this is an archive and we have derived descriptors get the
88          locks for all of them.  */
89       libelf_acquire_all (elf);
90
91       if (elf->maximum_size == ~((size_t) 0))
92         {
93           /* We don't yet know how large the file is.   Determine that now.  */
94           struct stat st;
95
96           if (fstat (elf->fildes, &st) < 0)
97             goto read_error;
98
99           if (sizeof (size_t) >= sizeof (st.st_size)
100               || st.st_size <= ~((size_t) 0))
101             elf->maximum_size = (size_t) st.st_size;
102           else
103             {
104               errno = EOVERFLOW;
105               goto read_error;
106             }
107         }
108
109       /* Allocate all the memory we need.  */
110       mem = (char *) malloc (elf->maximum_size);
111       if (mem != NULL)
112         {
113           /* Read the file content.  */
114           if (unlikely ((size_t) pread_retry (elf->fildes, mem,
115                                               elf->maximum_size,
116                                               elf->start_offset)
117                         != elf->maximum_size))
118             {
119               /* Something went wrong.  */
120             read_error:
121               __libelf_seterrno (ELF_E_READ_ERROR);
122               free (mem);
123             }
124           else
125             {
126               /* Remember the address.  */
127               elf->map_address = mem;
128
129               /* Also remember that we allocated the memory.  */
130               elf->flags |= ELF_F_MALLOCED;
131
132               /* Propagate the information down to all children and
133                  their children.  */
134               set_address (elf, elf->start_offset);
135
136               /* Correct the own offsets.  */
137               if (elf->kind == ELF_K_AR)
138                 elf->state.ar.offset -= elf->start_offset;
139               elf->start_offset = 0;
140             }
141         }
142       else
143         __libelf_seterrno (ELF_E_NOMEM);
144
145       /* Free the locks on the children.  */
146       libelf_release_all (elf);
147     }
148
149   rwlock_unlock (elf->lock);
150
151   return (char *) elf->map_address;
152 }