Exemplo n.º 1
0
/*
 * 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);
}
Exemplo n.º 2
0
/*
 * 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);
}