Fixed tests failing to recent Version Tracking updates. Added a

priority to Version Tracking address correlators.
This commit is contained in:
dragonmacher 2024-07-23 18:01:38 -04:00
parent 220d6d9f58
commit 0fbd23653d
24 changed files with 488 additions and 293 deletions

View file

@ -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.
@ -16,7 +16,6 @@
package ghidra.program.util;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -31,19 +30,20 @@ public interface AddressCorrelation {
* Returns the AddressRange of a set of addresses in the destination
* program that correlates to corresponding range in the source program.
*
* @param sourceAddress
* the source program address
* @param sourceAddress the source program address
* @param monitor the task monitor
* @return the destination program address range, or null if the source program address maps
* to one that is "deleted" in the destination program
* @return the destination program address range, or null if there is not address range mapped
* @throws CancelledException if cancelled
*/
public AddressRange getCorrelatedDestinationRange(Address sourceAddress, TaskMonitor monitor)
throws CancelledException;
public AddressCorrelationRange getCorrelatedDestinationRange(Address sourceAddress,
TaskMonitor monitor) throws CancelledException;
/**
* Returns the name of the correlating algorithm.
* @return the name of the correlating algorithm.
* This method is no longer part of the API. Leaving a default implementation to reduce
* breaking clients.
* @return the simple class name of the implementing class
*/
public String getName();
public default String getName() {
return getClass().getSimpleName();
}
}

View file

@ -0,0 +1,48 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.util;
import java.util.Objects;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
/**
* A simple object that holds an {@link AddressCorrelation} address range and then name of the
* correlation.s
*/
public class AddressCorrelationRange {
private AddressRange range;
private String correlatorName;
public AddressCorrelationRange(AddressRange range, String correlatorName) {
this.range = Objects.requireNonNull(range);
this.correlatorName = Objects.requireNonNull(correlatorName);
}
public Address getMinAddress() {
return range.getMinAddress();
}
public AddressRange getRange() {
return range;
}
public String getCorrelatorName() {
return correlatorName;
}
}

View file

@ -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.
@ -23,9 +23,34 @@ import ghidra.program.model.listing.Function;
/**
* Interface for address correlation algorithms that can generate an address mapping from one
* set of program addresses to another.
* <p>
* This interface supplies a {@link #getPriority() priority} of {@link #DEFAULT_PRIORITY}.
* {@link DiscoverableAddressCorrelator discoverable} correlators can change this priority to be a
* lower value to be run before the supplied system correlators. Generally, the more specific or
* restrictive a correlator, the earlier (higher priority) it should be.
*/
public interface AddressCorrelator {
/**
* The default priority. This applies to client-supplied {@link DiscoverableAddressCorrelator}s
*/
public static final int DEFAULT_PRIORITY = 500;
/**
* A high priority (low number value) for correlators that should used before other correlators
*/
public static final int EARLY_PRIORITY = 100;
/**
* A low priority (high number value) for correlators that should used after other correlators
*/
public static final int LATE_CHANCE_PRIORITY = 1000;
/**
* A value used to raise or lower priorities.
*/
public static final int PRIORITY_OFFSET = 10;
/**
* Returns an address mapping from one function to another.
* @param sourceFunction the source function.
@ -61,4 +86,18 @@ public interface AddressCorrelator {
* @return the options with the default settings for this correlator.
*/
public Options getDefaultOptions();
/**
* Returns a number based on an arbitrary number scheme that dictates the order that correlators
* should be used. If a correlator returns a null value from one of the {@code correlate()}
* methods, then the next highest priority correlator will be called, and so on until a non-null
* correlation is found or all correlators have been called.
* <p>
* A lower number value is a higher priority. See {@link #DEFAULT_PRIORITY}.
*
* @return the priority
*/
public default int getPriority() {
return DEFAULT_PRIORITY;
}
}

View file

@ -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.
@ -15,7 +15,8 @@
*/
package ghidra.program.util;
import ghidra.program.model.address.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRangeImpl;
import ghidra.program.model.listing.Data;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -30,13 +31,14 @@ public class LinearDataAddressCorrelation implements AddressCorrelation {
}
@Override
public AddressRange getCorrelatedDestinationRange(Address sourceAddress, TaskMonitor monitor)
throws CancelledException {
public AddressCorrelationRange getCorrelatedDestinationRange(Address sourceAddress,
TaskMonitor monitor) throws CancelledException {
long offset = sourceAddress.getOffset();
long base = sourceData.getAddress().getOffset();
long delta = offset - base;
Address address = destinationData.getAddress().add(delta);
return new AddressRangeImpl(address, address);
AddressRangeImpl range = new AddressRangeImpl(address, address);
return new AddressCorrelationRange(range, getName());
}
@Override

View file

@ -0,0 +1,127 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.util;
import java.util.HashMap;
import java.util.Map;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class LinearFunctionAddressCorrelation implements AddressCorrelation {
public static final String NAME = "LinearFunctionAddressCorrelation";
private Map<Address, AddressRange> cachedForwardAddressMap;
private final Function sourceFunction;
private final Function destinationFunction;
public LinearFunctionAddressCorrelation(Function sourceFunction, Function destinationFunction) {
this.sourceFunction = sourceFunction;
this.destinationFunction = destinationFunction;
}
@Override
public String getName() {
return NAME;
}
@Override
public AddressCorrelationRange getCorrelatedDestinationRange(Address sourceAddress,
TaskMonitor monitor) throws CancelledException {
initialize(monitor);
AddressRange toRange = cachedForwardAddressMap.get(sourceAddress);
if (toRange == null) {
double percentOffset = findPercentageFromFunctionStart(sourceAddress);
Address destinationAddress = getDestinationAddress(percentOffset);
toRange = new AddressRangeImpl(destinationAddress, destinationAddress);
}
return new AddressCorrelationRange(toRange, getName());
}
private void initialize(TaskMonitor monitor) {
if (cachedForwardAddressMap == null) {
cachedForwardAddressMap = new HashMap<Address, AddressRange>();
computeParamCorrelation();
}
}
private double findPercentageFromFunctionStart(Address address) {
AddressSetView srcBody = sourceFunction.getBody();
long accumulatedLength = 0;
for (AddressRange range : srcBody) {
if (range.getMaxAddress().compareTo(address) < 0) {
accumulatedLength += range.getLength();
}
else {
if (range.contains(address)) {
accumulatedLength += address.subtract(range.getMinAddress());
}
break;
}
}
double percentOffset = (double) (accumulatedLength) / srcBody.getNumAddresses();
return percentOffset;
}
private Address getDestinationAddress(double percentOffset) {
AddressSetView srcBody = destinationFunction.getBody();
long offset = (long) (percentOffset * srcBody.getNumAddresses() + 0.5);
AddressRangeIterator addressRanges = srcBody.getAddressRanges();
while (addressRanges.hasNext()) {
AddressRange addressRange = addressRanges.next();
long rangeLength = addressRange.getLength();
if (offset < rangeLength) {
Address address = addressRange.getMinAddress().add(offset);
return address;
}
offset -= rangeLength;
}
return srcBody.getMaxAddress();
}
private void computeParamCorrelation() {
Parameter[] sourceParameters = sourceFunction.getParameters();
Parameter[] destinationParameters = destinationFunction.getParameters();
if (sourceParameters.length != destinationParameters.length) {
return;
}
Map<Address, AddressRange> map = new HashMap<Address, AddressRange>();
for (int i = 0; i < sourceParameters.length; i++) {
Parameter sourceParameter = sourceParameters[i];
Parameter destinationParameter = destinationParameters[i];
if (!sourceParameter.isValid() || !destinationParameter.isValid()) {
return;
}
VariableStorage sourceParamStorage = sourceParameter.getVariableStorage();
VariableStorage destParamStorage = destinationParameter.getVariableStorage();
if (!sourceParamStorage.equals(destParamStorage)) {
return;
}
Address dest = sourceParamStorage.getMinAddress();
Address src = destParamStorage.getMinAddress();
map.put(src, new AddressRangeImpl(dest, dest));
}
cachedForwardAddressMap.putAll(map);
}
}