f4fbe660b0dc527fb7e9286d77bbd560d1029248
[platform/upstream/elfutils.git] / libelf / elf_getdata_rawchunk.c
1 /* Return converted data from raw chunk of ELF file.
2    Copyright (C) 2007 Red Hat, Inc.
3    This file is part of elfutils.
4
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7
8      * the GNU Lesser General Public License as published by the Free
9        Software Foundation; either version 3 of the License, or (at
10        your option) any later version
11
12    or
13
14      * the GNU General Public License as published by the Free
15        Software Foundation; either version 2 of the License, or (at
16        your option) any later version
17
18    or both in parallel, as here.
19
20    elfutils is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    General Public License for more details.
24
25    You should have received copies of the GNU General Public License and
26    the GNU Lesser General Public License along with this program.  If
27    not, see <http://www.gnu.org/licenses/>.  */
28
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include <system.h>
40 #include "libelfP.h"
41 #include "common.h"
42
43 Elf_Data *
44 elf_getdata_rawchunk (elf, offset, size, type)
45      Elf *elf;
46      off64_t offset;
47      size_t size;
48      Elf_Type type;
49 {
50   if (unlikely (elf == NULL))
51     return NULL;
52
53   if (unlikely (elf->kind != ELF_K_ELF))
54     {
55       /* No valid descriptor.  */
56       __libelf_seterrno (ELF_E_INVALID_HANDLE);
57       return NULL;
58     }
59
60   if (unlikely (offset < 0 || offset + (off64_t) size < offset
61                 || offset + size > elf->maximum_size))
62     {
63       /* Invalid request.  */
64       __libelf_seterrno (ELF_E_INVALID_OP);
65       return NULL;
66     }
67
68   if (type >= ELF_T_NUM)
69     {
70       __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
71       return NULL;
72     }
73
74   /* Get the raw bytes from the file.  */
75   void *rawchunk;
76   int flags = 0;
77   Elf_Data *result = NULL;
78
79   rwlock_rdlock (elf->lock);
80
81   /* If the file is mmap'ed we can use it directly.  */
82   if (elf->map_address != NULL)
83     rawchunk = elf->map_address + elf->start_offset + offset;
84   else
85     {
86       /* We allocate the memory and read the data from the file.  */
87       rawchunk = malloc (size);
88       if (rawchunk == NULL)
89         {
90         nomem:
91           __libelf_seterrno (ELF_E_NOMEM);
92           goto out;
93         }
94
95       /* Read the file content.  */
96       if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
97                                           elf->start_offset + offset)
98                     != size))
99         {
100           /* Something went wrong.  */
101           free (rawchunk);
102           __libelf_seterrno (ELF_E_READ_ERROR);
103           goto out;
104         }
105
106       flags = ELF_F_MALLOCED;
107     }
108
109   /* Copy and/or convert the data as needed for aligned native-order access.  */
110   size_t align = __libelf_type_align (elf->class, type);
111   void *buffer;
112   if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
113     {
114       if (((uintptr_t) rawchunk & (align - 1)) == 0)
115         /* No need to copy, we can use the raw data.  */
116         buffer = rawchunk;
117       else
118         {
119           /* A malloc'd block is always sufficiently aligned.  */
120           assert (flags == 0);
121
122           buffer = malloc (size);
123           if (unlikely (buffer == NULL))
124             goto nomem;
125           flags = ELF_F_MALLOCED;
126
127           /* The copy will be appropriately aligned for direct access.  */
128           memcpy (buffer, rawchunk, size);
129         }
130     }
131   else
132     {
133       if (flags)
134         buffer = rawchunk;
135       else
136         {
137           buffer = malloc (size);
138           if (unlikely (buffer == NULL))
139             goto nomem;
140           flags = ELF_F_MALLOCED;
141         }
142
143       /* Call the conversion function.  */
144       (*__elf_xfctstom[LIBELF_EV_IDX][LIBELF_EV_IDX][elf->class - 1][type])
145         (buffer, rawchunk, size, 0);
146     }
147
148   /* Allocate the dummy container to point at this buffer.  */
149   Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
150   if (chunk == NULL)
151     {
152       if (flags)
153         free (buffer);
154       goto nomem;
155     }
156
157   chunk->dummy_scn.elf = elf;
158   chunk->dummy_scn.flags = flags;
159   chunk->data.s = &chunk->dummy_scn;
160   chunk->data.d.d_buf = buffer;
161   chunk->data.d.d_size = size;
162   chunk->data.d.d_type = type;
163   chunk->data.d.d_align = align;
164   chunk->data.d.d_version = __libelf_version;
165
166   rwlock_unlock (elf->lock);
167   rwlock_wrlock (elf->lock);
168
169   chunk->next = elf->state.elf.rawchunks;
170   elf->state.elf.rawchunks = chunk;
171   result = &chunk->data.d;
172
173  out:
174   rwlock_unlock (elf->lock);
175   return result;
176 }