You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.9 KiB
148 lines
5.9 KiB
2 years ago
|
#include "ft_nm.h"
|
||
|
|
||
|
int is_32_section_init(t_elf32 *nm, int i) {
|
||
|
for (Elf32_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_32_name(t_elf32 *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_32_type(t_elf32 *nm, int i) {
|
||
|
Elf32_Ehdr *ehdr = nm->ehdr;
|
||
|
Elf32_Sym sym = nm->symtab[i];
|
||
|
uint32_t bind = ELF32_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 "[ELF32_ST_TYPE(sym.st_info)];
|
||
|
if (ret == 'N') {
|
||
|
if (bind == STB_WEAK) return 'W';
|
||
|
if (is_32_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 {
|
||
|
Elf32_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_32_order_array(t_elf32 *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_32_name(nm, left);
|
||
|
char *r = get_32_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_32_symtab(t_elf32 *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("%8c", ' ');
|
||
|
else ft_printf("%08x", nm->symtab[id].st_value);
|
||
|
ft_printf(" %c", type);
|
||
|
char *name = get_32_name(nm, id);
|
||
|
ft_printf(" %s\n", name);
|
||
|
}
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int parse_32_symtab(t_elf32 *nm) {
|
||
|
Elf32_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 = (Elf32_Sym *)(nm->ptr + nm->shdr[i].sh_offset);
|
||
|
nm->symtab_end = nm->symtab + (nm->shdr[i].sh_size / sizeof(Elf32_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_32_type(nm, j);
|
||
|
nm->sym_names[j] = get_32_name(nm, j);
|
||
|
nm->ordered_sym_ids[j] = j;
|
||
|
}
|
||
|
if (nm->opts.p == 0) create_32_order_array(nm, symbol_num);
|
||
|
print_32_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_nm32(char *filename, int filesize, char *file, t_elf_opts opts) {
|
||
|
t_elf32 nm;
|
||
|
|
||
|
nm.file = filename;
|
||
|
nm.size = filesize;
|
||
|
nm.ptr = file;
|
||
|
nm.opts = opts;
|
||
|
nm.ehdr = (Elf32_Ehdr *)nm.ptr;
|
||
|
nm.shdr = (Elf32_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_32_symtab(&nm) ? 0 : -2;
|
||
|
}
|