Merge "Remove elftree."
This commit is contained in:
@@ -1,25 +0,0 @@
|
|||||||
# Copyright (C) 2010 The Android Open Source Project
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
LOCAL_PATH := $(call my-dir)
|
|
||||||
|
|
||||||
ifeq ($(HOST_OS),linux)
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
LOCAL_MODULE := elftree
|
|
||||||
LOCAL_SRC_FILES := elftree.c
|
|
||||||
LOCAL_STATIC_LIBRARIES := libelf
|
|
||||||
include $(BUILD_HOST_EXECUTABLE)
|
|
||||||
|
|
||||||
endif
|
|
||||||
@@ -1,328 +0,0 @@
|
|||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <gelf.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#define PATH_MAX 256
|
|
||||||
|
|
||||||
static enum { HIDE_DUPS, PRUNE_DUPS, SHOW_DUPS } dup_mode;
|
|
||||||
static char *root_name;
|
|
||||||
|
|
||||||
static void app_err(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unix_err(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
int errsv;
|
|
||||||
|
|
||||||
errsv = errno;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
fprintf(stderr, ": %s\n", strerror(errsv));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void elf_err(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
fprintf(stderr, ": %s\n", elf_errmsg(-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct seen {
|
|
||||||
char *name;
|
|
||||||
struct seen *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tree_state {
|
|
||||||
int level;
|
|
||||||
struct seen *seen;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int seen(struct tree_state *t, char *name)
|
|
||||||
{
|
|
||||||
struct seen *s;
|
|
||||||
|
|
||||||
for (s = t->seen; s; s = s->next) {
|
|
||||||
if (!strcmp(s->name, name))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void see(struct tree_state *t, char *name)
|
|
||||||
{
|
|
||||||
struct seen *s = malloc(sizeof(*s));
|
|
||||||
s->name = malloc(strlen(name) + 1);
|
|
||||||
strcpy(s->name, name);
|
|
||||||
s->next = t->seen;
|
|
||||||
t->seen = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *indent_str = " ";
|
|
||||||
|
|
||||||
static void indent(struct tree_state *t)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < t->level; i++)
|
|
||||||
printf("%s", indent_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct search_dir {
|
|
||||||
char *path;
|
|
||||||
struct search_dir *next;
|
|
||||||
} *dirs = NULL;
|
|
||||||
|
|
||||||
static void add_search_dir(char *path)
|
|
||||||
{
|
|
||||||
struct search_dir *dir = malloc(sizeof(*dir));
|
|
||||||
dir->path = malloc(strlen(path) + 1);
|
|
||||||
strcpy(dir->path, path);
|
|
||||||
dir->next = dirs;
|
|
||||||
dirs = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct file_state {
|
|
||||||
struct tree_state *t;
|
|
||||||
Elf *e;
|
|
||||||
Elf_Data *strtab_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static Elf_Scn *find_scn(struct file_state *f, GElf_Word sht, Elf_Scn *scn, GElf_Shdr *shdr_out)
|
|
||||||
{
|
|
||||||
while ((scn = elf_nextscn(f->e, scn))) {
|
|
||||||
if (!gelf_getshdr(scn, shdr_out))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (shdr_out->sh_type == sht)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return scn;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dyn_state {
|
|
||||||
struct file_state *f;
|
|
||||||
Elf_Data *dyn_data;
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int find_dyn(struct dyn_state *d, GElf_Sxword tag, GElf_Dyn *dyn_out)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < d->count; i++) {
|
|
||||||
if (!gelf_getdyn(d->dyn_data, i, dyn_out))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (dyn_out->d_tag == tag)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dump_file(struct tree_state *t, char *name, char *path);
|
|
||||||
|
|
||||||
static int dump_needed(struct tree_state *t, char *name)
|
|
||||||
{
|
|
||||||
struct search_dir *dir;
|
|
||||||
char path[PATH_MAX];
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
t->level++;
|
|
||||||
|
|
||||||
for (dir = dirs; dir; dir = dir->next) {
|
|
||||||
snprintf(path, PATH_MAX, "%s/%s", dir->path, name);
|
|
||||||
fd = open(path, O_RDONLY);
|
|
||||||
if (fd >= 0) {
|
|
||||||
close(fd);
|
|
||||||
dump_file(t, name, path);
|
|
||||||
t->level--;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app_err("Couldn't resolve dependency \"%s\".", name);
|
|
||||||
t->level--;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dump_dynamic(struct file_state *f, Elf_Scn *scn, GElf_Shdr *shdr)
|
|
||||||
{
|
|
||||||
struct dyn_state d;
|
|
||||||
GElf_Dyn needed_dyn;
|
|
||||||
char *needed_name;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
d.f = f;
|
|
||||||
d.dyn_data = elf_getdata(scn, NULL);
|
|
||||||
if (!d.dyn_data) {
|
|
||||||
elf_err("elf_getdata failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
d.count = shdr->sh_size / shdr->sh_entsize;
|
|
||||||
|
|
||||||
for (i = 0; i < d.count; i++) {
|
|
||||||
if (!gelf_getdyn(d.dyn_data, i, &needed_dyn))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (needed_dyn.d_tag != DT_NEEDED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
needed_name = (char *)f->strtab_data->d_buf
|
|
||||||
+ needed_dyn.d_un.d_val;
|
|
||||||
|
|
||||||
dump_needed(f->t, needed_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dump_file(struct tree_state *t, char *name, char *file)
|
|
||||||
{
|
|
||||||
struct file_state f;
|
|
||||||
int fd;
|
|
||||||
Elf_Scn *scn;
|
|
||||||
GElf_Shdr shdr;
|
|
||||||
|
|
||||||
if ((dup_mode == HIDE_DUPS) && seen(t, name))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
indent(t); printf("%s", name);
|
|
||||||
|
|
||||||
if ((dup_mode == PRUNE_DUPS) && seen(t, name)) {
|
|
||||||
printf("...\n");
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
printf(":\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
see(t, name);
|
|
||||||
|
|
||||||
f.t = t;
|
|
||||||
|
|
||||||
fd = open(file, O_RDONLY);
|
|
||||||
if (fd < 0) {
|
|
||||||
unix_err("open(%s) failed", file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
f.e = elf_begin(fd, ELF_C_READ, NULL);
|
|
||||||
if (!f.e) {
|
|
||||||
elf_err("elf_begin failed on %s", file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
scn = find_scn(&f, SHT_STRTAB, NULL, &shdr);
|
|
||||||
f.strtab_data = elf_getdata(scn, NULL);
|
|
||||||
if (!f.strtab_data) {
|
|
||||||
app_err("%s has no strtab section", file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
scn = NULL;
|
|
||||||
while ((scn = find_scn(&f, SHT_DYNAMIC, scn, &shdr))) {
|
|
||||||
dump_dynamic(&f, scn, &shdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
elf_end(f.e);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage(void)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage: elftree [ -s | -h ] elf-file\n"
|
|
||||||
" -S Duplicate entire subtree when a duplicate is found\n"
|
|
||||||
" -P Show duplicates, but only include subtree once\n"
|
|
||||||
" -H Show each library at most once, even if duplicated\n"
|
|
||||||
" -h Show this help screen\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_args(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 1; i < argc - 1; i++) {
|
|
||||||
if (!strcmp(argv[i], "-S")) {
|
|
||||||
dup_mode = SHOW_DUPS;
|
|
||||||
} else if (!strcmp(argv[i], "-P")) {
|
|
||||||
dup_mode = PRUNE_DUPS;
|
|
||||||
} else if (!strcmp(argv[i], "-H")) {
|
|
||||||
dup_mode = HIDE_DUPS;
|
|
||||||
} else if (!strcmp(argv[i], "-h")) {
|
|
||||||
usage();
|
|
||||||
exit(0);
|
|
||||||
} else {
|
|
||||||
app_err("Unexpected argument \"%s\"!\n", argv[i]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
root_name = argv[argc - 1];
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_search_dirs(void)
|
|
||||||
{
|
|
||||||
char *relpath;
|
|
||||||
char path[PATH_MAX];
|
|
||||||
|
|
||||||
relpath = getenv("ANDROID_PRODUCT_OUT");
|
|
||||||
if (!relpath) {
|
|
||||||
app_err("Warning: ANDROID_PRODUCT_OUT not set; "
|
|
||||||
"using current directory.\n");
|
|
||||||
relpath = ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(path, PATH_MAX, "%s/%s", relpath, "system/lib");
|
|
||||||
add_search_dir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct tree_state t;
|
|
||||||
|
|
||||||
if (argc < 2 || parse_args(argc, argv)) {
|
|
||||||
usage();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elf_version(EV_CURRENT) == EV_NONE) {
|
|
||||||
elf_err("version mismatch");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
t.level = 0;
|
|
||||||
t.seen = NULL;
|
|
||||||
|
|
||||||
add_search_dirs();
|
|
||||||
|
|
||||||
dump_file(&t, root_name, root_name);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user