mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-3282 Separated out the concepts of whether or not a program was analyzed from the state of if the user should be asked to analyze on open
This commit is contained in:
parent
008c299fa3
commit
bbadb4aed4
21 changed files with 215 additions and 152 deletions
|
@ -95,8 +95,8 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat
|
|||
protected void intoProject(DomainObject obj) {
|
||||
waitForDomainObject(obj);
|
||||
DomainFolder rootFolder = tool.getProject()
|
||||
.getProjectData()
|
||||
.getRootFolder();
|
||||
.getProjectData()
|
||||
.getRootFolder();
|
||||
waitForCondition(() -> {
|
||||
try {
|
||||
rootFolder.createFile(obj.getName(), obj, monitor);
|
||||
|
@ -141,7 +141,7 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat
|
|||
try (Transaction tx = program.openTransaction("Assemble")) {
|
||||
Address entry = addr(program, 0x00400000);
|
||||
program.getMemory()
|
||||
.createInitializedBlock(".text", entry, 0x1000, (byte) 0, monitor, false);
|
||||
.createInitializedBlock(".text", entry, 0x1000, (byte) 0, monitor, false);
|
||||
Assembler asm =
|
||||
Assemblers.getAssembler(program.getLanguage(), StackUnwinderTest.NO_16BIT_CALLS);
|
||||
AssemblyBuffer buf = new AssemblyBuffer(asm, entry);
|
||||
|
@ -193,9 +193,9 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat
|
|||
dis.disassemble(entry, null);
|
||||
|
||||
Function function = program.getFunctionManager()
|
||||
.createFunction("fib", entry,
|
||||
new AddressSet(entry, entry.add(bytes.length - 1)),
|
||||
SourceType.USER_DEFINED);
|
||||
.createFunction("fib", entry,
|
||||
new AddressSet(entry, entry.add(bytes.length - 1)),
|
||||
SourceType.USER_DEFINED);
|
||||
|
||||
function.updateFunction("__cdecl",
|
||||
new ReturnParameterImpl(UnsignedIntegerDataType.dataType, program),
|
||||
|
@ -231,7 +231,7 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat
|
|||
DebuggerEmulationService emuService = addPlugin(tool, DebuggerEmulationServicePlugin.class);
|
||||
|
||||
Function function = createFibonacciProgramX86_32();
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
Address entry = function.getEntryPoint();
|
||||
|
||||
programManager.openProgram(program);
|
||||
|
@ -271,9 +271,9 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat
|
|||
|
||||
try (Transaction tx = tb.startTransaction()) {
|
||||
tb.trace.getBreakpointManager()
|
||||
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr,
|
||||
Set.of(),
|
||||
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
|
||||
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr,
|
||||
Set.of(),
|
||||
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
|
||||
}
|
||||
|
||||
EmulationResult result = emuService.run(atSetup.getPlatform(), atSetup.getTime(), monitor,
|
||||
|
|
|
@ -128,6 +128,20 @@
|
|||
Analyzers in the Analysis menu. Only those analyzers which support one-shot use and are
|
||||
applicable to the current program will be available within the One Shot sub-menu.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Ask_To_Analyze"></A>Ask To Analyze</H3>
|
||||
<BLOCKQUOTE>
|
||||
<P> When opening a program for the first time, you will be asked if you want to analyze the
|
||||
program. If you respond "Yes", The <A href= "#Auto_Analysis_Option">Auto Analysis Options</A>
|
||||
dialog will appear, allowing you to begin analyzing the program. If you decide not to
|
||||
analyze the program, you have the choice of having Ghidra asking you again the next time
|
||||
you open the program. If you pick the "No" options, Ghidra will continue to ask you to
|
||||
every time you open the program. If you pick "No (Don't ask again)" Ghidra will never ask you to
|
||||
analyze the program again, but you can still manually initiate analysis at any time.
|
||||
If you choose not to have Ghidra ask again, it will set a property in the program called
|
||||
"Should Ask To Analyze" to false. Since this changes a property in the program, the program
|
||||
now has changes that need to be saved. </P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Auto_Analysis_Option"></A> <A name=
|
||||
"ghidra_app_plugin_analysis_AutoAnalysisPlugin_AnalysisOptionsDialog"></A> <A name=
|
||||
|
@ -199,9 +213,7 @@
|
|||
<LI>Delete - Deletes the currently selected named configuration.</LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<H2><A name="Auto_Analyzers"></A>Auto Analyzers</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
|
|
@ -72,7 +72,8 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
* resultProgram and latestProgram start out the same
|
||||
*/
|
||||
public PropertyListMergeManager(ProgramMultiUserMergeManager mergeManager,
|
||||
Program resultProgram, Program myProgram, Program originalProgram, Program latestProgram) {
|
||||
Program resultProgram, Program myProgram, Program originalProgram,
|
||||
Program latestProgram) {
|
||||
this.mergeManager = mergeManager;
|
||||
this.resultProgram = resultProgram;
|
||||
this.myProgram = myProgram;
|
||||
|
@ -142,7 +143,8 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
currentMonitor.setProgress(i);
|
||||
String myName = myNames.get(i);
|
||||
int progress = (int) (((float) (i / myNamesCount)) * 100);
|
||||
mergeManager.updateProgress(progress, "Merging property list for " + myName + "...");
|
||||
mergeManager.updateProgress(progress,
|
||||
"Merging property list for " + myName + "...");
|
||||
boolean isInLatest = latestNames.contains(myName);
|
||||
boolean isInOrig = origNames.contains(myName);
|
||||
if (!isInLatest && !isInOrig) {
|
||||
|
@ -277,11 +279,6 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
// value was not modified in my program or it was changed the same as in latest
|
||||
return;
|
||||
}
|
||||
if (propertyName.equals(Program.ANALYZED) && Boolean.TRUE.equals(myValue)) {
|
||||
// If my version sets "Analyzed" to true, then it should result in true.
|
||||
setValue(resultList, propertyName, myList.getType(propertyName), Boolean.TRUE);
|
||||
return;
|
||||
}
|
||||
if (SystemUtilities.isEqual(resultValue, origValue)) {
|
||||
// no change by latest - use my value
|
||||
setValue(resultList, propertyName, myList.getType(propertyName), myValue);
|
||||
|
|
|
@ -53,7 +53,7 @@ public class AnalysisBackgroundCommand extends MergeableBackgroundCommand {
|
|||
@Override
|
||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
||||
if (markAsAnalyzed) {
|
||||
GhidraProgramUtilities.setAnalyzedFlag((Program) obj, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed((Program) obj);
|
||||
}
|
||||
mgr.startAnalysis(monitor);
|
||||
return true;
|
||||
|
@ -63,12 +63,12 @@ public class AnalysisBackgroundCommand extends MergeableBackgroundCommand {
|
|||
@Override
|
||||
public MergeableBackgroundCommand mergeCommands(MergeableBackgroundCommand command) {
|
||||
SystemUtilities.assertTrue(command instanceof AnalysisBackgroundCommand,
|
||||
"This code assumes that the "
|
||||
+ "two commands are both AnalysisBackgroundCommands and this is not the case.");
|
||||
"This code assumes that the " +
|
||||
"two commands are both AnalysisBackgroundCommands and this is not the case.");
|
||||
|
||||
AnalysisBackgroundCommand abc = (AnalysisBackgroundCommand) command;
|
||||
SystemUtilities.assertTrue(mgr == abc.mgr, "This code assumes that the "
|
||||
+ "managers of the two commands are the same instance and this is not the case.");
|
||||
SystemUtilities.assertTrue(mgr == abc.mgr, "This code assumes that the " +
|
||||
"managers of the two commands are the same instance and this is not the case.");
|
||||
|
||||
// once we encounter a markAsAnalyzed value that is true, then leave it on
|
||||
markAsAnalyzed = markAsAnalyzed | abc.markAsAnalyzed;
|
||||
|
|
|
@ -359,8 +359,8 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
}
|
||||
File saveFile = getOptionsSaveFile(saveName);
|
||||
if (saveFile.exists() && OptionDialog.CANCEL_OPTION == OptionDialog
|
||||
.showOptionDialogWithCancelAsDefaultButton(this, "Overwrite Configuration",
|
||||
"Overwrite existing configuration file: " + saveName + " ?", "Overwrite")) {
|
||||
.showOptionDialogWithCancelAsDefaultButton(this, "Overwrite Configuration",
|
||||
"Overwrite existing configuration file: " + saveName + " ?", "Overwrite")) {
|
||||
return;
|
||||
}
|
||||
FileOptions currentOptions = getCurrentOptionsAsFileOptions();
|
||||
|
@ -687,7 +687,7 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
GenericOptionsComponent.createOptionComponent(childState);
|
||||
|
||||
HelpLocation helpLoc = analysisOptions
|
||||
.getHelpLocation(analyzerName + Options.DELIMITER_STRING + childOptionName);
|
||||
.getHelpLocation(analyzerName + Options.DELIMITER_STRING + childOptionName);
|
||||
if (helpLoc != null) {
|
||||
help.registerHelp(comp, helpLoc);
|
||||
}
|
||||
|
@ -775,7 +775,7 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
|
|||
|
||||
private boolean isAnalyzed() {
|
||||
Options options = programs.get(0).getOptions(Program.PROGRAM_INFO);
|
||||
return options.getBoolean(Program.ANALYZED, false);
|
||||
return options.getBoolean(Program.ANALYZED_OPTION_NAME, false);
|
||||
}
|
||||
|
||||
private Options[] loadPossibleOptionsChoicesForComboBox() {
|
||||
|
|
|
@ -132,7 +132,7 @@ class AnalyzeAllOpenProgramsTask extends Task {
|
|||
AutoAnalysisManager manager = AutoAnalysisManager.getAnalysisManager(program);
|
||||
initializeAnalysisOptions(program, prototypeAnalysisOptions, manager);
|
||||
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
|
||||
analyzeStrategy.analyzeProgram(program, manager, monitor);
|
||||
}
|
||||
|
|
|
@ -1048,8 +1048,8 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
|
|||
}
|
||||
|
||||
public void registerOptions() {
|
||||
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
registerOptions(options);
|
||||
registerGlobalAnalyisOptions();
|
||||
registerAnalyzerOptions();
|
||||
}
|
||||
|
||||
public void initializeOptions() {
|
||||
|
@ -1075,7 +1075,18 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
|
|||
dataTasks.optionsChanged(options);
|
||||
}
|
||||
|
||||
public void registerOptions(Options options) {
|
||||
private void registerGlobalAnalyisOptions() {
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
options.registerOption(Program.ANALYZED_OPTION_NAME, false, null,
|
||||
"Indicates if program has ever been analyzed");
|
||||
|
||||
options.registerOption(Program.ASK_TO_ANALYZE_OPTION_NAME, true, null,
|
||||
"Indicates if user should be prompted to analyze an unanalyzed program when opened");
|
||||
|
||||
}
|
||||
|
||||
public void registerAnalyzerOptions() {
|
||||
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
byteTasks.registerOptions(options);
|
||||
functionTasks.registerOptions(options);
|
||||
functionModifierChangedTasks.registerOptions(options);
|
||||
|
@ -1106,13 +1117,16 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
|
|||
Swing.assertSwingThread("Asking to analyze must be on the swing thread!");
|
||||
|
||||
if (GhidraProgramUtilities.shouldAskToAnalyze(program)) {
|
||||
// initialize the analyzed flag to a non-null value to indicate we at least asked
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, false);
|
||||
String name = HTMLUtilities.escapeHTML(program.getDomainFile().getName());
|
||||
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Ask_To_Analyze");
|
||||
int result = OptionDialog.showOptionNoCancelDialog(tool.getToolFrame(), "Analyze?",
|
||||
"<html>" + name + " has not been analyzed. Would you like to analyze it now?",
|
||||
"Yes", "No", "No (Don't ask again)", OptionDialog.QUESTION_MESSAGE, help);
|
||||
|
||||
int answer = OptionDialog.showYesNoDialog(tool.getToolFrame(), "Analyze",
|
||||
"<html>" + HTMLUtilities.escapeHTML(program.getDomainFile().getName()) +
|
||||
" has not been analyzed. Would you like to analyze it now?");
|
||||
return answer == OptionDialog.OPTION_ONE; //Analyze
|
||||
if (result == OptionDialog.OPTION_THREE) {
|
||||
GhidraProgramUtilities.markProgramNotToAskToAnalyze(program);
|
||||
}
|
||||
return result == OptionDialog.OPTION_ONE; //Analyze
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1271,12 +1285,12 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
|
|||
testLen = spacer.length() - 5;
|
||||
}
|
||||
taskTimesStringBuf
|
||||
.append(" " + element + spacer.substring(testLen) + secString + "\n");
|
||||
.append(" " + element + spacer.substring(testLen) + secString + "\n");
|
||||
}
|
||||
|
||||
taskTimesStringBuf.append("-----------------------------------------------------\n");
|
||||
taskTimesStringBuf
|
||||
.append(" Total Time " + (int) (totalTaskTime / 1000.00) + " secs\n");
|
||||
.append(" Total Time " + (int) (totalTaskTime / 1000.00) + " secs\n");
|
||||
taskTimesStringBuf.append("-----------------------------------------------------\n");
|
||||
|
||||
return taskTimesStringBuf.toString();
|
||||
|
|
|
@ -188,7 +188,7 @@ public class AutoAnalysisPlugin extends Plugin implements AutoAnalysisManagerLis
|
|||
|
||||
// check if this is the first time this program is being analyzed. If so,
|
||||
// schedule a callback when it is completed to send a FirstTimeAnalyzedPluginEvent
|
||||
boolean isAnalyzed = GhidraProgramUtilities.isAnalyzedFlagSet(program);
|
||||
boolean isAnalyzed = GhidraProgramUtilities.isAnalyzed(program);
|
||||
if (!isAnalyzed) {
|
||||
analysisMgr.addListener(new FirstTimeAnalyzedCallback());
|
||||
}
|
||||
|
|
|
@ -457,7 +457,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
|||
//
|
||||
// Cancel
|
||||
//
|
||||
if (choice == OptionDialog.OPTION_THREE) {
|
||||
if (choice == OptionDialog.CANCEL_OPTION) {
|
||||
// Cancel
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -878,7 +878,7 @@ public class HeadlessAnalyzer {
|
|||
|
||||
// Get parent folder to pass to GhidraScript
|
||||
File parentFile = new File(c.getResource(c.getSimpleName() + ".class").toURI())
|
||||
.getParentFile();
|
||||
.getParentFile();
|
||||
|
||||
currScript = (GhidraScript) c.getConstructor().newInstance();
|
||||
currScript.setScriptArgs(scriptArgs);
|
||||
|
@ -1019,7 +1019,7 @@ public class HeadlessAnalyzer {
|
|||
mgr.startAnalysis(TaskMonitor.DUMMY); // kick start
|
||||
|
||||
Msg.info(this, "REPORT: Analysis succeeded for file: " + fileAbsolutePath);
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
}
|
||||
else {
|
||||
HeadlessTimedTaskMonitor timerMonitor =
|
||||
|
@ -1042,7 +1042,7 @@ public class HeadlessAnalyzer {
|
|||
timerMonitor.cancel();
|
||||
|
||||
Msg.info(this, "REPORT: Analysis succeeded for file: " + fileAbsolutePath);
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1559,7 +1559,7 @@ public class HeadlessAnalyzer {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Save
|
||||
for (Loaded<Program> loaded : loadResults) {
|
||||
if (!loaded.getDomainObject().isTemporary()) {
|
||||
|
|
|
@ -124,7 +124,6 @@ public abstract class AbstractProgramLoader implements Loader {
|
|||
MessageLog messageLog, Object consumer, TaskMonitor monitor) throws IOException,
|
||||
CancelledException, VersionException, LoadException {
|
||||
|
||||
|
||||
if (!loadSpec.isComplete()) {
|
||||
throw new LoadException("Load spec is incomplete");
|
||||
}
|
||||
|
@ -369,7 +368,7 @@ public abstract class AbstractProgramLoader implements Loader {
|
|||
fsrl = fsrl.withMD5(md5);
|
||||
}
|
||||
prog.getOptions(Program.PROGRAM_INFO)
|
||||
.setString(ProgramMappingService.PROGRAM_SOURCE_FSRL, fsrl.toString());
|
||||
.setString(ProgramMappingService.PROGRAM_SOURCE_FSRL, fsrl.toString());
|
||||
}
|
||||
prog.setExecutableMD5(md5);
|
||||
String sha256 = computeBinarySHA256(provider);
|
||||
|
@ -498,17 +497,19 @@ public abstract class AbstractProgramLoader implements Loader {
|
|||
boolean anchorSymbols = shouldAnchorSymbols(options);
|
||||
List<AddressLabelInfo> labels = lang.getDefaultSymbols();
|
||||
for (AddressLabelInfo info : labels) {
|
||||
createSymbol(program, info.getLabel(), info.getAddress(), info.isEntry(), info.isPrimary(), anchorSymbols);
|
||||
createSymbol(program, info.getLabel(), info.getAddress(), info.isEntry(),
|
||||
info.isPrimary(), anchorSymbols);
|
||||
}
|
||||
}
|
||||
GhidraProgramUtilities.removeAnalyzedFlag(program);
|
||||
GhidraProgramUtilities.resetAnalysisFlags(program);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(id, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSymbol(Program program, String labelname, Address address, boolean isEntry, boolean isPrimary, boolean anchorSymbols) {
|
||||
private static void createSymbol(Program program, String labelname, Address address,
|
||||
boolean isEntry, boolean isPrimary, boolean anchorSymbols) {
|
||||
SymbolTable symTable = program.getSymbolTable();
|
||||
Address addr = address;
|
||||
Symbol s = symTable.getPrimarySymbol(addr);
|
||||
|
|
|
@ -389,7 +389,7 @@ public class ProgramXmlMgr {
|
|||
|
||||
//if instructions were imported, then remove the "needs analyzed" property
|
||||
if (options.isInstructions()) {
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
}
|
||||
|
||||
return log;
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
*/
|
||||
package ghidra.plugins.fsbrowser.tasks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
|
@ -140,7 +139,7 @@ public class GFileSystemLoadKernelTask extends Task {
|
|||
file.getParentFile().getPath());
|
||||
String fileName = ProjectDataUtils.getUniqueName(folder, program.getName());
|
||||
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
|
||||
folder.createFile(fileName, program, monitor);
|
||||
|
||||
|
|
|
@ -136,10 +136,10 @@ public class ProgramBuilder {
|
|||
CompilerSpec compilerSpec = compilerSpecID == null ? language.getDefaultCompilerSpec()
|
||||
: language.getCompilerSpecByID(new CompilerSpecID(compilerSpecID));
|
||||
program = new ProgramDB(name, language, compilerSpec, consumer == null ? this : consumer);
|
||||
setAnalyzed(true);
|
||||
setAnalyzed();
|
||||
program.setTemporary(true); // ignore changes
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct program builder using a full language object rather than a language id string
|
||||
* @param name program name
|
||||
|
@ -150,7 +150,7 @@ public class ProgramBuilder {
|
|||
throws Exception {
|
||||
CompilerSpec compilerSpec = language.getDefaultCompilerSpec();
|
||||
program = new ProgramDB(name, language, compilerSpec, this);
|
||||
setAnalyzed(true);
|
||||
setAnalyzed();
|
||||
program.setTemporary(true); // ignore changes
|
||||
}
|
||||
|
||||
|
@ -281,10 +281,9 @@ public class ProgramBuilder {
|
|||
|
||||
/**
|
||||
* This prevents the 'ask to analyze' dialog from showing when called with {@code true}
|
||||
* @param analyzed true to mark the program as analyzed
|
||||
*/
|
||||
public void setAnalyzed(boolean analyzed) {
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, analyzed);
|
||||
public void setAnalyzed() {
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
}
|
||||
|
||||
public MemoryBlock createMemory(String name, String address, int size) {
|
||||
|
@ -321,8 +320,8 @@ public class ProgramBuilder {
|
|||
|
||||
return tx(() -> {
|
||||
return program.getMemory()
|
||||
.createInitializedBlock(name, addr(address), size, (byte) 0, TaskMonitor.DUMMY,
|
||||
true);
|
||||
.createInitializedBlock(name, addr(address), size, (byte) 0, TaskMonitor.DUMMY,
|
||||
true);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@ public class GhidraProgramUtilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* returns the current program, given a tool, if a program is opened;
|
||||
* otherwise returns null.
|
||||
* Returns the current program for the given tool or null if no program is open.
|
||||
* @param tool the tool get get the current program for
|
||||
* @return the current program for the given tool or null if no program is open
|
||||
*/
|
||||
public static Program getCurrentProgram(PluginTool tool) {
|
||||
ProgramManager pmService = tool.getService(ProgramManager.class);
|
||||
|
@ -34,11 +35,13 @@ public class GhidraProgramUtilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if the program does not contain the analyzed flag. The assumption is that a
|
||||
* non-null value means that the user has already made a decision about analyzing.
|
||||
* Returns true if the user should be asked to analyze. They will only be asked if the program
|
||||
* hasn't already been analyzed (analyzed flag property is false or null) or the
|
||||
* "ask to analyze" flag property is true or null (default is true unless explicitly set to
|
||||
* false).
|
||||
*
|
||||
* @param program the program to check for the property
|
||||
* @return true if the program does not contain the analyzed flag
|
||||
* @return true if the user should be prompted to analyze the program
|
||||
*/
|
||||
public static boolean shouldAskToAnalyze(Program program) {
|
||||
|
||||
|
@ -48,20 +51,27 @@ public class GhidraProgramUtilities {
|
|||
}
|
||||
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
return !options.contains(Program.ANALYZED);
|
||||
// older programs don't have a "Ask" property, so check analyzed flag
|
||||
boolean isAnalyzed = options.getBoolean(Program.ANALYZED_OPTION_NAME, false);
|
||||
if (isAnalyzed) {
|
||||
return false;
|
||||
}
|
||||
return options.getBoolean(Program.ASK_TO_ANALYZE_OPTION_NAME, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the analyzed flag from the program properties.
|
||||
* With this property removed, the user will be prompted to analyze the
|
||||
* Resets the analysis flags to the program defaults
|
||||
* With this reset, the user will be prompted to analyze the
|
||||
* program the next time it is opened.
|
||||
* @param program the program containing the property to be removed
|
||||
* @param program the program whose analysis flags should be reset
|
||||
*/
|
||||
public static void removeAnalyzedFlag(Program program) {
|
||||
int transactionID = program.startTransaction(Program.ANALYZED);
|
||||
public static void resetAnalysisFlags(Program program) {
|
||||
int transactionID = program.startTransaction("Reset Analysis Flags");
|
||||
|
||||
try {
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
options.removeOption(Program.ANALYZED);
|
||||
options.removeOption(Program.ANALYZED_OPTION_NAME);
|
||||
options.removeOption(Program.ASK_TO_ANALYZE_OPTION_NAME);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
|
@ -69,21 +79,28 @@ public class GhidraProgramUtilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the analyzed flag to the specified value.
|
||||
* Marks the program has having been analyzed
|
||||
* @param program the program to set property
|
||||
* @param analyzed the analyzed flag
|
||||
*/
|
||||
public static void setAnalyzedFlag(Program program, boolean analyzed) {
|
||||
public static void markProgramAnalyzed(Program program) {
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
|
||||
// once the program is analyzed, register the value, so it won't keep writing it to the database.
|
||||
if (analyzed && !options.isRegistered(Program.ANALYZED)) {
|
||||
options.registerOption(Program.ANALYZED, false, null,
|
||||
"Indicates if program has been analyzed");
|
||||
}
|
||||
int transactionID = program.startTransaction(Program.ANALYZED);
|
||||
int transactionID = program.startTransaction("Mark Program Analyzed");
|
||||
try {
|
||||
options.setBoolean(Program.ANALYZED, analyzed);
|
||||
options.setBoolean(Program.ANALYZED_OPTION_NAME, true);
|
||||
options.setBoolean(Program.ASK_TO_ANALYZE_OPTION_NAME, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void markProgramNotToAskToAnalyze(Program program) {
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
|
||||
int transactionID = program.startTransaction("Mark Program To Not Ask To Analyze");
|
||||
try {
|
||||
options.setBoolean(Program.ASK_TO_ANALYZE_OPTION_NAME, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
|
@ -95,17 +112,10 @@ public class GhidraProgramUtilities {
|
|||
* @param program the program to test to see if it has been analyzed
|
||||
* @return true if the program has been analyzed at least once.
|
||||
*/
|
||||
public static boolean isAnalyzedFlagSet(Program program) {
|
||||
public static boolean isAnalyzed(Program program) {
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
|
||||
// we first have to check if the flag has even been created because checking the flag
|
||||
// directly causes it to be created if it doesn't exist and we unfortunately use the
|
||||
// existence of the flag to know whether or not to ask the user if they want to start
|
||||
// analysis
|
||||
if (!options.isRegistered(Program.ANALYZED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return options.getBoolean(Program.ANALYZED, false);
|
||||
return options.getBoolean(Program.ANALYZED_OPTION_NAME, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -256,9 +256,9 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
// By default, create test output within a directory at the same level as the
|
||||
// development repositories
|
||||
outputRoot = Application.getApplicationRootDirectory()
|
||||
.getParentFile()
|
||||
.getParentFile()
|
||||
.getCanonicalPath();
|
||||
.getParentFile()
|
||||
.getParentFile()
|
||||
.getCanonicalPath();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@ -1562,7 +1562,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
|
||||
setAnalysisOptions(program.getOptions(Program.ANALYSIS_PROPERTIES));
|
||||
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, true);
|
||||
GhidraProgramUtilities.markProgramAnalyzed(program);
|
||||
|
||||
// Remove all single-byte functions created by Elf importer
|
||||
// NOTE: This is a known issues with optimized code and symbols marked as ElfSymbol.STT_FUNC
|
||||
|
@ -1670,7 +1670,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
RegisterValue thumbMode = new RegisterValue(tReg, BigInteger.ONE);
|
||||
try {
|
||||
program.getProgramContext()
|
||||
.setRegisterValue(functionAddr, functionAddr, thumbMode);
|
||||
.setRegisterValue(functionAddr, functionAddr, thumbMode);
|
||||
}
|
||||
catch (ContextChangeException e) {
|
||||
throw new AssertException(e);
|
||||
|
@ -1684,7 +1684,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
RegisterValue thumbMode = new RegisterValue(isaModeReg, BigInteger.ONE);
|
||||
try {
|
||||
program.getProgramContext()
|
||||
.setRegisterValue(functionAddr, functionAddr, thumbMode);
|
||||
.setRegisterValue(functionAddr, functionAddr, thumbMode);
|
||||
}
|
||||
catch (ContextChangeException e) {
|
||||
throw new AssertException(e);
|
||||
|
@ -1909,7 +1909,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
if (absoluteGzfFilePath.exists()) {
|
||||
program = getGzfProgram(outputDir, gzfCachePath);
|
||||
if (program != null && !MD5Utilities.getMD5Hash(testFile.file)
|
||||
.equals(program.getExecutableMD5())) {
|
||||
.equals(program.getExecutableMD5())) {
|
||||
// remove obsolete GZF cache file
|
||||
env.release(program);
|
||||
program = null;
|
||||
|
@ -1934,7 +1934,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
}
|
||||
else {
|
||||
program = env.getGhidraProject()
|
||||
.importProgram(testFile.file, language, compilerSpec);
|
||||
.importProgram(testFile.file, language, compilerSpec);
|
||||
}
|
||||
program.addConsumer(this);
|
||||
env.getGhidraProject().close(program);
|
||||
|
@ -1955,8 +1955,8 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
|
||||
if (!program.getLanguageID().equals(language.getLanguageID()) ||
|
||||
!program.getCompilerSpec()
|
||||
.getCompilerSpecID()
|
||||
.equals(compilerSpec.getCompilerSpecID())) {
|
||||
.getCompilerSpecID()
|
||||
.equals(compilerSpec.getCompilerSpecID())) {
|
||||
throw new IOException((usingCachedGZF ? "Cached " : "") +
|
||||
"Program has incorrect language/compiler spec (" + program.getLanguageID() +
|
||||
"/" + program.getCompilerSpec().getCompilerSpecID() + "): " +
|
||||
|
@ -2121,7 +2121,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E
|
|||
testFileDigest.append(nameAndAddr);
|
||||
testFileDigest.append(" (GroupInfo @ ");
|
||||
testFileDigest
|
||||
.append(testGroup.controlBlock.getInfoStructureAddress().toString(true));
|
||||
.append(testGroup.controlBlock.getInfoStructureAddress().toString(true));
|
||||
testFileDigest.append(")");
|
||||
if (duplicateTests.contains(testGroup.testGroupName)) {
|
||||
testFileDigest.append(" *DUPLICATE*");
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.util.pdb;
|
|||
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.GhidraProgramUtilities;
|
||||
|
||||
/**
|
||||
* Storage of PDB-related attributes
|
||||
|
@ -47,9 +48,7 @@ public class PdbProgramAttributes {
|
|||
pdbLoaded = propList.contains(PdbParserConstants.PDB_LOADED)
|
||||
? propList.getBoolean(PdbParserConstants.PDB_LOADED, false)
|
||||
: false;
|
||||
programAnalyzed = propList.contains(Program.ANALYZED)
|
||||
? propList.getBoolean(Program.ANALYZED, false)
|
||||
: false;
|
||||
programAnalyzed = GhidraProgramUtilities.isAnalyzed(program);
|
||||
pdbSignature = propList.contains(PdbParserConstants.PDB_SIGNATURE)
|
||||
? propList.getString(PdbParserConstants.PDB_SIGNATURE, null)
|
||||
: null;
|
||||
|
@ -141,5 +140,4 @@ public class PdbProgramAttributes {
|
|||
return programAnalyzed;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -15,12 +15,11 @@
|
|||
*/
|
||||
package pdb;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
|
@ -39,6 +38,7 @@ import ghidra.framework.plugintool.*;
|
|||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.GhidraProgramUtilities;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -75,22 +75,22 @@ public class PdbPlugin extends Plugin {
|
|||
|
||||
private void createActions() {
|
||||
new ActionBuilder("Load PDB File", this.getName())
|
||||
.supportsDefaultToolContext(true)
|
||||
.withContext(ProgramActionContext.class)
|
||||
.validContextWhen(pac -> pac.getProgram() != null &&
|
||||
PdbAnalyzerCommon.canAnalyzeProgram(pac.getProgram()))
|
||||
.menuPath(ToolConstants.MENU_FILE, "Load PDB File...")
|
||||
.menuGroup("Import PDB", "3")
|
||||
.helpLocation(new HelpLocation(PDB_PLUGIN_HELP_TOPIC, "Load PDB File"))
|
||||
.onAction(pac -> loadPDB(pac))
|
||||
.buildAndInstall(tool);
|
||||
.supportsDefaultToolContext(true)
|
||||
.withContext(ProgramActionContext.class)
|
||||
.validContextWhen(pac -> pac.getProgram() != null &&
|
||||
PdbAnalyzerCommon.canAnalyzeProgram(pac.getProgram()))
|
||||
.menuPath(ToolConstants.MENU_FILE, "Load PDB File...")
|
||||
.menuGroup("Import PDB", "3")
|
||||
.helpLocation(new HelpLocation(PDB_PLUGIN_HELP_TOPIC, "Load PDB File"))
|
||||
.onAction(pac -> loadPDB(pac))
|
||||
.buildAndInstall(tool);
|
||||
|
||||
new ActionBuilder("Symbol Server Config", this.getName())
|
||||
.menuPath(ToolConstants.MENU_EDIT, "Symbol Server Config")
|
||||
.menuGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP)
|
||||
.helpLocation(new HelpLocation(PDB_PLUGIN_HELP_TOPIC, "Symbol Server Config"))
|
||||
.onAction(ac -> configPDB())
|
||||
.buildAndInstall(tool);
|
||||
.menuPath(ToolConstants.MENU_EDIT, "Symbol Server Config")
|
||||
.menuGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP)
|
||||
.helpLocation(new HelpLocation(PDB_PLUGIN_HELP_TOPIC, "Symbol Server Config"))
|
||||
.onAction(ac -> configPDB())
|
||||
.buildAndInstall(tool);
|
||||
}
|
||||
|
||||
private void configPDB() {
|
||||
|
@ -107,8 +107,7 @@ public class PdbPlugin extends Plugin {
|
|||
return;
|
||||
}
|
||||
|
||||
boolean analyzed =
|
||||
program.getOptions(Program.PROGRAM_INFO).getBoolean(Program.ANALYZED, false);
|
||||
boolean analyzed = GhidraProgramUtilities.isAnalyzed(program);
|
||||
|
||||
if (analyzed) {
|
||||
int response =
|
||||
|
@ -147,8 +146,8 @@ public class PdbPlugin extends Plugin {
|
|||
LoadPdbTask loadPdbTask = new LoadPdbTask(program, pdbFile,
|
||||
loadPdbResults.useMsDiaParser, loadPdbResults.control, dataTypeManagerService);
|
||||
TaskBuilder.withTask(loadPdbTask)
|
||||
.setStatusTextAlignment(SwingConstants.LEADING)
|
||||
.setLaunchDelay(0);
|
||||
.setStatusTextAlignment(SwingConstants.LEADING)
|
||||
.setLaunchDelay(0);
|
||||
new TaskLauncher(loadPdbTask, null, 0);
|
||||
|
||||
// Check for error messages & exceptions and handle them here
|
||||
|
@ -282,15 +281,15 @@ public class PdbPlugin extends Plugin {
|
|||
SymbolServerInstanceCreatorContext symbolServerInstanceCreatorContext) {
|
||||
SymbolServer temporarySymbolServer =
|
||||
symbolServerInstanceCreatorContext.getSymbolServerInstanceCreatorRegistry()
|
||||
.newSymbolServer(Preferences.getProperty(SYMBOL_STORAGE_DIR_OPTION, "", true),
|
||||
symbolServerInstanceCreatorContext);
|
||||
.newSymbolServer(Preferences.getProperty(SYMBOL_STORAGE_DIR_OPTION, "", true),
|
||||
symbolServerInstanceCreatorContext);
|
||||
SymbolStore symbolStore =
|
||||
(temporarySymbolServer instanceof SymbolStore) ? (SymbolStore) temporarySymbolServer
|
||||
: new SameDirSymbolStore(symbolServerInstanceCreatorContext.getRootDir());
|
||||
List<SymbolServer> symbolServers =
|
||||
symbolServerInstanceCreatorContext.getSymbolServerInstanceCreatorRegistry()
|
||||
.createSymbolServersFromPathList(getSymbolSearchPaths(),
|
||||
symbolServerInstanceCreatorContext);
|
||||
.createSymbolServersFromPathList(getSymbolSearchPaths(),
|
||||
symbolServerInstanceCreatorContext);
|
||||
return new SymbolServerService(symbolStore, symbolServers);
|
||||
}
|
||||
|
||||
|
@ -307,9 +306,9 @@ public class PdbPlugin extends Plugin {
|
|||
symbolServerService.getSymbolStore().getName());
|
||||
|
||||
String path = symbolServerService.getSymbolServers()
|
||||
.stream()
|
||||
.map(SymbolServer::getName)
|
||||
.collect(Collectors.joining(";"));
|
||||
.stream()
|
||||
.map(SymbolServer::getName)
|
||||
.collect(Collectors.joining(";"));
|
||||
Preferences.setProperty(SYMBOL_SEARCH_PATH_OPTION, path);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -310,7 +310,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
return ps;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
panel.add(label, BorderLayout.WEST);
|
||||
panel.add(textPanel, BorderLayout.CENTER);
|
||||
return panel;
|
||||
|
@ -764,7 +764,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
return Swing.runNow(() -> {
|
||||
OptionDialog info =
|
||||
new OptionDialog(title, message, option1, option2, PLAIN_MESSAGE, icon, false);
|
||||
return info.show();
|
||||
return info.show(parent);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -794,7 +794,39 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
return Swing.runNow(() -> {
|
||||
OptionDialog info = new OptionDialog(title, message, option1, option2, option3,
|
||||
messageType, null, false);
|
||||
return info.show();
|
||||
return info.show(parent);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Static helper method to easily display an three-option dialog with no Cancel button.
|
||||
* The dialog will remain until the user presses the
|
||||
* Option1, Option 2, or Option 3 button.
|
||||
*
|
||||
* @param parent The parent component of this dialog. If the given component is
|
||||
* a frame or dialog, then the component will be used to parent the option dialog.
|
||||
* Otherwise, the parent frame or dialog will be found by traversing up the given
|
||||
* component's parent hierarchy. Also, null can be used to not parent the dialog at all,
|
||||
* but this promotes poor dialog behavior
|
||||
* @param title The String to be placed in the dialogs title area
|
||||
* @param message The information message to be displayed in the dialog
|
||||
* @param option1 The text to place on the first option button
|
||||
* @param option2 The text to place on the second option button
|
||||
* @param option3 The text to place on the third option button
|
||||
* @param messageType used to specify a default icon, can be ERROR_MESSAGE,
|
||||
* INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE, or PLAIN_MESSAGE)
|
||||
* @param help The help location for this dialog
|
||||
* @return The options selected by the user. 1 for the first option and
|
||||
* 2 for the second option. 0 is returned if the operation is cancelled
|
||||
*/
|
||||
public static int showOptionNoCancelDialog(Component parent, String title, String message,
|
||||
String option1, String option2, String option3, int messageType, HelpLocation help) {
|
||||
|
||||
return Swing.runNow(() -> {
|
||||
OptionDialog info = new OptionDialog(title, message, option1, option2, option3,
|
||||
messageType, null, false);
|
||||
info.setHelpLocation(help);
|
||||
return info.show(parent);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -51,26 +51,28 @@ public interface Program extends DataTypeManagerDomainObject {
|
|||
public static final String ANALYSIS_PROPERTIES = "Analyzers";
|
||||
public static final String DISASSEMBLER_PROPERTIES = "Disassembler";
|
||||
|
||||
/** Name of program information property list */
|
||||
/** Options for storing program info */
|
||||
public static final String PROGRAM_INFO = "Program Information";
|
||||
/** Name of program settings property list */
|
||||
public static final String PROGRAM_SETTINGS = "Program Settings";
|
||||
|
||||
/** Name of boolean analyzed property */
|
||||
public static final String ANALYZED = "Analyzed";
|
||||
/** Name of date created property */
|
||||
public static final String ANALYZED_OPTION_NAME = "Analyzed";
|
||||
/** Property to control if user should be asked to analyze when unanalyzed program opened */
|
||||
public static final String ASK_TO_ANALYZE_OPTION_NAME = "Should Ask To Analyze";
|
||||
|
||||
/** Date created property */
|
||||
public static final String DATE_CREATED = "Date Created";
|
||||
/** Name of ghidra version property */
|
||||
/** Ghidra version property */
|
||||
public static final String CREATED_WITH_GHIDRA_VERSION = "Created With Ghidra Version";
|
||||
/** Name of ghidra preferred root namespace category property */
|
||||
/** Ghidra preferred root namespace category property */
|
||||
public static final String PREFERRED_ROOT_NAMESPACE_CATEGORY_PROPERTY =
|
||||
"Preferred Root Namespace Category";
|
||||
/** Creation date to ask for analysis */
|
||||
|
||||
/** Creation date for analysis */
|
||||
public static final String ANALYSIS_START_DATE = "2007-Jan-01";
|
||||
/** Format string of analysis date */
|
||||
public static final String ANALYSIS_START_DATE_FORMAT = "yyyy-MMM-dd";
|
||||
/** A date from January 1, 1970 */
|
||||
public static final Date JANUARY_1_1970 = new Date(0);
|
||||
|
||||
/** The maximum number of operands for any assembly language */
|
||||
public final static int MAX_OPERANDS = 16;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public class PdbScreenShots extends GhidraScreenShotGenerator {
|
|||
temporaryDir = createTempDirectory("example_pdb");
|
||||
tx = program.startTransaction("set analyzed flag");
|
||||
Options proplist = program.getOptions(Program.PROGRAM_INFO);
|
||||
proplist.setBoolean(Program.ANALYZED, false);
|
||||
proplist.setBoolean(Program.ANALYZED_OPTION_NAME, false);
|
||||
PdbInfo pdbInfo = PdbInfoDotNet.fromValues("HelloWorld.pdb", 1, new GUID(GUID1_STR));
|
||||
pdbInfo.serializeToOptions(proplist);
|
||||
proplist.setString("Executable Location",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue