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 @@
-
+
+
+
+
+
+