diff --git a/src/main/java/yetmorecode/ghidra/LxLoader.java b/src/main/java/yetmorecode/ghidra/LxLoader.java index b9e12a4..71d49f7 100644 --- a/src/main/java/yetmorecode/ghidra/LxLoader.java +++ b/src/main/java/yetmorecode/ghidra/LxLoader.java @@ -191,8 +191,9 @@ private void createImageMappings(LxExecutable executable, Program program, ByteP program.getSymbolTable().createLabel(b.getStart(), "IMAGE_LE_HEADER", SourceType.ANALYSIS); log(CHECK + "Mapped LX Header Section"); - // LE loader section + if (loaderOptions.mapExtra) { + // LE loader section addr = b.getStart().add(header.objectTableOffset); monitor.setMessage(String.format(ARROW + "Mapping LX Loader section")); createData( @@ -202,9 +203,7 @@ private void createImageMappings(LxExecutable executable, Program program, ByteP ); program.getSymbolTable().createLabel(addr, "IMAGE_LE_LOADER", SourceType.ANALYSIS); log(CHECK + "Mapped LX Loader Section"); - } - - if (loaderOptions.mapExtra) { + // LE fixup section var dm = program.getDataTypeManager(); var cat = dm.createCategory(new CategoryPath("/_le/_fixup")); @@ -215,7 +214,8 @@ private void createImageMappings(LxExecutable executable, Program program, ByteP header.dataPagesOffset - dosHeader.e_lfanew() - header.fixupPageTableOffset, loaderOptions, cat, - program + program, + b ); createData(program, addr, ft); program.getSymbolTable().createLabel(addr, "IMAGE_LE_FIXUP", SourceType.ANALYSIS); @@ -277,11 +277,10 @@ private Data createData(Program program, Address address, DataType dt) { return null; } - private byte[] createObjectBlock(Program program, LxExecutable le, ObjectTableEntry object, boolean isLastObject) throws IOException, UsrException { + private byte[] createObjectBlock(Program program, LxExecutable le, ObjectTableEntry object, boolean isLastObject) throws IOException { var header = le.getLeHeader(); var pageMapOffset = le.getDosHeader().e_lfanew() + header.pageTableOffset; var pageSize = header.pageSize; - var space = program.getAddressFactory().getDefaultAddressSpace(); // Temporary memory to assemble all pages to one block byte block[] = new byte[object.size+4096]; @@ -299,15 +298,6 @@ private byte[] createObjectBlock(Program program, LxExecutable le, ObjectTableEn PageMapEntry entry = new PageMapEntry(le.getReader(), pageMapOffset + (index-1) * 4); var pageOffset = header.dataPagesOffset + (entry.getIndex()-1)*pageSize; - - // Create a label for each page - if (loaderOptions.createPageLabels) { - program.getSymbolTable().createLabel( - space.getAddress(loaderOptions.getBaseAddress(object) + blockIndex), - "LE_PAGE_" + index, - SourceType.ANALYSIS - ); - } // Read page from file FactoryBundledWithBinaryReader r = le.getReader(); @@ -486,11 +476,16 @@ private void createEntrypoint(LxExecutable exe, Program program, TaskMonitor mon addr = unit.getAddress(); } - var to = s.getAddress(loaderOptions.getBaseAddress(f.objectNumber) + f.targetOffset); - program.getReferenceManager().removeAllReferencesFrom(addr); - var ref = new MemReferenceImpl(addr, to, RefType.JUMP_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, 0, true); - program.getReferenceManager().addReference(ref); - + if (loaderOptions.fixupEnabled(f) && f.is1616PointerFixup()) { + // 16:16 pointer fixups are weird since they involve segment selectors + // and Ghidra only knows DOS segmented memory (no protected mode segmentation), + // so we remove the old ref and place on calculated by ourself + var to = s.getAddress(loaderOptions.getBaseAddress(f.objectNumber) + f.targetOffset); + program.getReferenceManager().removeAllReferencesFrom(addr); + var ref = new MemReferenceImpl(addr, to, RefType.JUMP_OVERRIDE_UNCONDITIONAL, SourceType.ANALYSIS, 0, true); + program.getReferenceManager().addReference(ref); + } + if (loaderOptions.createFixupLabels) { program.getListing().setComment( addr, @@ -503,11 +498,12 @@ private void createEntrypoint(LxExecutable exe, Program program, TaskMonitor mon } } } - + + // Create a label for each page if (loaderOptions.createPageLabels) { for (var i = 1; i <= exe.header.pageCount; i++) { var addr = s.getAddress(header.dataPagesOffset - dosHeader.e_lfanew()).add((i-1)*header.pageSize); - program.getSymbolTable().createLabel(addr, "IMAGE_LE_DATA", SourceType.ANALYSIS); + program.getSymbolTable().createLabel(addr, "LE_PAGE_" + i, SourceType.ANALYSIS); } } } diff --git a/src/main/java/yetmorecode/ghidra/format/lx/LoaderOptions.java b/src/main/java/yetmorecode/ghidra/format/lx/LoaderOptions.java index b3c6bea..4548272 100644 --- a/src/main/java/yetmorecode/ghidra/format/lx/LoaderOptions.java +++ b/src/main/java/yetmorecode/ghidra/format/lx/LoaderOptions.java @@ -41,7 +41,7 @@ public class LoaderOptions { // Default options public boolean disassembleEntry = true; public boolean addEntry = true; - public boolean mapExtra = true; + public boolean mapExtra = false; public boolean[] enableType = new boolean[9]; // More options available through "loader options" diff --git a/src/main/java/yetmorecode/ghidra/format/lx/datatype/FixupSectionType.java b/src/main/java/yetmorecode/ghidra/format/lx/datatype/FixupSectionType.java index 6d1a336..3cf6324 100644 --- a/src/main/java/yetmorecode/ghidra/format/lx/datatype/FixupSectionType.java +++ b/src/main/java/yetmorecode/ghidra/format/lx/datatype/FixupSectionType.java @@ -7,13 +7,14 @@ import ghidra.program.model.data.Category; import ghidra.program.model.data.StructureDataType; import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryBlock; import ghidra.util.exception.UsrException; import yetmorecode.ghidra.format.lx.LoaderOptions; import yetmorecode.ghidra.format.lx.model.LxExecutable; public class FixupSectionType extends StructureDataType { - public FixupSectionType(LxExecutable executable, int end, LoaderOptions options, Category cat, Program program) throws UsrException, IOException { + public FixupSectionType(LxExecutable executable, int end, LoaderOptions options, Category cat, Program program, MemoryBlock b) throws UsrException, IOException { super("IMAGE_LE_FIXUP", 0); var h = executable.header; @@ -29,7 +30,7 @@ public FixupSectionType(LxExecutable executable, int end, LoaderOptions options, for (var object : executable.getObjects()) { if (executable.objectHasFixups(object)) { add( - new ObjectFixupsType(executable, object, options, cat, program), + new ObjectFixupsType(executable, object, options, cat, program, b), "fixups_object" + object.number, "Fixup records for object #" + object.number ); diff --git a/src/main/java/yetmorecode/ghidra/format/lx/datatype/ObjectFixupsType.java b/src/main/java/yetmorecode/ghidra/format/lx/datatype/ObjectFixupsType.java index a451942..22854db 100644 --- a/src/main/java/yetmorecode/ghidra/format/lx/datatype/ObjectFixupsType.java +++ b/src/main/java/yetmorecode/ghidra/format/lx/datatype/ObjectFixupsType.java @@ -2,10 +2,15 @@ import java.io.IOException; +import ghidra.program.model.address.AddressSpace; import ghidra.program.model.data.Category; import ghidra.program.model.data.CategoryPath; import ghidra.program.model.data.StructureDataType; import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.symbol.MemReferenceImpl; +import ghidra.program.model.symbol.RefType; +import ghidra.program.model.symbol.SourceType; import ghidra.util.exception.UsrException; import yetmorecode.ghidra.format.lx.LoaderOptions; import yetmorecode.ghidra.format.lx.model.LxExecutable; @@ -13,12 +18,16 @@ public class ObjectFixupsType extends StructureDataType { - public ObjectFixupsType(LxExecutable executable, ObjectTableEntry object, LoaderOptions options, Category cat, Program program) throws UsrException, IOException { + public ObjectFixupsType(LxExecutable executable, ObjectTableEntry object, LoaderOptions options, Category cat, Program program, MemoryBlock b) throws UsrException, IOException { super(String.format("%08x_%d", options.getBaseAddress(object), object.number), 0); setCategoryPath(cat.getCategoryPath()); + + // Iterate over all object pages for (int i = 0; i < object.pageCount; i++) { var page = object.pageTableIndex + i; var pageSize = executable.header.pageSize; + + // If page has fixups if (executable.fixups.get(page).size() > 0) { var sub = new StructureDataType(String.format("%08x", options.getBaseAddress(object) + i*pageSize), 0); sub.setCategoryPath(new CategoryPath( @@ -29,17 +38,36 @@ public ObjectFixupsType(LxExecutable executable, ObjectTableEntry object, Loader ) )); add(sub, "page_" + page, "Page #" + page + " fixups"); + + // Each single fixup + var current = 0; for (var f : executable.fixups.get(page)) { + // Add datatype var fixupData = f.toDataType(); + fixupData.setCategoryPath(new CategoryPath( - String.format( - "%s/%08x/%08x", + String.format("%s/%08x/%08x", cat.getCategoryPathName(), options.getBaseAddress(object) + i*pageSize, f.getSourceAddress() ) )); sub.add(fixupData, "fix_" + f.index, "Fixup record #" + f.index); + + // Add xref + var to = b.getStart().add(executable.header.dataPagesOffset - executable.getDosHeader().e_lfanew() + (page-1)*pageSize + current); + var space = program.getAddressFactory().getDefaultAddressSpace(); + var ref = new MemReferenceImpl( + space.getAddress(f.getSourceAddress()), + to, + RefType.DATA_IND, + SourceType.ANALYSIS, + 0, + false + ); + program.getReferenceManager().addReference(ref); + + current += fixupData.getLength(); } } } diff --git a/src/main/java/yetmorecode/ghidra/format/lx/model/FixupRecord.java b/src/main/java/yetmorecode/ghidra/format/lx/model/FixupRecord.java index e9c205a..2e9fa9a 100644 --- a/src/main/java/yetmorecode/ghidra/format/lx/model/FixupRecord.java +++ b/src/main/java/yetmorecode/ghidra/format/lx/model/FixupRecord.java @@ -135,6 +135,10 @@ public int getSourceType() { public boolean isTargetOffset32Bit() { return (targetFlags & 0x10) > 0; } + + public boolean is1616PointerFixup() { + return getSourceType() == SOURCE_1616PTR_FIXUP; + } @Override public DataType toDataType() throws DuplicateNameException, IOException {