160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <errno.h> 260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <fcntl.h> 360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <gelf.h> 460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <stdarg.h> 560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <stdio.h> 660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <stdlib.h> 760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <string.h> 860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#include <unistd.h> 960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 1060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle#define PATH_MAX 256 1160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 1260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic enum { HIDE_DUPS, PRUNE_DUPS, SHOW_DUPS } dup_mode; 1360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic char *root_name; 1460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 1560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void app_err(const char *fmt, ...) 1660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 1760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_list ap; 1860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 1960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_start(ap, fmt); 2060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle vfprintf(stderr, fmt, ap); 2160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_end(ap); 2260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 2360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle fprintf(stderr, "\n"); 2460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 2560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 2660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void unix_err(const char *fmt, ...) 2760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 2860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_list ap; 2960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int errsv; 3060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 3160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle errsv = errno; 3260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 3360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_start(ap, fmt); 3460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle vfprintf(stderr, fmt, ap); 3560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_end(ap); 3660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 3760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle fprintf(stderr, ": %s\n", strerror(errsv)); 3860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 3960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 4060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void elf_err(const char *fmt, ...) 4160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 4260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_list ap; 4360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 4460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_start(ap, fmt); 4560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle vfprintf(stderr, fmt, ap); 4660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle va_end(ap); 4760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 4860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle fprintf(stderr, ": %s\n", elf_errmsg(-1)); 4960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 5060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 5160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestruct seen { 5260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle char *name; 5360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct seen *next; 5460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle}; 5560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 5660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestruct tree_state { 5760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int level; 5860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct seen *seen; 5960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle}; 6060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 6160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic int seen(struct tree_state *t, char *name) 6260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 6360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct seen *s; 6460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 6560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle for (s = t->seen; s; s = s->next) { 6660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!strcmp(s->name, name)) 6760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 1; 6860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 6960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 7060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 7160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 7260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 7360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void see(struct tree_state *t, char *name) 7460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 7560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct seen *s = malloc(sizeof(*s)); 7660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle s->name = malloc(strlen(name) + 1); 7760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle strcpy(s->name, name); 7860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle s->next = t->seen; 7960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle t->seen = s; 8060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 8160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 8260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlechar *indent_str = " "; 8360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 8460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void indent(struct tree_state *t) 8560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 8660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int i; 8760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 8860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle for (i = 0; i < t->level; i++) 8960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle printf("%s", indent_str); 9060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 9160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 9260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestruct search_dir { 9360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle char *path; 9460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct search_dir *next; 9560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} *dirs = NULL; 9660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 9760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void add_search_dir(char *path) 9860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 9960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct search_dir *dir = malloc(sizeof(*dir)); 10060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dir->path = malloc(strlen(path) + 1); 10160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle strcpy(dir->path, path); 10260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dir->next = dirs; 10360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dirs = dir; 10460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 10560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 10660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestruct file_state { 10760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct tree_state *t; 10860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle Elf *e; 10960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle Elf_Data *strtab_data; 11060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle}; 11160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 11260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic Elf_Scn *find_scn(struct file_state *f, GElf_Word sht, Elf_Scn *scn, GElf_Shdr *shdr_out) 11360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 11460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle while ((scn = elf_nextscn(f->e, scn))) { 11560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!gelf_getshdr(scn, shdr_out)) 11660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle continue; 11760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 11860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (shdr_out->sh_type == sht) 11960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle break; 12060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 12160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 12260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return scn; 12360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 12460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 12560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestruct dyn_state { 12660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct file_state *f; 12760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle Elf_Data *dyn_data; 12860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int count; 12960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle}; 13060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 13160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic int find_dyn(struct dyn_state *d, GElf_Sxword tag, GElf_Dyn *dyn_out) 13260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 13360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int i; 13460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 13560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle for (i = 0; i < d->count; i++) { 13660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!gelf_getdyn(d->dyn_data, i, dyn_out)) 13760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle continue; 13860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 13960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (dyn_out->d_tag == tag) 14060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 14160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 14260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 14360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return -1; 14460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 14560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 14660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic int dump_file(struct tree_state *t, char *name, char *path); 14760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 14860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic int dump_needed(struct tree_state *t, char *name) 14960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 15060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct search_dir *dir; 15160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle char path[PATH_MAX]; 15260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int fd; 15360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 15460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle t->level++; 15560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 15660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle for (dir = dirs; dir; dir = dir->next) { 15760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle snprintf(path, PATH_MAX, "%s/%s", dir->path, name); 15860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle fd = open(path, O_RDONLY); 15960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (fd >= 0) { 16060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle close(fd); 16160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dump_file(t, name, path); 16260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle t->level--; 16360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 16460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 16560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 16660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 16760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle app_err("Couldn't resolve dependency \"%s\".", name); 16860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle t->level--; 16960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return -1; 17060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 17160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 17260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic int dump_dynamic(struct file_state *f, Elf_Scn *scn, GElf_Shdr *shdr) 17360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 17460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct dyn_state d; 17560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle GElf_Dyn needed_dyn; 17660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle char *needed_name; 17760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int i; 17860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 17960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle d.f = f; 18060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle d.dyn_data = elf_getdata(scn, NULL); 18160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!d.dyn_data) { 18260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle elf_err("elf_getdata failed"); 18360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return -1; 18460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 18560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle d.count = shdr->sh_size / shdr->sh_entsize; 18660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 18760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle for (i = 0; i < d.count; i++) { 18860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!gelf_getdyn(d.dyn_data, i, &needed_dyn)) 18960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle continue; 19060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 19160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (needed_dyn.d_tag != DT_NEEDED) 19260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle continue; 19360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 19460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle needed_name = (char *)f->strtab_data->d_buf 19560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle + needed_dyn.d_un.d_val; 19660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 19760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dump_needed(f->t, needed_name); 19860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 19960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 20060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 20160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 20260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 20360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic int dump_file(struct tree_state *t, char *name, char *file) 20460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 20560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct file_state f; 20660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int fd; 20760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle Elf_Scn *scn; 20860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle GElf_Shdr shdr; 20960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 21060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if ((dup_mode == HIDE_DUPS) && seen(t, name)) 21160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 21260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 21360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle indent(t); printf("%s", name); 21460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 21560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if ((dup_mode == PRUNE_DUPS) && seen(t, name)) { 21660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle printf("...\n"); 21760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 21860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } else { 21960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle printf(":\n"); 22060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 22160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 22260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle see(t, name); 22360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 22460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle f.t = t; 22560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 22660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle fd = open(file, O_RDONLY); 22760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (fd < 0) { 22860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle unix_err("open(%s) failed", file); 22960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return -1; 23060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 23160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 23260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle f.e = elf_begin(fd, ELF_C_READ, NULL); 23360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!f.e) { 23460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle elf_err("elf_begin failed on %s", file); 23560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return -1; 23660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 23760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 23860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle scn = find_scn(&f, SHT_STRTAB, NULL, &shdr); 23960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle f.strtab_data = elf_getdata(scn, NULL); 24060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!f.strtab_data) { 24160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle app_err("%s has no strtab section", file); 24260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return -1; 24360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 24460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 24560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle scn = NULL; 24660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle while ((scn = find_scn(&f, SHT_DYNAMIC, scn, &shdr))) { 24760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dump_dynamic(&f, scn, &shdr); 24860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 24960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 25060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle elf_end(f.e); 25160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle close(fd); 25260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 25360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 25460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 25560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 25660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void usage(void) 25760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 25860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle fprintf(stderr, "Usage: elftree [ -s | -h ] elf-file\n" 25960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle " -S Duplicate entire subtree when a duplicate is found\n" 26060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle " -P Show duplicates, but only include subtree once\n" 26160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle " -H Show each library at most once, even if duplicated\n" 26260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle " -h Show this help screen\n"); 26360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 26460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 26560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic int parse_args(int argc, char *argv[]) 26660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 26760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle int i; 26860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 26960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle for (i = 1; i < argc - 1; i++) { 27060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!strcmp(argv[i], "-S")) { 27160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dup_mode = SHOW_DUPS; 27260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } else if (!strcmp(argv[i], "-P")) { 27360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dup_mode = PRUNE_DUPS; 27460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } else if (!strcmp(argv[i], "-H")) { 27560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dup_mode = HIDE_DUPS; 27660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } else if (!strcmp(argv[i], "-h")) { 27760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle usage(); 27860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle exit(0); 27960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } else { 28060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle app_err("Unexpected argument \"%s\"!\n", argv[i]); 28160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return -1; 28260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 28360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 28460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 28560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle root_name = argv[argc - 1]; 28660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 28760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 28860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 28960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 29060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttlestatic void add_search_dirs(void) 29160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 29260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle char *relpath; 29360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle char path[PATH_MAX]; 29460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 29560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle relpath = getenv("ANDROID_PRODUCT_OUT"); 29660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (!relpath) { 29760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle app_err("Warning: ANDROID_PRODUCT_OUT not set; " 29860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle "using current directory.\n"); 29960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle relpath = "."; 30060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 30160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 30260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle snprintf(path, PATH_MAX, "%s/%s", relpath, "system/lib"); 30360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle add_search_dir(path); 30460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 30560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 30660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttleint main(int argc, char *argv[]) 30760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle{ 30860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle struct tree_state t; 30960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 31060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (argc < 2 || parse_args(argc, argv)) { 31160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle usage(); 31260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle exit(EXIT_FAILURE); 31360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 31460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 31560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle if (elf_version(EV_CURRENT) == EV_NONE) { 31660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle elf_err("version mismatch"); 31760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle exit(EXIT_FAILURE); 31860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle } 31960a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 32060a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle t.level = 0; 32160a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle t.seen = NULL; 32260a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 32360a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle add_search_dirs(); 32460a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 32560a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle dump_file(&t, root_name, root_name); 32660a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle 32760a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle return 0; 32860a7ddf27ecc584d89018e16d90287cffae0bcdaThomas Tuttle} 329