xsplice: Implement payload loading

Add support for loading xsplice payloads. This is somewhat similar to
the Linux kernel module loader, implementing the following steps:
- Verify the elf file.
- Parse the elf file.
- Allocate a region of memory mapped within a free area of
  [xen_virt_end, XEN_VIRT_END].
- Copy allocated sections into the new region. Split them in three
  regions - .text, .data, and .rodata. MUST have at least .text.
- Resolve section symbols. All other symbols must be absolute addresses.
  (Note that patch titled "xsplice,symbols: Implement symbol name resolution
   on address" implements that)
- Perform relocations.
- Secure the the regions (.text,.data,.rodata) with proper permissions.

We capitalize on the vmalloc callback API (see patch titled:
"rm/x86/vmap: Add v[z|m]alloc_xen, and vm_init_type") to allocate
a region of memory within the [xen_virt_end, XEN_VIRT_END] for the code.

We also use the "x86/mm: Introduce modify_xen_mappings()"
to change the virtual address page-table permissions.

Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Acked-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Wei Liu <wei.liu2@citrix.com>
This commit is contained in:
Ross Lagerwall authored and Konrad Rzeszutek Wilk committed 2016-04-29 03:58:23 -04:00
1 parent 18adaa9da0
commit 380b229634
9 files changed
+603 -5

No files matched your search

+1
View File
@@ -40,6 +40,7 @@ obj-y += device.o
obj-y += decode.o
obj-y += processor.o
obj-y += smc.o
obj-$(CONFIG_XSPLICE) += xsplice.o
#obj-bin-y += ....o
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2016 Citrix Systems R&D Ltd.
*/
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/xsplice_elf.h>
#include <xen/xsplice.h>
int arch_xsplice_verify_elf(const struct xsplice_elf *elf)
{
return -ENOSYS;
}
int arch_xsplice_perform_rel(struct xsplice_elf *elf,
const struct xsplice_elf_sec *base,
const struct xsplice_elf_sec *rela)
{
return -ENOSYS;
}
int arch_xsplice_perform_rela(struct xsplice_elf *elf,
const struct xsplice_elf_sec *base,
const struct xsplice_elf_sec *rela)
{
return -ENOSYS;
}
int arch_xsplice_secure(const void *va, unsigned int pages, enum va_type type)
{
return -ENOSYS;
}
void __init arch_xsplice_init(void)
{
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
+1
View File
@@ -61,6 +61,7 @@ obj-y += x86_emulate.o
obj-y += tboot.o
obj-y += hpet.o
obj-y += vm_event.o
obj-$(CONFIG_XSPLICE) += xsplice.o
obj-y += xstate.o
obj-$(crash_debug) += gdbstub.o
+173
View File
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2016 Citrix Systems R&D Ltd.
*/
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/mm.h>
#include <xen/pfn.h>
#include <xen/vmap.h>
#include <xen/xsplice_elf.h>
#include <xen/xsplice.h>
int arch_xsplice_verify_elf(const struct xsplice_elf *elf)
{
const Elf_Ehdr *hdr = elf->hdr;
if ( hdr->e_machine != EM_X86_64 ||
hdr->e_ident[EI_CLASS] != ELFCLASS64 ||
hdr->e_ident[EI_DATA] != ELFDATA2LSB )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Unsupported ELF Machine type!\n",
elf->name);
return -EOPNOTSUPP;
}
return 0;
}
int arch_xsplice_perform_rel(struct xsplice_elf *elf,
const struct xsplice_elf_sec *base,
const struct xsplice_elf_sec *rela)
{
dprintk(XENLOG_ERR, XSPLICE "%s: SHT_REL relocation unsupported\n",
elf->name);
return -EOPNOTSUPP;
}
int arch_xsplice_perform_rela(struct xsplice_elf *elf,
const struct xsplice_elf_sec *base,
const struct xsplice_elf_sec *rela)
{
const Elf_RelA *r;
unsigned int symndx, i;
uint64_t val;
uint8_t *dest;
/* Nothing to do. */
if ( !rela->sec->sh_size )
return 0;
if ( rela->sec->sh_entsize < sizeof(Elf_RelA) ||
rela->sec->sh_size % rela->sec->sh_entsize )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Section relative header is corrupted!\n",
elf->name);
return -EINVAL;
}
for ( i = 0; i < (rela->sec->sh_size / rela->sec->sh_entsize); i++ )
{
r = rela->data + i * rela->sec->sh_entsize;
symndx = ELF64_R_SYM(r->r_info);
if ( symndx > elf->nsym )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Relative relocation wants symbol@%u which is past end!\n",
elf->name, symndx);
return -EINVAL;
}
dest = base->load_addr + r->r_offset;
val = r->r_addend + elf->sym[symndx].sym->st_value;
switch ( ELF64_R_TYPE(r->r_info) )
{
case R_X86_64_NONE:
break;
case R_X86_64_64:
if ( r->r_offset >= base->sec->sh_size ||
(r->r_offset + sizeof(uint64_t)) > base->sec->sh_size )
goto bad_offset;
*(uint64_t *)dest = val;
break;
case R_X86_64_PLT32:
/*
* Xen uses -fpic which normally uses PLT relocations
* except that it sets visibility to hidden which means
* that they are not used. However, when gcc cannot
* inline memcpy it emits memcpy with default visibility
* which then creates a PLT relocation. It can just be
* treated the same as R_X86_64_PC32.
*/
case R_X86_64_PC32:
if ( r->r_offset >= base->sec->sh_size ||
(r->r_offset + sizeof(uint32_t)) > base->sec->sh_size )
goto bad_offset;
val -= (uint64_t)dest;
*(int32_t *)dest = val;
if ( (int64_t)val != *(int32_t *)dest )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Overflow in relocation %u in %s for %s!\n",
elf->name, i, rela->name, base->name);
return -EOVERFLOW;
}
break;
default:
dprintk(XENLOG_ERR, XSPLICE "%s: Unhandled relocation %lu\n",
elf->name, ELF64_R_TYPE(r->r_info));
return -EOPNOTSUPP;
}
}
return 0;
bad_offset:
dprintk(XENLOG_ERR, XSPLICE "%s: Relative relocation offset is past %s section!\n",
elf->name, base->name);
return -EINVAL;
}
/*
* Once the resolving symbols, performing relocations, etc is complete
* we secure the memory by putting in the proper page table attributes
* for the desired type.
*/
int arch_xsplice_secure(const void *va, unsigned int pages, enum va_type type)
{
unsigned long start = (unsigned long)va;
unsigned int flag;
ASSERT(va);
ASSERT(pages);
if ( type == XSPLICE_VA_RX )
flag = PAGE_HYPERVISOR_RX;
else if ( type == XSPLICE_VA_RW )
flag = PAGE_HYPERVISOR_RW;
else
flag = PAGE_HYPERVISOR_RO;
modify_xen_mappings(start, start + pages * PAGE_SIZE, flag);
return 0;
}
void __init arch_xsplice_init(void)
{
void *start, *end;
start = (void *)xen_virt_end;
end = (void *)(XEN_VIRT_END - NR_CPUS * PAGE_SIZE);
BUG_ON(end <= start);
vm_init_type(VMAP_XEN, start, end);
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
+227 -3
View File
@@ -13,6 +13,7 @@
#include <xen/smp.h>
#include <xen/spinlock.h>
#include <xen/vmap.h>
#include <xen/xsplice_elf.h>
#include <xen/xsplice.h>
#include <asm/event.h>
@@ -29,6 +30,13 @@ struct payload {
uint32_t state; /* One of the XSPLICE_STATE_*. */
int32_t rc; /* 0 or -XEN_EXX. */
struct list_head list; /* Linked to 'payload_list'. */
const void *text_addr; /* Virtual address of .text. */
size_t text_size; /* .. and its size. */
const void *rw_addr; /* Virtual address of .data. */
size_t rw_size; /* .. and its size (if any). */
const void *ro_addr; /* Virtual address of .rodata. */
size_t ro_size; /* .. and its size (if any). */
unsigned int pages; /* Total pages for [text,rw,ro]_addr */
char name[XEN_XSPLICE_NAME_SIZE]; /* Name of it. */
};
@@ -83,19 +91,220 @@ static struct payload *find_payload(const char *name)
return found;
}
/*
* Functions related to XEN_SYSCTL_XSPLICE_UPLOAD (see xsplice_upload), and
* freeing payload (XEN_SYSCTL_XSPLICE_ACTION:XSPLICE_ACTION_UNLOAD).
*/
static void free_payload_data(struct payload *payload)
{
/* Set to zero until "move_payload". */
if ( !payload->pages )
return;
vfree((void *)payload->text_addr);
payload->pages = 0;
}
/*
* calc_section computes the size (taking into account section alignment).
*
* Furthermore the offset is set with the offset from the start of the virtual
* address space for the payload (using passed in size). This is used in
* move_payload to figure out the destination location (load_addr).
*/
static void calc_section(const struct xsplice_elf_sec *sec, size_t *size,
unsigned int *offset)
{
const Elf_Shdr *s = sec->sec;
size_t align_size;
align_size = ROUNDUP(*size, s->sh_addralign);
*offset = align_size;
*size = s->sh_size + align_size;
}
static int move_payload(struct payload *payload, struct xsplice_elf *elf)
{
void *text_buf, *ro_buf, *rw_buf;
unsigned int i;
size_t size = 0;
unsigned int *offset;
int rc = 0;
offset = xmalloc_array(unsigned int, elf->hdr->e_shnum);
if ( !offset )
return -ENOMEM;
/* Compute size of different regions. */
for ( i = 1; i < elf->hdr->e_shnum; i++ )
{
/*
* Do nothing. These are .rel.text, rel.*, .symtab, .strtab,
* and .shstrtab. For the non-relocate we allocate and copy these
* via other means - and the .rel we can ignore as we only use it
* once during loading.
*/
if ( !(elf->sec[i].sec->sh_flags & SHF_ALLOC) )
offset[i] = UINT_MAX;
else if ( (elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
!(elf->sec[i].sec->sh_flags & SHF_WRITE) )
calc_section(&elf->sec[i], &payload->text_size, &offset[i]);
else if ( !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
(elf->sec[i].sec->sh_flags & SHF_WRITE) )
calc_section(&elf->sec[i], &payload->rw_size, &offset[i]);
else if ( !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
!(elf->sec[i].sec->sh_flags & SHF_WRITE) )
calc_section(&elf->sec[i], &payload->ro_size, &offset[i]);
else
{
dprintk(XENLOG_DEBUG, XSPLICE "%s: Not supporting %s section!\n",
elf->name, elf->sec[i].name);
rc = -EOPNOTSUPP;
goto out;
}
}
/*
* Total of all three regions - RX, RW, and RO. We have to have
* keep them in seperate pages so we PAGE_ALIGN the RX and RW to have
* them on seperate pages. The last one will by default fall on its
* own page.
*/
size = PAGE_ALIGN(payload->text_size) + PAGE_ALIGN(payload->rw_size) +
payload->ro_size;
size = PFN_UP(size); /* Nr of pages. */
text_buf = vmalloc_xen(size * PAGE_SIZE);
if ( !text_buf )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Could not allocate memory for payload!\n",
elf->name);
rc = -ENOMEM;
goto out;
}
rw_buf = text_buf + PAGE_ALIGN(payload->text_size);
ro_buf = rw_buf + PAGE_ALIGN(payload->rw_size);
payload->pages = size;
payload->text_addr = text_buf;
payload->rw_addr = rw_buf;
payload->ro_addr = ro_buf;
for ( i = 1; i < elf->hdr->e_shnum; i++ )
{
if ( elf->sec[i].sec->sh_flags & SHF_ALLOC )
{
void *buf;
if ( elf->sec[i].sec->sh_flags & SHF_EXECINSTR )
buf = text_buf;
else if ( elf->sec[i].sec->sh_flags & SHF_WRITE )
buf = rw_buf;
else
buf = ro_buf;
ASSERT(offset[i] != UINT_MAX);
elf->sec[i].load_addr = buf + offset[i];
/* Don't copy NOBITS - such as BSS. */
if ( elf->sec[i].sec->sh_type != SHT_NOBITS )
{
memcpy(elf->sec[i].load_addr, elf->sec[i].data,
elf->sec[i].sec->sh_size);
dprintk(XENLOG_DEBUG, XSPLICE "%s: Loaded %s at %p\n",
elf->name, elf->sec[i].name, elf->sec[i].load_addr);
}
else
memset(elf->sec[i].load_addr, 0, elf->sec[i].sec->sh_size);
}
}
out:
xfree(offset);
return rc;
}
static int secure_payload(struct payload *payload, struct xsplice_elf *elf)
{
int rc;
unsigned int text_pages, rw_pages, ro_pages;
text_pages = PFN_UP(payload->text_size);
ASSERT(text_pages);
rc = arch_xsplice_secure(payload->text_addr, text_pages, XSPLICE_VA_RX);
if ( rc )
return rc;
rw_pages = PFN_UP(payload->rw_size);
if ( rw_pages )
{
rc = arch_xsplice_secure(payload->rw_addr, rw_pages, XSPLICE_VA_RW);
if ( rc )
return rc;
}
ro_pages = PFN_UP(payload->ro_size);
if ( ro_pages )
rc = arch_xsplice_secure(payload->ro_addr, ro_pages, XSPLICE_VA_RO);
ASSERT(ro_pages + rw_pages + text_pages == payload->pages);
return rc;
}
static void free_payload(struct payload *data)
{
ASSERT(spin_is_locked(&payload_lock));
list_del(&data->list);
payload_cnt--;
payload_version++;
free_payload_data(data);
xfree(data);
}
static int load_payload_data(struct payload *payload, void *raw, size_t len)
{
struct xsplice_elf elf = { .name = payload->name, .len = len };
int rc = 0;
rc = xsplice_elf_load(&elf, raw);
if ( rc )
goto out;
rc = move_payload(payload, &elf);
if ( rc )
goto out;
rc = xsplice_elf_resolve_symbols(&elf);
if ( rc )
goto out;
rc = xsplice_elf_perform_relocs(&elf);
if ( rc )
goto out;
rc = secure_payload(payload, &elf);
out:
if ( rc )
free_payload_data(payload);
/* Free our temporary data structure. */
xsplice_elf_free(&elf);
return rc;
}
static int xsplice_upload(xen_sysctl_xsplice_upload_t *upload)
{
struct payload *data, *found;
char n[XEN_XSPLICE_NAME_SIZE];
void *raw_data;
int rc;
rc = verify_payload(upload, n);
@@ -103,6 +312,7 @@ static int xsplice_upload(xen_sysctl_xsplice_upload_t *upload)
return rc;
data = xzalloc(struct payload);
raw_data = vmalloc(upload->size);
spin_lock(&payload_lock);
@@ -111,11 +321,18 @@ static int xsplice_upload(xen_sysctl_xsplice_upload_t *upload)
rc = PTR_ERR(found);
else if ( found )
rc = -EEXIST;
else if ( !data )
else if ( !data || !raw_data )
rc = -ENOMEM;
else if ( __copy_from_guest(raw_data, upload->payload, upload->size) )
rc = -EFAULT;
else
{
memcpy(data->name, n, strlen(n));
rc = load_payload_data(data, raw_data, upload->size);
if ( rc )
goto out;
data->state = XSPLICE_STATE_CHECKED;
INIT_LIST_HEAD(&data->list);
@@ -123,8 +340,12 @@ static int xsplice_upload(xen_sysctl_xsplice_upload_t *upload)
payload_cnt++;
payload_version++;
}
out:
spin_unlock(&payload_lock);
vfree(raw_data);
if ( rc )
xfree(data);
@@ -359,8 +580,9 @@ static void xsplice_printall(unsigned char key)
}
list_for_each_entry ( data, &payload_list, list )
printk(" name=%s state=%s(%d)\n", data->name,
state2str(data->state), data->state);
printk(" name=%s state=%s(%d) %p (.data=%p, .rodata=%p) using %u pages.\n",
data->name, state2str(data->state), data->state, data->text_addr,
data->rw_addr, data->ro_addr, data->pages);
spin_unlock(&payload_lock);
}
@@ -368,6 +590,8 @@ static void xsplice_printall(unsigned char key)
static int __init xsplice_init(void)
{
register_keyhandler('x', xsplice_printall, "print xsplicing info", 1);
arch_xsplice_init();
return 0;
}
__initcall(xsplice_init);
+118
View File
@@ -100,6 +100,7 @@ static int elf_resolve_sections(struct xsplice_elf *elf, const void *data)
elf->symtab = &sec[i];
elf->symtab_idx = i;
/*
* elf->symtab->sec->sh_link would point to the right section
* but we hadn't finished parsing all the sections.
@@ -250,9 +251,122 @@ static int elf_get_sym(struct xsplice_elf *elf, const void *data)
return 0;
}
int xsplice_elf_resolve_symbols(struct xsplice_elf *elf)
{
unsigned int i;
int rc = 0;
ASSERT(elf->sym);
for ( i = 1; i < elf->nsym; i++ )
{
unsigned int idx = elf->sym[i].sym->st_shndx;
const Elf_Sym *sym = elf->sym[i].sym;
Elf_Addr st_value = sym->st_value;
switch ( idx )
{
case SHN_COMMON:
dprintk(XENLOG_ERR, XSPLICE "%s: Unexpected common symbol: %s\n",
elf->name, elf->sym[i].name);
rc = -EINVAL;
break;
case SHN_UNDEF:
dprintk(XENLOG_ERR, XSPLICE "%s: Unknown symbol: %s\n",
elf->name, elf->sym[i].name);
rc = -ENOENT;
break;
case SHN_ABS:
dprintk(XENLOG_DEBUG, XSPLICE "%s: Absolute symbol: %s => %#"PRIxElfAddr"\n",
elf->name, elf->sym[i].name, sym->st_value);
break;
default:
/* SHN_COMMON and SHN_ABS are above. */
if ( idx >= SHN_LORESERVE )
rc = -EOPNOTSUPP;
else if ( idx >= elf->hdr->e_shnum )
rc = -EINVAL;
if ( rc )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Out of bounds symbol section %#x\n",
elf->name, idx);
break;
}
/* Matches 'move_payload' which ignores such sections. */
if ( !(elf->sec[idx].sec->sh_flags & SHF_ALLOC) )
break;
st_value += (unsigned long)elf->sec[idx].load_addr;
if ( elf->sym[i].name )
dprintk(XENLOG_DEBUG, XSPLICE "%s: Symbol resolved: %s => %#"PRIxElfAddr" (%s)\n",
elf->name, elf->sym[i].name,
st_value, elf->sec[idx].name);
}
if ( rc )
break;
((Elf_Sym *)sym)->st_value = st_value;
}
return rc;
}
int xsplice_elf_perform_relocs(struct xsplice_elf *elf)
{
struct xsplice_elf_sec *r, *base;
unsigned int i;
int rc = 0;
ASSERT(elf->sym);
for ( i = 1; i < elf->hdr->e_shnum; i++ )
{
r = &elf->sec[i];
if ( (r->sec->sh_type != SHT_RELA) &&
(r->sec->sh_type != SHT_REL) )
continue;
/* Is it a valid relocation section? */
if ( r->sec->sh_info >= elf->hdr->e_shnum )
continue;
base = &elf->sec[r->sec->sh_info];
/* Don't relocate non-allocated sections. */
if ( !(base->sec->sh_flags & SHF_ALLOC) )
continue;
if ( r->sec->sh_link != elf->symtab_idx )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Relative link of %s is incorrect (%d, expected=%d)\n",
elf->name, r->name, r->sec->sh_link, elf->symtab_idx);
rc = -EINVAL;
break;
}
if ( r->sec->sh_type == SHT_RELA )
rc = arch_xsplice_perform_rela(elf, base, r);
else /* SHT_REL */
rc = arch_xsplice_perform_rel(elf, base, r);
if ( rc )
break;
}
return rc;
}
static int xsplice_header_check(const struct xsplice_elf *elf)
{
const Elf_Ehdr *hdr = elf->hdr;
int rc;
if ( sizeof(*elf->hdr) > elf->len )
{
@@ -279,6 +393,10 @@ static int xsplice_header_check(const struct xsplice_elf *elf)
return -EOPNOTSUPP;
}
rc = arch_xsplice_verify_elf(elf);
if ( rc )
return rc;
if ( elf->hdr->e_shstrndx == SHN_UNDEF )
{
dprintk(XENLOG_ERR, XSPLICE "%s: Section name idx is undefined!?\n",
+4
View File
@@ -472,6 +472,8 @@ typedef struct {
#endif
#if defined(ELFSIZE) && (ELFSIZE == 32)
#define PRIxElfAddr "08x"
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#define Elf_Shdr Elf32_Shdr
@@ -497,6 +499,8 @@ typedef struct {
#define AuxInfo Aux32Info
#elif defined(ELFSIZE) && (ELFSIZE == 64)
#define PRIxElfAddr PRIx64
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Shdr Elf64_Shdr
+24
View File
@@ -6,6 +6,9 @@
#ifndef __XEN_XSPLICE_H__
#define __XEN_XSPLICE_H__
struct xsplice_elf;
struct xsplice_elf_sec;
struct xsplice_elf_sym;
struct xen_sysctl_xsplice_op;
#ifdef CONFIG_XSPLICE
@@ -15,6 +18,27 @@ struct xen_sysctl_xsplice_op;
int xsplice_op(struct xen_sysctl_xsplice_op *);
/* Arch hooks. */
int arch_xsplice_verify_elf(const struct xsplice_elf *elf);
int arch_xsplice_perform_rel(struct xsplice_elf *elf,
const struct xsplice_elf_sec *base,
const struct xsplice_elf_sec *rela);
int arch_xsplice_perform_rela(struct xsplice_elf *elf,
const struct xsplice_elf_sec *base,
const struct xsplice_elf_sec *rela);
enum va_type {
XSPLICE_VA_RX, /* .text */
XSPLICE_VA_RW, /* .data */
XSPLICE_VA_RO, /* .rodata */
};
/*
* Function to secure the allocate pages (from arch_xsplice_alloc_payload)
* with the right page permissions.
*/
int arch_xsplice_secure(const void *va, unsigned int pages, enum va_type types);
void arch_xsplice_init(void);
#else
#include <xen/errno.h> /* For -ENOSYS */
+9 -2
View File
@@ -15,6 +15,8 @@ struct xsplice_elf_sec {
elf_resolve_section_names. */
const void *data; /* Pointer to the section (done by
elf_resolve_sections). */
void *load_addr; /* A pointer to the allocated destination.
Done by load_payload_data. */
};
struct xsplice_elf_sym {
@@ -29,8 +31,10 @@ struct xsplice_elf {
struct xsplice_elf_sec *sec; /* Array of sections, allocated by us. */
struct xsplice_elf_sym *sym; /* Array of symbols , allocated by us. */
unsigned int nsym;
const struct xsplice_elf_sec *symtab;/* Pointer to .symtab section - aka to sec[x]. */
const struct xsplice_elf_sec *strtab;/* Pointer to .strtab section - aka to sec[y]. */
const struct xsplice_elf_sec *symtab;/* Pointer to .symtab section - aka to
sec[symtab_idx]. */
const struct xsplice_elf_sec *strtab;/* Pointer to .strtab section. */
unsigned int symtab_idx;
};
const struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf *elf,
@@ -38,6 +42,9 @@ const struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf *
int xsplice_elf_load(struct xsplice_elf *elf, const void *data);
void xsplice_elf_free(struct xsplice_elf *elf);
int xsplice_elf_resolve_symbols(struct xsplice_elf *elf);
int xsplice_elf_perform_relocs(struct xsplice_elf *elf);
#endif /* __XEN_XSPLICE_ELF_H__ */
/*
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.