static int elf_reloc_x86_64(struct elf_binary *elf, int type,
                            uint64_t addr, uint64_t value)
{
    void *ptr = elf_get_ptr(elf, addr);
    uint64_t *u64;
    uint32_t *u32;
    int32_t *s32;

    switch ( type )
    {
    case 1 /* R_X86_64_64 */ :
        u64 = ptr;
        value += elf->reloc_offset;
        *u64 = value;
        break;
    case 2 /* R_X86_64_PC32 */ :
        u32 = ptr;
        *u32 = value - addr;
        if ( *u32 != (uint32_t)(value - addr) )
        {
            elf_err(elf, "R_X86_64_PC32 overflow: 0x%" PRIx32
                    " != 0x%" PRIx32 "\n",
                    *u32, (uint32_t) (value - addr));
            return -1;
        }
        break;
    case 10 /* R_X86_64_32 */ :
        u32 = ptr;
        value += elf->reloc_offset;
        *u32 = value;
        if ( *u32 != value )
        {
            elf_err(elf, "R_X86_64_32 overflow: 0x%" PRIx32
                    " != 0x%" PRIx64 "\n",
                    *u32, value);
            return -1;
        }
        break;
    case 11 /* R_X86_64_32S */ :
        s32 = ptr;
        value += elf->reloc_offset;
        *s32 = value;
        if ( *s32 != (int64_t) value )
        {
            elf_err(elf, "R_X86_64_32S overflow: 0x%" PRIx32
                    " != 0x%" PRIx64 "\n",
                    *s32, (int64_t) value);
            return -1;
        }
        break;
    default:
        return -1;
    }
    return 0;
}
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;
}
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;
}