159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath/* Return converted data from raw chunk of ELF file.
21ccdfb683ad6c7e59793136c3a657ddf131cafd1Mark Wielaard   Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
3de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is part of elfutils.
4b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
5de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is free software; you can redistribute it and/or modify
6de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   it under the terms of either
7b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
8de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU Lesser General Public License as published by the Free
9de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 3 of the License, or (at
10de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
11de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
12de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or
13de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
14de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU General Public License as published by the Free
15de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 2 of the License, or (at
16de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
17de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
18de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or both in parallel, as here.
19de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
20de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   elfutils is distributed in the hope that it will be useful, but
21361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   WITHOUT ANY WARRANTY; without even the implied warranty of
22361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   General Public License for more details.
24b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
25de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   You should have received copies of the GNU General Public License and
26de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   the GNU Lesser General Public License along with this program.  If
27de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   not, see <http://www.gnu.org/licenses/>.  */
28b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
29b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#ifdef HAVE_CONFIG_H
30b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper# include <config.h>
31b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#endif
32b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
3359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath#include <assert.h>
34fbe998a0b1be1f006bc72e5138fb38c188cc0433Ulrich Drepper#include <errno.h>
35b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <stdlib.h>
3659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath#include <string.h>
37b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <unistd.h>
38b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
39fbe998a0b1be1f006bc72e5138fb38c188cc0433Ulrich Drepper#include <system.h>
40b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include "libelfP.h"
4159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath#include "common.h"
42b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
4359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrathElf_Data *
443425454a10d307fae891fb667cf7969e945cde79Josh Stoneelf_getdata_rawchunk (Elf *elf, off_t offset, size_t size, Elf_Type type)
45b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper{
4659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  if (unlikely (elf == NULL))
4759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    return NULL;
4859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
4959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  if (unlikely (elf->kind != ELF_K_ELF))
50b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
51b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      /* No valid descriptor.  */
52b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      __libelf_seterrno (ELF_E_INVALID_HANDLE);
53b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      return NULL;
54b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
55b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
56f62658f71fdcf6a51e0dac1bfe4ab082be03bb8aMark Wielaard  if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
57f62658f71fdcf6a51e0dac1bfe4ab082be03bb8aMark Wielaard		|| elf->maximum_size - (uint64_t) offset < size))
58f62658f71fdcf6a51e0dac1bfe4ab082be03bb8aMark Wielaard
59b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
60b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      /* Invalid request.  */
61b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      __libelf_seterrno (ELF_E_INVALID_OP);
62b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      return NULL;
63b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
64b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
6559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  if (type >= ELF_T_NUM)
6659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    {
6759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
6859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      return NULL;
6959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    }
7059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
7159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  /* Get the raw bytes from the file.  */
7259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  void *rawchunk;
7359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  int flags = 0;
7402f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper  Elf_Data *result = NULL;
7502f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper
7602f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper  rwlock_rdlock (elf->lock);
7759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
78ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard  size_t align = __libelf_type_align (elf->class, type);
79b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if (elf->map_address != NULL)
80ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard    {
81ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard    /* If the file is mmap'ed we can use it directly, if aligned for type.  */
82ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard      char *rawdata = elf->map_address + elf->start_offset + offset;
83ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard      if (ALLOW_UNALIGNED ||
84ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	  ((uintptr_t) rawdata & (align - 1)) == 0)
85ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	rawchunk = rawdata;
86ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard      else
87ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	{
88ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	  /* We allocate the memory and memcpy it to get aligned data. */
89ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	  rawchunk = malloc (size);
90ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	  if (rawchunk == NULL)
91ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	    goto nomem;
92ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	  memcpy (rawchunk, rawdata, size);
93ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	  flags = ELF_F_MALLOCED;
94ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard	}
95ede1d9d8aa4b04810e1ee04fcec9386e63f48d77Mark Wielaard    }
9659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  else
9759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    {
9859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      /* We allocate the memory and read the data from the file.  */
9959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      rawchunk = malloc (size);
10059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (rawchunk == NULL)
10159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	{
10259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	nomem:
10359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  __libelf_seterrno (ELF_E_NOMEM);
10402f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper	  goto out;
10559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	}
10659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
10759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      /* Read the file content.  */
10859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
10959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath					  elf->start_offset + offset)
11059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath		    != size))
11159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	{
11259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  /* Something went wrong.  */
11359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  free (rawchunk);
11459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  __libelf_seterrno (ELF_E_READ_ERROR);
11502f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper	  goto out;
11659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	}
117b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
11859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      flags = ELF_F_MALLOCED;
11959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    }
12059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
12159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  /* Copy and/or convert the data as needed for aligned native-order access.  */
12259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  void *buffer;
12359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
12459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    {
12559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (((uintptr_t) rawchunk & (align - 1)) == 0)
12659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	/* No need to copy, we can use the raw data.  */
12759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	buffer = rawchunk;
12859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      else
12959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	{
13059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  /* A malloc'd block is always sufficiently aligned.  */
13159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  assert (flags == 0);
13259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
13359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  buffer = malloc (size);
13459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  if (unlikely (buffer == NULL))
13559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	    goto nomem;
13659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  flags = ELF_F_MALLOCED;
13759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
13859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  /* The copy will be appropriately aligned for direct access.  */
13959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  memcpy (buffer, rawchunk, size);
14059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	}
14159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    }
142b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  else
14359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    {
14459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (flags)
14559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	buffer = rawchunk;
14659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      else
14759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	{
14859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  buffer = malloc (size);
14959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  if (unlikely (buffer == NULL))
15059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	    goto nomem;
15159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  flags = ELF_F_MALLOCED;
15259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	}
15359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
15459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      /* Call the conversion function.  */
15559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      (*__elf_xfctstom[LIBELF_EV_IDX][LIBELF_EV_IDX][elf->class - 1][type])
15659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	(buffer, rawchunk, size, 0);
15759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    }
15859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
15959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  /* Allocate the dummy container to point at this buffer.  */
16059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
16159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  if (chunk == NULL)
16259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    {
16359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (flags)
16459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	free (buffer);
16559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      goto nomem;
16659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    }
16759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
16859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->dummy_scn.elf = elf;
16959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->dummy_scn.flags = flags;
17059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->data.s = &chunk->dummy_scn;
17159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->data.d.d_buf = buffer;
17259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->data.d.d_size = size;
17359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->data.d.d_type = type;
17459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->data.d.d_align = align;
17559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->data.d.d_version = __libelf_version;
17659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
17702f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper  rwlock_unlock (elf->lock);
17802f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper  rwlock_wrlock (elf->lock);
17902f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper
18059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  chunk->next = elf->state.elf.rawchunks;
18159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  elf->state.elf.rawchunks = chunk;
18202f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper  result = &chunk->data.d;
18359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
18402f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper out:
18502f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper  rwlock_unlock (elf->lock);
18602f66452635df3d01f7e57845c3362ab828e3d89Ulrich Drepper  return result;
187b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper}
188