105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh/* Return converted data from raw chunk of ELF file.
205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   This file is part of elfutils.
405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   This file is free software; you can redistribute it and/or modify
605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   it under the terms of either
705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh     * the GNU Lesser General Public License as published by the Free
905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh       Software Foundation; either version 3 of the License, or (at
1005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh       your option) any later version
1105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
1205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   or
13b158b93a7d941a52bedd64ca6b78ff18de9b6ca3Nguyen Anh Quynh
1405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh     * the GNU General Public License as published by the Free
1505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh       Software Foundation; either version 2 of the License, or (at
1605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh       your option) any later version
1705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
1805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   or both in parallel, as here.
1905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
2005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   elfutils is distributed in the hope that it will be useful, but
2105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   WITHOUT ANY WARRANTY; without even the implied warranty of
2205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   General Public License for more details.
2405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
2505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   You should have received copies of the GNU General Public License and
2605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   the GNU Lesser General Public License along with this program.  If
2705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh   not, see <http://www.gnu.org/licenses/>.  */
2805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
2905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#ifdef HAVE_CONFIG_H
3005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh# include <config.h>
3105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#endif
3205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
3305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <assert.h>
3405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <errno.h>
3505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <stdlib.h>
3605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <string.h>
3705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <unistd.h>
3805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
3905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <system.h>
40159ddbd99fae8c435f815aa5251bb6466160cb91Nguyen Anh Quynh#include "libelfP.h"
4105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include "common.h"
4205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
4305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh QuynhElf_Data *
4405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynhelf_getdata_rawchunk (Elf *elf, off_t offset, size_t size, Elf_Type type)
4505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh{
4605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  if (unlikely (elf == NULL))
4705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    return NULL;
4805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
4905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  if (unlikely (elf->kind != ELF_K_ELF))
5005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
5105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      /* No valid descriptor.  */
5205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      __libelf_seterrno (ELF_E_INVALID_HANDLE);
5305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      return NULL;
5405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
5505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
5605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
5705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh		|| elf->maximum_size - (uint64_t) offset < size))
5805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
5905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
6005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      /* Invalid request.  */
6105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      __libelf_seterrno (ELF_E_INVALID_OP);
6205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      return NULL;
6305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
6405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
6505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  if (type >= ELF_T_NUM)
6605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
6705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
6805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      return NULL;
6905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
7005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
7105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  /* Get the raw bytes from the file.  */
7205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  void *rawchunk;
7305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  int flags = 0;
7405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  Elf_Data *result = NULL;
7505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
7605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  rwlock_rdlock (elf->lock);
7705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
7805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  size_t align = __libelf_type_align (elf->class, type);
7905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  if (elf->map_address != NULL)
8005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
8105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    /* If the file is mmap'ed we can use it directly, if aligned for type.  */
8205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      char *rawdata = elf->map_address + elf->start_offset + offset;
8305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      if (ALLOW_UNALIGNED ||
8405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  ((uintptr_t) rawdata & (align - 1)) == 0)
8505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	rawchunk = rawdata;
8605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      else
8705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	{
8805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  /* We allocate the memory and memcpy it to get aligned data. */
8905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  rawchunk = malloc (size);
9005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  if (rawchunk == NULL)
9105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	    goto nomem;
9205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  memcpy (rawchunk, rawdata, size);
9305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  flags = ELF_F_MALLOCED;
9405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	}
9505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
9605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  else
9705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
9805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      /* We allocate the memory and read the data from the file.  */
9905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      rawchunk = malloc (size);
10005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      if (rawchunk == NULL)
10105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	{
10205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	nomem:
10305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  __libelf_seterrno (ELF_E_NOMEM);
10405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  goto out;
10505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	}
10605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
10705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      /* Read the file content.  */
10805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
10905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh					  elf->start_offset + offset)
11005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh		    != size))
11105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	{
11205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  /* Something went wrong.  */
11305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  free (rawchunk);
11405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  __libelf_seterrno (ELF_E_READ_ERROR);
11505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  goto out;
11605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	}
11705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
11805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      flags = ELF_F_MALLOCED;
11905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
12005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
12105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  /* Copy and/or convert the data as needed for aligned native-order access.  */
12205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  void *buffer;
12305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
12405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
12505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      if (((uintptr_t) rawchunk & (align - 1)) == 0)
12605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	/* No need to copy, we can use the raw data.  */
12705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	buffer = rawchunk;
12805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      else
12905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	{
13005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  /* A malloc'd block is always sufficiently aligned.  */
13105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  assert (flags == 0);
13205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
13305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  buffer = malloc (size);
13405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  if (unlikely (buffer == NULL))
13505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	    goto nomem;
13605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  flags = ELF_F_MALLOCED;
13705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
13805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  /* The copy will be appropriately aligned for direct access.  */
13905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  memcpy (buffer, rawchunk, size);
14005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	}
14105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
14205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  else
14305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
14405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      if (flags)
14505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	buffer = rawchunk;
14605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      else
14705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	{
14805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  buffer = malloc (size);
14905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  if (unlikely (buffer == NULL))
15005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	    goto nomem;
15105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	  flags = ELF_F_MALLOCED;
15205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	}
15305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
15405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      /* Call the conversion function.  */
15505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      (*__elf_xfctstom[LIBELF_EV_IDX][LIBELF_EV_IDX][elf->class - 1][type])
15605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	(buffer, rawchunk, size, 0);
15705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
15805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
15905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  /* Allocate the dummy container to point at this buffer.  */
16005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
16105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  if (chunk == NULL)
16205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    {
16305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      if (flags)
16405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh	free (buffer);
16505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh      goto nomem;
16605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh    }
16705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
16805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->dummy_scn.elf = elf;
16905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->dummy_scn.flags = flags;
17005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->data.s = &chunk->dummy_scn;
17105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->data.d.d_buf = buffer;
17205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->data.d.d_size = size;
17305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->data.d.d_type = type;
17405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->data.d.d_align = align;
17505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->data.d.d_version = __libelf_version;
17605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
17705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  rwlock_unlock (elf->lock);
17805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  rwlock_wrlock (elf->lock);
17905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
18005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  chunk->next = elf->state.elf.rawchunks;
18105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  elf->state.elf.rawchunks = chunk;
18205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  result = &chunk->data.d;
18305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh
18405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh out:
18505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  rwlock_unlock (elf->lock);
18605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh  return result;
18705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh}
18805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh