diff --git a/readelf/gen-test1.c b/readelf/gen-test1.c index bc1e161..5a4665c 100644 --- a/readelf/gen-test1.c +++ b/readelf/gen-test1.c @@ -9,10 +9,222 @@ #include "pdp10-elf36.h" #include "pdp10-stdio.h" +/* + * Layout (mirroring a minimal x86 ELF32 file with empty .data and .bss omitted): + * + * 0: + * - ELF Header (52 nonets, 13 words) + * 52: + * - Contents of .text (12 nonets, 3 words) + * 64: + * - Contents of .shstrtab: "", ".symtab", ".strtab", ".shstrtab", ".text" + * (33 nonets padded to 36 nonets, 9 words) + * 100: + * - Section headers: + * + [0] empty + * + [1] .text + * + [2] .shstrtab + * + [3] .symtab + * + [4] .strtab + * (200 (5 * 40) nonets, 50 words) + * 300: + * - Contents of .symtab: (undef), function global .text "start" + * (32 (2 * 16) nonets, 8 words) + * 332: + * - Contents of .strtab: "", "start" + * (7 nonets padded to 8 nonets, 2 words) + * 340: + * - end of file + */ + +static int write_elf(PDP10_FILE *pdp10fp) +{ + enum { + /* size of start and .text */ + TEXT_SIZE_start = 12, + TEXT_SIZE = TEXT_SIZE_start, + + /* .shstrtab indices and size */ + SHSTRTAB_IX_symtab = 1, + SHSTRTAB_IX_strtab = 9, + SHSTRTAB_IX_shstrtab = 17, + SHSTRTAB_IX_text = 27, + SHSTRTAB_SIZE = 36, + + /* .strtab indices and size */ + STRTAB_IX_start = 1, + STRTAB_SIZE = 8, + + /* section header indices and size */ + SHTAB_IX_text = 1, + SHTAB_IX_shstrtab = 2, + SHTAB_IX_strtab = 3, + SHTAB_NR = 5, + + /* .symtab indices and size */ + SYMTAB_IX_LAST_LOCAL = 0, + SYMTAB_NR = 2, + SYMTAB_SIZE = SYMTAB_NR * ELF36_SYM_SIZEOF, + + /* file offsets */ + FILE_OFFSET_TEXT = ELF36_EHDR_SIZEOF, + FILE_OFFSET_SHSTRTAB = FILE_OFFSET_TEXT + TEXT_SIZE, + FILE_OFFSET_SHTAB = FILE_OFFSET_SHSTRTAB + SHSTRTAB_SIZE, + FILE_OFFSET_SYMTAB = FILE_OFFSET_SHTAB + (SHTAB_NR * ELF36_SHDR_SIZEOF), + FILE_OFFSET_STRTAB = FILE_OFFSET_SYMTAB + SYMTAB_SIZE, + }; + static const pdp10_uint36_t text[3] = { + /* start: */ + PDP10_UINT36_C(0201040000000), /* MOVEI 1,0 ; exit status = 0 */ + PDP10_UINT36_C(0104000000136), /* JSYS 0136 ; SYS_exit_group */ + PDP10_UINT36_C(0254000000000), /* HALT */ + }; + static const pdp10_uint9_t shstrtab[36] = { + '\0', '.', 's', 'y', 'm', 't', 'a', 'b', '\0', '.', 's', 't', 'r', 't', 'a', 'b', + '\0', '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0', '.', 't', 'e', 'x', 't', + '\0', '\0', '\0', '\0', + }; + static const pdp10_uint9_t strtab[8] = { + '\0', 's', 't', 'a', 'r', 't', '\0', '\0' + }; + static const Elf36_Shdr shtab[5] = { + [0] = { /* (empty) */ + .sh_name = 0, + .sh_type = SHT_NULL, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = 0, + .sh_size = 0, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 0, + .sh_entsize = 0, + }, + [1] = { /* .text */ + .sh_name = SHSTRTAB_IX_text, + .sh_type = SHT_PROGBITS, + .sh_flags = SHF_ALLOC | SHF_EXECINSTR, + .sh_addr = 0, + .sh_offset = FILE_OFFSET_TEXT, + .sh_size = TEXT_SIZE, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 4, + .sh_entsize = 0, + }, + [2] = { /* .shstrtab */ + .sh_name = SHSTRTAB_IX_shstrtab, + .sh_type = SHT_STRTAB, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = FILE_OFFSET_SHSTRTAB, + .sh_size = SHSTRTAB_SIZE, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 1, + .sh_entsize = 0, + }, + [3] = { /* .strtab */ + .sh_name = SHSTRTAB_IX_strtab, + .sh_type = SHT_STRTAB, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = FILE_OFFSET_STRTAB, + .sh_size = STRTAB_SIZE, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 1, + .sh_entsize = 0, + }, + [4] = { /* .symtab */ + .sh_name = SHSTRTAB_IX_symtab, + .sh_type = SHT_SYMTAB, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = FILE_OFFSET_SYMTAB, + .sh_size = SYMTAB_SIZE, + .sh_link = SHTAB_IX_strtab, + .sh_info = SYMTAB_IX_LAST_LOCAL + 1, + .sh_addralign = 4, + .sh_entsize = ELF36_SYM_SIZEOF, + }, + }; + static const Elf36_Sym symtab[2] = { + [0] = { /* (empty) */ + .st_name = 0, + .st_value = 0, + .st_size = 0, + .st_info = ELF36_ST_INFO(STB_LOCAL, STT_NOTYPE), + .st_other = 0, + .st_shndx = SHN_UNDEF, + }, + [1] = { /* start */ + .st_name = STRTAB_IX_start, + .st_value = 0, + .st_size = TEXT_SIZE_start, + .st_info = ELF36_ST_INFO(STB_GLOBAL, STT_FUNC), + .st_other = STV_DEFAULT, + .st_shndx = SHTAB_IX_text, + }, + }; + static const Elf36_Ehdr ehdr = { + .e_wident[0] = (((pdp10_uint36_t)ELFMAG0 << 28) + | (ELFMAG1 << 20) + | (ELFMAG2 << 12) + | (ELFMAG3 << 4) + | (ELFCLASS36 >> 4)), + .e_wident[1] = (((pdp10_uint36_t)(ELFCLASS36 & 0x0f) << 32) + | (ELFDATA2MSB << 24) + | (EV_CURRENT << 16) + | (ELFOSABI_NONE << 8) + | 0), /* EI_ABIVERSION */ + .e_wident[2] = 0, + .e_wident[3] = 0, + .e_type = ET_REL, + .e_machine = EM_PDP10, + .e_version = EV_CURRENT, + .e_entry = 0, + .e_phoff = 0, + .e_shoff = FILE_OFFSET_SHTAB, + .e_flags = 0, + .e_ehsize = ELF36_EHDR_SIZEOF, + .e_phentsize = 0, + .e_phnum = 0, + .e_shentsize = ELF36_SHDR_SIZEOF, + .e_shnum = SHTAB_NR, + .e_shstrndx = SHTAB_IX_shstrtab, + }; + unsigned int i; + + if (pdp10_elf36_write_ehdr(pdp10fp, &ehdr) < 0) + return 1; + + for (i = 0; i < 3; ++i) + if (pdp10_elf36_write_uint36(pdp10fp, text[i]) < 0) + return -1; + + for (i = 0; i < 36; ++i) + if (pdp10_elf36_write_uint9(pdp10fp, shstrtab[i]) < 0) + return -1; + + for (i = 0; i < 5; ++i) + if (pdp10_elf36_write_shdr(pdp10fp, &shtab[i]) < 0) + return -1; + + for (i = 0; i < 2; ++i) + if (pdp10_elf36_write_sym(pdp10fp, &symtab[i]) < 0) + return -1; + + for (i = 0; i < 8; ++i) + if (pdp10_elf36_write_uint9(pdp10fp, strtab[i]) < 0) + return -1; + + return 0; +} + int main(void) { PDP10_FILE *pdp10fp; - Elf36_Ehdr ehdr; pdp10fp = pdp10_fopen("test1.o", "wb"); if (!pdp10fp) { @@ -20,38 +232,11 @@ int main(void) return 1; } - ehdr.e_wident[0] = - (((pdp10_uint36_t)ELFMAG0 << 28) - | (ELFMAG1 << 20) - | (ELFMAG2 << 12) - | (ELFMAG3 << 4) - | (ELFCLASS36 >> 4)); - ehdr.e_wident[1] = - (((pdp10_uint36_t)(ELFCLASS36 & 0x0f) << 32) - | (ELFDATA2MSB << 24) - | (EV_CURRENT << 16) - | (ELFOSABI_NONE << 8) - | 0); /* EI_ABIVERSION */ - ehdr.e_wident[2] = 0; - ehdr.e_wident[3] = 0; - ehdr.e_type = ET_REL; - ehdr.e_machine = EM_PDP10; - ehdr.e_version = EV_CURRENT; - ehdr.e_entry = 0; - ehdr.e_phoff = 0; - ehdr.e_shoff = 0; - ehdr.e_flags = 0; - ehdr.e_ehsize = ELF36_EHDR_SIZEOF; - ehdr.e_phentsize = 0; - ehdr.e_phnum = 0; - ehdr.e_shentsize = 0; - ehdr.e_shnum = 0; - ehdr.e_shstrndx = SHN_UNDEF; - - if (pdp10_elf36_write_ehdr(pdp10fp, &ehdr) < 0) { - fprintf(stderr, "writer to write ELF header: %s\n", strerror(errno)); + if (write_elf(pdp10fp) < 0) { + fprintf(stderr, "failed to write ELF data: %s\n", strerror(errno)); return 1; } + pdp10_fclose(pdp10fp); return 0; } diff --git a/readelf/readelf.c b/readelf/readelf.c index 52868e2..098ea99 100644 --- a/readelf/readelf.c +++ b/readelf/readelf.c @@ -7,6 +7,7 @@ #include #include /* for getopt_long() */ #include +#include #include #include "pdp10-elf36.h" #include "pdp10-inttypes.h" @@ -31,93 +32,52 @@ struct options { unsigned char disassemble; /* local extension */ }; -static void ehdr_unpack_ident(const Elf36_Ehdr *ehdr, unsigned char *e_ident) +struct params { + const char *progname; + struct options opts; + + const char *filename; + PDP10_FILE *pdp10fp; + + Elf36_Ehdr ehdr; + Elf36_Shdr *shtab; + pdp10_uint36_t shnum; + pdp10_uint9_t *shstrtab; + pdp10_uint36_t shstrtablen; + + Elf36_Sym *symtab; + pdp10_uint36_t symtabndx; + pdp10_uint36_t symnum; + pdp10_uint9_t *strtab; + pdp10_uint36_t strtablen; +}; + +static void params_init(struct params *params) { - pdp10_uint36_t wident[4]; - unsigned int w, i, b; - - for (w = 0; w < 4; ++w) - wident[w] = ehdr->e_wident[w]; - - for (i = 0; i < EI_NIDENT; ++i) { - for (w = 0; w < 4; ++w) { - b = (wident[w] >> (36 - 8)) & 0xff; - if (w == 0) - e_ident[i] = b; - else - wident[w - 1] |= b; - wident[w] = (wident[w] & ((1 << (36 - 8)) - 1)) << 8; - } - } + memset(params, 0, sizeof *params); } -static int check_eident(const unsigned char *e_ident, const char *filename) +static void params_file_init(struct params *params) { - if (e_ident[EI_MAG0] != ELFMAG0 - || e_ident[EI_MAG1] != ELFMAG1 - || e_ident[EI_MAG2] != ELFMAG2 - || e_ident[EI_MAG3] != ELFMAG3 - || e_ident[EI_VERSION] != EV_CURRENT) { - fprintf(stderr, "readelf: %s: not an ELF file: wrong magic\n", filename); - return -1; - } - - if (e_ident[EI_CLASS] != ELFCLASS36) { - fprintf(stderr, "readelf: %s: not an ELF36 file: wrong class %u\n", filename, e_ident[EI_CLASS]); - return -1; - } - - if (e_ident[EI_DATA] != ELFDATA2MSB) { - fprintf(stderr, "readelf: %s: not a PDP10 ELF36 file: wrong data %u\n", filename, e_ident[EI_DATA]); - return -1; - } - - switch (e_ident[EI_OSABI]) { - case ELFOSABI_NONE: - case ELFOSABI_LINUX: - break; - default: - fprintf(stderr, "readelf: %s: not a PDP10 ELF36 file: wrong osabi %u\n", filename, e_ident[EI_OSABI]); - return -1; - } - - if (e_ident[EI_ABIVERSION] != 0) { - fprintf(stderr, "readelf: %s: not a PDP10 ELF36 file: wrong abiversion %u\n", filename, e_ident[EI_ABIVERSION]); - return -1; - } - - return 0; + params->pdp10fp = NULL; + params->shtab = NULL; + params->shnum = 0; + params->shstrtab = NULL; + params->shstrtablen = 0; + params->symtab = NULL; + params->symtabndx = 0; + params->symnum = 0; + params->strtab = NULL; + params->strtablen = 0; } -static int check_ehdr(const Elf36_Ehdr *ehdr, const char *filename) +static void params_file_fini(struct params *params) { - switch (ehdr->e_type) { - case ET_REL: - case ET_EXEC: - case ET_DYN: - case ET_CORE: - break; - default: - fprintf(stderr, "readelf: %s: not a PDP10 ELF36 file: wrong type %u\n", filename, ehdr->e_type); - return -1; - } - - if (ehdr->e_machine != EM_PDP10) { - fprintf(stderr, "readelf: %s: not a PDP10 ELF36 file: wrong machine %u\n", filename, ehdr->e_machine); - return -1; - } - - if (ehdr->e_version != EV_CURRENT) { - fprintf(stderr, "readelf: %s: not a PDP10 ELF36 file: wrong version %" PDP10_PRIu36 "\n", filename, ehdr->e_version); - return -1; - } - - if (ehdr->e_ehsize != ELF36_EHDR_SIZEOF) { - fprintf(stderr, "readelf: %s: not a PDP10 ELF36 file: wrong ehsize %u\n", filename, ehdr->e_ehsize); - return -1; - } - - return 0; + free(params->strtab); + free(params->symtab); + free(params->shstrtab); + free(params->shtab); + pdp10_fclose(params->pdp10fp); } static const char *class_name(unsigned int ei_class) @@ -189,6 +149,116 @@ static const char *machine_name(unsigned int e_machine) } } +static void ehdr_unpack_ident(const Elf36_Ehdr *ehdr, unsigned char *e_ident) +{ + pdp10_uint36_t wident[4]; + unsigned int w, i, b; + + for (w = 0; w < 4; ++w) + wident[w] = ehdr->e_wident[w]; + + for (i = 0; i < EI_NIDENT; ++i) { + for (w = 0; w < 4; ++w) { + b = (wident[w] >> (36 - 8)) & 0xff; + if (w == 0) + e_ident[i] = b; + else + wident[w - 1] |= b; + wident[w] = (wident[w] & ((1 << (36 - 8)) - 1)) << 8; + } + } +} + +static int check_eident(struct params *params, const unsigned char *e_ident) +{ + if (e_ident[EI_MAG0] != ELFMAG0 + || e_ident[EI_MAG1] != ELFMAG1 + || e_ident[EI_MAG2] != ELFMAG2 + || e_ident[EI_MAG3] != ELFMAG3) { + fprintf(stderr, "%s: %s: not an ELF file: wrong magic\n", params->progname, params->filename); + return -1; + } + + if (e_ident[EI_CLASS] != ELFCLASS36) { + fprintf(stderr, "%s: %s: not an ELF36 file: wrong class %u (%s)\n", + params->progname, params->filename, e_ident[EI_CLASS], class_name(e_ident[EI_CLASS])); + return -1; + } + + if (e_ident[EI_DATA] != ELFDATA2MSB) { + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong data %u (%s)\n", + params->progname, params->filename, e_ident[EI_DATA], data_name(e_ident[EI_DATA])); + return -1; + } + + if (e_ident[EI_VERSION] != EV_CURRENT) { + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong version %u (%s)\n", + params->progname, params->filename, e_ident[EI_VERSION], version_name(e_ident[EI_VERSION])); + return -1; + } + + switch (e_ident[EI_OSABI]) { + case ELFOSABI_NONE: + case ELFOSABI_LINUX: + break; + default: + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong osabi %u (%s)\n", + params->progname, params->filename, e_ident[EI_OSABI], osabi_name(e_ident[EI_OSABI])); + return -1; + } + + if (e_ident[EI_ABIVERSION] != 0) { + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong abiversion %u\n", + params->progname, params->filename, e_ident[EI_ABIVERSION]); + return -1; + } + + return 0; +} + +static int check_ehdr(struct params *params) +{ + Elf36_Ehdr *ehdr = ¶ms->ehdr; + + switch (ehdr->e_type) { + case ET_REL: + case ET_EXEC: + case ET_DYN: + case ET_CORE: + break; + default: + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong type %u\n", + params->progname, params->filename, ehdr->e_type); + return -1; + } + + if (ehdr->e_machine != EM_PDP10) { + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong machine %u\n", + params->progname, params->filename, ehdr->e_machine); + return -1; + } + + if (ehdr->e_version != EV_CURRENT) { + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong version %" PDP10_PRIu36 "\n", + params->progname, params->filename, ehdr->e_version); + return -1; + } + + if (ehdr->e_ehsize != ELF36_EHDR_SIZEOF) { + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong ehsize %u\n", + params->progname, params->filename, ehdr->e_ehsize); + return -1; + } + + if (ehdr->e_shoff != 0 && ehdr->e_shentsize != ELF36_SHDR_SIZEOF) { + fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong shentsize %u\n", + params->progname, params->filename, ehdr->e_shentsize); + return -1; + } + + return 0; +} + static void print_ehdr(const Elf36_Ehdr *ehdr, const unsigned char *e_ident) { unsigned int i; @@ -222,39 +292,431 @@ static void print_ehdr(const Elf36_Ehdr *ehdr, const unsigned char *e_ident) printf("\n"); } -static int do_readelf_fp(const struct options *options, PDP10_FILE *pdp10fp, const char *filename) +static const char *sh_type_name(Elf36_Word sh_type) { - Elf36_Ehdr ehdr; - unsigned char e_ident[EI_NIDENT]; + switch (sh_type) { + case SHT_NULL: + return "NULL"; + case SHT_PROGBITS: + return "PROGBITS"; + case SHT_SYMTAB: + return "SYMTAB"; + case SHT_STRTAB: + return "STRTAB"; + case SHT_RELA: + return "RELA"; + case SHT_HASH: + return "HASH"; + case SHT_DYNAMIC: + return "DYNAMIC"; + case SHT_NOTE: + return "NOTE"; + case SHT_NOBITS: + return "NOBITS"; + case SHT_REL: + return "REL"; + case SHT_SHLIB: + return "SHLIB"; + case SHT_DYNSYM: + return "DYNSYM"; + case SHT_INIT_ARRAY: + return "INIT_ARRAY"; + case SHT_FINI_ARRAY: + return "FINI_ARRAY"; + case SHT_PREINIT_ARRAY: + return "PREINIT_ARRAY"; + case SHT_GROUP: + return "GROUP"; + case SHT_SYMTAB_SHNDX: + return "SYMTAB_SHNDX"; + case SHT_GNU_INCREMENTAL_INPUTS: + return "GNU_INCREMENTAL_INPUTS"; + case SHT_GNU_ATTRIBUTES: + return "GNU_ATTRIBUTES"; + case SHT_GNU_HASH: + return "GNU_HASH"; + case SHT_GNU_LIBLIST: + return "GNU_LIBLIST"; + case SHT_GNU_verdef: + return "GNU_verdef"; + case SHT_GNU_verneed: + return "GNU_verneed"; + case SHT_GNU_versym: + return "GNU_versym"; + default: + return "?"; + } +} - if (pdp10_elf36_read_ehdr(pdp10fp, &ehdr) < 0) { - fprintf(stderr, "readelf: %s: failed to read ELF header: %s\n", filename, strerror(errno)); +static int read_strtab(struct params *params, pdp10_uint36_t i, pdp10_uint9_t **strtab_ptr, pdp10_uint36_t *strtablen_ptr, const char *kind) +{ + pdp10_uint9_t *strtab; + pdp10_uint36_t strtablen; + + if (i == 0 || i >= params->shnum) { + fprintf(stderr, "%s: %s: invalid index %" PDP10_PRIu36 " for %s string table\n", + params->progname, params->filename, i, kind); return -1; } - ehdr_unpack_ident(&ehdr, e_ident); - if (check_eident(e_ident, filename) < 0 - || check_ehdr(&ehdr, filename) < 0) + if (params->shtab[i].sh_type != SHT_STRTAB) { + fprintf(stderr, "%s: %s: %s string table at index %" PDP10_PRIu36 " has wrong type %" PDP10_PRIu36 " (%s)\n", + params->progname, params->filename, kind, i, params->shtab[i].sh_type, sh_type_name(params->shtab[i].sh_type)); + return -1; + } + *strtablen_ptr = strtablen = params->shtab[i].sh_size; + *strtab_ptr = strtab = malloc(strtablen * sizeof(pdp10_uint9_t)); + if (!strtab) { + fprintf(stderr, "%s: %s: failed to allocate %zu bytes for %s string table: %s\n", + params->progname, params->filename, strtablen * sizeof(pdp10_uint9_t), kind, strerror(errno)); + return -1; + } + if (pdp10_fseeko(params->pdp10fp, params->shtab[i].sh_offset, PDP10_SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: failed to seek to %s string table at %" PDP10_PRIu36 ": %s\n", + params->progname, params->filename, kind, params->shtab[i].sh_offset, strerror(errno)); + return -1; + } + for (i = 0; i < strtablen; ++i) + if (pdp10_elf36_read_uint9(params->pdp10fp, &strtab[i]) < 0) { + fprintf(stderr, "%s: %s: failed to read %s string table at index %" PDP10_PRIu36 ": %s\n", + params->progname, params->filename, kind, i, strerror(errno)); + return -1; + } + return 0; +} + +static int read_shtab(struct params *params) +{ + Elf36_Shdr shdr0; + pdp10_uint36_t i; + + if (params->ehdr.e_shoff == 0) + return 0; + + params->shnum = params->ehdr.e_shnum; + + if (pdp10_fseeko(params->pdp10fp, params->ehdr.e_shoff, PDP10_SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: failed to seek to section header table at %" PDP10_PRIu36 ": %s\n", + params->progname, params->filename, params->ehdr.e_shoff, strerror(errno)); + return -1; + } + if (pdp10_elf36_read_shdr(params->pdp10fp, &shdr0) < 0) { + fprintf(stderr, "%s: %s: failed to read section header index 0: %s\n", + params->progname, params->filename, strerror(errno)); + return -1; + } + if (params->shnum == 0) + params->shnum = shdr0.sh_size; + params->shtab = malloc(params->shnum * sizeof(Elf36_Shdr)); + if (!params->shtab) { + fprintf(stderr, "%s: %s: failed to allocate %zu bytes for section header table: %s\n", + params->progname, params->filename, params->shnum * sizeof(Elf36_Shdr), strerror(errno)); + return -1; + } + params->shtab[0] = shdr0; + for (i = 1; i < params->shnum; ++i) + if (pdp10_elf36_read_shdr(params->pdp10fp, ¶ms->shtab[i]) < 0) { + fprintf(stderr, "%s: %s: failed to read section header index %" PDP10_PRIu36 ": %s\n", + params->progname, params->filename, i, strerror(errno)); + return -1; + } + + i = params->ehdr.e_shstrndx; + if (i == SHN_UNDEF) + return 0; + if (i == SHN_XINDEX) + i = shdr0.sh_link; + if (read_strtab(params, i, ¶ms->shstrtab, ¶ms->shstrtablen, "section header") < 0) + return -1; + return 0; +} + +static char *sh_flags_name(Elf36_Word sh_flags, char *flagsbuf) +{ + const char flagnames[12] = "WAXxMSILOGTZ"; + char *p; + unsigned int i; + + p = flagsbuf; + if (sh_flags == 0) { + *p++ = '-'; + } else { + for (i = 0; i < 12; ++i) + if (sh_flags & (1 << i)) + *p++ = flagnames[i]; + if (sh_flags & SHF_EXCLUDE) { + sh_flags ^= SHF_EXCLUDE; + *p++ = 'E'; + } + if (sh_flags & SHF_MASKOS) + *p++ = 'o'; + if (sh_flags & SHF_MASKPROC) + *p++ = 'p'; + } + *p = '\0'; + return flagsbuf; +} + +static int print_name(struct params *params, pdp10_uint9_t *strtab, pdp10_uint36_t strtablen, pdp10_uint36_t name, int say_empty) +{ + pdp10_uint36_t i; + + if (name >= strtablen) { + fprintf(stderr, "%s: %s: name index %" PDP10_PRIu36 " is larger than the string table\n", + params->progname, params->filename, name); + return -1; + } + i = name; + while (strtab[i] != '\0') { + printf("%c", strtab[i]); + ++i; + if (i >= strtablen) { + fprintf(stderr, "%s: %s: name string at index %" PDP10_PRIu36 " is not NUL-terminated\n", + params->progname, params->filename, name); + return -1; + } + } + if (i == name && say_empty) + printf("(empty)"); + return 0; +} + +static int print_sh_name(struct params *params, pdp10_uint36_t i, int say_empty) +{ + return print_name(params, params->shstrtab, params->shstrtablen, params->shtab[i].sh_name, say_empty); +} + +static int print_shdr(struct params *params, pdp10_uint36_t i) +{ + Elf36_Shdr *shdr; + char flagsbuf[16]; + + printf(" [%" PDP10_PRIu36 "] ", i); + if (print_sh_name(params, i, 1) < 0) + return -1; + shdr = ¶ms->shtab[i]; + printf(" %" PDP10_PRIu36 " (%s) %" PDP10_PRIx36 " %" PDP10_PRIx36 " %" PDP10_PRIx36 " %" PDP10_PRIx36 + " %" PDP10_PRIx36 " (%s) %" PDP10_PRIu36 " %" PDP10_PRIu36 " %" PDP10_PRIu36 "\n", + shdr->sh_type, sh_type_name(shdr->sh_type), shdr->sh_addr, shdr->sh_offset, shdr->sh_size, shdr->sh_entsize, + shdr->sh_flags, sh_flags_name(shdr->sh_flags, flagsbuf), shdr->sh_link, shdr->sh_info, shdr->sh_addralign); + return 0; +} + +static int print_shtab(struct params *params) +{ + pdp10_uint36_t i; + + printf("Section Headers:\n"); + printf(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Aln\n"); + for (i = 0; i < params->shnum; ++i) + if (print_shdr(params, i) < 0) { + fprintf(stderr, "%s: %s: failed to print section header index %" PDP10_PRIu36 "\n", + params->progname, params->filename, i); + return -1; + } + printf("Key to Flags:\n"); + printf(" W (write), A (alloc), X (execute), M (merge), S (strings), Z (compressed)\n"); + printf(" I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\n"); + printf(" O (extra OS processing required), o (OS specific), p (processor specific)\n"); + printf("\n"); + return 0; +} + +static int read_symtab(struct params *params) +{ + pdp10_uint36_t i; + + for (i = 1; i < params->shnum; ++i) + if (params->shtab[i].sh_type == SHT_SYMTAB) + break; + + if (i >= params->shnum) + return 0; + + params->symtabndx = i; + + if (read_strtab(params, params->shtab[i].sh_link, ¶ms->strtab, ¶ms->strtablen, "symtab") < 0) return -1; - if (options->file_header) - print_ehdr(&ehdr, e_ident); + if (params->shtab[i].sh_entsize != ELF36_SYM_SIZEOF) { + fprintf(stderr, "%s: %s: bogus sh_entsize %" PDP10_PRIu36 " in symbol table section header at index %" PDP10_PRIu36 "\n", + params->progname, params->filename, params->shtab[i].sh_entsize, i); + return -1; + } + + if ((params->shtab[i].sh_size % ELF36_SYM_SIZEOF) != 0) { + fprintf(stderr, "%s: %s: bogus sh_size %" PDP10_PRIu36 " in symbol table section header at index %" PDP10_PRIu36 "\n", + params->progname, params->filename, params->shtab[i].sh_size, i); + return -1; + } + + params->symnum = params->shtab[i].sh_size / ELF36_SYM_SIZEOF; + if (params->symnum == 0) + return 0; + + params->symtab = malloc(params->symnum * sizeof(Elf36_Sym)); + if (!params->symtab) { + fprintf(stderr, "%s: %s: failed to allocate %zu bytes for symbol table: %s\n", + params->progname, params->filename, params->symnum * sizeof(Elf36_Sym), strerror(errno)); + return -1; + } + + if (pdp10_fseeko(params->pdp10fp, params->shtab[i].sh_offset, PDP10_SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: failed to seek to symbol table at %" PDP10_PRIu36 ": %s\n", + params->progname, params->filename, params->shtab[i].sh_offset, strerror(errno)); + return -1; + } + + for (i = 0; i < params->symnum; ++i) + if (pdp10_elf36_read_sym(params->pdp10fp, ¶ms->symtab[i]) < 0) { + fprintf(stderr, "%s: %s: failed to read symbol table index %" PDP10_PRIu36 ": %s\n", + params->progname, params->filename, i, strerror(errno)); + return -1; + } return 0; } -static int do_readelf(const struct options *options, const char *filename) +static int print_sym_name(struct params *params, pdp10_uint36_t i) { - PDP10_FILE *pdp10fp; - int status; + return print_name(params, params->strtab, params->strtablen, params->symtab[i].st_name, 1); +} - pdp10fp = pdp10_fopen(filename, "rb"); - if (!pdp10fp) { - fprintf(stderr, "%s: failed to open %s: %s\n", __FUNCTION__, filename, strerror(errno)); +static const char *st_type_name(unsigned int st_type) +{ + switch (st_type) { + case STT_NOTYPE: + return "NOTYPE"; + case STT_OBJECT: + return "OBJECT"; + case STT_FUNC: + return "FUNC"; + case STT_SECTION: + return "SECTION"; + case STT_FILE: + return "FILE"; + case STT_COMMON: + return "COMMON"; + case STT_TLS: + return "TLS"; + case STT_RELC: + return "RELC"; + case STT_SRELC: + return "SRELC"; + case STT_GNU_IFUNC: + return "GNU_IFUNC"; + default: + return "?"; + } +} + +static const char *st_bind_name(unsigned int st_bind) +{ + switch (st_bind) { + case STB_LOCAL: + return "LOCAL"; + case STB_GLOBAL: + return "GLOBAL"; + case STB_WEAK: + return "WEAK"; + case STB_GNU_UNIQUE: + return "GNU_UNIQUE"; + default: + return "?"; + } +} + +static const char *st_vis_name(unsigned int st_vis) +{ + switch (st_vis) { + case STV_DEFAULT: + return "DEFAULT"; + case STV_INTERNAL: + return "INTERNAL"; + case STV_HIDDEN: + return "HIDDEN"; + case STV_PROTECTED: + return "PROTECTED"; + default: + return "?"; + } +} + +static int print_sym(struct params *params, pdp10_uint36_t i) +{ + Elf36_Sym *sym; + + sym = ¶ms->symtab[i]; + printf(" %" PDP10_PRIu36 " %" PDP10_PRIx36 " %" PDP10_PRIx36 " %u (%s) %u (%s) %u (%s) %" PDP10_PRIu18 " (", + i, sym->st_value, sym->st_size, ELF36_ST_TYPE(sym->st_info), st_type_name(ELF36_ST_TYPE(sym->st_info)), + ELF36_ST_BIND(sym->st_info), st_bind_name(ELF36_ST_BIND(sym->st_info)), ELF36_ST_VISIBILITY(sym->st_other), + st_vis_name(ELF36_ST_VISIBILITY(sym->st_other)), sym->st_shndx); + if (print_sh_name(params, sym->st_shndx, 1) < 0) /* XXX: NYI: SHN_XINDEX and SHT_SYMTAB_SHNDX */ + return -1; + printf(") "); + if (print_sym_name(params, i) < 0) + return -1; + printf("\n"); + return 0; +} + +static int print_symtab(struct params *params) +{ + pdp10_uint36_t i; + + printf("Symbol table '"); + if (print_sh_name(params, params->symtabndx, 0) < 0) + return -1; + printf("' in section %" PDP10_PRIu36 " contains %" PDP10_PRIu36 " entries:\n", + params->symtabndx, params->symnum); + printf(" Num Value Size Type Bind Vis Ndx Name\n"); + for (i = 0; i < params->symnum; ++i) + if (print_sym(params, i) < 0) { + fprintf(stderr, "%s: %s: failed to print symbol table entry %" PDP10_PRIu36 "\n", + params->progname, params->filename, i); + return -1; + } + printf("\n"); + return 0; +} + +static int readelf(struct params *params) +{ + unsigned char e_ident[EI_NIDENT]; + + if (pdp10_elf36_read_ehdr(params->pdp10fp, ¶ms->ehdr) < 0) { + fprintf(stderr, "%s: %s: failed to read ELF header: %s\n", + params->progname, params->filename, strerror(errno)); return -1; } - status = do_readelf_fp(options, pdp10fp, filename); - pdp10_fclose(pdp10fp); - return status; + ehdr_unpack_ident(¶ms->ehdr, e_ident); + if (check_eident(params, e_ident) < 0 + || check_ehdr(params) < 0) + return -1; + + if (params->opts.file_header) + print_ehdr(¶ms->ehdr, e_ident); + + if (read_shtab(params) < 0) { + fprintf(stderr, "%s: %s: failed to read section header table\n", + params->progname, params->filename); + return -1; + } + + if (params->opts.sections + && print_shtab(params) < 0) + return -1; + + if (read_symtab(params) < 0) { + fprintf(stderr, "%s: %s: read to read symbol table\n", + params->progname, params->filename); + return -1; + } + + if (params->opts.symbols + && print_symtab(params) < 0) + return -1; + + return 0; } /* @@ -302,11 +764,12 @@ static void usage(const char *progname) int main(int argc, char **argv) { - struct options options; + struct params params; int opt_version; int i; - memset(&options, 0, sizeof options); + params_init(¶ms); + params.progname = argv[0]; opt_version = 0; for (;;) { @@ -315,88 +778,104 @@ int main(int argc, char **argv) ch = getopt_long(argc, argv, "ahlSgtesnrudVADcv", long_options, NULL); switch (ch) { case 'a': - options.symbols = 1; - options.relocs = 1; - options.dynamic = 1; - options.notes = 1; - options.version_info = 1; + params.opts.symbols = 1; + params.opts.relocs = 1; + params.opts.dynamic = 1; + params.opts.notes = 1; + params.opts.version_info = 1; /*FALLTHROUGH*/ case 'e': - options.file_header = 1; - options.segments = 1; - options.sections = 1; + params.opts.file_header = 1; + params.opts.segments = 1; + params.opts.sections = 1; continue; case 'h': - options.file_header = 1; + params.opts.file_header = 1; continue; case 'l': - options.segments = 1; + params.opts.segments = 1; continue; case 't': - options.section_details = 1; + params.opts.section_details = 1; /*FALLTHROUGH*/ case 'S': - options.sections = 1; + params.opts.sections = 1; continue; case 'g': - options.section_groups = 1; + params.opts.section_groups = 1; continue; case 's': - options.symbols = 1; + params.opts.symbols = 1; continue; case 'n': - options.notes = 1; + params.opts.notes = 1; continue; case 'r': - options.relocs = 1; + params.opts.relocs = 1; continue; case 'u': - options.unwind = 1; + params.opts.unwind = 1; continue; case 'd': - options.dynamic = 1; + params.opts.dynamic = 1; continue; case 'V': - options.version_info = 1; + params.opts.version_info = 1; continue; case 'A': - options.arch_specific = 1; + params.opts.arch_specific = 1; continue; case 'D': - options.use_dynamic = 1; + params.opts.use_dynamic = 1; continue; case 'c': - options.archive_index = 1; + params.opts.archive_index = 1; continue; case 'v': opt_version = 1; continue; case LOPT_dyn_syms: - options.dyn_syms = 1; + params.opts.dyn_syms = 1; continue; case LOPT_disassemble: /* local extension */ - options.disassemble = 1; + params.opts.disassemble = 1; continue; case -1: break; default: - usage(argv[0]); + usage(params.progname); return 1; } break; } if (optind >= argc && !opt_version) { - usage(argv[0]); + usage(params.progname); return 1; } if (opt_version) printf("pdp10-tools readelf version 0.0 " __DATE__ " " __TIME__ "\n"); - for (i = optind; i < argc; ++i) - if (do_readelf(&options, argv[i]) != 0) + for (i = optind; i < argc; ++i) { + int status; + + params_file_init(¶ms); + + params.filename = argv[i]; + params.pdp10fp = pdp10_fopen(params.filename, "rb"); + if (!params.pdp10fp) { + fprintf(stderr, "%s: failed to open %s: %s\n", + params.progname, params.filename, strerror(errno)); + return -1; + } + status = readelf(¶ms); + + params_file_fini(¶ms); + + if (status < 0) return 1; + } return 0; }