|
Packit Service |
97d2fb |
/* Return converted data from raw chunk of ELF file.
|
|
Packit Service |
97d2fb |
Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
|
|
Packit Service |
97d2fb |
This file is part of elfutils.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
This file is free software; you can redistribute it and/or modify
|
|
Packit Service |
97d2fb |
it under the terms of either
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
* the GNU Lesser General Public License as published by the Free
|
|
Packit Service |
97d2fb |
Software Foundation; either version 3 of the License, or (at
|
|
Packit Service |
97d2fb |
your option) any later version
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
or
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
* the GNU General Public License as published by the Free
|
|
Packit Service |
97d2fb |
Software Foundation; either version 2 of the License, or (at
|
|
Packit Service |
97d2fb |
your option) any later version
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
or both in parallel, as here.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
elfutils is distributed in the hope that it will be useful, but
|
|
Packit Service |
97d2fb |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
97d2fb |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
97d2fb |
General Public License for more details.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
You should have received copies of the GNU General Public License and
|
|
Packit Service |
97d2fb |
the GNU Lesser General Public License along with this program. If
|
|
Packit Service |
97d2fb |
not, see <http://www.gnu.org/licenses/>. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
97d2fb |
# include <config.h>
|
|
Packit Service |
97d2fb |
#endif
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include <assert.h>
|
|
Packit Service |
97d2fb |
#include <errno.h>
|
|
Packit Service |
97d2fb |
#include <stdlib.h>
|
|
Packit Service |
97d2fb |
#include <string.h>
|
|
Packit Service |
97d2fb |
#include <unistd.h>
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include <system.h>
|
|
Packit Service |
97d2fb |
#include "libelfP.h"
|
|
Packit Service |
97d2fb |
#include "common.h"
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Elf_Data *
|
|
Packit Service |
97d2fb |
elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (unlikely (elf == NULL))
|
|
Packit Service |
97d2fb |
return NULL;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (unlikely (elf->kind != ELF_K_ELF))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* No valid descriptor. */
|
|
Packit Service |
97d2fb |
__libelf_seterrno (ELF_E_INVALID_HANDLE);
|
|
Packit Service |
97d2fb |
return NULL;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
|
|
Packit Service |
97d2fb |
|| elf->maximum_size - (uint64_t) offset < size))
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Invalid request. */
|
|
Packit Service |
97d2fb |
__libelf_seterrno (ELF_E_INVALID_OP);
|
|
Packit Service |
97d2fb |
return NULL;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (type >= ELF_T_NUM)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
__libelf_seterrno (ELF_E_UNKNOWN_TYPE);
|
|
Packit Service |
97d2fb |
return NULL;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Get the raw bytes from the file. */
|
|
Packit Service |
97d2fb |
void *rawchunk;
|
|
Packit Service |
97d2fb |
int flags = 0;
|
|
Packit Service |
97d2fb |
Elf_Data *result = NULL;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
rwlock_rdlock (elf->lock);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
size_t align = __libelf_type_align (elf->class, type);
|
|
Packit Service |
97d2fb |
if (elf->map_address != NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* If the file is mmap'ed we can use it directly, if aligned for type. */
|
|
Packit Service |
97d2fb |
char *rawdata = elf->map_address + elf->start_offset + offset;
|
|
Packit Service |
97d2fb |
if (((uintptr_t) rawdata & (align - 1)) == 0)
|
|
Packit Service |
97d2fb |
rawchunk = rawdata;
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* We allocate the memory and memcpy it to get aligned data. */
|
|
Packit Service |
97d2fb |
rawchunk = malloc (size);
|
|
Packit Service |
97d2fb |
if (rawchunk == NULL)
|
|
Packit Service |
97d2fb |
goto nomem;
|
|
Packit Service |
97d2fb |
memcpy (rawchunk, rawdata, size);
|
|
Packit Service |
97d2fb |
flags = ELF_F_MALLOCED;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* We allocate the memory and read the data from the file. */
|
|
Packit Service |
97d2fb |
rawchunk = malloc (size);
|
|
Packit Service |
97d2fb |
if (rawchunk == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
nomem:
|
|
Packit Service |
97d2fb |
__libelf_seterrno (ELF_E_NOMEM);
|
|
Packit Service |
97d2fb |
goto out;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Read the file content. */
|
|
Packit Service |
97d2fb |
if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
|
|
Packit Service |
97d2fb |
elf->start_offset + offset)
|
|
Packit Service |
97d2fb |
!= size))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Something went wrong. */
|
|
Packit Service |
97d2fb |
free (rawchunk);
|
|
Packit Service |
97d2fb |
__libelf_seterrno (ELF_E_READ_ERROR);
|
|
Packit Service |
97d2fb |
goto out;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
flags = ELF_F_MALLOCED;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Copy and/or convert the data as needed for aligned native-order access. */
|
|
Packit Service |
97d2fb |
void *buffer;
|
|
Packit Service |
97d2fb |
if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (((uintptr_t) rawchunk & (align - 1)) == 0)
|
|
Packit Service |
97d2fb |
/* No need to copy, we can use the raw data. */
|
|
Packit Service |
97d2fb |
buffer = rawchunk;
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* A malloc'd block is always sufficiently aligned. */
|
|
Packit Service |
97d2fb |
assert (flags == 0);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
buffer = malloc (size);
|
|
Packit Service |
97d2fb |
if (unlikely (buffer == NULL))
|
|
Packit Service |
97d2fb |
goto nomem;
|
|
Packit Service |
97d2fb |
flags = ELF_F_MALLOCED;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* The copy will be appropriately aligned for direct access. */
|
|
Packit Service |
97d2fb |
memcpy (buffer, rawchunk, size);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (flags)
|
|
Packit Service |
97d2fb |
buffer = rawchunk;
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
buffer = malloc (size);
|
|
Packit Service |
97d2fb |
if (unlikely (buffer == NULL))
|
|
Packit Service |
97d2fb |
goto nomem;
|
|
Packit Service |
97d2fb |
flags = ELF_F_MALLOCED;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Call the conversion function. */
|
|
Packit Service |
97d2fb |
(*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Allocate the dummy container to point at this buffer. */
|
|
Packit Service |
97d2fb |
Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
|
|
Packit Service |
97d2fb |
if (chunk == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (flags)
|
|
Packit Service |
97d2fb |
free (buffer);
|
|
Packit Service |
97d2fb |
goto nomem;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
chunk->dummy_scn.elf = elf;
|
|
Packit Service |
97d2fb |
chunk->dummy_scn.flags = flags;
|
|
Packit Service |
97d2fb |
chunk->data.s = &chunk->dummy_scn;
|
|
Packit Service |
97d2fb |
chunk->data.d.d_buf = buffer;
|
|
Packit Service |
97d2fb |
chunk->data.d.d_size = size;
|
|
Packit Service |
97d2fb |
chunk->data.d.d_type = type;
|
|
Packit Service |
97d2fb |
chunk->data.d.d_align = align;
|
|
Packit Service |
97d2fb |
chunk->data.d.d_version = EV_CURRENT;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
rwlock_unlock (elf->lock);
|
|
Packit Service |
97d2fb |
rwlock_wrlock (elf->lock);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
chunk->next = elf->state.elf.rawchunks;
|
|
Packit Service |
97d2fb |
elf->state.elf.rawchunks = chunk;
|
|
Packit Service |
97d2fb |
result = &chunk->data.d;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
out:
|
|
Packit Service |
97d2fb |
rwlock_unlock (elf->lock);
|
|
Packit Service |
97d2fb |
return result;
|
|
Packit Service |
97d2fb |
}
|