Home | History | Annotate | Download | only in libelf
      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 
     43 Elf_Data *
     44 elf_getdata_rawchunk (Elf *elf, off_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