/* ### * 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.dwarf.line; import ghidra.app.util.bin.BinaryReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class StatementProgramPrologue { public final static int TOTAL_LENGTH_FIELD_LEN = 4; public final static int PRE_PROLOGUE_LEN = 4 + 2 + 4; private int totalLength; private short version; private int prologueLength; private byte minimumInstructionLength; private boolean defaultIsStatement; private byte lineBase; private byte lineRange; private byte opcodeBase; private byte [] standardOpcodeLengths; private List<String> includeDirectories = new ArrayList<String>(); private List<FileEntry> fileNames = new ArrayList<FileEntry>(); public StatementProgramPrologue(BinaryReader reader) throws IOException { totalLength = reader.readNextInt(); version = reader.readNextShort(); if (version != 2) { throw new IllegalStateException("Only DWARF v2 is supported."); } prologueLength = reader.readNextInt(); minimumInstructionLength = reader.readNextByte(); defaultIsStatement = reader.readNextByte() != 0; lineBase = reader.readNextByte(); lineRange = reader.readNextByte(); opcodeBase = reader.readNextByte(); standardOpcodeLengths = reader.readNextByteArray(opcodeBase - 1); while (true) { String dir = reader.readNextAsciiString(); if (dir.length() == 0) { break; } includeDirectories.add(dir); } while (true) { FileEntry entry = new FileEntry(reader); if (entry.getFileName().length() == 0) { break; } fileNames.add(entry); } } /** * Returns the size in bytes of the statement information for this * compilation unit (not including the total_length field itself). * @return size in bytes of the statement information */ public int getTotalLength() { return totalLength; } /** * Returns the version identifier for the statement information format. * @return the version identifier for the statement information format */ public int getVersion() { return version & 0xffff; } /** * Returns the number of bytes following the prologue_length field to the * beginning of the first byte of the statement program itself. * @return the number of bytes following the prologue_length */ public int getPrologueLength() { return prologueLength; } /** * Returns the size in bytes of the smallest target machine instruction. * Statement program opcodes that alter the address register first * multiply their operands by this value. * @return the size in bytes of the smallest target machine instruction */ public int getMinimumInstructionLength() { return minimumInstructionLength & 0xff; } /** * Returns the initial value of the is_stmt register. * @return the initial value of the is_stmt register */ public boolean isDefaultIsStatement() { return defaultIsStatement; } /** * Returns the line base value. * This parameter affects the meaning of the special opcodes. See below. * @return the line base value */ public int getLineBase() { return lineBase & 0xff; } /** * Returns the line range value. * This parameter affects the meaning of the special opcodes. See below. * @return the line range value */ public int getLineRange() { return lineRange & 0xff; } /** * Returns the number assigned to the first special opcode. * @return the number assigned to the first special opcode */ public int getOpcodeBase() { return opcodeBase & 0xff; } /** * return the array for each of the standard opcodes * @return the array for each of the standard opcodes */ public byte [] getStandardOpcodeLengths() { return standardOpcodeLengths; } /** * @return each path that was searched for included source files */ public List<String> getIncludeDirectories() { return includeDirectories; } /** * @return an entry for each source file that contributed to the statement */ public List<FileEntry> getFileNames() { return fileNames; } /** * Returns the file entry at the given index. * @param fileIndex the file index * @return the file entry at the given index */ public FileEntry getFileNameByIndex(int fileIndex) { return fileNames.get(fileIndex - 1); } /** * The directory index represents an entry in the * include directories section. If the directoryIndex * is LEB128(0), then the file was found in the current * directory. * @param directoryIndex the directory index * @return the directory or current directory */ public String getDirectoryByIndex(LEB128 directoryIndex) { if (directoryIndex.getValue() == 0) { return "."; } return includeDirectories.get((int)directoryIndex.getValue() - 1); } }