Line data Source code
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;
24 : } path_search_t;
25 :
26 : always_inline void
27 0 : path_search_free (path_search_t * p)
28 : {
29 : uword i;
30 0 : for (i = 0; i < vec_len (p->path); i++)
31 0 : vec_free (p->path[i]);
32 0 : vec_free (p->path);
33 0 : }
34 :
35 : static char **
36 0 : split_string (char *string, u8 delimiter)
37 : {
38 0 : char **result = 0;
39 : char *p, *start, *s;
40 :
41 0 : p = string;
42 : while (1)
43 : {
44 0 : start = p;
45 0 : while (*p != 0 && *p != delimiter)
46 0 : p++;
47 0 : s = 0;
48 0 : vec_add (s, start, p - start);
49 0 : vec_add1 (s, 0);
50 0 : vec_add1 (result, s);
51 0 : if (*p == 0)
52 0 : break;
53 0 : p++;
54 : }
55 :
56 0 : return result;
57 : }
58 :
59 : static int
60 0 : file_exists_and_is_executable (char *dir, char *file)
61 : {
62 0 : char *path = (char *) format (0, "%s/%s%c", dir, file, 0);
63 : struct stat s;
64 : uword yes;
65 :
66 0 : yes = (stat (path, &s) >= 0
67 0 : && S_ISREG (s.st_mode)
68 0 : && 0 != (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)));
69 :
70 0 : vec_free (path);
71 :
72 0 : return yes;
73 : }
74 :
75 : static char *
76 575 : path_search (char *file)
77 : {
78 : path_search_t ps;
79 : uword i;
80 : char *result;
81 :
82 : /* Relative or absolute path. */
83 575 : if (file[0] == '.' || file[0] == '/')
84 575 : return file;
85 :
86 0 : if (getenv ("PATH") == 0)
87 0 : return file;
88 :
89 0 : ps.path = split_string (getenv ("PATH"), ':');
90 :
91 0 : for (i = 0; i < vec_len (ps.path); i++)
92 0 : if (file_exists_and_is_executable (ps.path[i], file))
93 0 : break;
94 :
95 0 : result = 0;
96 0 : if (i < vec_len (ps.path))
97 0 : result = (char *) format (0, "%s/%s%c", ps.path[i], file, 0);
98 :
99 0 : path_search_free (&ps);
100 :
101 0 : return result;
102 : }
103 :
104 : static clib_error_t *
105 58111 : clib_elf_parse_file (clib_elf_main_t * cem,
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 58111 : uword mmap_length = 0;
113 58111 : void *data = 0;
114 58111 : clib_error_t *error = 0;
115 :
116 58111 : vec_add2 (cem->elf_mains, em, 1);
117 :
118 58111 : fd = open (file_name, 0);
119 58111 : if (fd < 0)
120 : {
121 575 : error = clib_error_return_unix (0, "open `%s'", file_name);
122 575 : goto done;
123 : }
124 :
125 57536 : if (fstat (fd, &fd_stat) < 0)
126 : {
127 0 : error = clib_error_return_unix (0, "fstat `%s'", file_name);
128 0 : goto done;
129 : }
130 57536 : mmap_length = fd_stat.st_size;
131 :
132 57536 : data = mmap (0, mmap_length, PROT_READ, MAP_SHARED, fd, /* offset */ 0);
133 57536 : if (~pointer_to_uword (data) == 0)
134 : {
135 0 : error = clib_error_return_unix (0, "mmap `%s'", file_name);
136 0 : goto done;
137 : }
138 :
139 57536 : error = elf_parse (em, data, mmap_length);
140 57536 : if (error)
141 0 : goto done;
142 :
143 : /* Look for CLIB special sections. */
144 : {
145 57536 : char *section_name_start = CLIB_ELF_SECTION_ADD_PREFIX ();
146 57536 : uword section_name_start_len = strlen (section_name_start);
147 :
148 2184660 : vec_foreach (s, em->sections)
149 : {
150 2127120 : u8 *name = elf_section_name (em, s);
151 : uword *p;
152 : clib_elf_section_t *vs;
153 : clib_elf_section_bounds_t *b;
154 :
155 : /* Section name must begin with CLIB_ELF_SECTION key. */
156 2127120 : if (strcmp ((char *) name, section_name_start))
157 2127120 : continue;
158 :
159 0 : name += section_name_start_len;
160 0 : p = hash_get_mem (cem->section_by_name, name);
161 0 : if (p)
162 0 : vs = vec_elt_at_index (cem->sections, p[0]);
163 : else
164 : {
165 0 : name = format (0, "%s%c", name, 0);
166 0 : if (!cem->section_by_name)
167 0 : cem->section_by_name = hash_create_string (0, sizeof (uword));
168 0 : hash_set_mem (cem->section_by_name, name, vec_len (cem->sections));
169 0 : vec_add2 (cem->sections, vs, 1);
170 0 : vs->name = name;
171 : }
172 :
173 0 : vec_add2 (vs->bounds, b, 1);
174 0 : b->lo = link_address + s->header.exec_address;
175 0 : b->hi = b->lo + s->header.file_size;
176 : }
177 : }
178 :
179 : /* Parse symbols for this file. */
180 : {
181 : elf_symbol_table_t *t;
182 : elf64_symbol_t *s;
183 :
184 57536 : elf_parse_symbols (em);
185 166854 : vec_foreach (t, em->symbol_tables)
186 : {
187 293197000 : vec_foreach (s, t->symbols)
188 : {
189 293088000 : 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 2184660 : vec_foreach (s, em->sections)
198 : {
199 2127120 : if (s->header.type != ELF_SECTION_STRING_TABLE)
200 1960270 : vec_free (s->contents);
201 : }
202 : }
203 :
204 57536 : done:
205 58111 : if (error)
206 575 : elf_main_free (em);
207 58111 : if (fd >= 0)
208 57536 : close (fd);
209 58111 : if (data)
210 57536 : munmap (data, mmap_length);
211 58111 : return error;
212 : }
213 :
214 : #define __USE_GNU
215 : #include <link.h>
216 :
217 : static int
218 58111 : add_section (struct dl_phdr_info *info, size_t size, void *opaque)
219 : {
220 58111 : clib_elf_main_t *cem = opaque;
221 : clib_error_t *error;
222 58111 : char *name = (char *) info->dlpi_name;
223 58111 : void *addr = (void *) info->dlpi_addr;
224 : uword is_main;
225 :
226 58111 : is_main = strlen (name) == 0;
227 58111 : if (is_main)
228 : {
229 : static int done;
230 :
231 : /* Only do main program once. */
232 575 : if (done++)
233 0 : return 0;
234 :
235 575 : name = path_search (cem->exec_path);
236 575 : if (!name)
237 : {
238 0 : clib_error ("failed to find %s on PATH", cem->exec_path);
239 0 : return 0;
240 : }
241 575 : addr = 0;
242 : }
243 :
244 58111 : error = clib_elf_parse_file (cem, name, addr);
245 58111 : if (error)
246 : {
247 : /* Don't complain about 'linux-vdso.so.1' */
248 575 : if (!is_main && name[0] != '/' && error->code == ENOENT)
249 575 : clib_error_free (error);
250 : else
251 0 : clib_error_report (error);
252 : }
253 :
254 58111 : if (is_main && name != cem->exec_path)
255 0 : vec_free (name);
256 :
257 58111 : return 0;
258 : }
259 :
260 : static clib_elf_main_t clib_elf_main;
261 :
262 : __clib_export void
263 575 : clib_elf_main_init (char *exec_path)
264 : {
265 575 : clib_elf_main_t *cem = &clib_elf_main;
266 :
267 575 : cem->exec_path = exec_path;
268 :
269 575 : dl_iterate_phdr (add_section, cem);
270 575 : }
271 :
272 : clib_elf_section_bounds_t *
273 0 : clib_elf_get_section_bounds (char *name)
274 : {
275 0 : clib_elf_main_t *em = &clib_elf_main;
276 0 : uword *p = hash_get (em->section_by_name, name);
277 0 : return p ? vec_elt_at_index (em->sections, p[0])->bounds : 0;
278 : }
279 :
280 : static uword
281 12 : symbol_by_address_or_name (char *by_name,
282 : uword by_address, clib_elf_symbol_t * s)
283 : {
284 12 : clib_elf_main_t *cem = &clib_elf_main;
285 : elf_main_t *em;
286 :
287 66 : vec_foreach (em, cem->elf_mains)
288 : {
289 : elf_symbol_table_t *t;
290 66 : s->elf_main_index = em - cem->elf_mains;
291 149 : vec_foreach (t, em->symbol_tables)
292 : {
293 95 : s->symbol_table_index = t - em->symbol_tables;
294 95 : if (by_name)
295 : {
296 0 : uword *p = hash_get (t->symbol_by_name, by_name);
297 0 : if (p)
298 : {
299 0 : s->symbol = vec_elt (t->symbols, p[0]);
300 0 : return 1;
301 : }
302 : }
303 : else
304 : {
305 : elf64_symbol_t *x;
306 : /* FIXME linear search. */
307 1325090 : vec_foreach (x, t->symbols)
308 : {
309 1325000 : if (by_address >= x->value && by_address < x->value + x->size)
310 : {
311 12 : s->symbol = x[0];
312 12 : return 1;
313 : }
314 : }
315 : }
316 : }
317 : }
318 :
319 0 : return 0;
320 : }
321 :
322 : __clib_export uword
323 0 : clib_elf_symbol_by_name (char *by_name, clib_elf_symbol_t *s)
324 : {
325 0 : return symbol_by_address_or_name (by_name, /* by_address */ 0, s);
326 : }
327 :
328 : __clib_export uword
329 12 : clib_elf_symbol_by_address (uword by_address, clib_elf_symbol_t *s)
330 : {
331 12 : return symbol_by_address_or_name ( /* by_name */ 0, by_address, s);
332 : }
333 :
334 : __clib_export const char *
335 0 : clib_elf_symbol_name (clib_elf_symbol_t *s)
336 : {
337 0 : clib_elf_main_t *cem = &clib_elf_main;
338 : elf_main_t *em;
339 : elf_symbol_table_t *t;
340 :
341 0 : em = vec_elt_at_index (cem->elf_mains, s->elf_main_index);
342 0 : t = vec_elt_at_index (em->symbol_tables, s->symbol_table_index);
343 :
344 0 : return (const char *) elf_symbol_name (t, &s->symbol);
345 : }
346 :
347 : __clib_export u8 *
348 0 : format_clib_elf_symbol (u8 *s, va_list *args)
349 : {
350 0 : clib_elf_main_t *cem = &clib_elf_main;
351 0 : clib_elf_symbol_t *sym = va_arg (*args, clib_elf_symbol_t *);
352 : elf_main_t *em;
353 : elf_symbol_table_t *t;
354 :
355 0 : if (!sym)
356 : /* Just print table headings. */
357 0 : return format (s, "%U", format_elf_symbol, 0, 0, 0);
358 :
359 : else
360 : {
361 0 : em = vec_elt_at_index (cem->elf_mains, sym->elf_main_index);
362 0 : t = vec_elt_at_index (em->symbol_tables, sym->symbol_table_index);
363 0 : return format (s, "%U", format_elf_symbol, em, t, &sym->symbol);
364 : }
365 : }
366 :
367 : __clib_export u8 *
368 12 : format_clib_elf_symbol_with_address (u8 * s, va_list * args)
369 : {
370 12 : uword address = va_arg (*args, uword);
371 12 : clib_elf_main_t *cem = &clib_elf_main;
372 : clib_elf_symbol_t sym;
373 : elf_main_t *em;
374 : elf_symbol_table_t *t;
375 :
376 12 : if (clib_elf_symbol_by_address (address, &sym))
377 : {
378 12 : em = vec_elt_at_index (cem->elf_mains, sym.elf_main_index);
379 12 : t = vec_elt_at_index (em->symbol_tables, sym.symbol_table_index);
380 12 : s = format (s, "%s + 0x%wx",
381 : elf_symbol_name (t, &sym.symbol),
382 12 : address - sym.symbol.value);
383 : }
384 : else
385 0 : s = format (s, "0x%wx", address);
386 :
387 12 : return s;
388 : }
389 :
390 : /*
391 : * fd.io coding-style-patch-verification: ON
392 : *
393 : * Local Variables:
394 : * eval: (c-set-style "gnu")
395 : * End:
396 : */
|