GP-4743 - PDB - Developer stream and offset locator for file offset

This commit is contained in:
ghizard 2024-07-03 12:43:22 +00:00
parent d58923419c
commit 8a62ed795f
4 changed files with 94 additions and 8 deletions

View File

@ -20,8 +20,7 @@ import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.Msf;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
import ghidra.app.util.datatype.microsoft.GUID;
@ -469,6 +468,35 @@ public abstract class AbstractPdb implements AutoCloseable {
return msf.getMonitor();
}
/**
* Developer mechanism to locate stream and offset within that stream that is associated with
* the given absolute file offset
* @param fileOffset the absolute file offset that we are trying to locate
* @return the stream and offset or {@code null} if not located
*/
public StreamAndOffset getStreamOffsetForAbsoluteFileOffset(long fileOffset) {
if (msf instanceof AbstractMsf myMsf) {
return myMsf.getStreamOffsetForAbsoluteFileOffset(fileOffset);
}
return null;
}
/**
* Developer mechanism to get a {@code PdbByteReader} for the particular stream, offset, and
* length.
* @param streamNumber the stream number
* @param offset the offset in the stream
* @param length the number of bytes to include from the stream
* @return the reader
* @throws CancelledException upon user cancellation
* @throws IOException upon issue getting the stream for the PDB
*/
public PdbByteReader getDeveloperBytes(int streamNumber, int offset, int length)
throws CancelledException, IOException {
PdbByteReader reader = getReaderForStreamNumber(streamNumber, offset, length);
return reader;
}
/**
* Check to see if this monitor has been canceled
* @throws CancelledException if monitor has been cancelled

View File

@ -238,6 +238,26 @@ public abstract class AbstractMsf implements Msf {
}
}
/**
* Developer mechanism to locate stream and offset within the stream that contains the
* absolute file offset
* @param fileOffset the absolute file offset that we are trying to locate
* @return the offset in the stream of the file offset or {@code null} if not in the stream
*/
public StreamAndOffset getStreamOffsetForAbsoluteFileOffset(long fileOffset) {
if (fileOffset < 0L || fileOffset > (long) numPages * pageSize) {
return null;
}
for (int number = 0; number < streamTable.getNumStreams(); number++) {
MsfStream s = getStream(number);
Integer offset = s.getStreamOffsetForAbsoluteFileOffset(fileOffset);
if (offset != null) {
return new StreamAndOffset(number, offset);
}
}
return null;
}
//==============================================================================================
// Class Internals
//==============================================================================================

View File

@ -72,8 +72,7 @@ public class MsfStream {
* inability to read required bytes
* @throws CancelledException upon user cancellation
*/
public byte[] read(int streamOffset, int numToRead)
throws IOException, CancelledException {
public byte[] read(int streamOffset, int numToRead) throws IOException, CancelledException {
if (numToRead <= 0) {
return null;
}
@ -231,12 +230,10 @@ public class MsfStream {
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/
void deserializePageNumbers(PdbByteReader reader)
throws PdbException, CancelledException {
void deserializePageNumbers(PdbByteReader reader) throws PdbException, CancelledException {
// This calculations works fine for streamLength = 0
// and even streamLength = -1 (0xffffffff).
int numPages =
Msf.floorDivisionWithLog2Divisor(streamLength, msf.getLog2PageSize());
int numPages = Msf.floorDivisionWithLog2Divisor(streamLength, msf.getLog2PageSize());
if (msf.getPageNumberSize() == 2) {
for (int i = 0; i < numPages; i++) {
msf.checkCancelled();
@ -276,4 +273,27 @@ public class MsfStream {
deserializePageNumbers(reader);
}
/**
* Developer mechanism to see if the stream hold the absolute file offset and what the
* corresponding stream offset is
* @param fileOffset the absolute file offset that we are trying to locate
* @return the offset in the stream of the file offset or {@code null} if not in the stream
*/
Integer getStreamOffsetForAbsoluteFileOffset(long fileOffset) {
long pageSize = msf.getPageSize();
for (int pageCount = 0; pageCount < pageList.size(); pageCount++) {
int page = pageList.get(pageCount);
long pageStart = page * pageSize;
long pageEndExclusive = pageStart + pageSize;
if (pageStart <= fileOffset && fileOffset < pageEndExclusive) {
// We must get the offset within page, but then must use the pageCount to determine
// the rest of the streamOffset
Long pageOffset = fileOffset - pageStart;
Long streamOffset = pageCount * pageSize + pageOffset;
return streamOffset.intValue();
}
}
return null;
}
}

View File

@ -0,0 +1,18 @@
/* ###
* 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.pdb2.pdbreader.msf;
public record StreamAndOffset(int number, int offset) {}