/* * 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) <style>.highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span><span class="gh">#</span> CSIT - Continuous System Integration Testing <span class="k">1.</span> [<span class="nt">Architecture</span>](<span class="na">#architecture</span>) <span class="k">1.</span> [<span class="nt">Directory Structure</span>](<span class="na">#directory-structure</span>) <span class="k">1.</span> [<span class="nt">Tests</span>](<span class="na">#tests</span>) <span class="k">1.</span> [<span class="nt">Keywords</span>](<span class="na">#keywords</span>) <span class="k">1.</span> [<span class="nt">Other Resources</span>](<span class="na">#other-resources</span>) <span class="k">1.</span> [<span class="nt">Quickstart</span>](<span class="na">#quick-start</span>) <span class="k">1.</span> [<span class="nt">Vagrant</span>](<span class="na">#vagrant</span>) <span class="k">1.</span> [<span class="nt">Physical Testbed</span>](<span class="na">#physical-testbed</span>) <span class="k">1.</span> [<span class="nt">Report</span>](<span class="na">#report</span>) <span class="k">1.</span> [<span class="nt">Trending</span>](<span class="na">#trending</span>) <span class="k">1.</span> [<span class="nt">Code Documentation</span>](<span class="na">#code-documentation</span>) <span class="k">1.</span> [<span class="nt">Coding Guidelines</span>](<span class="na">#coding-guidelines</span>) <span class="gu">##</span> Architecture FD.io CSIT system design needs to meet continuously expanding requirements of FD.io projects including VPP, related sub-systems (e.g. plugin applications, DPDK drivers) and FD.io applications (e.g. DPDK applications), as well as growing number of compute platforms running those applications. With CSIT project scope and charter including both FD.io continuous testing AND performance trending/comparisons, those evolving requirements further amplify the need for CSIT framework modularity, flexibility and usability. CSIT follows a hierarchical system design with SUTs and DUTs at the bottom level of the hierarchy, presentation level at the top level and a number of functional layers in-between. The current CSIT system design including CSIT framework is depicted in the figure below.  A brief bottom-up description is provided here: <span class="k">1.</span> SUTs, DUTs, TGs <span class="k">-</span> SUTs - Systems Under Test; <span class="k">-</span> DUTs - Devices Under Test; <span class="k">-</span> TGs - Traffic Generators; <span class="k">1.</span> Level-1 libraries - Robot and Python <span class="k">-</span> Lowest level CSIT libraries abstracting underlying test environment, SUT, DUT and TG specifics; <span class="k">-</span> Used commonly across multiple L2 KWs; <span class="k">-</span> Performance and functional tests: <span class="k">-</span> L1 KWs (KeyWords) are implemented as RF libraries and Python libraries; <span class="k">-</span> Performance TG L1 KWs: <span class="k">-</span> All L1 KWs are implemented as Python libraries: <span class="k">-</span> Support for TRex only today; <span class="k">-</span> Performance data plane traffic profiles: <span class="k">-</span> TG-specific stream profiles provide full control of: <span class="k">-</span> Packet definition – layers, MACs, IPs, ports, combinations thereof e.g. IPs and UDP ports; <span class="k">-</span> Stream definitions - different streams can run together, delayed, one after each other; <span class="k">-</span> Stream profiles are independent of CSIT framework and can be used in any T-rex setup, can be sent anywhere to repeat tests with exactly the same setup; <span class="k">-</span> Easily extensible – one can create a new stream profile that meets tests requirements; <span class="k">-</span> Same stream profile can be used for different tests with the same traffic needs; <span class="k">-</span> Functional data plane traffic scripts: <span class="k">-</span> Scapy specific traffic scripts; <span class="k">1.</span> Level-2 libraries - Robot resource files <span class="k">-</span> Higher level CSIT libraries abstracting required functions for executing tests; <span class="k">-</span> L2 KWs are classified into the following functional categories: <span class="k">-</span> Configuration, test, verification, state report; <span class="k">-</span> Suite setup, suite teardown; <span class="k">-</span> Test setup, test teardown; <span class="k">1.</span> Tests - Robot <span class="k">-</span> Device tests using containerized environment with SR-IOV access to a NIC; <span class="k">-</span> VPP; <span class="k">-</span> Performance tests using physical testbed environment: <span class="k">-</span> VPP; <span class="k">-</span> DPDK-Testpmd; <span class="k">-</span> DPDK-L3Fwd; <span class="k">-</span> Tools: <span class="k">-</span> Documentation generator; <span class="k">-</span> Report generator; <span class="k">-</span> Testbed environment setup ansible playbooks; <span class="k">-</span> Operational debugging scripts; <span class="gu">##</span> Directory Structure <span class="gu">###</span> Tests <span class="s">```</span> . └── tests ├── dpdk │ ├── dpdk_scripts # DPDK helper scripts │ └── perf # DPDK performance tests └── vpp ├── device # VPP device tests └── perf # VPP performance tests <span class="s">```</span> <span class="gu">###</span> Keywords <span class="s">```</span> . resources └── libraries ├── bash # Contains a dependency of KubernetesUtils │ ├── config # Config for KubernetesUtils dependency │ ├── entry # Main bootstrap entry directory │ ├── function # Bootstrap function library │ └── shell # Various functions for KubernetesUtils ├── python # Python L1 KWs └── robot # Robot Framework L2 KWs <span class="s">```</span> <span class="gu">###</span> Other Resources <span class="s">```</span> . ├── docs # Main documentaion ├── PyPI # PyPI packages provided by CSIT │ ├── jumpavg │ └── MLRsearch ├── resources │ ├── templates # Templates (vpp_api_test, kubernetes, ...) │ ├── test_data # Robot Test configuration │ ├── tools │ │ ├── disk-image-builder # Utilities for building (DCR, VM) images │ │ ├── doc_gen # Code documentation generator │ │ ├── papi # PAPI driver │ │ ├── presentation # Report generator │ │ ├── scripts # Various tools │ │ ├── testbed-setup # Physical testbed setup scripts │ │ ├── topology # Helper scripts for topology manipulation │ │ ├── trex # TRex driver │ │ ├── vagrant # VPP device vagrant environment │ │ └── wrk # WRK driver │ ├── topology_schemas │ ├── traffic_profiles # Performance tests traffic profiles │ │ ├── trex │ │ └── wrk │ └── traffic_scripts # Functional tests traffic profiles │ ├── dhcp │ └── lisp └── topologies # Linux Foundation topology files ├── available └── enabled <span class="s">```</span> <span class="gu">##</span> Quickstart <span class="gu">###</span> Vagrant [<span class="nt">Vagrant environment preparation</span>](<span class="na">docs/testing_in_vagrant.rst</span>) documentaion is describing local VPP Device functional testing. <span class="gu">###</span> Physical Testbed [<span class="nt">Physical testbed preparation</span>](<span class="na">resources/tools/testbed-setup/README.rst</span>) documentation is describing PXE and Ansible setup process. All the software requirements for running Performance Teste are part of Ansible playbooks. <span class="gu">##</span> Report [<span class="nt">CSIT Report</span>](<span class="na">https://docs.fd.io/csit/master/report/</span>). <span class="gu">##</span> Trending [<span class="nt">CSIT Trending</span>](<span class="na">https://docs.fd.io/csit/master/trending/</span>). <span class="gu">##</span> Code Documentation [<span class="nt">CSIT Code Documentation</span>](<span class="na">https://docs.fd.io/csit/master/doc/</span>). <span class="gu">##</span> Coding Guidelines If you are interested in contributing, please see the [<span class="nt">coding guidelines</span>](<span class="na">docs/test_code_guidelines.rst</span>). </pre></div> </code></pre></td></tr></table> </div> <!-- class=content --> <div id="lfcollabprojects-footer"> <div class="gray-diagonal"> <div class="footer-inner"> <p> © 2016 <a href="https://www.fd.io/">FD.io</a> a Linux Foundation Collaborative Project. All Rights Reserved. </p> <p> Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered <a href="http://www.linuxfoundation.org/programs/legal/trademark" title="Linux Mark Institute" >trademark</a > of Linus Torvalds. </p> <p> Please see our <a href="http://www.linuxfoundation.org/privacy">privacy policy</a> and <a href="http://www.linuxfoundation.org/terms">terms of use</a> </p> </div> </div> </div> </div> <!-- id=cgit --> </body> </html> 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: */