diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/MingwRelocationAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/MingwRelocationAnalyzer.java new file mode 100644 index 0000000000..330c7a2b63 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/MingwRelocationAnalyzer.java @@ -0,0 +1,705 @@ +/* ### + * 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.plugin.core.analysis; + +import java.util.*; + +import org.apache.commons.lang3.StringUtils; + +import ghidra.app.cmd.label.DemanglerCmd; +import ghidra.app.services.*; +import ghidra.app.util.bin.format.elf.relocation.ElfRelocationHandler; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; +import ghidra.program.model.data.DataUtilities.ClearDataMode; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.*; +import ghidra.program.model.reloc.Relocation.Status; +import ghidra.program.model.reloc.RelocationResult; +import ghidra.program.model.reloc.RelocationTable; +import ghidra.program.model.symbol.*; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.Msg; +import ghidra.util.exception.*; +import ghidra.util.task.TaskMonitor; + +public class MingwRelocationAnalyzer extends AbstractAnalyzer { + + private final static String NAME = "MinGW Relocations"; + private final static String DESCRIPTION = + "Identify, markup and apply MinGW pseudo-relocations (must be done immediately after import)."; + + public MingwRelocationAnalyzer() { + super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); + // run right before any other analyzer and immediately after import + setPriority(AnalysisPriority.FORMAT_ANALYSIS.before().before().before().before().before()); + setDefaultEnablement(true); + } + + @Override + public boolean canAnalyze(Program program) { + if (!MinGWPseudoRelocationHandler.canHandle(program)) { + return false; + } + if (!program.hasExclusiveAccess()) { + // Exclusive access required since relocation table lacks merge support + Msg.warn(this, + NAME + " analysis requires exclusive access to " + program.getDomainFile()); + return false; + } + return true; + } + + @Override + public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) + throws CancelledException { + if (MinGWPseudoRelocationHandler.isRelocTableWithinSet(program, set)) { + MinGWPseudoRelocationHandler handler = new MinGWPseudoRelocationHandler(program); + handler.processRelocations(log, monitor); + } + return true; + } + +} + +/** + * MinGW pseudo-relocation handler + */ +class MinGWPseudoRelocationHandler { + + private static final String PSEUDO_RELOC_LIST_START_NAME = "__RUNTIME_PSEUDO_RELOC_LIST__"; + private static final String PSEUDO_RELOC_LIST_END_NAME = "__RUNTIME_PSEUDO_RELOC_LIST_END__"; + + private static final int RP_VERSION_V1 = 0; + private static final int RP_VERSION_V2 = 1; + + private static final int OLD_STYLE_ENTRY_SIZE = 8; + private static final int NEW_STYLE_ENTRY_HEADER_SIZE = 12; + + private static final String RELOC_TABLE_HEADER_STRUCT_NAME = "pseudoRelocTableHeader"; + private static final String V1_RELOC_ITEM_STRUCT_NAME = "pseudoRelocItemV1"; + private static final String V2_RELOC_ITEM_STRUCT_NAME = "pseudoRelocItemV2"; + + private Program program; + private int pointerSize; + private DataType dwAddressDataType; + + /** + * Determine if the specified Program contains MingGW pseud-relocations that can be processed. + * This does not check if they were previously processed. + * @param program program to be processed. + * @return true if Program contains MingGW pseud-relocations that can be processed. + */ + static boolean canHandle(Program program) { + return isSupportedProgram(program) && + getLabel(program, PSEUDO_RELOC_LIST_START_NAME) != null && + getLabel(program, PSEUDO_RELOC_LIST_END_NAME) != null; + } + + /** + * Determine if the relocation table is contained within the specified address set. + * @param program program to be processed + * @param set address set + * @return true if table contained within set of addresses + */ + static boolean isRelocTableWithinSet(Program program, AddressSetView set) { + + Symbol pdwTableBegin = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program, + PSEUDO_RELOC_LIST_START_NAME, m -> { + /* ignore */}); + Symbol pdwTableEnd = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program, + PSEUDO_RELOC_LIST_END_NAME, m -> { + /* ignore */}); + if (pdwTableBegin == null || pdwTableEnd == null) { + return false; + } + Address pdwTableBeginAddr = pdwTableBegin.getAddress(); + Address pdwTableEndAddr = pdwTableEnd.getAddress(); + if (pdwTableBeginAddr.getAddressSpace() != pdwTableEndAddr.getAddressSpace()) { + return false; + } + return set.contains(pdwTableBeginAddr, pdwTableEndAddr); + } + + /** + * Construct MinGW pseudo-relocation handler for a Program. + * @param program program to be processed + */ + MinGWPseudoRelocationHandler(Program program) { + this.program = program; + } + + private static boolean isSupportedProgram(Program program) { + return "x86".equals(program.getLanguage().getProcessor().toString()) && + "windows".equals(program.getCompilerSpec().getCompilerSpecID().toString()); + } + + private static Symbol getLabel(Program program, String name) { + return SymbolUtilities.getExpectedLabelOrFunctionSymbol(program, name, m -> { + /* ignore */}); + } + + private Symbol createPrimaryLabel(Address address, String name) { + try { + SymbolTable symbolTable = program.getSymbolTable(); + Symbol symbol = symbolTable.createLabel(address, name, null, SourceType.ANALYSIS); + if (!symbol.isPrimary()) { + symbol.setPrimary(); + } + return symbol; + } + catch (InvalidInputException e) { + throw new AssertException("unexpected", e); + } + } + + boolean processRelocations(MessageLog log, TaskMonitor monitor) throws CancelledException { + if (!isSupportedProgram(program)) { + return false; + } + + pointerSize = program.getDefaultPointerSize(); + dwAddressDataType = new IBO32DataType(program.getDataTypeManager()); + + Symbol pdwTableBegin = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program, + PSEUDO_RELOC_LIST_START_NAME, m -> { + /* ignore */}); + Symbol pdwTableEnd = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program, + PSEUDO_RELOC_LIST_END_NAME, m -> { + /* ignore */}); + if (pdwTableBegin == null || pdwTableEnd == null) { + return false; + } + + Address pdwTableBeginAddr = pdwTableBegin.getAddress(); + Address pdwTableEndAddr = pdwTableEnd.getAddress(); + if (pdwTableBeginAddr.getAddressSpace() != pdwTableEndAddr.getAddressSpace()) { + return false; + } + + long size = pdwTableEndAddr.subtract(pdwTableBeginAddr); + + Memory memory = program.getMemory(); + + // First table entry is used to identify implementation version + int version; + + try { + if (size >= OLD_STYLE_ENTRY_SIZE && memory.getLong(pdwTableBeginAddr) != 0) { + version = RP_VERSION_V1; // header not used + } + else if (size >= NEW_STYLE_ENTRY_HEADER_SIZE) { + applyPseudoRelocHeader(program, pdwTableBeginAddr, log); + version = memory.getInt(pdwTableBeginAddr.add(8)); // 3rd DWORD is version + // update table pointer to first item + pdwTableBeginAddr = pdwTableBeginAddr.add(NEW_STYLE_ENTRY_HEADER_SIZE); + size -= NEW_STYLE_ENTRY_HEADER_SIZE; // reduce size by header size + } + else { + log.appendMsg("Unsupported MinGW relocation table at " + pdwTableBeginAddr); + return false; + } + } + catch (MemoryAccessException | AddressOutOfBoundsException e) { + String msg = "MinGW relocation table processing failed at " + pdwTableBeginAddr; + log.appendMsg(msg); + Msg.error(this, msg, e); + return false; + } + + boolean success; + switch (version) { + case RP_VERSION_V1: + success = relocateV1(pdwTableBeginAddr, (int) (size / OLD_STYLE_ENTRY_SIZE), log, + monitor); + break; + case RP_VERSION_V2: + success = relocateV2(pdwTableBeginAddr, (int) (size / NEW_STYLE_ENTRY_HEADER_SIZE), + log, monitor); + break; + default: + log.appendMsg("Unsupported MinGW relocation table (Version: " + version + ") at " + + pdwTableBeginAddr); + return false; + } + + // Cleanup duplicate External Import symbols + ExternalManager extMgr = program.getExternalManager(); + ReferenceManager refMgr = program.getReferenceManager(); + SymbolTable symbolTable = program.getSymbolTable(); + for (Symbol extSym : program.getSymbolTable().getExternalSymbols()) { + monitor.checkCancelled(); + ExternalLocation extLoc = extMgr.getExternalLocation(extSym); + if (extLoc.getOriginalImportedName() != null) { + continue; // skip - already demangled + } + if (refMgr.hasReferencesTo(extSym.getAddress())) { + continue; // skip - reference exists + } + List globalSymbols = symbolTable.getGlobalSymbols(extSym.getName()); + if (globalSymbols.size() != 1) { + continue; + } + Symbol s = globalSymbols.get(0); + if (memory.isExternalBlockAddress(s.getAddress())) { + extSym.delete(); + } + } + + return success; + } + + /** + * Maps IAT addresses to EXTERNAL block allocation identified by {@link ExternalIATSymbol} + */ + private class ExternalIATSymbolMap extends HashMap { + + private Address nextExtAddr; + + ExternalIATSymbolMap(Address extBlockStart) { + this.nextExtAddr = extBlockStart; + } + + ExternalIATSymbol allocateIATEntry(Address iatEntryAddr, RelocationTable relocationTable) + throws MemoryAccessException, CodeUnitInsertionException { + /** + * symbolAddr (0x41a724) - corresponds to IAT location which refers to + * __imp__ZTIPi -> _ZTIPi + * following original IBO32 value points at IMAGE_IMPORT_BY_NAME: + * dword index (0x135c) + * ds name ("_ZTIPi") + * The above was used to formulate external location and reference + * + * targetAddr (0x410ea0) - location to be fixed-up (relocation applied) + * data at relocation target: + * -original bytes: address of IAT entry (i.e., symbolAddr) - may vary by bitLength! + * -post fixup: adjusted by offset from symbolAddr to real external + * symbol address (*symbolAddr - symbolAddr) + */ + + ExternalIATSymbol existingEntry = get(iatEntryAddr); + if (existingEntry != null) { + return existingEntry; + } + + Reference ref = + program.getReferenceManager().getPrimaryReferenceFrom(iatEntryAddr, 0); + if (!ref.isExternalReference()) { + return null; + } + + Symbol extSym = program.getSymbolTable().getSymbol(ref); + if (extSym == null) { + return null; + } + + ExternalLocation extLoc = + program.getExternalManager().getExternalLocation(extSym); + if (extLoc == null) { + return null; + } + + // Update IAT value - reference to EXTERNAL block + Listing listing = program.getListing(); + listing.clearCodeUnits(iatEntryAddr, iatEntryAddr, false); + Memory memory = program.getMemory(); + if (pointerSize == 8) { // 64-bit + memory.setLong(iatEntryAddr, nextExtAddr.getOffset()); + } + else { // 32-bit + memory.setInt(iatEntryAddr, (int) nextExtAddr.getOffset()); + } + listing.createData(iatEntryAddr, PointerDataType.dataType); + + relocationTable.add(iatEntryAddr, Status.APPLIED_OTHER, 0, null, pointerSize, + extSym.getName()); + + try { + if (extLoc.isFunction()) { + Function func = listing.createFunction(null, nextExtAddr, + new AddressSet(nextExtAddr, nextExtAddr), SourceType.DEFAULT); + func.setThunkedFunction(extLoc.getFunction()); + } + else { + // TODO: Not sure how to preserve relationship to external symbol + // which refers to Library + listing.setComment(nextExtAddr, CodeUnit.PLATE_COMMENT, + "External Location: " + extSym.getName(true)); + String name = extLoc.getOriginalImportedName(); + boolean demangle = true; + if (name == null) { + name = extSym.getName(); + demangle = false; + } + + createPrimaryLabel(nextExtAddr, name); + + if (demangle) { + DemanglerCmd cmd = new DemanglerCmd(nextExtAddr, name); + cmd.applyTo(program); + } + } + } + catch (Exception e) { + Msg.error(this, "Failed to create EXTERNAL block symbol at " + nextExtAddr); + } + + ExternalIATSymbol extIATSym = new ExternalIATSymbol(nextExtAddr, extLoc); + put(iatEntryAddr, extIATSym); + + nextExtAddr = nextExtAddr.add(pointerSize); + + return extIATSym; + } + + } + + /** + * External Import Address Table (IAT) Symbol Record + */ + private static record ExternalIATSymbol(Address extAddr, ExternalLocation extLoc) { + // record only + } + + private Address getDWAddress(MemBuffer buf) { + return (Address) dwAddressDataType.getValue(buf, dwAddressDataType.getDefaultSettings(), + -1); + } + + private boolean relocateV2(Address pdwTableBeginAddr, int entryCount, MessageLog log, + TaskMonitor monitor) throws CancelledException { + + Listing listing = program.getListing(); + Data d = listing.getDefinedDataAt(pdwTableBeginAddr); + if (d != null && (d.isArray() || d.isStructure())) { + return false; // silent - appears to have been previously processed + } + + AddressSpace space = program.getAddressFactory().getDefaultAddressSpace(); + Memory memory = program.getMemory(); + DataTypeManager dtm = program.getDataTypeManager(); + RelocationTable relocationTable = program.getRelocationTable(); + + // Determine number of unique IAT symbol locations referenced + Address addr = pdwTableBeginAddr; + MemoryBufferImpl buf = new MemoryBufferImpl(memory, addr); + HashSet
uniqueIATAddressSet = new HashSet<>(); + for (int i = 0; i < entryCount; i++) { + monitor.checkCancelled(); + Address iatSymbolAddr = getDWAddress(buf); + if (iatSymbolAddr == null) { + log.appendMsg("Failed to read Mingw pseudo-relocation symbol RVA at: " + addr); + return false; + } + uniqueIATAddressSet.add(iatSymbolAddr); + addr = addr.add(NEW_STYLE_ENTRY_HEADER_SIZE); + buf.setPosition(addr); + } + + // Allocate EXTERNAL block + int extBlockSize = uniqueIATAddressSet.size() * pointerSize; + Address extBlockStart; + try { + extBlockStart = allocateBlock(MemoryBlock.EXTERNAL_BLOCK_NAME, extBlockSize); + } + catch (Exception e) { + String msg = "Failed to allocate EXTERNAL block for MinGW relocation processing"; + log.appendMsg(msg); + Msg.error(this, msg, e); + return false; + } + ExternalIATSymbolMap extIATSymbolMap = new ExternalIATSymbolMap(extBlockStart); + + // relocation result counters + int applied = 0; + int failed = 0; + int unsupported = 0; + + // Process relocations + addr = pdwTableBeginAddr; // 1st dword of item is symbol address + buf.setPosition(addr); + for (int i = 0; i < entryCount; i++) { + monitor.checkCancelled(); + + Address iatSymbolAddr = getDWAddress(buf); + + addr = addr.add(4); // 2nd dword of item is target address + buf.setPosition(addr); + Address targetAddr = getDWAddress(buf); + if (targetAddr == null) { + log.appendMsg("Failed to read Mingw pseudo-relocation target RVA at: " + addr); + return false; + } + + addr = addr.add(4); // 3rd dword of item is flags (treated as bit-length) + buf.setPosition(addr); + + String symbolName = null; + RelocationResult result; + try { + + // read item flags as bit-length + int bitLength = buf.getInt(0) & 0xff; + + ExternalIATSymbol extSymbolEntry = + extIATSymbolMap.allocateIATEntry(iatSymbolAddr, relocationTable); + if (extSymbolEntry == null) { + throw new UnsupportedOperationException(); + } + + symbolName = extSymbolEntry.extLoc.getOriginalImportedName(); + if (symbolName == null) { + symbolName = extSymbolEntry.extLoc.getSymbol().getName(); + } + + // compute relocation symbol offset value + long impValue = pointerSize == 8 ? memory.getLong(iatSymbolAddr) + : Integer.toUnsignedLong(memory.getInt(iatSymbolAddr)); + Address pointerValue = space.getAddress(impValue); + + long qwOffset = pointerValue.subtract(iatSymbolAddr); + long addend = 0; + + result = new RelocationResult(Status.APPLIED_OTHER, bitLength / 8); // treat flags as bit length + switch (bitLength) { + case 8: + byte val8 = (byte) (memory.getByte(targetAddr) + qwOffset); + memory.setByte(targetAddr, val8); + ++applied; + break; + case 16: + short val16 = (short) (memory.getShort(targetAddr) + qwOffset); + memory.setShort(targetAddr, val16); + ++applied; + break; + case 32: + int val32 = memory.getInt(targetAddr); + if (pointerSize == 4) { + addend = (val32 - (int) iatSymbolAddr.getOffset()); + } + val32 += qwOffset; + memory.setInt(targetAddr, val32); + ++applied; + break; + case 64: + long val64 = memory.getLong(targetAddr); + if (pointerSize == 8) { + addend = val64 - iatSymbolAddr.getOffset(); + } + val64 += qwOffset; + memory.setLong(targetAddr, val64); + ++applied; + break; + default: + result = RelocationResult.UNSUPPORTED; + ++unsupported; + } + + if (addend != 0) { + ElfRelocationHandler.warnExternalOffsetRelocation(program, + targetAddr, pointerValue, symbolName, addend, null); + if (!memory.getBlock(targetAddr).isExecute()) { + // assume pointer if not in execute block + ElfRelocationHandler.applyComponentOffsetPointer(program, + targetAddr, addend); + } + } + } + catch (MemoryAccessException | UnsupportedOperationException + | CodeUnitInsertionException e) { + markAsError(targetAddr, symbolName, e.getMessage(), log); + result = RelocationResult.FAILURE; + ++failed; + } + + relocationTable.add(targetAddr, result.status(), 0, null, result.byteLength(), + symbolName); + + addr = addr.add(4); + buf.setPosition(addr); // position on next element + } + + if (failed != 0 || unsupported != 0) { + log.appendMsg("MinGW pseudo-relocations - applied:" + applied + " failed:" + failed + + " unsupported:" + unsupported); + } + + Structure relocEntryStruct = new StructureDataType(V2_RELOC_ITEM_STRUCT_NAME, 0, dtm); + relocEntryStruct.setPackingEnabled(true); + relocEntryStruct.add(dwAddressDataType, "sym", null); + relocEntryStruct.add(DWordDataType.dataType, "target", null); // could be offcut + relocEntryStruct.add(DWordDataType.dataType, "flags", null); + + Array a = new ArrayDataType(relocEntryStruct, entryCount, -1, dtm); + + try { + DataUtilities.createData(program, pdwTableBeginAddr, a, -1, false, + ClearDataMode.CLEAR_ALL_CONFLICT_DATA); + } + catch (CodeUnitInsertionException e) { + log.appendMsg( + "Failed to markup Mingw pseudo-relocation Table at: " + pdwTableBeginAddr); + } + return true; + } + + private void applyPseudoRelocHeader(Program program, Address relocHeaderAddr, MessageLog log) { + + Structure relocHeaderStruct = + new StructureDataType(RELOC_TABLE_HEADER_STRUCT_NAME, 0, program.getDataTypeManager()); + relocHeaderStruct.setPackingEnabled(true); + relocHeaderStruct.add(DWordDataType.dataType, "zero1", null); + relocHeaderStruct.add(DWordDataType.dataType, "zero2", null); + relocHeaderStruct.add(DWordDataType.dataType, "version", null); + + try { + DataUtilities.createData(program, relocHeaderAddr, relocHeaderStruct, -1, + false, ClearDataMode.CLEAR_ALL_CONFLICT_DATA); + } + catch (CodeUnitInsertionException e) { + log.appendMsg( + "Failed to markup Mingw pseudo-relocation Table header at: " + relocHeaderAddr); + } + } + + private void markAsError(Address relocationAddress, String symbolName, String msg, + MessageLog log) { + symbolName = StringUtils.isEmpty(symbolName) ? "" : symbolName; + log.appendMsg("MinGW Relocation Error: at " + relocationAddress + ", Symbol = " + + symbolName + ": " + msg); + BookmarkManager bookmarkManager = program.getBookmarkManager(); + bookmarkManager.setBookmark(relocationAddress, BookmarkType.ERROR, "MinGW Relocation", + "MinGW Relocation Error: Symbol = " + symbolName + ": " + msg); + } + + private void markAsError(Address relocationAddress, String msg, MessageLog log) { + log.appendMsg("MinGW Relocation Error: at " + relocationAddress + ": " + msg); + BookmarkManager bookmarkManager = program.getBookmarkManager(); + bookmarkManager.setBookmark(relocationAddress, BookmarkType.ERROR, "MinGW Relocation", + "MinGW Relocation Error: " + msg); + } + + private Address allocateBlock(String blockName, int extBlockSize) throws Exception { + + Memory memory = program.getMemory(); + AddressSpace space = program.getAddressFactory().getDefaultAddressSpace(); + long delta = 0x10000000; + Address startAddr = null; + for (long offset = delta; offset < 0x100000000L; offset += delta) { + Address addr = space.getAddress(offset); + AddressIterator addresses = memory.getAddresses(addr, true); + if (!addresses.hasNext()) { + startAddr = addr; + break; + } + Address nextAddr = addresses.next(); + if (!nextAddr.getAddressSpace().equals(space) || + nextAddr.subtract(addr) > extBlockSize) { + startAddr = addr; + break; + } + } + if (startAddr != null) { + memory.createUninitializedBlock(blockName, startAddr, extBlockSize, false); + return startAddr; + } + throw new MemoryAccessException("Failed to allocate block: " + blockName); + } + + private boolean relocateV1(Address pdwTablePayloadAddr, int entryCount, MessageLog log, + TaskMonitor monitor) throws CancelledException { + + Listing listing = program.getListing(); + Data d = listing.getDefinedDataAt(pdwTablePayloadAddr); + if (d != null && (d.isArray() || d.isStructure())) { + return false; // silent - appears to have been previously processed + } + + Memory memory = program.getMemory(); + DataTypeManager dtm = program.getDataTypeManager(); + RelocationTable relocationTable = program.getRelocationTable(); + + Address addr = pdwTablePayloadAddr; + DumbMemBufferImpl buf = new DumbMemBufferImpl(memory, pdwTablePayloadAddr); + + RelocationResult appliedResult = new RelocationResult(Status.APPLIED_OTHER, 4); + + // relocation result counters + int applied = 0; + int failed = 0; + + for (int i = 0; i < entryCount; i++) { + monitor.checkCancelled(); + + RelocationResult result = appliedResult; + int dwOffset = 0; + try { + dwOffset = buf.getInt(0); + } + catch (MemoryAccessException e1) { + log.appendMsg("Failed to read Mingw pseudo-relocation offset at: " + addr); + return false; + } + + addr = addr.add(4); + buf.setPosition(addr); // position on 2nd value + Address targetAddr = getDWAddress(buf); + if (targetAddr == null) { + log.appendMsg("Failed to read Mingw pseudo-relocation target RVA at: " + addr); + return false; + } + + try { + int val32 = memory.getInt(targetAddr) + dwOffset; + memory.setInt(targetAddr, val32); + ++applied; + } + catch (Exception e) { + markAsError(targetAddr, e.getMessage(), log); + result = RelocationResult.FAILURE; + ++failed; + } + + relocationTable.add(targetAddr, result.status(), 0, null, result.byteLength(), null); + + addr = addr.add(4); + buf.setPosition(addr); // position on next element + } + + if (failed != 0) { + log.appendMsg("MinGW pseudo-relocations - applied:" + applied + " failed:" + failed); + } + + Structure s = new StructureDataType(V1_RELOC_ITEM_STRUCT_NAME, 0, dtm); + s.setPackingEnabled(true); + s.add(DWordDataType.dataType, "addend", null); + s.add(DWordDataType.dataType, "target", null); // may be offcut + + Array a = new ArrayDataType(s, entryCount, -1, dtm); + + try { + DataUtilities.createData(program, pdwTablePayloadAddr, a, -1, false, + ClearDataMode.CLEAR_ALL_CONFLICT_DATA); + } + catch (CodeUnitInsertionException e) { + Msg.error(this, + "Failed to markup Mingw pseudo-relocation Table at: " + pdwTablePayloadAddr); + } + return true; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTablePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTablePlugin.java index c06ce62776..1ff85adf55 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTablePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTablePlugin.java @@ -103,6 +103,7 @@ public class RelocationTablePlugin extends Plugin implements DomainObjectListene @Override public void domainObjectChanged(DomainObjectChangedEvent ev) { if (ev.containsEvent(ChangeManager.DOCR_IMAGE_BASE_CHANGED) || + ev.containsEvent(ChangeManager.DOCR_RELOCATION_ADDED) || ev.containsEvent(DomainObject.DO_OBJECT_RESTORED)) { provider.setProgram(currentProgram); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java b/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java index 3b52a66aa5..067d3aa7b3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java @@ -184,7 +184,7 @@ public class FlatProgramAPI { * only necessary to analyze changes and not the entire program which can take much * longer and affect more of the program than is necessary. */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public void analyze(Program program) { analyzeAll(program); } @@ -405,7 +405,7 @@ public class FlatProgramAPI { * @deprecated use {@link #createLabel(Address, String, boolean)} instead. * Deprecated in Ghidra 7.4 */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public final Symbol createSymbol(Address address, String name, boolean makePrimary) throws Exception { return createLabel(address, name, makePrimary); @@ -443,9 +443,8 @@ public class FlatProgramAPI { */ public final Symbol createLabel(Address address, String name, Namespace namespace, boolean makePrimary, SourceType sourceType) throws Exception { - Symbol symbol; SymbolTable symbolTable = currentProgram.getSymbolTable(); - symbol = symbolTable.createLabel(address, name, namespace, sourceType); + Symbol symbol = symbolTable.createLabel(address, name, namespace, sourceType); if (makePrimary && !symbol.isPrimary()) { SetLabelPrimaryCmd cmd = new SetLabelPrimaryCmd(address, name, namespace); if (cmd.applyTo(currentProgram)) { @@ -458,7 +457,7 @@ public class FlatProgramAPI { /** * @deprecated use {@link #createLabel(Address, String, boolean, SourceType)} instead. Deprecated in Ghidra 7.4 */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public final Symbol createSymbol(Address address, String name, boolean makePrimary, boolean makeUnique, SourceType sourceType) throws Exception { return createLabel(address, name, makePrimary, sourceType); @@ -1129,7 +1128,7 @@ public class FlatProgramAPI { * no longer have to be unique. Use {@link #getGlobalFunctions(String)} * Deprecated in Ghidra 7.4 */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public final Function getFunction(String name) { List globalFunctions = currentProgram.getListing().getGlobalFunctions(name); return globalFunctions.isEmpty() ? null : globalFunctions.get(0); @@ -1383,7 +1382,7 @@ public class FlatProgramAPI { * @deprecated Since the same label name can be at the same address if in a different namespace, * this method is ambiguous. Use {@link #getSymbolAt(Address, String, Namespace)} instead. */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public final Symbol getSymbolAt(Address address, String name) { SymbolIterator symbols = currentProgram.getSymbolTable().getSymbolsAsIterator(address); for (Symbol symbol : symbols) { @@ -1477,7 +1476,7 @@ public class FlatProgramAPI { * @throws IllegalStateException if there is more than one symbol with that name. * @deprecated use {@link #getSymbols(String, Namespace)} */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public final Symbol getSymbol(String name, Namespace namespace) { List symbols = currentProgram.getSymbolTable().getSymbols(name, namespace); if (symbols.size() == 1) { @@ -1583,7 +1582,7 @@ public class FlatProgramAPI { * @deprecated This method is deprecated because it did not allow you to include the * largest possible address. Instead use the one that takes a start address and a length. */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public final ProgramFragment createFragment(String fragmentName, Address start, Address end) throws DuplicateNameException, NotFoundException { ProgramModule module = currentProgram.getListing().getDefaultRootModule(); @@ -1617,7 +1616,7 @@ public class FlatProgramAPI { * @deprecated This method is deprecated because it did not allow you to include the * largest possible address. Instead use the one that takes a start address and a length. */ - @Deprecated + @Deprecated(since = "7.4", forRemoval = true) public final ProgramFragment createFragment(ProgramModule module, String fragmentName, Address start, Address end) throws DuplicateNameException, NotFoundException { ProgramFragment fragment = getFragment(module, fragmentName); diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java index e6516ef974..0298e76bc7 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java @@ -19,12 +19,7 @@ import java.io.File; import java.io.IOException; import generic.jar.ResourceFile; -import ghidra.app.util.demangler.DemangledAddressTable; -import ghidra.app.util.demangler.DemangledException; -import ghidra.app.util.demangler.DemangledFunction; -import ghidra.app.util.demangler.DemangledObject; -import ghidra.app.util.demangler.Demangler; -import ghidra.app.util.demangler.DemanglerOptions; +import ghidra.app.util.demangler.*; import ghidra.app.util.opinion.ElfLoader; import ghidra.app.util.opinion.MachoLoader; import ghidra.framework.Application; @@ -66,6 +61,7 @@ public class GnuDemangler implements Demangler { if (!specId.toLowerCase().contains("windows")) { return true; } + return false; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java index dad8abd667..e5f9dd6d36 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationManager.java @@ -31,6 +31,7 @@ import ghidra.program.model.mem.Memory; import ghidra.program.model.reloc.Relocation; import ghidra.program.model.reloc.Relocation.Status; import ghidra.program.model.reloc.RelocationTable; +import ghidra.program.util.ChangeManager; import ghidra.util.Lock; import ghidra.util.exception.CancelledException; import ghidra.util.exception.VersionException; @@ -147,9 +148,15 @@ public class RelocationManager implements RelocationTable, ManagerDB { try { byte flags = RelocationDBAdapter.getFlags(status, 0); adapter.add(addr, flags, type, values, bytes, symbolName); - return new Relocation(addr, status, type, values, + Relocation reloc = new Relocation(addr, status, type, values, getOriginalBytes(addr, status, bytes, 0), symbolName); + + // fire event + // TODO: full change support is missing + program.setChanged(ChangeManager.DOCR_RELOCATION_ADDED, null, reloc); + + return reloc; } catch (IOException e) { program.dbError(e); @@ -167,9 +174,15 @@ public class RelocationManager implements RelocationTable, ManagerDB { try { byte flags = RelocationDBAdapter.getFlags(status, byteLength); adapter.add(addr, flags, type, values, null, symbolName); - return new Relocation(addr, status, type, values, + Relocation reloc = new Relocation(addr, status, type, values, getOriginalBytes(addr, status, null, byteLength), symbolName); + + // fire event + // TODO: full change support is missing + program.setChanged(ChangeManager.DOCR_RELOCATION_ADDED, null, reloc); + + return reloc; } catch (IOException e) { program.dbError(e); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java index a86bedc28a..ba43d4fa1d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java @@ -179,16 +179,25 @@ public abstract class AbstractPointerTypedefBuiltIn extends BuiltIn implements T @Override public Class getValueClass(Settings settings) { + if (settings == null) { + settings = getDefaultSettings(); + } return modelTypedef.getValueClass(settings); } @Override public Object getValue(MemBuffer buf, Settings settings, int length) { + if (settings == null) { + settings = getDefaultSettings(); + } return modelTypedef.getValue(buf, settings, length); } @Override public String getRepresentation(MemBuffer buf, Settings settings, int length) { + if (settings == null) { + settings = getDefaultSettings(); + } return modelTypedef.getRepresentation(buf, settings, length); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java index 26dc584901..66ba56455e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java @@ -724,6 +724,17 @@ public interface ChangeManager { */ public static final int DOCR_USER_DATA_CHANGED = 201; + //////////////////////////////////////////////////////////////////////////// + // + // RELOCATIONS + // + //////////////////////////////////////////////////////////////////////////// + + /** + * A relocation entry was added + */ + public static final int DOCR_RELOCATION_ADDED = 210; + //////////////////////////////////////////////////////////////////////////// /** * Mark the state of a Program as having changed and generate