#include "ft_nm.h" int is_64_section_init(t_elf64 *nm, int i) { for (Elf64_Xword j = 0; j < nm->shdr[i].sh_size; j++) { if (nm->ptr + nm->shdr[i].sh_offset + j != 0) return 1; } return 0; } char *get_64_name(t_elf64 *nm, int sym) { if (nm->opts.a && ELF64_ST_TYPE(nm->symtab[sym].st_info) == STT_SECTION) return nm->string_table + nm->shdr[nm->symtab[sym].st_shndx].sh_name; else return nm->linked_symnames + nm->symtab[sym].st_name; } char get_64_type(t_elf64 *nm, int i) { Elf64_Ehdr *ehdr = nm->ehdr; Elf64_Sym sym = nm->symtab[i]; uint64_t bind = ELF64_ST_BIND(sym.st_info); int is_global = bind == STB_GLOBAL; if (sym.st_shndx == SHN_ABS) return is_global ? 'A' : bind == STB_WEAK ? 'W' : 'a'; if (sym.st_shndx == SHN_UNDEF) return bind == STB_WEAK ? 'w' : 'U'; char ret = "NDTDFDB "[ELF64_ST_TYPE(sym.st_info)]; if (ret == 'N') { if (bind == STB_WEAK) return 'W'; if (is_64_section_init(nm, sym.st_shndx) || sym.st_value) ret = 'D'; } if (ret == 'D') { if (ehdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD && bind == STB_GNU_UNIQUE) ret = 'u'; else if (bind == STB_WEAK) return 'V'; // should be 'V' or 'W' else if (is_sym_bss(nm->string_table + nm->shdr[sym.st_shndx].sh_name)) ret = 'B'; else if (sym.st_shndx == SHN_COMMON) ret = 'C'; else { Elf64_Shdr shdr = nm->shdr[sym.st_shndx]; if (shdr.sh_type == SHT_NOBITS && !(shdr.sh_flags & SHF_EXECINSTR)) ret = 'B'; else if (!(shdr.sh_flags & SHF_WRITE)) { if (shdr.sh_flags & SHF_EXECINSTR) ret = 'T'; else if (is_sec_read_only2(nm->string_table + shdr.sh_name)) return 't'; else if (is_sec_read_only(nm->string_table + shdr.sh_name) && sym.st_value == 0) return 'n'; else if (is_sym_debug(nm->string_table + shdr.sh_name)) return 'N'; else if (is_sym_text2(nm->string_table + shdr.sh_name)) return 'a'; else ret = 'R'; } } } else if (ret == 'T') if (bind == STB_WEAK) return 'W'; return is_global ? ret : tolower(ret); } void create_64_order_array(t_elf64 *nm, int symbol_num) { for (int i = 0; i < symbol_num; i++) { for (int j = i + 1; j < symbol_num; j++) { int left = nm->ordered_sym_ids[i]; int right = nm->ordered_sym_ids[j]; char *l = get_64_name(nm, left); char *r = get_64_name(nm, right); int cmp = strcmp_ignored(l, r); if ((nm->opts.r && (cmp < 0 || (!cmp && left < right))) || (!nm->opts.r && (cmp > 0 || (!cmp && left > right)))) { int tmp = nm->ordered_sym_ids[i]; nm->ordered_sym_ids[i] = nm->ordered_sym_ids[j]; nm->ordered_sym_ids[j] = tmp; } } } } int print_64_symtab(t_elf64 *nm) { int sym_num = nm->symtab_end - nm->symtab; for (int i = 0; i < sym_num; i++) { int id = nm->opts.p == 0 ? nm->ordered_sym_ids[i] : i; if (nm->sym_names[id] == NULL) continue; if (nm->opts.a || nm->sym_types[id] == 'w' || nm->sym_types[id] == 'U' || (!nm->opts.u && ELF64_ST_TYPE(nm->symtab[id].st_info) != STT_FILE)) { char type = nm->sym_types[id]; if (strlen(nm->sym_names[id]) == 0 && (!nm->opts.a || type == 'u' || type == 'U')) continue; if (type == 'U' || type == 'w') ft_printf("%16c", ' '); else ft_printf("%016x", nm->symtab[id].st_value); ft_printf(" %c", type); char *name = get_64_name(nm, id); ft_printf(" %s\n", name); } } return (0); } int parse_64_symtab(t_elf64 *nm) { Elf64_Shdr *shdr = &nm->shdr[nm->ehdr->e_shstrndx]; nm->string_table = (char *)(nm->ptr + shdr->sh_offset); for (int i = 0; i < nm->ehdr->e_shnum; i++) { if (nm->shdr[i].sh_type == SHT_SYMTAB || (nm->opts.D && nm->shdr[i].sh_type == SHT_DYNSYM)) { nm->symtab = (Elf64_Sym *)(nm->ptr + nm->shdr[i].sh_offset); nm->symtab_end = nm->symtab + (nm->shdr[i].sh_size / sizeof(Elf64_Sym)); int symbol_num = nm->shdr[i].sh_size / nm->shdr[i].sh_entsize; nm->linked_symnames = (char *)(nm->ptr + nm->shdr[nm->shdr[i].sh_link].sh_offset); nm->sym_names = malloc(sizeof(char *) * symbol_num); nm->ordered_sym_ids = malloc(sizeof(int) * symbol_num); nm->sym_types = malloc(sizeof(char) * symbol_num); for (int j = 0; j < symbol_num; j++) { nm->sym_types[j] = get_64_type(nm, j); nm->sym_names[j] = get_64_name(nm, j); nm->ordered_sym_ids[j] = j; } if (nm->opts.p == 0) create_64_order_array(nm, symbol_num); print_64_symtab(nm); free(nm->sym_names); free(nm->sym_types); free(nm->ordered_sym_ids); return (i); } nm->symtab = NULL; nm->symtab_end = NULL; nm->sym_names = NULL; nm->ordered_sym_ids = NULL; } return (0); } int ft_nm64(char *filename, int filesize, char *file, t_elf_opts opts) { t_elf64 nm; nm.file = filename; nm.size = filesize; nm.ptr = file; nm.opts = opts; nm.ehdr = (Elf64_Ehdr *)nm.ptr; nm.shdr = (Elf64_Shdr *)(nm.ptr + nm.ehdr->e_shoff); nm.name = malloc(nm.ehdr->e_shnum * sizeof(char *)); if (file[EI_DATA] != ET_REL && nm.ehdr->e_entry == 0) return -1; if (nm.ehdr->e_shnum == 0) return -2; if (nm.ehdr->e_shoff + nm.ehdr->e_shnum * nm.ehdr->e_shentsize > nm.size) return -3; for (int i = 0; i < nm.ehdr->e_shnum; i++) nm.name[i] = &nm.string_table[nm.shdr[i].sh_name]; return parse_64_symtab(&nm) ? 0 : -2; }