Remove another redundant check for file offset < 0

Fixed four comments.
Changed location of call to containsFileOffset() from Memory.java toMemoryBlockSourceInfo.java.  Changed from print() to println() in thepython file.
GP-782: New API to support converting file offsets to memory addresses, with sample scripts that use it
This commit is contained in:
ghidra2 2021-06-03 10:16:57 -04:00
parent 70675fce99
commit 0ec17a9bb7
4 changed files with 218 additions and 10 deletions

View file

@ -0,0 +1,88 @@
/* ###
* 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.
*/
//This example script locates a memory address for a file offset.
//Prompt user for a file offset.
//Print the associated memory address to the Ghidra console
//Print the file offset as a Ghidra comment at the memory address in the Ghidra Listing
//If multiple addresses are located, then print the addresses to the console (do not set a
//Ghidra comment)
//@category Examples
import java.util.Set;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.mem.Memory;
import ghidra.util.exception.CancelledException;
public class LocateMemoryAddressesForFileOffset extends GhidraScript {
@Override
public void run() throws Exception {
long myFileOffset = getFileOffset();
Memory mem = currentProgram.getMemory();
Set<Address> addressSet = mem.locateAddressesForFileOffset(myFileOffset);
if (addressSet.isEmpty()) {
println("No memory address found for: " + Long.toHexString(myFileOffset));
}
else if (addressSet.size() == 1) {
Address address = addressSet.iterator().next();
processAddress(address, mem.getBlock(address).getName(), myFileOffset);
}
//address set size is > 1, file offset matches to multiple addresses.
//Let the user decide which address they want.
else {
println("Possible memory block:address are:");
for (Address addr : addressSet) {
println(mem.getBlock(addr).getName() + ":" + addr.toString());
}
}
}
public long getFileOffset()
throws CancelledException, NumberFormatException, IllegalArgumentException {
String userFileOffset =
askString("File offset", "Please provide a hexadecimal file offset");
long myFileOffset = 0;
myFileOffset = Long.parseLong(userFileOffset, 16);
if (myFileOffset < 0) {
throw new IllegalArgumentException(
"Offset cannot be a negative value." + userFileOffset);
}
return myFileOffset;
}
public void processAddress(Address addr, String memBlockName, long fileOffset) {
println("File offset " + Long.toHexString(fileOffset) +
" is associated with memory block:address " + memBlockName + ":" + addr.toString());
CodeUnit myCodeUnit = currentProgram.getListing().getCodeUnitContaining(addr);
String comment = myCodeUnit.getComment(0);
if (comment == null) {
myCodeUnit.setComment(0,
this.getScriptName() + ": File offset: " + Long.toHexString(fileOffset) +
", Memory block:address " + memBlockName + ":" + addr.toString());
}
else {
myCodeUnit.setComment(0,
comment + ", " + this.getScriptName() + ": File offset: " +
Long.toHexString(fileOffset) + ", Memory block:address " + memBlockName + ":" +
addr.toString());
}
}
}

View file

@ -0,0 +1,64 @@
## ###
# 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.
##
# This example script locates a memory address for a file offset.
#Prompt user for a file offset.
#Print the associated memory address to the Ghidra console
#Print the file offset as a Ghidra comment at the memory address in the Ghidra Listing
#If multiple addresses are located, then print the addresses to the console (do not set a Ghidra comment)
# @category Examples
import sys
from ghidra.program.model.address import Address
from ghidra.program.model.listing import CodeUnit
from ghidra.program.model.listing import Listing
from ghidra.program.model.mem import Memory
from java.util import Set
def getFileOffset():
userFileOffset = askString('File offset', 'Please provide a hexadecimal file offset')
try:
int(userFileOffset,16)
except ValueError:
raise ValueError('Please provide a hexadecimal file offset.')
myFileOffset = long(userFileOffset,16) #specify base 16 since we expect address in hex
if myFileOffset < 0:
raise ValueError('Offset cannot be a negative value.')
return myFileOffset
def processAddress(addr, memBlockName, fileOffset):
println('File offset ' + hex(fileOffset) + ' is associated with memory block:address ' + memBlockName + ':' + addr.toString());
myCodeUnit = currentProgram.getListing().getCodeUnitContaining(addr)
comment = myCodeUnit.getComment(0)
if not comment:
myCodeUnit.setComment(0, getScriptName() + ': File offset: ' + hex(fileOffset) +
', Memory block:address ' + memBlockName + ':'+ addr.toString())
else:
myCodeUnit.setComment(0, comment + ' ' + getScriptName() + ': File offset: ' + hex(fileOffset) +
', Memory block:address ' + memBlockName + ':' + addr.toString())
myFileOffset = getFileOffset()
mem = currentProgram.getMemory()
addressSet = mem.locateAddressesForFileOffset(myFileOffset)
if addressSet.isEmpty():
println('No memory address found for: ' + hex(myFileOffset))
elif addressSet.size() == 1:
address = addressSet.iterator().next()
processAddress(address, mem.getBlock(address).getName(), myFileOffset)
#file offset matches to multiple addresses. Let the user decide which address they want.
else:
println('Possible memory block:address are:')
for addr in addressSet:
println(mem.getBlock(addr).getName() + ":" + addr.toString())

View file

@ -17,7 +17,7 @@ package ghidra.program.model.mem;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.*;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.database.mem.*; import ghidra.program.database.mem.*;
@ -247,9 +247,8 @@ public interface Memory extends AddressSetView {
* @throws IllegalArgumentException if invalid block name * @throws IllegalArgumentException if invalid block name
*/ */
public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress, public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress,
long length, ByteMappingScheme byteMappingScheme, boolean overlay) long length, ByteMappingScheme byteMappingScheme, boolean overlay) throws LockException,
throws LockException, MemoryConflictException, AddressOverflowException, MemoryConflictException, AddressOverflowException, IllegalArgumentException;
IllegalArgumentException;
/** /**
* Create a memory block that uses the bytes located at a different location with a 1:1 * Create a memory block that uses the bytes located at a different location with a 1:1
@ -271,8 +270,7 @@ public interface Memory extends AddressSetView {
*/ */
default public MemoryBlock createByteMappedBlock(String name, Address start, default public MemoryBlock createByteMappedBlock(String name, Address start,
Address mappedAddress, long length, boolean overlay) throws LockException, Address mappedAddress, long length, boolean overlay) throws LockException,
MemoryConflictException, MemoryConflictException, AddressOverflowException, IllegalArgumentException {
AddressOverflowException, IllegalArgumentException {
return createByteMappedBlock(name, start, mappedAddress, length, null, overlay); return createByteMappedBlock(name, start, mappedAddress, length, null, overlay);
} }
@ -830,4 +828,23 @@ public interface Memory extends AddressSetView {
return true; return true;
} }
/**
* Gets a {@link Set} of {@link Address addresses} that correspond to the given file offset.
*
* @param fileOffset the file offset that will be used to locate the corresponding memory
* addresses
* @return a {@link Set} of {@link Address}es that are associated with the provided file offset
*/
public default Set<Address> locateAddressesForFileOffset(long fileOffset) {
Set<Address> set = new HashSet<>();
for (MemoryBlock memBlock : getBlocks()) {
for (MemoryBlockSourceInfo info : memBlock.getSourceInfos()) {
Address addr = info.locateAddressForFileOffset(fileOffset);
if (addr != null) {
set.add(addr);
}
}
}
return set;
}
} }

View file

@ -59,16 +59,17 @@ public interface MemoryBlockSourceInfo {
Optional<FileBytes> getFileBytes(); Optional<FileBytes> getFileBytes();
/** /**
* Returns the offset into the {@link FileBytes} object where this section starts getting its bytes or * Returns the offset into the underlying {@link FileBytes} object where this sub-block
* -1 if this SourceInfo does not have an associated {@link FileBytes} * starts getting its bytes from or -1 if this sub-block does not have an associated {@link FileBytes}
* or a complex bit/byte-mapping is used.
* @return the offset into the {@link FileBytes} object where this section starts getting its bytes. * @return the offset into the {@link FileBytes} object where this section starts getting its bytes.
*/ */
long getFileBytesOffset(); long getFileBytesOffset();
/** /**
* Returns the offset into the {@link FileBytes} object for the given address or * Returns the offset into the {@link FileBytes} object for the given address or
* -1 if this MemoryBlockSourceInfo does not have an associated {@link FileBytes} or the address doesn't * -1 if this sub-block if address is out of range or this sub-block does not have
* belong to this MemoryBlockSourceInfo. * an associated {@link FileBytes}, or a complex bit/byte-mapping is used.
* *
* @param address the address for which to get an offset into the {@link FileBytes} object. * @param address the address for which to get an offset into the {@link FileBytes} object.
* @return the offset into the {@link FileBytes} object for the given address. * @return the offset into the {@link FileBytes} object for the given address.
@ -103,4 +104,42 @@ public interface MemoryBlockSourceInfo {
*/ */
boolean contains(Address address); boolean contains(Address address);
/**
* Determine if this block source contains the specified file offset.
*
* @param fileOffset file offset within underlying FileBytes (if applicable) within the loaded
* range associated with this source info.
* @return true if file offset is within the loaded range of the corresponding FileBytes, else
* false if method is not supported by the sub-block type (e.g., bit/byte-mapped sub-block).
*/
default boolean containsFileOffset(long fileOffset) {
long startOffset = getFileBytesOffset();
if (startOffset < 0 || fileOffset < 0) {
return false;
}
// NOTE: logic does not handle bit/byte-mapped blocks (assumes 1:1 mapping)
long endOffset = startOffset + (getLength() - 1);
return (fileOffset >= startOffset) && (fileOffset <= endOffset);
}
/**
* Get the Address within this sub-block which corresponds to the specified file offset.
*
* @param fileOffset file offset
* @return {@link Address} within this sub-block or null if file offset is out of range
* or method is not supported by the sub-block type (e.g., bit/byte-mapped sub-block).
*/
default Address locateAddressForFileOffset(long fileOffset) {
long startOffset = getFileBytesOffset();
if (!containsFileOffset(fileOffset)) {
return null;
}
// NOTE: logic does not handle bit/byte-mapped blocks (assumes 1:1 mapping)
long offset = fileOffset - startOffset;
if (offset >= getLength()) {
return null;
}
return getMinAddress().add(offset);
}
} }