mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 02:59:00 +08: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:
+9
@@ -216,9 +216,13 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand<Program> {
|
||||
monitor.checkCancelled();
|
||||
Symbol[] syms = symTable.getSymbols(addr);
|
||||
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) {
|
||||
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()) {
|
||||
continue;
|
||||
}
|
||||
@@ -718,6 +722,11 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand<Program> {
|
||||
if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
|
||||
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)) {
|
||||
|
||||
+14
-22
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -167,8 +167,7 @@ public class ElfDefaultGotPltMarkup {
|
||||
// PLT head is unknown. If the binary has not placed external symbols within the PLT
|
||||
// processing and disassembly of the PLT may be skipped.
|
||||
|
||||
long pltgot = elf.adjustAddressForPrelink(
|
||||
dynamicTable.getDynamicValue(pltGotType));
|
||||
long pltgot = elf.adjustAddressForPrelink(dynamicTable.getDynamicValue(pltGotType));
|
||||
Address gotStart = defaultSpace.getAddress(pltgot + imageBaseAdj);
|
||||
|
||||
ElfRelocation[] relocations = relocationTable.getRelocations();
|
||||
@@ -354,7 +353,7 @@ public class ElfDefaultGotPltMarkup {
|
||||
* Mark-up all GOT entries as pointers within the memory range gotStart to
|
||||
* gotEnd.
|
||||
* @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
|
||||
* @throws CancelledException thrown if task cancelled
|
||||
*/
|
||||
@@ -402,21 +401,17 @@ public class ElfDefaultGotPltMarkup {
|
||||
|
||||
try {
|
||||
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
|
||||
long gotSizeRemaining = gotEnd.subtract(gotStart) + 1;
|
||||
long entryOffset = 0;
|
||||
Address newImageBase = null;
|
||||
Address nextGotAddr = gotStart;
|
||||
while (gotEnd.subtract(nextGotAddr) >= pointerSize) {
|
||||
|
||||
while (gotSizeRemaining >= pointerSize) {
|
||||
Address nextGotAddr = gotStart.addNoWrap(entryOffset);
|
||||
data = createPointer(nextGotAddr, true);
|
||||
if (data == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
nextGotAddr = data.getMaxAddress().add(1);
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
break; // no more room
|
||||
}
|
||||
gotSizeRemaining -= pointerSize;
|
||||
entryOffset += pointerSize;
|
||||
newImageBase = UglyImageBaseCheck(data, newImageBase);
|
||||
}
|
||||
if (newImageBase != null) {
|
||||
@@ -573,12 +568,6 @@ public class ElfDefaultGotPltMarkup {
|
||||
}
|
||||
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
|
||||
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);
|
||||
if (data == null || !pointer.isEquivalent(data.getDataType())) {
|
||||
if (data != null) {
|
||||
@@ -623,7 +612,10 @@ public class ElfDefaultGotPltMarkup {
|
||||
Program program = pointerData.getProgram();
|
||||
Memory memory = program.getMemory();
|
||||
Address refAddr = (Address) pointerData.getValue();
|
||||
if (memory.contains(refAddr)) {
|
||||
if (refAddr == null) {
|
||||
return false;
|
||||
}
|
||||
else if (memory.contains(refAddr)) {
|
||||
return true;
|
||||
}
|
||||
Symbol primary = program.getSymbolTable().getPrimarySymbol(refAddr);
|
||||
|
||||
+5
@@ -20,6 +20,8 @@ import static ghidra.program.util.FunctionChangeRecord.FunctionChangeType.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
@@ -140,6 +142,9 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||
|
||||
@Override
|
||||
public void setThunkedFunction(Function referencedFunction) {
|
||||
if (isExternal()) {
|
||||
throw new UnsupportedOperationException("External functions may not be a thunk");
|
||||
}
|
||||
if ((referencedFunction != null) && !(referencedFunction instanceof FunctionDB)) {
|
||||
throw new IllegalArgumentException("FunctionDB expected for referenced function");
|
||||
}
|
||||
|
||||
+1
@@ -702,6 +702,7 @@ public interface Function extends Namespace {
|
||||
* @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
|
||||
* 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;
|
||||
|
||||
|
||||
+4
-2
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -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.
|
||||
* @throws OverlappingFunctionException if the address set of the body overlaps an existing
|
||||
* function
|
||||
* @throws UnsupportedOperationException if this method is invoked on an external entryPoint
|
||||
* address.
|
||||
*/
|
||||
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||
AddressSetView body, Function thunkedFunction, SourceType source)
|
||||
|
||||
+331
-102
File diff suppressed because it is too large
Load Diff
+11
-50
@@ -25,7 +25,6 @@ import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.*;
|
||||
|
||||
public class PowerPC64_ElfRelocationHandler
|
||||
extends AbstractElfRelocationHandler<PowerPC64_ElfRelocationType, ElfRelocationContext<?>> {
|
||||
@@ -46,7 +45,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||
|
||||
@Override
|
||||
public boolean canRelocate(ElfHeader elf) {
|
||||
return elf.e_machine() == ElfConstants.EM_PPC64 && elf.is64Bit();
|
||||
return elf.e_machine() == ElfConstants.EM_PPC64;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +61,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
Memory memory = program.getMemory();
|
||||
|
||||
|
||||
// NOTE: Based upon glibc source it appears that PowerPC only uses RELA relocations
|
||||
long addend = relocation.getAddend();
|
||||
long offset = relocationAddress.getOffset();
|
||||
@@ -98,7 +97,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
|
||||
// Handle relative relocations that do not require symbolAddr or symbolValue
|
||||
switch (type) {
|
||||
|
||||
@@ -106,32 +105,32 @@ public class PowerPC64_ElfRelocationHandler
|
||||
long value64 = elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
|
||||
memory.setLong(relocationAddress, value64);
|
||||
return new RelocationResult(Status.APPLIED, 8);
|
||||
|
||||
|
||||
case R_PPC64_TOC:
|
||||
memory.setLong(relocationAddress, toc);
|
||||
return new RelocationResult(Status.APPLIED, 8);
|
||||
|
||||
|
||||
case R_PPC64_COPY:
|
||||
markAsUnsupportedCopy(program, relocationAddress, type, symbolName, symbolIndex,
|
||||
sym.getSize(), elfRelocationContext.getLog());
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
|
||||
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
int oldValue = memory.getInt(relocationAddress);
|
||||
int newValue = 0;
|
||||
|
||||
|
||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||
|
||||
switch (type) {
|
||||
|
||||
|
||||
case R_PPC64_ADDR32:
|
||||
newValue = (int) (symbolValue + addend);
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
@@ -194,10 +193,6 @@ public class PowerPC64_ElfRelocationHandler
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
break;
|
||||
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 = ((newValue << 2) & PPC64_LOW24);
|
||||
newValue = (oldValue & ~PPC64_LOW24) | newValue;
|
||||
@@ -230,7 +225,7 @@ public class PowerPC64_ElfRelocationHandler
|
||||
}
|
||||
|
||||
if (PowerPC64_ElfExtension
|
||||
.getPpc64ABIVersion(elfRelocationContext.getElfHeader()) == 1) {
|
||||
.getPpc64ElfABIVersion(elfRelocationContext.getElfHeader()) == 1) {
|
||||
// ABI ELFv1 (used by big-endian PPC64) expected to copy full function descriptor
|
||||
// into .got.plt section where symbolAddr refers to function descriptor
|
||||
// Copy function descriptor data
|
||||
@@ -273,38 +268,4 @@ public class PowerPC64_ElfRelocationHandler
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user