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