Merge remote-tracking branch 'origin/GT-3320_ghidra1_PR-1192_brggs_ElfAndroidRelocs'

This commit is contained in:
ghidra1 2019-11-22 16:41:55 -05:00
commit f1fcd421d6
14 changed files with 1016 additions and 51 deletions

View file

@ -0,0 +1,157 @@
/* ###
* 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.util.bin;
import java.io.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException;
/**
* <code>MemBufferByteProvider</code> provide a {@link ByteProvider} backed by
* a {@link MemBuffer}.
*/
public class MemBufferByteProvider implements ByteProvider {
private MemBuffer buffer;
/**
* Constructor
* @param buffer memory buffer
*/
public MemBufferByteProvider(MemBuffer buffer) {
this.buffer = buffer;
}
@Override
public File getFile() {
return null;
}
@Override
public String getName() {
return null;
}
@Override
public String getAbsolutePath() {
return null;
}
/**
* Return maximum length since actual length is unknown
* @return maximum possible length
*/
@Override
public long length() {
return Integer.MAX_VALUE;
}
@Override
public boolean isValidIndex(long index) {
if (index < 0 || index > Integer.MAX_VALUE) {
return false;
}
try {
buffer.getByte((int) index);
return true;
}
catch (MemoryAccessException e) {
return false;
}
}
@Override
public void close() throws IOException {
// not applicable
}
@Override
public byte readByte(long index) throws IOException {
if (index < 0 || index > Integer.MAX_VALUE) {
throw new IOException("index out of range");
}
try {
return buffer.getByte((int) index);
}
catch (MemoryAccessException e) {
throw new IOException("index out of range");
}
}
@Override
public byte[] readBytes(long index, long length) throws IOException {
if (index < 0 || (index + length - 1) > Integer.MAX_VALUE) {
throw new IOException("index/length of range");
}
int len = (int) length;
byte[] bytes = new byte[len];
if (buffer.getBytes(bytes, (int) index) != len) {
throw new IOException("index/length of range");
}
return bytes;
}
@Override
public InputStream getInputStream(long index) throws IOException {
if (index < 0 || index > Integer.MAX_VALUE) {
throw new IOException("index out of range");
}
return new MemBufferProviderInputStream((int) index);
}
private class MemBufferProviderInputStream extends InputStream {
private int initialOffset;
private int offset;
MemBufferProviderInputStream(int offset) {
this.offset = offset;
this.initialOffset = offset;
}
@Override
public int read() throws IOException {
byte b = readByte(offset++);
return b & 0xff;
}
@Override
public int read(byte[] b, int off, int len) {
byte[] bytes = new byte[len];
int count = buffer.getBytes(bytes, offset);
System.arraycopy(bytes, 0, b, off, count);
offset += count;
return count;
}
@Override
public int available() {
return (int) length() - offset;
}
@Override
public synchronized void reset() throws IOException {
offset = initialOffset;
}
@Override
public void close() throws IOException {
// not applicable
}
}
}

View file

@ -0,0 +1,89 @@
/* ###
* 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.util.bin.format.elf;
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
/**
* <code>AndroidElfRelocationData</code> provides a dynamic LEB128 data
* component for packed Android ELF Relocation Table.
* See {@link AndroidElfRelocationTableDataType}.
* <br>
* Secondary purpose is to retain the relocation offset associated with a
* component instance. This functionality relies on the 1:1 relationship
* between this dynamic datatype and the single component which references it.
*/
class AndroidElfRelocationData extends AbstractLeb128DataType {
private final long relocationOffset;
/**
* Creates a packed relocation offset data type based upon a signed LEB128
* value.
* @param dtm the data type manager to associate with this data type.
* @param relocationOffset relocation offset associated with component.
*/
AndroidElfRelocationData(DataTypeManager dtm, long relocationOffset) {
super("sleb128", true, dtm);
this.relocationOffset = relocationOffset;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new AndroidElfRelocationData(dtm, relocationOffset);
}
@Override
public String getMnemonic(Settings settings) {
return name;
}
@Override
public String getDescription() {
return "Android Packed Relocation Data for ELF";
}
@Override
public String getDefaultLabelPrefix() {
return "sleb128";
}
@Override
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
return null;
}
@Override
public Class<?> getValueClass(Settings settings) {
return Address.class;
}
/**
* Get the relocation offset associated with this data item
* @return the relocation offset associated with this data item
*/
long getRelocationOffset() {
return relocationOffset;
}
}

View file

@ -0,0 +1,195 @@
/* ###
* 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.util.bin.format.elf;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.elf.AndroidElfRelocationTableDataType.LEB128Info;
import ghidra.docking.settings.Settings;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.WrappedMemBuffer;
import ghidra.program.model.scalar.Scalar;
/**
* <code>AndroidElfRelocationGroup</code> provides a dynamic substructure
* component for relocation groups within a packed Android ELF Relocation Table.
* See {@link AndroidElfRelocationTableDataType}.
*/
class AndroidElfRelocationGroup extends DynamicDataType {
// Packed Android APS2 relocation group flags
static final long RELOCATION_GROUPED_BY_INFO_FLAG = 1;
static final long RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
static final long RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
static final long RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
private final long baseRelocOffset;
AndroidElfRelocationGroup(DataTypeManager dtm, long baseRelocOffset) {
super(CategoryPath.ROOT, "AndroidElfRelocationGroup", dtm);
this.baseRelocOffset = baseRelocOffset;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == dataMgr) {
return this;
}
return new AndroidElfRelocationGroup(dtm, baseRelocOffset);
}
@Override
public String getDescription() {
return "Android Packed Relocation Entry Group for ELF";
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return "";
}
@Override
protected DataTypeComponent[] getAllComponents(MemBuffer buf) {
try {
ByteProvider provider = new MemBufferByteProvider(buf);
BinaryReader reader = new BinaryReader(provider, false);
ArrayList<DataTypeComponent> list = new ArrayList<>();
LEB128Info sleb128 = LEB128Info.parse(reader, true);
long groupSize = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "group_size", null));
sleb128 = LEB128Info.parse(reader, true);
long groupFlags = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "group_flags", null));
boolean groupedByInfo = (groupFlags & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
boolean groupedByDelta = (groupFlags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
boolean groupedByAddend = (groupFlags & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
boolean groupHasAddend = (groupFlags & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
long groupOffsetDelta = 0;
if (groupedByDelta) {
sleb128 = LEB128Info.parse(reader, true);
groupOffsetDelta = sleb128.value;
long minOffset = baseRelocOffset + groupOffsetDelta;
String rangeStr = "First relocation offset: 0x" + Long.toHexString(minOffset);
list.add(sleb128.getComponent(this, list.size(), "group_offsetDelta", rangeStr));
}
if (groupedByInfo) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "group_info", null));
}
if (groupedByAddend && groupHasAddend) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "group_addend", null));
}
long relocOffset = baseRelocOffset;
if (groupedByDelta && groupedByInfo && (!groupHasAddend || groupedByAddend)) {
// no individual relocation entry data
relocOffset += (groupSize - 1) * groupOffsetDelta;
}
else {
for (int i = 0; i < groupSize; i++) {
if (groupedByDelta) {
relocOffset += groupOffsetDelta;
}
else {
sleb128 = LEB128Info.parse(reader, true);
relocOffset += sleb128.value;
DataTypeComponent dtc = new ReadOnlyDataTypeComponent(
new AndroidElfRelocationOffset(dataMgr, relocOffset), this,
sleb128.byteLength, list.size(), sleb128.offset, "reloc_offset_" + i,
null);
list.add(dtc);
}
if (!groupedByInfo) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "reloc_info_" + i, null,
relocOffset));
}
if (groupHasAddend && !groupedByAddend) {
sleb128 = LEB128Info.parse(reader, true);
list.add(sleb128.getComponent(this, list.size(), "reloc_addend_" + i, null,
relocOffset));
}
}
}
DataTypeComponent[] comps = new DataTypeComponent[list.size()];
return list.toArray(comps);
}
catch (IOException e) {
return null;
}
}
long getLastRelocationOffset(WrappedMemBuffer buf) {
DataTypeComponent[] comps = getComps(buf);
if ((comps == null) || (comps.length < 3)) {
return -1;
}
Scalar s = (Scalar) comps[0].getDataType().getValue(buf, null, comps[0].getLength());
int groupSize = (int) s.getValue();
DataTypeComponent lastDtc = comps[comps.length - 1];
if ("group_offsetDelta".equals(comps[2].getFieldName())) {
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);
}
}
if (lastDtc.getFieldName().startsWith("group_")) {
return -1; // unexpected
}
DataType dt = lastDtc.getDataType();
if (dt instanceof AndroidElfRelocationOffset) {
AndroidElfRelocationOffset d = (AndroidElfRelocationOffset) dt;
return d.getRelocationOffset(); // return stashed offset
}
else if (dt instanceof AndroidElfRelocationData) {
AndroidElfRelocationData d = (AndroidElfRelocationData) dt;
return d.getRelocationOffset(); // return stashed offset
}
return -1; // unexpected
}
}

View file

@ -0,0 +1,133 @@
/* ###
* 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.util.bin.format.elf;
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType;
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.mem.MemBuffer;
import ghidra.program.model.scalar.Scalar;
/**
* <code>AndroidElfRelocationOffset</code> provides a dynamic LEB128 relocation
* offset adjustment component for packed Android ELF Relocation Table groups.
* See {@link AndroidElfRelocationGroup}. The offset adjustment provided
* by the LEB128 memory data is added to the associated baseOffset to obtain
* the corresponding relocation offset/address.
* <br>
* Secondary purpose is to retain the relocation offset associated with a
* component instance. This functionality relies on the 1:1 relationship
* between this dynamic datatype and the single component which references it.
*/
class AndroidElfRelocationOffset extends AbstractLeb128DataType {
private final long baseOffset;
private long relocationOffset;
/**
* Creates a packed relocation offset data type based upon a signed LEB128
* 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
*/
AndroidElfRelocationOffset(DataTypeManager dtm, long baseOffset) {
super("sleb128_offset", true, dtm);
this.baseOffset = baseOffset;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new AndroidElfRelocationOffset(dtm, baseOffset);
}
@Override
public String getMnemonic(Settings settings) {
return name;
}
@Override
public String getDescription() {
return "Android Packed Relocation Offset for ELF";
}
@Override
public String getDefaultLabelPrefix() {
return "sleb128";
}
@Override
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
return null;
}
@Override
public Class<?> getValueClass(Settings settings) {
return Address.class;
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
Scalar s = (Scalar) super.getValue(buf, settings, length);
if (s == null) {
return null;
}
// assume pointer into physical space associated with buf
AddressSpace space = buf.getAddress().getAddressSpace().getPhysicalSpace();
return space.getAddress(s.getUnsignedValue() + baseOffset);
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
Scalar s = (Scalar) super.getValue(buf, settings, length);
if (s == null) {
return "??";
}
// TODO: not sure what representation to use
StringBuilder b = new StringBuilder();
if (baseOffset != 0) {
b.append("0x");
b.append(Long.toHexString(baseOffset));
b.append(" + ");
}
b.append("0x");
b.append(Long.toHexString(s.getUnsignedValue()));
return b.toString();
}
/**
* Get the stashed relocation offset associated with this data item
* @return the relocation offset associated with this data item
*/
long getRelocationOffset() {
return relocationOffset;
}
/**
* Set the computed relocation offset location associated with this
* component.
* @param relocationOffset stashed relocation offset
*/
void setRelocationOffset(long relocationOffset) {
this.relocationOffset = relocationOffset;
}
}

View file

@ -0,0 +1,169 @@
/* ###
* 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.util.bin.format.elf;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.dwarf4.LEB128;
import ghidra.docking.settings.Settings;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.WrappedMemBuffer;
import ghidra.util.Msg;
/**
* <code>AndroidElfRelocationTableDataType</code> provides an implementation of
* an Android APS2 packed ELF relocation table.
*/
public class AndroidElfRelocationTableDataType extends DynamicDataType {
public AndroidElfRelocationTableDataType() {
this(null);
}
public AndroidElfRelocationTableDataType(DataTypeManager dtm) {
super(CategoryPath.ROOT, "AndroidElfRelocationTable", dtm);
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == dataMgr) {
return this;
}
return new AndroidElfRelocationTableDataType(dtm);
}
@Override
public String getDescription() {
return "Android Packed Relocation Table for ELF";
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return "";
}
static class LEB128Info {
final int offset;
final long value;
final int byteLength;
private LEB128Info(int offset, long value, int byteLength) {
this.offset = offset;
this.value = value;
this.byteLength = byteLength;
}
DataTypeComponent getComponent(DynamicDataType parent, int ordinal, String name,
String comment, long relocOffset) {
return new ReadOnlyDataTypeComponent(
new AndroidElfRelocationData(parent.getDataTypeManager(), relocOffset), parent,
byteLength, ordinal, offset, name, comment);
}
DataTypeComponent getComponent(DynamicDataType parent, int ordinal, String name,
String comment) {
return new ReadOnlyDataTypeComponent(
new SignedLeb128DataType(parent.getDataTypeManager()), parent, byteLength, ordinal,
offset, name, comment);
}
static LEB128Info parse(BinaryReader reader, boolean signed) throws IOException {
long nextPos = reader.getPointerIndex();
long value = LEB128.decode(reader, signed);
long pos = reader.getPointerIndex();
int size = (int) (pos - nextPos);
return new LEB128Info((int) nextPos, value, size);
}
}
@Override
protected DataTypeComponent[] getAllComponents(MemBuffer buf) {
try {
byte[] bytes = new byte[4];
if (buf.getBytes(bytes, 0) != 4 || !"APS2".equals(new String(bytes))) {
return null;
}
ByteProvider provider = new MemBufferByteProvider(buf);
BinaryReader reader = new BinaryReader(provider, false);
ArrayList<DataTypeComponent> list = new ArrayList<>();
// assume APS2 format
list.add(new ReadOnlyDataTypeComponent(StringDataType.dataType, this, 4, 0, 0, "format",
null));
reader.setPointerIndex(4);
LEB128Info sleb128 = LEB128Info.parse(reader, true);
long remainingRelocations = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "reloc_count", null));
sleb128 = LEB128Info.parse(reader, true);
long baseRelocOffset = sleb128.value;
list.add(sleb128.getComponent(this, list.size(), "reloc_baseOffset", null));
int groupIndex = 0;
long groupRelocOffset = baseRelocOffset;
while (remainingRelocations > 0) {
// NOTE: assumes 2-GByte MemBuffer limit
int offset = (int) reader.getPointerIndex();
long groupSize = LEB128.decode(reader, true);
if (groupSize > remainingRelocations) {
Msg.debug(this, "Group relocation count " + groupSize +
" exceeded total count " + remainingRelocations);
break;
}
AndroidElfRelocationGroup group =
new AndroidElfRelocationGroup(dataMgr, groupRelocOffset);
WrappedMemBuffer groupBuffer = new WrappedMemBuffer(buf, offset);
int groupLength = group.getLength(groupBuffer, -1);
DataTypeComponent dtc = new ReadOnlyDataTypeComponent(group, this, groupLength,
list.size(), offset, "reloc_group_" + groupIndex++, null);
list.add(dtc);
groupRelocOffset = group.getLastRelocationOffset(groupBuffer);
if (groupRelocOffset < 0) {
break;
}
offset += groupLength;
reader.setPointerIndex(offset);
remainingRelocations -= groupSize;
}
DataTypeComponent[] comps = new DataTypeComponent[list.size()];
return list.toArray(comps);
}
catch (IOException e) {
return null;
}
}
}

View file

@ -90,17 +90,36 @@ public class ElfDynamicType {
"Size in bytes of DT_FINI_ARRAY", ElfDynamicValueType.VALUE); "Size in bytes of DT_FINI_ARRAY", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_RUNPATH = addDefaultDynamicType(29, "DT_RUNPATH", public static ElfDynamicType DT_RUNPATH = addDefaultDynamicType(29, "DT_RUNPATH",
"Library search path (string ref)", ElfDynamicValueType.STRING); "Library search path (string ref)", ElfDynamicValueType.STRING);
// see DF_ constants for flag definitions
public static ElfDynamicType DT_FLAGS = addDefaultDynamicType(30, "DT_FLAGS", public static ElfDynamicType DT_FLAGS = addDefaultDynamicType(30, "DT_FLAGS",
"Flags for the object being loaded", ElfDynamicValueType.VALUE); "Flags for the object being loaded", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_ENCODING = addDefaultDynamicType(32, "DT_ENCODING", public static final int DF_ORIGIN = 0x1; // $ORIGIN processing required
"Start of encoded range", ElfDynamicValueType.VALUE); public static final int DF_SYMBOLIC = 0x2; // Symbolic symbol resolution required
// public static ElfDynamicType DT_PREINIT_ARRAY = addDefaultDynamicType(32, "DT_PREINIT_ARRAY", "Array with addresses of preinit fct", ElfDynamicValueType.VALUE); public static final int DF_TEXTREL = 0x4; // Text relocations exist
public static final int DF_BIND_NOW = 0x8; // Non-lazy binding required
public static final int DF_STATIC_TLS = 0x10; // Object uses static TLS scheme
// glibc and BSD disagree for DT_ENCODING
// public static ElfDynamicType DT_ENCODING = addDefaultDynamicType(32, "DT_ENCODING",
// "Start of encoded range", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_PREINIT_ARRAY = addDefaultDynamicType(32, "DT_PREINIT_ARRAY",
"Array with addresses of preinit fct", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_PREINIT_ARRAYSZ = addDefaultDynamicType(33, public static ElfDynamicType DT_PREINIT_ARRAYSZ = addDefaultDynamicType(33,
"DT_PREINIT_ARRAYSZ", "Size in bytes of DT_PREINIT_ARRAY", ElfDynamicValueType.VALUE); "DT_PREINIT_ARRAYSZ", "Size in bytes of DT_PREINIT_ARRAY", ElfDynamicValueType.VALUE);
// OS-specific range: 0x6000000d - 0x6ffff000 // OS-specific range: 0x6000000d - 0x6ffff000
public static ElfDynamicType DT_ANDROID_REL = addDefaultDynamicType(0x6000000F,
"DT_ANDROID_REL", "Address of Rel relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELSZ = addDefaultDynamicType(0x60000010,
"DT_ANDROID_RELSZ", "Total size of Rel relocs", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_ANDROID_RELA = addDefaultDynamicType(0x60000011,
"DT_ANDROID_RELA", "Address of Rela relocs", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_ANDROID_RELASZ = addDefaultDynamicType(0x60000012,
"DT_ANDROID_RELASZ", "Total size of Rela relocs", ElfDynamicValueType.VALUE);
// Value Range (??): 0x6ffffd00 - 0x6ffffdff // Value Range (??): 0x6ffffd00 - 0x6ffffdff
public static ElfDynamicType DT_GNU_PRELINKED = addDefaultDynamicType(0x6ffffdf5, public static ElfDynamicType DT_GNU_PRELINKED = addDefaultDynamicType(0x6ffffdf5,
@ -158,8 +177,23 @@ public class ElfDynamicType {
addDefaultDynamicType(0x6ffffff9, "DT_RELACOUNT", "", ElfDynamicValueType.VALUE); addDefaultDynamicType(0x6ffffff9, "DT_RELACOUNT", "", ElfDynamicValueType.VALUE);
public static ElfDynamicType DT_RELCOUNT = public static ElfDynamicType DT_RELCOUNT =
addDefaultDynamicType(0x6ffffffa, "DT_RELCOUNT", "", ElfDynamicValueType.VALUE); addDefaultDynamicType(0x6ffffffa, "DT_RELCOUNT", "", ElfDynamicValueType.VALUE);
// see DF_1_ constants for flag definitions
public static ElfDynamicType DT_FLAGS_1 = public static ElfDynamicType DT_FLAGS_1 =
addDefaultDynamicType(0x6ffffffb, "DT_FLAGS_1", "State flags", ElfDynamicValueType.VALUE); addDefaultDynamicType(0x6ffffffb, "DT_FLAGS_1", "State flags", ElfDynamicValueType.VALUE);
public static final int DF_1_NOW = 0x1;
public static final int DF_1_GLOBAL = 0x2;
public static final int DF_1_GROUP = 0x4;
public static final int DF_1_NODELETE = 0x8;
public static final int DF_1_LOADFLTR = 0x10;
public static final int DF_1_INITFIRST = 0x20;
public static final int DF_1_NOOPEN = 0x40;
public static final int DF_1_ORIGIN = 0x80;
public static final int DF_1_DIRECT = 0x100;
public static final int DF_1_INTERPOSE = 0x400;
public static final int DF_1_NODEFLIB = 0x800;
public static ElfDynamicType DT_VERDEF = addDefaultDynamicType(0x6ffffffc, "DT_VERDEF", public static ElfDynamicType DT_VERDEF = addDefaultDynamicType(0x6ffffffc, "DT_VERDEF",
"Address of version definition table", ElfDynamicValueType.ADDRESS); "Address of version definition table", ElfDynamicValueType.ADDRESS);
public static ElfDynamicType DT_VERDEFNUM = addDefaultDynamicType(0x6ffffffd, "DT_VERDEFNUM", public static ElfDynamicType DT_VERDEFNUM = addDefaultDynamicType(0x6ffffffd, "DT_VERDEFNUM",

View file

@ -23,6 +23,7 @@ import generic.continues.GenericFactory;
import ghidra.app.util.bin.*; import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
import ghidra.app.util.bin.format.Writeable; import ghidra.app.util.bin.format.Writeable;
import ghidra.app.util.bin.format.elf.ElfRelocationTable.TableFormat;
import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory; import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory;
import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter; import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
@ -346,6 +347,13 @@ public class ElfHeader implements StructConverter, Writeable {
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_RELA, parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_RELA,
ElfDynamicType.DT_RELAENT, ElfDynamicType.DT_RELASZ, true); ElfDynamicType.DT_RELAENT, ElfDynamicType.DT_RELASZ, true);
// Android versions
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_REL, null,
ElfDynamicType.DT_ANDROID_RELSZ, false);
parseDynamicRelocTable(relocationTableList, ElfDynamicType.DT_ANDROID_RELA, null,
ElfDynamicType.DT_ANDROID_RELASZ, true);
parseJMPRelocTable(relocationTableList); parseJMPRelocTable(relocationTableList);
// In general the above dynamic relocation tables should cover most cases, we will // In general the above dynamic relocation tables should cover most cases, we will
@ -363,7 +371,9 @@ public class ElfHeader implements StructConverter, Writeable {
try { try {
int sectionHeaderType = section.getType(); int sectionHeaderType = section.getType();
if (sectionHeaderType == ElfSectionHeaderConstants.SHT_REL || if (sectionHeaderType == ElfSectionHeaderConstants.SHT_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA) { sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) {
for (ElfRelocationTable relocTable : relocationTableList) { for (ElfRelocationTable relocTable : relocationTableList) {
if (relocTable.getFileOffset() == section.getOffset()) { if (relocTable.getFileOffset() == section.getOffset()) {
@ -379,11 +389,24 @@ public class ElfHeader implements StructConverter, Writeable {
sectionToBeRelocated != null ? sectionToBeRelocated.getNameAsString() sectionToBeRelocated != null ? sectionToBeRelocated.getNameAsString()
: "PT_LOAD"; : "PT_LOAD";
ElfSectionHeader symbolTableSection = getLinkedSection(link, ElfSectionHeader symbolTableSection;
ElfSectionHeaderConstants.SHT_DYNSYM, ElfSectionHeaderConstants.SHT_SYMTAB); if (link == 0) {
ElfSymbolTable symbolTable = getSymbolTable(symbolTableSection); // dynamic symbol table assumed when link section value is 0
symbolTableSection = getSection(ElfSectionHeaderConstants.dot_dynsym);
}
else {
symbolTableSection = getLinkedSection(link,
ElfSectionHeaderConstants.SHT_DYNSYM, ElfSectionHeaderConstants.SHT_SYMTAB);
}
boolean addendTypeReloc = (sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA); ElfSymbolTable symbolTable = getSymbolTable(symbolTableSection);
if (symbolTable == null) {
throw new NotFoundException("Referenced relocation symbol section not found.");
}
boolean addendTypeReloc =
(sectionHeaderType == ElfSectionHeaderConstants.SHT_RELA ||
sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA);
Msg.debug(this, Msg.debug(this,
"Elf relocation table section " + section.getNameAsString() + "Elf relocation table section " + section.getNameAsString() +
@ -394,9 +417,18 @@ public class ElfHeader implements StructConverter, Writeable {
return; return;
} }
relocationTableList.add(ElfRelocationTable.createElfRelocationTable(reader, this, ElfRelocationTable.TableFormat format = TableFormat.DEFAULT;
section, section.getOffset(), section.getAddress(), section.getSize(), if (sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_REL ||
section.getEntrySize(), addendTypeReloc, symbolTable, sectionToBeRelocated)); sectionHeaderType == ElfSectionHeaderConstants.SHT_ANDROID_RELA) {
format = TableFormat.ANDROID;
}
ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader,
this, section, section.getOffset(), section.getAddress(), section.getSize(),
section.getEntrySize(), addendTypeReloc, symbolTable, sectionToBeRelocated,
format);
relocationTableList.add(relocTable);
} }
} }
catch (NotFoundException e) { catch (NotFoundException e) {
@ -468,13 +500,20 @@ public class ElfHeader implements StructConverter, Writeable {
} }
long relocTableOffset = relocTableLoadHeader.getOffset(relocTableAddr); long relocTableOffset = relocTableLoadHeader.getOffset(relocTableAddr);
long tableEntrySize = dynamicTable.getDynamicValue(relocEntrySizeType); long tableEntrySize =
relocEntrySizeType != null ? dynamicTable.getDynamicValue(relocEntrySizeType) : -1;
long tableSize = dynamicTable.getDynamicValue(relocTableSizeType); long tableSize = dynamicTable.getDynamicValue(relocTableSizeType);
relocationTableList.add(ElfRelocationTable.createElfRelocationTable(reader, this, null, ElfRelocationTable.TableFormat format = TableFormat.DEFAULT;
relocTableOffset, relocTableAddr, tableSize, tableEntrySize, addendTypeReloc, if (relocTableAddrType == ElfDynamicType.DT_ANDROID_REL ||
dynamicSymbolTable, null)); relocTableAddrType == ElfDynamicType.DT_ANDROID_RELA) {
format = TableFormat.ANDROID;
}
ElfRelocationTable relocTable = ElfRelocationTable.createElfRelocationTable(reader,
this, null, relocTableOffset, relocTableAddr, tableSize, tableEntrySize,
addendTypeReloc, dynamicSymbolTable, null, format);
relocationTableList.add(relocTable);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
// ignore - skip (required dynamic table value is missing) // ignore - skip (required dynamic table value is missing)
@ -1536,6 +1575,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the symbol table associated to the specified section header * @return the symbol table associated to the specified section header
*/ */
public ElfSymbolTable getSymbolTable(ElfSectionHeader symbolTableSection) { public ElfSymbolTable getSymbolTable(ElfSectionHeader symbolTableSection) {
if (symbolTableSection == null) {
return null;
}
for (int i = 0; i < symbolTables.length; i++) { for (int i = 0; i < symbolTables.length; i++) {
if (symbolTables[i].getFileOffset() == symbolTableSection.getOffset()) { if (symbolTables[i].getFileOffset() == symbolTableSection.getOffset()) {
return symbolTables[i]; return symbolTables[i];

View file

@ -101,20 +101,24 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
/** /**
* GenericFactory construction and initialization method for a ELF representative * GenericFactory construction and initialization method for a ELF representative
* relocation entry (entry data will be 0) * relocation entry
* @param factory instantiation factory. * @param reader binary reader positioned at start of relocation entry.
* @param elfHeader ELF header * @param elfHeader ELF header
* @param relocationIndex index of entry in relocation table * @param relocationIndex index of entry in relocation table
* @param withAddend true if if RELA entry with addend, else false * @param withAddend true if if RELA entry with addend, else false
* @param r_offset The offset for the entry
* @param r_info The info value for the entry
* @param r_addend The addend for the entry
* @return ELF relocation object * @return ELF relocation object
*/ */
static ElfRelocation createElfRelocation(GenericFactory factory, ElfHeader elfHeader, static ElfRelocation createElfRelocation(GenericFactory factory, ElfHeader elfHeader,
int relocationIndex, boolean withAddend) { int relocationIndex, boolean withAddend, long r_offset, long r_info, long r_addend) {
Class<? extends ElfRelocation> elfRelocationClass = getElfRelocationClass(elfHeader); Class<? extends ElfRelocation> elfRelocationClass = getElfRelocationClass(elfHeader);
ElfRelocation elfRelocation = (ElfRelocation) factory.create(elfRelocationClass); ElfRelocation elfRelocation = (ElfRelocation) factory.create(elfRelocationClass);
try { try {
elfRelocation.initElfRelocation(null, elfHeader, relocationIndex, withAddend); elfRelocation.initElfRelocation(elfHeader, relocationIndex, withAddend, r_offset,
r_info, r_addend);
} }
catch (IOException e) { catch (IOException e) {
// absence of reader should prevent any IOException from occurring // absence of reader should prevent any IOException from occurring
@ -161,6 +165,38 @@ public class ElfRelocation implements ByteArrayConverter, StructConverter {
} }
} }
/**
* Initialize ELF relocation entry using data provided via the parameters.
* @param elfHeader ELF header
* @param relocationTableIndex index of relocation within relocation table
* @param withAddend true if if RELA entry with addend, else false
* @param r_offset The offset for the entry
* @param r_info The info value for the entry
* @param r_addend The addend for the entry
* @throws IOException
*/
protected void initElfRelocation(ElfHeader elfHeader, int relocationTableIndex,
boolean withAddend, long r_offset, long r_info, long r_addend) throws IOException {
this.is32bit = elfHeader.is32Bit();
this.relocationIndex = relocationTableIndex;
this.hasAddend = withAddend;
if (is32bit) {
this.r_offset = r_offset & Conv.INT_MASK;
this.r_info = r_info & Conv.INT_MASK;
if (hasAddend) {
this.r_addend = r_addend & Conv.INT_MASK;
}
}
else {
this.r_offset = r_offset;
this.r_info = r_info;
if (hasAddend) {
this.r_addend = r_addend;
}
}
}
private void readEntryData(FactoryBundledWithBinaryReader reader) throws IOException { private void readEntryData(FactoryBundledWithBinaryReader reader) throws IOException {
if (is32bit) { if (is32bit) {
this.r_offset = reader.readNextInt() & Conv.INT_MASK; this.r_offset = reader.readNextInt() & Conv.INT_MASK;

View file

@ -22,15 +22,23 @@ import java.util.List;
import generic.continues.GenericFactory; import generic.continues.GenericFactory;
import ghidra.app.util.bin.ByteArrayConverter; import ghidra.app.util.bin.ByteArrayConverter;
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
import ghidra.app.util.bin.format.dwarf4.LEB128;
import ghidra.program.model.data.ArrayDataType; import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.util.DataConverter; import ghidra.util.DataConverter;
import ghidra.util.Msg;
/** /**
* A container class to hold ELF relocations. * A container class to hold ELF relocations.
*/ */
public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter { public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
public enum TableFormat {
DEFAULT, ANDROID;
}
private TableFormat format;
private ElfSectionHeader sectionToBeRelocated; private ElfSectionHeader sectionToBeRelocated;
private ElfSymbolTable symbolTable; private ElfSymbolTable symbolTable;
@ -59,17 +67,19 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
* @param addendTypeReloc true if addend type relocation table * @param addendTypeReloc true if addend type relocation table
* @param symbolTable associated symbol table * @param symbolTable associated symbol table
* @param sectionToBeRelocated or null for dynamic relocation table * @param sectionToBeRelocated or null for dynamic relocation table
* @param format table format
* @return Elf relocation table object * @return Elf relocation table object
* @throws IOException * @throws IOException
*/ */
static ElfRelocationTable createElfRelocationTable(FactoryBundledWithBinaryReader reader, static ElfRelocationTable createElfRelocationTable(FactoryBundledWithBinaryReader reader,
ElfHeader header, ElfSectionHeader relocTableSection, long fileOffset, long addrOffset, ElfHeader header, ElfSectionHeader relocTableSection, long fileOffset, long addrOffset,
long length, long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable, long length, long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
ElfSectionHeader sectionToBeRelocated) throws IOException { ElfSectionHeader sectionToBeRelocated, TableFormat format) throws IOException {
ElfRelocationTable elfRelocationTable = ElfRelocationTable elfRelocationTable =
(ElfRelocationTable) reader.getFactory().create(ElfRelocationTable.class); (ElfRelocationTable) reader.getFactory().create(ElfRelocationTable.class);
elfRelocationTable.initElfRelocationTable(reader, header, relocTableSection, fileOffset, elfRelocationTable.initElfRelocationTable(reader, header, relocTableSection, fileOffset,
addrOffset, length, entrySize, addendTypeReloc, symbolTable, sectionToBeRelocated); addrOffset, length, entrySize, addendTypeReloc, symbolTable, sectionToBeRelocated,
format);
return elfRelocationTable; return elfRelocationTable;
} }
@ -82,7 +92,7 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
private void initElfRelocationTable(FactoryBundledWithBinaryReader reader, ElfHeader header, private void initElfRelocationTable(FactoryBundledWithBinaryReader reader, ElfHeader header,
ElfSectionHeader relocTableSection, long fileOffset, long addrOffset, long length, ElfSectionHeader relocTableSection, long fileOffset, long addrOffset, long length,
long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable, long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
ElfSectionHeader sectionToBeRelocated) throws IOException { ElfSectionHeader sectionToBeRelocated, TableFormat format) throws IOException {
this.relocTableSection = relocTableSection; this.relocTableSection = relocTableSection;
this.fileOffset = fileOffset; this.fileOffset = fileOffset;
@ -92,6 +102,7 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
this.addendTypeReloc = addendTypeReloc; this.addendTypeReloc = addendTypeReloc;
this.elfHeader = header; this.elfHeader = header;
this.factory = reader.getFactory(); this.factory = reader.getFactory();
this.format = format;
this.sectionToBeRelocated = sectionToBeRelocated; this.sectionToBeRelocated = sectionToBeRelocated;
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
@ -99,12 +110,12 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
long ptr = reader.getPointerIndex(); long ptr = reader.getPointerIndex();
reader.setPointerIndex(fileOffset); reader.setPointerIndex(fileOffset);
List<ElfRelocation> relocList = new ArrayList<ElfRelocation>(); List<ElfRelocation> relocList;
if (format == TableFormat.ANDROID) {
int nRelocs = (int) (length / entrySize); relocList = parseAndroidRelocations(reader);
for (int relocationIndex = 0; relocationIndex < nRelocs; ++relocationIndex) { }
relocList.add(ElfRelocation.createElfRelocation(reader, header, relocationIndex, else {
addendTypeReloc)); relocList = parseStandardRelocations(reader);
} }
reader.setPointerIndex(ptr); reader.setPointerIndex(ptr);
@ -113,6 +124,91 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
relocList.toArray(relocs); relocList.toArray(relocs);
} }
private List<ElfRelocation> parseStandardRelocations(FactoryBundledWithBinaryReader reader)
throws IOException {
List<ElfRelocation> relocations = new ArrayList<>();
int nRelocs = (int) (length / entrySize);
for (int relocationIndex = 0; relocationIndex < nRelocs; ++relocationIndex) {
relocations.add(ElfRelocation.createElfRelocation(reader, elfHeader, relocationIndex,
addendTypeReloc));
}
return relocations;
}
private List<ElfRelocation> parseAndroidRelocations(FactoryBundledWithBinaryReader reader)
throws IOException {
String identifier = reader.readNextAsciiString(4);
if (!"APS2".equals(identifier)) {
throw new IOException("Unsupported Android relocation table format");
}
List<ElfRelocation> relocations = new ArrayList<>();
try {
int relocationIndex = 0;
long remainingRelocations = LEB128.decode(reader, true);
long offset = LEB128.decode(reader, true);
long addend = 0;
while (remainingRelocations > 0) {
long groupSize = LEB128.decode(reader, true);
if (groupSize > remainingRelocations) {
Msg.warn(this, "Group relocation count " + groupSize +
" exceeded total count " + remainingRelocations);
break;
}
long groupFlags = LEB128.decode(reader, true);
boolean groupedByInfo =
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
boolean groupedByDelta = (groupFlags &
AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
boolean groupedByAddend =
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
boolean groupHasAddend =
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
long groupOffsetDelta = groupedByDelta ? LEB128.decode(reader, true) : 0;
long groupRInfo = groupedByInfo ? LEB128.decode(reader, true) : 0;
if (groupedByAddend && groupHasAddend) {
addend += LEB128.decode(reader, true);
}
for (int i = 0; i < groupSize; i++) {
offset += groupedByDelta ? groupOffsetDelta : LEB128.decode(reader, true);
long info = groupedByInfo ? groupRInfo : LEB128.decode(reader, true);
long rAddend = 0;
if (groupHasAddend) {
if (!groupedByAddend) {
addend += LEB128.decode(reader, true);
}
rAddend = addend;
}
relocations.add(ElfRelocation.createElfRelocation(reader.getFactory(),
elfHeader, relocationIndex++, addendTypeReloc, offset, info, rAddend));
}
if (!groupHasAddend) {
addend = 0;
}
remainingRelocations -= groupSize;
}
}
catch (IOException e) {
Msg.error(this, "Error reading relocations.", e);
}
return relocations;
}
/** /**
* @return true if has addend relocations, otherwise addend extraction from * @return true if has addend relocations, otherwise addend extraction from
* relocation target may be required * relocation target may be required
@ -150,9 +246,6 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
return symbolTable; return symbolTable;
} }
/**
* @see ghidra.app.util.bin.ByteArrayConverter#toBytes(ghidra.util.DataConverter)
*/
@Override @Override
public byte[] toBytes(DataConverter dc) { public byte[] toBytes(DataConverter dc) {
byte[] bytes = new byte[relocs.length * relocs[0].sizeof()]; byte[] bytes = new byte[relocs.length * relocs[0].sizeof()];
@ -194,13 +287,14 @@ public class ElfRelocationTable implements ElfFileSection, ByteArrayConverter {
return (int) entrySize; return (int) entrySize;
} }
/**
* @see ghidra.app.util.bin.StructConverter#toDataType()
*/
@Override @Override
public DataType toDataType() { public DataType toDataType() {
if (format == TableFormat.ANDROID) {
return new AndroidElfRelocationTableDataType();
}
ElfRelocation relocationRepresentative = ElfRelocation relocationRepresentative =
ElfRelocation.createElfRelocation(factory, elfHeader, -1, addendTypeReloc); ElfRelocation.createElfRelocation(factory, elfHeader, -1, addendTypeReloc, 0, 0, 0);
DataType relocEntryDataType = relocationRepresentative.toDataType(); DataType relocEntryDataType = relocationRepresentative.toDataType();
return new ArrayDataType(relocEntryDataType, (int) (length / entrySize), (int) entrySize); return new ArrayDataType(relocEntryDataType, (int) (length / entrySize), (int) entrySize);
} }

View file

@ -111,6 +111,11 @@ public class ElfSectionHeaderConstants {
// OS Specific Section Types // OS Specific Section Types
/**Android relocation entries w/o explicit addends*/
public static final int SHT_ANDROID_REL = 0x60000001;
/**Android relocation entries with explicit addends*/
public static final int SHT_ANDROID_RELA = 0x60000002;
/**Object attributes */ /**Object attributes */
public static final int SHT_GNU_ATTRIBUTES = 0x6ffffff5; public static final int SHT_GNU_ATTRIBUTES = 0x6ffffff5;
/**GNU-style hash table */ /**GNU-style hash table */

View file

@ -69,6 +69,11 @@ public class ElfSectionHeaderType {
// OS-specific range: 0x60000000 - 0x6fffffff // OS-specific range: 0x60000000 - 0x6fffffff
public static ElfSectionHeaderType SHT_ANDROID_REL = addDefaultSectionHeaderType(
ElfSectionHeaderConstants.SHT_ANDROID_REL, "SHT_ANDROID_REL", "Android relocation entries w/o explicit addends");
public static ElfSectionHeaderType SHT_ANDROID_RELA = addDefaultSectionHeaderType(
ElfSectionHeaderConstants.SHT_ANDROID_RELA, "SHT_ANDROID_RELA", "Android relocation entries with explicit addends");
public static ElfSectionHeaderType SHT_GNU_ATTRIBUTES = addDefaultSectionHeaderType( public static ElfSectionHeaderType SHT_GNU_ATTRIBUTES = addDefaultSectionHeaderType(
ElfSectionHeaderConstants.SHT_GNU_ATTRIBUTES, "SHT_GNU_ATTRIBUTES", "Object attributes"); ElfSectionHeaderConstants.SHT_GNU_ATTRIBUTES, "SHT_GNU_ATTRIBUTES", "Object attributes");
public static ElfSectionHeaderType SHT_GNU_HASH = addDefaultSectionHeaderType( public static ElfSectionHeaderType SHT_GNU_HASH = addDefaultSectionHeaderType(

View file

@ -90,7 +90,8 @@ public class ElfLoader extends AbstractLibrarySupportLoader {
} }
@Override @Override
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) { public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program) {
if (options != null) { if (options != null) {
String validationErrorStr = ElfLoaderOptionsFactory.validateOptions(loadSpec, options); String validationErrorStr = ElfLoaderOptionsFactory.validateOptions(loadSpec, options);
if (validationErrorStr != null) { if (validationErrorStr != null) {
@ -143,7 +144,8 @@ public class ElfLoader extends AbstractLibrarySupportLoader {
@Override @Override
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options, public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program, TaskMonitor monitor, MessageLog log) throws IOException { Program program, TaskMonitor monitor, MessageLog log)
throws IOException, CancelledException {
try { try {
GenericFactory factory = MessageLogContinuesFactory.create(log); GenericFactory factory = MessageLogContinuesFactory.create(log);
@ -153,10 +155,6 @@ public class ElfLoader extends AbstractLibrarySupportLoader {
catch (ElfException e) { catch (ElfException e) {
throw new IOException(e.getMessage()); throw new IOException(e.getMessage());
} }
catch (CancelledException e) {
// TODO: Caller should properly handle CancelledException instead
throw new IOException(e.getMessage());
}
} }
@Override @Override

View file

@ -158,9 +158,9 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
elf.getLoadAdapter().processElf(this, monitor); elf.getLoadAdapter().processElf(this, monitor);
processRelocations(monitor);
processEntryPoints(monitor); processEntryPoints(monitor);
processImports(monitor); processImports(monitor);
processRelocations(monitor);
monitor.setMessage("Processing PLT/GOT ..."); monitor.setMessage("Processing PLT/GOT ...");
elf.getLoadAdapter().processGotPlt(this, monitor); elf.getLoadAdapter().processGotPlt(this, monitor);
@ -469,17 +469,19 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
// process dynamic entry points // process dynamic entry points
createDynamicEntryPoints(ElfDynamicType.DT_INIT, null, monitor); createDynamicEntryPoints(ElfDynamicType.DT_INIT, null, "_INIT_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_INIT_ARRAY, ElfDynamicType.DT_INIT_ARRAYSZ, createDynamicEntryPoints(ElfDynamicType.DT_INIT_ARRAY, ElfDynamicType.DT_INIT_ARRAYSZ,
monitor); "_INIT_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_FINI, null, monitor); createDynamicEntryPoints(ElfDynamicType.DT_PREINIT_ARRAY, ElfDynamicType.DT_PREINIT_ARRAYSZ,
"_PREINIT_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_FINI, null, "_FINI_", monitor);
createDynamicEntryPoints(ElfDynamicType.DT_FINI_ARRAY, ElfDynamicType.DT_FINI_ARRAYSZ, createDynamicEntryPoints(ElfDynamicType.DT_FINI_ARRAY, ElfDynamicType.DT_FINI_ARRAYSZ,
monitor); "_FINI_", monitor);
} }
private void createDynamicEntryPoints(ElfDynamicType dynamicEntryType, private void createDynamicEntryPoints(ElfDynamicType dynamicEntryType,
ElfDynamicType entryArraySizeType, TaskMonitor monitor) { ElfDynamicType entryArraySizeType, String baseName, TaskMonitor monitor) {
ElfDynamicTable dynamicTable = elf.getDynamicTable(); ElfDynamicTable dynamicTable = elf.getDynamicTable();
if (dynamicTable == null) { if (dynamicTable == null) {
@ -502,8 +504,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
long arraySize = dynamicTable.getDynamicValue(entryArraySizeType); long arraySize = dynamicTable.getDynamicValue(entryArraySizeType);
long elementCount = arraySize / dt.getLength(); long elementCount = arraySize / dt.getLength();
String baseName = dynamicEntryType.name.startsWith("DT_INIT") ? "_INIT_" : "_FINI_";
for (int i = 0; i < elementCount; i++) { for (int i = 0; i < elementCount; i++) {
Address addr = entryArrayAddr.add(i * dt.getLength()); Address addr = entryArrayAddr.add(i * dt.getLength());
Data data = createData(addr, dt); Data data = createData(addr, dt);
@ -512,6 +512,9 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
Scalar value = (Scalar) data.getValue(); Scalar value = (Scalar) data.getValue();
if (value != null) { if (value != null) {
if (i != 0 && value.getValue() == 0) {
continue;
}
long funcAddrOffset = elf.adjustAddressForPrelink(value.getValue()); long funcAddrOffset = elf.adjustAddressForPrelink(value.getValue());
Address funcAddr = createEntryFunction(baseName + i, funcAddrOffset, monitor); Address funcAddr = createEntryFunction(baseName + i, funcAddrOffset, monitor);
if (funcAddr != null) { if (funcAddr != null) {

View file

@ -64,7 +64,6 @@ public abstract class DynamicDataType extends BuiltIn implements Dynamic {
* their data context. A null value is acceptable to indicate that a memory * their data context. A null value is acceptable to indicate that a memory
* context is not available. DataTypes that need a context will return -1 * context is not available. DataTypes that need a context will return -1
* if the context is null. * if the context is null.
* @return the number of components that make up this data prototype * @return the number of components that make up this data prototype
* - if this is an Array, return the number of elements in the array. * - if this is an Array, return the number of elements in the array.
* - if this datatype is a subcomponent of another datatype and it * - if this datatype is a subcomponent of another datatype and it
@ -78,7 +77,7 @@ public abstract class DynamicDataType extends BuiltIn implements Dynamic {
return -1; return -1;
} }
private DataTypeComponent[] getComps(MemBuffer buf) { protected DataTypeComponent[] getComps(MemBuffer buf) {
Address addr = buf.getAddress(); Address addr = buf.getAddress();
DataTypeComponent[] comps = map.get(addr); DataTypeComponent[] comps = map.get(addr);
if (comps == null) { if (comps == null) {
@ -150,6 +149,12 @@ public abstract class DynamicDataType extends BuiltIn implements Dynamic {
} }
/**
* Get all dynamic components associated with the specified MemBuffer
* @param buf memory buffer positioned at start of data type instance
* @return all components or null if memory data is not valid for this
* data type.
*/
protected abstract DataTypeComponent[] getAllComponents(MemBuffer buf); protected abstract DataTypeComponent[] getAllComponents(MemBuffer buf);
@Override @Override