mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-0: OMF-51 improvements
This commit is contained in:
parent
26d3c933e7
commit
22a4de14ea
8 changed files with 525 additions and 21 deletions
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -20,6 +20,7 @@ import java.lang.reflect.Field;
|
|||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -132,4 +133,18 @@ public class OmfUtils {
|
|||
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Stream} of {@link OmfRecord records} that match the given class type
|
||||
*
|
||||
* @param <T> The class type
|
||||
* @param records The {@link List} of all {@link OmfRecord records}
|
||||
* @param classType The class type to match on
|
||||
* @return A {@link Stream} of matching (@link OmfRecord records}
|
||||
*/
|
||||
public static <T> Stream<T> filterRecords(List<OmfRecord> records, Class<T> classType) {
|
||||
return records.stream()
|
||||
.filter(classType::isInstance)
|
||||
.map(classType::cast);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,31 +24,38 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
|
||||
public class Omf51Content extends OmfRecord {
|
||||
|
||||
private byte segId;
|
||||
private int segId;
|
||||
private int offset;
|
||||
private byte[] dataBytes;
|
||||
private long dataIndex;
|
||||
private int dataSize;
|
||||
|
||||
boolean largeSegmentId;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Omf51Content} record
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the record
|
||||
* @param largeSegmentId True if the segment ID is 2 bytes; false if 1 byte
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public Omf51Content(BinaryReader reader) throws IOException {
|
||||
public Omf51Content(BinaryReader reader, boolean largeSegmentId) throws IOException {
|
||||
super(reader);
|
||||
this.largeSegmentId = largeSegmentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseData() throws IOException, OmfException {
|
||||
segId = dataReader.readNextByte();
|
||||
segId =
|
||||
largeSegmentId ? dataReader.readNextUnsignedShort() : dataReader.readNextUnsignedByte();
|
||||
offset = dataReader.readNextUnsignedShort();
|
||||
dataBytes = dataReader.readNextByteArray((int) (dataEnd - dataReader.getPointerIndex()));
|
||||
dataIndex = dataReader.getPointerIndex();
|
||||
dataSize = (int) (dataEnd - dataIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment ID}
|
||||
*/
|
||||
public byte getSegId() {
|
||||
public int getSegId() {
|
||||
return segId;
|
||||
}
|
||||
|
||||
|
@ -60,10 +67,17 @@ public class Omf51Content extends OmfRecord {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@return the data}
|
||||
* {@return the data size in bytes}
|
||||
*/
|
||||
public byte[] getDataBytes() {
|
||||
return dataBytes;
|
||||
public int getDataSize() {
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the start of the data in the reader}
|
||||
*/
|
||||
public long getDataIndex() {
|
||||
return dataIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,10 +85,10 @@ public class Omf51Content extends OmfRecord {
|
|||
StructureDataType struct = new StructureDataType(Omf51RecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
struct.add(BYTE, "SEG ID", null);
|
||||
struct.add(largeSegmentId ? WORD : BYTE, "SEG ID", null);
|
||||
struct.add(WORD, "offset", null);
|
||||
if (dataBytes.length > 0) {
|
||||
struct.add(new ArrayDataType(BYTE, dataBytes.length, 1), "data", null);
|
||||
if (dataSize > 0) {
|
||||
struct.add(new ArrayDataType(BYTE, dataSize, 1), "data", null);
|
||||
}
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* ###
|
||||
* 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.omf.omf51;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class Omf51FixupRecord extends OmfRecord {
|
||||
|
||||
/**
|
||||
* OMF-51 fixup metadata
|
||||
*
|
||||
* @param refLoc The reference location
|
||||
* @param refType The reference type
|
||||
* @param operand the fixup operand
|
||||
*/
|
||||
public static record Omf51Fixup(int refLoc, byte refType, int operand) {}
|
||||
|
||||
private List<Omf51Fixup> fixups = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link Omf51FixupRecord} record
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the record
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public Omf51FixupRecord(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseData() throws IOException, OmfException {
|
||||
while (dataReader.getPointerIndex() < dataEnd) {
|
||||
int refLoc = dataReader.readNextUnsignedByte();
|
||||
byte refType = dataReader.readNextByte();
|
||||
int operand = dataReader.readNextUnsignedShort();
|
||||
fixups.add(new Omf51Fixup(refLoc, refType, operand));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(Omf51RecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
StructureDataType fixupStruct = new StructureDataType("Omf51Fixup", 0);
|
||||
fixupStruct.add(BYTE, "ref_loc", null);
|
||||
fixupStruct.add(BYTE, "ref_type", null);
|
||||
fixupStruct.add(WORD, "operand", null);
|
||||
struct.add(new ArrayDataType(fixupStruct, fixups.size(), fixupStruct.getLength()), "fixup",
|
||||
null);
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link List} of fixups
|
||||
*
|
||||
* @return A {@link List} of fixups
|
||||
*/
|
||||
public List<Omf51Fixup> getFixups() {
|
||||
return fixups;
|
||||
}
|
||||
}
|
|
@ -23,8 +23,8 @@ import java.util.List;
|
|||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.app.util.bin.format.omf.omf166.Omf166RecordTypes;
|
||||
import ghidra.app.util.bin.format.omf.omf166.Omf166DepList;
|
||||
import ghidra.app.util.bin.format.omf.omf166.Omf166RecordTypes;
|
||||
|
||||
/**
|
||||
* A class for reading/creating OMF-51 records
|
||||
|
@ -51,9 +51,15 @@ public class Omf51RecordFactory extends AbstractOmfRecordFactory {
|
|||
case Omf166RecordTypes.DEPLST:
|
||||
yield new Omf166DepList(reader);
|
||||
case Content:
|
||||
yield new Omf51Content(reader);
|
||||
case Fixup:
|
||||
case KeilContent:
|
||||
yield new Omf51Content(reader, true);
|
||||
case SegmentDEF:
|
||||
yield new Omf51SegmentDefs(reader, false);
|
||||
case KeilSegmentDEF:
|
||||
yield new Omf51SegmentDefs(reader, true);
|
||||
case KeilFixup:
|
||||
yield new Omf51FixupRecord(reader);
|
||||
case Fixup:
|
||||
case ScopeDEF:
|
||||
case DebugItem:
|
||||
case PublicDEF:
|
||||
|
|
|
@ -40,6 +40,8 @@ public class Omf51RecordTypes {
|
|||
|
||||
// Record types with names ending in "Keil", which are produced by ARM Keil's
|
||||
// 8051 tooling, are only slight variants of the similarly-named record types in the Intel spec.
|
||||
public final static int KeilContent = Content + 1;
|
||||
public final static int KeilFixup = Fixup + 1;
|
||||
public final static int KeilSegmentDEF = SegmentDEF + 1;
|
||||
public final static int KeilScopeDEF = ScopeDEF + 1;
|
||||
public final static int KeilDebugItemOBJ = 0x22; // Keil debug items, in linker output format
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/* ###
|
||||
* 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.omf.omf51;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.OmfString;
|
||||
import ghidra.app.util.bin.format.omf.OmfUtils;
|
||||
|
||||
public class Omf51Segment {
|
||||
|
||||
// Segment Types
|
||||
public static final int CODE = 0;
|
||||
public static final int XDATA = 1;
|
||||
public static final int DATA = 2;
|
||||
public static final int IDATA = 3;
|
||||
public static final int BIT = 4;
|
||||
|
||||
// Relocation Types
|
||||
public static final int ABS = 0;
|
||||
public static final int UNIT = 1;
|
||||
public static final int BITADDRESSABLE = 2;
|
||||
public static final int INPAGE = 3;
|
||||
public static final int INBLOCK = 4;
|
||||
public static final int PAGE = 5;
|
||||
|
||||
private int id;
|
||||
private byte info;
|
||||
private byte relType;
|
||||
private int base;
|
||||
private int size;
|
||||
private OmfString name;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Omf51Segment}
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the segment definition
|
||||
* @param largeSegmentId True if the segment ID is 2 bytes; false if 1 byte
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public Omf51Segment(BinaryReader reader, boolean largeSegmentId) throws IOException {
|
||||
id = largeSegmentId ? reader.readNextUnsignedShort() : reader.readNextUnsignedByte();
|
||||
info = reader.readNextByte();
|
||||
relType = reader.readNextByte();
|
||||
reader.readNextByte(); // unused
|
||||
base = reader.readNextUnsignedShort();
|
||||
size = reader.readNextUnsignedShort();
|
||||
name = OmfUtils.readString(reader);
|
||||
|
||||
// Size of 0 is used to represent 0x10000
|
||||
if (size == 0) {
|
||||
size = 0x10000;
|
||||
}
|
||||
|
||||
// Size is ignored if empty bit is set, but force it to be 0 for consistency
|
||||
if ((info & 0x8) != 0) {
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment id}
|
||||
*/
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment info}
|
||||
*/
|
||||
public byte info() {
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment relocation type}
|
||||
*/
|
||||
public byte relType() {
|
||||
return relType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment base address}
|
||||
*/
|
||||
public int base() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment size}
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment name}
|
||||
*/
|
||||
public OmfString name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the segment type (CODE, XDATA, etc)}
|
||||
*/
|
||||
public int getType() {
|
||||
return info & 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return whether or not this segment is code}
|
||||
*/
|
||||
public boolean isCode() {
|
||||
return getType() == CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return whether or not this segment is absolute}
|
||||
*/
|
||||
public boolean isAbsolute() {
|
||||
return id == 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/* ###
|
||||
* 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.omf.omf51;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class Omf51SegmentDefs extends OmfRecord {
|
||||
|
||||
private boolean largeSegmentId;
|
||||
private List<Omf51Segment> segments = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link Omf51SegmentDefs} record
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the record
|
||||
* @param largeSegmentId True if the segment ID is 2 bytes; false if 1 byte
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public Omf51SegmentDefs(BinaryReader reader, boolean largeSegmentId) throws IOException {
|
||||
super(reader);
|
||||
this.largeSegmentId = largeSegmentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseData() throws IOException, OmfException {
|
||||
while (dataReader.getPointerIndex() < dataEnd) {
|
||||
segments.add(new Omf51Segment(dataReader, largeSegmentId));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(Omf51RecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
for (Omf51Segment segment : segments) {
|
||||
struct.add(largeSegmentId ? WORD : BYTE, "id", null);
|
||||
struct.add(BYTE, "info", null);
|
||||
struct.add(BYTE, "rel type", null);
|
||||
struct.add(BYTE, "unused", null);
|
||||
struct.add(WORD, "base", null);
|
||||
struct.add(WORD, "size", null);
|
||||
struct.add(segment.name().toDataType(), segment.name().getDataTypeSize(), "name", null);
|
||||
}
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the list of segments}
|
||||
*/
|
||||
public List<Omf51Segment> getSegments() {
|
||||
return segments;
|
||||
}
|
||||
}
|
|
@ -17,21 +17,23 @@ package ghidra.app.util.opinion;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.app.util.bin.format.omf.omf51.Omf51RecordFactory;
|
||||
import ghidra.app.util.bin.format.omf.omf51.*;
|
||||
import ghidra.app.util.bin.format.omf.omf51.Omf51FixupRecord.Omf51Fixup;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataUtilities;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -79,13 +81,114 @@ public class Omf51Loader extends AbstractProgramWrapperLoader {
|
|||
AbstractOmfRecordFactory factory = new Omf51RecordFactory(provider);
|
||||
try {
|
||||
List<OmfRecord> records = OmfUtils.readRecords(factory);
|
||||
Map<Integer, Address> segmentToAddr =
|
||||
processMemoryBlocks(program, fileBytes, records, log, monitor);
|
||||
performFixups(program, fileBytes, records, segmentToAddr, log, monitor);
|
||||
markupRecords(program, fileBytes, records, log, monitor);
|
||||
}
|
||||
catch (OmfException e) {
|
||||
catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Integer, Address> processMemoryBlocks(Program program, FileBytes fileBytes,
|
||||
List<OmfRecord> records, MessageLog log, TaskMonitor monitor) throws Exception {
|
||||
|
||||
// Gather all segments for processing, putting the absolute segments (id == 0) first since
|
||||
// they are not flexible about where they get placed
|
||||
List<Omf51Segment> segments = OmfUtils.filterRecords(records, Omf51SegmentDefs.class)
|
||||
.map(Omf51SegmentDefs::getSegments)
|
||||
.flatMap(List::stream)
|
||||
.sorted((a, b) -> Integer.compare(a.id(), b.id())) // absolute (id=0) comes first
|
||||
.toList();
|
||||
|
||||
// Group all of a segment's content records together
|
||||
Map<Integer, List<Omf51Content>> contentMap =
|
||||
OmfUtils.filterRecords(records, Omf51Content.class)
|
||||
.collect(Collectors.groupingBy(Omf51Content::getSegId));
|
||||
|
||||
// Create some data structures that will aid in segment relocation:
|
||||
// - A set of addresses currently in use, so we can find holes for new segments in the
|
||||
// address space
|
||||
// - A map to keep track of segment's size, since segments with different ID's but the
|
||||
// same name and type must be adjacent
|
||||
// - A map to keep track of where same-named segments currently ends, so the next
|
||||
// same-named segment can easily know where to go
|
||||
// NOTE: The key for these maps needs to include both the segment name and the type
|
||||
AddressSet usedAddresses = new AddressSet();
|
||||
Map<String, Integer> segmentSizes = new HashMap<>();
|
||||
Map<String, Address> segmentEnds = new HashMap<>();
|
||||
for (Omf51Segment segment : segments) {
|
||||
segmentSizes.compute(key(segment),
|
||||
(k, v) -> (v == null ? segment.size() : v + segment.size()));
|
||||
}
|
||||
|
||||
// We will be returning a map of segment ID's to starting address, for use when we later
|
||||
// perform fixups within the content
|
||||
Map<Integer, Address> segmentToAddr = new HashMap<>();
|
||||
|
||||
for (Omf51Segment segment : segments) {
|
||||
List<Omf51Content> segmentContent = contentMap.get(segment.id());
|
||||
String blockName = segment.isAbsolute() ? "<ABSOLUTE>" : segment.name().str();
|
||||
if (blockName.isBlank()) {
|
||||
blockName = "<NONAME>";
|
||||
}
|
||||
AddressSpace space = getAddressSpace(program, segment);
|
||||
Address segmentAddr;
|
||||
if (segmentContent != null) {
|
||||
segmentAddr = findAddr(segment, segmentSizes, segmentEnds, space, usedAddresses);
|
||||
for (Omf51Content content : segmentContent) {
|
||||
Address contentAddr =
|
||||
segment.isAbsolute() ? space.getAddress(content.getOffset())
|
||||
: segmentAddr.add(content.getOffset());
|
||||
try {
|
||||
MemoryBlockUtils.createInitializedBlock(program, false, blockName,
|
||||
contentAddr, fileBytes, content.getDataIndex(), content.getDataSize(),
|
||||
"", space.getName(), true, !segment.isCode(), segment.isCode(), log);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.appendMsg(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
segmentAddr = findAddr(segment, segmentSizes, segmentEnds, space, usedAddresses);
|
||||
MemoryBlockUtils.createUninitializedBlock(program, false, blockName, segmentAddr,
|
||||
segment.size(), "", space.getName(), true, true, false, log);
|
||||
}
|
||||
if (segment.isCode()) {
|
||||
AbstractProgramLoader.markAsFunction(program, blockName, segmentAddr);
|
||||
}
|
||||
segmentToAddr.put(segment.id(), segmentAddr);
|
||||
}
|
||||
return segmentToAddr;
|
||||
}
|
||||
|
||||
private void performFixups(Program program, FileBytes fileBytes, List<OmfRecord> records,
|
||||
Map<Integer, Address> segmentToAddr, MessageLog log, TaskMonitor monitor)
|
||||
throws Exception {
|
||||
OmfRecord previous = null;
|
||||
for (OmfRecord record : records) {
|
||||
if (record instanceof Omf51FixupRecord fixupRec) {
|
||||
if (!(previous instanceof Omf51Content content)) {
|
||||
throw new Exception("Record prior to fixup is not content!");
|
||||
}
|
||||
Address segmentAddr = segmentToAddr.get(content.getSegId());
|
||||
if (segmentAddr == null) {
|
||||
throw new Exception("Failed to get lookup segment ID 0x%x for content fixup!"
|
||||
.formatted(content.getSegId()));
|
||||
}
|
||||
for (Omf51Fixup fixup : fixupRec.getFixups()) {
|
||||
Address fixupAddr = segmentAddr.add(fixup.refLoc());
|
||||
program.getRelocationTable()
|
||||
.add(fixupAddr, Status.UNSUPPORTED, fixup.refType(),
|
||||
new long[] { fixup.operand() }, 0, null);
|
||||
}
|
||||
}
|
||||
previous = record;
|
||||
}
|
||||
}
|
||||
|
||||
private void markupRecords(Program program, FileBytes fileBytes, List<OmfRecord> records,
|
||||
MessageLog log, TaskMonitor monitor) {
|
||||
monitor.setMessage("Marking up records...");
|
||||
|
@ -114,6 +217,71 @@ public class Omf51Loader extends AbstractProgramWrapperLoader {
|
|||
}
|
||||
}
|
||||
|
||||
private Address findAddr(Omf51Segment segment, Map<String, Integer> segmentSizes,
|
||||
Map<String, Address> segmentEnds, AddressSpace space, AddressSet usedAddresses)
|
||||
throws Exception {
|
||||
return switch (segment.relType()) {
|
||||
case Omf51Segment.ABS: {
|
||||
if (segment.id() != 0) {
|
||||
throw new Exception("Absolute segment does not have ID 0!");
|
||||
}
|
||||
Address start = space.getAddress(segment.base());
|
||||
Address end = start.add(segment.size());
|
||||
if (usedAddresses.intersects(start, end)) {
|
||||
throw new Exception("Absolute segment overlaps with existing segment!");
|
||||
}
|
||||
usedAddresses.add(start, end);
|
||||
yield start;
|
||||
}
|
||||
case Omf51Segment.UNIT: {
|
||||
Address lastEnd = segmentEnds.get(key(segment));
|
||||
if (lastEnd != null) {
|
||||
Address start = lastEnd.add(1);
|
||||
Address end = start.add(segment.size() - 1);
|
||||
segmentEnds.put(key(segment), end);
|
||||
yield start;
|
||||
}
|
||||
Address start = space.getMinAddress();
|
||||
Address end = start.add(segment.size() - 1);
|
||||
int requiredSize = segmentSizes.get(key(segment));
|
||||
AddressSet intersection =
|
||||
usedAddresses.intersectRange(start, start.add(requiredSize - 1));
|
||||
while (!intersection.isEmpty()) {
|
||||
start = intersection.getMaxAddress().add(1);
|
||||
end = start.add(segment.size() - 1);
|
||||
intersection = usedAddresses.intersectRange(start, start.add(requiredSize - 1));
|
||||
}
|
||||
usedAddresses.add(start, start.add(requiredSize - 1));
|
||||
segmentEnds.put(key(segment), end);
|
||||
yield start;
|
||||
}
|
||||
case Omf51Segment.BITADDRESSABLE:
|
||||
case Omf51Segment.INPAGE:
|
||||
case Omf51Segment.INBLOCK:
|
||||
case Omf51Segment.PAGE:
|
||||
default:
|
||||
throw new Exception(
|
||||
"Skipping segment '%s'. Relocation type 0x%x is not yet supported"
|
||||
.formatted(segment.name(), segment.relType()));
|
||||
};
|
||||
}
|
||||
|
||||
private AddressSpace getAddressSpace(Program program, Omf51Segment segment) throws Exception {
|
||||
return program.getAddressFactory().getAddressSpace(switch (segment.getType()) {
|
||||
case Omf51Segment.CODE -> "CODE";
|
||||
case Omf51Segment.XDATA -> "EXTMEM";
|
||||
case Omf51Segment.DATA -> "INTMEM";
|
||||
case Omf51Segment.IDATA -> "INTMEM";
|
||||
case Omf51Segment.BIT -> "BITS";
|
||||
default -> throw new Exception(
|
||||
"Unsupported address space: 0x%x".formatted(segment.getType()));
|
||||
});
|
||||
}
|
||||
|
||||
private String key(Omf51Segment segment) {
|
||||
return segment.name().str() + "_" + segment.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return OMF51_NAME;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue