FD.io VPP  v16.06
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  char ** path;
24 
25 always_inline void
27 {
28  uword i;
29  for (i = 0; i < vec_len (p->path); i++)
30  vec_free (p->path[i]);
31  vec_free (p->path);
32 }
33 
34 static char **
35 split_string (char * string, u8 delimiter)
36 {
37  char ** result = 0;
38  char * p, * start, * s;
39 
40  p = string;
41  while (1)
42  {
43  start = p;
44  while (*p != 0 && *p != delimiter)
45  p++;
46  s = 0;
47  vec_add (s, start, p - start);
48  vec_add1 (s, 0);
49  vec_add1 (result, s);
50  if (*p == 0)
51  break;
52  p++;
53  }
54 
55  return result;
56 }
57 
58 static int
59 file_exists_and_is_executable (char * dir, char * file)
60 {
61  char * path = (char *) format (0, "%s/%s%c", dir, file, 0);
62  struct stat s;
63  uword yes;
64 
65  yes = (stat (path, &s) >= 0
66  && S_ISREG (s.st_mode)
67  && 0 != (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)));
68 
69  vec_free (path);
70 
71  return yes;
72 }
73 
74 static char *
75 path_search (char * file)
76 {
77  path_search_t ps;
78  uword i;
79  char * result;
80 
81  /* Relative or absolute path. */
82  if (file[0] == '.' || file[0] == '/')
83  return file;
84 
85  ps.path = split_string (getenv ("PATH"), ':');
86 
87  for (i = 0; i < vec_len (ps.path); i++)
88  if (file_exists_and_is_executable (ps.path[i], file))
89  break;
90 
91  result = 0;
92  if (i < vec_len (ps.path))
93  result = (char *) format (0, "%s/%s%c", ps.path[i], file);
94 
95  path_search_free (&ps);
96 
97  return result;
98 }
99 
100 static clib_error_t *
102  char * file_name,
103  void * link_address)
104 {
105  elf_main_t * em;
106  elf_section_t * s;
107  int fd;
108  struct stat fd_stat;
109  uword mmap_length = 0;
110  void * data = 0;
111  clib_error_t * error = 0;
112 
113  vec_add2 (cem->elf_mains, em, 1);
114 
115  fd = open (file_name, 0);
116  if (fd < 0)
117  {
118  error = clib_error_return_unix (0, "open `%s'", file_name);
119  goto done;
120  }
121 
122  if (fstat (fd, &fd_stat) < 0)
123  {
124  error = clib_error_return_unix (0, "fstat `%s'", file_name);
125  goto done;
126  }
127  mmap_length = fd_stat.st_size;
128 
129  data = mmap (0, mmap_length, PROT_READ, MAP_SHARED, fd, /* offset */ 0);
130  if (~pointer_to_uword (data) == 0)
131  {
132  error = clib_error_return_unix (0, "mmap `%s'", file_name);
133  goto done;
134  }
135 
136  error = elf_parse (em, data, mmap_length);
137  if (error)
138  goto done;
139 
140  /* Look for CLIB special sections. */
141  {
142  char * section_name_start = CLIB_ELF_SECTION_ADD_PREFIX ();
143  uword section_name_start_len = strlen (section_name_start);
144 
145  vec_foreach (s, em->sections)
146  {
147  u8 * name = elf_section_name (em, s);
148  uword * p;
149  clib_elf_section_t * vs;
151 
152  /* Section name must begin with CLIB_ELF_SECTION key. */
153  if (memcmp (name, section_name_start, section_name_start_len))
154  continue;
155 
156  name += section_name_start_len;
157  p = hash_get_mem (cem->section_by_name, name);
158  if (p)
159  vs = vec_elt_at_index (cem->sections, p[0]);
160  else
161  {
162  name = format (0, "%s%c", name, 0);
163  if (! cem->section_by_name)
164  cem->section_by_name = hash_create_string (0, sizeof (uword));
165  hash_set_mem (cem->section_by_name, name, vec_len (cem->sections));
166  vec_add2 (cem->sections, vs, 1);
167  vs->name = name;
168  }
169 
170  vec_add2 (vs->bounds, b, 1);
171  b->lo = link_address + s->header.exec_address;
172  b->hi = b->lo + s->header.file_size;
173  }
174  }
175 
176  /* Parse symbols for this file. */
177  {
178  elf_symbol_table_t * t;
179  elf64_symbol_t * s;
180 
181  elf_parse_symbols (em);
182  vec_foreach (t, em->symbol_tables)
183  {
184  vec_foreach (s, t->symbols)
185  {
186  s->value += pointer_to_uword (link_address);
187  }
188  }
189  }
190 
191  /* No need to keep section contents around. */
192  {
193  elf_section_t * s;
194  vec_foreach (s, em->sections)
195  {
196  if (s->header.type != ELF_SECTION_STRING_TABLE)
197  vec_free (s->contents);
198  }
199  }
200 
201  done:
202  if (error)
203  elf_main_free (em);
204  if (fd >= 0)
205  close (fd);
206  if (data)
207  munmap (data, mmap_length);
208  return error;
209 }
210 
211 #define __USE_GNU
212 #include <link.h>
213 
214 static int
215 add_section (struct dl_phdr_info * info, size_t size, void * opaque)
216 {
217  clib_elf_main_t * cem = opaque;
218  clib_error_t * error;
219  char * name = (char *) info->dlpi_name;
220  void * addr = (void *) info->dlpi_addr;
221  uword is_main;
222 
223  is_main = strlen (name) == 0;
224  if (is_main)
225  {
226  static int done;
227 
228  /* Only do main program once. */
229  if (done++)
230  return 0;
231 
232  name = path_search (cem->exec_path);
233  if (! name)
234  clib_error ("failed to find %s on PATH", cem->exec_path);
235  addr = 0;
236  }
237 
238  error = clib_elf_parse_file (cem, name, addr);
239  if (error)
240  clib_error_report (error);
241 
242  if (is_main && name != cem->exec_path)
243  vec_free (name);
244 
245  return 0;
246 }
247 
249 
250 void clib_elf_main_init (char * exec_path)
251 {
253 
254  cem->exec_path = exec_path;
255 
256  dl_iterate_phdr (add_section, cem);
257 }
258 
261 {
263  uword * p = hash_get (em->section_by_name, name);
264  return p ? vec_elt_at_index (em->sections, p[0])->bounds : 0;
265 }
266 
267 static uword
269  uword by_address,
270  clib_elf_symbol_t * s)
271 {
273  elf_main_t * em;
274 
275  vec_foreach (em, cem->elf_mains)
276  {
277  elf_symbol_table_t * t;
278  s->elf_main_index = em - cem->elf_mains;
279  vec_foreach (t, em->symbol_tables)
280  {
281  s->symbol_table_index = t - em->symbol_tables;
282  if (by_name)
283  {
284  uword * p = hash_get (t->symbol_by_name, by_name);
285  if (p)
286  {
287  s->symbol = vec_elt (t->symbols, p[0]);
288  return 1;
289  }
290  }
291  else
292  {
293  elf64_symbol_t * x;
294  /* FIXME linear search. */
295  vec_foreach (x, t->symbols)
296  {
297  if (by_address >= x->value && by_address < x->value + x->size)
298  {
299  s->symbol = x[0];
300  return 1;
301  }
302  }
303  }
304  }
305  }
306 
307  return 0;
308 }
309 
311 { return symbol_by_address_or_name (by_name, /* by_address */ 0, s); }
312 
314 { return symbol_by_address_or_name (/* by_name */ 0, by_address, s); }
315 
316 u8 * format_clib_elf_symbol (u8 * s, va_list * args)
317 {
319  clib_elf_symbol_t * sym = va_arg (*args, clib_elf_symbol_t *);
320  elf_main_t * em;
321  elf_symbol_table_t * t;
322 
323  if (! sym)
324  /* Just print table headings. */
325  return format (s, "%U", format_elf_symbol, 0, 0, 0);
326 
327  else
328  {
329  em = vec_elt_at_index (cem->elf_mains, sym->elf_main_index);
331  return format (s, "%U", format_elf_symbol, em, t, &sym->symbol);
332  }
333 }
334 
336 {
337  uword address = va_arg (*args, uword);
339  clib_elf_symbol_t sym;
340  elf_main_t * em;
341  elf_symbol_table_t * t;
342 
343  if (clib_elf_symbol_by_address (address, &sym))
344  {
345  em = vec_elt_at_index (cem->elf_mains, sym.elf_main_index);
347  s = format (s, "%s + 0x%wx",
348  elf_symbol_name (t, &sym.symbol),
349  address - sym.symbol.value);
350  }
351  else
352  s = format (s, "0x%wx", address);
353 
354  return s;
355 }
clib_elf_section_t * sections
Definition: elf_clib.h:77
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
char ** path
Definition: elf_clib.c:22
static int file_exists_and_is_executable(char *dir, char *file)
Definition: elf_clib.c:59
#define clib_error(format, args...)
Definition: error.h:62
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
#define CLIB_ELF_SECTION_ADD_PREFIX(n)
Definition: elf_clib.h:46
#define hash_set_mem(h, key, value)
Definition: hash.h:257
#define clib_error_report(e)
Definition: error.h:126
void elf_parse_symbols(elf_main_t *em)
Definition: elf.c:846
always_inline u8 * elf_section_name(elf_main_t *em, elf_section_t *s)
Definition: elf.h:974
uword clib_elf_symbol_by_address(uword by_address, clib_elf_symbol_t *s)
Definition: elf_clib.c:313
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:557
clib_elf_section_bounds_t * bounds
Definition: elf_clib.h:69
u8 * contents
Definition: elf.h:847
#define always_inline
Definition: clib.h:84
static clib_error_t * clib_elf_parse_file(clib_elf_main_t *cem, char *file_name, void *link_address)
Definition: elf_clib.c:101
elf64_symbol_t symbol
Definition: elf_clib.h:117
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
char * exec_path
Definition: elf_clib.h:83
static char ** split_string(char *string, u8 delimiter)
Definition: elf_clib.c:35
elf_symbol_table_t * symbol_tables
Definition: elf.h:879
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define hash_create_string(elts, value_bytes)
Definition: hash.h:609
#define hash_get(h, key)
Definition: hash.h:231
#define clib_error_return_unix(e, args...)
Definition: error.h:115
uword * section_by_name
Definition: elf_clib.h:80
always_inline void path_search_free(path_search_t *p)
Definition: elf_clib.c:26
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
always_inline void elf_main_free(elf_main_t *em)
Definition: elf.h:903
void clib_elf_main_init(char *exec_path)
Definition: elf_clib.c:250
elf64_symbol_t * symbols
Definition: elf.h:801
always_inline u8 * elf_symbol_name(elf_symbol_table_t *t, elf64_symbol_t *sym)
Definition: elf.h:818
elf_main_t * elf_mains
Definition: elf_clib.h:85
uword clib_elf_symbol_by_name(char *by_name, clib_elf_symbol_t *s)
Definition: elf_clib.c:310
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
u32 size
Definition: vhost-user.h:74
elf_section_t * sections
Definition: elf.h:874
static char * path_search(char *file)
Definition: elf_clib.c:75
clib_elf_section_bounds_t * clib_elf_get_section_bounds(char *name)
Definition: elf_clib.c:260
static uword symbol_by_address_or_name(char *by_name, uword by_address, clib_elf_symbol_t *s)
Definition: elf_clib.c:268
u64 uword
Definition: types.h:112
#define vec_elt(v, i)
Get vector value at index i.
u8 * format_clib_elf_symbol(u8 *s, va_list *args)
Definition: elf_clib.c:316
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
clib_error_t * elf_parse(elf_main_t *em, void *data, uword data_bytes)
Definition: elf.c:951
unsigned char u8
Definition: types.h:56
uword * symbol_by_name
Definition: elf.h:807
format_function_t format_elf_symbol
Definition: elf.h:1001
#define hash_get_mem(h, key)
Definition: hash.h:251
u8 * format_clib_elf_symbol_with_address(u8 *s, va_list *args)
Definition: elf_clib.c:335
elf64_section_header_t header
Definition: elf.h:834
#define vec_foreach(var, vec)
Vector iterator.
vhost_vring_addr_t addr
Definition: vhost-user.h:78
static int add_section(struct dl_phdr_info *info, size_t size, void *opaque)
Definition: elf_clib.c:215
u32 symbol_table_index
Definition: elf_clib.h:123
static clib_elf_main_t clib_elf_main
Definition: elf_clib.c:248