ghidra/Ghidra/Features/PDB/src/main/java/pdb/LoadPdbTask.java
ghidra1 a721ddc9c7 Merge remote-tracking branch 'origin/Ghidra_9.2'
Conflicts:
	Ghidra/Features/PDB/src/main/java/pdb/LoadPdbTask.java
2020-11-03 18:41:32 -05:00

219 lines
6.8 KiB
Java

/* ###
* 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 pdb;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import docking.DockingWindowManager;
import docking.widgets.OptionDialog;
import docking.widgets.dialogs.MultiLineMessageDialog;
import ghidra.app.plugin.core.analysis.*;
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.bin.format.pdb.PdbException;
import ghidra.app.util.bin.format.pdb.PdbParser;
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.pdb.PdbLocator;
import ghidra.app.util.pdb.PdbProgramAttributes;
import ghidra.app.util.pdb.pdbapplicator.*;
import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor;
class LoadPdbTask extends Task {
private File pdbFile;
private DataTypeManagerService service;
private final Program program;
private final boolean useMsDiaParser;
private final PdbApplicatorRestrictions restrictions; // PDB Universal Parser only
LoadPdbTask(Program program, File pdbFile, boolean useMsDiaParser,
PdbApplicatorRestrictions restrictions, DataTypeManagerService service) {
super("Load PDB", true, false, true, true);
this.program = program;
this.pdbFile = pdbFile;
this.useMsDiaParser = useMsDiaParser;
this.restrictions = restrictions;
this.service = service;
}
@Override
public void run(final TaskMonitor monitor) {
final MessageLog log = new MessageLog();
AnalysisWorker worker = new AnalysisWorker() {
@Override
public String getWorkerName() {
return "Load PDB";
}
@Override
public boolean analysisWorkerCallback(Program currentProgram, Object workerContext,
TaskMonitor currentMonitor) throws CancelledException {
try {
if (useMsDiaParser) {
if (!parseWithMsDiaParser(log, monitor)) {
return false;
}
}
else if (!parseWithNewParser(log, monitor)) {
return false;
}
analyzeSymbols(currentMonitor, log);
}
catch (IOException e) {
log.appendMsg("PDB IO Error: " + e.getMessage());
}
return false;
}
};
try {
AutoAnalysisManager.getAnalysisManager(program)
.scheduleWorker(worker, null, true, monitor);
if (log.hasMessages()) {
MultiLineMessageDialog dialog = new MultiLineMessageDialog("Load PDB File",
"There were warnings/errors loading the PDB file.", log.toString(),
MultiLineMessageDialog.WARNING_MESSAGE, false);
DockingWindowManager.showDialog(null, dialog);
}
}
catch (InterruptedException | CancelledException e1) {
// ignore
}
catch (InvocationTargetException e) {
String message;
Throwable t = e.getCause();
if (t == null) {
message = "Unknown cause";
}
else {
message = t.getMessage();
if (message == null) {
message = t.toString();
}
}
message = "Error processing PDB file: " + pdbFile + ".\n" + message;
Msg.showError(getClass(), null, "Load PDB Failed", message, t);
}
}
private boolean parseWithMsDiaParser(MessageLog log, TaskMonitor monitor)
throws IOException, CancelledException {
PdbParser parser = new PdbParser(pdbFile, program, service, true, monitor);
try {
parser.parse();
parser.openDataTypeArchives();
parser.applyTo(log);
return true;
}
catch (PdbException | DuplicateIdException e) {
log.appendMsg("PDB Error: " + e.getMessage());
}
return false;
}
// NOTE: OptionDialog will not display an empty line
private static final String BLANK_LINE = " \n";
private boolean parseWithNewParser(MessageLog log, TaskMonitor monitor)
throws IOException, CancelledException {
PdbReaderOptions pdbReaderOptions = new PdbReaderOptions(); // use defaults
PdbApplicatorOptions pdbApplicatorOptions = new PdbApplicatorOptions();
pdbApplicatorOptions.setRestrictions(restrictions);
PdbProgramAttributes programAttributes = new PdbProgramAttributes(program);
try (AbstractPdb pdb = ghidra.app.util.bin.format.pdb2.pdbreader.PdbParser
.parse(pdbFile.getAbsolutePath(), pdbReaderOptions, monitor)) {
PdbIdentifiers identifiers = pdb.getIdentifiers();
if (!PdbLocator.verifyPdbSignature(programAttributes, identifiers)) {
StringBuilder builder = new StringBuilder();
builder.append("Selected PDB does not match program's PDB specification!\n");
builder.append(BLANK_LINE);
builder.append("Program's PDB specification:\n");
builder.append(PdbLocator.formatPdbIdentifiers(programAttributes));
builder.append(BLANK_LINE);
builder.append("Selected PDB file specification:\n");
builder.append(
PdbLocator.formatPdbIdentifiers(pdbFile.getAbsolutePath(), identifiers));
builder.append(BLANK_LINE);
builder.append("Do you wish to force load this PDB?");
if (OptionDialog.YES_OPTION != OptionDialog.showYesNoDialog(null,
"Confirm PDB Load", builder.toString())) {
return false;
}
}
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
pdb.deserialize(monitor);
PdbApplicator applicator = new PdbApplicator(pdbFile.getAbsolutePath(), pdb);
applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(),
pdbApplicatorOptions, monitor, log);
return true;
}
catch (ghidra.app.util.bin.format.pdb2.pdbreader.PdbException e) {
log.appendMsg("PDB Error: " + e.getMessage());
}
return false;
}
private void analyzeSymbols(TaskMonitor monitor, MessageLog log) {
MicrosoftDemanglerAnalyzer demanglerAnalyzer = new MicrosoftDemanglerAnalyzer();
String analyzerName = demanglerAnalyzer.getName();
Options analysisProperties = program.getOptions(Program.ANALYSIS_PROPERTIES);
String defaultValueAsString = analysisProperties.getValueAsString(analyzerName);
boolean doDemangle = true;
if (defaultValueAsString != null) {
doDemangle = Boolean.parseBoolean(defaultValueAsString);
}
if (doDemangle) {
AddressSetView addrs = program.getMemory();
monitor.initialize(addrs.getNumAddresses());
try {
demanglerAnalyzer.added(program, addrs, monitor, log);
}
catch (CancelledException e) {
// ignore cancel
}
}
}
}