<commit_before>/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ghidra.app.util.bin.format.elf;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;

import generic.continues.GenericFactory;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
import ghidra.app.util.bin.format.Writeable;
import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory;
import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.*;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.NotFoundException;

/**
 * A class to represent the Executable and Linking Format (ELF)
 * header and specification.
 */
public class ElfHeader implements StructConverter, Writeable {

	private static final int MAX_HEADERS_TO_CHECK_FOR_IMAGEBASE = 20;

	private HashMap<Integer, ElfProgramHeaderType> programHeaderTypeMap;
	private HashMap<Integer, ElfSectionHeaderType> sectionHeaderTypeMap;
	private HashMap<Integer, ElfDynamicType> dynamicTypeMap;

	private FactoryBundledWithBinaryReader reader;
	private ElfLoadAdapter elfLoadAdapter = new ElfLoadAdapter();

	private byte e_ident_magic_num; //magic number
	private String e_ident_magic_str; //magic string
	private byte e_ident_class; //file class
	private byte e_ident_data; //data encoding
	private byte e_ident_version; //file version
	private byte[] e_ident_pad; //padding
	private short e_type; //object file type
	private short e_machine; //target architecture
	private int e_version; //object file version
	private long e_entry; //executable entry point
	private long e_phoff; //program header table offset
	private long e_shoff; //section header table offset
	private int e_flags; //processor-specific flags
	private short e_ehsize; //elf header size
	private short e_phentsize; //size of entries in the program header table
	private short e_phnum; //number of enties in the program header table
	private short e_shentsize; //size of entries in the section header table
	private short e_shnum; //number of enties in the section header table
	private short e_shstrndx; //section index of the section name string table

	private Structure headerStructure;

	private boolean parsed = false;
	private boolean parsedSectionHeaders = false;

	private ElfSectionHeader[] sectionHeaders = new ElfSectionHeader[0];
	private ElfProgramHeader[] programHeaders = new ElfProgramHeader[0];
	private ElfStringTable[] stringTables = new ElfStringTable[0];
	private ElfSymbolTable[] symbolTables = new ElfSymbolTable[0];
	private ElfRelocationTable[] relocationTables = new ElfRelocationTable[0];
	private ElfDynamicTable dynamicTable;

	private ElfStringTable dynamicStringTable;
	private ElfSymbolTable dynamicSymbolTable;

	private String[] dynamicLibraryNames;

	private boolean hasLittleEndianHeaders;

	private static int INITIAL_READ_LEN = ElfConstants.EI_NIDENT + 18;

	/**
	 * Constructs a new ELF header using the specified byte provider.
	 * @param provider the byte provider to supply the bytes
	 * @throws ElfException if the underlying bytes in the byte provider 
	 * do not constitute a valid ELF.
	 */
	public static ElfHeader createElfHeader(GenericFactory factory, ByteProvider provider)
			throws ElfException {
		ElfHeader elfHeader = (ElfHeader) factory.create(ElfHeader.class);
		elfHeader.initElfHeader(factory, provider);
		return elfHeader;
	}

	/**
	 * DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
	 */
	public ElfHeader() {
	}

	/**
	 * Returns the binary reader.
	 * @return the binary reader
	 */
	public BinaryReader getReader() {
		return reader;
	}

	protected void initElfHeader(GenericFactory factory, ByteProvider provider)
			throws ElfException {
		try {

			determineHeaderEndianess(provider);

			reader = new FactoryBundledWithBinaryReader(factory, provider, hasLittleEndianHeaders);

			e_ident_magic_num = reader.readNextByte();
			e_ident_magic_str = reader.readNextAsciiString(ElfConstants.MAGIC_STR_LEN);

			boolean magicMatch = ElfConstants.MAGIC_NUM == e_ident_magic_num &&
				ElfConstants.MAGIC_STR.equalsIgnoreCase(e_ident_magic_str);

			if (!magicMatch) {
				throw new ElfException("Not a valid ELF executable.");
			}

			e_ident_class = reader.readNextByte();
			e_ident_data = reader.readNextByte();
			e_ident_version = reader.readNextByte();
			e_ident_pad = reader.readNextByteArray(9);
			e_type = reader.readNextShort();
			e_machine = reader.readNextShort();
			e_version = reader.readNextInt();

			if (is32Bit()) {
				e_entry = reader.readNextInt() & 0xffffffffL;
				e_phoff = reader.readNextInt() & 0xffffffffL;
				e_shoff = reader.readNextInt() & 0xffffffffL;
			}
			else if (is64Bit()) {
				e_entry = reader.readNextLong();
				e_phoff = reader.readNextLong();
				e_shoff = reader.readNextLong();
			}
			else {
				throw new ElfException("Only 32-bit and 64-bit ELF headers are supported.");
			}

			e_flags = reader.readNextInt();
			e_ehsize = reader.readNextShort();
			e_phentsize = reader.readNextShort();
			e_phnum = reader.readNextShort();
			e_shentsize = reader.readNextShort();
			e_shnum = reader.readNextShort();
			e_shstrndx = reader.readNextShort();
		}
		catch (IOException e) {
			throw new ElfException(e);
		}
	}

	private void initElfLoadAdapter() {

		programHeaderTypeMap = new HashMap<>();
		ElfProgramHeaderType.addDefaultTypes(programHeaderTypeMap);

		sectionHeaderTypeMap = new HashMap<>();
		ElfSectionHeaderType.addDefaultTypes(sectionHeaderTypeMap);

		dynamicTypeMap = new HashMap<>();<commit_msg>GT-3241: Better handling of stripped ELF section headers (fixes #1119).<commit_after>/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ghidra.app.util.bin.format.elf;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;

import generic.continues.GenericFactory;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
import ghidra.app.util.bin.format.Writeable;
import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory;
import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.*;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.NotFoundException;

/**
 * A class to represent the Executable and Linking Format (ELF)
 * header and specification.
 */
public class ElfHeader implements StructConverter, Writeable {

	private static final int MAX_HEADERS_TO_CHECK_FOR_IMAGEBASE = 20;

	private HashMap<Integer, ElfProgramHeaderType> programHeaderTypeMap;
	private HashMap<Integer, ElfSectionHeaderType> sectionHeaderTypeMap;
	private HashMap<Integer, ElfDynamicType> dynamicTypeMap;

	private FactoryBundledWithBinaryReader reader;
	private ElfLoadAdapter elfLoadAdapter = new ElfLoadAdapter();

	private byte e_ident_magic_num; //magic number
	private String e_ident_magic_str; //magic string
	private byte e_ident_class; //file class
	private byte e_ident_data; //data encoding
	private byte e_ident_version; //file version
	private byte[] e_ident_pad; //padding
	private short e_type; //object file type
	private short e_machine; //target architecture
	private int e_version; //object file version
	private long e_entry; //executable entry point
	private long e_phoff; //program header table offset
	private long e_shoff; //section header table offset
	private int e_flags; //processor-specific flags
	private short e_ehsize; //elf header size
	private short e_phentsize; //size of entries in the program header table
	private short e_phnum; //number of enties in the program header table
	private short e_shentsize; //size of entries in the section header table
	private short e_shnum; //number of enties in the section header table
	private short e_shstrndx; //section index of the section name string table

	private Structure headerStructure;

	private boolean parsed = false;
	private boolean parsedSectionHeaders = false;

	private ElfSectionHeader[] sectionHeaders = new ElfSectionHeader[0];
	private ElfProgramHeader[] programHeaders = new ElfProgramHeader[0];
	private ElfStringTable[] stringTables = new ElfStringTable[0];
	private ElfSymbolTable[] symbolTables = new ElfSymbolTable[0];
	private ElfRelocationTable[] relocationTables = new ElfRelocationTable[0];
	private ElfDynamicTable dynamicTable;

	private ElfStringTable dynamicStringTable;
	private ElfSymbolTable dynamicSymbolTable;

	private String[] dynamicLibraryNames;

	private boolean hasLittleEndianHeaders;

	private static int INITIAL_READ_LEN = ElfConstants.EI_NIDENT + 18;

	/**
	 * Constructs a new ELF header using the specified byte provider.
	 * @param provider the byte provider to supply the bytes
	 * @throws ElfException if the underlying bytes in the byte provider 
	 * do not constitute a valid ELF.
	 */
	public static ElfHeader createElfHeader(GenericFactory factory, ByteProvider provider)
			throws ElfException {
		ElfHeader elfHeader = (ElfHeader) factory.create(ElfHeader.class);
		elfHeader.initElfHeader(factory, provider);
		return elfHeader;
	}

	/**
	 * DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
	 */
	public ElfHeader() {
	}

	/**
	 * Returns the binary reader.
	 * @return the binary reader
	 */
	public BinaryReader getReader() {
		return reader;
	}

	protected void initElfHeader(GenericFactory factory, ByteProvider provider)
			throws ElfException {
		try {

			determineHeaderEndianess(provider);

			reader = new FactoryBundledWithBinaryReader(factory, provider, hasLittleEndianHeaders);

			e_ident_magic_num = reader.readNextByte();
			e_ident_magic_str = reader.readNextAsciiString(ElfConstants.MAGIC_STR_LEN);

			boolean magicMatch = ElfConstants.MAGIC_NUM == e_ident_magic_num &&
				ElfConstants.MAGIC_STR.equalsIgnoreCase(e_ident_magic_str);

			if (!magicMatch) {
				throw new ElfException("Not a valid ELF executable.");
			}

			e_ident_class = reader.readNextByte();
			e_ident_data = reader.readNextByte();
			e_ident_version = reader.readNextByte();
			e_ident_pad = reader.readNextByteArray(9);
			e_type = reader.readNextShort();
			e_machine = reader.readNextShort();
			e_version = reader.readNextInt();

			if (is32Bit()) {
				e_entry = reader.readNextInt() & 0xffffffffL;
				e_phoff = reader.readNextInt() & 0xffffffffL;
				e_shoff = reader.readNextInt() & 0xffffffffL;
			}
			else if (is64Bit()) {
				e_entry = reader.readNextLong();
				e_phoff = reader.readNextLong();
				e_shoff = reader.readNextLong();
			}
			else {
				throw new ElfException("Only 32-bit and 64-bit ELF headers are supported.");
			}

			e_flags = reader.readNextInt();
			e_ehsize = reader.readNextShort();
			e_phentsize = reader.readNextShort();
			e_phnum = reader.readNextShort();
			if (e_phnum < 0) {
				e_phnum = 0; // protect against stripped program headers
			}
			e_shentsize = reader.readNextShort();
			e_shnum = reader.readNextShort();
			if (e_shnum < 0) {
				e_shnum = 0; // protect against stripped section headers (have seen -1)
			}
			e_shstrndx = reader.readNextShort();
		}
		catch (IOException e) {
			throw new ElfException(e);
		}
	}

	private void initElfLoadAdapter() {

		programHeaderTypeMap = new HashMap<>();
		ElfProgramHeaderType.addDefaultTypes(programHeaderTypeMap);

		sectionHeaderTypeMap = new HashMap<>();
		ElfSectionHeaderType.addDefaultTypes(sectionHeaderTypeMap);

		dynamicTypeMap = new HashMap<>();
{'fraction_non_alphanumeric': 0.08670791885329365, 'fraction_numerical': 0.0049345970079110206, 'mean_word_length': 4.735849056603773, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4826938', 'n_tokens_mistral': 4112, 'n_tokens_neox': 3727, 'n_words': 1103}