diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/omf51/Omf51ModuleHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/omf51/Omf51ModuleHeader.java index dc884d7424..0746c2ef79 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/omf51/Omf51ModuleHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/omf51/Omf51ModuleHeader.java @@ -40,8 +40,16 @@ public class Omf51ModuleHeader extends OmfRecord { @Override public void parseData() throws IOException, OmfException { moduleName = OmfUtils.readString(dataReader); - dataReader.readNextByte(); trnId = dataReader.readNextByte(); + + switch (trnId) { + case (byte) 0xfd: // ASM51 + case (byte) 0xfe: // PL/M-51 + case (byte) 0xff: // RL51 + break; + default: + throw new OmfException("Invalid TRN ID: 0x%x".formatted(trnId)); + } } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxHeader.java new file mode 100644 index 0000000000..4b5061f546 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxHeader.java @@ -0,0 +1,59 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Abstract parent class for SOM auxiliary headers + */ +public abstract class SomAuxHeader implements StructConverter { + + protected SomAuxId auxId; + + /** + * Creates a new {@link SomAuxHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the auxiliary header + * @throws IOException if there was an IO-related error + */ + public SomAuxHeader(BinaryReader reader) throws IOException { + auxId = new SomAuxId(reader); + } + + /** + * {@return this {@link SomAuxHeader}'s {@link SomAuxId aux ID}} + */ + public SomAuxId getAuxId() { + return auxId; + } + + /** + * {@return the length in bytes of this {@link SomAuxHeader auxiliary header} (including the + * size of the aux id)} + */ + public long getLength() { + return auxId.getLength() + SomAuxId.SIZE; + } + + @Override + public abstract DataType toDataType() throws DuplicateNameException, IOException; +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxHeaderFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxHeaderFactory.java new file mode 100644 index 0000000000..b38e941617 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxHeaderFactory.java @@ -0,0 +1,43 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; + +/** + * A class for reading/creating SOM auxiliary headers + */ +public class SomAuxHeaderFactory { + + public static SomAuxHeader readNextAuxHeader(BinaryReader reader) throws IOException { + long origReaderIndex = reader.getPointerIndex(); + SomAuxId auxId = new SomAuxId(reader); + reader.setPointerIndex(origReaderIndex); + + return switch (auxId.getType()) { + case SomConstants.EXEC_AUXILIARY_HEADER: + yield new SomExecAuxHeader(reader); + case SomConstants.LINKER_FOOTPRINT: + yield new SomLinkerFootprintAuxHeader(reader); + case SomConstants.PRODUCT_SPECIFICS: + yield new SomProductSpecificsAuxHeader(reader); + default: + yield new SomUnknownAuxHeader(reader); + }; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxId.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxId.java new file mode 100644 index 0000000000..15e7888e3b --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomAuxId.java @@ -0,0 +1,138 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code aux_id} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomAuxId implements StructConverter { + + /** The size in bytes of a {@link SomAuxId} */ + public static final int SIZE = 0x8; + + private boolean mandatory; + private boolean copy; + private boolean append; + private boolean ignore; + private int reserved; + private int type; + private long length; + + /** + * Creates a new {@link SomAuxId} + * + * @param reader A {@link BinaryReader} positioned at the start of the auxiliary ID + * @throws IOException if there was an IO-related error + */ + public SomAuxId(BinaryReader reader) throws IOException { + int bitfield = reader.readNextInt(); + type = bitfield & 0xffff; + reserved = (bitfield >> 16) & 0xfff; + ignore = ((bitfield >> 28) & 0x1) != 0; + append = ((bitfield >> 29) & 0x1) != 0; + copy = ((bitfield >> 30) & 0x1) != 0; + mandatory = ((bitfield >> 31) & 0x1) != 0; + length = reader.readNextUnsignedInt(); + } + + /** + * {@return whether or not this auxiliary header contains information that the linker must + * understand} + */ + public boolean getMandatory() { + return mandatory; + } + + /** + * {@return whether or not this auxiliary header is to be copied without modification to any new + * SOM created from this SOM} + */ + public boolean getCopy() { + return copy; + } + + /** + * {@return whether or not this auxiliary header is to be copied without modification to any new + * SOM created from this SOM, except that multiple entries with the same type and append set of + * “action flags” (i.e., mandatory, copy, append, ignore) should be merged (concatenation of the + * data portion)} + */ + public boolean getAppend() { + return append; + } + + /** + * {@return whether or not this auxiliary header should be ignored if its type field is unknown + * (i.e., do not copy, do not merge)} + */ + public boolean getIgnore() { + return ignore; + } + + /** + * {@return the reserved value} + */ + public int getReserved() { + return reserved; + } + + /** + * {@return the type of auxiliary header} + * + * @see SomConstants + */ + public int getType() { + return type; + } + + /** + * {@return the length of the auxiliary header in bytes (this value does NOT include the two + * word identifiers at the front of the header)} + */ + public long getLength() { + return length; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("aux_id", SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(DWORD, 1, "mandatory", null); + struct.addBitField(DWORD, 1, "copy", null); + struct.addBitField(DWORD, 1, "append", null); + struct.addBitField(DWORD, 1, "ignore", null); + struct.addBitField(DWORD, 12, "reserved", null); + struct.addBitField(DWORD, 16, "type", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(DWORD, "length", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomCompilationUnit.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomCompilationUnit.java new file mode 100644 index 0000000000..6e85e5d26f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomCompilationUnit.java @@ -0,0 +1,141 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code compilation_unit} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomCompilationUnit implements StructConverter { + + /** The size in bytes of a {@link SomCompilationUnit} */ + public static final int SIZE = 0x24; + + private String name; + private String languageName; + private String productId; + private String versionId; + private int reserved; + private boolean chunkFlag; + private SomSysClock compileTime; + private SomSysClock sourceTime; + + + /** + * Creates a new {@link SomCompilationUnit} + * + * @param reader A {@link BinaryReader} positioned at the start of the record + * @param symbolStringsLocation The starting index of the symbol strings + * @throws IOException if there was an IO-related error + */ + public SomCompilationUnit(BinaryReader reader, long symbolStringsLocation) throws IOException { + name = reader.readAsciiString(symbolStringsLocation + reader.readNextUnsignedInt()); + languageName = reader.readAsciiString(symbolStringsLocation + reader.readNextUnsignedInt()); + productId = reader.readAsciiString(symbolStringsLocation + reader.readNextUnsignedInt()); + versionId = reader.readAsciiString(symbolStringsLocation + reader.readNextUnsignedInt()); + int bitfield = reader.readNextInt(); + chunkFlag = (bitfield & 0x1) != 0; + reserved = (bitfield >> 1) & 0x7fffffff; + compileTime = new SomSysClock(reader); + sourceTime = new SomSysClock(reader); + } + + /** + * {@return the compilation unit name} + */ + public String getName() { + return name; + } + + /** + * {@return the language name} + */ + public String getLanguageName() { + return languageName; + } + + /** + * {@return the product ID} + */ + public String getProductId() { + return productId; + } + + /** + * {@return the version ID} + */ + public String getVersionId() { + return versionId; + } + + /** + * {@return the reserved value} + */ + public int getReserved() { + return reserved; + } + + /** + * {@return whether or not the compilation unit is not the first SOM in a multiple chunk + * compilation} + */ + public boolean getChunkFlag() { + return chunkFlag; + } + + /** + * {@return the compile time} + */ + public SomSysClock getCompileTime() { + return compileTime; + } + + /** + * {@return the source time} + */ + public SomSysClock getSourceTime() { + return sourceTime; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("compilation_unit", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "name", null); + struct.add(DWORD, "language_name", null); + struct.add(DWORD, "product_id", null); + struct.add(DWORD, "version_id", null); + try { + struct.addBitField(DWORD, 31, "reserved", null); + struct.addBitField(DWORD, 1, "chunk_flag", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(compileTime.toDataType(), "compile_time", null); + struct.add(sourceTime.toDataType(), "source_time", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomConstants.java new file mode 100644 index 0000000000..a644f815b1 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomConstants.java @@ -0,0 +1,93 @@ +/* ### + * 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.som; + +/** + * SOM constant values + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomConstants { + + // System IDs + public static final int SYSTEM_PA_RISC_1_0 = 0x20b; + public static final int SYSTEM_PA_RISC_1_1 = 0x210; + public static final int SYSTEM_PA_RISC_2_0 = 0x214; + + // Magic numbers + public static final int MAGIC_LIBRARY = 0x104; + public static final int MAGIC_RELOCATABLE = 0x106; + public static final int MAGIC_NON_SHAREABLE_EXE = 0x107; + public static final int MAGIC_SHAREABLE_EXE = 0x108; + public static final int MAGIC_SHARABLE_DEMAND_LOADABLE_EXE = 0x10b; + public static final int MAGIC_DYNAMIC_LOAD_LIBRARY = 0x10d; + public static final int MAGIC_SHARED_LIBRARY = 0x10e; + public static final int MAGIC_RELOCATABLE_LIBRARY = 0x0619; + + // Version IDs + public static final int VERSION_OLD = 0x85082112; + public static final int VERSION_NEW = 0x87102412; + + // Auxiliary header types + public static final int TYPE_NULL = 0; + public static final int LINKER_FOOTPRINT = 1; + public static final int MEP_IX_PROGRAM = 2; + public static final int DEBUGGER_FOOTPRINT = 3; + public static final int EXEC_AUXILIARY_HEADER = 4; + public static final int IPL_AUXILIARY_HEADER = 5; + public static final int VERSION_STRIING = 6; + public static final int MPE_IX_PROGRAM = 7; + public static final int MPE_IX_SOM = 8; + public static final int COPYRIGHT = 9; + public static final int SHARED_LIBARY_VERSION_INFORMATION = 10; + public static final int PRODUCT_SPECIFICS = 11; + public static final int NETWARE_LOADABLE_MODULE = 12; + + // Symbol types + public static final int SYMBOL_NULL = 0; + public static final int SYMBOL_ABSOLUTE = 1; + public static final int SYMBOL_DATA = 2; + public static final int SYMBOL_CODE = 3; + public static final int SYMBOL_PRI_PROG = 4; + public static final int SYMBOL_SEC_PROG = 5; + public static final int SYMBOL_ENTRY = 6; + public static final int SYMBOL_STORAGE = 7; + public static final int SYMBOL_STUB = 8; + public static final int SYMBOL_MODULE = 9; + public static final int SYMBOL_SYM_EXT = 10; + public static final int SYMBOL_ARG_EXT = 11; + public static final int SYMBOL_MILLICODE = 12; + public static final int SYMBOL_PLABEL = 13; + public static final int SYMBOL_OCT_DIS = 14; + public static final int SYMBOL_MILLI_EXT = 15; + public static final int SYMBOL_TSTORAGE = 16; + public static final int SYMBOL_COMDAT = 17; + + // Symbol scopes + public static final int SYMBOL_SCOPE_UNSAT = 0; + public static final int SYMBOL_SCOPE_EXTERNAL = 1; + public static final int SYMBOL_SCOPE_LOCAL = 2; + public static final int SYMBOL_SCOPE_UNIVERSAL = 3; + + // Dynamic relocation types + public static final int DR_PLABEL_EXT = 1; + public static final int DR_PLABEL_INT = 2; + public static final int DR_DATA_EXT = 3; + public static final int DR_DATA_INT = 4; + public static final int DR_PROPAGATE = 5; + public static final int DR_INVOKE = 6; + public static final int DR_TEXT_INT = 7; +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDltEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDltEntry.java new file mode 100644 index 0000000000..075412541e --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDltEntry.java @@ -0,0 +1,58 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code DLT} value + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomDltEntry implements StructConverter { + + /** The size in bytes of a {@link SomDltEntry} */ + public static final int SIZE = 0x4; + + private int value; + + /** + * Creates a new {@link SomDltEntry} + * + * @param reader A {@link BinaryReader} positioned at the start of the DLT + * @throws IOException if there was an IO-related error + */ + public SomDltEntry(BinaryReader reader) throws IOException { + value = reader.readNextInt(); + } + + /** + * {@return the value of the DLT entry} + */ + public int getValue() { + return value; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + return POINTER; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDynamicLoaderHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDynamicLoaderHeader.java new file mode 100644 index 0000000000..cac53a08b7 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDynamicLoaderHeader.java @@ -0,0 +1,591 @@ +/* ### + * 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.som; + +import static ghidra.program.model.data.DataUtilities.ClearDataMode.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a SOM {@code dl_header} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomDynamicLoaderHeader implements StructConverter { + + /** The size in bytes of a {@link SomDynamicLoaderHeader} */ + public static final int SIZE = 0x70; + + private int hdrVersion; + private int ltptrValue; + private int shlibListLoc; + private int shlibListCount; + private int importListLoc; + private int importListCount; + private int hashTableLoc; + private int hashTableSize; + private int exportListLoc; + private int exportListCount; + private int stringTableLoc; + private int stringTableSize; + private int drelocLoc; + private int drelocCount; + private int dltLoc; + private int pltLoc; + private int dltCount; + private int pltCount; + private short highwaterMark; + private short flags; + private int exportExtLoc; + private int moduleLoc; + private int moduleCount; + private int elaborator; + private int initializer; + private int embeddedPath; + private int initializerCount; + private int tdsize; + private int fastbindListLoc; + + private Address textAddr; + private Address dataAddr; + private List shlibs = new ArrayList<>(); + private List imports = new ArrayList<>(); + private List exports = new ArrayList<>(); + private List drelocs = new ArrayList<>(); + private List plt = new ArrayList<>(); + private List dlt = new ArrayList<>(); + private List exportExtensions = new ArrayList<>(); + private List modules = new ArrayList<>(); + + /** + * Creates a new {@link SomDynamicLoaderHeader} + * + * @param program The {@link Program} + * @param textAddr The {@link Address} of the "text" space + * @param dataAddr The {@link Address} of the "data" space + * @throws IOException if there was an IO-related error + */ + public SomDynamicLoaderHeader(Program program, Address textAddr, Address dataAddr) + throws IOException { + if (textAddr == null) { + throw new IOException("Address of text space required to create dynamic loader header"); + } + if (dataAddr == null) { + throw new IOException("Address of data space required to create dynamic loader header"); + } + BinaryReader textReader = + new BinaryReader(new MemoryByteProvider(program.getMemory(), textAddr), false); + BinaryReader dataReader = + new BinaryReader(new MemoryByteProvider(program.getMemory(), dataAddr), false); + + hdrVersion = textReader.readNextInt(); + ltptrValue = textReader.readNextInt(); + shlibListLoc = textReader.readNextInt(); + shlibListCount = textReader.readNextInt(); + importListLoc = textReader.readNextInt(); + importListCount = textReader.readNextInt(); + hashTableLoc = textReader.readNextInt(); + hashTableSize = textReader.readNextInt(); + exportListLoc = textReader.readNextInt(); + exportListCount = textReader.readNextInt(); + stringTableLoc = textReader.readNextInt(); + stringTableSize = textReader.readNextInt(); + drelocLoc = textReader.readNextInt(); + drelocCount = textReader.readNextInt(); + dltLoc = textReader.readNextInt(); + pltLoc = textReader.readNextInt(); + dltCount = textReader.readNextInt(); + pltCount = textReader.readNextInt(); + highwaterMark = textReader.readNextShort(); + flags = textReader.readNextShort(); + exportExtLoc = textReader.readNextInt(); + moduleLoc = textReader.readNextInt(); + moduleCount = textReader.readNextInt(); + elaborator = textReader.readNextInt(); + initializer = textReader.readNextInt(); + embeddedPath = textReader.readNextInt(); + initializerCount = textReader.readNextInt(); + tdsize = textReader.readNextInt(); + fastbindListLoc = textReader.readNextInt(); + + this.textAddr = textAddr; + this.dataAddr = dataAddr; + + if (shlibListLoc > 0) { + textReader.setPointerIndex(shlibListLoc); + for (int i = 0; i < shlibListCount; i++) { + shlibs.add(new SomShlibListEntry(textReader, stringTableLoc)); + } + } + + if (importListCount > 0) { + textReader.setPointerIndex(importListLoc); + for (int i = 0; i < importListCount; i++) { + imports.add(new SomImportEntry(textReader, stringTableLoc)); + } + } + + if (exportListCount > 0) { + textReader.setPointerIndex(exportListLoc); + for (int i = 0; i < exportListCount; i++) { + exports.add(new SomExportEntry(textReader, stringTableLoc)); + } + } + + if (drelocCount > 0) { + textReader.setPointerIndex(drelocLoc); + for (int i = 0; i < drelocCount; i++) { + drelocs.add(new SomDynamicRelocation(textReader)); + } + } + + if (pltCount > 0) { + dataReader.setPointerIndex(pltLoc); + for (int i = 0; i < pltCount; i++) { + plt.add(new SomPltEntry(dataReader)); + } + } + + if (dltCount > 0) { + dataReader.setPointerIndex(dltLoc); + for (int i = 0; i < dltCount; i++) { + dlt.add(new SomDltEntry(dataReader)); + } + } + + if (exportExtLoc > 0) { + textReader.setPointerIndex(exportExtLoc); + for (int i = 0; i < exportListCount; i++) { + exportExtensions.add(new SomExportEntryExt(textReader)); + } + } + + if (moduleCount > 0) { + textReader.setPointerIndex(moduleLoc); + for (int i = 0; i < moduleCount; i++) { + modules.add(new SomModuleEntry(textReader)); + } + } + } + + /** + * {@return the version of the DL header} + */ + public int getHdrVersion() { + return hdrVersion; + } + + /** + * {@return the data-relative offset of the Linkage Table pointer} + */ + public int getLtptrValue() { + return ltptrValue; + } + + /** + * {@return the text-relative offset of the shared library list} + */ + public int getShlibListLoc() { + return shlibListLoc; + } + + /** + * {@return the number of entries in the shared library list} + */ + public int getShlibListCount() { + return shlibListCount; + } + + /** + * {@return the text-relative offset of the import list} + */ + public int getImportListLoc() { + return importListLoc; + } + + /** + * {@return the number of entries in the import list} + */ + public int getImportListCount() { + return importListCount; + } + + /** + * {@return the text-relative offset of the hash table} + */ + public int getHashTableLoc() { + return hashTableLoc; + } + + /** + * {@return the number of slots used in the hash table} + */ + public int getHashTableSize() { + return hashTableSize; + } + + /** + * {@return the text-relative offset of the export list} + */ + public int getExportListLoc() { + return exportListLoc; + } + + /** + * {@return the number of export entries} + */ + public int getExportListCount() { + return exportListCount; + } + + /** + * {@return the text-relative offset of the string table} + */ + public int getStringTableLoc() { + return stringTableLoc; + } + + /** + * {@return the length of the string table} + */ + public int getStringTableSize() { + return stringTableSize; + } + + /** + * {@return the text-relative offset of the dynamic relocation records} + */ + public int getDrelocLoc() { + return drelocLoc; + } + + /** + * {@return the number of dynamic relocation records generated} + */ + public int getDrelocCount() { + return drelocCount; + } + + /** + * {@return the offset in the $DATA$ space of the Data Linkage Table} + */ + public int getDltLoc() { + return dltLoc; + } + + /** + * {@return the offset in the $DATA$ space of the Procedure Linkage Table} + */ + public int getPltLoc() { + return pltLoc; + } + + /** + * {@return the number of entries in the DLT} + */ + public int getDltCount() { + return dltCount; + } + + /** + * {@return the number of entries in the PLT} + */ + public int getPltCount() { + return pltCount; + } + + /** + * {@return the highest version number of any symbol defined in the shared library or in the + * set of highwater marks of the shared libraries in the shared library list} + */ + public short getHighwaterMark() { + return highwaterMark; + } + + /** + * {@return the flags} + */ + public short getFlags() { + return flags; + } + + /** + * {@return the text-relative offset of the export extension table} + */ + public int getExportExtLoc() { + return exportExtLoc; + } + + /** + * {@return the text-relative offset of the module table} + */ + public int getModuleLoc() { + return moduleLoc; + } + + /** + * {@return the number of modules in the module table} + */ + public int getModuleCount() { + return moduleCount; + } + + /** + * {@return the index into the import table if the elab_ref bit in the flags field is set} + */ + public int getElaborator() { + return elaborator; + } + + /** + * {@return the index into the import table if the init_ref bit in the flags field is set and + * the initializer_count field is set 0} + */ + public int getInitializer() { + return initializer; + } + + /** + * {@return the index into the shared library string table} + */ + public int getEmbeddedPath() { + return embeddedPath; + } + + /** + * {@return the number of initializers declared} + */ + public int getInitializerCount() { + return initializerCount; + } + + /** + * {@return the size of the TSD area} + */ + public int getTdsize() { + return tdsize; + } + + /** + * {@return the text-relative offset of fastbind info} + */ + public int getFastbindListLoc() { + return fastbindListLoc; + } + + /** + * {@return the {@link Address} of the "text" space} + */ + public Address getTextAddress() { + return textAddr; + } + + /** + * {@return the {@link Address} of the "data" space} + */ + public Address getDataAddress() { + return dataAddr; + } + + /** + * {@return the {@link List} of {@link SomShlibListEntry shared library entries}} + */ + public List getShlibs() { + return shlibs; + } + + /** + * {@return the {@link List} of {@link SomImportEntry import entries}} + */ + public List getImports() { + return imports; + } + + /** + * {@return the {@link List} of {@link SomExportEntry export entries}} + */ + public List getExports() { + return exports; + } + + /** + * {@return the {@link List} of {@link SomDynamicRelocation dynamic relocation entries}} + */ + public List getDynamicRelocations() { + return drelocs; + } + + /** + * {@return the {@link List} of {@link SomPltEntry PLT entries}} + */ + public List getPlt() { + return plt; + } + + /** + * {@return the {@link List} of {@link SomDltEntry DLT entries}} + */ + public List getDlt() { + return dlt; + } + + /** + * {@return the {@link List} of {@link SomExportEntryExt export entry extensions} + */ + public List getExportExtensions() { + return exportExtensions; + } + + /** + * {@return the {@link List} of {@link SomModuleEntry module entries}} + */ + public List getModules() { + return modules; + } + + /** + * Marks up this header + * + * @param program The {@link Program} + * @param monitor A cancellable monitor + * @throws Exception if there was a problem during markup + */ + public void markup(Program program, TaskMonitor monitor) throws Exception { + Listing listing = program.getListing(); + + DataUtilities.createData(program, textAddr, toDataType(), -1, CHECK_FOR_SPACE); + + monitor.initialize(shlibListCount, "Marking up shared library list..."); + for (int i = 0; i < shlibListCount; i++) { + monitor.increment(); + SomShlibListEntry shlib = shlibs.get(i); + Address addr = textAddr.add(shlibListLoc + i * SomShlibListEntry.SIZE); + DataUtilities.createData(program, addr, shlib.toDataType(), -1, CHECK_FOR_SPACE); + listing.setComment(addr, CommentType.EOL, shlib.getShlibName()); + } + + monitor.initialize(importListCount, "Marking up imports list..."); + for (int i = 0; i < importListCount; i++) { + monitor.increment(); + SomImportEntry entry = imports.get(i); + Address addr = textAddr.add(importListLoc + i * SomImportEntry.SIZE); + DataUtilities.createData(program, addr, entry.toDataType(), -1, CHECK_FOR_SPACE); + listing.setComment(addr, CommentType.EOL, entry.getName()); + } + + monitor.initialize(exportListCount, "Marking up exports list..."); + for (int i = 0; i < exportListCount; i++) { + monitor.increment(); + SomExportEntry entry = exports.get(i); + Address addr = textAddr.add(exportListLoc + i * SomExportEntry.SIZE); + DataUtilities.createData(program, addr, entry.toDataType(), -1, CHECK_FOR_SPACE); + listing.setComment(addr, CommentType.EOL, entry.getName()); + } + + monitor.initialize(drelocCount, "Marking up dreloc list..."); + for (int i = 0; i < drelocCount; i++) { + monitor.increment(); + SomDynamicRelocation entry = drelocs.get(i); + Address addr = textAddr.add(drelocLoc + i * SomDynamicRelocation.SIZE); + DataUtilities.createData(program, addr, entry.toDataType(), -1, CHECK_FOR_SPACE); + switch (entry.getType()) { + case SomConstants.DR_PLABEL_EXT: + case SomConstants.DR_DATA_EXT: + listing.setComment(addr, CommentType.EOL, + imports.get(entry.getSymbol()).getName()); + } + } + + monitor.initialize(dltCount, "Marking up DLT entries..."); + for (int i = 0; i < dltCount; i++) { + monitor.increment(); + SomDltEntry entry = dlt.get(i); + Address addr = dataAddr.add(dltLoc + i * SomDltEntry.SIZE); + DataUtilities.createData(program, addr, entry.toDataType(), -1, CHECK_FOR_SPACE); + } + + monitor.initialize(pltCount, "Marking up PLT entries..."); + for (int i = 0; i < pltCount; i++) { + monitor.increment(); + SomPltEntry entry = plt.get(i); + Address addr = dataAddr.add(pltLoc + i * SomPltEntry.SIZE); + DataUtilities.createData(program, addr, entry.toDataType(), -1, CHECK_FOR_SPACE); + } + + monitor.initialize(exportListCount, "Marking up export extensions list..."); + for (int i = 0; i < exportListCount && exportExtLoc > 0; i++) { + monitor.increment(); + SomExportEntryExt entry = exportExtensions.get(i); + Address addr = textAddr.add(exportExtLoc + i * SomExportEntryExt.SIZE); + DataUtilities.createData(program, addr, entry.toDataType(), -1, CHECK_FOR_SPACE); + listing.setComment(addr, CommentType.EOL, exports.get(i).getName()); + } + + monitor.initialize(moduleCount, "Marking up modules list..."); + for (int i = 0; i < moduleCount; i++) { + monitor.increment(); + SomModuleEntry entry = modules.get(i); + Address addr = textAddr.add(moduleLoc + i * SomModuleEntry.SIZE); + DataUtilities.createData(program, addr, entry.toDataType(), -1, CHECK_FOR_SPACE); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("dl_header", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "hdr_version", "header version number"); + struct.add(DWORD, "ltptr_value", "data offset of LT pointer (R19)"); + struct.add(DWORD, "shlib_list_loc", "text offset of shlib list"); + struct.add(DWORD, "shlib_list_count", "count of items in shlib list"); + struct.add(DWORD, "import_list_loc", "text offset of import list"); + struct.add(DWORD, "import_list_count", "count of items in import list"); + struct.add(DWORD, "hash_table_loc", "text offset of export hash table"); + struct.add(DWORD, "hash_table_size", "count of slots in export hash table"); + struct.add(DWORD, "export_list_loc", "text offset of export list"); + struct.add(DWORD, "export_list_count", "count of items in export list"); + struct.add(DWORD, "string_table_loc", "text offset of string table"); + struct.add(DWORD, "string_table_size", "length in bytes of string table"); + struct.add(DWORD, "dreloc_loc", "text offset of dynamic reloc records"); + struct.add(DWORD, "dreloc_count", "number of dynamic relocation records"); + struct.add(DWORD, "dlt_loc", "data offset of data linkage table"); + struct.add(DWORD, "plt_loc", "data offset of procedure linkage table"); + struct.add(DWORD, "dlt_count", "number of dlt entries in linkage table"); + struct.add(DWORD, "plt_count", "number of plt entries in linkage table"); + struct.add(WORD, "highwater_mark", "highest version number seen in lib or in shlib list"); + struct.add(WORD, "flags", "various flags"); + struct.add(DWORD, "export_ext_loc", "text offset of export extension tbl"); + struct.add(DWORD, "module_loc", "text offset of module table"); + struct.add(DWORD, "module_count", "number of module entries"); + struct.add(DWORD, "elaborator", "import index of elaborator"); + struct.add(DWORD, "initializer", "import index of initializer"); + struct.add(DWORD, "embedded_path", "index into string table for search path"); + struct.add(DWORD, "initializer_count", "count of items in initializer import list"); + struct.add(DWORD, "tdsize", "size of the TSD area"); + struct.add(DWORD, "fastbind_list_loc", "text-relative offset of fastbind info"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDynamicRelocation.java new file mode 100644 index 0000000000..9c03044e5b --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomDynamicRelocation.java @@ -0,0 +1,126 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code dreloc_record} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomDynamicRelocation implements StructConverter { + + /** The size in bytes of a {@link SomDynamicRelocation} */ + public static final int SIZE = 0x14; + + private int shlib; + private int symbol; + private int location; + private int value; + private int type; + private byte reserved; + private short moduleIndex; + + /** + * Creates a new {@link SomDynamicRelocation} + * + * @param reader A {@link BinaryReader} positioned at the start of the dynamic relocation list + * @throws IOException if there was an IO-related error + */ + public SomDynamicRelocation(BinaryReader reader) throws IOException { + shlib = reader.readNextInt(); + symbol = reader.readNextInt(); + location = reader.readNextInt(); + value = reader.readNextInt(); + type = reader.readNextUnsignedByte(); + reserved = reader.readNextByte(); + moduleIndex = reader.readNextShort(); + } + + /** + * {@return the shared library name (currently a reserved field)} + */ + public int getShlib() { + return shlib; + } + + /** + * {@return the index into the import table if the relocation is an external type} + */ + public int getSymbol() { + return symbol; + } + + /** + * {@return the data-relative offset of the data item the dreloc record refers to} + */ + public int getLocation() { + return location; + } + + /** + * {@return the text or data-relative offset to use for a patch if it is an internal fixup type} + */ + public int getValue() { + return value; + } + + /** + * {@return the type of dynamic relocation} + * + * @see SomConstants + */ + public int getType() { + return type; + } + + /** + * {@return the reserved value} + */ + public byte getReserved() { + return reserved; + } + + /** + * {@return the module index (currently reserved)} + */ + public short getModuleIndex() { + return moduleIndex; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("dreloc_record", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "shlib", "reserved"); + struct.add(DWORD, "symbol", + "index into import table of shlib if *_EXT type. low order 16 bits used for module index if *_INT type"); + struct.add(DWORD, "location", "offset of location to patch data-relative"); + struct.add(DWORD, "value", + "text or data-relative offset to use for patch if internal-type fixup"); + struct.add(BYTE, "type", "type of dreloc record"); + struct.add(BYTE, "reserved", "currently unused"); + struct.add(WORD, "module_index", "reserved"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExecAuxHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExecAuxHeader.java new file mode 100644 index 0000000000..a39aa8948b --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExecAuxHeader.java @@ -0,0 +1,150 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code som_exec_auxhdr} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomExecAuxHeader extends SomAuxHeader { + + private long execTextSize; + private long execTextMem; + private long execTextFile; + private long execDataSize; + private long execDataMem; + private long execDataFile; + private long execBssSize; + private long execEntry; + private long execFlags; + private long execBssFill; + + /** + * Creates a new {@link SomExecAuxHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the auxiliary header + * @throws IOException if there was an IO-related error + */ + public SomExecAuxHeader(BinaryReader reader) throws IOException { + super(reader); + execTextSize = reader.readNextUnsignedInt(); + execTextMem = reader.readNextUnsignedInt(); + execTextFile = reader.readNextUnsignedInt(); + execDataSize = reader.readNextUnsignedInt(); + execDataMem = reader.readNextUnsignedInt(); + execDataFile = reader.readNextUnsignedInt(); + execBssSize = reader.readNextUnsignedInt(); + execEntry = reader.readNextUnsignedInt(); + execFlags = reader.readNextUnsignedInt(); + execBssFill = reader.readNextUnsignedInt(); + } + + /** + * {@return the text size in bytes} + */ + public long getExecTextSize() { + return execTextSize; + } + + /** + * {@return the offset of text in memory} + */ + public long getExecTextMem() { + return execTextMem; + } + + /** + * {@return the location of text in file} + */ + public long getExecTextFile() { + return execTextFile; + } + + /** + * {@return the initialized data size in bytes} + */ + public long getExecDataSize() { + return execDataSize; + } + + /** + * {@return the offset of data in memory} + */ + public long getExecDataMem() { + return execDataMem; + } + + /** + * {@return the location of data in file} + */ + public long getExecDataFile() { + return execDataFile; + } + + /** + * {@return the uninitialized data (BSS) size in bytes} + */ + public long getExecBssSize() { + return execBssSize; + } + + /** + * {@return the offset of entrypoint} + */ + public long getExecEntry() { + return execEntry; + } + + /** + * {@return the loader flags} + */ + public long getExecFlags() { + return execFlags; + } + + /** + * {@return BSS initialization value} + */ + public long getExecBssFill() { + return execBssFill; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("som_exec_auxhdr", 0); + struct.setPackingEnabled(true); + struct.add(auxId.toDataType(), "som_auxhdr", null); + struct.add(DWORD, "exec_tsize", "text size in bytes"); + struct.add(DWORD, "exec_tmem", "offset of text in memory"); + struct.add(DWORD, "exec_tfile", "location of text in file"); + struct.add(DWORD, "exec_dsize", "initialized data size in bytes"); + struct.add(DWORD, "exec_dmem", "offset of data in memory"); + struct.add(DWORD, "exec_dfile", "location of data in file"); + struct.add(DWORD, "exec_bsize", "uninitialized data (bss) size in bytes"); + struct.add(DWORD, "exec_entry", "offset of entrypoint"); + struct.add(DWORD, "exec_flags", "loader flags"); + struct.add(DWORD, "exec_bfill", "bss initialization value"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExportEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExportEntry.java new file mode 100644 index 0000000000..a937fcb203 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExportEntry.java @@ -0,0 +1,160 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code export_entry} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomExportEntry implements StructConverter { + + /** The size in bytes of a {@link SomExportEntry} */ + public static final int SIZE = 0x14; + + private int next; + private String name; + private int value; + private int info; + private int type; + private boolean isTpRelative; + private int reserved1; + private short moduleIndex; + + /** + * Creates a new {@link SomExportEntry} + * + * @param reader A {@link BinaryReader} positioned at the start of the export list + * @param stringTableLoc The location of the string table + * @throws IOException if there was an IO-related error + */ + public SomExportEntry(BinaryReader reader, long stringTableLoc) throws IOException { + next = reader.readNextInt(); + int nameIndex = reader.readNextInt(); + name = nameIndex != -1 ? reader.readAsciiString(stringTableLoc + nameIndex) : null; + value = reader.readNextInt(); + info = reader.readNextInt(); + type = reader.readNextUnsignedByte(); + int bitfield = reader.readNextUnsignedByte(); + reserved1 = bitfield & 0x7f; + isTpRelative = ((bitfield >> 7) & 0x1) != 0; + moduleIndex = reader.readNextShort(); + } + + /** + * {@return the next export record in the hash chain} + */ + public int getNext() { + return next; + } + + /** + * {@return the symbol name} + */ + public String getName() { + return name; + } + + /** + * {@return the symbol address (subject to relocation)} + */ + public int getValue() { + return value; + } + + /** + * {@return the size of the storage request if exported symbol is of type {@code STORAGE}, or + * the version of the exported symbol along with argument relocation information} + */ + public int getInfo() { + return info; + } + + /** + * {@return the symbol type} + * + * @see SomConstants + */ + public int getType() { + return type; + } + + /** + * {@return whether or not this is a TLS export} + */ + public boolean isTpRelative() { + return isTpRelative; + } + + /** + * {@return the first reserved value} + */ + public int getReserved1() { + return reserved1; + } + + /** + * {@return the index into the module table of the module defining this symbol} + */ + public short getModuleIndex() { + return moduleIndex; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType miscInfoStruct = new StructureDataType("misc_info", 4); + miscInfoStruct.setPackingEnabled(true); + miscInfoStruct.add(WORD, "version", "months since January, 1990"); + try { + miscInfoStruct.addBitField(WORD, 6, "reserved2", null); + miscInfoStruct.addBitField(WORD, 10, "arg_reloc", "parameter relocation bits (5*2)"); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + miscInfoStruct.setCategoryPath(new CategoryPath("/SOM")); + + UnionDataType infoUnion = new UnionDataType("info"); + infoUnion.add(DWORD, "size", "storage request area size in bytes"); + infoUnion.add(miscInfoStruct, "misc", "version, etc. N/A to storage requests"); + infoUnion.setCategoryPath(new CategoryPath("/SOM")); + + StructureDataType struct = new StructureDataType("export_entry", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "next", "index of next export entry in hash chain"); + struct.add(DWORD, "name", "offset within string table"); + struct.add(DWORD, "value", "offset of symbol (subject to relocation)"); + struct.add(infoUnion, "info", null); + struct.add(BYTE, "type", "symbol type"); + try { + struct.addBitField(BYTE, 1, "is_tp_relative", "TLS export"); + struct.addBitField(BYTE, 7, "reserved1", "reserved"); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(WORD, "module_index", "index of module defining symbol"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExportEntryExt.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExportEntryExt.java new file mode 100644 index 0000000000..75baef79fe --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomExportEntryExt.java @@ -0,0 +1,103 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code export_entry_ext} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomExportEntryExt implements StructConverter { + + /** The size in bytes of a {@link SomExportEntryExt} */ + public static final int SIZE = 0x14; + + private int size; + private int dreloc; + private int sameList; + private int reserved2; + private int reserved3; + + /** + * Creates a new {@link SomExportEntryExt} + * + * @param reader A {@link BinaryReader} positioned at the start of the export extension list + * @throws IOException if there was an IO-related error + */ + public SomExportEntryExt(BinaryReader reader) throws IOException { + size = reader.readNextInt(); + dreloc = reader.readNextInt(); + sameList = reader.readNextInt(); + reserved2 = reader.readNextInt(); + reserved3 = reader.readNextInt(); + } + + /** + * {@return the size of the export symbol and is only valid for exports of type {@code ST_DATA} + */ + public int getSize() { + return size; + } + + /** + * {@return the start of the dreloc records for the exported symbol} + */ + public int getDreloc() { + return dreloc; + } + + /** + * {@return the circular list of exports that have the same value (physical location) in the + * library} + */ + public int getSameList() { + return sameList; + } + + /** + * {@return the second reserved value} + */ + public int getReserved2() { + return reserved2; + } + + /** + * {@return the third reserved value} + */ + public int getReserved3() { + return reserved3; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("export_entry_ext", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "size", "export symbol size, data only"); + struct.add(DWORD, "dreloc", "start of dreloc for this symbol"); + struct.add(DWORD, "same_list", "circular list of exports that have the same value"); + struct.add(DWORD, "reserved2", null); + struct.add(DWORD, "reserved3", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomHeader.java new file mode 100644 index 0000000000..8eab52fc09 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomHeader.java @@ -0,0 +1,605 @@ +/* ### + * 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.som; + +import static ghidra.app.util.bin.format.som.SomConstants.*; +import static ghidra.program.model.data.DataUtilities.ClearDataMode.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.CommentType; +import ghidra.program.model.listing.Program; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a SOM {@code header} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomHeader implements StructConverter { + + /** The size in bytes of a {@link SomHeader} */ + public static final int SIZE = 0x80; + + private int systemId; + private int magic; + private long versionId; + private SomSysClock fileTime; + private long entrySpace; + private long entrySubspace; + private long entryOffset; + private long auxHeaderLocation; + private long auxHeaderSize; + private long somLength; + private long presumedDp; + private long spaceLocation; + private long spaceTotal; + private long subspaceLocation; + private long subspaceTotal; + private long loaderFixupLocation; + private long loaderFixupTotal; + private long spaceStringsLocation; + private long spaceStringsSize; + private long initArrayLocation; + private long initArrayTotal; + private long compilerLocation; + private long compilerTotal; + private long symbolLocation; + private long symbolTotal; + private long fixupRequestLocation; + private long fixupRequestTotal; + private long symbolStringsLocation; + private long symbolStringsSize; + private long unloadableSpLocation; + private long unloadableSpSize; + private long checksum; + + private List spaces = new ArrayList<>(); + private List subspaces = new ArrayList<>(); + private List auxHeaders = new ArrayList<>(); + private List compilationUnits = new ArrayList<>(); + private List symbols = new ArrayList<>(); + + /** + * Creates a new {@link SomHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the header + * @throws IOException if there was an IO-related error + */ + public SomHeader(BinaryReader reader) throws IOException { + systemId = reader.readNextUnsignedShort(); + magic = reader.readNextUnsignedShort(); + versionId = reader.readNextUnsignedInt(); + fileTime = new SomSysClock(reader); + entrySpace = reader.readNextUnsignedInt(); + entrySubspace = reader.readNextUnsignedInt(); + entryOffset = reader.readNextUnsignedInt(); + auxHeaderLocation = reader.readNextUnsignedInt(); + auxHeaderSize = reader.readNextUnsignedInt(); + somLength = reader.readNextUnsignedInt(); + presumedDp = reader.readNextUnsignedInt(); + spaceLocation = reader.readNextUnsignedInt(); + spaceTotal = reader.readNextUnsignedInt(); + subspaceLocation = reader.readNextUnsignedInt(); + subspaceTotal = reader.readNextUnsignedInt(); + loaderFixupLocation = reader.readNextUnsignedInt(); + loaderFixupTotal = reader.readNextUnsignedInt(); + spaceStringsLocation = reader.readNextUnsignedInt(); + spaceStringsSize = reader.readNextUnsignedInt(); + initArrayLocation = reader.readNextUnsignedInt(); + initArrayTotal = reader.readNextUnsignedInt(); + compilerLocation = reader.readNextUnsignedInt(); + compilerTotal = reader.readNextUnsignedInt(); + symbolLocation = reader.readNextUnsignedInt(); + symbolTotal = reader.readNextUnsignedInt(); + fixupRequestLocation = reader.readNextUnsignedInt(); + fixupRequestTotal = reader.readNextUnsignedInt(); + symbolStringsLocation = reader.readNextUnsignedInt(); + symbolStringsSize = reader.readNextUnsignedInt(); + unloadableSpLocation = reader.readNextUnsignedInt(); + unloadableSpSize = reader.readNextUnsignedInt(); + checksum = reader.readNextUnsignedInt(); + + if (spaceLocation > 0) { + reader.setPointerIndex(spaceLocation); + for (int i = 0; i < spaceTotal; i++) { + spaces.add(new SomSpace(reader, spaceStringsLocation)); + } + } + + if (subspaceLocation > 0) { + reader.setPointerIndex(subspaceLocation); + for (int i = 0; i < subspaceTotal; i++) { + subspaces.add(new SomSubspace(reader, spaceStringsLocation)); + } + } + + if (auxHeaderLocation > 0) { + reader.setPointerIndex(auxHeaderLocation); + long sizeRemaining = auxHeaderSize; + while (sizeRemaining > 0) { + SomAuxHeader auxHeader = SomAuxHeaderFactory.readNextAuxHeader(reader); + auxHeaders.add(auxHeader); + sizeRemaining -= auxHeader.getAuxId().getLength() + SomAuxId.SIZE; + } + } + + if (compilerLocation > 0) { + reader.setPointerIndex(compilerLocation); + for (int i = 0; i < compilerTotal; i++) { + compilationUnits.add(new SomCompilationUnit(reader, symbolStringsLocation)); + } + } + + if (symbolLocation > 0) { + reader.setPointerIndex(symbolLocation); + for (int i = 0; i < symbolTotal; i++) { + symbols.add(new SomSymbol(reader, symbolStringsLocation)); + } + } + } + + /** + * {@return the system ID} + */ + public int getSystemId() { + return systemId; + } + + /** + * {@return the magic} + */ + public int getMagic() { + return magic; + } + + /** + * {@return true if this {@link SomHeader} has a valid magic number; otherwise false} + */ + public boolean hasValidMagic() { + return switch (magic) { + case MAGIC_LIBRARY: + case MAGIC_RELOCATABLE: + case MAGIC_NON_SHAREABLE_EXE: + case MAGIC_SHAREABLE_EXE: + case MAGIC_SHARABLE_DEMAND_LOADABLE_EXE: + case MAGIC_DYNAMIC_LOAD_LIBRARY: + case MAGIC_SHARED_LIBRARY: + case MAGIC_RELOCATABLE_LIBRARY: + yield true; + default: + yield false; + }; + } + + /** + * {@return the version ID} + */ + public long getVersionId() { + return versionId; + } + + /** + * {@return true if this {@link SomHeader} has a valid version ID; otherwise false} + */ + public boolean hasValidVersionId() { + return versionId == 85082112 || versionId == 87102412; + } + + /** + * {@return the file time} + */ + public SomSysClock getFileType() { + return fileTime; + } + + /** + * {@return the index of space containing entry point} + */ + public long getEntrySpace() { + return entrySpace; + } + + /** + * {@return the index of subspace for entry point} + */ + public long getEntrySubspace() { + return entrySubspace; + } + + /** + * {@return the offset of entry point} + */ + public long getEntryOffset() { + return entryOffset; + } + + /** + * {@return the auxiliary header location} + */ + public long getAuxHeaderLocation() { + return auxHeaderLocation; + } + + /** + * {@return the auxiliary header size} + */ + public long getAuxHeaderSize() { + return auxHeaderSize; + } + + /** + * {@return the length in bytes of entire som} + */ + public long getSomLength() { + return somLength; + } + + /** + * {@return the DP value assumed during compilation} + */ + public long getPresumedDp() { + return presumedDp; + } + + /** + * {@return the location in file of space dictionary} + */ + public long getSpaceLocation() { + return spaceLocation; + } + + /** + * {@return the number of space entries} + */ + public long getSpaceTotal() { + return spaceTotal; + } + + /** + * {@return the location of subspace entries} + */ + public long getSubspaceLocation() { + return subspaceLocation; + } + + /** + * {@return the number of subspace entries} + */ + public long getSubspaceTotal() { + return subspaceTotal; + } + + /** + * {@return the MPE/iX loader fixup location} + */ + public long getLoaderFixupLocation() { + return loaderFixupLocation; + } + + /** + * {@return the number of loader fixup records} + */ + public long getLoaderFixupTotal() { + return loaderFixupTotal; + } + + /** + * {@return the file location of string area for space and subspace names} + */ + public long getSpaceStringsLocation() { + return spaceStringsLocation; + } + + /** + * {@return the size of string area for space and subspace names} + */ + public long getSpaceStringsSize() { + return spaceStringsSize; + } + + /** + * {@return the init array location} + */ + public long getInitArrayLocation() { + return initArrayLocation; + } + + /** + * {@return the init array total} + */ + public long getInitArrayTotal() { + return initArrayTotal; + } + + /** + * {@return the location in file of module dictionary} + */ + public long getCompilerLocation() { + return compilerLocation; + } + + /** + * {@return the number of modules} + */ + public long getCompilerTotal() { + return compilerTotal; + } + + /** + * {@return the location in file of symbol dictionary} + */ + public long getSymbolLocation() { + return symbolLocation; + } + + /** + * {@return the number of symbol records} + */ + public long getSymbolTotal() { + return symbolTotal; + } + + /** + * {@return the location in file of fixup requests} + */ + public long getFixupRequestLocation() { + return fixupRequestLocation; + } + + /** + * {@return the number of fixup requests} + */ + public long getFixupRequestTotal() { + return fixupRequestTotal; + } + + /** + * {@return the file location of string area for module and symbol names} + */ + public long getSymbolStringsLocation() { + return symbolStringsLocation; + } + + /** + * {@return the size of string area for module and symbol names} + */ + public long getSymbolStringsSize() { + return symbolStringsSize; + } + + /** + * {@return the byte offset of first byte of data for unloadable spaces} + */ + public long getUnloadableSpLocation() { + return unloadableSpLocation; + } + + /** + * {@return the byte length of data for unloadable spaces} + */ + public long getUnloadableSpSize() { + return unloadableSpSize; + } + + /** + * {@return the checksum} + */ + public long getChecksum() { + return checksum; + } + + /** + * {@return the {@link List} of {@link SomSpace spaces}} + */ + public List getSpaces() { + return new ArrayList<>(spaces); + } + + /** + * {@return the {@link List} of {@link SomSubspace subspaces}} + */ + public List getSubspaces() { + return subspaces; + } + + /** + * {@return the {@link List} of {@link SomAuxHeader auxiliary headers}} + */ + public List getAuxHeaders() { + return auxHeaders; + } + + /** + * {@return the {@link List} of {@link SomAuxHeader auxiliary headers}} of the given type} + * + * @param The type of auxiliary header to get + * @param classType The type of auxiliary header to get + */ + public List getAuxHeaders(Class classType) { + List tmp = new ArrayList<>(); + for (SomAuxHeader auxHeader : auxHeaders) { + if (classType.isAssignableFrom(auxHeader.getClass())) { + tmp.add(classType.cast(auxHeader)); + } + } + return tmp; + } + + /** + * {@return the first found {@link SomAuxHeader auxiliary header}} of the given type} + * + * @param The type of auxiliary header to get + * @param classType The type of auxiliary header to get + */ + public T getFirstAuxHeader(Class classType) { + for (SomAuxHeader auxHeader : auxHeaders) { + if (classType.isAssignableFrom(auxHeader.getClass())) { + return classType.cast(auxHeader); + } + } + return null; + } + + /** + * {@return the {@link List} of {@link SomCompilationUnit compilation units}} + */ + public List getCompilationUnits() { + return compilationUnits; + } + + /** + * {@return the {@link List} of {@link SomSymbol symbols}} + */ + public List getSymbols() { + return symbols; + } + + /** + * {@return the starting address of the "text" space} + * + * @param program The {@link Program} + * @throws Exception if there was a problem getting the address + */ + public Address getTextAddress(Program program) throws Exception { + // Assuming that the text space is the first space + return program.getAddressFactory() + .getDefaultAddressSpace() + .getAddress(subspaces.get(spaces.get(0).getSubspaceIndex()).getSubspaceStart()); + } + + /** + * {@return the starting address of the "data" space, or {@code null} if it wasn't found} + * + * @param program The {@link Program} + * @throws Exception if there was a problem getting the address + */ + public Address getDataAddress(Program program) throws Exception { + // Assuming that the text space is the second space + return program.getAddressFactory() + .getDefaultAddressSpace() + .getAddress(subspaces.get(spaces.get(1).getSubspaceIndex()).getSubspaceStart()); + } + + /** + * Marks up this header + * + * @param program The {@link Program} + * @param headerAddr The {@link Address} of this header + * @param monitor A cancellable monitor + * @throws Exception if there was a problem during markup + */ + public void markup(Program program, Address headerAddr, TaskMonitor monitor) throws Exception { + DataUtilities.createData(program, headerAddr, toDataType(), -1, CHECK_FOR_SPACE); + + monitor.initialize(spaceTotal, "Marking up spaces..."); + for (int i = 0; i < spaceTotal; i++) { + monitor.increment(); + SomSpace space = spaces.get(i); + Address addr = headerAddr.add(spaceLocation + i * SomSpace.SIZE); + DataUtilities.createData(program, addr, space.toDataType(), -1, CHECK_FOR_SPACE); + program.getListing().setComment(addr, CommentType.EOL, space.getName()); + } + + monitor.initialize(subspaceTotal, "Marking up subspaces..."); + for (int i = 0; i < subspaceTotal; i++) { + monitor.increment(); + SomSubspace subspace = subspaces.get(i); + Address addr = headerAddr.add(subspaceLocation + i * SomSubspace.SIZE); + DataUtilities.createData(program, addr, subspace.toDataType(), -1, CHECK_FOR_SPACE); + program.getListing().setComment(addr, CommentType.EOL, subspace.getName()); + } + + monitor.initialize(auxHeaders.size(), "Marking up auxiliary headers..."); + Address auxHeaderAddr = headerAddr.add(auxHeaderLocation); + for (SomAuxHeader auxHeader : auxHeaders) { + monitor.increment(); + DataUtilities.createData(program, auxHeaderAddr, auxHeader.toDataType(), -1, + CHECK_FOR_SPACE); + auxHeaderAddr = auxHeaderAddr.add(auxHeader.getLength()); + } + + monitor.initialize(compilerTotal, "Marking up compilation units..."); + for (int i = 0; i < compilerTotal; i++) { + monitor.increment(); + SomCompilationUnit unit = compilationUnits.get(i); + Address addr = headerAddr.add(compilerLocation + i * SomCompilationUnit.SIZE); + DataUtilities.createData(program, addr, unit.toDataType(), -1, CHECK_FOR_SPACE); + program.getListing().setComment(addr, CommentType.EOL, unit.getName()); + } + + monitor.initialize(symbolTotal, "Marking up symbols..."); + for (int i = 0; i < symbolTotal; i++) { + monitor.increment(); + SomSymbol symbol = symbols.get(i); + Address addr = headerAddr.add(symbolLocation + i * SomSymbol.SIZE); + DataUtilities.createData(program, addr, symbol.toDataType(), -1, CHECK_FOR_SPACE); + program.getListing().setComment(addr, CommentType.EOL, symbol.getName()); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("header", SIZE); + struct.setPackingEnabled(true); + struct.add(WORD, "system_id", "magic number - system"); + struct.add(WORD, "a_magic", "magic number - file type"); + struct.add(DWORD, "version_id", "version id; format=YYMMDDHH"); + struct.add(fileTime.toDataType(), "file_time", "system clock- zero if unused"); + struct.add(DWORD, "entry_space", "index of space containing entry point"); + struct.add(DWORD, "entry_subspace", "index of subspace for entry point"); + struct.add(DWORD, "entry_offset", "offset of entry point"); + struct.add(DWORD, "aux_header_location", "auxiliary header location"); + struct.add(DWORD, "aux_header_size", "auxiliary header size"); + struct.add(DWORD, "som_length", "length in bytes of entire som"); + struct.add(DWORD, "presumed_dp", "DP value assumed during compilation"); + struct.add(DWORD, "space_location", "location in file of space dictionary"); + struct.add(DWORD, "space_total", "number of space entries"); + struct.add(DWORD, "subspace_location", "location of subspace entries"); + struct.add(DWORD, "subspace_total", "number of subspace entries"); + struct.add(DWORD, "loader_fixup_location", "MPE/iX loader fixup"); + struct.add(DWORD, "loader_fixup_total", "number of loader fixup records"); + struct.add(DWORD, "space_strings_location", + "file location of string area for space and subspace names"); + struct.add(DWORD, "space_strings_size", "size of string area for space and subspace names"); + struct.add(DWORD, "init_array_location", "reserved for use by system"); + struct.add(DWORD, "init_array_total", "reserved for use by system"); + struct.add(DWORD, "compiler_location", "location in file of module dictionary"); + struct.add(DWORD, "compiler_total", "number of modules"); + struct.add(DWORD, "symbol_location", "location in file of symbol dictionary"); + struct.add(DWORD, "symbol_total", "number of symbol records"); + struct.add(DWORD, "fixup_request_location", "location in file of fixup requests"); + struct.add(DWORD, "fixup_request_total", "number of fixup requests"); + struct.add(DWORD, "symbol_strings_location", + "file location of string area for module and symbol names"); + struct.add(DWORD, "symbol_strings_size", "size of string area for module and symbol names"); + struct.add(DWORD, "unloadable_sp_location", + "byte offset of first byte of data for unloadable spaces"); + struct.add(DWORD, "unloadable_sp_size", "byte length of data for unloadable spaces"); + struct.add(DWORD, "checksum", ""); + + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomImportEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomImportEntry.java new file mode 100644 index 0000000000..179027d67f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomImportEntry.java @@ -0,0 +1,110 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code import_entry} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomImportEntry implements StructConverter { + + /** The size in bytes of a {@link SomImportEntry} */ + public static final int SIZE = 0x8; + + private String name; + private int reserved2; + private int type; + private boolean bypassable; + private int reserved1; + + /** + * Creates a new {@link SomImportEntry} + * + * @param reader A {@link BinaryReader} positioned at the start of the import list + * @param stringTableLoc The location of the string table + * @throws IOException if there was an IO-related error + */ + public SomImportEntry(BinaryReader reader, long stringTableLoc) throws IOException { + int nameIndex = reader.readNextInt(); + name = nameIndex != -1 ? reader.readAsciiString(stringTableLoc + nameIndex) : null; + int bitfield = reader.readNextInt(); + reserved1 = bitfield & 0x7f; + bypassable = ((bitfield >> 7) & 0x1) != 0; + type = (bitfield >> 8) & 0xff; + reserved2 = (bitfield >> 16) & 0xffff; + } + + /** + * {@return the name of the import, or {@code null} if it doesn't have one} + */ + public String getName() { + return name; + } + + /** + * {@return the second reserved value} + */ + public int getReserved2() { + return reserved2; + } + + /** + * {@return the symbol type (text, data, or bss)} + */ + public int getType() { + return type; + } + + /** + * {@return whether or not code imports do not have their address taken in that shared library} + */ + public boolean isBypassable() { + return bypassable; + } + + /** + * {@return the first reserved value} + */ + public int getReserved1() { + return reserved1; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("import_entry", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "name", "offset in string table"); + try { + struct.addBitField(DWORD, 16, "reserved2", "unused"); + struct.addBitField(DWORD, 8, "type", "symbol type"); + struct.addBitField(DWORD, 1, "bypassable", "address of code symbol not taken in shlib"); + struct.addBitField(DWORD, 7, "reserved1", "unused"); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomLinkerFootprintAuxHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomLinkerFootprintAuxHeader.java new file mode 100644 index 0000000000..acff6bce7e --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomLinkerFootprintAuxHeader.java @@ -0,0 +1,81 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code linker_footprint} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomLinkerFootprintAuxHeader extends SomAuxHeader { + + private String productId; + private String versionId; + private SomSysClock htime; + + /** + * Creates a new {@link SomLinkerFootprintAuxHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the auxiliary header + * @throws IOException if there was an IO-related error + */ + public SomLinkerFootprintAuxHeader(BinaryReader reader) throws IOException { + super(reader); + productId = reader.readNextAsciiString(12); + versionId = reader.readNextAsciiString(12); + htime = new SomSysClock(reader); + } + + /** + * {@return the product ID} + */ + public String getProductId() { + return productId; + } + + /** + * {@return the version ID} + */ + public String getVersionId() { + return versionId; + } + + /** + * {@return the htime} + */ + public SomSysClock getHtime() { + return htime; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("linker_footprint", 0); + struct.setPackingEnabled(true); + struct.add(auxId.toDataType(), "som_auxhdr", null); + struct.add(STRING, 12, "product_id", null); + struct.add(STRING, 8, "version_id", null); + struct.add(htime.toDataType(), "htime", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomModuleEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomModuleEntry.java new file mode 100644 index 0000000000..7d74a97c16 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomModuleEntry.java @@ -0,0 +1,123 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code module_entry} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomModuleEntry implements StructConverter { + + /** The size in bytes of a {@link SomModuleEntry} */ + public static final int SIZE = 0x14; + + private int drelocs; + private int imports; + private int importCount; + private int flags; + private int reserved1; + private int moduleDependencies; + private int reserved2; + + /** + * Creates a new {@link SomModuleEntry} + * + * @param reader A {@link BinaryReader} positioned at the start of the module list + * @throws IOException if there was an IO-related error + */ + public SomModuleEntry(BinaryReader reader) throws IOException { + drelocs = reader.readNextInt(); + imports = reader.readNextInt(); + importCount = reader.readNextInt(); + flags = reader.readNextUnsignedByte(); + reserved1 = reader.readNextUnsignedByte(); + moduleDependencies = reader.readNextUnsignedShort(); + reserved2 = reader.readNextInt(); + } + + /** + * {@return the text address into the dynamic relocation table} + */ + public int getDrelocs() { + return drelocs; + } + + /** + * {@return the text address into the module import table} + */ + public int getImports() { + return imports; + } + + /** + * {@return the number of symbol entries in the module import table belonging to this module} + */ + public int getImportCount() { + return importCount; + } + + /** + * {@return the flags} + */ + public int getFlags() { + return flags; + } + + /** + * {@return the first reserved value} + */ + public int getReserved1() { + return reserved1; + } + + /** + * {@return the number of modules the current module needs to have bound before all of its own + * import symbols can be found} + */ + public int getModuleDependencies() { + return moduleDependencies; + } + + /** + * {@return the second reserved value} + */ + public int getReserved2() { + return reserved2; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("module_entry", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "drelocs", "text offset into module dynamic relocation array"); + struct.add(DWORD, "imports", "text offset into module import array"); + struct.add(DWORD, "imports_count", "number of entries into module import array"); + struct.add(BYTE, "flags", "currently flags defined: ELAB_REF"); + struct.add(BYTE, "reserved1", null); + struct.add(WORD, "module_dependencies", null); + struct.add(DWORD, "reserved2", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomPltEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomPltEntry.java new file mode 100644 index 0000000000..ea641523f5 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomPltEntry.java @@ -0,0 +1,72 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code PLT_entry} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomPltEntry implements StructConverter { + + /** The size in bytes of a {@link SomPltEntry} */ + public static final int SIZE = 0x8; + + private int procAddr; + private int ltptrValue; + + /** + * Creates a new {@link SomPltEntry} + * + * @param reader A {@link BinaryReader} positioned at the start of the PLT + * @throws IOException if there was an IO-related error + */ + public SomPltEntry(BinaryReader reader) throws IOException { + procAddr = reader.readNextInt(); + ltptrValue = reader.readNextInt(); + } + + /** + * {@return the address of the procedure to be branched to} + */ + public int getProcAddr() { + return procAddr; + } + + /** + * {@return the import index of the code symbol (if {@code proc_addr} points to the BOR routine} + */ + public int getLtptrValue() { + return ltptrValue; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("PLT_entry", SIZE); + struct.setPackingEnabled(true); + struct.add(POINTER, "poc_addr", "address of procedure"); + struct.add(DWORD, "ltptr_value", "value of r19 required for this procedure"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomProductSpecificsAuxHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomProductSpecificsAuxHeader.java new file mode 100644 index 0000000000..a1faf80dcb --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomProductSpecificsAuxHeader.java @@ -0,0 +1,61 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM "product specifics" structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomProductSpecificsAuxHeader extends SomAuxHeader { + + private byte[] bytes; + + /** + * Creates a new {@link SomProductSpecificsAuxHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the auxiliary header + * @throws IOException if there was an IO-related error + */ + public SomProductSpecificsAuxHeader(BinaryReader reader) throws IOException { + super(reader); + bytes = reader.readNextByteArray((int) auxId.getLength()); + } + + /** + * {@return the product specific bytes} + */ + public byte[] getBytes() { + return bytes; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("som_product_specifics_auxhdr", 0); + struct.setPackingEnabled(true); + struct.add(auxId.toDataType(), "som_auxhdr", null); + struct.add(new ArrayDataType(BYTE, (int) auxId.getLength(), 1), "bytes", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomShlibListEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomShlibListEntry.java new file mode 100644 index 0000000000..f84a80f23f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomShlibListEntry.java @@ -0,0 +1,121 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code shlib_list_entry} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomShlibListEntry implements StructConverter { + + /** The size in bytes of a {@link SomShlibListEntry} */ + public static final int SIZE = 0x8; + + private String shlibName; + private int reserved1; + private boolean internalName; + private boolean dashLReference; + private int bind; + private short highwaterMark; + + /** + * Creates a new {@link SomShlibListEntry} + * + * @param reader A {@link BinaryReader} positioned at the start of the header + * @param stringTableLoc The location of the string table + * @throws IOException if there was an IO-related error + */ + public SomShlibListEntry(BinaryReader reader, long stringTableLoc) throws IOException { + shlibName = reader.readAsciiString(stringTableLoc + reader.readNextInt()); + int bitfield = reader.readNextUnsignedByte(); + dashLReference = (bitfield & 0x1) != 0; + internalName = ((bitfield >> 1) & 0x1) != 0; + reserved1 = (bitfield >> 2) & 0x3f; + bind = reader.readNextUnsignedByte(); + highwaterMark = reader.readNextShort(); + } + + /** + * {@return the name of the shared library} + */ + public String getShlibName() { + return shlibName; + } + + /** + * {@return the reserved value} + */ + public int getReserved1() { + return reserved1; + } + + /** + * {@return whether or not the shared library entry is an internal name} + */ + public boolean isInternalName() { + return internalName; + } + + /** + * {@return whether or not the shared library was specified on the link line with + * the {@code -l} option or not} + */ + public boolean getDashLReference() { + return dashLReference; + } + + /** + * {@return the binding-time preference} + */ + public int getBind() { + return bind; + } + + /** + * {@return the {@code highwater_mark} value} + */ + public short getHighwaterMark() { + return highwaterMark; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("shlib_list_entry", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "shlib_name", "offset withing string table"); + try { + struct.addBitField(BYTE, 6, "reserved1", ""); + struct.addBitField(BYTE, 1, "internal_name", "shlib entry is an internal name"); + struct.addBitField(BYTE, 1, "dash_l_reference", "referenced with -lc or absolute path"); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(BYTE, "bind", "BIND_IMMEDIATE, BIND_DEFERRED or BIND_REFERENCE"); + struct.add(WORD, "highwater_mark", "highwater mark of the library"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSpace.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSpace.java new file mode 100644 index 0000000000..f91d2ef0ee --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSpace.java @@ -0,0 +1,222 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code space_dictionary_record} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomSpace implements StructConverter { + + /** The size in bytes of a {@link SomSpace} */ + public static final int SIZE = 0x24; + + private String name; + private boolean isLoadable; + private boolean isDefined; + private boolean isPrivate; + private boolean hasIntermediateCode; + private boolean isThreadSpecific; + private int reserved; + private int sortKey; + private int reserved2; + private int spaceNumber; + private int subspaceIndex; + private long subspaceQuantity; + private int loaderFixIndex; + private long loaderFixQuantity; + private int initPointerIndex; + private long initPointerQuantity; + + + /** + * Creates a new {@link SomSpace} + * + * @param reader A {@link BinaryReader} positioned at the start of the record + * @param spaceStringsLocation The starting index of the space strings + * @throws IOException if there was an IO-related error + */ + public SomSpace(BinaryReader reader, long spaceStringsLocation) throws IOException { + name = reader.readAsciiString(spaceStringsLocation + reader.readNextUnsignedInt()); + int bitfield = reader.readNextInt(); + reserved2 = bitfield & 0xff; + sortKey = (bitfield >> 8) & 0xff; + reserved = (bitfield >> 16) & 0x7ff; + isThreadSpecific = ((bitfield >> 27) & 0x1) != 0; + hasIntermediateCode = ((bitfield >> 28) & 0x1) != 0; + isPrivate = ((bitfield >> 29) & 0x1) != 0; + isDefined = ((bitfield >> 30) & 0x1) != 0; + isLoadable = ((bitfield >> 31) & 0x1) != 0; + spaceNumber = reader.readNextInt(); + subspaceIndex = reader.readNextInt(); + subspaceQuantity = reader.readNextUnsignedInt(); + loaderFixIndex = reader.readNextInt(); + loaderFixQuantity = reader.readNextUnsignedInt(); + initPointerIndex = reader.readNextInt(); + initPointerQuantity = reader.readNextUnsignedInt(); + + } + + /** + * {@return the space name} + */ + public String getName() { + return name; + } + + /** + * {@return whether or not the space is loadable} + */ + public boolean isLoadable() { + return isLoadable; + } + + /** + * {@return whether or not the space is defined within the file} + */ + public boolean isDefined() { + return isDefined; + } + + /** + * {@return whether or not the space is not sharable} + */ + public boolean isPrivate() { + return isPrivate; + } + + /** + * {@return whether or not the space contains intermediate code} + */ + public boolean hasIntermediateCode() { + return hasIntermediateCode; + } + + /** + * {@return whether or not the space is thread specific} + */ + public boolean isThreadSpecific() { + return isThreadSpecific; + } + + /** + * {@return the first reserved value} + */ + public int getReserved() { + return reserved; + } + + /** + * {@return the sort key for the space} + */ + public int getSortKey() { + return sortKey; + } + + /** + * {@return the second reserved value} + */ + public int getReserved2() { + return reserved2; + } + + /** + * {@return the space index} + */ + public int getSpaceNumber() { + return spaceNumber; + } + + /** + * {@return the index into the subspace dictionary} + */ + public int getSubspaceIndex() { + return subspaceIndex; + } + + /** + * {@return the number of subspaces in the space} + */ + public long getSubspaceQuantity() { + return subspaceQuantity; + } + + /** + * {@return the load fix index} + */ + public int getLoaderFixIndex() { + return loaderFixIndex; + } + + /** + * {@return the load fix quantity} + */ + public long getLoaderFixQuantity() { + return loaderFixQuantity; + } + + /** + * {@return the index into data (init) pointer array} + */ + public int getInitPonterIndex() { + return initPointerIndex; + } + + /** + * {@return the number of data (init) pointers} + */ + public long getInitPointerQuantity() { + return initPointerQuantity; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = + new StructureDataType("space_dictionary_record", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "name", "index to subspace name"); + try { + struct.addBitField(DWORD, 1, "is_loadable", "space is loadable"); + struct.addBitField(DWORD, 1, "is_defined", "space is defined within file"); + struct.addBitField(DWORD, 1, "is_private", "space is not sharable"); + struct.addBitField(DWORD, 1, "has_intermediate_code", "contain intermediate code"); + struct.addBitField(DWORD, 1, "is_tspecific", "is thread specific"); + struct.addBitField(DWORD, 11, "reserved", "reserved for future expansion"); + struct.addBitField(DWORD, 8, "sort_key", "sort key for space"); + struct.addBitField(DWORD, 8, "reserved2", "reserved for future expansion"); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(DWORD, "space_number", "space index"); + struct.add(DWORD, "subspace_index", "index into subspace dictionary"); + struct.add(DWORD, "subspace_quantity", "number of subspaces in space"); + struct.add(DWORD, "loader_fix_index", "loader usage"); + struct.add(DWORD, "loader_fix_quantity", "loader usage"); + struct.add(DWORD, "init_pointer_index", "index into data(initialization) pointer array"); + struct.add(DWORD, "init_pointer_quantity", "number of data (init) pointers"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSubspace.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSubspace.java new file mode 100644 index 0000000000..2800b706f4 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSubspace.java @@ -0,0 +1,348 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code subspace_dictionary_record} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomSubspace implements StructConverter { + + /** The size in bytes of a {@link SomSubspace} */ + public static final int SIZE = 0x28; + + private int spaceIndex; + private int accessControlBits; + private boolean memoryResident; + private boolean dupCommon; + private boolean isCommon; + private boolean isLoadable; + private int quadrant; + private boolean initiallyFrozen; + private boolean isFirst; + private boolean codeOnly; + private int sortKey; + private boolean replicateInit; + private boolean continuation; + private boolean isThreadSpecific; + private boolean isComdat; + private int reserved; + private int fileLocInitValue; + private long initializationLength; + private long subspaceStart; + private long subspaceLength; + private int reserved2; + private int alignment; + private String name; + private int fixupRequestIndex; + private long fixupRequestQuantity; + + + /** + * Creates a new {@link SomSubspace} + * + * @param reader A {@link BinaryReader} positioned at the start of the record + * @param spaceStringsLocation The starting index of the space strings + * @throws IOException if there was an IO-related error + */ + public SomSubspace(BinaryReader reader, long spaceStringsLocation) throws IOException { + spaceIndex = reader.readNextInt(); + int bitfield = reader.readNextInt(); + reserved = bitfield & 0x0f; + isComdat = ((bitfield >> 4) & 0x1) != 0; + isThreadSpecific = ((bitfield >> 5) & 0x1) != 0; + continuation = ((bitfield >> 6) & 0x1) != 0; + replicateInit = ((bitfield >> 7) & 0x1) != 0; + sortKey = (bitfield >> 8) & 0xff; + codeOnly = ((bitfield >> 16) & 0x1) != 0; + isFirst = ((bitfield >> 17) & 0x1) != 0; + initiallyFrozen = ((bitfield >> 18) & 0x1) != 0; + quadrant = (bitfield >> 19) & 0x3; + isLoadable = ((bitfield >> 21) & 0x1) != 0; + isCommon = ((bitfield >> 22) & 0x1) != 0; + dupCommon = ((bitfield >> 23) & 0x1) != 0; + memoryResident = ((bitfield >> 24) & 0x1) != 0; + accessControlBits = (bitfield >> 25) & 0x7f; + fileLocInitValue = reader.readNextInt(); + initializationLength = reader.readNextUnsignedInt(); + subspaceStart = reader.readNextUnsignedInt(); + subspaceLength = reader.readNextUnsignedInt(); + bitfield = reader.readNextInt(); + alignment = bitfield & 0x7ffffff; + reserved2 = (bitfield >> 27) & 0x1f; + name = reader.readAsciiString(spaceStringsLocation + reader.readNextUnsignedInt()); + fixupRequestIndex = reader.readNextInt(); + fixupRequestQuantity = reader.readNextUnsignedInt(); + + } + + /** + * {@return the space index} + */ + public int getSpaceIndex() { + return spaceIndex; + } + + /** + * {@return the access control bits for PDIR entries} + */ + public int getAccessControlBits() { + return accessControlBits; + } + + /** + * {@return whether or not to lock in memory during execution} + */ + public boolean isMemoryResident() { + return memoryResident; + } + + /** + * {@return whether or not data name clashes are allowed} + */ + public boolean isDupCommon() { + return dupCommon; + } + + /** + * {@return whether or not the subspace is a common} + */ + public boolean isCommon() { + return isCommon; + } + + /** + * {@return whether or not the subspace is loadable} + */ + public boolean isLoadable() { + return isLoadable; + } + + /** + * {@return the quadrant request} + */ + public int getQuadrant() { + return quadrant; + } + + /** + * {@return whether or not the subspace must be locked into memory when the OS is booted} + */ + public boolean isInitiallyFrozen() { + return initiallyFrozen; + } + + /** + * {@return whether or not this must be the first subspace} + */ + public boolean isFirst() { + return isFirst; + } + + /** + * {@return whether or not the subspace must contain only code} + */ + public boolean isCodeOnly() { + return codeOnly; + } + + /** + * {@return the sort key for the subspace} + */ + public int getSortKey() { + return sortKey; + } + + /** + * {@return whether or not init values are replicated to fill {@code subspace_length}} + */ + public boolean isReplicateInit() { + return replicateInit; + } + + /** + * {@return whether or not this subspace is a continuation} + */ + public boolean isContinuation() { + return continuation; + } + + /** + * {@return whether or not the subspace is thread specific} + */ + public boolean isThreadSpecific() { + return isThreadSpecific; + } + + /** + * {@return whether or not this is for COMDAT subspaces} + */ + public boolean isComdat() { + return isComdat; + } + + /** + * {@return the first reserved value} + */ + public int getReserved() { + return reserved; + } + + /** + * {@return the file location or initialization value} + */ + public int getFileLocInitValue() { + return fileLocInitValue; + } + + /** + * {@return the initialization length} + */ + public long getInitializationLength() { + return initializationLength; + } + + /** + * {@return the starting offset} + */ + public long getSubspaceStart() { + return subspaceStart; + } + + /** + * {@return the number of bytes defined by this subspace} + */ + public long getSubspaceLength() { + return subspaceLength; + } + + /** + * {@return the second reserved value} + */ + public int getReserved2() { + return reserved2; + } + + /** + * {@return the alignment required for the subspace} + */ + public int getAlignment() { + return alignment; + } + + /** + * {@return the subspace name} + */ + public String getName() { + return name; + } + + /** + * {@return the index into fixup array} + */ + public int getFixupRequestIndex() { + return fixupRequestIndex; + } + + /** + * {@return the number of fixup requests} + */ + public long getFixupRequestQuantity() { + return fixupRequestQuantity; + } + + /** + * {@return whether or not this subspace is readable} + */ + public boolean isRead() { + return getAccessControlType() < 4; + } + + /** + * {@return whether or not this subspace is writeable} + */ + public boolean isWrite() { + return getAccessControlType() == 1 || getAccessControlType() == 3; + } + + /** + * {@return whether or not this subspace is executable} + */ + public boolean isExecute() { + return getAccessControlType() >= 2; + } + + /** + * {@return the "type" part of the access control bits} + */ + private int getAccessControlType() { + return (accessControlBits >> 4) & 0x3; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("subspace_dictionary_record", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "space_index", ""); + try { + struct.addBitField(DWORD, 7, "access_control_bits", "access for PDIR entries"); + struct.addBitField(DWORD, 1, "memory_resident", "lock in memory during execution"); + struct.addBitField(DWORD, 1, "dup_common", "data name clashes allowed"); + struct.addBitField(DWORD, 1, "is_common", "subspace is a common"); + struct.addBitField(DWORD, 1, "is_loadable", ""); + struct.addBitField(DWORD, 2, "quadrant", "quadrant request"); + struct.addBitField(DWORD, 1, "initially_frozen", + "must be locked into memory when OS is booted"); + struct.addBitField(DWORD, 1, "is_first", "must be first subspace"); + struct.addBitField(DWORD, 1, "code_only", "must contain only code"); + struct.addBitField(DWORD, 8, "sort_key", "subspace sort key"); + struct.addBitField(DWORD, 1, "replicate_init", + "init values replicated to fill subspace_length"); + struct.addBitField(DWORD, 1, "continuation", "subspace is a continuation"); + struct.addBitField(DWORD, 1, "is_tspecific", "is thread specific?"); + struct.addBitField(DWORD, 1, "is_comdat", "Is for COMDAT subspaces?"); + struct.addBitField(DWORD, 4, "reserved", ""); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(DWORD, "file_loc_init_value", "file location or initialization value"); + struct.add(DWORD, "initialization_length", ""); + struct.add(DWORD, "subspace_start", "starting offset"); + struct.add(DWORD, "subspace_length", "number of bytes defined by this subspace"); + try { + struct.addBitField(DWORD, 5, "reserved2", ""); + struct.addBitField(DWORD, 27, "alignment", + "alignment required for the subspace (largest alignment requested for any item in the subspace)"); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(DWORD, "name", "index of subspace name"); + struct.add(DWORD, "fixup_request_index", "index into fixup array"); + struct.add(DWORD, "fixup_request_quantity", "number of fixup requests"); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSymbol.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSymbol.java new file mode 100644 index 0000000000..0ae0839a6a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSymbol.java @@ -0,0 +1,285 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code symbol_dictionary_record} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomSymbol implements StructConverter { + + /** The size in bytes of a {@link SomSymbol} */ + public static final int SIZE = 0x14; + + private boolean hidden; + private boolean secondaryDef; + private int symbolType; + private int symbolScope; + private int checkLevel; + private boolean mustQualify; + private boolean initiallyFrozen; + private boolean memoryResident; + private boolean isCommon; + private boolean dupCommon; + private int xleast; + private int argReloc; + private String name; + private String qualifierName; + private boolean hasLongReturn; + private boolean noRelocation; + private boolean isComdat; + private int reserved; + private int symbolInfo; + private long symbolValue; + + + /** + * Creates a new {@link SomSymbol} + * + * @param reader A {@link BinaryReader} positioned at the start of the record + * @param symbolStringsLocation The starting index of the symbol strings + * @throws IOException if there was an IO-related error + */ + public SomSymbol(BinaryReader reader, long symbolStringsLocation) throws IOException { + int bitfield = reader.readNextInt(); + argReloc = bitfield & 0x3ff; + xleast = (bitfield >> 10) & 0x3; + dupCommon = ((bitfield >> 12) & 0x1) != 0; + isCommon = ((bitfield >> 13) & 0x1) != 0; + memoryResident = ((bitfield >> 14) & 0x1) != 0; + initiallyFrozen = ((bitfield >> 15) & 0x1) != 0; + mustQualify = ((bitfield >> 16) & 0x1) != 0; + checkLevel = (bitfield >> 17) & 0x7; + symbolScope = (bitfield >> 20) & 0xf; + symbolType = (bitfield >> 24) & 0x3f; + secondaryDef = ((bitfield >> 30) & 0x1) != 0; + hidden = ((bitfield >> 31) & 0x1) != 0; + name = reader.readAsciiString(symbolStringsLocation + reader.readNextUnsignedInt()); + qualifierName = + reader.readAsciiString(symbolStringsLocation + reader.readNextUnsignedInt()); + bitfield = reader.readNextInt(); + symbolInfo = bitfield & 0xffffff; + reserved = (bitfield >> 24) & 0x1f; + isComdat = ((bitfield >> 29) & 0x1) != 0; + noRelocation = ((bitfield >> 30) & 0x1) != 0; + hasLongReturn = ((bitfield >> 31) & 0x1) != 0; + symbolValue = reader.readNextUnsignedInt(); + } + + /** + * {@return whether or not the symbol is to be hidden from the loader for the purpose of + * resolving external (inter-SOM) references} + */ + public boolean isHidden() { + return hidden; + } + + /** + * {@return whether or not the symbol is a secondary definition and has an additional name + * that is preceded by “_”} + */ + public boolean isSecondaryDef() { + return secondaryDef; + } + + /** + * {@return the symbol type} + * + * @see SomConstants + */ + public int getSymbolType() { + return symbolType; + } + + /** + * {@return the symbol scope} + * + * @see SomConstants + */ + public int getSymbolScope() { + return symbolScope; + } + + /** + * {@return the check level} + */ + public int getCheckLevel() { + return checkLevel; + } + + /** + * {@return whether or not the qualifier name must be used to fully qualify the symbol} + */ + public boolean mustQualify() { + return mustQualify; + } + + /** + * {@return whether or not the code importing or exporting this symbol is to be locked in + * physical memory when the operating system is being booted} + */ + public boolean isInitiallyFrozen() { + return initiallyFrozen; + } + + /** + * {@return whether or the the code that is importing or exporting this symbol is frozen in + * memory} + */ + public boolean isMemoryResident() { + return memoryResident; + } + + /** + * {@return whether or not this symbol is an initialized common data block} + */ + public boolean isCommon() { + return isCommon; + } + + /** + * {@return whether or not this symbol name may conflict with another symbol of the same name if + * both are of type data} + */ + public boolean isDupCommon() { + return dupCommon; + } + + /** + * {@return the execution level that is required to call this entry point} + */ + public int getXleast() { + return xleast; + } + + /** + * {@return the location of the first four words of the parameter list, and the location of the + * function return value to the linker and loader} + */ + public int getArgReloc() { + return argReloc; + } + + /** + * {@return the symbol name} + */ + public String getName() { + return name; + } + + /** + * {@return the symbol qualifier name} + */ + public String getQualifierName() { + return qualifierName; + } + + /** + * {@return whether or not the called entry point will have a long return sequence} + */ + public boolean hasLongReturn() { + return hasLongReturn; + } + + /** + * {@return whether or not the called entry point will not require any parameter relocation} + */ + public boolean hasNoRelocation() { + return noRelocation; + } + + /** + * {@return whether or not this symbol identifies as the key symbol for a set of COMDAT + * subspaces} + */ + public boolean isComdat() { + return isComdat; + } + + /** + * {@return the reserved value} + */ + public int getReserved() { + return reserved; + } + + /** + * {@return the symbol info} + */ + public int getSymbolInfo() { + return symbolInfo; + } + + /** + * {@return the symbol value} + */ + public long getSymbolValue() { + return symbolValue; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("symbol_dictionary_record", SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(DWORD, 1, "hidden", null); + struct.addBitField(DWORD, 1, "secondary_def", null); + struct.addBitField(DWORD, 6, "symbol_type", null); + struct.addBitField(DWORD, 4, "symbol_scope", null); + struct.addBitField(DWORD, 3, "check_level", null); + struct.addBitField(DWORD, 1, "must_qualify", null); + struct.addBitField(DWORD, 1, "initially_frozen", null); + struct.addBitField(DWORD, 1, "memory_resident", null); + struct.addBitField(DWORD, 1, "is_common", null); + struct.addBitField(DWORD, 1, "dup_common", null); + struct.addBitField(DWORD, 2, "xleast", null); + struct.addBitField(DWORD, 10, "arg_reloc", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(DWORD, "name", null); + struct.add(DWORD, "qualifier_name", null); + try { + struct.addBitField(DWORD, 1, "has_long_return", null); + struct.addBitField(DWORD, 1, "no_relocation", null); + struct.addBitField(DWORD, 1, "is_comdat", null); + struct.addBitField(DWORD, 5, "reserved", null); + struct.addBitField(DWORD, 24, "symbol_info", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.add(DWORD, "symbol_value", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } + + @Override + public String toString() { + return "name=%s, type=%d, scope=%d, value = 0x%x".formatted(name, symbolType, symbolScope, + symbolValue); + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSysClock.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSysClock.java new file mode 100644 index 0000000000..69cffa44ad --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomSysClock.java @@ -0,0 +1,72 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a SOM {@code sys_clock} structure + * + * @see The 32-bit PA-RISC Run-time Architecture Document + */ +public class SomSysClock implements StructConverter { + + /** The size in bytes of a {@link SomSysClock} */ + public static final int SIZE = 0x8; + + private long seconds; + private long nano; + + /** + * Creates a new {@link SomSysClock} + * + * @param reader A {@link BinaryReader} positioned at the start of the value + * @throws IOException if there was an IO-related error + */ + public SomSysClock(BinaryReader reader) throws IOException { + seconds = reader.readNextUnsignedInt(); + nano = reader.readNextUnsignedInt(); + } + + /** + * {@return the number of seconds that have elapsed since January 1, 1970 (at 0:00 GMT)} + */ + public long getSeconds() { + return seconds; + } + + /** + * {@return the nano second of the second (which requires 30 bits to represent)} + */ + public long getNanoSeconds() { + return nano; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("sys_clock", SIZE); + struct.setPackingEnabled(true); + struct.add(DWORD, "seconds", null); + struct.add(DWORD, "nano", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomUnknownAuxHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomUnknownAuxHeader.java new file mode 100644 index 0000000000..c5d140f936 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/som/SomUnknownAuxHeader.java @@ -0,0 +1,58 @@ +/* ### + * 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.som; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents an unknown SOM auxiliary header + */ +public class SomUnknownAuxHeader extends SomAuxHeader { + + private byte[] bytes; + + /** + * Creates a new {@link SomUnknownAuxHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the auxiliary header + * @throws IOException if there was an IO-related error + */ + public SomUnknownAuxHeader(BinaryReader reader) throws IOException { + super(reader); + bytes = reader.readNextByteArray((int) auxId.getLength()); + } + + /** + * {@return the unknown bytes of this auxiliary header} + */ + public byte[] getBytes() { + return bytes; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("som_unknown_auxhdr", 0); + struct.setPackingEnabled(true); + struct.add(auxId.toDataType(), "som_auxhdr", null); + struct.add(new ArrayDataType(BYTE, (int) auxId.getLength(), 1), "bytes", null); + struct.setCategoryPath(new CategoryPath("/SOM")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/SomLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/SomLoader.java new file mode 100644 index 0000000000..362d73c2eb --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/SomLoader.java @@ -0,0 +1,313 @@ +/* ### + * 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.opinion; + +import static ghidra.app.util.bin.format.som.SomConstants.*; + +import java.io.IOException; +import java.util.*; + +import ghidra.app.util.MemoryBlockUtils; +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.ByteProvider; +import ghidra.app.util.bin.format.som.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.database.mem.FileBytes; +import ghidra.program.model.address.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.symbol.*; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * A {@link Loader} for System Object Model files + */ +public class SomLoader extends AbstractProgramWrapperLoader { + public final static String SOM_NAME = "System Object Model (SOM)"; + + @Override + public Collection findSupportedLoadSpecs(ByteProvider provider) throws IOException { + List loadSpecs = new ArrayList<>(); + + if (provider.length() < SomHeader.SIZE) { + return loadSpecs; + } + + try { + SomHeader header = new SomHeader(new BinaryReader(provider, false)); + if (header.hasValidMagic() && header.hasValidVersionId()) { + List results = QueryOpinionService.query(getName(), + Integer.toString(header.getSystemId()), null); + for (QueryResult result : results) { + loadSpecs.add(new LoadSpec(this, 0, result)); + } + if (loadSpecs.isEmpty()) { + loadSpecs.add(new LoadSpec(this, 0, true)); + } + } + } + catch (IOException e) { + // that's ok, not a System Object Model + } + return loadSpecs; + } + + @Override + protected void load(Program program, ImporterSettings settings) + throws IOException, CancelledException { + MessageLog log = settings.log(); + TaskMonitor monitor = settings.monitor(); + FileBytes fileBytes = + MemoryBlockUtils.createFileBytes(program, settings.provider(), monitor); + BinaryReader reader = new BinaryReader(settings.provider(), false); + try { + SomHeader header = new SomHeader(reader); + processMemoryBlocks(program, fileBytes, header, log, monitor); + SomDynamicLoaderHeader dlHeader = new SomDynamicLoaderHeader(program, + header.getTextAddress(program), header.getDataAddress(program)); + processEntryPoint(program, header, log, monitor); + processSymbols(program, header, log, monitor); + processImports(program, dlHeader, log, monitor); + processExports(program, dlHeader, log, monitor); + processLibraries(program, dlHeader, log, monitor); + markupHeaders(program, fileBytes, header, dlHeader, log, monitor); + } + catch (Exception e) { + throw new IOException(e); + } + } + + private void processMemoryBlocks(Program program, FileBytes fileBytes, SomHeader header, + MessageLog log, TaskMonitor monitor) throws Exception { + monitor.setMessage("Processing memory blocks..."); + + AddressSpace addrSpace = program.getAddressFactory().getDefaultAddressSpace(); + List spaces = header.getSpaces(); + List subspaces = header.getSubspaces(); + for (SomSubspace subspace : subspaces) { + SomSpace space = spaces.get(subspace.getSpaceIndex()); + long initSize = subspace.getInitializationLength(); + long size = subspace.getSubspaceLength(); + if (size == 0) { + continue; + } + Address addr = subspace.isLoadable() ? addrSpace.getAddress(subspace.getSubspaceStart()) + : AddressSpace.OTHER_SPACE.getAddress(subspace.getSubspaceStart()); + if (initSize > 0) { + MemoryBlockUtils.createInitializedBlock(program, !subspace.isLoadable(), + subspace.getName(), addr, fileBytes, subspace.getFileLocInitValue(), initSize, + "", space.getName(), subspace.isRead(), subspace.isWrite(), + subspace.isExecute(), log); + addr = addr.add(initSize); + } + if (size > initSize) { + MemoryBlockUtils.createUninitializedBlock(program, !subspace.isLoadable(), + subspace.getName(), addr, size - initSize, "", space.getName(), + subspace.isRead(), subspace.isWrite(), subspace.isExecute(), log); + } + } + } + + private void processEntryPoint(Program program, SomHeader header, MessageLog log, + TaskMonitor monitor) throws Exception { + monitor.setMessage("Processing entry point..."); + + SymbolTable symbolTable = program.getSymbolTable(); + AddressSpace addrSpace = program.getAddressFactory().getDefaultAddressSpace(); + SomSpace space = header.getSpaces().get((int) header.getEntrySpace()); + SomSubspace subspace = + header.getSubspaces().get((int) (space.getSubspaceIndex() + header.getEntrySubspace())); + Address subspaceAddr = addrSpace.getAddress(subspace.getSubspaceStart()); + + long entryOffset = 0; + SomExecAuxHeader execHeader = header.getFirstAuxHeader(SomExecAuxHeader.class); + if (execHeader != null) { + long execEntry = execHeader.getExecEntry(); + if (execEntry != 0) { + entryOffset = execEntry; + } + } + if (entryOffset == 0) { + entryOffset = header.getEntryOffset(); + } + + if (entryOffset != 0) { + Address addr = subspaceAddr.add(entryOffset); + addr = addrSpace.getAddress(entryOffset); + AbstractProgramLoader.markAsFunction(program, "entry", addr); + symbolTable.addExternalEntryPoint(addr); + } + } + + private void processSymbols(Program program, SomHeader header, MessageLog log, + TaskMonitor monitor) throws Exception { + SymbolTable symbolTable = program.getSymbolTable(); + AddressSpace addrSpace = program.getAddressFactory().getDefaultAddressSpace(); + List somSymbols = header.getSymbols(); + monitor.initialize(somSymbols.size(), "Processing symbols..."); + for (SomSymbol somSymbol : somSymbols) { + monitor.increment(); + + if (somSymbol.getSymbolScope() == SYMBOL_SCOPE_UNSAT) { + // The symbol value is meaningless in this case, so don't create a symbol + continue; + } + + Address addr = addrSpace.getAddress(somSymbol.getSymbolValue()); + String name = SymbolUtilities.replaceInvalidChars(somSymbol.getName(), true); + + // For code symbols, mask off bottom 2 permission bits + switch (somSymbol.getSymbolType()) { + case SYMBOL_ENTRY: + case SYMBOL_MILLICODE: + case SYMBOL_CODE: + addr = addr.getNewAddress(addr.getOffset() & 0xfffffffc); + } + + // Create label on supported symbols + switch (somSymbol.getSymbolType()) { + case SYMBOL_ENTRY: + case SYMBOL_MILLICODE: + case SYMBOL_CODE: + case SYMBOL_DATA: + case SYMBOL_STUB: + symbolTable.createLabel(addr, name, SourceType.IMPORTED); + } + + // Create functions on relevant symbols + switch (somSymbol.getSymbolType()) { + case SYMBOL_ENTRY: + case SYMBOL_MILLICODE: + AbstractProgramLoader.markAsFunction(program, name, addr); + } + } + } + + private void processImports(Program program, SomDynamicLoaderHeader dlHeader, MessageLog log, + TaskMonitor monitor) throws Exception { + int importCounter = 0; + List imports = dlHeader.getImports(); + List dlt = dlHeader.getDlt(); + List plt = dlHeader.getPlt(); + SymbolTable symbolTable = program.getSymbolTable(); + FunctionManager functionMgr = program.getFunctionManager(); + ExternalManager extMgr = program.getExternalManager(); + Address dataAddr = dlHeader.getDataAddress(); + + monitor.initialize(dlt.size(), "Processing DLT imports..."); + for (int i = 0; i < dlt.size(); i++, importCounter++) { + monitor.increment(); + SomImportEntry importEntry = imports.get(importCounter); + String importName = importEntry.getName(); + if (importName != null) { + SomDltEntry dltEntry = dlt.get(i); + Address target = dataAddr.getNewAddress(dltEntry.getValue()); + symbolTable.createLabel(target, importName, SourceType.IMPORTED); + extMgr.addExtLocation(Library.UNKNOWN, importName, null, SourceType.IMPORTED); + } + } + + monitor.initialize(plt.size(), "Processing PLT imports..."); + for (int i = 0; i < plt.size(); i++, importCounter++) { + monitor.increment(); + SomImportEntry importEntry = imports.get(importCounter); + SomPltEntry pltEntry = plt.get(i); + Address target = dataAddr.getNewAddress(pltEntry.getProcAddr()); + String name = importEntry.getName(); + Function stubFunc = functionMgr.getFunctionAt(target); + if (stubFunc == null) { + stubFunc = functionMgr.createFunction(name, target, new AddressSet(target), + SourceType.IMPORTED); + } + ExternalLocation loc = + extMgr.addExtLocation(Library.UNKNOWN, name, null, SourceType.IMPORTED); + stubFunc.setThunkedFunction(loc.createFunction()); + } + } + + private void processExports(Program program, SomDynamicLoaderHeader dlHeader, MessageLog log, + TaskMonitor monitor) throws Exception { + SymbolTable symbolTable = program.getSymbolTable(); + AddressSpace addrSpace = program.getAddressFactory().getDefaultAddressSpace(); + + List exports = dlHeader.getExports(); + monitor.initialize(exports.size(), "Processing exports..."); + for (SomExportEntry export : dlHeader.getExports()) { + String name = export.getName(); + if (name == null) { + continue; + } + Address addr = addrSpace.getAddress(export.getValue()); + SymbolIterator iter = symbolTable.getSymbols(name); + if (!iter.hasNext()) { + symbolTable.createLabel(addr, name, SourceType.IMPORTED); + symbolTable.addExternalEntryPoint(addr); + } + else { + for (Symbol symbol : iter) { + if (symbol.getAddress().getOffset() == export.getValue()) { + symbolTable.addExternalEntryPoint(addr); + } + } + } + } + } + + private void processLibraries(Program program, SomDynamicLoaderHeader dlHeader, MessageLog log, + TaskMonitor monitor) throws Exception { + monitor.initialize(dlHeader.getShlibListCount(), "Processing libraries..."); + for (SomShlibListEntry entry : dlHeader.getShlibs()) { + String name = SymbolUtilities.replaceInvalidChars(entry.getShlibName(), true); + try { + program.getExternalManager().addExternalLibraryName(name, SourceType.IMPORTED); + } + catch (DuplicateNameException e) { + // do not care + } + catch (Exception e) { + log.appendMsg("Unable to add external library name: " + e.getMessage()); + } + } + } + + private void markupHeaders(Program program, FileBytes fileBytes, SomHeader header, + SomDynamicLoaderHeader dlHeader, MessageLog log, TaskMonitor monitor) { + monitor.setMessage("Marking up headers..."); + Address headerSpaceAddr = AddressSpace.OTHER_SPACE.getAddress(0); + try { + MemoryBlock headerBlock = MemoryBlockUtils.createInitializedBlock(program, true, + "FILE", headerSpaceAddr, fileBytes, 0, fileBytes.getSize(), "", "", false, false, + false, log); + header.markup(program, headerBlock.getStart(), monitor); + } + catch (Exception e) { + log.appendMsg("Failed to markup headers: " + e.getMessage()); + } + try { + dlHeader.markup(program, monitor); + } + catch (Exception e) { + log.appendMsg("Failed to markup dynamic loader headers: " + e.getMessage()); + } + } + + @Override + public String getName() { + return SOM_NAME; + } +} diff --git a/Ghidra/Processors/PA-RISC/data/languages/pa-risc.opinion b/Ghidra/Processors/PA-RISC/data/languages/pa-risc.opinion index 240b48959c..92bd17caf6 100644 --- a/Ghidra/Processors/PA-RISC/data/languages/pa-risc.opinion +++ b/Ghidra/Processors/PA-RISC/data/languages/pa-risc.opinion @@ -1,5 +1,10 @@ - + + + + + +