elf_getdata_rawchunk.c revision 1ccdfb683ad6c7e59793136c3a657ddf131cafd1
1/* Return converted data from raw chunk of ELF file.
2   Copyright (C) 2007, 2014, 2015 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
43Elf_Data *
44elf_getdata_rawchunk (Elf *elf, off64_t offset, size_t size, Elf_Type type)
45{
46  if (unlikely (elf == NULL))
47    return NULL;
48
49  if (unlikely (elf->kind != ELF_K_ELF))
50    {
51      /* No valid descriptor.  */
52      __libelf_seterrno (ELF_E_INVALID_HANDLE);
53      return NULL;
54    }
55
56  if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
57		|| elf->maximum_size - (uint64_t) offset < size))
58
59    {
60      /* Invalid request.  */
61      __libelf_seterrno (ELF_E_INVALID_OP);
62      return NULL;
63    }
64
65  if (type >= ELF_T_NUM)
66    {
67      __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
68      return NULL;
69    }
70
71  /* Get the raw bytes from the file.  */
72  void *rawchunk;
73  int flags = 0;
74  Elf_Data *result = NULL;
75
76  rwlock_rdlock (elf->lock);
77
78  size_t align = __libelf_type_align (elf->class, type);
79  if (elf->map_address != NULL)
80    {
81    /* If the file is mmap'ed we can use it directly, if aligned for type.  */
82      char *rawdata = elf->map_address + elf->start_offset + offset;
83      if (ALLOW_UNALIGNED ||
84	  ((uintptr_t) rawdata & (align - 1)) == 0)
85	rawchunk = rawdata;
86      else
87	{
88	  /* We allocate the memory and memcpy it to get aligned data. */
89	  rawchunk = malloc (size);
90	  if (rawchunk == NULL)
91	    goto nomem;
92	  memcpy (rawchunk, rawdata, size);
93	  flags = ELF_F_MALLOCED;
94	}
95    }
96  else
97    {
98      /* We allocate the memory and read the data from the file.  */
99      rawchunk = malloc (size);
100      if (rawchunk == NULL)
101	{
102	nomem:
103	  __libelf_seterrno (ELF_E_NOMEM);
104	  goto out;
105	}
106
107      /* Read the file content.  */
108      if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
109					  elf->start_offset + offset)
110		    != size))
111	{
112	  /* Something went wrong.  */
113	  free (rawchunk);
114	  __libelf_seterrno (ELF_E_READ_ERROR);
115	  goto out;
116	}
117
118      flags = ELF_F_MALLOCED;
119    }
120
121  /* Copy and/or convert the data as needed for aligned native-order access.  */
122  void *buffer;
123  if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
124    {
125      if (((uintptr_t) rawchunk & (align - 1)) == 0)
126	/* No need to copy, we can use the raw data.  */
127	buffer = rawchunk;
128      else
129	{
130	  /* A malloc'd block is always sufficiently aligned.  */
131	  assert (flags == 0);
132
133	  buffer = malloc (size);
134	  if (unlikely (buffer == NULL))
135	    goto nomem;
136	  flags = ELF_F_MALLOCED;
137
138	  /* The copy will be appropriately aligned for direct access.  */
139	  memcpy (buffer, rawchunk, size);
140	}
141    }
142  else
143    {
144      if (flags)
145	buffer = rawchunk;
146      else
147	{
148	  buffer = malloc (size);
149	  if (unlikely (buffer == NULL))
150	    goto nomem;
151	  flags = ELF_F_MALLOCED;
152	}
153
154      /* Call the conversion function.  */
155      (*__elf_xfctstom[LIBELF_EV_IDX][LIBELF_EV_IDX][elf->class - 1][type])
156	(buffer, rawchunk, size, 0);
157    }
158
159  /* Allocate the dummy container to point at this buffer.  */
160  Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
161  if (chunk == NULL)
162    {
163      if (flags)
164	free (buffer);
165      goto nomem;
166    }
167
168  chunk->dummy_scn.elf = elf;
169  chunk->dummy_scn.flags = flags;
170  chunk->data.s = &chunk->dummy_scn;
171  chunk->data.d.d_buf = buffer;
172  chunk->data.d.d_size = size;
173  chunk->data.d.d_type = type;
174  chunk->data.d.d_align = align;
175  chunk->data.d.d_version = __libelf_version;
176
177  rwlock_unlock (elf->lock);
178  rwlock_wrlock (elf->lock);
179
180  chunk->next = elf->state.elf.rawchunks;
181  elf->state.elf.rawchunks = chunk;
182  result = &chunk->data.d;
183
184 out:
185  rwlock_unlock (elf->lock);
186  return result;
187}
188