/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.format; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import jpcsp.Emulator; import jpcsp.util.Utilities; public class Elf32 { // File offset private int elfOffset; private boolean kernelMode; // Headers private Elf32Header header; private List<Elf32ProgramHeader> programHeaderList; private List<Elf32SectionHeader> sectionHeaderList; private HashMap<String, Elf32SectionHeader> sectionHeaderMap; private Elf32SectionHeader shstrtab; // Debug info private String ElfInfo; // ELF header private String ProgInfo; // ELF program headers private String SectInfo; // ELF section headers public Elf32(ByteBuffer f) throws IOException { elfOffset = f.position(); loadHeader(f); if (header.isValid()) { loadProgramHeaders(f); loadSectionHeaders(f); } } private void loadHeader(ByteBuffer f) throws IOException { header = new Elf32Header(f); ElfInfo = header.toString(); } private void loadProgramHeaders(ByteBuffer f) throws IOException { programHeaderList = new LinkedList<Elf32ProgramHeader>(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < header.getE_phnum(); i++) { f.position(elfOffset + header.getE_phoff() + (i * header.getE_phentsize())); Elf32ProgramHeader phdr = new Elf32ProgramHeader(f); // Save loaded header programHeaderList.add(phdr); // Construct ELF program header info for debugger sb.append("-----PROGRAM HEADER #" + i + "-----" + "\n"); sb.append(phdr.toString()); // yapspd: if the PRX file is a kernel module then the most significant // bit must be set in the phsyical address of the first program header. if (i == 0 && (phdr.getP_paddr() & 0x80000000) != 0) { kernelMode = true; Emulator.log.debug("Kernel mode PRX detected"); } } ProgInfo = sb.toString(); } private void loadSectionHeaders(ByteBuffer f) throws IOException { sectionHeaderList = new LinkedList<Elf32SectionHeader>(); sectionHeaderMap = new HashMap<String, Elf32SectionHeader>(); // 1st pass // - save headers // - find .shstrtab for (int i = 0; i < header.getE_shnum(); i++) { f.position(elfOffset + header.getE_shoff() + (i * header.getE_shentsize())); Elf32SectionHeader shdr = new Elf32SectionHeader(f); // Save loaded header sectionHeaderList.add(shdr); // Find the .shstrtab section if (shdr.getSh_type() == Elf32SectionHeader.SHT_STRTAB && // 0x00000003 shstrtab == null && // Some programs have 2 STRTAB headers, // the header with size 1 has to be ignored. shdr.getSh_size() > 1) { shstrtab = shdr; } } if (shstrtab == null) { Emulator.log.warn(".shstrtab section not found"); return; } // 2nd pass // - Construct ELF section header info for debugger StringBuilder sb = new StringBuilder(); int SectionCounter = 0; for (Elf32SectionHeader shdr : sectionHeaderList) { int position = elfOffset + shstrtab.getSh_offset() + shdr.getSh_name(); f.position(position); // removed past end of file check (fiveofhearts 18/10/08) // Number the section sb.append("-----SECTION HEADER #" + SectionCounter + "-----" + "\n"); String SectionName = Utilities.readStringZ(f); // removed readStringZ exception check (fiveofhearts 18/10/08) if (SectionName.length() > 0) { shdr.setSh_namez(SectionName); sb.append(SectionName + "\n"); sectionHeaderMap.put(SectionName, shdr); } else { //Emulator.log.debug("Section header #" + SectionCounter + " has no name"); } // Add this section header's info sb.append(shdr.toString()); SectionCounter++; } SectInfo = sb.toString(); } /** @return The elf was loaded from some kind of file or buffer. The elf * offset is an offset into this buffer where the elf actually starts. If * the returned offset is non-zero this is typically due to the elf being * embedded inside a pbp. */ public int getElfOffset() { return elfOffset; } public Elf32Header getHeader() { return header; } public List<Elf32ProgramHeader> getProgramHeaderList() { return programHeaderList; } public Elf32ProgramHeader getProgramHeader(int index) { if (index < 0 || index >= programHeaderList.size()) { return null; } return programHeaderList.get(index); } public List<Elf32SectionHeader> getSectionHeaderList() { return sectionHeaderList; } public Elf32SectionHeader getSectionHeader(int index) { if (index < 0 || index >= sectionHeaderList.size()) { return null; } return sectionHeaderList.get(index); } public Elf32SectionHeader getSectionHeader(String name) { return sectionHeaderMap.get(name); } public String getElfInfo() { return ElfInfo; } public String getProgInfo() { return ProgInfo; } public String getSectInfo() { return SectInfo; } public boolean isKernelMode() { return kernelMode; } }