diff options
Diffstat (limited to 'src/vppinfra/elf.c')
-rw-r--r-- | src/vppinfra/elf.c | 2040 |
1 files changed, 2040 insertions, 0 deletions
diff --git a/src/vppinfra/elf.c b/src/vppinfra/elf.c new file mode 100644 index 00000000000..931fbcccc48 --- /dev/null +++ b/src/vppinfra/elf.c @@ -0,0 +1,2040 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <vppinfra/bitmap.h> +#include <vppinfra/byte_order.h> +#include <vppinfra/error.h> +#include <vppinfra/hash.h> +#include <vppinfra/vec.h> +#include <vppinfra/elf.h> + +always_inline void +elf_swap_first_header (elf_main_t * em, elf_first_header_t * h) +{ + h->architecture = elf_swap_u16 (em, h->architecture); + h->file_type = elf_swap_u16 (em, h->file_type); + h->file_version = elf_swap_u32 (em, h->file_version); +} + +always_inline void +elf_swap_verneed (elf_dynamic_version_need_t * n) +{ +#define _(t,f) n->f = clib_byte_swap_##t (n->f); + foreach_elf_dynamic_version_need_field +#undef _ +} + +always_inline void +elf_swap_verneed_aux (elf_dynamic_version_need_aux_t * n) +{ +#define _(t,f) n->f = clib_byte_swap_##t (n->f); + foreach_elf_dynamic_version_need_aux_field +#undef _ +} + +clib_error_t * +elf_get_section_by_name (elf_main_t * em, char *section_name, + elf_section_t ** result) +{ + uword *p; + + p = hash_get_mem (em->section_by_name, section_name); + if (!p) + return clib_error_return (0, "no such section `%s'", section_name); + + *result = vec_elt_at_index (em->sections, p[0]); + return 0; +} + +elf_section_t * +elf_get_section_by_start_address_no_check (elf_main_t * em, + uword start_address) +{ + uword *p = hash_get (em->section_by_start_address, start_address); + return p ? vec_elt_at_index (em->sections, p[0]) : 0; +} + +clib_error_t * +elf_get_section_by_start_address (elf_main_t * em, uword start_address, + elf_section_t ** result) +{ + elf_section_t *s = + elf_get_section_by_start_address_no_check (em, start_address); + if (!s) + return clib_error_return (0, "no section with address 0x%wx", + start_address); + *result = s; + return 0; +} + +static u8 * +format_elf_section_type (u8 * s, va_list * args) +{ + elf_section_type_t type = va_arg (*args, elf_section_type_t); + char *t = 0; + + switch (type) + { +#define _(f,i) case ELF_SECTION_##f: t = #f; break; + foreach_elf_section_type +#undef _ + } + + if (!t) + s = format (s, "unknown 0x%x", type); + else + s = format (s, "%s", t); + return s; +} + +static u8 * +format_elf_section (u8 * s, va_list * args) +{ + elf_main_t *em = va_arg (*args, elf_main_t *); + elf_section_t *es = va_arg (*args, elf_section_t *); + elf64_section_header_t *h = &es->header; + + if (!h) + return format (s, "%=40s%=10s%=20s%=8s%=16s%=16s%=16s", + "Name", "Index", "Type", "Size", "Align", "Address", + "File offset"); + + s = format (s, "%-40s%10d%=20U%8Lx%16d%16Lx %Lx-%Lx", + elf_section_name (em, es), + es->index, + format_elf_section_type, h->type, + h->file_size, + h->align, + h->exec_address, h->file_offset, h->file_offset + h->file_size); + + if (h->flags != 0) + { +#define _(f,i) \ + if (h->flags & ELF_SECTION_FLAG_##f) s = format (s, " %s", #f); + foreach_elf_section_flag; +#undef _ + } + + return s; +} + +static u8 * +format_elf_segment_type (u8 * s, va_list * args) +{ + elf_segment_type_t type = va_arg (*args, elf_segment_type_t); + char *t = 0; + + switch (type) + { +#define _(f,i) case ELF_SEGMENT_##f: t = #f; break; + foreach_elf_segment_type +#undef _ + } + + if (!t) + s = format (s, "unknown 0x%x", type); + else + s = format (s, "%s", t); + return s; +} + +static u8 * +format_elf_segment (u8 * s, va_list * args) +{ + elf_segment_t *es = va_arg (*args, elf_segment_t *); + elf64_segment_header_t *h = &es->header; + + if (!h) + return format (s, "%=16s%=16s%=16s%=16s", + "Type", "Virt. Address", "Phys. Address", "Size"); + + s = format (s, "%=16U%16Lx%16Lx%16Lx%16Lx", + format_elf_segment_type, h->type, + h->virtual_address, + h->physical_address, h->memory_size, h->file_offset); + + if (h->flags != 0) + { +#define _(f,i) \ + if (h->flags & ELF_SEGMENT_FLAG_##f) s = format (s, " %s", #f); + foreach_elf_segment_flag; +#undef _ + } + + return s; +} + +static u8 * +format_elf_symbol_binding_and_type (u8 * s, va_list * args) +{ + int bt = va_arg (*args, int); + int b, t; + char *type_string = 0; + char *binding_string = 0; + + switch ((b = ((bt >> 4) & 0xf))) + { +#define _(f,n) case n: binding_string = #f; break; + foreach_elf_symbol_binding; +#undef _ + default: + break; + } + + switch ((t = ((bt >> 0) & 0xf))) + { +#define _(f,n) case n: type_string = #f; break; + foreach_elf_symbol_type; +#undef _ + default: + break; + } + + if (binding_string) + s = format (s, "%s", binding_string); + else + s = format (s, "binding 0x%x", b); + + if (type_string) + s = format (s, " %s", type_string); + else + s = format (s, " type 0x%x", t); + + return s; +} + +static u8 * +format_elf_symbol_visibility (u8 * s, va_list * args) +{ + int visibility = va_arg (*args, int); + char *t = 0; + + switch (visibility) + { +#define _(f,n) case n: t = #f; break; + foreach_elf_symbol_visibility +#undef _ + } + + if (t) + return format (s, "%s", t); + else + return format (s, "unknown 0x%x", visibility); +} + +static u8 * +format_elf_symbol_section_name (u8 * s, va_list * args) +{ + elf_main_t *em = va_arg (*args, elf_main_t *); + int si = va_arg (*args, int); + char *t = 0; + + if (si < vec_len (em->sections)) + { + elf_section_t *es = vec_elt_at_index (em->sections, si); + return format (s, "%s", elf_section_name (em, es)); + } + + if (si >= ELF_SYMBOL_SECTION_RESERVED_LO + && si <= ELF_SYMBOL_SECTION_RESERVED_HI) + { + switch (si) + { +#define _(f,n) case n: t = #f; break; + foreach_elf_symbol_reserved_section_index +#undef _ + default: + break; + } + } + + if (t) + return format (s, "%s", t); + else + return format (s, "unknown 0x%x", si); +} + +u8 * +format_elf_symbol (u8 * s, va_list * args) +{ + elf_main_t *em = va_arg (*args, elf_main_t *); + elf_symbol_table_t *t = va_arg (*args, elf_symbol_table_t *); + elf64_symbol_t *sym = va_arg (*args, elf64_symbol_t *); + + if (!sym) + return format (s, "%=32s%=16s%=16s%=16s%=16s%=16s", + "Symbol", "Size", "Value", "Type", "Visibility", + "Section"); + + s = format (s, "%-32s%16Ld%16Lx%=16U%=16U%U", + elf_symbol_name (t, sym), + sym->size, sym->value, + format_elf_symbol_binding_and_type, sym->binding_and_type, + format_elf_symbol_visibility, sym->visibility, + format_elf_symbol_section_name, em, sym->section_index); + + return s; +} + +static u8 * +format_elf_relocation_type (u8 * s, va_list * args) +{ + elf_main_t *em = va_arg (*args, elf_main_t *); + int type = va_arg (*args, int); + char *t = 0; + + switch (em->first_header.architecture) + { +#define _(f,i) [i] = #f, + + case ELF_ARCH_X86_64: + { + static char *tab[] = { + foreach_elf_x86_64_relocation_type + }; + +#undef _ + if (type < ARRAY_LEN (tab)) + t = tab[type]; + break; + } + + default: + break; + } + + if (!t) + s = format (s, "0x%02x", type); + else + s = format (s, "%s", t); + + return s; +} + +static u8 * +format_elf_relocation (u8 * s, va_list * args) +{ + elf_main_t *em = va_arg (*args, elf_main_t *); + elf_relocation_with_addend_t *r = + va_arg (*args, elf_relocation_with_addend_t *); + elf_symbol_table_t *t; + elf64_symbol_t *sym; + + if (!r) + return format (s, "%=16s%=16s%=16s", "Address", "Type", "Symbol"); + + t = vec_elt_at_index (em->symbol_tables, 0); + sym = vec_elt_at_index (t->symbols, r->symbol_and_type >> 32); + + s = format (s, "%16Lx%16U", + r->address, + format_elf_relocation_type, em, r->symbol_and_type & 0xff); + + if (sym->section_index != 0) + { + elf_section_t *es; + es = vec_elt_at_index (em->sections, sym->section_index); + s = format (s, " (section %s)", elf_section_name (em, es)); + } + + if (sym->name != 0) + s = format (s, " %s", elf_symbol_name (t, sym)); + + { + i64 a = r->addend; + if (a != 0) + s = format (s, " %c 0x%Lx", a > 0 ? '+' : '-', a > 0 ? a : -a); + } + + return s; +} + +static u8 * +format_elf_dynamic_entry_type (u8 * s, va_list * args) +{ + u32 type = va_arg (*args, u32); + char *t = 0; + switch (type) + { +#define _(f,n) case n: t = #f; break; + foreach_elf_dynamic_entry_type; +#undef _ + default: + break; + } + if (t) + return format (s, "%s", t); + else + return format (s, "unknown 0x%x", type); +} + +static u8 * +format_elf_dynamic_entry (u8 * s, va_list * args) +{ + elf_main_t *em = va_arg (*args, elf_main_t *); + elf64_dynamic_entry_t *e = va_arg (*args, elf64_dynamic_entry_t *); + + if (!e) + return format (s, "%=40s%=16s", "Type", "Data"); + + s = format (s, "%=40U", format_elf_dynamic_entry_type, (u32) e->type); + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_NEEDED_LIBRARY: + case ELF_DYNAMIC_ENTRY_RPATH: + case ELF_DYNAMIC_ENTRY_RUN_PATH: + s = format (s, "%s", em->dynamic_string_table + e->data); + break; + + case ELF_DYNAMIC_ENTRY_INIT_FUNCTION: + case ELF_DYNAMIC_ENTRY_FINI_FUNCTION: + case ELF_DYNAMIC_ENTRY_SYMBOL_HASH: + case ELF_DYNAMIC_ENTRY_GNU_HASH: + case ELF_DYNAMIC_ENTRY_STRING_TABLE: + case ELF_DYNAMIC_ENTRY_SYMBOL_TABLE: + case ELF_DYNAMIC_ENTRY_PLT_GOT: + case ELF_DYNAMIC_ENTRY_PLT_RELOCATION_ADDRESS: + case ELF_DYNAMIC_ENTRY_RELA_ADDRESS: + case ELF_DYNAMIC_ENTRY_VERSION_NEED: + case ELF_DYNAMIC_ENTRY_VERSYM: + { + elf_section_t *es = + elf_get_section_by_start_address_no_check (em, e->data); + if (es) + s = format (s, "section %s", elf_section_name (em, es)); + else + s = format (s, "0x%Lx", e->data); + break; + } + + default: + s = format (s, "0x%Lx", e->data); + break; + } + + return s; +} + +static u8 * +format_elf_architecture (u8 * s, va_list * args) +{ + int a = va_arg (*args, int); + char *t; + + switch (a) + { +#define _(f,n) case n: t = #f; break; + foreach_elf_architecture; +#undef _ + default: + return format (s, "unknown 0x%x", a); + } + + return format (s, "%s", t); +} + +static u8 * +format_elf_abi (u8 * s, va_list * args) +{ + int a = va_arg (*args, int); + char *t; + + switch (a) + { +#define _(f,n) case n: t = #f; break; + foreach_elf_abi; +#undef _ + default: + return format (s, "unknown 0x%x", a); + } + + return format (s, "%s", t); +} + +static u8 * +format_elf_file_class (u8 * s, va_list * args) +{ + int a = va_arg (*args, int); + char *t; + + switch (a) + { +#define _(f) case ELF_##f: t = #f; break; + foreach_elf_file_class; +#undef _ + default: + return format (s, "unknown 0x%x", a); + } + + return format (s, "%s", t); +} + +static u8 * +format_elf_file_type (u8 * s, va_list * args) +{ + int a = va_arg (*args, int); + char *t; + + if (a >= ELF_ARCH_SPECIFIC_LO && a <= ELF_ARCH_SPECIFIC_HI) + return format (s, "arch-specific 0x%x", a - ELF_ARCH_SPECIFIC_LO); + + if (a >= ELF_OS_SPECIFIC_LO && a <= ELF_OS_SPECIFIC_HI) + return format (s, "os-specific 0x%x", a - ELF_OS_SPECIFIC_LO); + + switch (a) + { +#define _(f,n) case n: t = #f; break; + foreach_elf_file_type; +#undef _ + default: + return format (s, "unknown 0x%x", a); + } + + return format (s, "%s", t); +} + +static u8 * +format_elf_data_encoding (u8 * s, va_list * args) +{ + int a = va_arg (*args, int); + char *t; + + switch (a) + { +#define _(f) case ELF_##f: t = #f; break; + foreach_elf_data_encoding; +#undef _ + default: + return format (s, "unknown 0x%x", a); + } + + return format (s, "%s", t); +} + +static int +elf_section_offset_compare (void *a1, void *a2) +{ + elf_section_t *s1 = a1; + elf_section_t *s2 = a2; + + return ((i64) s1->header.file_offset - (i64) s2->header.file_offset); +} + +static int +elf_segment_va_compare (void *a1, void *a2) +{ + elf_segment_t *s1 = a1; + elf_segment_t *s2 = a2; + + return ((i64) s1->header.virtual_address - + (i64) s2->header.virtual_address); +} + +u8 * +format_elf_main (u8 * s, va_list * args) +{ + elf_main_t *em = va_arg (*args, elf_main_t *); + u32 verbose = va_arg (*args, u32); + elf64_file_header_t *fh = &em->file_header; + + s = + format (s, + "File header: machine: %U, file type/class %U/%U, data-encoding: %U, abi: %U version %d\n", + format_elf_architecture, em->first_header.architecture, + format_elf_file_type, em->first_header.file_type, + format_elf_file_class, em->first_header.file_class, + format_elf_data_encoding, em->first_header.data_encoding, + format_elf_abi, em->first_header.abi, + em->first_header.abi_version); + + s = format (s, " entry 0x%Lx, arch-flags 0x%x", + em->file_header.entry_point, em->file_header.flags); + + if (em->interpreter) + s = format (s, "\n interpreter: %s", em->interpreter); + + { + elf_section_t *h, *copy; + + copy = 0; + vec_foreach (h, em->sections) if (h->header.type != ~0) + vec_add1 (copy, h[0]); + + vec_sort_with_function (copy, elf_section_offset_compare); + + s = format (s, "\nSections %d at file offset 0x%Lx-0x%Lx:\n", + fh->section_header_count, + fh->section_header_file_offset, + fh->section_header_file_offset + + (u64) fh->section_header_count * fh->section_header_size); + s = format (s, "%U\n", format_elf_section, em, 0); + vec_foreach (h, copy) s = format (s, "%U\n", format_elf_section, em, h); + + vec_free (copy); + } + + { + elf_segment_t *h, *copy; + + copy = 0; + vec_foreach (h, em->segments) + if (h->header.type != ELF_SEGMENT_UNUSED && h->header.type != ~0) + vec_add1 (copy, h[0]); + + /* Sort segments by address. */ + vec_sort_with_function (copy, elf_segment_va_compare); + + s = format (s, "\nSegments: %d at file offset 0x%Lx-0x%Lx:\n", + fh->segment_header_count, + fh->segment_header_file_offset, + (u64) fh->segment_header_file_offset + + (u64) fh->segment_header_count * + (u64) fh->segment_header_size); + + s = format (s, "%U\n", format_elf_segment, 0); + vec_foreach (h, copy) s = format (s, "%U\n", format_elf_segment, h); + + vec_free (copy); + } + + if ((verbose & FORMAT_ELF_MAIN_SYMBOLS) && vec_len (em->symbol_tables) > 0) + { + elf_symbol_table_t *t; + elf64_symbol_t *sym; + elf_section_t *es; + + vec_foreach (t, em->symbol_tables) + { + es = vec_elt_at_index (em->sections, t->section_index); + s = + format (s, "\nSymbols for section %s:\n", + elf_section_name (em, es)); + + s = format (s, "%U\n", format_elf_symbol, em, 0, 0); + vec_foreach (sym, t->symbols) + s = format (s, "%U\n", format_elf_symbol, em, t, sym); + } + } + + if ((verbose & FORMAT_ELF_MAIN_RELOCATIONS) + && vec_len (em->relocation_tables) > 0) + { + elf_relocation_table_t *t; + elf_relocation_with_addend_t *r; + elf_section_t *es; + + vec_foreach (t, em->relocation_tables) + { + es = vec_elt_at_index (em->sections, t->section_index); + r = t->relocations; + s = format (s, "\nRelocations for section %s:\n", + elf_section_name (em, es)); + + s = format (s, "%U\n", format_elf_relocation, em, 0); + vec_foreach (r, t->relocations) + { + s = format (s, "%U\n", format_elf_relocation, em, r); + } + } + } + + if ((verbose & FORMAT_ELF_MAIN_DYNAMIC) + && vec_len (em->dynamic_entries) > 0) + { + elf64_dynamic_entry_t *es, *e; + s = format (s, "\nDynamic linker information:\n"); + es = vec_dup (em->dynamic_entries); + s = format (s, "%U\n", format_elf_dynamic_entry, em, 0); + vec_foreach (e, es) + s = format (s, "%U\n", format_elf_dynamic_entry, em, e); + } + + return s; +} + +static void +elf_parse_segments (elf_main_t * em, void *data) +{ + void *d = data + em->file_header.segment_header_file_offset; + uword n = em->file_header.segment_header_count; + uword i; + + vec_resize (em->segments, n); + + for (i = 0; i < n; i++) + { + em->segments[i].index = i; + + if (em->first_header.file_class == ELF_64BIT) + { + elf64_segment_header_t *h = d; +#define _(t,f) em->segments[i].header.f = elf_swap_##t (em, h->f); + foreach_elf64_segment_header +#undef _ + d = (h + 1); + } + else + { + elf32_segment_header_t *h = d; +#define _(t,f) em->segments[i].header.f = elf_swap_##t (em, h->f); + foreach_elf32_segment_header +#undef _ + d = (h + 1); + } + } +} + +static void +elf_parse_sections (elf_main_t * em, void *data) +{ + elf64_file_header_t *fh = &em->file_header; + elf_section_t *s; + void *d = data + fh->section_header_file_offset; + uword n = fh->section_header_count; + uword i; + + vec_resize (em->sections, n); + + for (i = 0; i < n; i++) + { + s = em->sections + i; + + s->index = i; + + if (em->first_header.file_class == ELF_64BIT) + { + elf64_section_header_t *h = d; +#define _(t,f) em->sections[i].header.f = elf_swap_##t (em, h->f); + foreach_elf64_section_header +#undef _ + d = (h + 1); + } + else + { + elf32_section_header_t *h = d; +#define _(t,f) em->sections[i].header.f = elf_swap_##t (em, h->f); + foreach_elf32_section_header +#undef _ + d = (h + 1); + } + + if (s->header.type != ELF_SECTION_NO_BITS) + vec_add (s->contents, data + s->header.file_offset, + s->header.file_size); + } + + s = vec_elt_at_index (em->sections, fh->section_header_string_table_index); + + em->section_by_name + = hash_create_string ( /* # elts */ vec_len (em->sections), + /* sizeof of value */ sizeof (uword)); + + vec_foreach (s, em->sections) + { + hash_set_mem (em->section_by_name, + elf_section_name (em, s), s - em->sections); + hash_set (em->section_by_start_address, + s->header.exec_address, s - em->sections); + } +} + +static void +add_symbol_table (elf_main_t * em, elf_section_t * s) +{ + elf_symbol_table_t *tab; + elf32_symbol_t *sym32; + elf64_symbol_t *sym64; + uword i; + + if (s->header.type == ELF_SECTION_DYNAMIC_SYMBOL_TABLE) + em->dynamic_symbol_table_index = vec_len (em->symbol_tables); + + vec_add2 (em->symbol_tables, tab, 1); + + tab->section_index = s->index; + + if (em->first_header.file_class == ELF_64BIT) + { + tab->symbols = + elf_get_section_contents (em, s - em->sections, + sizeof (tab->symbols[0])); + for (i = 0; i < vec_len (tab->symbols); i++) + { +#define _(t,f) tab->symbols[i].f = elf_swap_##t (em, tab->symbols[i].f); + foreach_elf64_symbol_header; +#undef _ + } + } + else + { + sym32 = + elf_get_section_contents (em, s - em->sections, sizeof (sym32[0])); + vec_clone (tab->symbols, sym32); + for (i = 0; i < vec_len (tab->symbols); i++) + { +#define _(t,f) tab->symbols[i].f = elf_swap_##t (em, sym32[i].f); + foreach_elf32_symbol_header; +#undef _ + } + } + + if (s->header.link == 0) + return; + + tab->string_table = + elf_get_section_contents (em, s->header.link, + sizeof (tab->string_table[0])); + tab->symbol_by_name = + hash_create_string ( /* # elts */ vec_len (tab->symbols), + /* sizeof of value */ sizeof (uword)); + + vec_foreach (sym64, tab->symbols) + { + if (sym64->name != 0) + hash_set_mem (tab->symbol_by_name, + tab->string_table + sym64->name, sym64 - tab->symbols); + } +} + +static void +add_relocation_table (elf_main_t * em, elf_section_t * s) +{ + uword has_addend = s->header.type == ELF_SECTION_RELOCATION_ADD; + elf_relocation_table_t *t; + uword i; + + vec_add2 (em->relocation_tables, t, 1); + t->section_index = s - em->sections; + + if (em->first_header.file_class == ELF_64BIT) + { + elf64_relocation_t *r, *rs; + + rs = elf_get_section_contents (em, t->section_index, + sizeof (rs[0]) + + has_addend * sizeof (rs->addend[0])); + + if (em->need_byte_swap) + { + r = rs; + for (i = 0; i < vec_len (r); i++) + { + r->address = elf_swap_u64 (em, r->address); + r->symbol_and_type = elf_swap_u32 (em, r->symbol_and_type); + if (has_addend) + r->addend[0] = elf_swap_u64 (em, r->addend[0]); + r = elf_relocation_next (r, s->header.type); + } + } + + vec_resize (t->relocations, vec_len (rs)); + clib_memcpy (t->relocations, rs, vec_bytes (t->relocations)); + vec_free (rs); + } + else + { + elf_relocation_with_addend_t *r; + elf32_relocation_t *r32, *r32s; + + r32s = elf_get_section_contents (em, t->section_index, + sizeof (r32s[0]) + + has_addend * sizeof (r32s->addend[0])); + vec_resize (t->relocations, vec_len (r32s)); + + r32 = r32s; + vec_foreach (r, t->relocations) + { + r->address = elf_swap_u32 (em, r32->address); + r->symbol_and_type = elf_swap_u32 (em, r->symbol_and_type); + r->addend = has_addend ? elf_swap_u32 (em, r32->addend[0]) : 0; + r32 = elf_relocation_next (r32, s->header.type); + } + + vec_free (r32s); + } +} + +void +elf_parse_symbols (elf_main_t * em) +{ + elf_section_t *s; + + /* No need to parse symbols twice. */ + if (em->parsed_symbols) + return; + em->parsed_symbols = 1; + + vec_foreach (s, em->sections) + { + switch (s->header.type) + { + case ELF_SECTION_SYMBOL_TABLE: + case ELF_SECTION_DYNAMIC_SYMBOL_TABLE: + add_symbol_table (em, s); + break; + + case ELF_SECTION_RELOCATION_ADD: + case ELF_SECTION_RELOCATION: + add_relocation_table (em, s); + break; + + default: + break; + } + } +} + +void +elf_set_dynamic_entries (elf_main_t * em) +{ + uword i; + + /* Start address for sections may have changed. */ + { + elf64_dynamic_entry_t *e; + + vec_foreach (e, em->dynamic_entries) + { + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_INIT_FUNCTION: + case ELF_DYNAMIC_ENTRY_FINI_FUNCTION: + case ELF_DYNAMIC_ENTRY_SYMBOL_HASH: + case ELF_DYNAMIC_ENTRY_GNU_HASH: + case ELF_DYNAMIC_ENTRY_STRING_TABLE: + case ELF_DYNAMIC_ENTRY_SYMBOL_TABLE: + case ELF_DYNAMIC_ENTRY_PLT_GOT: + case ELF_DYNAMIC_ENTRY_PLT_RELOCATION_ADDRESS: + case ELF_DYNAMIC_ENTRY_RELA_ADDRESS: + case ELF_DYNAMIC_ENTRY_VERSION_NEED: + case ELF_DYNAMIC_ENTRY_VERSYM: + { + elf_section_t *es = + elf_get_section_by_start_address_no_check (em, e->data); + /* If section is not found just leave e->data alone. */ + if (es) + e->data = es->header.exec_address; + break; + } + + default: + break; + } + } + } + + if (em->first_header.file_class == ELF_64BIT) + { + elf64_dynamic_entry_t *e, *es; + + es = em->dynamic_entries; + if (em->need_byte_swap) + { + es = vec_dup (es); + vec_foreach (e, es) + { + e->type = elf_swap_u64 (em, e->type); + e->data = elf_swap_u64 (em, e->data); + } + } + + elf_set_section_contents (em, em->dynamic_section_index, es, + vec_bytes (es)); + if (es != em->dynamic_entries) + vec_free (es); + } + else + { + elf32_dynamic_entry_t *es; + + vec_clone (es, em->dynamic_entries); + if (em->need_byte_swap) + { + for (i = 0; i < vec_len (es); i++) + { + es[i].type = elf_swap_u32 (em, em->dynamic_entries[i].type); + es[i].data = elf_swap_u32 (em, em->dynamic_entries[i].data); + } + } + + elf_set_section_contents (em, em->dynamic_section_index, es, + vec_bytes (es)); + vec_free (es); + } +} + +clib_error_t * +elf_parse (elf_main_t * em, void *data, uword data_bytes) +{ + elf_first_header_t *h = data; + elf64_file_header_t *fh = &em->file_header; + clib_error_t *error = 0; + + { + char *save = em->file_name; + memset (em, 0, sizeof (em[0])); + em->file_name = save; + } + + em->first_header = h[0]; + em->need_byte_swap = + CLIB_ARCH_IS_BIG_ENDIAN != (h->data_encoding == + ELF_TWOS_COMPLEMENT_BIG_ENDIAN); + elf_swap_first_header (em, &em->first_header); + + if (!(h->magic[0] == 0x7f + && h->magic[1] == 'E' && h->magic[2] == 'L' && h->magic[3] == 'F')) + return clib_error_return (0, "`%s': bad magic", em->file_name); + + if (h->file_class == ELF_64BIT) + { + elf64_file_header_t *h64 = (void *) (h + 1); +#define _(t,f) fh->f = elf_swap_##t (em, h64->f); + foreach_elf64_file_header +#undef _ + } + else + { + elf32_file_header_t *h32 = (void *) (h + 1); + +#define _(t,f) fh->f = elf_swap_##t (em, h32->f); + foreach_elf32_file_header +#undef _ + } + + elf_parse_segments (em, data); + elf_parse_sections (em, data); + + /* Figure which sections are contained in each segment. */ + { + elf_segment_t *g; + elf_section_t *s; + vec_foreach (g, em->segments) + { + u64 g_lo, g_hi; + u64 s_lo, s_hi; + + if (g->header.memory_size == 0) + continue; + + g_lo = g->header.virtual_address; + g_hi = g_lo + g->header.memory_size; + + vec_foreach (s, em->sections) + { + s_lo = s->header.exec_address; + s_hi = s_lo + s->header.file_size; + + if (s_lo >= g_lo && s_hi <= g_hi) + { + g->section_index_bitmap = + clib_bitmap_ori (g->section_index_bitmap, s->index); + s->segment_index_bitmap = + clib_bitmap_ori (s->segment_index_bitmap, g->index); + } + } + } + } + + return error; +} + +#ifdef CLIB_UNIX + +static void +add_dynamic_entries (elf_main_t * em, elf_section_t * s) +{ + uword i; + + /* Can't have more than one dynamic section. */ + ASSERT (em->dynamic_section_index == 0); + em->dynamic_section_index = s->index; + + if (em->first_header.file_class == ELF_64BIT) + { + elf64_dynamic_entry_t *e; + + e = elf_get_section_contents (em, s - em->sections, sizeof (e[0])); + if (em->need_byte_swap) + for (i = 0; i < vec_len (e); i++) + { + e[i].type = elf_swap_u64 (em, e[i].type); + e[i].data = elf_swap_u64 (em, e[i].data); + } + + em->dynamic_entries = e; + } + else + { + elf32_dynamic_entry_t *e; + + e = elf_get_section_contents (em, s - em->sections, sizeof (e[0])); + vec_clone (em->dynamic_entries, e); + if (em->need_byte_swap) + for (i = 0; i < vec_len (e); i++) + { + em->dynamic_entries[i].type = elf_swap_u32 (em, e[i].type); + em->dynamic_entries[i].data = elf_swap_u32 (em, e[i].data); + } + + vec_free (e); + } +} + +static void +byte_swap_verneed (elf_main_t * em, elf_dynamic_version_need_union_t * vus) +{ + uword *entries_swapped = 0; + uword i, j; + + for (i = 0; i < vec_len (vus); i++) + { + elf_dynamic_version_need_union_t *n = vec_elt_at_index (vus, i); + elf_dynamic_version_need_union_t *a; + + if (clib_bitmap_get (entries_swapped, i)) + continue; + + elf_swap_verneed (&n->need); + entries_swapped = clib_bitmap_set (entries_swapped, i, 1); + + if (n->need.first_aux_offset != 0) + { + ASSERT (n->need.first_aux_offset % sizeof (n[0]) == 0); + j = i + (n->need.first_aux_offset / sizeof (n[0])); + while (1) + { + a = vec_elt_at_index (vus, j); + if (!clib_bitmap_get (entries_swapped, j)) + { + entries_swapped = clib_bitmap_set (entries_swapped, j, 1); + elf_swap_verneed_aux (&a->aux); + } + if (a->aux.next_offset == 0) + break; + ASSERT (a->aux.next_offset % sizeof (a->aux) == 0); + j += (a->aux.next_offset / sizeof (a->aux)); + } + } + } + + clib_bitmap_free (entries_swapped); +} + +static void set_dynamic_verneed (elf_main_t * em) __attribute__ ((unused)); +static void +set_dynamic_verneed (elf_main_t * em) +{ + elf_dynamic_version_need_union_t *vus = em->verneed; + + if (em->need_byte_swap) + { + vus = vec_dup (vus); + byte_swap_verneed (em, vus); + } + + elf_set_section_contents (em, em->verneed_section_index, vus, + vec_bytes (vus)); + if (vus != em->verneed) + vec_free (vus); +} + +static void +set_symbol_table (elf_main_t * em, u32 table_index) __attribute__ ((unused)); +static void +set_symbol_table (elf_main_t * em, u32 table_index) +{ + elf_symbol_table_t *tab = vec_elt_at_index (em->symbol_tables, table_index); + + if (em->first_header.file_class == ELF_64BIT) + { + elf64_symbol_t *s, *syms; + + syms = vec_dup (tab->symbols); + vec_foreach (s, syms) + { +#define _(t,f) s->f = elf_swap_##t (em, s->f); + foreach_elf64_symbol_header; +#undef _ + } + + elf_set_section_contents (em, tab->section_index, + syms, vec_bytes (syms)); + } + else + { + elf32_symbol_t *syms; + uword i; + vec_clone (syms, tab->symbols); + for (i = 0; i < vec_len (tab->symbols); i++) + { +#define _(t,f) syms[i].f = elf_swap_##t (em, tab->symbols[i].f); + foreach_elf32_symbol_header; +#undef _ + } + + elf_set_section_contents (em, tab->section_index, + syms, vec_bytes (syms)); + } +} + +static char * +elf_find_interpreter (elf_main_t * em, void *data) +{ + elf_segment_t *g; + elf_section_t *s; + uword *p; + + vec_foreach (g, em->segments) + { + if (g->header.type == ELF_SEGMENT_INTERP) + break; + } + + if (g >= vec_end (em->segments)) + return 0; + + p = hash_get (em->section_by_start_address, g->header.virtual_address); + if (!p) + return 0; + + s = vec_elt_at_index (em->sections, p[0]); + return (char *) vec_dup (s->contents); +} + +static void * +elf_get_section_contents_with_starting_address (elf_main_t * em, + uword start_address, + uword elt_size, + u32 * section_index_result) +{ + elf_section_t *s = 0; + clib_error_t *error; + + error = elf_get_section_by_start_address (em, start_address, &s); + if (error) + { + clib_error_report (error); + return 0; + } + + if (section_index_result) + *section_index_result = s->index; + + return elf_get_section_contents (em, s->index, elt_size); +} + +static void +elf_parse_dynamic (elf_main_t * em) +{ + elf_section_t *s; + elf64_dynamic_entry_t *e; + + vec_foreach (s, em->sections) + { + switch (s->header.type) + { + case ELF_SECTION_DYNAMIC: + add_dynamic_entries (em, s); + break; + + default: + break; + } + } + + em->dynamic_string_table_section_index = ~0; + em->dynamic_string_table = 0; + + vec_foreach (e, em->dynamic_entries) + { + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_STRING_TABLE: + ASSERT (vec_len (em->dynamic_string_table) == 0); + em->dynamic_string_table + = + elf_get_section_contents_with_starting_address (em, e->data, + sizeof (u8), + &em-> + dynamic_string_table_section_index); + break; + + case ELF_DYNAMIC_ENTRY_SYMBOL_TABLE: + { + elf_section_t *s = 0; + clib_error_t *error; + + error = elf_get_section_by_start_address (em, e->data, &s); + if (error) + { + clib_error_report (error); + return; + } + + em->dynamic_symbol_table_section_index = s - em->sections; + } + break; + + case ELF_DYNAMIC_ENTRY_VERSYM: + em->versym + = + elf_get_section_contents_with_starting_address (em, e->data, + sizeof (em->versym + [0]), + &em-> + versym_section_index); + if (em->need_byte_swap) + { + uword i; + for (i = 0; i < vec_len (em->versym); i++) + em->versym[i] = clib_byte_swap_u16 (em->versym[i]); + } + break; + + case ELF_DYNAMIC_ENTRY_VERSION_NEED: + em->verneed + = + elf_get_section_contents_with_starting_address (em, e->data, + sizeof (em->verneed + [0]), + &em-> + verneed_section_index); + if (em->need_byte_swap) + byte_swap_verneed (em, em->verneed); + break; + + default: + break; + } + } +} + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +clib_error_t * +elf_read_file (elf_main_t * em, char *file_name) +{ + int fd; + struct stat fd_stat; + uword mmap_length = 0; + void *data = 0; + clib_error_t *error = 0; + + elf_main_init (em); + + fd = open (file_name, 0); + if (fd < 0) + { + error = clib_error_return_unix (0, "open `%s'", file_name); + goto done; + } + + if (fstat (fd, &fd_stat) < 0) + { + error = clib_error_return_unix (0, "fstat `%s'", file_name); + goto done; + } + mmap_length = fd_stat.st_size; + + data = mmap (0, mmap_length, PROT_READ, MAP_SHARED, fd, /* offset */ 0); + if (~pointer_to_uword (data) == 0) + { + error = clib_error_return_unix (0, "mmap `%s'", file_name); + goto done; + } + + em->file_name = file_name; + + error = elf_parse (em, data, mmap_length); + if (error) + goto done; + + elf_parse_symbols (em); + elf_parse_dynamic (em); + + em->interpreter = elf_find_interpreter (em, data); + + munmap (data, mmap_length); + close (fd); + + return /* no error */ 0; + +done: + elf_main_free (em); + if (fd >= 0) + close (fd); + if (data) + munmap (data, mmap_length); + return error; +} + +typedef struct +{ + u8 *new_table; + + u8 *old_table; + + uword *hash; +} string_table_builder_t; + +static u32 +string_table_add_name (string_table_builder_t * b, u8 * n) +{ + uword *p, i, j, l; + + p = hash_get_mem (b->hash, n); + if (p) + return p[0]; + + l = strlen ((char *) n); + i = vec_len (b->new_table); + vec_add (b->new_table, n, l + 1); + + for (j = 0; j <= l; j++) + { + if (j > 0) + { + p = hash_get_mem (b->hash, n + j); + + /* Sub-string already in table? */ + if (p) + continue; + } + + hash_set_mem (b->hash, n + j, i + j); + } + + return i; +} + +static u32 string_table_add_name_index (string_table_builder_t * b, u32 index) + __attribute__ ((unused)); +static u32 +string_table_add_name_index (string_table_builder_t * b, u32 index) +{ + u8 *n = b->old_table + index; + return string_table_add_name (b, n); +} + +static void string_table_init (string_table_builder_t * b, u8 * old_table) + __attribute__ ((unused)); +static void +string_table_init (string_table_builder_t * b, u8 * old_table) +{ + memset (b, 0, sizeof (b[0])); + b->old_table = old_table; + b->hash = hash_create_string (0, sizeof (uword)); +} + +static u8 *string_table_done (string_table_builder_t * b) + __attribute__ ((unused)); +static u8 * +string_table_done (string_table_builder_t * b) +{ + hash_free (b->hash); + return b->new_table; +} + +static void +layout_sections (elf_main_t * em) +{ + elf_section_t *s; + u32 n_sections_with_changed_exec_address = 0; + u32 *deferred_symbol_and_string_sections = 0; + u32 n_deleted_sections = 0; + /* note: rebuild is always zero. Intent lost in the sands of time */ +#if 0 + int rebuild = 0; + + /* Re-build section string table (sections may have been deleted). */ + if (rebuild) + { + u8 *st = 0; + + vec_foreach (s, em->sections) + { + u8 *name; + if (s->header.type == ~0) + continue; + name = elf_section_name (em, s); + s->header.name = vec_len (st); + vec_add (st, name, strlen ((char *) name) + 1); + } + + s = + vec_elt_at_index (em->sections, + em->file_header.section_header_string_table_index); + + vec_free (s->contents); + s->contents = st; + } + + /* Re-build dynamic string table. */ + if (rebuild && em->dynamic_string_table_section_index != ~0) + { + string_table_builder_t b; + + string_table_init (&b, em->dynamic_string_table); + + /* Add all dynamic symbols. */ + { + elf_symbol_table_t *symtab; + elf64_symbol_t *sym; + + symtab = + vec_elt_at_index (em->symbol_tables, + em->dynamic_symbol_table_index); + vec_foreach (sym, symtab->symbols) + { + u8 *name = elf_symbol_name (symtab, sym); + sym->name = string_table_add_name (&b, name); + } + + set_symbol_table (em, em->dynamic_symbol_table_index); + } + + /* Add all dynamic entries. */ + { + elf64_dynamic_entry_t *e; + + vec_foreach (e, em->dynamic_entries) + { + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_NEEDED_LIBRARY: + case ELF_DYNAMIC_ENTRY_RPATH: + case ELF_DYNAMIC_ENTRY_RUN_PATH: + e->data = string_table_add_name_index (&b, e->data); + break; + } + } + } + + /* Add all version needs. */ + if (vec_len (em->verneed) > 0) + { + elf_dynamic_version_need_union_t *n, *a; + + n = em->verneed; + while (1) + { + n->need.file_name_offset = + string_table_add_name_index (&b, n->need.file_name_offset); + + if (n->need.first_aux_offset != 0) + { + a = n + n->need.first_aux_offset / sizeof (n[0]); + while (1) + { + a->aux.name = + string_table_add_name_index (&b, a->aux.name); + if (a->aux.next_offset == 0) + break; + a += a->aux.next_offset / sizeof (a[0]); + } + } + + if (n->need.next_offset == 0) + break; + + n += n->need.next_offset / sizeof (n[0]); + } + + set_dynamic_verneed (em); + } + + s = + vec_elt_at_index (em->sections, + em->dynamic_string_table_section_index); + + vec_free (s->contents); + s->contents = string_table_done (&b); + } +#endif /* dead code */ + + /* Figure file offsets and exec addresses for sections. */ + { + u64 exec_address = 0, file_offset = 0; + u64 file_size, align_size; + + vec_foreach (s, em->sections) + { + /* Ignore deleted and unused sections. */ + switch (s->header.type) + { + case ~0: + n_deleted_sections++; + case ELF_SECTION_UNUSED: + continue; + + case ELF_SECTION_STRING_TABLE: + case ELF_SECTION_SYMBOL_TABLE: + if (!(s->index == em->dynamic_string_table_section_index + || s->index == + em->file_header.section_header_string_table_index)) + { + vec_add1 (deferred_symbol_and_string_sections, s->index); + continue; + } + break; + + default: + break; + } + + exec_address = round_pow2_u64 (exec_address, s->header.align); + + /* Put sections we added at end of file. */ + if (s->header.file_offset == ~0) + s->header.file_offset = file_offset; + + /* Follow gaps in original file. */ + if (s->header.exec_address > exec_address) + { + exec_address = s->header.exec_address; + file_offset = s->header.file_offset; + } + + if (s->header.flags & ELF_SECTION_FLAG_ALLOC) + { + s->exec_address_change = exec_address - s->header.exec_address; + n_sections_with_changed_exec_address += s->exec_address_change != 0; + s->header.exec_address = exec_address; + } + + if (s->header.type == ELF_SECTION_NO_BITS) + file_size = s->header.file_size; + else + file_size = vec_len (s->contents); + + { + u64 align; + + if (s + 1 >= vec_end (em->sections)) + align = 16; + else if (s[1].header.type == ELF_SECTION_NO_BITS) + align = 8; + else + align = s[1].header.align; + + if (s->header.flags & ELF_SECTION_FLAG_ALLOC) + { + u64 v = round_pow2_u64 (exec_address + file_size, align); + align_size = v - exec_address; + } + else + { + u64 v = round_pow2_u64 (file_offset + file_size, align); + align_size = v - file_offset; + } + } + + s->header.file_offset = file_offset; + s->header.file_size = file_size; + s->align_size = align_size; + + if (s->header.type != ELF_SECTION_NO_BITS) + file_offset += align_size; + exec_address += align_size; + } + + /* Section headers go after last section but before symbol/string + tables. */ + { + elf64_file_header_t *fh = &em->file_header; + + fh->section_header_file_offset = file_offset; + fh->section_header_count = vec_len (em->sections) - n_deleted_sections; + file_offset += (u64) fh->section_header_count * fh->section_header_size; + } + + { + int i; + for (i = 0; i < vec_len (deferred_symbol_and_string_sections); i++) + { + s = + vec_elt_at_index (em->sections, + deferred_symbol_and_string_sections[i]); + + s->header.file_offset = file_offset; + s->header.file_size = vec_len (s->contents); + + align_size = round_pow2 (vec_len (s->contents), 16); + s->align_size = align_size; + file_offset += align_size; + } + vec_free (deferred_symbol_and_string_sections); + } + } + + /* Update dynamic entries now that sections have been assigned + possibly new addresses. */ +#if 0 + if (rebuild) + elf_set_dynamic_entries (em); +#endif + + /* Update segments for changed section addresses. */ + { + elf_segment_t *g; + uword si; + + vec_foreach (g, em->segments) + { + u64 s_lo, s_hi, f_lo = 0; + u32 n_sections = 0; + + if (g->header.memory_size == 0) + continue; + + s_lo = s_hi = 0; + /* *INDENT-OFF* */ + clib_bitmap_foreach (si, g->section_index_bitmap, ({ + u64 lo, hi; + + s = vec_elt_at_index (em->sections, si); + lo = s->header.exec_address; + hi = lo + s->align_size; + if (n_sections == 0) + { + s_lo = lo; + s_hi = hi; + f_lo = s->header.file_offset; + n_sections++; + } + else + { + if (lo < s_lo) + { + s_lo = lo; + f_lo = s->header.file_offset; + } + if (hi > s_hi) + s_hi = hi; + } + })); + /* *INDENT-ON* */ + + if (n_sections == 0) + continue; + + /* File offset zero includes ELF headers/segment headers. + Don't change that. */ + if (g->header.file_offset == 0 && g->header.type == ELF_SEGMENT_LOAD) + { + s_lo = g->header.virtual_address; + f_lo = g->header.file_offset; + } + + g->header.virtual_address = s_lo; + g->header.physical_address = s_lo; + g->header.file_offset = f_lo; + g->header.memory_size = s_hi - s_lo; + } + } +} + +clib_error_t * +elf_write_file (elf_main_t * em, char *file_name) +{ + int fd; + FILE *f; + clib_error_t *error = 0; + + fd = open (file_name, O_CREAT | O_RDWR | O_TRUNC, 0755); + if (fd < 0) + return clib_error_return_unix (0, "open `%s'", file_name); + + f = fdopen (fd, "w"); + + /* Section contents may have changed. So, we need to update + stuff to reflect this. */ + layout_sections (em); + + /* Write first header. */ + { + elf_first_header_t h = em->first_header; + + elf_swap_first_header (em, &h); + if (fwrite (&h, sizeof (h), 1, f) != 1) + { + error = clib_error_return_unix (0, "write first header"); + goto error; + } + } + + /* Write file header. */ + { + elf64_file_header_t h = em->file_header; + + /* Segment headers are after first header. */ + h.segment_header_file_offset = sizeof (elf_first_header_t); + if (em->first_header.file_class == ELF_64BIT) + h.segment_header_file_offset += sizeof (elf64_file_header_t); + else + h.segment_header_file_offset += sizeof (elf32_file_header_t); + + if (em->first_header.file_class == ELF_64BIT) + { +#define _(t,field) h.field = elf_swap_##t (em, h.field); + foreach_elf64_file_header; +#undef _ + + if (fwrite (&h, sizeof (h), 1, f) != 1) + { + error = clib_error_return_unix (0, "write file header"); + goto error; + } + } + else + { + elf32_file_header_t h32; + +#define _(t,field) h32.field = elf_swap_##t (em, h.field); + foreach_elf32_file_header; +#undef _ + + if (fwrite (&h32, sizeof (h32), 1, f) != 1) + { + error = clib_error_return_unix (0, "write file header"); + goto error; + } + } + } + + /* Write segment headers. */ + { + elf_segment_t *s; + + vec_foreach (s, em->segments) + { + elf64_segment_header_t h; + + if (s->header.type == ~0) + continue; + + h = s->header; + + if (em->first_header.file_class == ELF_64BIT) + { +#define _(t,field) h.field = elf_swap_##t (em, h.field); + foreach_elf64_segment_header; +#undef _ + + if (fwrite (&h, sizeof (h), 1, f) != 1) + { + error = + clib_error_return_unix (0, "write segment header %U", + format_elf_segment, em, s); + goto error; + } + } + else + { + elf32_segment_header_t h32; + +#define _(t,field) h32.field = elf_swap_##t (em, h.field); + foreach_elf32_segment_header; +#undef _ + + if (fwrite (&h32, sizeof (h32), 1, f) != 1) + { + error = + clib_error_return_unix (0, "write segment header %U", + format_elf_segment, em, s); + goto error; + } + } + } + } + + /* Write contents for all sections. */ + { + elf_section_t *s; + + vec_foreach (s, em->sections) + { + if (s->header.file_size == 0) + continue; + + if (fseek (f, s->header.file_offset, SEEK_SET) < 0) + { + fclose (f); + return clib_error_return_unix (0, "fseek 0x%Lx", + s->header.file_offset); + } + + if (s->header.type == ELF_SECTION_NO_BITS) + /* don't write for .bss sections */ ; + else if (fwrite (s->contents, vec_len (s->contents), 1, f) != 1) + { + error = + clib_error_return_unix (0, "write %s section contents", + elf_section_name (em, s)); + goto error; + } + } + + /* Finally write section headers. */ + if (fseek (f, em->file_header.section_header_file_offset, SEEK_SET) < 0) + { + fclose (f); + return clib_error_return_unix + (0, "fseek 0x%Lx", em->file_header.section_header_file_offset); + } + + vec_foreach (s, em->sections) + { + elf64_section_header_t h; + + if (s->header.type == ~0) + continue; + + h = s->header; + + if (em->first_header.file_class == ELF_64BIT) + { +#define _(t,field) h.field = elf_swap_##t (em, h.field); + foreach_elf64_section_header; +#undef _ + + if (fwrite (&h, sizeof (h), 1, f) != 1) + { + error = + clib_error_return_unix (0, "write %s section header", + elf_section_name (em, s)); + goto error; + } + } + else + { + elf32_section_header_t h32; + +#define _(t,field) h32.field = elf_swap_##t (em, h.field); + foreach_elf32_section_header; +#undef _ + + if (fwrite (&h32, sizeof (h32), 1, f) != 1) + { + error = + clib_error_return_unix (0, "write %s section header", + elf_section_name (em, s)); + goto error; + } + } + } + } + +error: + fclose (f); + return error; +} + +clib_error_t * +elf_delete_named_section (elf_main_t * em, char *section_name) +{ + elf_section_t *s = 0; + clib_error_t *error; + + error = elf_get_section_by_name (em, section_name, &s); + if (error) + return error; + + s->header.type = ~0; + + return 0; +} + +void +elf_create_section_with_contents (elf_main_t * em, + char *section_name, + elf64_section_header_t * header, + void *contents, uword n_content_bytes) +{ + elf_section_t *s, *sts; + u8 *st, *c; + uword *p, is_new_section; + + /* See if section already exists with given name. + If so, just replace contents. */ + is_new_section = 0; + if ((p = hash_get_mem (em->section_by_name, section_name))) + { + s = vec_elt_at_index (em->sections, p[0]); + _vec_len (s->contents) = 0; + c = s->contents; + } + else + { + vec_add2 (em->sections, s, 1); + is_new_section = 1; + c = 0; + } + + sts = + vec_elt_at_index (em->sections, + em->file_header.section_header_string_table_index); + st = sts->contents; + + s->header = header[0]; + + s->header.file_offset = ~0; + s->header.file_size = n_content_bytes; + s->index = s - em->sections; + + /* Add name to string table. */ + s->header.name = vec_len (st); + vec_add (st, section_name, strlen (section_name)); + vec_add1 (st, 0); + sts->contents = st; + + vec_resize (c, n_content_bytes); + clib_memcpy (c, contents, n_content_bytes); + s->contents = c; + + em->file_header.section_header_count += is_new_section + && s->header.type != ~0; +} + +uword +elf_delete_segment_with_type (elf_main_t * em, + elf_segment_type_t segment_type) +{ + uword n_deleted = 0; + elf_segment_t *s; + + vec_foreach (s, em->segments) if (s->header.type == segment_type) + { + s->header.type = ~0; + n_deleted += 1; + } + + ASSERT (em->file_header.segment_header_count >= n_deleted); + em->file_header.segment_header_count -= n_deleted; + + return n_deleted; +} + +#endif /* CLIB_UNIX */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |