diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java index bff3212273a..3d341207ae0 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java @@ -580,7 +580,7 @@ boolean isReadOnly() { boolean isVersioned() { synchronized (fileSystem) { if (versionedFolderItem == null) { - return false; + return isCheckedOut(); } return !isHijacked(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java index 992e326e2e5..bc6386b766b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java @@ -284,7 +284,7 @@ public ProgramDB(DBHandle dbh, int openMode, TaskMonitor monitor, Object consume if (monitor == null) { monitor = TaskMonitorAdapter.DUMMY; } - + boolean success = false; try { int id = startTransaction("create program"); @@ -2284,8 +2284,9 @@ public void setLanguage(Language newLanguage, CompilerSpecID newCompilerSpecID, * Translate language * @param translator language translator, if null only re-disassembly will occur. * @param newCompilerSpecID new compiler specification which corresponds to new language, may be null. - * @param monitor - * @throws LockException + * @param forceRedisassembly if true a redisassembly will be forced even if not required + * @param monitor task monitor + * @throws LockException if exclusive access is missing */ public void setLanguage(LanguageTranslator translator, CompilerSpecID newCompilerSpecID, boolean forceRedisassembly, TaskMonitor monitor) throws LockException { @@ -2296,7 +2297,7 @@ public void setLanguage(LanguageTranslator translator, CompilerSpecID newCompile try { setEventsEnabled(false); try { - boolean notifyCodeManager = true; + boolean redisassemblyRequired = true; int oldLanguageVersion = languageVersion; int oldLanguageMinorVersion = languageMinorVersion; if (translator != null) { @@ -2311,7 +2312,7 @@ public void setLanguage(LanguageTranslator translator, CompilerSpecID newCompile } else if (!forceRedisassembly && language.getVersion() == languageVersion && language.getMinorVersion() == languageMinorVersion) { - notifyCodeManager = false; // compiler spec change only + redisassemblyRequired = false; // compiler spec change only Msg.info(this, "Setting compiler spec for Program " + getName() + ": " + compilerSpecID + " -> " + newCompilerSpecID); } @@ -2350,15 +2351,14 @@ else if (!forceRedisassembly && language.getVersion() == languageVersion && monitor.setProgress(0); ProgramRegisterContextDB contextMgr = (ProgramRegisterContextDB) getProgramContext(); - if (translator != null) { + if (redisassemblyRequired) { contextMgr.setLanguage(translator, compilerSpec, memoryManager, monitor); } else { - // force re-initialization contextMgr.initializeDefaultValues(language, compilerSpec); } - if (notifyCodeManager) { + if (redisassemblyRequired) { Disassembler.clearUnimplementedPcodeWarnings(this, null, monitor); repairContext(oldLanguageVersion, oldLanguageMinorVersion, translator, monitor); monitor.setMessage("Updating instructions..."); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java index 1249c92d968..2cd68cb0ee4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java @@ -72,12 +72,12 @@ public ProgramRegisterContextDB(DBHandle dbHandle, ErrorHandler errHandler, Lang } if (openMode == DBConstants.UPGRADE && oldContextDataExists) { -// TODO: Make sure upgrade is working correctly before uncommenting -// try { -// OldProgramContextDB.removeOldContextData(dbHandle); -// } catch (IOException e) { -// errorHandler.dbError(e); -// } + try { + OldProgramContextDB.removeOldContextData(dbHandle); + } + catch (IOException e) { + errorHandler.dbError(e); + } } } @@ -161,6 +161,12 @@ private void initializedCurrentValues() { } } + /** + * Intialize context with default values defined by pspec and cspec. + * NOTE: cspec values take precedence + * @param lang processor language + * @param compilerSpec compiler specification + */ public void initializeDefaultValues(Language lang, CompilerSpec compilerSpec) { defaultRegisterValueMap.clear(); lang.applyContextSettings(this); @@ -288,9 +294,31 @@ public void setRegisterValue(Address start, Address end, RegisterValue value) } } + /** + * Perform context upgrade due to a language change + * @param translator language translator required by major upgrades (may be null) + * @param newCompilerSpec new compiler specification + * @param programMemory program memory + * @param monitor task monitor + * @throws CancelledException thrown if monitor cancelled + */ public void setLanguage(LanguageTranslator translator, CompilerSpec newCompilerSpec, AddressSetView programMemory, TaskMonitor monitor) throws CancelledException { + if (translator == null) { + Language lang = program.getLanguage(); + boolean clearContext = Boolean.valueOf( + lang.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE)); + if (clearContext) { + RegisterValueStore store = registerValueMap.get(baseContextRegister); + if (store != null) { + store.clearAll(); + } + } + initializeDefaultValues(lang, newCompilerSpec); + return; + } + Language newLanguage = translator.getNewLanguage(); // Sort the registers by size so that largest come first. @@ -309,8 +337,11 @@ public void setLanguage(LanguageTranslator translator, CompilerSpec newCompilerS continue; } + boolean clearContext = register.isProcessorContext() && Boolean.valueOf( + newLanguage.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE)); + // Update storage range map - if (!store.setLanguage(translator, monitor)) { + if (clearContext || !store.setLanguage(translator, monitor)) { // Clear and remove old register value store Msg.warn(this, "WARNING! Discarding all context for register " + register.getName()); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java index c438fb4d764..37c7ecf0859 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java @@ -112,4 +112,11 @@ private GhidraLanguagePropertyKeys() { * following the call. Non-returning functions can be detected in many cases. */ public static final String ENABLE_NO_RETURN_ANALYSIS = "enableNoReturnAnalysis"; + + /** + * Property to indicate that all stored instruction context should be cleared + * during a language upgrade operation which requires redisassembly. + * NOTE: This is an experimental concept which may be removed in the future + */ + public static final String RESET_CONTEXT_ON_UPGRADE = "resetContextOnUpgrade"; }