summaryrefslogtreecommitdiffstats
path: root/src/vppinfra/elf_clib.c
blob: 2bc05e1d8d4dba8c7787f988bbe029d1cbf85ead (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.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 */
}
# Test VPPCOM config file
vcl {
  heapsize 1G
  heapsize 1
  vpp-api-q-length 32
  vpp-api-q-length 65536
  api-prefix daw  # this is a comment
  uid 1020 this is also a comment.
  gid 1020
# This is yet another comment!
  segment-baseva 0x300000000
  segment-size 0x10000000
  segment-size 268435456
  add-segment-size 0x1000000
  add-segment-size 134217728
  preallocated-fifo-pairs 16
  rx-fifo-size 3145728
  rx-fifo-size 0x300000
  tx-fifo-size 3145728
  tx-fifo-size 0x300000
  event-queue-size 1024
  event-queue-size 0x400
  listen-queue-size 32
  listen-queue-size 0x20
  app-timeout 54.3
  session-timeout 66.6
  accept-timeout 0.1
  app-proxy-transport-tcp
  app-proxy-transport-udp
  app-scope-local
  app-scope-global
  namespace-id 0123456789012345678901234567890123456789012345678901234567890123456789
  namespace-id Oh_Bother!_Said_Winnie-The-Pooh
  namespace-secret 42
}
54 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
/*
 * 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/elf_clib.h>

#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>

typedef struct
{
  char **path;
} path_search_t;

always_inline void
path_search_free (path_search_t * p)
{
  uword i;
  for (i = 0; i < vec_len (p->path); i++)
    vec_free (p->path[i]);
  vec_free (p->path);
}

static char **
split_string (char *string, u8 delimiter)
{
  char **result = 0;
  char *p, *start, *s;

  p = string;
  while (1)
    {
      start = p;
      while (*p != 0 && *p != delimiter)
	p++;
      s = 0;
      vec_add (s, start, p - start);
      vec_add1 (s, 0);
      vec_add1 (result, s);
      if (*p == 0)
	break;
      p++;
    }

  return result;
}

static int
file_exists_and_is_executable (char *dir, char *file)
{
  char *path = (char *) format (0, "%s/%s%c", dir, file, 0);
  struct stat s;
  uword yes;

  yes = (stat (path, &s) >= 0
	 && S_ISREG (s.st_mode)
	 && 0 != (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)));

  vec_free (path);

  return yes;
}

static char *
path_search (char *file)
{
  path_search_t ps;
  uword i;
  char *result;

  /* Relative or absolute path. */
  if (file[0] == '.' || file[0] == '/')
    return file;

  if (getenv ("PATH") == 0)
    return file;

  ps.path = split_string (getenv ("PATH"), ':');

  for (i = 0; i < vec_len (ps.path); i++)
    if (file_exists_and_is_executable (ps.path[i], file))
      break;

  result = 0;
  if (i < vec_len (ps.path))
    result = (char *) format (0, "%s/%s%c", ps.path[i], file);

  path_search_free (&ps);

  return result;
}

static clib_error_t *
clib_elf_parse_file (clib_elf_main_t * cem,
		     char *file_name, void *link_address)
{
  elf_main_t *em;
  elf_section_t *s;
  int fd;
  struct stat fd_stat;
  uword mmap_length = 0;
  void *data = 0;
  clib_error_t *error = 0;

  vec_add2 (cem->elf_mains, em, 1);

  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;
    }

  error = elf_parse (em, data, mmap_length);
  if (error)
    goto done;

  /* Look for CLIB special sections. */
  {
    char *section_name_start = CLIB_ELF_SECTION_ADD_PREFIX ();
    uword section_name_start_len = strlen (section_name_start);

    vec_foreach (s, em->sections)
    {
      u8 *name = elf_section_name (em, s);
      uword *p;
      clib_elf_section_t *vs;
      clib_elf_section_bounds_t *b;

      /* Section name must begin with CLIB_ELF_SECTION key. */
      if (strcmp ((char *) name, section_name_start))
	continue;

      name += section_name_start_len;
      p = hash_get_mem (cem->section_by_name, name);
      if (p)
	vs = vec_elt_at_index (cem->sections, p[0]);
      else
	{
	  name = format (0, "%s%c", name, 0);
	  if (!cem->section_by_name)
	    cem->section_by_name = hash_create_string (0, sizeof (uword));
	  hash_set_mem (cem->section_by_name, name, vec_len (cem->sections));
	  vec_add2 (cem->sections, vs, 1);
	  vs->name = name;
	}

      vec_add2 (vs->bounds, b, 1);
      b->lo = link_address + s->header.exec_address;
      b->hi = b->lo + s->header.file_size;
    }
  }

  /* Parse symbols for this file. */
  {
    elf_symbol_table_t *t;
    elf64_symbol_t *s;

    elf_parse_symbols (em);
    vec_foreach (t, em->symbol_tables)
    {
      vec_foreach (s, t->symbols)
      {
	s->value += pointer_to_uword (link_address);
      }
    }
  }

  /* No need to keep section contents around. */
  {
    elf_section_t *s;
    vec_foreach (s, em->sections)
    {
      if (s->header.type != ELF_SECTION_STRING_TABLE)
	vec_free (s->contents);
    }
  }

done:
  if (error)
    elf_main_free (em);
  if (fd >= 0)
    close (fd);
  if (data)
    munmap (data, mmap_length);
  return error;
}

#define __USE_GNU
#include <link.h>

static int
add_section (struct dl_phdr_info *info, size_t size, void *opaque)
{
  clib_elf_main_t *cem = opaque;
  clib_error_t *error;
  char *name = (char *) info->dlpi_name;
  void *addr = (void *) info->dlpi_addr;
  uword is_main;

  is_main = strlen (name) == 0;
  if (is_main)
    {
      static int done;

      /* Only do main program once. */
      if (done++)
	return 0;

      name = path_search (cem->exec_path);
      if (!name)
	{
	  clib_error ("failed to find %s on PATH", cem->exec_path);
	  return 0;
	}
      addr = 0;
    }

  error = clib_elf_parse_file (cem, name, addr);
  if (error)
    clib_error_report (error);

  if (is_main && name != cem->exec_path)
    vec_free (name);

  return 0;
}

static clib_elf_main_t clib_elf_main;

void
clib_elf_main_init (char *exec_path)
{
  clib_elf_main_t *cem = &clib_elf_main;

  cem->exec_path = exec_path;

  dl_iterate_phdr (add_section, cem);
}

clib_elf_section_bounds_t *
clib_elf_get_section_bounds (char *name)
{
  clib_elf_main_t *em = &clib_elf_main;
  uword *p = hash_get (em->section_by_name, name);
  return p ? vec_elt_at_index (em->sections, p[0])->bounds : 0;
}

static uword
symbol_by_address_or_name (char *by_name,
			   uword by_address, clib_elf_symbol_t * s)
{
  clib_elf_main_t *cem = &clib_elf_main;
  elf_main_t *em;

  vec_foreach (em, cem->elf_mains)
  {
    elf_symbol_table_t *t;
    s->elf_main_index = em - cem->elf_mains;
    vec_foreach (t, em->symbol_tables)
    {
      s->symbol_table_index = t - em->symbol_tables;
      if (by_name)
	{
	  uword *p = hash_get (t->symbol_by_name, by_name);
	  if (p)
	    {
	      s->symbol = vec_elt (t->symbols, p[0]);
	      return 1;
	    }
	}
      else
	{
	  elf64_symbol_t *x;
	  /* FIXME linear search. */
	  vec_foreach (x, t->symbols)
	  {
	    if (by_address >= x->value && by_address < x->value + x->size)
	      {
		s->symbol = x[0];
		return 1;
	      }
	  }
	}
    }
  }

  return 0;
}

uword
clib_elf_symbol_by_name (char *by_name, clib_elf_symbol_t * s)
{
  return symbol_by_address_or_name (by_name, /* by_address */ 0, s);
}

uword
clib_elf_symbol_by_address (uword by_address, clib_elf_symbol_t * s)
{
  return symbol_by_address_or_name ( /* by_name */ 0, by_address, s);
}

u8 *
format_clib_elf_symbol (u8 * s, va_list * args)
{
  clib_elf_main_t *cem = &clib_elf_main;
  clib_elf_symbol_t *sym = va_arg (*args, clib_elf_symbol_t *);
  elf_main_t *em;
  elf_symbol_table_t *t;

  if (!sym)
    /* Just print table headings. */
    return format (s, "%U", format_elf_symbol, 0, 0, 0);

  else
    {
      em = vec_elt_at_index (cem->elf_mains, sym->elf_main_index);
      t = vec_elt_at_index (em->symbol_tables, sym->symbol_table_index);
      return format (s, "%U", format_elf_symbol, em, t, &sym->symbol);
    }
}

u8 *
format_clib_elf_symbol_with_address (u8 * s, va_list * args)
{
  uword address = va_arg (*args, uword);
  clib_elf_main_t *cem = &clib_elf_main;
  clib_elf_symbol_t sym;
  elf_main_t *em;
  elf_symbol_table_t *t;

  if (clib_elf_symbol_by_address (address, &sym))
    {
      em = vec_elt_at_index (cem->elf_mains, sym.elf_main_index);
      t = vec_elt_at_index (em->symbol_tables, sym.symbol_table_index);
      s = format (s, "%s + 0x%wx",
		  elf_symbol_name (t, &sym.symbol),
		  address - sym.symbol.value);
    }
  else
    s = format (s, "0x%wx", address);

  return s;
}

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */