mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-3091 ppc64 ELF improvements for 32-bit addressing. Fixed default ELF
GOT markup boundary condition. Fixed improper EXTERNAL symbols with .pltgot. prefix and duplication.
This commit is contained in:
parent
0ddd0d7533
commit
4a0e95ecd3
7 changed files with 375 additions and 176 deletions
|
@ -216,9 +216,13 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand<Program> {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Symbol[] syms = symTable.getSymbols(addr);
|
Symbol[] syms = symTable.getSymbols(addr);
|
||||||
for (Symbol sym : syms) {
|
for (Symbol sym : syms) {
|
||||||
|
// TODO: GP-5872 This code is suspect - should it be restricted to LABELS only.
|
||||||
|
// Why would we remove a non-default function that had references?
|
||||||
if (sym.getSource() == SourceType.DEFAULT) {
|
if (sym.getSource() == SourceType.DEFAULT) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// TODO: GP-5872 If one of many labels at a location has a direct reference why
|
||||||
|
// would we bail when we may have already removed a few that did not.
|
||||||
if (sym.hasReferences()) {
|
if (sym.hasReferences()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -718,6 +722,11 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand<Program> {
|
||||||
if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
|
if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
|
||||||
continue; // keep imported or user-defined function
|
continue; // keep imported or user-defined function
|
||||||
}
|
}
|
||||||
|
// TODO: GP-5872 Clearing thunks explicitly created by loader or pattern
|
||||||
|
// generally have default SourceType and may not have references
|
||||||
|
// to them. We need to prevent these thunks from getting cleared.
|
||||||
|
// PowerPC64 ELF extension was forced to rename thunks it created to
|
||||||
|
// avoid this where the thunk rename has its own set of issues.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clearOffcut && !destAddrs.contains(blockAddr)) {
|
if (clearOffcut && !destAddrs.contains(blockAddr)) {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -167,8 +167,7 @@ public class ElfDefaultGotPltMarkup {
|
||||||
// PLT head is unknown. If the binary has not placed external symbols within the PLT
|
// PLT head is unknown. If the binary has not placed external symbols within the PLT
|
||||||
// processing and disassembly of the PLT may be skipped.
|
// processing and disassembly of the PLT may be skipped.
|
||||||
|
|
||||||
long pltgot = elf.adjustAddressForPrelink(
|
long pltgot = elf.adjustAddressForPrelink(dynamicTable.getDynamicValue(pltGotType));
|
||||||
dynamicTable.getDynamicValue(pltGotType));
|
|
||||||
Address gotStart = defaultSpace.getAddress(pltgot + imageBaseAdj);
|
Address gotStart = defaultSpace.getAddress(pltgot + imageBaseAdj);
|
||||||
|
|
||||||
ElfRelocation[] relocations = relocationTable.getRelocations();
|
ElfRelocation[] relocations = relocationTable.getRelocations();
|
||||||
|
@ -354,7 +353,7 @@ public class ElfDefaultGotPltMarkup {
|
||||||
* Mark-up all GOT entries as pointers within the memory range gotStart to
|
* Mark-up all GOT entries as pointers within the memory range gotStart to
|
||||||
* gotEnd.
|
* gotEnd.
|
||||||
* @param gotStart address for start of GOT
|
* @param gotStart address for start of GOT
|
||||||
* @param gotEnd address for end of GOT
|
* @param gotEnd address for end of GOT (inclusive)
|
||||||
* @param monitor task monitor
|
* @param monitor task monitor
|
||||||
* @throws CancelledException thrown if task cancelled
|
* @throws CancelledException thrown if task cancelled
|
||||||
*/
|
*/
|
||||||
|
@ -402,21 +401,17 @@ public class ElfDefaultGotPltMarkup {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
|
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
|
||||||
|
long gotSizeRemaining = gotEnd.subtract(gotStart) + 1;
|
||||||
|
long entryOffset = 0;
|
||||||
Address newImageBase = null;
|
Address newImageBase = null;
|
||||||
Address nextGotAddr = gotStart;
|
while (gotSizeRemaining >= pointerSize) {
|
||||||
while (gotEnd.subtract(nextGotAddr) >= pointerSize) {
|
Address nextGotAddr = gotStart.addNoWrap(entryOffset);
|
||||||
|
|
||||||
data = createPointer(nextGotAddr, true);
|
data = createPointer(nextGotAddr, true);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
gotSizeRemaining -= pointerSize;
|
||||||
try {
|
entryOffset += pointerSize;
|
||||||
nextGotAddr = data.getMaxAddress().add(1);
|
|
||||||
}
|
|
||||||
catch (AddressOutOfBoundsException e) {
|
|
||||||
break; // no more room
|
|
||||||
}
|
|
||||||
newImageBase = UglyImageBaseCheck(data, newImageBase);
|
newImageBase = UglyImageBaseCheck(data, newImageBase);
|
||||||
}
|
}
|
||||||
if (newImageBase != null) {
|
if (newImageBase != null) {
|
||||||
|
@ -573,12 +568,6 @@ public class ElfDefaultGotPltMarkup {
|
||||||
}
|
}
|
||||||
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
|
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
|
||||||
Pointer pointer = PointerDataType.dataType.clone(program.getDataTypeManager());
|
Pointer pointer = PointerDataType.dataType.clone(program.getDataTypeManager());
|
||||||
if (elf.is32Bit() && pointerSize != 4) {
|
|
||||||
pointer = Pointer32DataType.dataType;
|
|
||||||
}
|
|
||||||
else if (elf.is64Bit() && pointerSize != 8) {
|
|
||||||
pointer = Pointer64DataType.dataType;
|
|
||||||
}
|
|
||||||
Data data = listing.getDataAt(addr);
|
Data data = listing.getDataAt(addr);
|
||||||
if (data == null || !pointer.isEquivalent(data.getDataType())) {
|
if (data == null || !pointer.isEquivalent(data.getDataType())) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
@ -623,7 +612,10 @@ public class ElfDefaultGotPltMarkup {
|
||||||
Program program = pointerData.getProgram();
|
Program program = pointerData.getProgram();
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
Address refAddr = (Address) pointerData.getValue();
|
Address refAddr = (Address) pointerData.getValue();
|
||||||
if (memory.contains(refAddr)) {
|
if (refAddr == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (memory.contains(refAddr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Symbol primary = program.getSymbolTable().getPrimarySymbol(refAddr);
|
Symbol primary = program.getSymbolTable().getPrimarySymbol(refAddr);
|
||||||
|
|
|
@ -20,6 +20,8 @@ import static ghidra.program.util.FunctionChangeRecord.FunctionChangeType.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import javax.help.UnsupportedOperationException;
|
||||||
|
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
import ghidra.program.database.*;
|
import ghidra.program.database.*;
|
||||||
import ghidra.program.database.data.DataTypeManagerDB;
|
import ghidra.program.database.data.DataTypeManagerDB;
|
||||||
|
@ -140,6 +142,9 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setThunkedFunction(Function referencedFunction) {
|
public void setThunkedFunction(Function referencedFunction) {
|
||||||
|
if (isExternal()) {
|
||||||
|
throw new UnsupportedOperationException("External functions may not be a thunk");
|
||||||
|
}
|
||||||
if ((referencedFunction != null) && !(referencedFunction instanceof FunctionDB)) {
|
if ((referencedFunction != null) && !(referencedFunction instanceof FunctionDB)) {
|
||||||
throw new IllegalArgumentException("FunctionDB expected for referenced function");
|
throw new IllegalArgumentException("FunctionDB expected for referenced function");
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,6 +702,7 @@ public interface Function extends Namespace {
|
||||||
* @throws IllegalArgumentException if an attempt is made to thunk a function or another
|
* @throws IllegalArgumentException if an attempt is made to thunk a function or another
|
||||||
* thunk which would result in a loop back to this function or if this function is an external
|
* thunk which would result in a loop back to this function or if this function is an external
|
||||||
* function, or specified function is from a different program instance.
|
* function, or specified function is from a different program instance.
|
||||||
|
* @throws UnsupportedOperationException if this method is invoked on an external function.
|
||||||
*/
|
*/
|
||||||
public void setThunkedFunction(Function thunkedFunction) throws IllegalArgumentException;
|
public void setThunkedFunction(Function thunkedFunction) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -113,6 +113,8 @@ public interface FunctionManager extends ManagerDB {
|
||||||
* @return new function or null if one or more functions overlap the specified body address set.
|
* @return new function or null if one or more functions overlap the specified body address set.
|
||||||
* @throws OverlappingFunctionException if the address set of the body overlaps an existing
|
* @throws OverlappingFunctionException if the address set of the body overlaps an existing
|
||||||
* function
|
* function
|
||||||
|
* @throws UnsupportedOperationException if this method is invoked on an external entryPoint
|
||||||
|
* address.
|
||||||
*/
|
*/
|
||||||
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
|
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||||
AddressSetView body, Function thunkedFunction, SourceType source)
|
AddressSetView body, Function thunkedFunction, SourceType source)
|
||||||
|
|
|
@ -24,13 +24,11 @@ import ghidra.app.util.bin.format.elf.*;
|
||||||
import ghidra.app.util.bin.format.elf.ElfDynamicType.ElfDynamicValueType;
|
import ghidra.app.util.bin.format.elf.ElfDynamicType.ElfDynamicValueType;
|
||||||
import ghidra.app.util.bin.format.elf.relocation.PowerPC64_ElfRelocationType;
|
import ghidra.app.util.bin.format.elf.relocation.PowerPC64_ElfRelocationType;
|
||||||
import ghidra.app.util.opinion.ElfLoader;
|
import ghidra.app.util.opinion.ElfLoader;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressOverflowException;
|
|
||||||
import ghidra.program.model.data.PointerDataType;
|
import ghidra.program.model.data.PointerDataType;
|
||||||
import ghidra.program.model.data.QWordDataType;
|
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.program.model.reloc.Relocation;
|
import ghidra.program.model.reloc.Relocation;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
@ -66,19 +64,24 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
private static final int STO_PPC64_LOCAL_BIT = 5;
|
private static final int STO_PPC64_LOCAL_BIT = 5;
|
||||||
private static final int STO_PPC64_LOCAL_MASK = 0xE0;
|
private static final int STO_PPC64_LOCAL_MASK = 0xE0;
|
||||||
|
|
||||||
|
// Use equate for ELFv1 to remember if function descriptors use 2 or 3 pointers.
|
||||||
|
// An equate value of 0 indicates 3-pointers, while 1 indicates 2-pointers
|
||||||
|
private static final String FN_DESCR_TYPE_NAME = "_ELFv1_PPC64_FN_DESCR_TYPE_";
|
||||||
|
|
||||||
public static final String TOC_BASE = "TOC_BASE"; // injected symbol to mark global TOC_BASE
|
public static final String TOC_BASE = "TOC_BASE"; // injected symbol to mark global TOC_BASE
|
||||||
|
|
||||||
|
public static final String OPD_SECTION_NAME = ".opd";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canHandle(ElfHeader elf) {
|
public boolean canHandle(ElfHeader elf) {
|
||||||
return elf.e_machine() == ElfConstants.EM_PPC64 && elf.is64Bit();
|
return elf.e_machine() == ElfConstants.EM_PPC64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
|
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
|
||||||
Language language = elfLoadHelper.getProgram().getLanguage();
|
Language language = elfLoadHelper.getProgram().getLanguage();
|
||||||
return canHandle(elfLoadHelper.getElfHeader()) &&
|
return canHandle(elfLoadHelper.getElfHeader()) &&
|
||||||
"PowerPC".equals(language.getProcessor().toString()) &&
|
"PowerPC".equals(language.getProcessor().toString());
|
||||||
language.getLanguageDescription().getSize() == 64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,12 +110,104 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
setEntryPointContext(elfLoadHelper, monitor);
|
setEntryPointContext(elfLoadHelper, monitor);
|
||||||
|
|
||||||
processOPDSection(elfLoadHelper, monitor);
|
if (getPpc64ElfABIVersion(elfLoadHelper.getElfHeader()) != 2) {
|
||||||
|
processOPDSection(elfLoadHelper, monitor); // establishes OPD_SIZE equate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Super handles conventional GOT and executable PLT
|
||||||
super.processGotPlt(elfLoadHelper, monitor);
|
super.processGotPlt(elfLoadHelper, monitor);
|
||||||
|
|
||||||
processPpc64v2PltPointerTable(elfLoadHelper, monitor);
|
// ppc64 extension only handles non-execute PLT containing pointers or function descriptors
|
||||||
processPpc64PltGotPointerTable(elfLoadHelper, monitor);
|
ElfHeader elf = elfLoadHelper.getElfHeader();
|
||||||
|
if (getPpc64ElfABIVersion(elf) == 2) {
|
||||||
|
setPpc64ELFv2TocBase(elfLoadHelper, monitor);
|
||||||
|
}
|
||||||
|
if (!processPpc64DynamicPltPointerTable(elfLoadHelper, monitor)) {
|
||||||
|
processPpc64PltSectionPointerTable(elfLoadHelper, monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPpc64ELFv2TocBase(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) {
|
||||||
|
// paint TOC_BASE value as r2 across executable blocks since r2
|
||||||
|
// is needed to resolve call stubs
|
||||||
|
Symbol tocSymbol = SymbolUtilities.getLabelOrFunctionSymbol(elfLoadHelper.getProgram(),
|
||||||
|
TOC_BASE, err -> elfLoadHelper.getLog().appendMsg("PowerPC64_ELF", err));
|
||||||
|
if (tocSymbol != null) {
|
||||||
|
paintTocAsR2value(tocSymbol.getAddress().getOffset(), elfLoadHelper, monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rememberELFv1FunctionDescriptorSize(ElfLoadHelper elfLoadHelper,
|
||||||
|
boolean hasThreePointerFnDescriptor) {
|
||||||
|
EquateTable equateTable = elfLoadHelper.getProgram().getEquateTable();
|
||||||
|
try {
|
||||||
|
equateTable.createEquate(FN_DESCR_TYPE_NAME, hasThreePointerFnDescriptor ? 0 : 1);
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException | InvalidInputException e) {
|
||||||
|
Msg.error(this, "Unexpected exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recall the determination of function desciptors using 2 or 3 pointers for ELFv1.
|
||||||
|
* The {@link #rememberELFv1FunctionDescriptorSize(ElfLoadHelper, boolean)} must have been
|
||||||
|
* previously invoked to store this via an Equate use {@link #FN_DESCR_TYPE_NAME}.
|
||||||
|
* @param elfLoadHelper ELF load helper
|
||||||
|
* @return true if 3-pointer or false if 2-pointer function descriptor, null if never stored
|
||||||
|
*/
|
||||||
|
private Boolean hasELFv1ThreePointerFnDescriptor(ElfLoadHelper elfLoadHelper) {
|
||||||
|
EquateTable equateTable = elfLoadHelper.getProgram().getEquateTable();
|
||||||
|
Equate value = equateTable.getEquate(FN_DESCR_TYPE_NAME);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return value.getValue() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the ELFv1 Function Descriptor size/type by checking TOC_Base entry for first
|
||||||
|
* two .opd entries.
|
||||||
|
* @param opdAddr entry address of within .opd (generally, should be first entry)
|
||||||
|
* @param uses32bitPtr true if 32-bit pointers are used, false if 64-bit
|
||||||
|
* @param mem program memory
|
||||||
|
* @param isFirstEntry true if opdAddr corresponds to first entry
|
||||||
|
* @return true if .opd entried consist of three pointers, false if two pointers
|
||||||
|
* @throws MemoryAccessException if memory access error occurs while checking .opd entries
|
||||||
|
* @throws AddressOverflowException if address error occurs while checking .opd entries
|
||||||
|
*/
|
||||||
|
private boolean hasELFv1ThreePointerFnDescriptor(Address opdAddr, boolean uses32bitPtr,
|
||||||
|
Memory mem, boolean isFirstEntry)
|
||||||
|
throws MemoryAccessException, AddressOverflowException {
|
||||||
|
|
||||||
|
// NOTE: This method assumes the first two entries within the .opd region will have the same
|
||||||
|
// TOC value (2nd pointer). I'm sure this is over simplified and could fail for some larger
|
||||||
|
// binaries. If a better test is devised it could replace the use of this method.
|
||||||
|
|
||||||
|
int pointerSize = uses32bitPtr ? 4 : 8;
|
||||||
|
|
||||||
|
long tocValue = getUnsignedValue(opdAddr.addNoWrap(pointerSize), uses32bitPtr, mem);
|
||||||
|
|
||||||
|
// look forward assuming 2-pointer descriptor size
|
||||||
|
try {
|
||||||
|
long nextTocValue =
|
||||||
|
getUnsignedValue(opdAddr.addNoWrap(3 * pointerSize), uses32bitPtr, mem);
|
||||||
|
if (nextTocValue == tocValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isFirstEntry) {
|
||||||
|
long prevTocValue =
|
||||||
|
getUnsignedValue(opdAddr.subtractNoWrap(pointerSize), uses32bitPtr, mem);
|
||||||
|
if (prevTocValue == tocValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (AddressOverflowException | MemoryAccessException e) {
|
||||||
|
// ignore error from peeking around
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // assume 3-pointer descriptor use
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findTocBase(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) {
|
private void findTocBase(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) {
|
||||||
|
@ -147,27 +242,33 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPpc64PltGotPointerTable(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
private void processPpc64PltSectionPointerTable(ElfLoadHelper elfLoadHelper,
|
||||||
throws CancelledException {
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
MemoryBlock pltBlock = getPltSectionBlockSetReadOnly(elfLoadHelper);
|
||||||
|
if (pltBlock == null) {
|
||||||
|
return; // .plt not found or is executable
|
||||||
|
}
|
||||||
|
|
||||||
ElfHeader elf = elfLoadHelper.getElfHeader();
|
ElfHeader elf = elfLoadHelper.getElfHeader();
|
||||||
if (getPpc64ABIVersion(elf) == 2) {
|
if (getPpc64ElfABIVersion(elf) == 2) {
|
||||||
// paint TOC_BASE value as r2 across executable blocks since r2
|
markupELFv2PltGot(elfLoadHelper, pltBlock.getStart(), -1, monitor);
|
||||||
// is needed to resolve call stubs
|
|
||||||
Symbol tocSymbol = SymbolUtilities.getLabelOrFunctionSymbol(elfLoadHelper.getProgram(),
|
|
||||||
TOC_BASE, err -> elfLoadHelper.getLog().appendMsg("PowerPC64_ELF", err));
|
|
||||||
if (tocSymbol != null) {
|
|
||||||
paintTocAsR2value(tocSymbol.getAddress().getOffset(), elfLoadHelper, monitor);
|
|
||||||
}
|
|
||||||
// TODO: verify ABI detection
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
markupELFv1PltPointerTable(elfLoadHelper, pltBlock.getStart(), -1, monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean processPpc64DynamicPltPointerTable(ElfLoadHelper elfLoadHelper,
|
||||||
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
ElfHeader elf = elfLoadHelper.getElfHeader();
|
||||||
|
|
||||||
ElfDynamicTable dynamicTable = elf.getDynamicTable();
|
ElfDynamicTable dynamicTable = elf.getDynamicTable();
|
||||||
if (dynamicTable == null || !dynamicTable.containsDynamicValue(ElfDynamicType.DT_PLTGOT) ||
|
if (dynamicTable == null || !dynamicTable.containsDynamicValue(ElfDynamicType.DT_PLTGOT) ||
|
||||||
!dynamicTable.containsDynamicValue(ElfDynamicType.DT_PLTRELSZ) ||
|
!dynamicTable.containsDynamicValue(ElfDynamicType.DT_PLTRELSZ) ||
|
||||||
!dynamicTable.containsDynamicValue(ElfDynamicType.DT_PLTREL)) {
|
!dynamicTable.containsDynamicValue(ElfDynamicType.DT_PLTREL)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -175,27 +276,119 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
elf.adjustAddressForPrelink(dynamicTable.getDynamicValue(ElfDynamicType.DT_PLTGOT));
|
elf.adjustAddressForPrelink(dynamicTable.getDynamicValue(ElfDynamicType.DT_PLTGOT));
|
||||||
Address pltAddr = elfLoadHelper.getDefaultAddress(pltgotOffset);
|
Address pltAddr = elfLoadHelper.getDefaultAddress(pltgotOffset);
|
||||||
Program program = elfLoadHelper.getProgram();
|
Program program = elfLoadHelper.getProgram();
|
||||||
MemoryBlock pltBlock = program.getMemory().getBlock(pltAddr);
|
MemoryBlock block = program.getMemory().getBlock(pltAddr);
|
||||||
if (pltBlock == null || pltBlock.isExecute()) {
|
if (block == null || block.isExecute()) {
|
||||||
return;
|
return false; // PLT block not found or is executable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute number of entries in .pltgot based upon number of associated dynamic relocations
|
||||||
int relEntrySize = (dynamicTable
|
int relEntrySize = (dynamicTable
|
||||||
.getDynamicValue(ElfDynamicType.DT_PLTREL) == ElfDynamicType.DT_RELA.value) ? 24
|
.getDynamicValue(ElfDynamicType.DT_PLTREL) == ElfDynamicType.DT_RELA.value) ? 24
|
||||||
: 16;
|
: 16;
|
||||||
|
|
||||||
long pltEntryCount =
|
long pltEntryCount =
|
||||||
dynamicTable.getDynamicValue(ElfDynamicType.DT_PLTRELSZ) / relEntrySize;
|
dynamicTable.getDynamicValue(ElfDynamicType.DT_PLTRELSZ) / relEntrySize;
|
||||||
|
|
||||||
|
if (getPpc64ElfABIVersion(elf) == 2) {
|
||||||
|
markupELFv2PltGot(elfLoadHelper, pltAddr, pltEntryCount, monitor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
markupELFv1PltPointerTable(elfLoadHelper, pltAddr, pltEntryCount, monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NotFoundException e) {
|
||||||
|
throw new AssertException("Unexpected Error", e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markupELFv2PltGot(ElfLoadHelper elfLoadHelper, Address pltAddr, long pltEntryCount,
|
||||||
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
int pointerSize = elfLoadHelper.getProgram().getDefaultPointerSize();
|
||||||
|
|
||||||
|
if (pltEntryCount <= 0) {
|
||||||
|
// compute based upon block size
|
||||||
|
MemoryBlock pltBlock = elfLoadHelper.getProgram().getMemory().getBlock(pltAddr);
|
||||||
|
pltEntryCount = (pltBlock.getSize() - PLT_HEAD_SIZE) / pointerSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address addr = pltAddr.add(PLT_HEAD_SIZE);
|
||||||
|
try {
|
||||||
|
monitor.setShowProgressValue(true);
|
||||||
|
monitor.setProgress(0);
|
||||||
|
monitor.setMaximum(pltEntryCount);
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
for (int i = 0; i < pltEntryCount; i++) {
|
for (int i = 0; i < pltEntryCount; i++) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
pltAddr = pltAddr.addNoWrap(24);
|
monitor.setProgress(++count);
|
||||||
Symbol refSymbol = markupDescriptorEntry(pltAddr, false, elfLoadHelper);
|
if (elfLoadHelper.createData(addr, PointerDataType.dataType) == null) {
|
||||||
|
break; // stop early if failed to create a pointer
|
||||||
|
}
|
||||||
|
addr = addr.addNoWrap(pointerSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (AddressOverflowException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markupELFv1PltPointerTable(ElfLoadHelper elfLoadHelper, Address pltAddr,
|
||||||
|
long pltEntryCount, TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
// Recover ELFv1 function descriptor type from stored Equate
|
||||||
|
Boolean hasThreePointerFnDescriptor = hasELFv1ThreePointerFnDescriptor(elfLoadHelper);
|
||||||
|
if (hasThreePointerFnDescriptor == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: There are different conventions for the PLT based upon specific ABI
|
||||||
|
// conventions. Dectecting what convention applies can be very tricky
|
||||||
|
// and may requiring applying some hueristic. For now we will avoid
|
||||||
|
// marking up this section and rely on other analysis.
|
||||||
|
//
|
||||||
|
// Case observations:
|
||||||
|
// - Shared library for ELFv1 treated .plt section similar to .opd with
|
||||||
|
// the placement of function descriptors (3 pointers).
|
||||||
|
|
||||||
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
Memory mem = program.getMemory();
|
||||||
|
|
||||||
|
int fnDescriptorSize = hasThreePointerFnDescriptor ? 3 : 2;
|
||||||
|
int pointerByteSize = program.getDefaultPointerSize();
|
||||||
|
int opdEntryByteSize = fnDescriptorSize * pointerByteSize;
|
||||||
|
|
||||||
|
if (pltEntryCount <= 0) {
|
||||||
|
// compute based upon block size
|
||||||
|
MemoryBlock pltBlock = elfLoadHelper.getProgram().getMemory().getBlock(pltAddr);
|
||||||
|
pltEntryCount = pltBlock.getSize() / opdEntryByteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
monitor.setShowProgressValue(true);
|
||||||
|
monitor.setProgress(0);
|
||||||
|
monitor.setMaximum(pltEntryCount);
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < pltEntryCount; i++) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
monitor.setProgress(++count);
|
||||||
|
|
||||||
|
// NOTE: First entry is skipped intentionally
|
||||||
|
pltAddr = pltAddr.addNoWrap(opdEntryByteSize);
|
||||||
|
|
||||||
|
Symbol refSymbol = markupDescriptorEntry(pltAddr, false,
|
||||||
|
hasThreePointerFnDescriptor, elfLoadHelper);
|
||||||
if (refSymbol != null && refSymbol.getSymbolType() == SymbolType.FUNCTION &&
|
if (refSymbol != null && refSymbol.getSymbolType() == SymbolType.FUNCTION &&
|
||||||
refSymbol.getSource() == SourceType.DEFAULT) {
|
refSymbol.getSource() == SourceType.DEFAULT &&
|
||||||
|
!mem.isExternalBlockAddress(refSymbol.getAddress())) {
|
||||||
|
|
||||||
|
// TODO: Rename of DEFAULT thunk should always be avoided (see GP-5872)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Force source type on function to prevent potential removal by clear-flow
|
// Rename default symbol with non-default source to prevent potential removal
|
||||||
refSymbol.setName(".pltgot." + refSymbol.getName(), SourceType.IMPORTED);
|
// by clear-flow.
|
||||||
|
refSymbol.setName(".plt." + refSymbol.getName(), SourceType.IMPORTED);
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException | InvalidInputException e) {
|
catch (DuplicateNameException | InvalidInputException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -203,9 +396,6 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (NotFoundException e) {
|
|
||||||
throw new AssertException("unexpected", e);
|
|
||||||
}
|
|
||||||
catch (AddressOverflowException e) {
|
catch (AddressOverflowException e) {
|
||||||
elfLoadHelper.log("Failed to process PltGot entries: " + e.getMessage());
|
elfLoadHelper.log("Failed to process PltGot entries: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -234,91 +424,120 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPpc64v2PltPointerTable(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
private MemoryBlock getPltSectionBlockSetReadOnly(ElfLoadHelper elfLoadHelper) {
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
ElfHeader elf = elfLoadHelper.getElfHeader();
|
ElfHeader elf = elfLoadHelper.getElfHeader();
|
||||||
ElfSectionHeader pltSection = elf.getSection(ElfSectionHeaderConstants.dot_plt);
|
ElfSectionHeader pltSection = elf.getSection(ElfSectionHeaderConstants.dot_plt);
|
||||||
if (pltSection == null) {
|
if (pltSection == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
Program program = elfLoadHelper.getProgram();
|
Program program = elfLoadHelper.getProgram();
|
||||||
MemoryBlock pltBlock = program.getMemory().getBlock(pltSection.getNameAsString());
|
MemoryBlock pltBlock = program.getMemory().getBlock(pltSection.getNameAsString());
|
||||||
if (pltBlock == null) {
|
if (pltBlock == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
if (pltSection.isExecutable()) {
|
if (pltSection.isExecutable()) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set pltBlock read-only to permit decompiler simplification
|
// set pltBlock read-only to permit decompiler simplification
|
||||||
pltBlock.setWrite(false);
|
pltBlock.setWrite(false);
|
||||||
|
|
||||||
if (getPpc64ABIVersion(elf) != 2) {
|
return pltBlock;
|
||||||
// TODO: add support for other PLT implementations
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Uncertain
|
|
||||||
|
|
||||||
Address addr = pltBlock.getStart().add(PLT_HEAD_SIZE);
|
|
||||||
try {
|
|
||||||
while (addr.compareTo(pltBlock.getEnd()) < 0) {
|
|
||||||
monitor.checkCancelled();
|
|
||||||
if (elfLoadHelper.createData(addr, PointerDataType.dataType) == null) {
|
|
||||||
break; // stop early if failed to create a pointer
|
|
||||||
}
|
|
||||||
addr = addr.addNoWrap(PLT_ENTRY_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (AddressOverflowException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processOPDSection(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
private void processOPDSection(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
MemoryBlock opdBlock = elfLoadHelper.getProgram().getMemory().getBlock(".opd");
|
boolean makeSymbol = false;
|
||||||
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
Memory mem = program.getMemory();
|
||||||
|
MemoryBlock opdBlock = mem.getBlock(OPD_SECTION_NAME);
|
||||||
if (opdBlock == null) {
|
if (opdBlock == null) {
|
||||||
|
|
||||||
|
// Handle case where section names have been stripped - find .opd section
|
||||||
|
ElfHeader elf = elfLoadHelper.getElfHeader();
|
||||||
|
if (elf.getSectionHeaderCount() == 0 || !(elf.isExecutable() || elf.isSharedObject())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine entry address which should point into .opd block
|
||||||
|
long entry = elf.e_entry();
|
||||||
|
if (entry == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AddressFactory addrFactory = program.getAddressFactory();
|
||||||
|
entry += elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||||
|
Address entryAddress =
|
||||||
|
addrFactory.getDefaultAddressSpace().getTruncatedAddress(entry, true);
|
||||||
|
opdBlock = mem.getBlock(entryAddress);
|
||||||
|
makeSymbol = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opdBlock == null || !opdBlock.isInitialized() || opdBlock.isExecute()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (makeSymbol) {
|
||||||
|
try {
|
||||||
|
// Create .opd symbol if section lacked this name
|
||||||
|
elfLoadHelper.createSymbol(opdBlock.getStart(), OPD_SECTION_NAME, false, false,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
catch (InvalidInputException e) {
|
||||||
|
// ignore - unexpected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
monitor.setMessage("Processing Function Descriptor Symbols...");
|
monitor.setMessage("Processing Function Descriptor Symbols...");
|
||||||
|
|
||||||
Address addr = opdBlock.getStart();
|
Address addr = opdBlock.getStart();
|
||||||
Address endAddr = opdBlock.getEnd();
|
Address endAddr = opdBlock.getEnd();
|
||||||
|
|
||||||
monitor.setShowProgressValue(true);
|
|
||||||
monitor.setProgress(0);
|
|
||||||
monitor.setMaximum((endAddr.subtract(addr) + 1) / 24);
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
int pointerByteSize = program.getDefaultPointerSize();
|
||||||
|
boolean hasThreePointerFnDescriptor =
|
||||||
|
hasELFv1ThreePointerFnDescriptor(addr, pointerByteSize == 4, mem, true);
|
||||||
|
int fnDescriptorSize = hasThreePointerFnDescriptor ? 3 : 2;
|
||||||
|
int opdEntryByteSize = fnDescriptorSize * pointerByteSize;
|
||||||
|
|
||||||
|
rememberELFv1FunctionDescriptorSize(elfLoadHelper, hasThreePointerFnDescriptor); // remember as equate
|
||||||
|
|
||||||
|
monitor.setShowProgressValue(true);
|
||||||
|
monitor.setProgress(0);
|
||||||
|
monitor.setMaximum((endAddr.subtract(addr) + 1) / opdEntryByteSize);
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
while (addr.compareTo(endAddr) < 0) {
|
while (addr.compareTo(endAddr) < 0) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
monitor.setProgress(++count);
|
monitor.setProgress(++count);
|
||||||
processOPDEntry(elfLoadHelper, addr);
|
processOPDEntry(elfLoadHelper, addr, hasThreePointerFnDescriptor);
|
||||||
addr = addr.addNoWrap(24);
|
addr = addr.addNoWrap(opdEntryByteSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (AddressOverflowException e) {
|
catch (MemoryAccessException | AddressOverflowException e) {
|
||||||
// ignore end of space
|
// ignore end of space or failure to detect descriptor size
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow .opd section contents to be treated as constant values
|
// allow .opd section contents to be treated as constant values
|
||||||
opdBlock.setWrite(false);
|
opdBlock.setWrite(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processOPDEntry(ElfLoadHelper elfLoadHelper, Address opdAddr) {
|
private long getUnsignedValue(Address addr, boolean uses32bitPtr, Memory mem)
|
||||||
|
throws MemoryAccessException {
|
||||||
|
return uses32bitPtr ? Integer.toUnsignedLong(mem.getInt(addr)) : mem.getLong(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processOPDEntry(ElfLoadHelper elfLoadHelper, Address opdAddr,
|
||||||
|
boolean fnDescriptorHasEnvPtr) {
|
||||||
|
|
||||||
Program program = elfLoadHelper.getProgram();
|
Program program = elfLoadHelper.getProgram();
|
||||||
SymbolTable symbolTable = program.getSymbolTable();
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
|
||||||
boolean isGlobal = symbolTable.isExternalEntryPoint(opdAddr);
|
boolean isGlobal = symbolTable.isExternalEntryPoint(opdAddr);
|
||||||
|
|
||||||
Symbol refSymbol = markupDescriptorEntry(opdAddr, isGlobal, elfLoadHelper);
|
Symbol refSymbol =
|
||||||
|
markupDescriptorEntry(opdAddr, isGlobal, fnDescriptorHasEnvPtr, elfLoadHelper);
|
||||||
if (refSymbol == null) {
|
if (refSymbol == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -334,7 +553,8 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
refSymbol.getSource() == SourceType.DEFAULT) {
|
refSymbol.getSource() == SourceType.DEFAULT) {
|
||||||
try {
|
try {
|
||||||
// Force source type on function to prevent potential removal by clear-flow
|
// Force source type on function to prevent potential removal by clear-flow
|
||||||
refSymbol.setName(".opd." + refSymbol.getName(), SourceType.IMPORTED);
|
refSymbol.setName(OPD_SECTION_NAME + "." + refSymbol.getName(),
|
||||||
|
SourceType.IMPORTED);
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException | InvalidInputException e) {
|
catch (DuplicateNameException | InvalidInputException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -365,24 +585,35 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol markupDescriptorEntry(Address entryAddr, boolean isGlobal,
|
private Symbol markupDescriptorEntry(Address entryAddr, boolean isGlobal,
|
||||||
ElfLoadHelper elfLoadHelper) {
|
boolean hasThreePointerFnDescriptor, ElfLoadHelper elfLoadHelper) {
|
||||||
Program program = elfLoadHelper.getProgram();
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
|
||||||
// markup function descriptor (3 elements, 24-bytes)
|
// markup function descriptor (two or three pointers)
|
||||||
Data refPtr = elfLoadHelper.createData(entryAddr, PointerDataType.dataType);
|
Data refPtr = elfLoadHelper.createData(entryAddr, PointerDataType.dataType); // function *
|
||||||
Data tocPtr = elfLoadHelper.createData(entryAddr.add(program.getDefaultPointerSize()),
|
Data tocPtr = elfLoadHelper.createData(entryAddr.add(program.getDefaultPointerSize()),
|
||||||
PointerDataType.dataType);
|
PointerDataType.dataType); // toc *
|
||||||
// TODO: uncertain what 3rd procedure descriptor element represents
|
|
||||||
elfLoadHelper.createData(entryAddr.add(2 * program.getDefaultPointerSize()),
|
|
||||||
QWordDataType.dataType);
|
|
||||||
|
|
||||||
if (refPtr == null || tocPtr == null) {
|
if (refPtr == null || tocPtr == null) {
|
||||||
Msg.error(this, "Failed to process PPC64 descriptor at " + entryAddr);
|
Msg.error(this, "Failed to process PPC64 function descriptor at " + entryAddr);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME! How do we determine if an env* is present - descriptor may only have two pointers
|
||||||
|
// instead of three.
|
||||||
|
|
||||||
|
if (hasThreePointerFnDescriptor) {
|
||||||
|
elfLoadHelper.createData(entryAddr.add(2 * program.getDefaultPointerSize()),
|
||||||
|
PointerDataType.dataType); // env *
|
||||||
|
}
|
||||||
|
|
||||||
Address refAddr = (Address) refPtr.getValue();
|
Address refAddr = (Address) refPtr.getValue();
|
||||||
if (refAddr == null || program.getMemory().getBlock(refAddr) == null) {
|
if (refAddr == null || refAddr.getOffset() == 0 ||
|
||||||
|
program.getMemory().getBlock(refAddr) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address tocAddr = (Address) tocPtr.getValue();
|
||||||
|
if (tocAddr == null || tocAddr.getOffset() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,17 +634,15 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set r2 to TOC base for each function
|
// set r2 to TOC base for each function
|
||||||
Address tocAddr = (Address) tocPtr.getValue();
|
Register r2reg = program.getRegister("r2");
|
||||||
if (tocAddr != null) {
|
RegisterValue tocValue = new RegisterValue(r2reg, tocAddr.getOffsetAsBigInteger());
|
||||||
Register r2reg = program.getRegister("r2");
|
try {
|
||||||
RegisterValue tocValue = new RegisterValue(r2reg, tocAddr.getOffsetAsBigInteger());
|
program.getProgramContext().setRegisterValue(refAddr, refAddr, tocValue);
|
||||||
try {
|
|
||||||
program.getProgramContext().setRegisterValue(refAddr, refAddr, tocValue);
|
|
||||||
}
|
|
||||||
catch (ContextChangeException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (ContextChangeException e) {
|
||||||
|
throw new AssertException(e);
|
||||||
|
}
|
||||||
|
|
||||||
return function.getSymbol();
|
return function.getSymbol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,7 +669,7 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
Program program = elfLoadHelper.getProgram();
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
|
||||||
if (getPpc64ABIVersion(elfLoadHelper.getElfHeader()) == 2) {
|
if (getPpc64ElfABIVersion(elfLoadHelper.getElfHeader()) == 2) {
|
||||||
|
|
||||||
monitor.setMessage("Assuming r12 for global functions...");
|
monitor.setMessage("Assuming r12 for global functions...");
|
||||||
|
|
||||||
|
@ -476,11 +705,11 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
// Check for V2 ABI
|
// Check for V2 ABI
|
||||||
if (isExternal || elfSymbol.getType() != ElfSymbol.STT_FUNC ||
|
if (isExternal || elfSymbol.getType() != ElfSymbol.STT_FUNC ||
|
||||||
getPpc64ABIVersion(elfHeader) != 2) {
|
getPpc64ElfABIVersion(elfHeader) != 2) {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: I don't think the ABI supports little-endian
|
// NOTE: I don't think the ELFv1 ABI supports little-endian
|
||||||
Language language = elfLoadHelper.getProgram().getLanguage();
|
Language language = elfLoadHelper.getProgram().getLanguage();
|
||||||
if (!canHandle(elfLoadHelper) || elfHeader.e_machine() != ElfConstants.EM_PPC64 ||
|
if (!canHandle(elfLoadHelper) || elfHeader.e_machine() != ElfConstants.EM_PPC64 ||
|
||||||
language.getLanguageDescription().getSize() != 64) {
|
language.getLanguageDescription().getSize() != 64) {
|
||||||
|
@ -530,22 +759,22 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the PPC64 ABI version specified within the ELF header.
|
* Get the PPC64 ELF ABI version specified within the ELF header.
|
||||||
* Expected values include:
|
* Expected values include:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> 1 for original function descriptor using ABI </li>
|
* <li> 1 for original function descriptor use (i.e., .opd) </li>
|
||||||
* <li> 2 for revised ABI without function descriptors </li>
|
* <li> 2 for revised ABI without function descriptors </li>
|
||||||
* <li> 0 for unspecified or not using any features affected by the differences </li>
|
* <li> 0 for unspecified or not using any features affected by the differences (ELFv1 assumed)</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* @param elf ELF header
|
* @param elf ELF header
|
||||||
* @return ABI version
|
* @return ELF ABI version
|
||||||
*/
|
*/
|
||||||
public static int getPpc64ABIVersion(ElfHeader elf) {
|
public static int getPpc64ElfABIVersion(ElfHeader elf) {
|
||||||
if (elf.e_machine() != ElfConstants.EM_PPC64) {
|
if (elf.e_machine() != ElfConstants.EM_PPC64) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elf.getSection(".opd") != null) {
|
if (elf.getSection(OPD_SECTION_NAME) != null) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import ghidra.program.model.reloc.Relocation.Status;
|
||||||
import ghidra.program.model.reloc.RelocationResult;
|
import ghidra.program.model.reloc.RelocationResult;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolUtilities;
|
import ghidra.program.model.symbol.SymbolUtilities;
|
||||||
import ghidra.util.*;
|
|
||||||
|
|
||||||
public class PowerPC64_ElfRelocationHandler
|
public class PowerPC64_ElfRelocationHandler
|
||||||
extends AbstractElfRelocationHandler<PowerPC64_ElfRelocationType, ElfRelocationContext<?>> {
|
extends AbstractElfRelocationHandler<PowerPC64_ElfRelocationType, ElfRelocationContext<?>> {
|
||||||
|
@ -46,7 +45,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canRelocate(ElfHeader elf) {
|
public boolean canRelocate(ElfHeader elf) {
|
||||||
return elf.e_machine() == ElfConstants.EM_PPC64 && elf.is64Bit();
|
return elf.e_machine() == ElfConstants.EM_PPC64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,7 +61,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||||
|
|
||||||
Program program = elfRelocationContext.getProgram();
|
Program program = elfRelocationContext.getProgram();
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
|
|
||||||
// NOTE: Based upon glibc source it appears that PowerPC only uses RELA relocations
|
// NOTE: Based upon glibc source it appears that PowerPC only uses RELA relocations
|
||||||
long addend = relocation.getAddend();
|
long addend = relocation.getAddend();
|
||||||
long offset = relocationAddress.getOffset();
|
long offset = relocationAddress.getOffset();
|
||||||
|
@ -98,7 +97,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle relative relocations that do not require symbolAddr or symbolValue
|
// Handle relative relocations that do not require symbolAddr or symbolValue
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
|
@ -106,32 +105,32 @@ public class PowerPC64_ElfRelocationHandler
|
||||||
long value64 = elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
|
long value64 = elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
|
||||||
memory.setLong(relocationAddress, value64);
|
memory.setLong(relocationAddress, value64);
|
||||||
return new RelocationResult(Status.APPLIED, 8);
|
return new RelocationResult(Status.APPLIED, 8);
|
||||||
|
|
||||||
case R_PPC64_TOC:
|
case R_PPC64_TOC:
|
||||||
memory.setLong(relocationAddress, toc);
|
memory.setLong(relocationAddress, toc);
|
||||||
return new RelocationResult(Status.APPLIED, 8);
|
return new RelocationResult(Status.APPLIED, 8);
|
||||||
|
|
||||||
case R_PPC64_COPY:
|
case R_PPC64_COPY:
|
||||||
markAsUnsupportedCopy(program, relocationAddress, type, symbolName, symbolIndex,
|
markAsUnsupportedCopy(program, relocationAddress, type, symbolName, symbolIndex,
|
||||||
sym.getSize(), elfRelocationContext.getLog());
|
sym.getSize(), elfRelocationContext.getLog());
|
||||||
return RelocationResult.UNSUPPORTED;
|
return RelocationResult.UNSUPPORTED;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
|
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
|
||||||
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
|
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
|
||||||
return RelocationResult.FAILURE;
|
return RelocationResult.FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int oldValue = memory.getInt(relocationAddress);
|
int oldValue = memory.getInt(relocationAddress);
|
||||||
int newValue = 0;
|
int newValue = 0;
|
||||||
|
|
||||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
case R_PPC64_ADDR32:
|
case R_PPC64_ADDR32:
|
||||||
newValue = (int) (symbolValue + addend);
|
newValue = (int) (symbolValue + addend);
|
||||||
memory.setInt(relocationAddress, newValue);
|
memory.setInt(relocationAddress, newValue);
|
||||||
|
@ -194,10 +193,6 @@ public class PowerPC64_ElfRelocationHandler
|
||||||
memory.setInt(relocationAddress, newValue);
|
memory.setInt(relocationAddress, newValue);
|
||||||
break;
|
break;
|
||||||
case R_PPC64_REL24:
|
case R_PPC64_REL24:
|
||||||
|
|
||||||
// attempt to handle Object module case where referenced symbol resides within .opd
|
|
||||||
symbolValue = fixupOPDSymbolValue(elfRelocationContext, sym);
|
|
||||||
|
|
||||||
newValue = (int) ((symbolValue + addend - offset) >> 2);
|
newValue = (int) ((symbolValue + addend - offset) >> 2);
|
||||||
newValue = ((newValue << 2) & PPC64_LOW24);
|
newValue = ((newValue << 2) & PPC64_LOW24);
|
||||||
newValue = (oldValue & ~PPC64_LOW24) | newValue;
|
newValue = (oldValue & ~PPC64_LOW24) | newValue;
|
||||||
|
@ -230,7 +225,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PowerPC64_ElfExtension
|
if (PowerPC64_ElfExtension
|
||||||
.getPpc64ABIVersion(elfRelocationContext.getElfHeader()) == 1) {
|
.getPpc64ElfABIVersion(elfRelocationContext.getElfHeader()) == 1) {
|
||||||
// ABI ELFv1 (used by big-endian PPC64) expected to copy full function descriptor
|
// ABI ELFv1 (used by big-endian PPC64) expected to copy full function descriptor
|
||||||
// into .got.plt section where symbolAddr refers to function descriptor
|
// into .got.plt section where symbolAddr refers to function descriptor
|
||||||
// Copy function descriptor data
|
// Copy function descriptor data
|
||||||
|
@ -273,38 +268,4 @@ public class PowerPC64_ElfRelocationHandler
|
||||||
return new RelocationResult(Status.APPLIED, byteLength);
|
return new RelocationResult(Status.APPLIED, byteLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method generates a symbol value with possible substitution for those
|
|
||||||
* symbols residing within the .opd to refer to the real function instead.
|
|
||||||
* Care must be taken not to invoke this method for relocations which may be
|
|
||||||
* applied to call stubs. It is also important that relocations have already
|
|
||||||
* been applied to the .opd section since we will be using its data for
|
|
||||||
* locating the real function.
|
|
||||||
* @param elfRelocationContext ELF relocation context
|
|
||||||
* @param sym ELF relocation symbol
|
|
||||||
* @return symbol value
|
|
||||||
* @throws MemoryAccessException if memory access error occurs
|
|
||||||
*/
|
|
||||||
private long fixupOPDSymbolValue(ElfRelocationContext<?> elfRelocationContext, ElfSymbol sym)
|
|
||||||
throws MemoryAccessException {
|
|
||||||
Address addr = elfRelocationContext.getSymbolAddress(sym);
|
|
||||||
if (addr == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Program program = elfRelocationContext.getProgram();
|
|
||||||
MemoryBlock block = program.getMemory().getBlock(addr);
|
|
||||||
if (block == null || !".opd".equals(block.getName())) {
|
|
||||||
return addr.getOffset();
|
|
||||||
}
|
|
||||||
// .opd symbols will get moved to the real function by the extension (see processFunctionDescriptors)
|
|
||||||
// Call stubs should always use the .opd symbol value and not the function address so we can - this
|
|
||||||
// distinction can only be made using the relocation type.
|
|
||||||
byte[] bytes = new byte[8];
|
|
||||||
block.getBytes(addr, bytes);
|
|
||||||
boolean bigEndian = elfRelocationContext.getElfHeader().isBigEndian();
|
|
||||||
DataConverter dataConverter =
|
|
||||||
bigEndian ? BigEndianDataConverter.INSTANCE : LittleEndianDataConverter.INSTANCE;
|
|
||||||
return dataConverter.getLong(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue