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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vppinfra/elf_clib.h>
26 path_search_free (path_search_t * p)
29 for (i = 0; i < vec_len (p->path); i++)
30 vec_free (p->path[i]);
35 split_string (char * string, u8 delimiter)
38 char * p, * start, * s;
44 while (*p != 0 && *p != delimiter)
47 vec_add (s, start, p - start);
59 file_exists_and_is_executable (char * dir, char * file)
61 char * path = (char *) format (0, "%s/%s%c", dir, file, 0);
65 yes = (stat (path, &s) >= 0
66 && S_ISREG (s.st_mode)
67 && 0 != (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)));
75 path_search (char * file)
81 /* Relative or absolute path. */
82 if (file[0] == '.' || file[0] == '/')
85 if (getenv("PATH") == 0)
88 ps.path = split_string (getenv ("PATH"), ':');
90 for (i = 0; i < vec_len (ps.path); i++)
91 if (file_exists_and_is_executable (ps.path[i], file))
95 if (i < vec_len (ps.path))
96 result = (char *) format (0, "%s/%s%c", ps.path[i], file);
98 path_search_free (&ps);
103 static clib_error_t *
104 clib_elf_parse_file (clib_elf_main_t * cem,
112 uword mmap_length = 0;
114 clib_error_t * error = 0;
116 vec_add2 (cem->elf_mains, em, 1);
118 fd = open (file_name, 0);
121 error = clib_error_return_unix (0, "open `%s'", file_name);
125 if (fstat (fd, &fd_stat) < 0)
127 error = clib_error_return_unix (0, "fstat `%s'", file_name);
130 mmap_length = fd_stat.st_size;
132 data = mmap (0, mmap_length, PROT_READ, MAP_SHARED, fd, /* offset */ 0);
133 if (~pointer_to_uword (data) == 0)
135 error = clib_error_return_unix (0, "mmap `%s'", file_name);
139 error = elf_parse (em, data, mmap_length);
143 /* Look for CLIB special sections. */
145 char * section_name_start = CLIB_ELF_SECTION_ADD_PREFIX ();
146 uword section_name_start_len = strlen (section_name_start);
148 vec_foreach (s, em->sections)
150 u8 * name = elf_section_name (em, s);
152 clib_elf_section_t * vs;
153 clib_elf_section_bounds_t * b;
155 /* Section name must begin with CLIB_ELF_SECTION key. */
156 if (memcmp (name, section_name_start, section_name_start_len))
159 name += section_name_start_len;
160 p = hash_get_mem (cem->section_by_name, name);
162 vs = vec_elt_at_index (cem->sections, p[0]);
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);
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;
179 /* Parse symbols for this file. */
181 elf_symbol_table_t * t;
184 elf_parse_symbols (em);
185 vec_foreach (t, em->symbol_tables)
187 vec_foreach (s, t->symbols)
189 s->value += pointer_to_uword (link_address);
194 /* No need to keep section contents around. */
197 vec_foreach (s, em->sections)
199 if (s->header.type != ELF_SECTION_STRING_TABLE)
200 vec_free (s->contents);
210 munmap (data, mmap_length);
218 add_section (struct dl_phdr_info * info, size_t size, void * opaque)
220 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;
226 is_main = strlen (name) == 0;
231 /* Only do main program once. */
235 name = path_search (cem->exec_path);
238 clib_error ("failed to find %s on PATH", cem->exec_path);
244 error = clib_elf_parse_file (cem, name, addr);
246 clib_error_report (error);
248 if (is_main && name != cem->exec_path)
254 static clib_elf_main_t clib_elf_main;
256 void clib_elf_main_init (char * exec_path)
258 clib_elf_main_t * cem = &clib_elf_main;
260 cem->exec_path = exec_path;
262 dl_iterate_phdr (add_section, cem);
265 clib_elf_section_bounds_t *
266 clib_elf_get_section_bounds (char * name)
268 clib_elf_main_t * em = &clib_elf_main;
269 uword * p = hash_get (em->section_by_name, name);
270 return p ? vec_elt_at_index (em->sections, p[0])->bounds : 0;
274 symbol_by_address_or_name (char * by_name,
276 clib_elf_symbol_t * s)
278 clib_elf_main_t * cem = &clib_elf_main;
281 vec_foreach (em, cem->elf_mains)
283 elf_symbol_table_t * t;
284 s->elf_main_index = em - cem->elf_mains;
285 vec_foreach (t, em->symbol_tables)
287 s->symbol_table_index = t - em->symbol_tables;
290 uword * p = hash_get (t->symbol_by_name, by_name);
293 s->symbol = vec_elt (t->symbols, p[0]);
300 /* FIXME linear search. */
301 vec_foreach (x, t->symbols)
303 if (by_address >= x->value && by_address < x->value + x->size)
316 uword clib_elf_symbol_by_name (char * by_name, clib_elf_symbol_t * s)
317 { return symbol_by_address_or_name (by_name, /* by_address */ 0, s); }
319 uword clib_elf_symbol_by_address (uword by_address, clib_elf_symbol_t * s)
320 { return symbol_by_address_or_name (/* by_name */ 0, by_address, s); }
322 u8 * format_clib_elf_symbol (u8 * s, va_list * args)
324 clib_elf_main_t * cem = &clib_elf_main;
325 clib_elf_symbol_t * sym = va_arg (*args, clib_elf_symbol_t *);
327 elf_symbol_table_t * t;
330 /* Just print table headings. */
331 return format (s, "%U", format_elf_symbol, 0, 0, 0);
335 em = vec_elt_at_index (cem->elf_mains, sym->elf_main_index);
336 t = vec_elt_at_index (em->symbol_tables, sym->symbol_table_index);
337 return format (s, "%U", format_elf_symbol, em, t, &sym->symbol);
341 u8 * format_clib_elf_symbol_with_address (u8 * s, va_list * args)
343 uword address = va_arg (*args, uword);
344 clib_elf_main_t * cem = &clib_elf_main;
345 clib_elf_symbol_t sym;
347 elf_symbol_table_t * t;
349 if (clib_elf_symbol_by_address (address, &sym))
351 em = vec_elt_at_index (cem->elf_mains, sym.elf_main_index);
352 t = vec_elt_at_index (em->symbol_tables, sym.symbol_table_index);
353 s = format (s, "%s + 0x%wx",
354 elf_symbol_name (t, &sym.symbol),
355 address - sym.symbol.value);
358 s = format (s, "0x%wx", address);