Merge remote-tracking branch 'origin/GP-3604_PDB_Remove_DisassembleCommand--SQUASHED'

This commit is contained in:
Ryan Kurtz 2023-08-09 11:34:13 -04:00
commit c3d10529f0
6 changed files with 212 additions and 159 deletions

View File

@ -22,9 +22,10 @@ import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.*;
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
@ -37,7 +38,9 @@ import ghidra.framework.options.Options;
import ghidra.graph.*;
import ghidra.graph.algo.GraphNavigator;
import ghidra.graph.jung.JungDirectedGraph;
import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
@ -163,6 +166,11 @@ public class DefaultPdbApplicator implements PdbApplicator {
private Map<String, Set<RecordNumber>> recordNumbersByFileName;
private Map<Integer, Set<RecordNumber>> recordNumbersByModuleNumber;
//==============================================================================================
// Addresses of locations of functions for disassembly/function-creation.
AddressSet disassembleAddresses;
List<DeferrableFunctionSymbolApplier> deferredFunctionWorkAppliers;
//==============================================================================================
public DefaultPdbApplicator(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null");
@ -213,6 +221,8 @@ public class DefaultPdbApplicator implements PdbApplicator {
}
if (program != null) {
doDeferredProgramProcessing();
// Mark PDB analysis as complete.
Options options = program.getOptions(Program.PROGRAM_INFO);
options.setBoolean(PdbParserConstants.PDB_LOADED, true);
}
@ -224,6 +234,57 @@ public class DefaultPdbApplicator implements PdbApplicator {
Msg.info(this, "PDB Terminated Normally");
}
//==============================================================================================
private void doDeferredProgramProcessing() throws CancelledException {
disassembleFunctions();
doDeferredFunctionProcessing();
}
//==============================================================================================
/**
* Set the context for each function, disassemble them, and then do fix-ups
*/
private void disassembleFunctions() throws CancelledException {
Listing listing = program.getListing();
DisassemblerContextImpl seedContext =
new DisassemblerContextImpl(program.getProgramContext());
AddressSet revisedSet = new AddressSet();
for (Address address : disassembleAddresses.getAddresses(true)) {
cancelOnlyWrappingMonitor.checkCancelled();
address = PseudoDisassembler.setTargetContextForDisassembly(seedContext, address);
Function myFunction = listing.getFunctionAt(address);
// If no function or not a full function, add it to set for disassembly.
if (myFunction == null || myFunction.getBody().getNumAddresses() <= 1) {
revisedSet.add(address);
}
}
// Do disassembly and ensure functions are created appropriately.
DisassembleCommand cmd = new DisassembleCommand(revisedSet, null, true);
cmd.setSeedContext(seedContext);
cmd.applyTo(program, cancelOnlyWrappingMonitor);
for (Address address : revisedSet.getAddresses(true)) {
cancelOnlyWrappingMonitor.checkCancelled();
Function function = listing.getFunctionAt(address);
if (function != null) {
CreateFunctionCmd.fixupFunctionBody(program, function, cancelOnlyWrappingMonitor);
}
}
}
//==============================================================================================
/**
* Do work, such as create parameters or local variables and scopes
* @throws CancelledException upon user cancellation
*/
private void doDeferredFunctionProcessing() throws CancelledException {
for (DeferrableFunctionSymbolApplier applier : deferredFunctionWorkAppliers) {
cancelOnlyWrappingMonitor.checkCancelled();
applier.doDeferredProcessing();
}
}
//==============================================================================================
private void processTypes() throws CancelledException, PdbException {
TaskMonitor monitor = getMonitor();
@ -359,6 +420,8 @@ public class DefaultPdbApplicator implements PdbApplicator {
symbolApplierParser = new SymbolApplierFactory(this);
if (program != null) {
disassembleAddresses = new AddressSet();
deferredFunctionWorkAppliers = new ArrayList<>();
// Currently, this must happen after symbolGroups are created.
PdbVbtManager pdbVbtManager = new PdbVbtManager(this);
//pdbVbtManager.CreateVirtualBaseTables(); // Depends on symbolGroups
@ -849,6 +912,42 @@ public class DefaultPdbApplicator implements PdbApplicator {
//==============================================================================================
//==============================================================================================
//==============================================================================================
//==============================================================================================
Function getExistingOrCreateOneByteFunction(Address address) {
if (program == null) {
return null;
}
// Get normalized address for function creation
Address normalizedAddress =
PseudoDisassembler.getNormalizedDisassemblyAddress(program, address);
// Does function already exist?
Function myFunction = program.getListing().getFunctionAt(normalizedAddress);
if (myFunction != null) {
return myFunction;
}
CreateFunctionCmd funCmd = new CreateFunctionCmd(null, normalizedAddress,
new AddressSet(normalizedAddress, normalizedAddress),
SourceType.DEFAULT);
if (!funCmd.applyTo(program, cancelOnlyWrappingMonitor)) {
appendLogMsg("Failed to apply function at address " + address.toString() +
"; attempting to use possible existing function");
return program.getListing().getFunctionAt(normalizedAddress);
}
myFunction = funCmd.getFunction();
return myFunction;
}
//==============================================================================================
void scheduleDeferredFunctionWork(DeferrableFunctionSymbolApplier applier) {
// Not using normalized address is OK, as we should have already set the context and
// used the normalized address when creating the one-byte function
disassembleAddresses.add(applier.getAddress());
deferredFunctionWorkAppliers.add(applier);
}
//==============================================================================================
// SymbolGroup-related methods.

View File

@ -0,0 +1,41 @@
/* ###
* 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.pdb.pdbapplicator;
import ghidra.program.model.address.Address;
/**
* Interface class for MsSymbolApplier that has deferrable function work.
*/
interface DeferrableFunctionSymbolApplier {
/**
* Returns entry address of code/function that needs disassembled; this is the original,
* non-normalized address (e.g., odd if Thumb)
* @return the address
*/
Address getAddress();
/**
* Deferred work for the MsSymbolApplier that can only be applied after all functions
* have been created and disassembled. Examples would be setting local variables and
* parameters
*/
default void doDeferredProcessing() {
// do nothing
}
}

View File

@ -17,8 +17,8 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.*;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.function.*;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
import ghidra.app.cmd.function.CallDepthChangeInfo;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
@ -37,7 +37,8 @@ import ghidra.util.task.TaskMonitor;
/**
* Applier for {@link AbstractProcedureStartMsSymbol} and {@link AbstractThunkMsSymbol} symbols.
*/
public class FunctionSymbolApplier extends MsSymbolApplier {
public class FunctionSymbolApplier extends MsSymbolApplier
implements DeferrableFunctionSymbolApplier {
private static final String BLOCK_INDENT = " ";
@ -134,6 +135,16 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
}
}
long getLength() {
if (procedureSymbol != null) {
return procedureSymbol.getProcedureLength();
}
else if (thunkSymbol != null) {
return thunkSymbol.getLength();
}
throw new AssertException("Unexpected Symbol type");
}
/**
* Returns the {@link Function} for this applier.
* @return the Function
@ -252,15 +263,16 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
}
private boolean applyFunction(TaskMonitor monitor) {
function = createFunction(monitor);
function = applicator.getExistingOrCreateOneByteFunction(address);
if (function == null) {
return false;
}
applicator.scheduleDeferredFunctionWork(this);
boolean succeededSetFunctionSignature = false;
if (thunkSymbol == null) {
function.setThunkedFunction(null);
if (function.getSignatureSource().isLowerPriorityThan(SourceType.IMPORTED)) {
function.setThunkedFunction(null);
succeededSetFunctionSignature = setFunctionDefinition(monitor);
function.setNoReturn(isNonReturning);
}
@ -274,28 +286,6 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
return true;
}
private Function createFunction(TaskMonitor monitor) {
// Does function already exist?
Function myFunction = applicator.getProgram().getListing().getFunctionAt(address);
if (myFunction != null) {
// Actually not sure if we should set to 0 or calculate from the function here.
// Need to investigate more, so at least keeping it as a separate 'else' for now.
return myFunction;
}
// Disassemble
Instruction instr = applicator.getProgram().getListing().getInstructionAt(address);
if (instr == null) {
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
cmd.applyTo(applicator.getProgram(), monitor);
}
myFunction = createFunctionCommand(monitor);
return myFunction;
}
/**
* returns true only if we set a function signature
* @param monitor monitor
@ -352,21 +342,6 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
return true;
}
private Function createFunctionCommand(TaskMonitor monitor) {
CreateFunctionCmd funCmd = new CreateFunctionCmd(address);
if (!funCmd.applyTo(applicator.getProgram(), monitor)) {
funCmd = new CreateFunctionCmd(null, address, new AddressSet(address, address),
SourceType.DEFAULT);
if (!funCmd.applyTo(applicator.getProgram(), monitor)) {
applicator
.appendLogMsg("Failed to apply function at address " + address.toString() +
"; attempting to use possible existing function");
return applicator.getProgram().getListing().getFunctionAt(address);
}
}
return funCmd.getFunction();
}
private boolean notDone() {
return (symbolBlockNestingLevel > 0) && iter.hasNext();
}
@ -500,4 +475,16 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
}
}
@Override
public void doDeferredProcessing() {
// TODO:
// Try to processes parameters, locals, scopes if applicable.
}
@Override
public Address getAddress() {
return address;
}
}

View File

@ -17,8 +17,6 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.regex.Matcher;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractLabelMsSymbol;
@ -26,16 +24,15 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Applier for {@link AbstractLabelMsSymbol} symbols.
*/
public class LabelSymbolApplier extends MsSymbolApplier {
public class LabelSymbolApplier extends MsSymbolApplier implements DeferrableFunctionSymbolApplier {
private AbstractLabelMsSymbol symbol;
private Function function = null;
@ -162,10 +159,11 @@ public class LabelSymbolApplier extends MsSymbolApplier {
private boolean applyFunction(Address address, String name, TaskMonitor monitor) {
applicator.createSymbol(address, name, true);
function = createFunction(address, monitor);
function = applicator.getExistingOrCreateOneByteFunction(address);
if (function == null) {
return false;
}
applicator.scheduleDeferredFunctionWork(this);
if (!function.isThunk() &&
function.getSignatureSource().isLowerPriorityThan(SourceType.IMPORTED)) {
@ -176,48 +174,12 @@ public class LabelSymbolApplier extends MsSymbolApplier {
function.setNoReturn(isNonReturning());
// We have seen no examples of custom calling convention flag being set.
if (hasCustomCallingConvention()) {
try {
function.setCallingConvention("unknown");
}
catch (InvalidInputException e) {
Msg.warn(this,
"PDB: Could not set \"unknown\" calling convention for label: " + name);
}
// For now: do nothing... the convention is unknown by default.
}
}
return true;
}
private Function createFunction(Address address, TaskMonitor monitor) {
// Check for existing function.
Function myFunction = applicator.getProgram().getListing().getFunctionAt(address);
if (myFunction != null) {
return myFunction;
}
// Disassemble
Instruction instr = applicator.getProgram().getListing().getInstructionAt(address);
if (instr == null) {
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
cmd.applyTo(applicator.getProgram(), monitor);
}
myFunction = createFunctionCommand(address, monitor);
return myFunction;
}
private Function createFunctionCommand(Address address, TaskMonitor monitor) {
CreateFunctionCmd funCmd = new CreateFunctionCmd(address);
if (!funCmd.applyTo(applicator.getProgram(), monitor)) {
applicator.appendLogMsg("Failed to apply function at address " + address.toString() +
"; attempting to use possible existing function");
return applicator.getProgram().getListing().getFunctionAt(address);
}
return funCmd.getFunction();
}
/**
* Returns label to apply or null if label excluded
* @return label to process or null
@ -235,4 +197,9 @@ public class LabelSymbolApplier extends MsSymbolApplier {
}
return label;
}
@Override
public Address getAddress() {
return applicator.getAddress(symbol);
}
}

View File

@ -17,9 +17,7 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.*;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.function.CallDepthChangeInfo;
import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractManagedProcedureMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
@ -50,7 +48,8 @@ import ghidra.util.task.TaskMonitor;
/**
* Applier for {@link AbstractManagedProcedureMsSymbol} symbols.
*/
public class ManagedProcedureSymbolApplier extends MsSymbolApplier {
public class ManagedProcedureSymbolApplier extends MsSymbolApplier
implements DeferrableFunctionSymbolApplier {
private static final String BLOCK_INDENT = " ";
@ -242,17 +241,14 @@ public class ManagedProcedureSymbolApplier extends MsSymbolApplier {
}
private boolean applyFunction(TaskMonitor monitor) {
Listing listing = applicator.getProgram().getListing();
applicator.createSymbol(address, getName(), true);
function = listing.getFunctionAt(address);
if (function == null) {
function = createFunction(monitor);
}
function = applicator.getExistingOrCreateOneByteFunction(address);
if (function == null) {
return false;
}
applicator.scheduleDeferredFunctionWork(this);
if (!function.isThunk() &&
function.getSignatureSource().isLowerPriorityThan(SourceType.IMPORTED)) {
@ -263,28 +259,6 @@ public class ManagedProcedureSymbolApplier extends MsSymbolApplier {
return true;
}
private Function createFunction(TaskMonitor monitor) {
// Does function already exist?
Function myFunction = applicator.getProgram().getListing().getFunctionAt(address);
if (myFunction != null) {
// Actually not sure if we should set to 0 or calculate from the function here.
// Need to investigate more, so at least keeping it as a separate 'else' for now.
return myFunction;
}
// Disassemble
Instruction instr = applicator.getProgram().getListing().getInstructionAt(address);
if (instr == null) {
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
cmd.applyTo(applicator.getProgram(), monitor);
}
myFunction = createFunctionCommand(monitor);
return myFunction;
}
private boolean setFunctionDefinition(TaskMonitor monitor) {
if (procedureSymbol == null) {
// TODO: is there anything we can do with thunkSymbol?
@ -364,16 +338,6 @@ public class ManagedProcedureSymbolApplier extends MsSymbolApplier {
return true;
}
private Function createFunctionCommand(TaskMonitor monitor) {
CreateFunctionCmd funCmd = new CreateFunctionCmd(address);
if (!funCmd.applyTo(applicator.getProgram(), monitor)) {
applicator.appendLogMsg("Failed to apply function at address " + address.toString() +
"; attempting to use possible existing function");
return applicator.getProgram().getListing().getFunctionAt(address);
}
return funCmd.getFunction();
}
private boolean notDone() {
return (symbolBlockNestingLevel > 0) && iter.hasNext();
}
@ -507,4 +471,15 @@ public class ManagedProcedureSymbolApplier extends MsSymbolApplier {
}
}
@Override
public void doDeferredProcessing() {
// TODO:
// Try to processes parameters, locals, scopes if applicable.
}
@Override
public Address getAddress() {
return address;
}
}

View File

@ -15,14 +15,11 @@
*/
package ghidra.app.util.pdb.pdbapplicator;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.TrampolineMsSymbol;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.listing.Function;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
@ -30,9 +27,11 @@ import ghidra.util.exception.CancelledException;
/**
* Applier for {@link TrampolineMsSymbol} symbols.
*/
public class TrampolineSymbolApplier extends MsSymbolApplier {
public class TrampolineSymbolApplier extends MsSymbolApplier
implements DeferrableFunctionSymbolApplier {
private TrampolineMsSymbol symbol;
private Address address;
/**
* Constructor
@ -47,6 +46,7 @@ public class TrampolineSymbolApplier extends MsSymbolApplier {
"Invalid symbol type: " + abstractSymbol.getClass().getSimpleName());
}
symbol = (TrampolineMsSymbol) abstractSymbol;
address = applicator.getAddress(symbol);
}
@Override
@ -57,21 +57,22 @@ public class TrampolineSymbolApplier extends MsSymbolApplier {
@Override
void apply() throws CancelledException, PdbException {
// We know the size of this trampoline, so use it to restrict the disassembly.
Address symbolAddress = applicator.getAddress(symbol);
Address targetAddress =
applicator.getAddress(symbol.getSegmentTarget(), symbol.getOffsetTarget());
Function target = null;
Function thunk = null;
if (!applicator.isInvalidAddress(targetAddress, "thunk target")) {
target = createNewFunction(targetAddress, 1);
target = applicator.getExistingOrCreateOneByteFunction(targetAddress);
}
if (!applicator.isInvalidAddress(symbolAddress, "thunk symbol")) {
thunk = createNewFunction(symbolAddress, symbol.getSizeOfThunk());
if (!applicator.isInvalidAddress(address, "thunk symbol")) {
thunk = applicator.getExistingOrCreateOneByteFunction(address);
}
if (target != null && thunk != null) {
thunk.setThunkedFunction(target);
}
applicator.scheduleDeferredFunctionWork(this);
// int thunkModule = findModuleNumberBySectionOffsetContribution(symbol.getSectionThunk(),
// symbol.getOffsetThunk());
// int targetModule = findModuleNumberBySectionOffsetContribution(symbol.getSectionTarget(),
@ -79,31 +80,14 @@ public class TrampolineSymbolApplier extends MsSymbolApplier {
}
// TODO? If we wanted to be able to apply this symbol to a different address, we should
@Override
public Address getAddress() {
return address;
}
// TODO? If we wanted to be able to apply this symbol to a different address, we should
// review code in FunctionSymbolApplier. Note, however, that there are two addresses
// that need to be dealt with here, and each could have a different address with a different
// delta from the specified address.
private Function createNewFunction(Address startAddress, long size) {
AddressSet addressSet = new AddressSet(startAddress, startAddress.add(size));
if (applicator.getProgram().getListing().getInstructionAt(startAddress) == null) {
DisassembleCommand cmd = new DisassembleCommand(addressSet, null, true); // TODO: false?
cmd.applyTo(applicator.getProgram(), applicator.getCancelOnlyWrappingMonitor());
}
// Only create function if it does not already exist.
Function function = applicator.getProgram().getListing().getFunctionAt(startAddress);
if (function != null) {
return function;
}
CreateFunctionCmd funCmd = new CreateFunctionCmd(startAddress);
if (!funCmd.applyTo(applicator.getProgram(), applicator.getCancelOnlyWrappingMonitor())) {
applicator.appendLogMsg("Failed to apply function at address " +
startAddress.toString() + "; attempting to use possible existing function");
}
return funCmd.getFunction();
}
}