GP-0: Allowing OMF-51 files to load even if reading records caused

exception
This commit is contained in:
Ryan Kurtz
2026-03-27 06:43:26 -04:00
parent f71e1f6035
commit 9da1425d73
6 changed files with 39 additions and 20 deletions
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,20 +18,23 @@ package ghidra.app.util.bin.format.omf;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.omf.omf.OmfRecordTypes;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
public class OmfObsoleteRecord extends OmfRecord { public class OmfObsoleteRecord extends OmfRecord {
private Class<?> recordTypesClass;
/** /**
* Create a new {@link OmfObsoleteRecord} * Create a new {@link OmfObsoleteRecord}
* *
* @param reader A {@link BinaryReader} positioned at the start of the record * @param reader A {@link BinaryReader} positioned at the start of the record
* @param recordTypesClass The class that contains accessible OMF type fields
* @throws IOException If an IO-related error occurred * @throws IOException If an IO-related error occurred
*/ */
public OmfObsoleteRecord(BinaryReader reader) throws IOException { public OmfObsoleteRecord(BinaryReader reader, Class<?> recordTypesClass) throws IOException {
super(reader); super(reader);
this.recordTypesClass = recordTypesClass;
} }
@Override @Override
@@ -41,6 +44,7 @@ public class OmfObsoleteRecord extends OmfRecord {
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType)); return OmfUtils.toOmfRecordDataType(this,
OmfUtils.getRecordName(recordType, recordTypesClass));
} }
} }
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,7 +18,6 @@ package ghidra.app.util.bin.format.omf;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.omf.omf.OmfRecordTypes;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -27,14 +26,18 @@ import ghidra.util.exception.DuplicateNameException;
*/ */
public class OmfUnknownRecord extends OmfRecord { public class OmfUnknownRecord extends OmfRecord {
private Class<?> recordTypesClass;
/** /**
* Create a new {@link OmfUnknownRecord} * Create a new {@link OmfUnknownRecord}
* *
* @param reader A {@link BinaryReader} positioned at the start of the record * @param reader A {@link BinaryReader} positioned at the start of the record
* @param recordTypesClass The class that contains accessible OMF type fields
* @throws IOException If an IO-related error occurred * @throws IOException If an IO-related error occurred
*/ */
public OmfUnknownRecord(BinaryReader reader) throws IOException { public OmfUnknownRecord(BinaryReader reader, Class<?> recordTypesClass) throws IOException {
super(reader); super(reader);
this.recordTypesClass = recordTypesClass;
} }
@Override @Override
@@ -44,6 +47,7 @@ public class OmfUnknownRecord extends OmfRecord {
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType)); return OmfUtils.toOmfRecordDataType(this,
OmfUtils.getRecordName(recordType, recordTypesClass));
} }
} }
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
/** /**
@@ -126,19 +127,29 @@ public class OmfUtils {
* {@link AbstractOmfRecordFactory} * {@link AbstractOmfRecordFactory}
* *
* @param factory The {@link AbstractOmfRecordFactory} * @param factory The {@link AbstractOmfRecordFactory}
* @param log The log
* @return A {@link List} of read {@link OmfRecord records} * @return A {@link List} of read {@link OmfRecord records}
* @throws IOException if there was an IO-related error * @throws IOException if there was an IO-related error
* @throws OmfException if there was a problem with the OMF specification * @throws OmfException if there was a problem with the OMF specification
*/ */
public static List<OmfRecord> readRecords(AbstractOmfRecordFactory factory) public static List<OmfRecord> readRecords(AbstractOmfRecordFactory factory, MessageLog log)
throws OmfException, IOException { throws OmfException, IOException {
List<OmfRecord> records = new ArrayList<>(); List<OmfRecord> records = new ArrayList<>();
factory.reset(); factory.reset();
while (true) { while (true) {
OmfRecord rec = factory.readNextRecord(); try {
records.add(rec); OmfRecord rec = factory.readNextRecord();
if (rec.getRecordType() == factory.getEndRecordType()) { if (!rec.validCheckSum()) {
log.appendMsg("OMF record [%s] has an invalid checksum".formatted(rec));
}
records.add(rec);
if (rec.getRecordType() == factory.getEndRecordType()) {
break;
}
}
catch (IOException e) {
log.appendException(e);
break; break;
} }
} }
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -91,7 +91,7 @@ public class OmfRecordFactory extends AbstractOmfRecordFactory {
case LIBNAM: case LIBNAM:
case LIBLOC: case LIBLOC:
case LIBDIC: case LIBDIC:
yield new OmfObsoleteRecord(reader); yield new OmfObsoleteRecord(reader, OmfRecordTypes.class);
case LOCSYM: case LOCSYM:
case TYPDEF: case TYPDEF:
case COMDAT: case COMDAT:
@@ -104,7 +104,7 @@ public class OmfRecordFactory extends AbstractOmfRecordFactory {
case VENDEXT: case VENDEXT:
yield new OmfUnsupportedRecord(reader, OmfRecordTypes.class); yield new OmfUnsupportedRecord(reader, OmfRecordTypes.class);
default: default:
yield new OmfUnknownRecord(reader); yield new OmfUnknownRecord(reader, OmfRecordTypes.class);
}; };
record.parseData(); record.parseData();
@@ -82,7 +82,7 @@ public class Omf51RecordFactory extends AbstractOmfRecordFactory {
case DebugItem: case DebugItem:
yield new OmfUnsupportedRecord(reader, Omf51RecordTypes.class); yield new OmfUnsupportedRecord(reader, Omf51RecordTypes.class);
default: default:
yield new OmfUnknownRecord(reader); yield new OmfUnknownRecord(reader, Omf51RecordTypes.class);
}; };
record.parseData(); record.parseData();
@@ -82,7 +82,7 @@ public class Omf51Loader extends AbstractProgramWrapperLoader {
MemoryBlockUtils.createFileBytes(program, settings.provider(), monitor); MemoryBlockUtils.createFileBytes(program, settings.provider(), monitor);
AbstractOmfRecordFactory factory = new Omf51RecordFactory(settings.provider()); AbstractOmfRecordFactory factory = new Omf51RecordFactory(settings.provider());
try { try {
List<OmfRecord> records = OmfUtils.readRecords(factory); List<OmfRecord> records = OmfUtils.readRecords(factory, settings.log());
Map<Integer, Address> segmentToAddr = Map<Integer, Address> segmentToAddr =
processMemoryBlocks(program, fileBytes, records, log, monitor); processMemoryBlocks(program, fileBytes, records, log, monitor);
Map<Integer, Address> extIdToAddr = Map<Integer, Address> extIdToAddr =