diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationData.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationData.java index 3100ec816f..dd17dae309 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationData.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationData.java @@ -15,6 +15,8 @@ */ package ghidra.app.util.bin.format.elf; +import javax.help.UnsupportedOperationException; + import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsDefinition; @@ -48,10 +50,8 @@ class AndroidElfRelocationData extends AbstractLeb128DataType { @Override public DataType clone(DataTypeManager dtm) { - if (dtm == getDataTypeManager()) { - return this; - } - return new AndroidElfRelocationData(dtm, relocationOffset); + // specific instances are used by AndroidElfRelocationTableDataType + throw new UnsupportedOperationException("may not be cloned"); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationGroup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationGroup.java index fc5f3e7b51..79901cc857 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationGroup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationGroup.java @@ -18,6 +18,8 @@ package ghidra.app.util.bin.format.elf; import java.io.IOException; import java.util.ArrayList; +import javax.help.UnsupportedOperationException; + import ghidra.app.util.bin.*; import ghidra.app.util.bin.format.elf.AndroidElfRelocationTableDataType.LEB128Info; import ghidra.docking.settings.Settings; @@ -48,10 +50,8 @@ class AndroidElfRelocationGroup extends DynamicDataType { @Override public DataType clone(DataTypeManager dtm) { - if (dtm == dataMgr) { - return this; - } - return new AndroidElfRelocationGroup(dtm, baseRelocOffset); + // specific instances are used by AndroidElfRelocationTableDatatype + throw new UnsupportedOperationException("may not be cloned"); } @Override @@ -125,9 +125,10 @@ class AndroidElfRelocationGroup extends DynamicDataType { } else { sleb128 = LEB128Info.parse(reader, true); + long baseOffset = relocOffset; relocOffset += sleb128.value; DataTypeComponent dtc = new ReadOnlyDataTypeComponent( - new AndroidElfRelocationOffset(dataMgr, relocOffset), this, + new AndroidElfRelocationOffset(dataMgr, baseOffset, relocOffset), this, sleb128.byteLength, list.size(), sleb128.offset, "reloc_offset_" + i, null); list.add(dtc); @@ -161,6 +162,7 @@ class AndroidElfRelocationGroup extends DynamicDataType { return -1; } + // group_size component Scalar s = (Scalar) comps[0].getDataType().getValue(buf, null, comps[0].getLength()); int groupSize = (int) s.getValue(); @@ -170,10 +172,7 @@ class AndroidElfRelocationGroup extends DynamicDataType { WrappedMemBuffer cbuf = new WrappedMemBuffer(buf, comps[2].getOffset()); s = (Scalar) comps[2].getDataType().getValue(cbuf, null, comps[2].getLength()); long groupOffsetDelta = s.getValue(); - if (lastDtc.getFieldName().startsWith("group_")) { - // must compute final offset for group - return baseRelocOffset + (groupSize * groupOffsetDelta); - } + return baseRelocOffset + ((groupSize - 1) * groupOffsetDelta); } if (lastDtc.getFieldName().startsWith("group_")) { @@ -189,7 +188,6 @@ class AndroidElfRelocationGroup extends DynamicDataType { AndroidElfRelocationData d = (AndroidElfRelocationData) dt; return d.getRelocationOffset(); // return stashed offset } - return -1; // unexpected } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationOffset.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationOffset.java index 48949851b8..74295254db 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationOffset.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/AndroidElfRelocationOffset.java @@ -15,14 +15,19 @@ */ package ghidra.app.util.bin.format.elf; +import javax.help.UnsupportedOperationException; + import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType; +import ghidra.app.util.opinion.ElfLoader; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsDefinition; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.mem.Memory; import ghidra.program.model.scalar.Scalar; /** @@ -46,18 +51,21 @@ class AndroidElfRelocationOffset extends AbstractLeb128DataType { * value adjusted by baseOffset. * @param dtm the data type manager to associate with this data type. * @param baseOffset base offset to which LEB128 offset data should be added + * @param relocationOffset the actual relocation offset value assciated with this + * instance (used by {@link #getValue(MemBuffer, Settings, int)} and + * returned by {@link #getRelocationOffset()}. This value should equals + * baseOffset plus decoded value of sleb128 data. */ - AndroidElfRelocationOffset(DataTypeManager dtm, long baseOffset) { + AndroidElfRelocationOffset(DataTypeManager dtm, long baseOffset, long relocationOffset) { super("sleb128_offset", true, dtm); this.baseOffset = baseOffset; + this.relocationOffset = relocationOffset; } @Override public DataType clone(DataTypeManager dtm) { - if (dtm == getDataTypeManager()) { - return this; - } - return new AndroidElfRelocationOffset(dtm, baseOffset); + // specific instances are used by AndroidElfRelocationGroup + throw new UnsupportedOperationException("may not be cloned"); } @Override @@ -85,15 +93,29 @@ class AndroidElfRelocationOffset extends AbstractLeb128DataType { return Address.class; } + private long getImageBaseAdjustment(Program program) { + Long originalimageBase = ElfLoader.getElfOriginalImageBase(program); + if (originalimageBase != null) { + return program.getImageBase().getOffset() - originalimageBase; + } + return 0; + } + @Override public Object getValue(MemBuffer buf, Settings settings, int length) { Scalar s = (Scalar) super.getValue(buf, settings, length); if (s == null) { return null; } + long imageBaseAdj = 0; + Memory mem = buf.getMemory(); + if (mem != null) { + imageBaseAdj = getImageBaseAdjustment(mem.getProgram()); + } + // assume pointer into physical space associated with buf AddressSpace space = buf.getAddress().getAddressSpace().getPhysicalSpace(); - return space.getAddress(s.getUnsignedValue() + baseOffset); + return space.getAddress(s.getSignedValue() + baseOffset + imageBaseAdj); } @Override @@ -110,7 +132,7 @@ class AndroidElfRelocationOffset extends AbstractLeb128DataType { b.append(" + "); } b.append("0x"); - b.append(Long.toHexString(s.getUnsignedValue())); + b.append(Long.toHexString(s.getSignedValue())); return b.toString(); } @@ -122,12 +144,4 @@ class AndroidElfRelocationOffset extends AbstractLeb128DataType { return relocationOffset; } - /** - * Set the computed relocation offset location associated with this - * component. - * @param relocationOffset stashed relocation offset - */ - void setRelocationOffset(long relocationOffset) { - this.relocationOffset = relocationOffset; - } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java index c4a8bcbaa5..d6c87c4d73 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocationTable.java @@ -205,12 +205,15 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { try { int relocationIndex = 0; - long remainingRelocations = LEB128.readAsLong(reader, true); - long offset = LEB128.readAsLong(reader, true); - long addend = 0; + long remainingRelocations = LEB128.readAsLong(reader, true); // reloc_count + long offset = LEB128.readAsLong(reader, true); // reloc_baseOffset while (remainingRelocations > 0) { + // start new group + long addend = 0; + + // group_size long groupSize = LEB128.readAsLong(reader, true); if (groupSize > remainingRelocations) { Msg.warn(this, "Group relocation count " + groupSize + @@ -218,6 +221,7 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { break; } + // group_flags long groupFlags = LEB128.readAsLong(reader, true); boolean groupedByInfo = (groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_INFO_FLAG) != 0; @@ -228,34 +232,36 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { boolean groupHasAddend = (groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0; + // group_offsetDelta (optional) long groupOffsetDelta = groupedByDelta ? LEB128.readAsLong(reader, true) : 0; + + // group_info (optional) long groupRInfo = groupedByInfo ? LEB128.readAsLong(reader, true) : 0; if (groupedByAddend && groupHasAddend) { + // group_addend (optional) addend += LEB128.readAsLong(reader, true); } for (int i = 0; i < groupSize; i++) { + // reloc_offset (optional) offset += groupedByDelta ? groupOffsetDelta : LEB128.readAsLong(reader, true); + // reloc_info (optional) long info = groupedByInfo ? groupRInfo : LEB128.readAsLong(reader, true); long rAddend = 0; if (groupHasAddend) { if (!groupedByAddend) { + // reloc_addend (optional) addend += LEB128.readAsLong(reader, true); } rAddend = addend; } - relocations.add(ElfRelocation.createElfRelocation(reader.getFactory(), elfHeader, relocationIndex++, addendTypeReloc, offset, info, rAddend)); } - if (!groupHasAddend) { - addend = 0; - } - remainingRelocations -= groupSize; } } diff --git a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java index 6bb4254096..7069a49195 100644 --- a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java +++ b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java @@ -29,6 +29,11 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler { return elf.e_machine() == ElfConstants.EM_ARM; } + @Override + public int getRelrRelocationType() { + return ARM_ElfRelocationConstants.R_ARM_RELATIVE; + } + @Override public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress) throws MemoryAccessException, NotFoundException {