Merge remote-tracking branch 'origin/GP-3282_ghidragon_analysisflag--SQUASHED'

This commit is contained in:
Ryan Kurtz 2023-04-05 07:34:25 -04:00
commit fba01cde18
21 changed files with 215 additions and 152 deletions

View file

@ -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);

View file

@ -129,6 +129,20 @@
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=
"AnalysisOptions"></A> Auto Analysis Options Panel</H2>
@ -199,9 +213,7 @@
<LI>Delete - Deletes the currently selected named configuration.</LI>
</UL>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2><A name="Auto_Analyzers"></A>Auto Analyzers</H2>
<BLOCKQUOTE>

View file

@ -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);

View file

@ -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;

View file

@ -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() {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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());
}

View file

@ -457,7 +457,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
//
// Cancel
//
if (choice == OptionDialog.OPTION_THREE) {
if (choice == OptionDialog.CANCEL_OPTION) {
// Cancel
return;
}

View file

@ -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);
}
}
}

View file

@ -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");
}
@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -136,7 +136,7 @@ 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
}
@ -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) {

View file

@ -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_OPTION_NAME, false);
}
return options.getBoolean(Program.ANALYZED, false);
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;
@ -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 =

View file

@ -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);
});
}

View file

@ -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;

View file

@ -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",