FD.io VPP  v21.06-3-gbb25fbf28
Vector Packet Processing
elf_clib.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vppinfra/elf_clib.h>
16 
17 #include <stdlib.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 
21 typedef struct
22 {
23  char **path;
25 
26 always_inline void
28 {
29  uword i;
30  for (i = 0; i < vec_len (p->path); i++)
31  vec_free (p->path[i]);
32  vec_free (p->path);
33 }
34 
35 static char **
36 split_string (char *string, u8 delimiter)
37 {
38  char **result = 0;
39  char *p, *start, *s;
40 
41  p = string;
42  while (1)
43  {
44  start = p;
45  while (*p != 0 && *p != delimiter)
46  p++;
47  s = 0;
48  vec_add (s, start, p - start);
49  vec_add1 (s, 0);
50  vec_add1 (result, s);
51  if (*p == 0)
52  break;
53  p++;
54  }
55 
56  return result;
57 }
58 
59 static int
60 file_exists_and_is_executable (char *dir, char *file)
61 {
62  char *path = (char *) format (0, "%s/%s%c", dir, file, 0);
63  struct stat s;
64  uword yes;
65 
66  yes = (stat (path, &s) >= 0
67  && S_ISREG (s.st_mode)
68  && 0 != (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)));
69 
70  vec_free (path);
71 
72  return yes;
73 }
74 
75 static char *
76 path_search (char *file)
77 {
78  path_search_t ps;
79  uword i;
80  char *result;
81 
82  /* Relative or absolute path. */
83  if (file[0] == '.' || file[0] == '/')
84  return file;
85 
86  if (getenv ("PATH") == 0)
87  return file;
88 
89  ps.path = split_string (getenv ("PATH"), ':');
90 
91  for (i = 0; i < vec_len (ps.path); i++)
92  if (file_exists_and_is_executable (ps.path[i], file))
93  break;
94 
95  result = 0;
96  if (i < vec_len (ps.path))
97  result = (char *) format (0, "%s/%s%c", ps.path[i], file, 0);
98 
99  path_search_free (&ps);
100 
101  return result;
102 }
103 
104 static clib_error_t *
106  char *file_name, void *link_address)
107 {
108  elf_main_t *em;
109  elf_section_t *s;
110  int fd;
111  struct stat fd_stat;
112  uword mmap_length = 0;
113  void *data = 0;
114  clib_error_t *error = 0;
115 
116  vec_add2 (cem->elf_mains, em, 1);
117 
118  fd = open (file_name, 0);
119  if (fd < 0)
120  {
121  error = clib_error_return_unix (0, "open `%s'", file_name);
122  goto done;
123  }
124 
125  if (fstat (fd, &fd_stat) < 0)
126  {
127  error = clib_error_return_unix (0, "fstat `%s'", file_name);
128  goto done;
129  }
130  mmap_length = fd_stat.st_size;
131 
132  data = mmap (0, mmap_length, PROT_READ, MAP_SHARED, fd, /* offset */ 0);
133  if (~pointer_to_uword (data) == 0)
134  {
135  error = clib_error_return_unix (0, "mmap `%s'", file_name);
136  goto done;
137  }
138 
139  error = elf_parse (em, data, mmap_length);
140  if (error)
141  goto done;
142 
143  /* Look for CLIB special sections. */
144  {
145  char *section_name_start = CLIB_ELF_SECTION_ADD_PREFIX ();
146  uword section_name_start_len = strlen (section_name_start);
147 
148  vec_foreach (s, em->sections)
149  {
150  u8 *name = elf_section_name (em, s);
151  uword *p;
152  clib_elf_section_t *vs;
154 
155  /* Section name must begin with CLIB_ELF_SECTION key. */
156  if (strcmp ((char *) name, section_name_start))
157  continue;
158 
159  name += section_name_start_len;
160  p = hash_get_mem (cem->section_by_name, name);
161  if (p)
162  vs = vec_elt_at_index (cem->sections, p[0]);
163  else
164  {
165  name = format (0, "%s%c", name, 0);
166  if (!cem->section_by_name)
167  cem->section_by_name = hash_create_string (0, sizeof (uword));
169  vec_add2 (cem->sections, vs, 1);
170  vs->name = name;
171  }
172 
173  vec_add2 (vs->bounds, b, 1);
174  b->lo = link_address + s->header.exec_address;
175  b->hi = b->lo + s->header.file_size;
176  }
177  }
178 
179  /* Parse symbols for this file. */
180  {
182  elf64_symbol_t *s;
183 
184  elf_parse_symbols (em);
185  vec_foreach (t, em->symbol_tables)
186  {
187  vec_foreach (s, t->symbols)
188  {
189  s->value += pointer_to_uword (link_address);
190  }
191  }
192  }
193 
194  /* No need to keep section contents around. */
195  {
196  elf_section_t *s;
197  vec_foreach (s, em->sections)
198  {
199  if (s->header.type != ELF_SECTION_STRING_TABLE)
200  vec_free (s->contents);
201  }
202  }
203 
204 done:
205  if (error)
206  elf_main_free (em);
207  if (fd >= 0)
208  close (fd);
209  if (data)
210  munmap (data, mmap_length);
211  return error;
212 }
213 
214 #define __USE_GNU
215 #include <link.h>
216 
217 static int
218 add_section (struct dl_phdr_info *info, size_t size, void *opaque)
219 {
220  clib_elf_main_t *cem = opaque;
222  char *name = (char *) info->dlpi_name;
223  void *addr = (void *) info->dlpi_addr;
224  uword is_main;
225 
226  is_main = strlen (name) == 0;
227  if (is_main)
228  {
229  static int done;
230 
231  /* Only do main program once. */
232  if (done++)
233  return 0;
234 
235  name = path_search (cem->exec_path);
236  if (!name)
237  {
238  clib_error ("failed to find %s on PATH", cem->exec_path);
239  return 0;
240  }
241  addr = 0;
242  }
243 
245  if (error)
246  {
247  /* Don't complain about 'linux-vdso.so.1' */
248  if (!is_main && name[0] != '/' && error->code == ENOENT)
250  else
252  }
253 
254  if (is_main && name != cem->exec_path)
255  vec_free (name);
256 
257  return 0;
258 }
259 
261 
262 __clib_export void
263 clib_elf_main_init (char *exec_path)
264 {
266 
267  cem->exec_path = exec_path;
268 
269  dl_iterate_phdr (add_section, cem);
270 }
271 
274 {
276  uword *p = hash_get (em->section_by_name, name);
277  return p ? vec_elt_at_index (em->sections, p[0])->bounds : 0;
278 }
279 
280 static uword
282  uword by_address, clib_elf_symbol_t * s)
283 {
285  elf_main_t *em;
286 
287  vec_foreach (em, cem->elf_mains)
288  {
290  s->elf_main_index = em - cem->elf_mains;
291  vec_foreach (t, em->symbol_tables)
292  {
293  s->symbol_table_index = t - em->symbol_tables;
294  if (by_name)
295  {
296  uword *p = hash_get (t->symbol_by_name, by_name);
297  if (p)
298  {
299  s->symbol = vec_elt (t->symbols, p[0]);
300  return 1;
301  }
302  }
303  else
304  {
305  elf64_symbol_t *x;
306  /* FIXME linear search. */
307  vec_foreach (x, t->symbols)
308  {
309  if (by_address >= x->value && by_address < x->value + x->size)
310  {
311  s->symbol = x[0];
312  return 1;
313  }
314  }
315  }
316  }
317  }
318 
319  return 0;
320 }
321 
322 uword
324 {
325  return symbol_by_address_or_name (by_name, /* by_address */ 0, s);
326 }
327 
328 uword
330 {
331  return symbol_by_address_or_name ( /* by_name */ 0, by_address, s);
332 }
333 
334 u8 *
335 format_clib_elf_symbol (u8 * s, va_list * args)
336 {
338  clib_elf_symbol_t *sym = va_arg (*args, clib_elf_symbol_t *);
339  elf_main_t *em;
341 
342  if (!sym)
343  /* Just print table headings. */
344  return format (s, "%U", format_elf_symbol, 0, 0, 0);
345 
346  else
347  {
348  em = vec_elt_at_index (cem->elf_mains, sym->elf_main_index);
350  return format (s, "%U", format_elf_symbol, em, t, &sym->symbol);
351  }
352 }
353 
354 __clib_export u8 *
356 {
357  uword address = va_arg (*args, uword);
359  clib_elf_symbol_t sym;
360  elf_main_t *em;
362 
364  {
365  em = vec_elt_at_index (cem->elf_mains, sym.elf_main_index);
367  s = format (s, "%s + 0x%wx",
368  elf_symbol_name (t, &sym.symbol),
369  address - sym.symbol.value);
370  }
371  else
372  s = format (s, "0x%wx", address);
373 
374  return s;
375 }
376 
377 /*
378  * fd.io coding-style-patch-verification: ON
379  *
380  * Local Variables:
381  * eval: (c-set-style "gnu")
382  * End:
383  */
vec_add
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:688
elf_parse
clib_error_t * elf_parse(elf_main_t *em, void *data, uword data_bytes)
Definition: elf.c:978
elf_symbol_table_t::symbol_by_name
uword * symbol_by_name
Definition: elf.h:823
elf64_symbol_t
Definition: elf.h:335
elf_parse_symbols
void elf_parse_symbols(elf_main_t *em)
Definition: elf.c:869
elf_section_t::contents
u8 * contents
Definition: elf.h:867
pointer_to_uword
static uword pointer_to_uword(const void *p)
Definition: types.h:131
path_search_free
static void path_search_free(path_search_t *p)
Definition: elf_clib.c:27
name
string name[64]
Definition: fib.api:25
elf_main_free
static void elf_main_free(elf_main_t *em)
Definition: elf.h:925
clib_elf_symbol_t::elf_main_index
u32 elf_main_index
Definition: elf_clib.h:124
format_elf_symbol
format_function_t format_elf_symbol
Definition: elf.h:1030
path
vl_api_fib_path_t path
Definition: mfib_types.api:44
clib_elf_main_t::elf_mains
elf_main_t * elf_mains
Definition: elf_clib.h:88
clib_elf_section_t::name
u8 * name
Definition: elf_clib.h:74
hash_create_string
#define hash_create_string(elts, value_bytes)
Definition: hash.h:689
elf_main_t::sections
elf_section_t * sections
Definition: elf.h:896
elf_symbol_table_t::symbols
elf64_symbol_t * symbols
Definition: elf.h:817
clib_error_report
#define clib_error_report(e)
Definition: error.h:113
addr
vhost_vring_addr_t addr
Definition: vhost_user.h:130
clib_elf_parse_file
static clib_error_t * clib_elf_parse_file(clib_elf_main_t *cem, char *file_name, void *link_address)
Definition: elf_clib.c:105
elf_main_t::symbol_tables
elf_symbol_table_t * symbol_tables
Definition: elf.h:901
error
Definition: cJSON.c:88
clib_elf_symbol_t
Definition: elf_clib.h:118
clib_elf_symbol_t::symbol_table_index
u32 symbol_table_index
Definition: elf_clib.h:127
vec_elt
#define vec_elt(v, i)
Get vector value at index i.
Definition: vec_bootstrap.h:210
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
CLIB_ELF_SECTION_ADD_PREFIX
#define CLIB_ELF_SECTION_ADD_PREFIX(n)
Definition: elf_clib.h:46
vec_add2
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:644
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
clib_elf_symbol_by_address
uword clib_elf_symbol_by_address(uword by_address, clib_elf_symbol_t *s)
Definition: elf_clib.c:329
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
split_string
static char ** split_string(char *string, u8 delimiter)
Definition: elf_clib.c:36
file_exists_and_is_executable
static int file_exists_and_is_executable(char *dir, char *file)
Definition: elf_clib.c:60
elf_symbol_table_t
Definition: elf.h:815
elf_section_name
static u8 * elf_section_name(elf_main_t *em, elf_section_t *s)
Definition: elf.h:993
uword
u64 uword
Definition: types.h:112
hash_get
#define hash_get(h, key)
Definition: hash.h:249
hash_set_mem
#define hash_set_mem(h, key, value)
Definition: hash.h:275
clib_elf_section_t
Definition: elf_clib.h:67
path_search
static char * path_search(char *file)
Definition: elf_clib.c:76
i
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
elf_clib.h
address
manual_print typedef address
Definition: ip_types.api:96
clib_elf_main
static clib_elf_main_t clib_elf_main
Definition: elf_clib.c:260
clib_elf_main_t::exec_path
char * exec_path
Definition: elf_clib.h:86
path_search_t::path
char ** path
Definition: elf_clib.c:23
data
u8 data[128]
Definition: ipsec_types.api:92
elf_section_t::header
elf64_section_header_t header
Definition: elf.h:854
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
size
u32 size
Definition: vhost_user.h:125
always_inline
#define always_inline
Definition: rdma_mlx5dv.h:23
clib_elf_symbol_t::symbol
elf64_symbol_t symbol
Definition: elf_clib.h:121
hash_get_mem
#define hash_get_mem(h, key)
Definition: hash.h:269
format
description fragment has unexpected format
Definition: map.api:433
format_clib_elf_symbol_with_address
__clib_export u8 * format_clib_elf_symbol_with_address(u8 *s, va_list *args)
Definition: elf_clib.c:355
clib_elf_main_t::section_by_name
uword * section_by_name
Definition: elf_clib.h:83
elf_section_t
Definition: elf.h:852
clib_elf_main_init
__clib_export void clib_elf_main_init(char *exec_path)
Definition: elf_clib.c:263
add_section
static int add_section(struct dl_phdr_info *info, size_t size, void *opaque)
Definition: elf_clib.c:218
clib_elf_main_t
Definition: elf_clib.h:77
vec_foreach
#define vec_foreach(var, vec)
Vector iterator.
Definition: vec_bootstrap.h:213
clib_error_return_unix
#define clib_error_return_unix(e, args...)
Definition: error.h:102
value
u8 value
Definition: qos.api:54
path_search_t
Definition: elf_clib.c:21
b
vlib_buffer_t ** b
Definition: nat44_ei_out2in.c:717
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
clib_error
#define clib_error(format, args...)
Definition: error.h:62
format_clib_elf_symbol
u8 * format_clib_elf_symbol(u8 *s, va_list *args)
Definition: elf_clib.c:335
elf_symbol_name
static u8 * elf_symbol_name(elf_symbol_table_t *t, elf64_symbol_t *sym)
Definition: elf.h:834
clib_error_free
#define clib_error_free(e)
Definition: error.h:86
clib_elf_main_t::sections
clib_elf_section_t * sections
Definition: elf_clib.h:80
symbol_by_address_or_name
static uword symbol_by_address_or_name(char *by_name, uword by_address, clib_elf_symbol_t *s)
Definition: elf_clib.c:281
clib_elf_symbol_by_name
uword clib_elf_symbol_by_name(char *by_name, clib_elf_symbol_t *s)
Definition: elf_clib.c:323
clib_elf_section_t::bounds
clib_elf_section_bounds_t * bounds
Definition: elf_clib.h:71
clib_elf_section_bounds_t
Definition: elf_clib.h:62
clib_elf_get_section_bounds
clib_elf_section_bounds_t * clib_elf_get_section_bounds(char *name)
Definition: elf_clib.c:273
string
const char *const string
Definition: cJSON.h:172
elf_main_t
Definition: elf.h:882