From b23ab30f5894c0042cf60bd2ecb3fdbb59070f5b Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Thu, 14 Jul 2022 15:59:13 -0400 Subject: [PATCH] GP-2128 changed relocation table to support multiple relocations at the same address and rely on original FileBytes for relocations when possible instead of storing within relocation. --- .../analysis/OperandReferenceAnalyzer.java | 2 +- .../core/analysis/ScalarOperandAnalyzer.java | 10 +- .../core/disassembler/AddressTable.java | 5 +- .../core/disassembler/EntryPointAnalyzer.java | 2 +- .../plugin/core/reloc/RelocationProvider.java | 8 +- .../core/reloc/RelocationTableModel.java | 91 +++++++--- .../RelocationToAddressTableRowMapper.java | 11 +- .../format/elf/ElfDefaultGotPltMarkup.java | 2 +- .../ghidra/app/util/opinion/CoffLoader.java | 14 +- .../app/util/opinion/ElfProgramBuilder.java | 30 ++- .../app/util/opinion/MachoProgramBuilder.java | 29 +-- .../ghidra/app/util/opinion/MzLoader.java | 3 +- .../ghidra/app/util/opinion/PeLoader.java | 8 +- .../MicrosoftCodeAnalyzerPlugin/PEUtil.java | 139 +++++++------- .../database/reloc/RelocationDBAdapter.java | 106 +++++++---- .../reloc/RelocationDBAdapterNoTable.java | 39 ++-- .../database/reloc/RelocationDBAdapterV1.java | 59 +++--- .../database/reloc/RelocationDBAdapterV2.java | 65 ++++--- .../database/reloc/RelocationDBAdapterV3.java | 87 +++++---- .../database/reloc/RelocationDBAdapterV4.java | 93 +++++----- .../database/reloc/RelocationDBAdapterV5.java | 101 +++++++++++ .../database/reloc/RelocationManager.java | 171 ++++++++++++------ .../program/model/reloc/Relocation.java | 9 +- .../program/model/reloc/RelocationTable.java | 47 +++-- .../elf/extend/PowerPC64_ElfExtension.java | 7 +- 25 files changed, 671 insertions(+), 467 deletions(-) create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java index 8d802fbf13..133c3ca89a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java @@ -1032,7 +1032,7 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer { RelocationTable relocationTable = program.getRelocationTable(); if (relocationTable.isRelocatable()) { // if it is relocatable, then there should be no pointers in memory, other than relacatable ones - if (relocationTable.getSize() > 0 && relocationTable.getRelocation(target) == null) { + if (relocationTable.getSize() != 0 && !relocationTable.hasRelocation(target)) { return false; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java index ff62e6debc..275459d2b5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java @@ -30,7 +30,6 @@ import ghidra.program.model.lang.GhidraLanguagePropertyKeys; import ghidra.program.model.lang.Language; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.program.model.reloc.Relocation; import ghidra.program.model.reloc.RelocationTable; import ghidra.program.model.scalar.Scalar; import ghidra.program.model.symbol.*; @@ -115,13 +114,12 @@ public class ScalarOperandAnalyzer extends AbstractAnalyzer { } Scalar scalar = (Scalar) objs[j]; - //if a relocation exists, then this is a valid address + //if a relocation exists, assume this is a valid address + RelocationTable relocTable = program.getRelocationTable(); boolean found = false; for (int r = 0; r < instr.getLength(); ++r) { Address addr = instr.getMinAddress().add(r); - RelocationTable relocTable = program.getRelocationTable(); - Relocation reloc = relocTable.getRelocation(addr); - if (reloc != null) { + if (relocTable.hasRelocation(addr)) { try { switch (scalar.bitLength()) { case 8: @@ -196,7 +194,7 @@ public class ScalarOperandAnalyzer extends AbstractAnalyzer { RelocationTable relocationTable = program.getRelocationTable(); if (relocationTable.isRelocatable()) { // if it is relocatable, then there should be no pointers in memory, other than relacatable ones - if (relocationTable.getSize() > 0 && relocationTable.getRelocation(target) == null) { + if (relocationTable.getSize() != 0 && !relocationTable.hasRelocation(target)) { return false; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java index 54387a4646..9c18cc9ae6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java @@ -1407,7 +1407,8 @@ public class AddressTable { * relocatable programs. Every address should be in the relocation table. * * @param target location to check - * @return + * @return false if relocations are defined but not at the specified target address, + * otherwise true. */ private static boolean isValidRelocationAddress(Program program, Address target) { // If the program is relocatable, and this address is not one of the relocations @@ -1415,7 +1416,7 @@ public class AddressTable { RelocationTable relocationTable = program.getRelocationTable(); if (relocationTable.isRelocatable()) { // if it is relocatable, then there should be no pointers in memory, other than relacatable ones - if (relocationTable.getSize() > 0 && relocationTable.getRelocation(target) == null) { + if (relocationTable.getSize() != 0 && !relocationTable.hasRelocation(target)) { return false; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java index 16112b7440..85c1452612 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java @@ -274,7 +274,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer { } // relocation at this place, don't trust it - if (program.getRelocationTable().getRelocation(entry) != null) { + if (program.getRelocationTable().hasRelocation(entry)) { laterIter.remove(); continue; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java index 4becb0cd70..b7a13edb60 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java @@ -20,11 +20,11 @@ import java.awt.Dimension; import javax.swing.*; +import ghidra.app.plugin.core.reloc.RelocationTableModel.RelocationRowObject; import ghidra.app.services.GoToService; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.listing.Program; -import ghidra.program.model.reloc.Relocation; import ghidra.util.HelpLocation; import ghidra.util.table.*; @@ -34,8 +34,8 @@ class RelocationProvider extends ComponentProviderAdapter { private RelocationTablePlugin plugin; private JPanel mainPanel; private Program currentProgram; - private GhidraTableFilterPanel tableFilterPanel; - private GhidraThreadedTablePanel threadedPanel; + private GhidraTableFilterPanel tableFilterPanel; + private GhidraThreadedTablePanel threadedPanel; RelocationProvider(RelocationTablePlugin plugin) { super(plugin.getTool(), "Relocation Table", plugin.getName()); @@ -83,6 +83,8 @@ class RelocationProvider extends ComponentProviderAdapter { table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); + table.getSelectionModel().addListSelectionListener(e -> contextChanged()); + ToolTipManager.sharedInstance().registerComponent(table); panel.add(threadedPanel, BorderLayout.CENTER); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java index f95c6a5f93..6607587f4c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationTableModel.java @@ -15,10 +15,12 @@ */ package ghidra.app.plugin.core.reloc; +import java.util.Comparator; import java.util.Iterator; import docking.widgets.table.DiscoverableTableUtils; import docking.widgets.table.TableColumnDescriptor; +import ghidra.app.plugin.core.reloc.RelocationTableModel.RelocationRowObject; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; @@ -33,12 +35,31 @@ import ghidra.util.table.field.AbstractProgramBasedDynamicTableColumn; import ghidra.util.table.field.AddressTableColumn; import ghidra.util.task.TaskMonitor; -class RelocationTableModel extends AddressBasedTableModel { +class RelocationTableModel extends AddressBasedTableModel { - final static String RELOCATION_ADDRESS = "Address"; - final static String RELOCATION_TYPE = "Type"; - final static String RELOCATION_VALUE = "Values"; - final static String RELOCATION_BYTES = "Original Bytes"; + private static Comparator ADDRESS_SORT_COMPARATOR = + new Comparator() { + + @Override + public int compare(RelocationRowObject o1, RelocationRowObject o2) { + int c = o1.relocation.getAddress().compareTo(o2.relocation.getAddress()); + if (c == 0) { + c = o1.relocationIndex - o2.relocationIndex; + } + return c; + } + }; + + static final int ADDRESS_COL = 0; + static final int TYPE_COL = 1; + static final int VALUE_COL = 2; + static final int BYTES_COL = 3; + static final int NAME_COL = 4; + + static final String RELOCATION_ADDRESS = "Address"; + static final String RELOCATION_TYPE = "Type"; + static final String RELOCATION_VALUE = "Values"; + static final String RELOCATION_BYTES = "Original Bytes"; static final String RELOCATION_NAME = "Name"; public RelocationTableModel(ServiceProvider serviceProvider, Program program, @@ -47,8 +68,8 @@ class RelocationTableModel extends AddressBasedTableModel { } @Override - protected TableColumnDescriptor createTableColumnDescriptor() { - TableColumnDescriptor descriptor = new TableColumnDescriptor<>(); + protected TableColumnDescriptor createTableColumnDescriptor() { + TableColumnDescriptor descriptor = new TableColumnDescriptor<>(); descriptor.addVisibleColumn( DiscoverableTableUtils.adaptColumForModel(this, new AddressTableColumn()), 1, true); @@ -60,6 +81,14 @@ class RelocationTableModel extends AddressBasedTableModel { return descriptor; } + @Override + protected Comparator createSortComparator(int columnIndex) { + if (columnIndex == ADDRESS_COL) { + return ADDRESS_SORT_COMPARATOR; + } + return super.createSortComparator(columnIndex); + } + @Override public void setProgram(Program p) { super.setProgram(p); @@ -68,32 +97,48 @@ class RelocationTableModel extends AddressBasedTableModel { } @Override - protected void doLoad(Accumulator accumulator, TaskMonitor monitor) + protected void doLoad(Accumulator accumulator, TaskMonitor monitor) throws CancelledException { if (getProgram() == null) { return; } + int relocationIndex = 0; RelocationTable relocationTable = getProgram().getRelocationTable(); Iterator iterator = relocationTable.getRelocations(); while (iterator.hasNext()) { Relocation r = iterator.next(); - accumulator.add(r); + accumulator.add(new RelocationRowObject(r, ++relocationIndex)); } } @Override public Address getAddress(int row) { - Relocation relocation = filteredData.get(row); - return relocation.getAddress(); + RelocationRowObject rowObject = filteredData.get(row); + return rowObject.relocation.getAddress(); } //================================================================================================== // Inner Classes //================================================================================================== + static class RelocationRowObject { + + /** + * The relocationIndex must be used to differentiate multiple relocations + * for the same address. This must be used for secondary comparison when sorting on address. + */ + final int relocationIndex; + final Relocation relocation; + + public RelocationRowObject(Relocation r, int relocationIndex) { + this.relocationIndex = relocationIndex; + this.relocation = r; + } + } + private static class RelocationTypeColumn extends - AbstractProgramBasedDynamicTableColumn { + AbstractProgramBasedDynamicTableColumn { @Override public String getColumnName() { @@ -101,15 +146,15 @@ class RelocationTableModel extends AddressBasedTableModel { } @Override - public String getValue(Relocation rowObject, Settings settings, Program program, + public String getValue(RelocationRowObject rowObject, Settings settings, Program program, ServiceProvider serviceProvider) throws IllegalArgumentException { - return "0x" + Integer.toHexString(rowObject.getType()); + return "0x" + Integer.toHexString(rowObject.relocation.getType()); } } private static class RelocationValueColumn extends - AbstractProgramBasedDynamicTableColumn { + AbstractProgramBasedDynamicTableColumn { @Override public String getColumnName() { @@ -117,9 +162,9 @@ class RelocationTableModel extends AddressBasedTableModel { } @Override - public String getValue(Relocation rowObject, Settings settings, Program program, + public String getValue(RelocationRowObject rowObject, Settings settings, Program program, ServiceProvider serviceProvider) throws IllegalArgumentException { - return packValues(rowObject.getValues()); + return packValues(rowObject.relocation.getValues()); } private String packValues(long[] values) { @@ -138,7 +183,7 @@ class RelocationTableModel extends AddressBasedTableModel { } private static class RelocationBytesColumn extends - AbstractProgramBasedDynamicTableColumn { + AbstractProgramBasedDynamicTableColumn { @Override public String getColumnName() { @@ -146,9 +191,9 @@ class RelocationTableModel extends AddressBasedTableModel { } @Override - public String getValue(Relocation rowObject, Settings settings, Program program, + public String getValue(RelocationRowObject rowObject, Settings settings, Program program, ServiceProvider serviceProvider) throws IllegalArgumentException { - return packBytes(rowObject.getBytes()); + return packBytes(rowObject.relocation.getBytes()); } private String packBytes(byte[] bytes) { @@ -171,7 +216,7 @@ class RelocationTableModel extends AddressBasedTableModel { } private static class RelocationNameColumn extends - AbstractProgramBasedDynamicTableColumn { + AbstractProgramBasedDynamicTableColumn { @Override public String getColumnName() { @@ -179,9 +224,9 @@ class RelocationTableModel extends AddressBasedTableModel { } @Override - public String getValue(Relocation rowObject, Settings settings, Program program, + public String getValue(RelocationRowObject rowObject, Settings settings, Program program, ServiceProvider serviceProvider) throws IllegalArgumentException { - return rowObject.getSymbolName(); + return rowObject.relocation.getSymbolName(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationToAddressTableRowMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationToAddressTableRowMapper.java index 479ac24958..90a44ac17c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationToAddressTableRowMapper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationToAddressTableRowMapper.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +15,19 @@ */ package ghidra.app.plugin.core.reloc; +import ghidra.app.plugin.core.reloc.RelocationTableModel.RelocationRowObject; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; -import ghidra.program.model.reloc.Relocation; import ghidra.util.table.ProgramLocationTableRowMapper; -public class RelocationToAddressTableRowMapper extends ProgramLocationTableRowMapper { +public class RelocationToAddressTableRowMapper + extends ProgramLocationTableRowMapper { @Override - public Address map( Relocation rowObject, Program program, ServiceProvider serviceProvider ) { - return rowObject.getAddress(); + public Address map(RelocationRowObject rowObject, Program program, + ServiceProvider serviceProvider) { + return rowObject.relocation.getAddress(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java index 86d0fe651b..baed2f3c30 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java @@ -660,7 +660,7 @@ public class ElfDefaultGotPltMarkup { if (program.getImageBase().getOffset() != 0) { return null; } - if (program.getRelocationTable().getRelocation(data.getAddress()) != null) { + if (program.getRelocationTable().hasRelocation(data.getAddress())) { return null; } MemoryBlock tBlock = memory.getBlock(".text"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java index a9072e0d32..0c69fc83bb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java @@ -689,8 +689,6 @@ public class CoffLoader extends AbstractLibrarySupportLoader { sectionStartAddr.add(relocation.getAddress() - section.getVirtualAddress()); short relocationType = relocation.getType(); - byte[] origBytes = new byte[0]; - if (handler == null) { ++failureCount; handleRelocationError(program, address, relocationType, @@ -698,7 +696,6 @@ public class CoffLoader extends AbstractLibrarySupportLoader { } else { try { - origBytes = new byte[4]; if (address.equals(failedAddr)) { // skip relocation if previous failed relocation was at the same address // since it is likely dependent on the previous failed relocation result @@ -708,15 +705,10 @@ public class CoffLoader extends AbstractLibrarySupportLoader { String.format("Skipped dependent COFF Relocation type 0x%x at %s", relocationType, address.toString()); Msg.error(this, program.getName() + ": " + logMessage); - - // TODO: once RelocationTable can retain all relocations at the same address - // this continue statement should be removed (see GP-2128) - continue; } - //else { - program.getMemory().getBytes(address, origBytes); + else { handler.relocate(address, relocation, relocationContext); - //} + } } catch (MemoryAccessException e) { ++failureCount; @@ -758,7 +750,7 @@ public class CoffLoader extends AbstractLibrarySupportLoader { // table. (see GP-2128) program.getRelocationTable() .add(address, relocation.getType(), - new long[] { relocation.getSymbolIndex() }, origBytes, + new long[] { relocation.getSymbolIndex() }, null, symbol != null ? symbol.getName() : ""); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java index 697889a968..d115b4126a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java @@ -902,8 +902,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { long[] values = new long[] { reloc.getSymbolIndex() }; - byte[] bytes = elf.is64Bit() ? new byte[8] : new byte[4]; - if (relrRelocationType != 0) { type = relrRelocationType; reloc.setType(relrRelocationType); @@ -927,8 +925,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { } } - memory.getBytes(relocAddr, bytes); - if (context != null) { if (relrTypeUnknown) { ElfRelocationHandler.markAsUnsupportedRelr(program, relocAddr); @@ -948,7 +944,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { finally { // Save relocation data program.getRelocationTable() - .add(relocAddr, reloc.getType(), values, bytes, symbolName); + .add(relocAddr, reloc.getType(), values, null, symbolName); } } } @@ -957,13 +953,14 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { public long getOriginalValue(Address addr, boolean signExtend) throws MemoryAccessException { byte[] bytes; int len = elf.is64Bit() ? 8 : 4; - Relocation relocation = program.getRelocationTable().getRelocation(addr); - if (relocation == null) { + List relocations = program.getRelocationTable().getRelocations(addr); + if (relocations.isEmpty()) { bytes = new byte[len]; memory.getBytes(addr, bytes); } else { - bytes = relocation.getBytes(); + // use bytes from first relocation + bytes = relocations.get(0).getBytes(); } DataConverter dataConverter = DataConverter.getInstance(elf.isBigEndian()); return signExtend ? dataConverter.getSignedValue(bytes, len) @@ -972,23 +969,18 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { @Override public boolean addFakeRelocTableEntry(Address address, int length) - throws MemoryAccessException, AddressOverflowException { - byte[] bytes = new byte[length]; + throws AddressOverflowException { Address maxAddr = address.addNoWrap(length - 1); RelocationTable relocationTable = program.getRelocationTable(); - Relocation relocation = relocationTable.getRelocation(address); - if (relocation != null) { + List relocations = relocationTable.getRelocations(address); + if (!relocations.isEmpty()) { return false; } - relocation = relocationTable.getRelocationAfter(address); - if (relocation != null && relocation.getAddress().compareTo(maxAddr) <= 0) { + Address nextRelocAddr = relocationTable.getRelocationAddressAfter(address); + if (nextRelocAddr != null && nextRelocAddr.compareTo(maxAddr) <= 0) { return false; } - int cnt = memory.getBytes(address, bytes); - if (cnt != length) { - throw new MemoryAccessException(); - } - relocationTable.add(address, 0, new long[0], bytes, null); + relocationTable.add(address, 0, new long[0], null, null); return true; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java index 72320d1270..fb454c6f84 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java @@ -1201,7 +1201,6 @@ public class MachoProgramBuilder { while (iter.hasNext()) { RelocationInfo relocationInfo = iter.next(); Address address = relocationMap.get(relocationInfo); - byte[] origBytes = getOriginalRelocationBytes(relocationInfo, address); MachoRelocation relocation = null; if (handler == null) { @@ -1235,7 +1234,7 @@ public class MachoProgramBuilder { .add(address, relocationInfo.getType(), new long[] { relocationInfo.getValue(), relocationInfo.getLength(), relocationInfo.isPcRelocated() ? 1 : 0, relocationInfo.isExternal() ? 1 : 0, relocationInfo.isScattered() ? 1 : 0 }, - origBytes, relocation.getTargetDescription()); + null, relocation.getTargetDescription()); } } @@ -1477,20 +1476,6 @@ public class MachoProgramBuilder { } } - private byte[] getOriginalRelocationBytes(RelocationInfo relocation, - Address relocationAddress) { - - int relocationSize = (int) Math.pow(2, relocation.getLength()); - byte[] originalRelocationBytes = new byte[relocationSize]; - try { - memory.getBytes(relocationAddress, originalRelocationBytes); - } - catch (MemoryAccessException e) { - // fall through - } - return originalRelocationBytes; - } - /** * Fixes up any chained fixups. Relies on the __thread_starts section being present. * @@ -1655,8 +1640,6 @@ public class MachoProgramBuilder { long imageBaseOffset = program.getImageBase().getOffset(); Address chainStart = memory.getProgram().getLanguage().getDefaultSpace().getAddress(page); - byte origBytes[] = new byte[8]; - long next = -1; boolean start = true; while (next != 0) { @@ -1718,10 +1701,10 @@ public class MachoProgramBuilder { newChainValue += imageBaseOffset; } - if (!start || program.getRelocationTable().getRelocation(chainLoc) == null) { + if (!start || !program.getRelocationTable().hasRelocation(chainLoc)) { addRelocationTableEntry(chainLoc, (start ? 0x8000 : 0x4000) | (isAuthenticated ? 4 : 0) | (isBound ? 2 : 0) | 1, - newChainValue, origBytes, symName); + newChainValue, symName); DyldChainedPtr.setChainValue(memory, chainLoc, pointerFormat, newChainValue); } // delay creating data until after memory has been changed @@ -1733,13 +1716,11 @@ public class MachoProgramBuilder { } } - private void addRelocationTableEntry(Address chainLoc, int type, long chainValue, - byte[] origBytes, String name) throws MemoryAccessException { + private void addRelocationTableEntry(Address chainLoc, int type, long chainValue, String name) { if (shouldAddChainedFixupsRelocations) { // Add entry to relocation table for the pointer fixup - memory.getBytes(chainLoc, origBytes); program.getRelocationTable() - .add(chainLoc, type, new long[] { chainValue }, origBytes, name); + .add(chainLoc, type, new long[] { chainValue }, null, name); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java index c6a31a7e44..ea8150c0cb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java @@ -373,8 +373,7 @@ public class MzLoader extends AbstractLibrarySupportLoader { // Add to relocation table prog.getRelocationTable() - .add(fixupAddr, 0, new long[] { off, seg }, converter.getBytes(value), - null); + .add(fixupAddr, 0, new long[] { off, seg }, null, null); } } catch (IOException e) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java index d028840ff9..828fa0a862 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java @@ -366,7 +366,8 @@ public class PeLoader extends AbstractPeDebugLoader { continue; } int offset = reloc.getOffset(j); - long addr = Conv.intToLong(baseAddr + offset) + optionalHeader.getImageBase(); + long addr = + Integer.toUnsignedLong(baseAddr + offset) + optionalHeader.getImageBase(); Address relocAddr = space.getAddress(addr); try { @@ -390,7 +391,7 @@ public class PeLoader extends AbstractPeDebugLoader { } } - relocTable.add(relocAddr, type, null, bytes, null); + relocTable.add(relocAddr, type, null, null, null); } catch (MemoryAccessException e) { @@ -437,7 +438,8 @@ public class PeLoader extends AbstractPeDebugLoader { return; } - long addr = Conv.intToLong(importInfo.getAddress()) + optionalHeader.getImageBase(); + long addr = + Integer.toUnsignedLong(importInfo.getAddress()) + optionalHeader.getImageBase(); //If not 64bit make sure address is not larger //than 32bit. On WindowsCE some sections are diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/PEUtil.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/PEUtil.java index a714d58b19..5db5cae77a 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/PEUtil.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/PEUtil.java @@ -21,18 +21,10 @@ import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.MemoryByteProvider; import ghidra.app.util.bin.format.mz.DOSHeader; import ghidra.app.util.bin.format.pe.Constants; -import ghidra.app.util.datatype.microsoft.GuidInfo; -import ghidra.app.util.datatype.microsoft.GuidUtil; import ghidra.app.util.opinion.BinaryLoader; import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum; -import ghidra.program.model.address.*; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.TypeDef; import ghidra.program.model.listing.Program; -import ghidra.program.model.mem.Memory; -import ghidra.program.model.mem.MemoryAccessException; -import ghidra.program.model.reloc.Relocation; public class PEUtil { @@ -67,70 +59,73 @@ public class PEUtil { program.getCompiler().equals(CompilerEnum.Clang.toString())); } - static DataType getActualType(DataType dataType) { - if (dataType instanceof TypeDef) { - return getActualType(((TypeDef) dataType).getDataType()); - } - return dataType; - } + // TODO: remove if not used - static boolean isValidPointer(Program program, Address addr) { - Memory memory = program.getMemory(); - AddressFactory addressFactory = program.getAddressFactory(); - AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace(); - try { - int addrAsInt = memory.getInt(addr); - Address pointedToAddr = addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt); - return memory.contains(pointedToAddr); - } - catch (MemoryAccessException e) { - } - return false; - } - - static boolean isValidGuidPointer(Program program, Address addr) { - Memory memory = program.getMemory(); - AddressFactory addressFactory = program.getAddressFactory(); - AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace(); - try { - int addrAsInt = memory.getInt(addr); - Address pointedToAddr = addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt); - if (memory.contains(pointedToAddr)) { - GuidInfo guidInfo = GuidUtil.getKnownGuid(program, pointedToAddr); - if (guidInfo != null) { - return true; - } - } - } - catch (MemoryAccessException e) { - } - return false; - } - - static long getBytesToEndOfBlock(Program program, Address addr) { - Memory memory = program.getMemory(); - Address endAddr = memory.getBlock(addr).getEnd(); - return endAddr.subtract(addr); - } - - static long getBytesToNextReferredToAddress(Program program, Address addr) { - AddressIterator refIter = - program.getReferenceManager().getReferenceDestinationIterator(addr.add(1L), true); - if (refIter.hasNext()) { - Address nextAddr = refIter.next(); - if (nextAddr != null) { - return nextAddr.subtract(addr); - } - } - return 0; - } - - static long getBytesToNextRelocation(Program program, Address addr) { - Relocation nextReloc = program.getRelocationTable().getRelocationAfter(addr); - if (nextReloc != null) { - return nextReloc.getAddress().subtract(addr); - } - return 0; - } +// static DataType getActualType(DataType dataType) { +// if (dataType instanceof TypeDef) { +// return getActualType(((TypeDef) dataType).getDataType()); +// } +// return dataType; +// } +// +// static boolean isValidPointer(Program program, Address addr) { +// Memory memory = program.getMemory(); +// AddressFactory addressFactory = program.getAddressFactory(); +// AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace(); +// try { +// int addrAsInt = memory.getInt(addr); +// Address pointedToAddr = addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt); +// return memory.contains(pointedToAddr); +// } +// catch (MemoryAccessException e) { +// } +// return false; +// } +// +// static boolean isValidGuidPointer(Program program, Address addr) { +// Memory memory = program.getMemory(); +// AddressFactory addressFactory = program.getAddressFactory(); +// AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace(); +// try { +// int addrAsInt = memory.getInt(addr); +// Address pointedToAddr = addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt); +// if (memory.contains(pointedToAddr)) { +// GuidInfo guidInfo = GuidUtil.getKnownGuid(program, pointedToAddr); +// if (guidInfo != null) { +// return true; +// } +// } +// } +// catch (MemoryAccessException e) { +// } +// return false; +// } +// +// static long getBytesToEndOfBlock(Program program, Address addr) { +// Memory memory = program.getMemory(); +// Address endAddr = memory.getBlock(addr).getEnd(); +// return endAddr.subtract(addr); +// } +// +// static long getBytesToNextReferredToAddress(Program program, Address addr) { +// AddressIterator refIter = +// program.getReferenceManager().getReferenceDestinationIterator(addr.add(1L), true); +// if (refIter.hasNext()) { +// Address nextAddr = refIter.next(); +// if (nextAddr != null) { +// return nextAddr.subtract(addr); +// } +// } +// return 0; +// } +// +// static long getBytesToNextRelocation(Program program, Address addr) { +// Address nextRelocAddr = program.getRelocationTable().getRelocationAddressAfter(addr); +// if (nextRelocAddr != null && +// addr.getAddressSpace().equals(nextRelocAddr.getAddressSpace())) { +// return nextRelocAddr.subtract(addr); +// } +// return 0; +// } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java index 9fb1388aa8..a75d8bd4d6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapter.java @@ -26,31 +26,30 @@ import ghidra.util.task.TaskMonitor; abstract class RelocationDBAdapter { - final static int TYPE_COL = 0; - final static int VALU_COL = 1; - final static int BYTES_COL = 2; - final static int SYMBOL_NAME_COL = 3; + // History: + // V1 - added Type + // V2 - added Value + // V3 - added Bytes + // V4 - added Name, switched Value to binary coded long[] from long + // V5 - moved Addr key to column and indexed, use one-up key + + final static int ADDR_COL = 0; // indexed + final static int TYPE_COL = 1; + final static int VALUE_COL = 2; + final static int BYTES_COL = 3; + final static int SYMBOL_NAME_COL = 4; final static String TABLE_NAME = "Relocations"; final static Schema SCHEMA = new Schema( - RelocationDBAdapterV4.VERSION, "Address", new Field[] { IntField.INSTANCE, + RelocationDBAdapterV5.VERSION, "Index", new Field[] { LongField.INSTANCE, IntField.INSTANCE, BinaryField.INSTANCE, BinaryField.INSTANCE, StringField.INSTANCE }, - new String[] { "Type", "Values", "Bytes", "Symbol Name" }); + new String[] { "Address", "Type", "Values", "Bytes", "Symbol Name" }); static RelocationDBAdapter getAdapter(DBHandle dbHandle, int openMode, AddressMap addrMap, TaskMonitor monitor) throws VersionException, IOException { - - if (openMode == DBConstants.CREATE) { - return new RelocationDBAdapterV4(dbHandle, addrMap, true); - } - try { - RelocationDBAdapter adapter = new RelocationDBAdapterV4(dbHandle, addrMap, false); - if (addrMap.isUpgraded()) { - throw new VersionException(true); - } - return adapter; + return new RelocationDBAdapterV5(dbHandle, addrMap, openMode == DBConstants.CREATE); } catch (VersionException e) { if (!e.isUpgradable() || openMode == DBConstants.UPDATE) { @@ -65,9 +64,15 @@ abstract class RelocationDBAdapter { } private static RelocationDBAdapter findReadOnlyAdapter(DBHandle handle, AddressMap addrMap) - throws IOException { + throws IOException, VersionException { try { - return new RelocationDBAdapterV3(handle, addrMap, false); + return new RelocationDBAdapterV4(handle, addrMap); + } + catch (VersionException e) { + // try the next version + } + try { + return new RelocationDBAdapterV3(handle, addrMap); } catch (VersionException e) { // try the next version @@ -84,7 +89,7 @@ abstract class RelocationDBAdapter { catch (VersionException e) { // try the next version } - return new RelocationDBAdapterNoTable(); + return new RelocationDBAdapterNoTable(handle); } private static RelocationDBAdapter upgrade(DBHandle dbHandle, AddressMap addrMap, @@ -97,27 +102,27 @@ abstract class RelocationDBAdapter { try { tmpHandle.startTransaction(); - RelocationDBAdapter tmpAdapter = new RelocationDBAdapterV4(tmpHandle, addrMap, true); + RelocationDBAdapter tmpAdapter = new RelocationDBAdapterV5(tmpHandle, addrMap, true); RecordIterator iter = oldAdapter.iterator(); while (iter.hasNext()) { DBRecord rec = iter.next(); - Address addr = oldAddrMap.decodeAddress(rec.getKey()); + // decode with old address map + Address addr = oldAddrMap.decodeAddress(rec.getLongValue(ADDR_COL)); BinaryCodedField values = - new BinaryCodedField((BinaryField) rec.getFieldValue(VALU_COL)); - tmpAdapter.add(addrMap.getKey(addr, true), rec.getIntValue(TYPE_COL), - values.getLongArray(), null /* bytes */, null /* symbol name */); + new BinaryCodedField((BinaryField) rec.getFieldValue(VALUE_COL)); + tmpAdapter.add(addr, rec.getIntValue(TYPE_COL), + values.getLongArray(), rec.getBinaryData(BYTES_COL), + rec.getString(SYMBOL_NAME_COL)); } dbHandle.deleteTable(TABLE_NAME); - RelocationDBAdapter newAdapter = new RelocationDBAdapterV4(dbHandle, addrMap, true); + + RelocationDBAdapterV5 newAdapter = new RelocationDBAdapterV5(dbHandle, addrMap, true); iter = tmpAdapter.iterator(); while (iter.hasNext()) { DBRecord rec = iter.next(); - BinaryCodedField values = - new BinaryCodedField((BinaryField) rec.getFieldValue(VALU_COL)); - newAdapter.add(rec.getKey(), rec.getIntValue(TYPE_COL), values.getLongArray(), - null /* bytes */, null /* symbol name */); + newAdapter.add(rec); } return newAdapter; } @@ -130,23 +135,52 @@ abstract class RelocationDBAdapter { // Adapter Required Methods //================================================================================================== - abstract void add(long addrKey, int type, long[] values, byte[] bytes, String symbolName) + /** + * Add new relocation record + * @param addr relocation address + * @param type relocation type + * @param values relocation value (e.g., symbol index) + * @param bytes original memory bytes + * @param symbolName symbol name + * @throws IOException if a database error occurs + */ + abstract void add(Address addr, int type, long[] values, byte[] bytes, String symbolName) throws IOException; - abstract void remove(long addrKey) throws IOException; - - abstract DBRecord get(long addrKey) throws IOException; - + /** + * Iterator over all records in address order. + * @return record iterator + * @throws IOException if a database error occurs + */ abstract RecordIterator iterator() throws IOException; + /** + * Iterator over all relocation records in address order constrained by the specified address set. + * @param set address set constraint + * @return record iterator + * @throws IOException if a database error occurs + */ abstract RecordIterator iterator(AddressSetView set) throws IOException; + /** + * Iterate over relocation records starting at specified start address. + * @param start start address + * @return relocation record iterator + * @throws IOException if a database error occurs + */ abstract RecordIterator iterator(Address start) throws IOException; - abstract int getVersion(); - + /** + * Get the total number of relocation records + * @return total number of relocation records + */ abstract int getRecordCount(); + /** + * Translate relocation record to latest schema format + * @param rec old record requiring translation + * @return translated relocation record + */ abstract DBRecord adaptRecord(DBRecord rec); //================================================================================================== diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java index 983124da1e..486e2600e1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterNoTable.java @@ -15,16 +15,13 @@ */ package ghidra.program.database.reloc; +import java.io.IOException; + +import db.*; import ghidra.program.database.util.EmptyRecordIterator; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; - -import java.io.IOException; - -import java.lang.UnsupportedOperationException; - -import db.DBRecord; -import db.RecordIterator; +import ghidra.util.exception.VersionException; /** * A stub for a time when we did not produce these tables. @@ -32,14 +29,22 @@ import db.RecordIterator; class RelocationDBAdapterNoTable extends RelocationDBAdapter { final static int VERSION = 0; - @Override - void add(long addrKey, int type, long[] values, byte[] bytes, String symbolName) { - throw new UnsupportedOperationException(); + /** + * Construct V0 read-only adapter + * @param handle database adapter + * @throws IOException if database IO error occurs + * @throws VersionException throw if table schema is not V0 + */ + RelocationDBAdapterNoTable(DBHandle handle) throws IOException, VersionException { + Table relocTable = handle.getTable(TABLE_NAME); + if (relocTable != null) { + throw new VersionException(); + } } @Override - DBRecord get(long addrKey) { - return null; + void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName) { + throw new UnsupportedOperationException(); } @Override @@ -47,16 +52,6 @@ class RelocationDBAdapterNoTable extends RelocationDBAdapter { return 0; } - @Override - int getVersion() { - return 0; - } - - @Override - void remove(long addrKey) { - throw new UnsupportedOperationException(); - } - @Override RecordIterator iterator() throws IOException { return new EmptyRecordIterator(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java index eb8b1a34fa..84af7aff0c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV1.java @@ -15,59 +15,53 @@ */ package ghidra.program.database.reloc; +import java.io.IOException; + +import db.*; import ghidra.program.database.map.AddressKeyRecordIterator; import ghidra.program.database.map.AddressMap; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.util.exception.VersionException; -import java.io.IOException; - -import java.lang.UnsupportedOperationException; - -import db.*; - class RelocationDBAdapterV1 extends RelocationDBAdapter { final static int VERSION = 1; + + private final static int V1_TYPE_COL = 0; + +// final static Schema SCHEMA = new Schema( +// RelocationDBAdapterV4.VERSION, "Address", new Field[] { IntField.INSTANCE }, +// new String[] { "Type" }); + private Table relocTable; private AddressMap addrMap; - RelocationDBAdapterV1(DBHandle handle, AddressMap addrMap) throws VersionException { - this.addrMap = addrMap.getOldAddressMap(); + /** + * Construct V1 read-only adapter + * @param handle database adapter + * @param addrMap address map for decode + * @throws IOException if database IO error occurs + * @throws VersionException throw if table schema is not V1 + */ + RelocationDBAdapterV1(DBHandle handle, AddressMap addrMap) throws IOException, + VersionException { + this.addrMap = addrMap; relocTable = handle.getTable(TABLE_NAME); - if (relocTable == null) { - throw new VersionException("Missing Table: " + TABLE_NAME); - } - else if (relocTable.getSchema().getVersion() != VERSION) { - throw new VersionException(false); + if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) { + throw new VersionException(); } } @Override - void add(long addrKey, int type, long[] values, byte[] bytes, String symbolName) { + void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName) { throw new UnsupportedOperationException(); } - @Override - DBRecord get(long addrKey) throws IOException { - return relocTable.getRecord(addrKey); - } - @Override int getRecordCount() { return relocTable.getRecordCount(); } - @Override - int getVersion() { - return VERSION; - } - - @Override - void remove(long addrKey) throws IOException { - throw new UnsupportedOperationException(); - } - @Override RecordIterator iterator() throws IOException { RecordIterator recIter = new AddressKeyRecordIterator(relocTable, addrMap); @@ -89,9 +83,12 @@ class RelocationDBAdapterV1 extends RelocationDBAdapter { @Override DBRecord adaptRecord(DBRecord rec) { + if (rec == null) { + return null; + } DBRecord newRec = SCHEMA.createRecord(rec.getKey()); - newRec.setIntValue(TYPE_COL, rec.getIntValue(TYPE_COL)); - newRec.setBinaryData(BYTES_COL, null); + newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address + newRec.setIntValue(TYPE_COL, rec.getIntValue(V1_TYPE_COL)); return newRec; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java index 74654a5792..e7032d88ac 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV2.java @@ -15,59 +15,55 @@ */ package ghidra.program.database.reloc; +import java.io.IOException; + +import db.*; import ghidra.program.database.map.AddressKeyRecordIterator; import ghidra.program.database.map.AddressMap; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.util.exception.VersionException; -import java.io.IOException; - -import java.lang.UnsupportedOperationException; - -import db.*; - class RelocationDBAdapterV2 extends RelocationDBAdapter { final static int VERSION = 2; + + private final static int V2_TYPE_COL = 0; + private final static int V2_VALUE_COL = 1; + +// final static Schema SCHEMA = new Schema( +// RelocationDBAdapterV4.VERSION, "Address", new Field[] { IntField.INSTANCE, +// LongField.INSTANCE }, +// new String[] { "Type", "Values" }); + private Table relocTable; private AddressMap addrMap; - RelocationDBAdapterV2(DBHandle handle, AddressMap addrMap) throws VersionException { - this.addrMap = addrMap.getOldAddressMap(); + /** + * Construct V2 read-only adapter + * @param handle database adapter + * @param addrMap address map for decode + * @throws IOException if database IO error occurs + * @throws VersionException throw if table schema is not V2 + */ + RelocationDBAdapterV2(DBHandle handle, AddressMap addrMap) throws IOException, + VersionException { + this.addrMap = addrMap; relocTable = handle.getTable(TABLE_NAME); - if (relocTable == null) { - throw new VersionException("Missing Table: " + TABLE_NAME); - } - else if (relocTable.getSchema().getVersion() != VERSION) { - throw new VersionException(false); + if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) { + throw new VersionException(); } } @Override - void add(long addrKey, int type, long[] values, byte[] bytes, String symbolName) { + void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName) { throw new UnsupportedOperationException(); } - @Override - DBRecord get(long addrKey) throws IOException { - return relocTable.getRecord(addrKey); - } - @Override int getRecordCount() { return relocTable.getRecordCount(); } - @Override - int getVersion() { - return VERSION; - } - - @Override - void remove(long addrKey) throws IOException { - throw new UnsupportedOperationException(); - } - @Override RecordIterator iterator() throws IOException { RecordIterator recIter = new AddressKeyRecordIterator(relocTable, addrMap); @@ -89,11 +85,14 @@ class RelocationDBAdapterV2 extends RelocationDBAdapter { @Override DBRecord adaptRecord(DBRecord rec) { + if (rec == null) { + return null; + } DBRecord newRec = SCHEMA.createRecord(rec.getKey()); - newRec.setIntValue(TYPE_COL, rec.getIntValue(TYPE_COL)); - long[] values = new long[] { rec.getLongValue(VALU_COL) }; - newRec.setField(VALU_COL, new BinaryCodedField(values)); - newRec.setBinaryData(BYTES_COL, null); + newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address + newRec.setIntValue(TYPE_COL, rec.getIntValue(V2_TYPE_COL)); + long[] values = new long[] { rec.getLongValue(V2_VALUE_COL) }; + newRec.setField(VALUE_COL, new BinaryCodedField(values)); return newRec; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java index 8d15f53ea6..39dc01378b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV3.java @@ -15,93 +15,88 @@ */ package ghidra.program.database.reloc; +import java.io.IOException; + +import db.*; import ghidra.program.database.map.AddressKeyRecordIterator; import ghidra.program.database.map.AddressMap; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.util.exception.VersionException; -import java.io.IOException; - -import java.lang.UnsupportedOperationException; - -import db.*; - class RelocationDBAdapterV3 extends RelocationDBAdapter { + final static int VERSION = 3; + + private final static int V3_TYPE_COL = 0; + private final static int V3_VALUE_COL = 1; + private final static int V3_BYTES_COL = 2; + +// final static Schema SCHEMA = new Schema( +// RelocationDBAdapterV4.VERSION, "Address", new Field[] { IntField.INSTANCE, +// LongField.INSTANCE, BinaryField.INSTANCE }, +// new String[] { "Type", "Values", "Bytes" }); + private Table relocTable; private AddressMap addrMap; - RelocationDBAdapterV3(DBHandle handle, AddressMap addrMap, boolean create) throws IOException, + /** + * Construct V3 read-only adapter + * @param handle database adapter + * @param addrMap address map for decode + * @throws IOException if database IO error occurs + * @throws VersionException throw if table schema is not V3 + */ + RelocationDBAdapterV3(DBHandle handle, AddressMap addrMap) throws IOException, VersionException { this.addrMap = addrMap; - if (create) { - relocTable = handle.createTable(TABLE_NAME, SCHEMA); - } - else { - relocTable = handle.getTable(TABLE_NAME); - if (relocTable == null) { - throw new VersionException("Missing Table: " + TABLE_NAME); - } - else if (relocTable.getSchema().getVersion() != VERSION) { - int version = relocTable.getSchema().getVersion(); - if (version < VERSION) { - throw new VersionException(true); - } - throw new VersionException(VersionException.NEWER_VERSION, false); - } + relocTable = handle.getTable(TABLE_NAME); + if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) { + throw new VersionException(); } } @Override - void add(long addrKey, int type, long[] values, byte[] bytes, String symbolName) + void add(Address addrKey, int type, long[] values, byte[] bytes, String symbolName) throws IOException { throw new UnsupportedOperationException(); } - @Override - DBRecord get(long addrKey) throws IOException { - return relocTable.getRecord(addrKey); - } - - @Override - void remove(long addrKey) throws IOException { - throw new UnsupportedOperationException(); - } - @Override int getRecordCount() { return relocTable.getRecordCount(); } - @Override - int getVersion() { - return VERSION; - } - @Override RecordIterator iterator() throws IOException { - return new AddressKeyRecordIterator(relocTable, addrMap); + RecordIterator recIter = new AddressKeyRecordIterator(relocTable, addrMap); + return new RecordIteratorAdapter(recIter); } @Override RecordIterator iterator(AddressSetView set) throws IOException { - return new AddressKeyRecordIterator(relocTable, addrMap, set, set.getMinAddress(), true); + RecordIterator recIter = + new AddressKeyRecordIterator(relocTable, addrMap, set, set.getMinAddress(), true); + return new RecordIteratorAdapter(recIter); } @Override RecordIterator iterator(Address start) throws IOException { - return new AddressKeyRecordIterator(relocTable, addrMap, start, true); + RecordIterator recIter = new AddressKeyRecordIterator(relocTable, addrMap, start, true); + return new RecordIteratorAdapter(recIter); } @Override DBRecord adaptRecord(DBRecord rec) { + if (rec == null) { + return null; + } DBRecord newRec = SCHEMA.createRecord(rec.getKey()); - newRec.setIntValue(TYPE_COL, rec.getIntValue(TYPE_COL)); - long[] values = new long[] { rec.getLongValue(VALU_COL) }; - newRec.setField(VALU_COL, new BinaryCodedField(values)); - newRec.setBinaryData(BYTES_COL, null); - newRec.setString(SYMBOL_NAME_COL, null); + newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address + newRec.setIntValue(TYPE_COL, rec.getIntValue(V3_TYPE_COL)); + long[] values = new long[] { rec.getLongValue(V3_VALUE_COL) }; + newRec.setField(VALUE_COL, new BinaryCodedField(values)); + newRec.setBinaryData(BYTES_COL, rec.getBinaryData(V3_BYTES_COL)); return newRec; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java index d73e3b354a..3ef8a1fe36 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV4.java @@ -15,63 +15,51 @@ */ package ghidra.program.database.reloc; +import java.io.IOException; + +import db.*; import ghidra.program.database.map.AddressKeyRecordIterator; import ghidra.program.database.map.AddressMap; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.util.exception.VersionException; -import java.io.IOException; - -import java.lang.UnsupportedOperationException; - -import db.*; - public class RelocationDBAdapterV4 extends RelocationDBAdapter { final static int VERSION = 4; + + private final static int V4_TYPE_COL = 0; + private final static int V4_VALUE_COL = 1; + private final static int V4_BYTES_COL = 2; + private final static int V4_SYMBOL_NAME_COL = 3; + +// final static Schema SCHEMA = new Schema( +// RelocationDBAdapterV4.VERSION, "Address", new Field[] { IntField.INSTANCE, +// BinaryField.INSTANCE, BinaryField.INSTANCE, StringField.INSTANCE }, +// new String[] { "Type", "Values", "Bytes", "Symbol Name" }); + private Table relocTable; private AddressMap addrMap; - RelocationDBAdapterV4(DBHandle handle, AddressMap addrMap, boolean create) throws IOException, + /** + * Construct V4 read-only adapter + * @param handle database adapter + * @param addrMap address map for decode + * @throws IOException if database IO error occurs + * @throws VersionException throw if table schema is not V4 + */ + RelocationDBAdapterV4(DBHandle handle, AddressMap addrMap) throws IOException, VersionException { this.addrMap = addrMap; - if (create) { - relocTable = handle.createTable(TABLE_NAME, SCHEMA); - } - else { - relocTable = handle.getTable(TABLE_NAME); - if (relocTable == null) { - throw new VersionException("Missing Table: " + TABLE_NAME); - } - else if (relocTable.getSchema().getVersion() != VERSION) { - int version = relocTable.getSchema().getVersion(); - if (version < VERSION) { - throw new VersionException(true); - } - throw new VersionException(VersionException.NEWER_VERSION, false); - } + relocTable = handle.getTable(TABLE_NAME); + if (relocTable == null || relocTable.getSchema().getVersion() != VERSION) { + throw new VersionException(); } } @Override - void add(long addrKey, int type, long[] values, byte[] bytes, String symbolName) + void add(Address addr, int type, long[] values, byte[] bytes, String symbolName) throws IOException { - DBRecord r = SCHEMA.createRecord(addrKey); - r.setIntValue(TYPE_COL, type); - r.setField(VALU_COL, new BinaryCodedField(values)); - r.setBinaryData(BYTES_COL, bytes); - r.setString(SYMBOL_NAME_COL, symbolName); - relocTable.putRecord(r); - } - - @Override - DBRecord get(long addrKey) throws IOException { - return relocTable.getRecord(addrKey); - } - - @Override - int getVersion() { - return VERSION; + throw new UnsupportedOperationException(); } @Override @@ -79,30 +67,37 @@ public class RelocationDBAdapterV4 extends RelocationDBAdapter { return relocTable.getRecordCount(); } - @Override - void remove(long addrKey) throws IOException { - relocTable.deleteRecord(addrKey); - } - @Override RecordIterator iterator() throws IOException { - return new AddressKeyRecordIterator(relocTable, addrMap); + RecordIterator recIter = new AddressKeyRecordIterator(relocTable, addrMap); + return new RecordIteratorAdapter(recIter); } @Override RecordIterator iterator(AddressSetView set) throws IOException { - return new AddressKeyRecordIterator(relocTable, addrMap, set, set.getMinAddress(), true); + RecordIterator recIter = + new AddressKeyRecordIterator(relocTable, addrMap, set, set.getMinAddress(), true); + return new RecordIteratorAdapter(recIter); } @Override RecordIterator iterator(Address start) throws IOException { - return new AddressKeyRecordIterator(relocTable, addrMap, start, true); + RecordIterator recIter = new AddressKeyRecordIterator(relocTable, addrMap, start, true); + return new RecordIteratorAdapter(recIter); } @Override DBRecord adaptRecord(DBRecord rec) { - // my guess is that we don't need to do this until there is a version newer than us - throw new UnsupportedOperationException("Don't know how to adapt to the new version"); + if (rec == null) { + return null; + } + DBRecord newRec = SCHEMA.createRecord(rec.getKey()); + newRec.setLongValue(ADDR_COL, rec.getKey()); // key was encoded address + newRec.setIntValue(TYPE_COL, rec.getIntValue(V4_TYPE_COL)); + newRec.setBinaryData(VALUE_COL, rec.getBinaryData(V4_VALUE_COL)); // binary coded long[] + newRec.setBinaryData(BYTES_COL, rec.getBinaryData(V4_BYTES_COL)); + newRec.setString(SYMBOL_NAME_COL, rec.getString(V4_SYMBOL_NAME_COL)); + return newRec; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java new file mode 100644 index 0000000000..3124c44fef --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/reloc/RelocationDBAdapterV5.java @@ -0,0 +1,101 @@ +/* ### + * 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.program.database.reloc; + +import java.io.IOException; + +import db.*; +import ghidra.program.database.map.AddressIndexPrimaryKeyIterator; +import ghidra.program.database.map.AddressMap; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSetView; +import ghidra.util.exception.VersionException; + +public class RelocationDBAdapterV5 extends RelocationDBAdapter { + final static int VERSION = 5; + private Table relocTable; + private AddressMap addrMap; + + RelocationDBAdapterV5(DBHandle handle, AddressMap addrMap, boolean create) throws IOException, + VersionException { + this.addrMap = addrMap; + if (create) { + relocTable = handle.createTable(TABLE_NAME, SCHEMA, new int[] { ADDR_COL }); + } + else { + relocTable = handle.getTable(TABLE_NAME); + if (relocTable == null) { + throw new VersionException(true); + } + int version = relocTable.getSchema().getVersion(); + if (version != VERSION) { + throw new VersionException(version < VERSION); + } + } + } + + @Override + void add(Address addr, int type, long[] values, byte[] bytes, String symbolName) + throws IOException { + long key = relocTable.getKey(); + DBRecord r = SCHEMA.createRecord(key); + r.setLongValue(ADDR_COL, addrMap.getKey(addr, true)); + r.setIntValue(TYPE_COL, type); + r.setField(VALUE_COL, new BinaryCodedField(values)); + r.setBinaryData(BYTES_COL, bytes); + r.setString(SYMBOL_NAME_COL, symbolName); + relocTable.putRecord(r); + } + + @Override + int getRecordCount() { + return relocTable.getRecordCount(); + } + + @Override + RecordIterator iterator() throws IOException { + return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable, + ADDR_COL, addrMap, true)); + } + + @Override + RecordIterator iterator(AddressSetView set) throws IOException { + return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable, + ADDR_COL, addrMap, set, true)); + } + + @Override + RecordIterator iterator(Address start) throws IOException { + return new KeyToRecordIterator(relocTable, new AddressIndexPrimaryKeyIterator(relocTable, + ADDR_COL, addrMap, start, true)); + } + + @Override + DBRecord adaptRecord(DBRecord rec) { + // my guess is that we don't need to do this until there is a version newer than us + throw new UnsupportedOperationException("Don't know how to adapt to the new version"); + } + + /** + * Add V5 relocation record to table. + * @param rec relocation record + * @throws IOException if database IO error occurs + */ + void add(DBRecord rec) throws IOException { + relocTable.putRecord(rec); + } + +} 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 43f5b36b19..b94e5d1bc1 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 @@ -15,13 +15,20 @@ */ package ghidra.program.database.reloc; +import java.io.IOException; +import java.util.*; + +import db.*; import ghidra.framework.options.Options; import ghidra.program.database.ManagerDB; import ghidra.program.database.ProgramDB; import ghidra.program.database.map.AddressMap; +import ghidra.program.database.mem.AddressSourceInfo; +import ghidra.program.database.mem.FileBytes; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryBlockSourceInfo; import ghidra.program.model.reloc.Relocation; import ghidra.program.model.reloc.RelocationTable; import ghidra.util.Lock; @@ -29,11 +36,6 @@ import ghidra.util.exception.CancelledException; import ghidra.util.exception.VersionException; import ghidra.util.task.TaskMonitor; -import java.io.IOException; -import java.util.Iterator; - -import db.*; - /** * An implementation of the relocation table interface. * @@ -45,6 +47,7 @@ public class RelocationManager implements RelocationTable, ManagerDB { private AddressMap addrMap; private RelocationDBAdapter adapter; private Boolean isRelocatable = null; + private Lock lock; /** * Constructs a new relocation manager. @@ -58,8 +61,8 @@ public class RelocationManager implements RelocationTable, ManagerDB { */ public RelocationManager(DBHandle handle, AddressMap addrMap, int openMode, Lock lock, TaskMonitor monitor) throws VersionException, IOException { - this.addrMap = addrMap; + this.lock = lock; initializeAdapters(handle, openMode, monitor); } @@ -70,7 +73,7 @@ public class RelocationManager implements RelocationTable, ManagerDB { @Override public void invalidateCache(boolean all) { - // guess we don't care + // no cache or DB objects } @Override @@ -84,130 +87,196 @@ public class RelocationManager implements RelocationTable, ManagerDB { // Nothing to do } + private byte[] getOriginalBytes(Address addr, byte[] bytes) throws IOException { + if (bytes != null) { + return bytes; + } + int byteCount = program.getDefaultPointerSize() > 4 ? 8 : 4; + byte[] originalBytes = new byte[byteCount]; + AddressSourceInfo addressSourceInfo = program.getMemory().getAddressSourceInfo(addr); + MemoryBlockSourceInfo memoryBlockSourceInfo = addressSourceInfo.getMemoryBlockSourceInfo(); + Optional optional = memoryBlockSourceInfo.getFileBytes(); + if (!optional.isEmpty()) { + FileBytes fileBytes = optional.get(); + long fileBytesOffset = addressSourceInfo.getFileOffset(); + long offsetIntoSourceRange = + fileBytesOffset - memoryBlockSourceInfo.getFileBytesOffset(); + long available = memoryBlockSourceInfo.getLength() - offsetIntoSourceRange; + int readSize = (int) Math.min(available, byteCount); + fileBytes.getOriginalBytes(fileBytesOffset, originalBytes, 0, readSize); + } + return originalBytes; + } + @Override public Relocation add(Address addr, int type, long[] values, byte[] bytes, String symbolName) { + lock.acquire(); try { - adapter.add(addrMap.getKey(addr, true), type, values, bytes, symbolName); - return new Relocation(addr, type, values, bytes, symbolName); + adapter.add(addr, type, values, bytes, symbolName); + return new Relocation(addr, type, values, getOriginalBytes(addr, bytes), symbolName); } catch (IOException e) { program.dbError(e); } + finally { + lock.release(); + } return null; } @Override - public void remove(Relocation reloc) { + public boolean hasRelocation(Address addr) { + lock.acquire(); try { - adapter.remove(addrMap.getKey(reloc.getAddress(), false)); - } - catch (IOException e) { - program.dbError(e); - } - } - - @Override - public Relocation getRelocation(Address addr) { - try { - DBRecord rec = adapter.get(addrMap.getKey(addr, false)); - if (rec != null) { - return getRelocation(rec); + RecordIterator it = adapter.iterator(addr); + if (!it.hasNext()) { + return false; } + DBRecord r = it.next(); + Address a = addrMap.decodeAddress(r.getLongValue(RelocationDBAdapter.ADDR_COL)); + return addr.equals(a); } catch (IOException e) { program.dbError(e); } + finally { + lock.release(); + } + return false; + } + + @Override + public List getRelocations(Address addr) { + lock.acquire(); + try { + List list = null; + RecordIterator it = adapter.iterator(addr); + while (it.hasNext()) { + DBRecord rec = it.next(); + Address a = addrMap.decodeAddress(rec.getLongValue(RelocationDBAdapter.ADDR_COL)); + if (!addr.equals(a)) { + break; + } + if (list == null) { + list = new ArrayList<>(); + } + list.add(getRelocation(rec)); + } + return list == null ? List.of() : list; + } + catch (IOException e) { + program.dbError(e); + } + finally { + lock.release(); + } return null; } - private Relocation getRelocation(DBRecord rec) { + private Relocation getRelocation(DBRecord rec) throws IOException { + Address addr = addrMap.decodeAddress(rec.getLongValue(RelocationDBAdapter.ADDR_COL)); BinaryCodedField valuesField = - new BinaryCodedField((BinaryField) rec.getFieldValue(RelocationDBAdapter.VALU_COL)); - return new Relocation(addrMap.decodeAddress(rec.getKey()), - rec.getIntValue(RelocationDBAdapter.TYPE_COL), valuesField.getLongArray(), - rec.getBinaryData(RelocationDBAdapter.BYTES_COL), - rec.getString(RelocationDBAdapter.SYMBOL_NAME_COL)); + new BinaryCodedField((BinaryField) rec.getFieldValue(RelocationDBAdapter.VALUE_COL)); + byte[] originalBytes = + getOriginalBytes(addr, rec.getBinaryData(RelocationDBAdapter.BYTES_COL)); + return new Relocation(addr, rec.getIntValue(RelocationDBAdapter.TYPE_COL), + valuesField.getLongArray(), + originalBytes, rec.getString(RelocationDBAdapter.SYMBOL_NAME_COL)); } @Override public Iterator getRelocations() { RecordIterator ri = null; + lock.acquire(); try { ri = adapter.iterator(); } catch (IOException e) { program.dbError(e); } + finally { + lock.release(); + } return new RelocationIterator(ri); } @Override - public Relocation getRelocationAfter(Address addr) { - RecordIterator ri = null; + public Address getRelocationAddressAfter(Address addr) { + lock.acquire(); try { - ri = adapter.iterator(addr); - if (ri.hasNext()) { - DBRecord r = ri.next(); - Relocation relocation = getRelocation(r); - if (!relocation.getAddress().equals(addr)) { - return relocation; - } - // The previous relocation was for the address that we want one after, so try again. - if (ri.hasNext()) { - r = ri.next(); - return getRelocation(r); + RecordIterator it = adapter.iterator(addr); + while (it.hasNext()) { + DBRecord rec = it.next(); + Address a = addrMap.decodeAddress(rec.getLongValue(RelocationDBAdapter.ADDR_COL)); + if (!addr.equals(a)) { + return a; } } } catch (IOException e) { program.dbError(e); } + finally { + lock.release(); + } return null; } @Override public Iterator getRelocations(AddressSetView set) { - RecordIterator ri = null; + RecordIterator it = null; + lock.acquire(); try { - ri = adapter.iterator(set); + it = adapter.iterator(set); } catch (IOException e) { program.dbError(e); } - return new RelocationIterator(ri); + finally { + lock.release(); + } + return new RelocationIterator(it); } private class RelocationIterator implements Iterator { - private RecordIterator ri; + private RecordIterator it; RelocationIterator(RecordIterator ri) { - this.ri = ri; + this.it = ri; } @Override public boolean hasNext() { - if (ri == null) + if (it == null) return false; + lock.acquire(); try { - return ri.hasNext(); + return it.hasNext(); } catch (IOException e) { program.dbError(e); } + finally { + lock.release(); + } return false; } @Override public Relocation next() { - if (ri == null) + if (it == null) return null; + lock.acquire(); try { - DBRecord r = ri.next(); + DBRecord r = it.next(); return getRelocation(r); } catch (IOException e) { program.dbError(e); } + finally { + lock.release(); + } return null; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java index 5ee0b0f397..a52bb5d87f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/Relocation.java @@ -31,10 +31,11 @@ public class Relocation { /** * Constructs a new relocation. * - * @param addr the address where the relocation is required - * @param type the type of relocation to perform - * @param values the values needed when performing the relocation - * @param bytes original instruction bytes affected by relocation + * @param addr the address where the relocation is required + * @param type the type of relocation to perform + * @param values the values needed when performing the relocation. Definition of values is + * specific to loader used and relocation type. + * @param bytes original instruction bytes affected by relocation * @param symbolName the name of the symbol being relocated */ public Relocation(Address addr, int type, long[] values, byte[] bytes, String symbolName) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java index 2a16da4c93..128948ea99 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/reloc/RelocationTable.java @@ -15,13 +15,17 @@ */ package ghidra.program.model.reloc; +import java.util.Iterator; +import java.util.List; + +import ghidra.program.database.mem.FileBytes; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; -import java.util.Iterator; - /** * An interface for storing the relocations defined in a program. + * Table must preserve the order in which relocations are added such that + * the iterators return them in the same order. */ public interface RelocationTable { /** Name of the relocatable property in the program information property list. */ @@ -33,47 +37,52 @@ public interface RelocationTable { * * @param addr the address where the relocation is required * @param type the type of relocation to perform - * @param values the values needed when performing the relocation - * @param bytes original instruction bytes affected by relocation + * @param values the values needed when performing the relocation. Definition of values is + * specific to loader used and relocation type. + * @param bytes original instruction bytes affected by relocation. A null value should be + * passed to rely on original underlying {@link FileBytes}. * @param symbolName the name of the symbol being relocated; may be null * @return the newly added relocation object */ public Relocation add(Address addr, int type, long[] values, byte[] bytes, String symbolName); /** - * Removes the relocation object. - * @param reloc the relocation object to remove + * Returns the ordered list of relocations which have been defined for the specified address. + * In most cases there will be one or none, but in some cases multiple relocations may be + * applied to a single address. + * @param addr the address where the relocation(s) are defined + * @return the ordered list of relocations which have been defined for the specified address. */ - public void remove(Relocation reloc); + public List getRelocations(Address addr); /** - * Returns the relocation with the specified address. - * @param addr the address where the relocation is defined - * @return the relocation with the specified address + * Determine if the specified address has a relocation defined. + * @param addr memory address within program + * @return true if relocation defined, otherwise false */ - public Relocation getRelocation(Address addr); + public boolean hasRelocation(Address addr); /** - * Returns an iterator over all relocation points (in ascending address order) located + * Returns an iterator over all defined relocations (in ascending address order) located * within the program. - * @return relocation iterator + * @return ordered relocation iterator */ public Iterator getRelocations(); /** - * Returns an iterator over all the relocation points (in ascending address order) located - * within the specified address set. + * Returns an iterator over all defined relocations (in ascending address order) located + * within the program over the specified address set. * @param set address set - * @return relocation iterator + * @return ordered relocation iterator */ public Iterator getRelocations(AddressSetView set); /** - * Returns the next relocation point which follows the specified address. + * Returns the next relocation address which follows the specified address. * @param addr starting point - * @return next relocation after addr + * @return next relocation address after addr or null if none */ - public Relocation getRelocationAfter(Address addr); + public Address getRelocationAddressAfter(Address addr); /** * Returns the number of relocation in this table. diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java index 87d8e3ab3a..288615404b 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java @@ -16,6 +16,7 @@ package ghidra.app.util.bin.format.elf.extend; import java.math.BigInteger; +import java.util.List; import ghidra.app.util.bin.format.elf.*; import ghidra.app.util.bin.format.elf.ElfDynamicType.ElfDynamicValueType; @@ -376,9 +377,9 @@ public class PowerPC64_ElfExtension extends ElfExtension { Function function = program.getListing().getFunctionAt(refAddr); if (function == null) { // Check for potential pointer table (unsure a non-function would be referenced by OPD section) - Relocation reloc = program.getRelocationTable().getRelocation(refAddr); - if (reloc != null && - reloc.getType() == PowerPC64_ElfRelocationConstants.R_PPC64_RELATIVE) { + List relocations = program.getRelocationTable().getRelocations(refAddr); + if (!relocations.isEmpty() && + relocations.get(0).getType() == PowerPC64_ElfRelocationConstants.R_PPC64_RELATIVE) { return program.getSymbolTable().getPrimarySymbol(refAddr); }