/* * Disassemble a complete file. First, we determine the type of the file based * on the ELF machine type, and instantiate a version of the disassembler * appropriate for the file. We then resolve any named sections or functions * against the file, and iterate over the results (or all sections if no flags * were specified). */ void dis_file(const char *filename) { dis_tgt_t *tgt, *current; dis_scnlist_t *sections; dis_funclist_t *functions; dis_handle_t *dhp; GElf_Ehdr ehdr; /* * First, initialize the target */ if ((tgt = dis_tgt_create(filename)) == NULL) return; if (!g_quiet) (void) printf("disassembly for %s\n\n", filename); /* * A given file may contain multiple targets (if it is an archive, for * example). We iterate over all possible targets if this is the case. */ for (current = tgt; current != NULL; current = dis_tgt_next(current)) { dis_tgt_ehdr(current, &ehdr); /* * Eventually, this should probably live within libdisasm, and * we should be able to disassemble targets from different * architectures. For now, we only support objects as the * native machine type. */ switch (ehdr.e_machine) { case EM_SPARC: if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for SPARC object"); return; } g_flags |= DIS_SPARC_V8; break; case EM_SPARC32PLUS: { uint64_t flags = ehdr.e_flags & EF_SPARC_32PLUS_MASK; if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for SPARC object"); return; } if (flags != 0 && (flags & (EF_SPARC_32PLUS | EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3)) != EF_SPARC_32PLUS) g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI; else g_flags |= DIS_SPARC_V9; break; } case EM_SPARCV9: if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for SPARC object"); return; } g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI; break; case EM_386: g_flags |= DIS_X86_SIZE32; break; case EM_AMD64: g_flags |= DIS_X86_SIZE64; break; case EM_S370: g_flags |= DIS_S370; if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for S370 object"); return; } break; case EM_S390: /* * Both 390 and z/Architecture use EM_S390, the only * differences is the class: ELFCLASS32 for plain * old s390 and ELFCLASS64 for z/Architecture (aka. * s390x). */ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) { g_flags |= DIS_S390_31; } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { g_flags |= DIS_S390_64; } else { warn("invalid E_IDENT field for S390 object"); return; } if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for S390 object"); return; } break; case EM_RISCV: /* * RISC-V is defined to be litle endian. The current ISA * makes it clear that the 64-bit instructions can * co-exist with the 32-bit ones and therefore we don't * need a separate elf class at this time. */ if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { warn("invalid EI_DATA field for RISC-V object"); return; } if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) { g_flags |= DIS_RISCV_32; } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { g_flags |= DIS_RISCV_64; } else { warn("invalid EI_CLASS field for RISC-V " "object"); return; } break; default: die("%s: unsupported ELF machine 0x%x", filename, ehdr.e_machine); } /* * If ET_REL (.o), printing immediate symbols is likely to * result in garbage, as symbol lookups on unrelocated * immediates find false and useless matches. */ if (ehdr.e_type == ET_REL) g_flags |= DIS_NOIMMSYM; if (!g_quiet && dis_tgt_member(current) != NULL) (void) printf("\narchive member %s\n", dis_tgt_member(current)); /* * Instantiate a libdisasm handle based on the file type. */ if ((dhp = dis_handle_create(g_flags, current, do_lookup, do_read)) == NULL) die("%s: failed to initialize disassembler: %s", filename, dis_strerror(dis_errno())); if (g_doall) { /* * With no arguments, iterate over all sections and * disassemble only those that contain text. */ dis_tgt_section_iter(current, dis_text_section, dhp); } else { callback_arg_t ca; ca.ca_tgt = current; ca.ca_handle = dhp; /* * If sections or functions were explicitly specified, * resolve those names against the object, and iterate * over just the resulting data. */ sections = dis_namelist_resolve_sections(g_seclist, current); functions = dis_namelist_resolve_functions(g_funclist, current); dis_scnlist_iter(sections, dis_named_section, &ca); dis_funclist_iter(functions, dis_named_function, &ca); dis_scnlist_destroy(sections); dis_funclist_destroy(functions); } dis_handle_destroy(dhp); } dis_tgt_destroy(tgt); }
/* * Disassemble a complete file. First, we determine the type of the file based * on the ELF machine type, and instantiate a version of the disassembler * appropriate for the file. We then resolve any named sections or functions * against the file, and iterate over the results (or all sections if no flags * were specified). */ void dis_file(const char *filename) { dis_tgt_t *tgt, *current; dis_scnlist_t *sections; dis_funclist_t *functions; dis_handle_t *dhp; GElf_Ehdr ehdr; /* * First, initialize the target */ if ((tgt = dis_tgt_create(filename)) == NULL) return; if (!g_quiet) (void) printf("disassembly for %s\n\n", filename); /* * A given file may contain multiple targets (if it is an archive, for * example). We iterate over all possible targets if this is the case. */ for (current = tgt; current != NULL; current = dis_tgt_next(current)) { dis_tgt_ehdr(current, &ehdr); /* * Eventually, this should probably live within libdisasm, and * we should be able to disassemble targets from different * architectures. For now, we only support objects as the * native machine type. */ switch (ehdr.e_machine) { #ifdef __sparc case EM_SPARC: if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for SPARC object"); return; } g_flags |= DIS_SPARC_V8; break; case EM_SPARC32PLUS: if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for SPARC object"); return; } switch (ehdr.e_flags & EF_SPARC_32PLUS_MASK) { case (EF_SPARC_32PLUS | EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3): case (EF_SPARC_32PLUS | EF_SPARC_SUN_US1): g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI; default: g_flags |= DIS_SPARC_V9; } break; case EM_SPARCV9: if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { warn("invalid E_IDENT field for SPARC object"); return; } g_flags |= DIS_SPARC_V9 | DIS_SPARC_V9_SGI; break; #endif /* __sparc */ #if defined(__i386) || defined(__amd64) case EM_386: g_flags |= DIS_X86_SIZE32; break; case EM_AMD64: g_flags |= DIS_X86_SIZE64; break; #endif /* __i386 || __amd64 */ default: die("%s: unsupported ELF machine 0x%x", filename, ehdr.e_machine); } /* * If ET_REL (.o), printing immediate symbols is likely to * result in garbage, as symbol lookups on unrelocated * immediates find false and useless matches. */ if (ehdr.e_type == ET_REL) g_flags |= DIS_NOIMMSYM; if (!g_quiet && dis_tgt_member(current) != NULL) (void) printf("\narchive member %s\n", dis_tgt_member(current)); /* * Instantiate a libdisasm handle based on the file type. */ if ((dhp = dis_handle_create(g_flags, current, do_lookup, do_read)) == NULL) die("%s: failed to initialize disassembler: %s", filename, dis_strerror(dis_errno())); if (g_doall) { /* * With no arguments, iterate over all sections and * disassemble only those that contain text. */ dis_tgt_section_iter(current, dis_text_section, dhp); } else { callback_arg_t ca; ca.ca_tgt = current; ca.ca_handle = dhp; /* * If sections or functions were explicitly specified, * resolve those names against the object, and iterate * over just the resulting data. */ sections = dis_namelist_resolve_sections(g_seclist, current); functions = dis_namelist_resolve_functions(g_funclist, current); dis_scnlist_iter(sections, dis_named_section, &ca); dis_funclist_iter(functions, dis_named_function, &ca); dis_scnlist_destroy(sections); dis_funclist_destroy(functions); } dis_handle_destroy(dhp); } dis_tgt_destroy(tgt); }