blob: d2865f800e32e015f841aac57e2747e5b8e9fdba [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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
Dave Barachc3799992016-08-15 11:12:27 -040021typedef struct
22{
23 char **path;
Ed Warnickecb9cada2015-12-08 15:45:58 -070024} path_search_t;
25
26always_inline void
27path_search_free (path_search_t * p)
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
35static char **
Dave Barachc3799992016-08-15 11:12:27 -040036split_string (char *string, u8 delimiter)
Ed Warnickecb9cada2015-12-08 15:45:58 -070037{
Dave Barachc3799992016-08-15 11:12:27 -040038 char **result = 0;
39 char *p, *start, *s;
40
Ed Warnickecb9cada2015-12-08 15:45:58 -070041 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
59static int
Dave Barachc3799992016-08-15 11:12:27 -040060file_exists_and_is_executable (char *dir, char *file)
Ed Warnickecb9cada2015-12-08 15:45:58 -070061{
Dave Barachc3799992016-08-15 11:12:27 -040062 char *path = (char *) format (0, "%s/%s%c", dir, file, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070063 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
75static char *
Dave Barachc3799992016-08-15 11:12:27 -040076path_search (char *file)
Ed Warnickecb9cada2015-12-08 15:45:58 -070077{
78 path_search_t ps;
79 uword i;
Dave Barachc3799992016-08-15 11:12:27 -040080 char *result;
Ed Warnickecb9cada2015-12-08 15:45:58 -070081
82 /* Relative or absolute path. */
83 if (file[0] == '.' || file[0] == '/')
84 return file;
85
Dave Barachc3799992016-08-15 11:12:27 -040086 if (getenv ("PATH") == 0)
Dave Barachf9c231e2016-08-05 10:10:18 -040087 return file;
88
Ed Warnickecb9cada2015-12-08 15:45:58 -070089 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))
Ryo Nishikawa4ec02992021-04-22 23:31:09 +090097 result = (char *) format (0, "%s/%s%c", ps.path[i], file, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 path_search_free (&ps);
100
101 return result;
102}
103
104static clib_error_t *
105clib_elf_parse_file (clib_elf_main_t * cem,
Dave Barachc3799992016-08-15 11:12:27 -0400106 char *file_name, void *link_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107{
Dave Barachc3799992016-08-15 11:12:27 -0400108 elf_main_t *em;
109 elf_section_t *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110 int fd;
111 struct stat fd_stat;
112 uword mmap_length = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400113 void *data = 0;
114 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115
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 {
Dave Barachc3799992016-08-15 11:12:27 -0400145 char *section_name_start = CLIB_ELF_SECTION_ADD_PREFIX ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146 uword section_name_start_len = strlen (section_name_start);
147
148 vec_foreach (s, em->sections)
Dave Barachc3799992016-08-15 11:12:27 -0400149 {
150 u8 *name = elf_section_name (em, s);
151 uword *p;
152 clib_elf_section_t *vs;
153 clib_elf_section_bounds_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154
Dave Barachc3799992016-08-15 11:12:27 -0400155 /* Section name must begin with CLIB_ELF_SECTION key. */
Benoît Gannec6eb5bc2019-04-26 11:09:49 +0200156 if (strcmp ((char *) name, section_name_start))
Dave Barachc3799992016-08-15 11:12:27 -0400157 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158
Dave Barachc3799992016-08-15 11:12:27 -0400159 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));
168 hash_set_mem (cem->section_by_name, name, vec_len (cem->sections));
169 vec_add2 (cem->sections, vs, 1);
170 vs->name = name;
171 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700172
Dave Barachc3799992016-08-15 11:12:27 -0400173 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177 }
178
179 /* Parse symbols for this file. */
180 {
Dave Barachc3799992016-08-15 11:12:27 -0400181 elf_symbol_table_t *t;
182 elf64_symbol_t *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183
184 elf_parse_symbols (em);
185 vec_foreach (t, em->symbol_tables)
Dave Barachc3799992016-08-15 11:12:27 -0400186 {
187 vec_foreach (s, t->symbols)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188 {
Dave Barachc3799992016-08-15 11:12:27 -0400189 s->value += pointer_to_uword (link_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190 }
Dave Barachc3799992016-08-15 11:12:27 -0400191 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192 }
193
194 /* No need to keep section contents around. */
195 {
Dave Barachc3799992016-08-15 11:12:27 -0400196 elf_section_t *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 vec_foreach (s, em->sections)
Dave Barachc3799992016-08-15 11:12:27 -0400198 {
199 if (s->header.type != ELF_SECTION_STRING_TABLE)
200 vec_free (s->contents);
201 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 }
203
Dave Barachc3799992016-08-15 11:12:27 -0400204done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 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
217static int
Dave Barachc3799992016-08-15 11:12:27 -0400218add_section (struct dl_phdr_info *info, size_t size, void *opaque)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219{
Dave Barachc3799992016-08-15 11:12:27 -0400220 clib_elf_main_t *cem = opaque;
221 clib_error_t *error;
222 char *name = (char *) info->dlpi_name;
223 void *addr = (void *) info->dlpi_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 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);
Dave Barachc3799992016-08-15 11:12:27 -0400236 if (!name)
237 {
238 clib_error ("failed to find %s on PATH", cem->exec_path);
239 return 0;
240 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 addr = 0;
242 }
243
244 error = clib_elf_parse_file (cem, name, addr);
245 if (error)
Dave Barach18f0d3e2020-09-25 10:18:04 -0400246 {
247 /* Don't complain about 'linux-vdso.so.1' */
248 if (!is_main && name[0] != '/' && error->code == ENOENT)
249 clib_error_free (error);
250 else
251 clib_error_report (error);
252 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253
254 if (is_main && name != cem->exec_path)
255 vec_free (name);
256
257 return 0;
258}
259
260static clib_elf_main_t clib_elf_main;
261
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200262__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -0400263clib_elf_main_init (char *exec_path)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264{
Dave Barachc3799992016-08-15 11:12:27 -0400265 clib_elf_main_t *cem = &clib_elf_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266
267 cem->exec_path = exec_path;
268
269 dl_iterate_phdr (add_section, cem);
270}
271
272clib_elf_section_bounds_t *
Dave Barachc3799992016-08-15 11:12:27 -0400273clib_elf_get_section_bounds (char *name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274{
Dave Barachc3799992016-08-15 11:12:27 -0400275 clib_elf_main_t *em = &clib_elf_main;
276 uword *p = hash_get (em->section_by_name, name);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277 return p ? vec_elt_at_index (em->sections, p[0])->bounds : 0;
278}
279
280static uword
Dave Barachc3799992016-08-15 11:12:27 -0400281symbol_by_address_or_name (char *by_name,
282 uword by_address, clib_elf_symbol_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283{
Dave Barachc3799992016-08-15 11:12:27 -0400284 clib_elf_main_t *cem = &clib_elf_main;
285 elf_main_t *em;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
287 vec_foreach (em, cem->elf_mains)
Dave Barachc3799992016-08-15 11:12:27 -0400288 {
289 elf_symbol_table_t *t;
290 s->elf_main_index = em - cem->elf_mains;
291 vec_foreach (t, em->symbol_tables)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 {
Dave Barachc3799992016-08-15 11:12:27 -0400293 s->symbol_table_index = t - em->symbol_tables;
294 if (by_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 {
Dave Barachc3799992016-08-15 11:12:27 -0400296 uword *p = hash_get (t->symbol_by_name, by_name);
297 if (p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298 {
Dave Barachc3799992016-08-15 11:12:27 -0400299 s->symbol = vec_elt (t->symbols, p[0]);
300 return 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301 }
302 }
Dave Barachc3799992016-08-15 11:12:27 -0400303 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316 }
Dave Barachc3799992016-08-15 11:12:27 -0400317 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318
319 return 0;
320}
321
Dave Barachc3799992016-08-15 11:12:27 -0400322uword
323clib_elf_symbol_by_name (char *by_name, clib_elf_symbol_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324{
Dave Barachc3799992016-08-15 11:12:27 -0400325 return symbol_by_address_or_name (by_name, /* by_address */ 0, s);
326}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327
Dave Barachc3799992016-08-15 11:12:27 -0400328uword
329clib_elf_symbol_by_address (uword by_address, clib_elf_symbol_t * s)
330{
331 return symbol_by_address_or_name ( /* by_name */ 0, by_address, s);
332}
333
334u8 *
335format_clib_elf_symbol (u8 * s, va_list * args)
336{
337 clib_elf_main_t *cem = &clib_elf_main;
338 clib_elf_symbol_t *sym = va_arg (*args, clib_elf_symbol_t *);
339 elf_main_t *em;
340 elf_symbol_table_t *t;
341
342 if (!sym)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343 /* 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);
349 t = vec_elt_at_index (em->symbol_tables, sym->symbol_table_index);
350 return format (s, "%U", format_elf_symbol, em, t, &sym->symbol);
351 }
352}
353
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200354__clib_export u8 *
Dave Barachc3799992016-08-15 11:12:27 -0400355format_clib_elf_symbol_with_address (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356{
357 uword address = va_arg (*args, uword);
Dave Barachc3799992016-08-15 11:12:27 -0400358 clib_elf_main_t *cem = &clib_elf_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 clib_elf_symbol_t sym;
Dave Barachc3799992016-08-15 11:12:27 -0400360 elf_main_t *em;
361 elf_symbol_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362
363 if (clib_elf_symbol_by_address (address, &sym))
364 {
365 em = vec_elt_at_index (cem->elf_mains, sym.elf_main_index);
366 t = vec_elt_at_index (em->symbol_tables, sym.symbol_table_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}
Dave Barachc3799992016-08-15 11:12:27 -0400376
377/*
378 * fd.io coding-style-patch-verification: ON
379 *
380 * Local Variables:
381 * eval: (c-set-style "gnu")
382 * End:
383 */