/* elf.c * This file is part of decomp - a disassembler. Here are the routines * for manipulating ELF32/64 files. * * Copyright (C) 2002 Jonathan duSaint * * Started on 30 January 2002. */ #include #include #include #include "decomp.h" /* give these forward references */ int elf_unneeded_section (const char *name); char *elf_get_flags (unsigned long flags); enum symbol_type elf_get_symbol_type (struct file_info *fi,unsigned char info); /* I finally found a problem with C - the lack of dynamic types forces me to separate elf32/elf64 handling into two virtually identical largish functions. Of course, that sort of thing would cause a lot of bloat in the language itself, so I guess I'll live. */ /* ELF32 section */ /* elf32_read_file_header * Reads the ELF32 file header in the file pointed to by FP and * populates FILE_HEADER with the information. */ void elf32_read_file_header (Elf32_Ehdr *file_header, FILE *fp) { d_read (file_header->e_ident, sizeof (char), EI_NIDENT, fp, 1); d_read (&file_header->e_type, sizeof (Elf32_Half), 1, fp, 0); d_read (&file_header->e_machine, sizeof (Elf32_Half), 1, fp, 0); d_read (&file_header->e_version, sizeof (Elf32_Word), 1, fp, 0); d_read (&file_header->e_entry, sizeof (Elf32_Addr), 1, fp, 0); d_read (&file_header->e_phoff, sizeof (Elf32_Off), 1, fp, 0); d_read (&file_header->e_shoff, sizeof (Elf32_Off), 1, fp, 0); d_read (&file_header->e_flags, sizeof (Elf32_Word), 1, fp, 0); d_read (&file_header->e_ehsize, sizeof (Elf32_Half), 1, fp, 0); d_read (&file_header->e_phentsize, sizeof (Elf32_Half), 1, fp, 0); d_read (&file_header->e_phnum, sizeof (Elf32_Half), 1, fp, 0); d_read (&file_header->e_shentsize, sizeof (Elf32_Half), 1, fp, 0); d_read (&file_header->e_shnum, sizeof (Elf32_Half), 1, fp, 0); d_read (&file_header->e_shstrndx, sizeof (Elf32_Half), 1, fp, 0); } /* elf32_read_section_header * Reads and ELF32 section header which is pointed to by FP and * uses the information to populate SH. */ void elf32_read_section_header (Elf32_Shdr *sh, FILE *fp) { d_read (&sh->sh_name, sizeof (Elf32_Word), 1, fp, 0); d_read (&sh->sh_type, sizeof (Elf32_Word), 1, fp, 0); d_read (&sh->sh_flags, sizeof (Elf32_Word), 1, fp, 0); d_read (&sh->sh_addr, sizeof (Elf32_Addr), 1, fp, 0); d_read (&sh->sh_offset, sizeof (Elf32_Off), 1, fp, 0); d_read (&sh->sh_size, sizeof (Elf32_Word), 1, fp, 0); d_read (&sh->sh_link, sizeof (Elf32_Word), 1, fp, 0); d_read (&sh->sh_info, sizeof (Elf32_Word), 1, fp, 0); d_read (&sh->sh_addralign, sizeof (Elf32_Word), 1, fp, 0); d_read (&sh->sh_entsize, sizeof (Elf32_Word), 1, fp, 0); } /* elf32_get_file_info * Get the information from an ELF32 file and populate FI with the * information. */ void elf32_get_file_info (struct file_info *fi) { int k, n_data = 0, n_code = 0; char *shstrtab; Elf32_Ehdr fh; Elf32_Shdr sh; elf32_read_file_header (&fh, fi->fp); fi->bit_size = BS_32; fi->load_address = fh.e_entry; fi->endian = ((fh.e_ident[EI_DATA] == ELFDATA2LSB) ? BO_LITTLE_ENDIAN : BO_BIG_ENDIAN); /* do some sanity checks on the header */ if (strncmp (fh.e_ident, ELFMAG, SELFMAG) /* magic - \x7fELF */ || (fh.e_ident[EI_VERSION] != EV_CURRENT) /* current version */ || (fh.e_type != ET_REL /* object file */ && fh.e_type != ET_EXEC /* or executable */ && fh.e_type != ET_DYN) /* or library */ || (fh.e_version != EV_CURRENT)) /* current version */ error_out (ERR_INVALID_FILE); /* only handle IA-32 for now... */ if (fh.e_machine == EM_386) fi->arch = MT_IA32; else fi->arch = MT_UNK; /* read the section header string table index */ fseek (fi->fp, fh.e_shoff + fh.e_shstrndx * fh.e_shentsize, SEEK_SET); elf32_read_section_header (&sh, fi->fp); shstrtab = xmalloc (sh.sh_size); fseek (fi->fp, sh.sh_offset, SEEK_SET); /* and then read the section header string table */ fread (shstrtab, sizeof (char), sh.sh_size, fi->fp); /* read the sections and put them in their proper places */ fi->data_sections = xmalloc ((fh.e_shnum + 1) * sizeof (struct section_info *)); fi->code_sections = xmalloc ((fh.e_shnum + 1) * sizeof (struct section_info *)); /* position at start of section headers */ fseek (fi->fp, fh.e_shoff, SEEK_SET); for (k = 0; k < fh.e_shnum; k++) { char *section_name = NULL; /* read the header */ elf32_read_section_header (&sh, fi->fp); /* find the name */ section_name = xmalloc (strlen (shstrtab + sh.sh_name) + 1); strcpy (section_name, shstrtab + sh.sh_name); if (debug) printf ("read %s, idx %#x, offset %#x\n", section_name, k, sh.sh_offset); /* parse the header into the proper place */ switch (sh.sh_type) { case SHT_PROGBITS: if (sh.sh_flags & SHF_EXECINSTR) /* code section */ { if (elf_unneeded_section (section_name)) { xfree (section_name); continue; } fi->code_sections[n_code] = alloc_section_info (section_name, CODE_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size); n_code++; } else /* data section */ { if (elf_unneeded_section (section_name)) { xfree (section_name); continue; } fi->data_sections[n_data] = alloc_section_info (section_name, DATA_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size); n_data++; } break; case SHT_SYMTAB: /* symbol table */ fi->symtab = alloc_section_info (section_name, OTHER_SECTION, sh.sh_offset, sh.sh_size, sh.sh_entsize, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); break; case SHT_STRTAB: /* string table */ if (elf_unneeded_section (section_name)) { xfree (section_name); continue; } if (!strcmp (section_name, ".strtab")) /* the string table */ { fi->strtab = alloc_section_info (section_name, STRING_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); } else /* another table with strings (??) */ { fi->data_sections[n_data] = alloc_section_info (section_name, STRING_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size); n_data++; } break; /* I don't think that these two are needed, but they're here as a reminder, just in case. case SHT_RELA: case SHT_HASH: */ default: xfree (section_name); continue; } } xfree (shstrtab); } /* elf32_read_symbol * Read an Elf32_Sym and store it into SYM. */ void elf32_read_symbol (Elf32_Sym *sym, FILE *fp) { d_read (&sym->st_name, sizeof (Elf32_Word), 1, fp, 0); d_read (&sym->st_value, sizeof (Elf32_Addr), 1, fp, 0); d_read (&sym->st_size, sizeof (Elf32_Word), 1, fp, 0); d_read (&sym->st_info, sizeof (unsigned char), 1, fp, 0); d_read (&sym->st_other, sizeof (unsigned char), 1, fp, 0); d_read (&sym->st_shndx, sizeof (Elf32_Section), 1, fp, 0); } /* elf_32_get_next_symbol * Read the next symbol from the object file and return it as a struct symtab. */ struct symtab * elf32_get_next_symbol (struct file_info *fi, char *strtab) { unsigned long unnamed_index = 0; char *tmp; struct symtab *sym; Elf32_Sym symbol; elf32_read_symbol (&symbol, fi->fp); /* ignore symbols with no section */ /* if (symbol.st_shndx == 0xfff1) continue; */ /* ignore unknown symbol types */ /*if (get_symbol_type (symbol.st_info) == UNKNOWN_SYMBOL) continue;*/ /* ignore null-named symbols */ /*if (!strlen (strtab + symbol.st_name)) continue;*/ /* if this symbol references a section or a file, ignore */ if (ELF32_ST_TYPE (symbol.st_info) == STT_SECTION || ELF32_ST_TYPE (symbol.st_info) == STT_FILE) return NULL; if (symbol.st_value == 0) return NULL; sym = xmalloc (sizeof (struct symtab)); /* if a symbol has no name, make up a (sorta) random name */ if (!strlen (strtab + symbol.st_name)) { char *tmp_name; tmp_name = xmalloc (16); snprintf (tmp_name, 16, "sym_%ld", unnamed_index++); sym->name = xmalloc (strlen (tmp_name) + 1); strcpy (sym->name, tmp_name); xfree (tmp_name); } else /* symbol has a name */ { sym->name = xmalloc (strlen (strtab + symbol.st_name) + 1); strcpy (sym->name, strtab + symbol.st_name); } sym->address = symbol.st_value; sym->size = symbol.st_size; sym->idx = symbol.st_shndx; sym->type = elf_get_symbol_type (fi, symbol.st_info); if (debug) printf ("%#lx:%s: size %#lx, info %#02x, other %#02x, idx %#x\n", (unsigned long)symbol.st_value, sym->name, (unsigned long)symbol.st_size, symbol.st_info, symbol.st_other, symbol.st_shndx); /* if (debug) */ /* printf ("%s: %#lx, %#lx, %#lx, %d\n", sym->name, sym->address, */ /* sym->size, sym->section_index, sym->type); */ /* check for @@foo at the end of a symbol - if it is there, strip it */ if ((tmp = strchr (sym->name, '@')) != NULL) *tmp = '\0'; return sym; } /* ELF64 section */ /* elf64_read_file_header * Reads the ELF64 file header in the file pointed to by FP and * populates FILE_HEADER with the information. */ void elf64_read_file_header (Elf64_Ehdr *file_header, FILE *fp) { d_read (file_header->e_ident, sizeof (char), EI_NIDENT, fp, 1); d_read (&file_header->e_type, sizeof (Elf64_Half), 1, fp, 0); d_read (&file_header->e_machine, sizeof (Elf64_Half), 1, fp, 0); d_read (&file_header->e_version, sizeof (Elf64_Word), 1, fp, 0); d_read (&file_header->e_entry, sizeof (Elf64_Addr), 1, fp, 0); d_read (&file_header->e_phoff, sizeof (Elf64_Off), 1, fp, 0); d_read (&file_header->e_shoff, sizeof (Elf64_Off), 1, fp, 0); d_read (&file_header->e_flags, sizeof (Elf64_Word), 1, fp, 0); d_read (&file_header->e_ehsize, sizeof (Elf64_Half), 1, fp, 0); d_read (&file_header->e_phentsize, sizeof (Elf64_Half), 1, fp, 0); d_read (&file_header->e_phnum, sizeof (Elf64_Half), 1, fp, 0); d_read (&file_header->e_shentsize, sizeof (Elf64_Half), 1, fp, 0); d_read (&file_header->e_shnum, sizeof (Elf64_Half), 1, fp, 0); d_read (&file_header->e_shstrndx, sizeof (Elf64_Half), 1, fp, 0); } /* elf64_read_section_header * Reads and ELF64 section header which is pointed to by FP and * uses the information to populate SH. */ void elf64_read_section_header (Elf64_Shdr *sh, FILE *fp) { d_read (&sh->sh_name, sizeof (Elf64_Word), 1, fp, 0); d_read (&sh->sh_type, sizeof (Elf64_Word), 1, fp, 0); d_read (&sh->sh_flags, sizeof (Elf64_Xword), 1, fp, 0); d_read (&sh->sh_addr, sizeof (Elf64_Addr), 1, fp, 0); d_read (&sh->sh_offset, sizeof (Elf64_Off), 1, fp, 0); d_read (&sh->sh_size, sizeof (Elf64_Xword), 1, fp, 0); d_read (&sh->sh_link, sizeof (Elf64_Word), 1, fp, 0); d_read (&sh->sh_info, sizeof (Elf64_Word), 1, fp, 0); d_read (&sh->sh_addralign, sizeof (Elf64_Xword), 1, fp, 0); d_read (&sh->sh_entsize, sizeof (Elf64_Xword), 1, fp, 0); } /* elf64_get_file_info * Get the information from an ELF64 file and populate FI with the * information. */ void elf64_get_file_info (struct file_info *fi) { int k, n_data = 0, n_code = 0; char *shstrtab; Elf64_Ehdr fh; Elf64_Shdr sh; elf64_read_file_header (&fh, fi->fp); fi->bit_size = BS_64; fi->load_address = fh.e_entry; fi->endian = ((fh.e_ident[EI_DATA] == ELFDATA2LSB) ? BO_LITTLE_ENDIAN : BO_BIG_ENDIAN); /* do some sanity checks on the header */ if (strncmp (fh.e_ident, ELFMAG, SELFMAG) /* magic - \x7fELF */ || (fh.e_ident[EI_VERSION] != EV_CURRENT) /* current version */ || (fh.e_type != ET_REL /* object file */ && fh.e_type != ET_EXEC /* or executable */ && fh.e_type != ET_DYN) /* or library */ || (fh.e_version != EV_CURRENT)) /* current version */ error_out (ERR_INVALID_FILE); /* only handle IA-32 for now... */ switch (fh.e_machine) { case EM_386: fi->arch = MT_IA32; break; default: fi->arch = MT_UNK; } /* read the section header string table index */ fseek (fi->fp, fh.e_shoff + fh.e_shstrndx * fh.e_shentsize, SEEK_SET); elf64_read_section_header (&sh, fi->fp); shstrtab = xmalloc (sh.sh_size); fseek (fi->fp, sh.sh_offset, SEEK_SET); /* and then read the section header string table */ fread (shstrtab, sizeof (char), sh.sh_size, fi->fp); /* read the sections and put them in their proper places */ fi->data_sections = xmalloc ((fh.e_shnum + 1) * sizeof (struct section_info *)); fi->code_sections = xmalloc ((fh.e_shnum + 1) * sizeof (struct section_info *)); /* position at start of section headers */ fseek (fi->fp, fh.e_shoff, SEEK_SET); for (k = 0; k < fh.e_shnum; k++) { char *section_name = NULL; /* read the header */ elf64_read_section_header (&sh, fi->fp); /* find the name */ section_name = xmalloc (strlen (shstrtab + sh.sh_name) + 1); strcpy (section_name, shstrtab + sh.sh_name); if (debug) printf ("read %s, idx %#x, offset %#llx\n", section_name, k, sh.sh_offset); /* parse the header into the proper place */ switch (sh.sh_type) { case SHT_PROGBITS: if (sh.sh_flags & SHF_EXECINSTR) /* code section */ { if (elf_unneeded_section (section_name)) { xfree (section_name); continue; } fi->code_sections[n_code] = alloc_section_info (section_name, CODE_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size); n_code++; } else /* data section */ { if (elf_unneeded_section (section_name)) { xfree (section_name); continue; } fi->data_sections[n_data] = alloc_section_info (section_name, DATA_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size); n_data++; } break; case SHT_SYMTAB: /* symbol table */ fi->symtab = alloc_section_info (section_name, OTHER_SECTION, sh.sh_offset, sh.sh_size, sh.sh_entsize, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); break; case SHT_STRTAB: /* string table */ if (elf_unneeded_section (section_name)) { xfree (section_name); continue; } if (!strcmp (section_name, ".strtab")) /* the string table */ { fi->strtab = alloc_section_info (section_name, STRING_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); } else /* another table with strings (??) */ { fi->data_sections[n_data] = alloc_section_info (section_name, STRING_SECTION, sh.sh_offset, sh.sh_size, 0, k, sh.sh_addr, NULL, elf_get_flags (sh.sh_flags), sh.sh_addralign); put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size); n_data++; } break; /* I don't think that these two are needed, but they're here as a reminder, just in case. case SHT_RELA: case SHT_HASH: */ default: xfree (section_name); continue; } } xfree (shstrtab); } /* elf64_read_symbol * Read an Elf64_Sym and store it into SYM. */ void elf64_read_symbol (Elf64_Sym *sym, FILE *fp) { d_read (&sym->st_name, sizeof (Elf64_Word), 1, fp, 0); d_read (&sym->st_info, sizeof (unsigned char), 1, fp, 0); d_read (&sym->st_other, sizeof (unsigned char), 1, fp, 0); d_read (&sym->st_shndx, sizeof (Elf64_Section), 1, fp, 0); d_read (&sym->st_value, sizeof (Elf64_Addr), 1, fp, 0); d_read (&sym->st_size, sizeof (Elf64_Xword), 1, fp, 0); } /* elf64_get_next_symbol * Read the next symbol from the object file and return it as a struct symtab. */ struct symtab * elf64_get_next_symbol (struct file_info *fi, char *strtab) { unsigned long unnamed_index = 0; char *tmp; struct symtab *sym; Elf64_Sym symbol; elf64_read_symbol (&symbol, fi->fp); /* ignore symbols with no section */ /* if (symbol.st_shndx == 0xfff1) continue; */ /* ignore unknown symbol types */ /*if (get_symbol_type (symbol.st_info) == UNKNOWN_SYMBOL) continue;*/ /* ignore null-named symbols */ /*if (!strlen (strtab + symbol.st_name)) continue;*/ /* if this symbol references a section or a file, ignore */ if (ELF64_ST_TYPE (symbol.st_info) == STT_SECTION || ELF64_ST_TYPE (symbol.st_info) == STT_FILE) return NULL; if (symbol.st_value == 0) return NULL; sym = xmalloc (sizeof (struct symtab)); /* if a symbol has no name, make up a (sorta) random name */ if (!strlen (strtab + symbol.st_name)) { char *tmp_name; tmp_name = xmalloc (16); snprintf (tmp_name, 16, "sym_%ld", unnamed_index++); sym->name = xmalloc (strlen (tmp_name) + 1); strcpy (sym->name, tmp_name); xfree (tmp_name); } else /* symbol has a name */ { sym->name = xmalloc (strlen (strtab + symbol.st_name) + 1); strcpy (sym->name, strtab + symbol.st_name); } sym->address = symbol.st_value; sym->size = symbol.st_size; sym->idx = symbol.st_shndx; sym->type = elf_get_symbol_type (fi, symbol.st_info); if (debug) printf ("%#lx:%s: size %#lx, info %#02x, other %#02x, idx %#x\n", (unsigned long)symbol.st_value, sym->name, (unsigned long)symbol.st_size, symbol.st_info, symbol.st_other, symbol.st_shndx); /* if (debug) */ /* printf ("%s: %#lx, %#lx, %#lx, %d\n", sym->name, sym->address, */ /* sym->size, sym->section_index, sym->type); */ /* check for @@foo at the end of a symbol - if it is there, strip it */ if ((tmp = strchr (sym->name, '@')) != NULL) *tmp = '\0'; return sym; } /* Generic ELF section */ /* elf_unneeded_section * If NAME matches one of the names of the unneeded data sections, * then 1 is returned, otherwise 0 is returned. */ int elf_unneeded_section (const char *name) { int k = -1; char *unneeded[] = { ".interp", ".plt", ".stab", ".comment", ".sbss", ".shstrtab", ".stabstr", ".got", ".dtors", ".dynstr", ".ctors", ".eh_frame", NULL }; while (unneeded[++k] != NULL) if (!strcmp (name, unneeded[k])) return 1; if (!strncmp (name, ".debug", 6)) return 1; return 0; } char *flag_str_array[] = { "", /* no flags */ ", \"w\"", /* writeable */ ", \"a\"", /* occupies memory during execution */ ", \"aw\"", /* writeable and occupies memory during execution */ ", \"x\"", /* executable */ ", \"xw\"", /* executable and writeable */ ", \"xa\"", /* executable and occupies memory during execution */ ", \"xaw\"", /* executable, occupies memory during execution and writeable */ }; /* elf_get_flags * Translate the flags from the section header into textual flags that the * assembler will understand. */ char * elf_get_flags (unsigned long flags) { int index; index = (flags & SHF_WRITE) + (flags & SHF_ALLOC) + (flags & SHF_EXECINSTR); if (index > 7) index = 0; return flag_str_array[index]; } /* elf_get_file_info * Get the information from the object file and populate FI. */ void elf_get_file_info (struct file_info *fi) { int k; char ident_buffer[EI_NIDENT]; fi->symtab = NULL; fi->strtab = NULL; /* read in the first EI_NIDENT chars in to find out if this is ELF32 or ELF64 */ fseek (fi->fp, 0, SEEK_SET); fread (ident_buffer, sizeof (char), EI_NIDENT, fi->fp); /* reset the file pointer */ fseek (fi->fp, 0, SEEK_SET); /* find the target byte order */ if (ident_buffer[EI_DATA] == ELFDATA2LSB) /* little endian */ target_endian = BO_LITTLE_ENDIAN; else /* big endian */ target_endian = BO_BIG_ENDIAN; if (ident_buffer[EI_CLASS] == ELFCLASS32) elf32_get_file_info (fi); else elf64_get_file_info (fi); /* print debug info */ if (debug) { k = -1; printf ("data:\n"); while (fi->data_sections[++k]) { printf (" %s (%#lx), %d, %#lx, %#lx, %#lx\n", fi->data_sections[k]->section_name, fi->data_sections[k]->section_index, fi->data_sections[k]->section_type, fi->data_sections[k]->section_offset, fi->data_sections[k]->section_size, fi->data_sections[k]->load_address); } k = -1; printf ("code:\n"); while (fi->code_sections[++k]) { printf (" %s (%#lx), %d, %#lx, %#lx, %#lx\n", fi->code_sections[k]->section_name, fi->code_sections[k]->section_index, fi->code_sections[k]->section_type, fi->code_sections[k]->section_offset, fi->code_sections[k]->section_size, fi->code_sections[k]->load_address); } if (fi->symtab != NULL) printf ("symtab:\n %s (%#lx), %d, %#lx, %#lx, %#lx\n", fi->symtab->section_name, fi->symtab->section_index, fi->symtab->section_type, fi->symtab->section_offset, fi->symtab->section_size, fi->symtab->load_address); if (fi->strtab != NULL) printf ("strtab:\n %s (%#lx), %d, %#lx, %#lx, %#lx\n", fi->strtab->section_name, fi->strtab->section_index, fi->strtab->section_type, fi->strtab->section_offset, fi->strtab->section_size, fi->strtab->load_address); } } /* elf_read_strtab * Read the string table from the object file. */ char * elf_read_strtab (struct file_info *fi) { char *strtab; if (fi->strtab == NULL) return (NULL); fseek (fi->fp, fi->strtab->section_offset, SEEK_SET); strtab = xmalloc (fi->strtab->section_size); d_read (strtab, sizeof (char), fi->strtab->section_size, fi->fp, 1); return strtab; } /* elf_get_symbol_type * Translate a symbol's type into the internal format. */ enum symbol_type elf_get_symbol_type (struct file_info *fi, unsigned char info) { unsigned char bind, type; enum symbol_type stype = UNKNOWN_SYMBOL; if (fi->bit_size == BS_32) { bind = ELF32_ST_BIND (info); type = ELF32_ST_TYPE (info); } else { bind = ELF64_ST_BIND (info); type = ELF64_ST_TYPE (info); } if (bind == STB_LOCAL && type == STT_OBJECT) stype = LOCAL_DATA; else if (bind == STB_LOCAL && type == STT_FUNC) stype = LOCAL_FUNCTION; else if (bind == STB_GLOBAL && type == STT_OBJECT) stype = GLOBAL_DATA; else if (bind == STB_GLOBAL && type == STT_FUNC) stype = GLOBAL_FUNCTION; else if (bind == STB_GLOBAL) stype = GLOBAL_UNKNOWN; else if (bind == STB_LOCAL) stype = LOCAL_UNKNOWN; else if (type == STT_OBJECT) stype = UNKNOWN_DATA; else if (type == STT_FUNC) stype = UNKNOWN_FUNCTION; else stype = UNKNOWN_SYMBOL; return (stype); } /* elf_get_next_symbol * Read the next symbol from the object file and return it as a struct symtab. */ struct symtab * elf_get_next_symbol (struct file_info *fi, char *strtab) { if (fi->bit_size == BS_32) return elf32_get_next_symbol (fi, strtab); else return elf64_get_next_symbol (fi, strtab); }