1 #include <stdio.h>
2 #include <common.h>
3 #include <debug.h>
4 #include <libelf.h>
5 #include <libebl.h>
6 #include <elf.h>
7 #include <gelf.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <hash.h>
16 #include <lsd.h>
17
18 extern int verbose_flag;
19
20 typedef struct source_t source_t;
21
22 typedef struct {
23 Elf_Scn *scn;
24 GElf_Shdr shdr;
25 Elf_Data *data;
26 } section_info_t;
27
28 typedef struct next_export_t {
29 source_t *source;
30 int next_idx;
31 } next_export_t;
32
33 struct source_t {
34 source_t *next;
35 int visited;
36
37 char *name; /* full path name of this executable file */
38 /* ELF-related information: */
39 Elf *elf;
40 int elf_fd;
41 GElf_Ehdr elf_hdr;
42 size_t shstrndx;
43 int shnum; /* number of sections */
44
45 section_info_t symtab;
46 section_info_t strtab;
47 section_info_t dynamic;
48 section_info_t hash;
49
50 section_info_t *relocations;
51 int num_relocations; /* number of relocs (<= relocations_size) */
52 int relocations_size; /* sice of array -- NOT number of relocs! */
53
54 /* satisfied_execs: array containing pointers to the libraries or
55 executables that this executable satisfies symbol references for. */
56 source_t **satisfied_execs;
57 int num_satisfied_execs;
58 int satisfied_execs_size;
59
60 /* satisfied: array is parallel to symbol table; for each undefined symbol
61 in that array, we maintain a flag stating whether that symbol has been
62 satisfied, and if so, by which library. This applies both to executable
63 files and libraries.
64 */
65 source_t **satisfied;
66
67 /* exports: array is parallel to symbol table; for each global symbol
68 in that array, we maintain a flag stating whether that symbol satisfies
69 a dependency in some other file. num_syms is the length of the exports
70 array, as well as the satisfied array. This applied to libraries only.
71
72 next_exports: this is a bit tricky. We use this field to maintain a
73 linked list of source_t for each global symbol of a shared library.
74 For a shared library's global symbol at index N has the property that
75 exports[N] is the head of a linked list (threaded through next_export)
76 of all source_t that this symbol resolves a reference to. For example,
77 if symbol printf has index 1000 in libc.so, and an executable A and
78 library L use printf, then the source_t entry corresponding to libc.so
79 will have exports[1000] be a linked list that contains the nodes for
80 application A and library L.
81 */
82
83 next_export_t *exports;
84 /* num_exported is the number of symbols in this file actually used by
85 somebody else; it's not the size of the exports array. */
86 int num_exported;
87 next_export_t *next_export;
88 int num_next_export;
89 int next_export_size;
90
91 int num_syms; /* number of symbols in symbol table. This is the length of
92 both exports[] and satisfied[] arrays. */
93
94 /* This is an array that contains one element for each library dependency
95 listed in the executable or shared library. */
96 source_t **lib_deps; /* list of library dependencies */
97 int num_lib_deps; /* actual number of library dependencies */
98 int lib_deps_size; /* size of lib_deps array--NOT actual number of deps! */
99
100 };
101
102 static source_t *sources = NULL;
103
104 static char * find_file(const char *libname,
105 char **lib_lookup_dirs,
106 int num_lib_lookup_dirs);
107
find_source(const char * name,char ** lib_lookup_dirs,int num_lib_lookup_dirs)108 static inline source_t* find_source(const char *name,
109 char **lib_lookup_dirs,
110 int num_lib_lookup_dirs) {
111 source_t *trav = sources;
112 char *full = find_file(name, lib_lookup_dirs, num_lib_lookup_dirs);
113 FAILIF(full == NULL, "Cannot construct full path for file [%s]!\n", name);
114 while (trav) {
115 if (!strcmp(trav->name, full))
116 break;
117 trav = trav->next;
118 }
119 free(full);
120 return trav;
121 }
122
add_to_sources(source_t * src)123 static inline void add_to_sources(source_t *src) {
124 src->next = sources;
125 sources = src;
126 }
127
init_source(char * full_path)128 static source_t* init_source(char *full_path) {
129 source_t *source = (source_t *)CALLOC(1, sizeof(source_t));
130
131 ASSERT(full_path);
132 source->name = full_path;
133 source->elf_fd = -1;
134
135 INFO("Opening %s...\n", full_path);
136 source->elf_fd = open(full_path, O_RDONLY);
137 FAILIF(source->elf_fd < 0, "open(%s): %s (%d)\n",
138 full_path,
139 strerror(errno),
140 errno);
141 INFO("Calling elf_begin(%s)...\n", full_path);
142 source->elf = elf_begin(source->elf_fd, ELF_C_READ, NULL);
143 FAILIF_LIBELF(source->elf == NULL, elf_begin);
144
145 /* libelf can recognize COFF and A.OUT formats, but we handle only ELF. */
146 if (elf_kind(source->elf) != ELF_K_ELF) {
147 ERROR("Input file %s is not in ELF format!\n", full_path);
148 return NULL;
149 }
150
151 /* Make sure this is a shared library or an executable. */
152 {
153 INFO("Making sure %s is a shared library or an executable...\n",
154 full_path);
155 FAILIF_LIBELF(0 == gelf_getehdr(source->elf, &source->elf_hdr), gelf_getehdr);
156 FAILIF(source->elf_hdr.e_type != ET_DYN &&
157 source->elf_hdr.e_type != ET_EXEC,
158 "%s must be a shared library (elf type is %d, expecting %d).\n",
159 full_path,
160 source->elf_hdr.e_type,
161 ET_DYN);
162 }
163
164 /* Get the index of the section-header-strings-table section. */
165 FAILIF_LIBELF(elf_getshstrndx (source->elf, &source->shstrndx) < 0,
166 elf_getshstrndx);
167
168 FAILIF_LIBELF(elf_getshnum (source->elf, &source->shnum) < 0, elf_getshnum);
169
170 /* Find various sections. */
171 size_t scnidx;
172 Elf_Scn *scn;
173 GElf_Shdr *shdr, shdr_mem;
174 INFO("Locating %d sections in %s...\n", source->shnum, full_path);
175 for (scnidx = 1; scnidx < source->shnum; scnidx++) {
176 scn = elf_getscn(source->elf, scnidx);
177 FAILIF_LIBELF(NULL == scn, elf_getscn);
178 shdr = gelf_getshdr(scn, &shdr_mem);
179 FAILIF_LIBELF(NULL == shdr, gelf_getshdr);
180 INFO("\tfound section [%s]...\n", elf_strptr(source->elf, source->shstrndx, shdr->sh_name));
181 if (shdr->sh_type == SHT_DYNSYM) {
182 source->symtab.scn = scn;
183 source->symtab.data = elf_getdata(scn, NULL);
184 FAILIF_LIBELF(NULL == source->symtab.data, elf_getdata);
185 memcpy(&source->symtab.shdr, shdr, sizeof(GElf_Shdr));
186
187 /* The sh_link field of the section header of the symbol table
188 contains the index of the associated strings table. */
189 source->strtab.scn = elf_getscn(source->elf,
190 source->symtab.shdr.sh_link);
191 FAILIF_LIBELF(NULL == source->strtab.scn, elf_getscn);
192 FAILIF_LIBELF(NULL == gelf_getshdr(scn, &source->strtab.shdr),
193 gelf_getshdr);
194 source->strtab.data = elf_getdata(source->strtab.scn, NULL);
195 FAILIF_LIBELF(NULL == source->strtab.data, elf_getdata);
196 }
197 else if (shdr->sh_type == SHT_DYNAMIC) {
198 source->dynamic.scn = scn;
199 source->dynamic.data = elf_getdata(scn, NULL);
200 FAILIF_LIBELF(NULL == source->symtab.data, elf_getdata);
201 memcpy(&source->dynamic.shdr, shdr, sizeof(GElf_Shdr));
202 }
203 else if (shdr->sh_type == SHT_HASH) {
204 source->hash.scn = scn;
205 source->hash.data = elf_getdata(scn, NULL);
206 FAILIF_LIBELF(NULL == source->hash.data, elf_getdata);
207 memcpy(&source->hash.shdr, shdr, sizeof(GElf_Shdr));
208 }
209 else if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
210 if (source->num_relocations == source->relocations_size) {
211 source->relocations_size += 5;
212 source->relocations =
213 (section_info_t *)REALLOC(source->relocations,
214 source->relocations_size *
215 sizeof(section_info_t));
216 }
217 section_info_t *reloc =
218 source->relocations + source->num_relocations;
219 reloc->scn = scn;
220 reloc->data = elf_getdata(scn, NULL);
221 FAILIF_LIBELF(NULL == reloc->data, elf_getdata);
222 memcpy(&reloc->shdr, shdr, sizeof(GElf_Shdr));
223 source->num_relocations++;
224 }
225 }
226
227 if (source->dynamic.scn == NULL) {
228 INFO("File [%s] does not have a dynamic section!\n", full_path);
229 return 0;
230 }
231
232 FAILIF(source->symtab.scn == NULL,
233 "File [%s] does not have a dynamic symbol table!\n",
234 full_path);
235
236 FAILIF(source->hash.scn == NULL,
237 "File [%s] does not have a hash table!\n",
238 full_path);
239 FAILIF(source->hash.shdr.sh_link != elf_ndxscn(source->symtab.scn),
240 "Hash points to section %d, not to %d as expected!\n",
241 source->hash.shdr.sh_link,
242 elf_ndxscn(scn));
243
244 /* Now, find out how many symbols we have and allocate the array of
245 satisfied symbols.
246
247 NOTE: We don't count the number of undefined symbols here; we will
248 iterate over the symbol table later, and count them then, when it is
249 more convenient.
250 */
251 size_t symsize = gelf_fsize (source->elf,
252 ELF_T_SYM,
253 1, source->elf_hdr.e_version);
254 ASSERT(symsize);
255
256 source->num_syms = source->symtab.data->d_size / symsize;
257 source->satisfied = (source_t **)CALLOC(source->num_syms,
258 sizeof(source_t *));
259 source->exports = (source_t **)CALLOC(source->num_syms,
260 sizeof(next_export_t));
261
262 source->num_exported = 0;
263 source->satisfied_execs = NULL;
264 source->num_satisfied_execs = 0;
265 source->satisfied_execs_size = 0;
266
267 add_to_sources(source);
268 return source;
269 }
270
destroy_source(source_t * source)271 static void destroy_source(source_t *source) {
272 FREE(source->satisfied_execs);
273 FREE(source->satisfied);
274 FREE(source->exports);
275 FREE(source->next_export);
276 FREE(source->lib_deps); /* list of library dependencies */
277 FAILIF_LIBELF(elf_end(source->elf), elf_end);
278 FAILIF(close(source->elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
279 source->name, strerror(errno), errno);
280 FREE(source->name);
281 FREE(source);
282 }
283
print_needed_libs(source_t * source)284 static void print_needed_libs(source_t *source)
285 {
286 size_t idx;
287 for (idx = 0; idx < source->num_lib_deps; idx++) {
288 PRINT("%s:%s\n",
289 source->name,
290 source->lib_deps[idx]->name);
291 }
292 }
293
is_symbol_imported(source_t * source,GElf_Sym * sym,size_t symidx)294 static int is_symbol_imported(source_t *source,
295 GElf_Sym *sym,
296 size_t symidx)
297 {
298 const char *symname = elf_strptr(source->elf,
299 elf_ndxscn(source->strtab.scn),
300 sym->st_name);
301
302 /* A symbol is imported by an executable or a library if it is undefined
303 and is either global or weak. There is an additional case for
304 executables that we will check below. */
305 if (sym->st_shndx == SHN_UNDEF &&
306 (GELF_ST_BIND(sym->st_info) == STB_GLOBAL ||
307 GELF_ST_BIND(sym->st_info) == STB_WEAK)) {
308 INFO("*** symbol [%s:%s] is imported (UNDEFIEND).\n",
309 source->name,
310 symname);
311 return 1;
312 }
313
314 #ifdef ARM_SPECIFIC_HACKS
315 /* A symbol is imported by an executable if is marked as an undefined
316 symbol--this is standard to all ELF formats. Alternatively, according
317 to the ARM specifications, a symbol in a BSS section that is also marked
318 by an R_ARM_COPY relocation is also imported. */
319
320 if (source->elf_hdr.e_type != ET_EXEC) {
321 INFO("is_symbol_imported(): [%s] is a library, "
322 "no further checks.\n", source->name);
323 return 0;
324 }
325
326 /* Is the symbol in the BSS section, and is there a COPY relocation on
327 that symbol? */
328 INFO("*** [%s:%s] checking further to see if symbol is imported.\n",
329 source->name, symname);
330 if (sym->st_shndx < source->shnum) {
331 /* Is it the .bss section? */
332 Elf_Scn *scn = elf_getscn(source->elf, sym->st_shndx);
333 FAILIF_LIBELF(NULL == scn, elf_getscn);
334 GElf_Shdr *shdr, shdr_mem;
335 shdr = gelf_getshdr(scn, &shdr_mem);
336 FAILIF_LIBELF(NULL == shdr, gelf_getshdr);
337 if (!strcmp(".bss", elf_strptr(source->elf,
338 source->shstrndx,
339 shdr->sh_name)))
340 {
341 /* Is there an R_ARM_COPY relocation on this symbol? Iterate
342 over the list of relocation sections and scan each section for
343 an entry that matches the symbol. */
344 size_t idx;
345 for (idx = 0; idx < source->num_relocations; idx++) {
346 section_info_t *reloc = source->relocations + idx;
347 /* Does the relocation section refer to the symbol table in
348 which this symbol resides, and does it relocate the .bss
349 section? */
350 if (reloc->shdr.sh_link == elf_ndxscn(source->symtab.scn) &&
351 reloc->shdr.sh_info == sym->st_shndx)
352 {
353 /* Go over the relocations and see if any of them matches
354 our symbol. */
355 size_t nrels = reloc->shdr.sh_size / reloc->shdr.sh_entsize;
356 size_t relidx, newidx;
357 if (reloc->shdr.sh_type == SHT_REL) {
358 for (newidx = relidx = 0; relidx < nrels; ++relidx) {
359 GElf_Rel rel_mem;
360 FAILIF_LIBELF(gelf_getrel (reloc->data,
361 relidx,
362 &rel_mem) == NULL,
363 gelf_getrel);
364 if (GELF_R_TYPE(rel_mem.r_info) == R_ARM_COPY &&
365 GELF_R_SYM (rel_mem.r_info) == symidx)
366 {
367 INFO("*** symbol [%s:%s] is imported "
368 "(DEFINED, REL-COPY-RELOCATED).\n",
369 source->name,
370 symname);
371 return 1;
372 }
373 } /* for each rel entry... */
374 } else {
375 for (newidx = relidx = 0; relidx < nrels; ++relidx) {
376 GElf_Rela rel_mem;
377 FAILIF_LIBELF(gelf_getrela (reloc->data,
378 relidx,
379 &rel_mem) == NULL,
380 gelf_getrela);
381 if (GELF_R_TYPE(rel_mem.r_info) == R_ARM_COPY &&
382 GELF_R_SYM (rel_mem.r_info) == symidx)
383 {
384 INFO("*** symbol [%s:%s] is imported "
385 "(DEFINED, RELA-COPY-RELOCATED).\n",
386 source->name,
387 symname);
388 return 1;
389 }
390 } /* for each rela entry... */
391 } /* if rel else rela */
392 }
393 }
394 }
395 }
396 #endif/*ARM_SPECIFIC_HACKS*/
397
398 return 0;
399 }
400
resolve(source_t * source)401 static void resolve(source_t *source) {
402 /* Iterate the symbol table. For each undefined symbol, scan the
403 list of dependencies till we find a global symbol in one of them that
404 satisfies the undefined reference. At this point, we update both the
405 satisfied[] array of the sources entry, as well as the exports array of
406 the dependency where we found the match.
407 */
408
409 GElf_Sym *sym, sym_mem;
410 size_t symidx;
411 for (symidx = 0; symidx < source->num_syms; symidx++) {
412 sym = gelf_getsymshndx(source->symtab.data,
413 NULL,
414 symidx,
415 &sym_mem,
416 NULL);
417 FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
418 if (is_symbol_imported(source, sym, symidx))
419 {
420 /* This is an undefined symbol. Go over the list of libraries
421 and look it up. */
422 size_t libidx;
423 int found = 0;
424 source_t *last_found = NULL;
425 const char *symname = elf_strptr(source->elf,
426 elf_ndxscn(source->strtab.scn),
427 sym->st_name);
428 for (libidx = 0; libidx < source->num_lib_deps; libidx++) {
429 source_t *lib = source->lib_deps[libidx];
430 int lib_symidx = hash_lookup(lib->elf,
431 lib->hash.data,
432 lib->symtab.data,
433 lib->strtab.data,
434 symname);
435 if (STN_UNDEF != lib_symidx)
436 {
437 /* We found the symbol--now check to see if it is global
438 or weak. If this is the case, then the symbol satisfies
439 the dependency. */
440 GElf_Sym *lib_sym, lib_sym_mem;
441 lib_sym = gelf_getsymshndx(lib->symtab.data,
442 NULL,
443 lib_symidx,
444 &lib_sym_mem,
445 NULL);
446 FAILIF_LIBELF(NULL == lib_sym, gelf_getsymshndx);
447
448 if(lib_sym->st_shndx != STN_UNDEF &&
449 (GELF_ST_BIND(lib_sym->st_info) == STB_GLOBAL ||
450 GELF_ST_BIND(lib_sym->st_info) == STB_WEAK))
451 {
452 /* We found the symbol! Update the satisfied array at this
453 index location. */
454 source->satisfied[symidx] = lib;
455 /* Now, link this structure into the linked list
456 corresponding to the found symbol in the library's
457 global array. */
458 if (source->num_next_export == source->next_export_size) {
459 source->next_export_size += 30;
460 source->next_export =
461 (source_t **)REALLOC(source->next_export,
462 source->next_export_size *
463 sizeof(struct next_export_t));
464 }
465 source->next_export[source->num_next_export] = lib->exports[lib_symidx];
466 lib->exports[lib_symidx].source = source;
467 lib->exports[lib_symidx].next_idx = source->num_next_export;
468
469 source->num_next_export++;
470 lib->num_exported++;
471
472 INFO("[%s:%s (index %d)] satisfied by [%s] (index %d)\n",
473 source->name,
474 symname,
475 symidx,
476 lib->name,
477 lib_symidx);
478 if (found) {
479 if (found == 1) {
480 found++;
481 ERROR("ERROR: multiple definitions found for [%s:%s]!\n",
482 source->name, symname);
483 ERROR("\tthis definition [%s]\n", lib->name);
484 }
485 ERROR("\tprevious definition [%s]\n", last_found->name);
486 }
487
488 last_found = lib;
489 if (!found) found = 1;
490 }
491 }
492 }
493 if(found == 0) {
494 ERROR("ERROR: could not find match for %s:%s.\n",
495 source->name,
496 symname);
497 }
498 } /* if we found the symbol... */
499 } /* for each symbol... */
500 } /* resolve() */
501
print_used_symbols(source_t * source)502 static void print_used_symbols(source_t *source) {
503
504 int name_len = strlen(source->name);
505 static const char ext[] = ".syms";
506 char *filter = (char *)MALLOC(name_len + sizeof(ext));
507 strcpy(filter, source->name);
508 strcpy(filter + name_len, ext);
509
510 FILE *fp = fopen(filter, "w+");
511 FAILIF(NULL == fp,
512 "Can't open %s: %s (%d)\n",
513 filter,
514 strerror(errno), errno);
515
516 /* Is anybody using the symbols defined in source? */
517
518 if (source->num_exported > 0) {
519 INFO("[%s] exports %d symbols to %d libraries and executables.\n",
520 source->name,
521 source->num_exported,
522 source->num_satisfied_execs);
523 size_t symidx;
524 for (symidx = 0; symidx < source->num_syms; symidx++) {
525 if (source->exports[symidx].source != NULL) {
526 GElf_Sym *sym, sym_mem;
527 sym = gelf_getsymshndx(source->symtab.data,
528 NULL,
529 symidx,
530 &sym_mem,
531 NULL);
532 FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
533 fprintf(fp, "%s\n", elf_strptr(source->elf,
534 elf_ndxscn(source->strtab.scn),
535 sym->st_name));
536 }
537 }
538 }
539 else if (source->num_satisfied_execs > 0) {
540
541 /* Is the source listed as a depenency on anyone? If so, then the source exports no symbols
542 to anyone, but someone lists it as a dependency, which is unnecessary, so we print a warning.
543 */
544
545 ERROR("WARNING: [%s] is listed as a dependency in: ", source->name);
546 int i;
547 for (i = 0; i < source->num_satisfied_execs; i++) {
548 ERROR(" [%s],", source->satisfied_execs[i]->name);
549 }
550 ERROR(" but none of its symbols are used!.\n");
551 }
552 #if 0 /* This is not really an error--a library's symbols may not be used anyone as specified in the ELF file,
553 but someone may still open a library via dlopen().
554 */
555 else {
556 ERROR("WARNING: None of [%s]'s symbols are used by any library or executable!\n", source->name);
557 }
558 #endif
559
560 fclose(fp);
561 FREE(filter);
562 }
563
print_symbol_references(source_t * source)564 static void print_symbol_references(source_t *source) {
565
566 int name_len = strlen(source->name);
567 static const char ext[] = ".info";
568 char *filter = (char *)MALLOC(name_len + sizeof(ext));
569 strcpy(filter, source->name);
570 strcpy(filter + name_len, ext);
571
572 FILE *fp = fopen(filter, "w+");
573 FAILIF(NULL == fp,
574 "Can't open %s: %s (%d)\n",
575 filter,
576 strerror(errno), errno);
577
578 if (source->num_exported > 0) {
579 size_t symidx;
580 for (symidx = 0; symidx < source->num_syms; symidx++) {
581 if (source->exports[symidx].source != NULL) {
582 const char *symname;
583 GElf_Sym *sym, sym_mem;
584 sym = gelf_getsymshndx(source->symtab.data,
585 NULL,
586 symidx,
587 &sym_mem,
588 NULL);
589 FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
590 symname = elf_strptr(source->elf,
591 elf_ndxscn(source->strtab.scn),
592 sym->st_name);
593 fprintf(fp, "%s\n", symname);
594 next_export_t *export = &source->exports[symidx];
595 while (export->source != NULL) {
596 //fprintf(stderr, "%s:%s\n", symname, export->source->name);
597 fprintf(fp, "\t%s\n", export->source->name);
598 export = &export->source->next_export[export->next_idx];
599 }
600 }
601 }
602 }
603
604 fclose(fp);
605 FREE(filter);
606 }
607
find_file(const char * libname,char ** lib_lookup_dirs,int num_lib_lookup_dirs)608 static char * find_file(const char *libname,
609 char **lib_lookup_dirs,
610 int num_lib_lookup_dirs) {
611 if (libname[0] == '/') {
612 /* This is an absolute path name--just return it. */
613 INFO("ABSOLUTE PATH: [%s].\n", libname);
614 return strdup(libname);
615 } else {
616 /* First try the working directory. */
617 int fd;
618 if ((fd = open(libname, O_RDONLY)) > 0) {
619 close(fd);
620 INFO("FOUND IN CURRENT DIR: [%s].\n", libname);
621 return strdup(libname);
622 } else {
623 /* Iterate over all library paths. For each path, append the file
624 name and see if there is a file at that place. If that fails,
625 bail out. */
626
627 char *name;
628 while (num_lib_lookup_dirs--) {
629 size_t lib_len = strlen(*lib_lookup_dirs);
630 /* one extra character for the slash, and another for the
631 terminating NULL. */
632 name = (char *)MALLOC(lib_len + strlen(libname) + 2);
633 strcpy(name, *lib_lookup_dirs);
634 name[lib_len] = '/';
635 strcpy(name + lib_len + 1, libname);
636 if ((fd = open(name, O_RDONLY)) > 0) {
637 close(fd);
638 INFO("FOUND: [%s] in [%s].\n", libname, name);
639 return name;
640 }
641 INFO("NOT FOUND: [%s] in [%s].\n", libname, name);
642 free(name);
643 }
644 }
645 }
646 return NULL;
647 }
648
process_library(const char * libname,char ** lib_lookup_dirs,int num_lib_lookup_dirs)649 static source_t* process_library(const char *libname,
650 char **lib_lookup_dirs,
651 int num_lib_lookup_dirs) {
652 source_t *source = find_source(libname, lib_lookup_dirs, num_lib_lookup_dirs);
653 if (NULL == source) {
654 INFO("Processing [%s].\n", libname);
655 char *full = find_file(libname, lib_lookup_dirs, num_lib_lookup_dirs);
656 FAILIF(NULL == full,
657 "Could not find [%s] in the current directory or in any of "
658 "the search paths!\n", libname);
659 source = init_source(full);
660 if (source) {
661 GElf_Dyn *dyn, dyn_mem;
662 size_t dynidx;
663 size_t numdyn =
664 source->dynamic.shdr.sh_size /
665 source->dynamic.shdr.sh_entsize;
666
667 for (dynidx = 0; dynidx < numdyn; dynidx++) {
668 dyn = gelf_getdyn (source->dynamic.data,
669 dynidx,
670 &dyn_mem);
671 FAILIF_LIBELF(NULL == dyn, gelf_getdyn);
672 if (dyn->d_tag == DT_NEEDED) {
673 /* Process the needed library recursively. */
674 const char *dep_lib =
675 elf_strptr (source->elf,
676 source->dynamic.shdr.sh_link,
677 dyn->d_un.d_val);
678 INFO("[%s] depends on [%s].\n", libname, dep_lib);
679 source_t *dep = process_library(dep_lib,
680 lib_lookup_dirs,
681 num_lib_lookup_dirs);
682
683 /* Tell dep that source depends on it. */
684 if (dep->num_satisfied_execs == dep->satisfied_execs_size) {
685 dep->satisfied_execs_size += 10;
686 dep->satisfied_execs =
687 REALLOC(dep->satisfied_execs,
688 dep->satisfied_execs_size *
689 sizeof(source_t *));
690 }
691 dep->satisfied_execs[dep->num_satisfied_execs++] = source;
692
693 /* Add the library to the dependency list. */
694 if (source->num_lib_deps == source->lib_deps_size) {
695 source->lib_deps_size += 10;
696 source->lib_deps = REALLOC(source->lib_deps,
697 source->lib_deps_size *
698 sizeof(source_t *));
699 }
700 source->lib_deps[source->num_lib_deps++] = dep;
701 }
702 } /* for each dynamic entry... */
703 }
704 } else INFO("[%s] has been processed already.\n", libname);
705
706 return source;
707 }
708
lsd(char ** execs,int num_execs,int list_needed_libs,int print_info,char ** lib_lookup_dirs,int num_lib_lookup_dirs)709 void lsd(char **execs, int num_execs,
710 int list_needed_libs,
711 int print_info,
712 char **lib_lookup_dirs, int num_lib_lookup_dirs) {
713
714 source_t *source; /* for general usage */
715 int input_idx;
716
717 for (input_idx = 0; input_idx < num_execs; input_idx++) {
718 INFO("executable: [%s]\n", execs[input_idx]);
719 /* Here process library is actually processing the top-level executable
720 files. */
721 process_library(execs[input_idx], lib_lookup_dirs, num_lib_lookup_dirs);
722 /* if source is NULL, then the respective executable is static */
723 /* Mark the source as an executable */
724 } /* for each input executable... */
725
726 if (list_needed_libs) {
727 source = sources;
728 while (source) {
729 print_needed_libs(source);
730 source = source->next;
731 }
732 }
733
734 /* Now, for each entry in the sources array, iterate its symbol table. For
735 each undefined symbol, scan the list of dependencies till we find a
736 global symbol in one of them that satisfies the undefined reference.
737 At this point, we update both the satisfied[] array of the sources entry,
738 as well as the exports array of the dependency where we found the match.
739 */
740
741 source = sources;
742 while (source) {
743 resolve(source);
744 source = source->next;
745 }
746
747 /* We are done! Since the end result of our calculations is a set of
748 symbols for each library that other libraries or executables link
749 against, we iterate over the set of libraries one last time, and for
750 each symbol that is marked as satisfying some dependence, we emit
751 a line with the symbol's name to a text file derived from the library's
752 name by appending the suffix .syms to it. */
753
754 source = sources;
755 while (source) {
756 /* If it's a library, print the results. */
757 if (source->elf_hdr.e_type == ET_DYN) {
758 print_used_symbols(source);
759 if (print_info)
760 print_symbol_references(source);
761 }
762 source = source->next;
763 }
764
765 /* Free the resources--you can't do it in the loop above because function
766 print_symbol_references() accesses nodes other than the one being
767 iterated over.
768 */
769 source = sources;
770 while (source) {
771 source_t *old = source;
772 source = source->next;
773 /* Destroy the evidence. */
774 destroy_source(old);
775 }
776 }
777
778