diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java index 9f9c9f4e01..aa16cb8c4d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java @@ -104,7 +104,7 @@ public class ProgramEmulationUtils { */ public static Set getRegionFlags(MemoryBlock block) { Set result = EnumSet.noneOf(TraceMemoryFlag.class); - int mask = block.getPermissions(); + int mask = block.getFlags(); if ((mask & MemoryBlock.READ) != 0) { result.add(TraceMemoryFlag.READ); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java index 4fcc08b297..69486012e9 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java @@ -18,6 +18,8 @@ package ghidra.trace.database.program; import java.io.InputStream; import java.math.BigInteger; +import javax.help.UnsupportedOperationException; + import ghidra.framework.store.LockException; import ghidra.program.model.address.*; import ghidra.trace.database.memory.DBTraceMemorySpace; @@ -57,7 +59,7 @@ public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramV } @Override - public int getPermissions() { + public int getFlags() { int bits = 0; for (TraceMemoryFlag flag : region.getFlags()) { bits |= flag.getBits(); @@ -145,4 +147,15 @@ public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramV public void setVolatile(boolean v) { region.setVolatile(v); } + + @Override + public boolean isArtificial() { + // By definition, any region present on target is non-artificial + return false; + } + + @Override + public void setArtificial(boolean a) { + throw new UnsupportedOperationException(); + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemorySpaceBlock.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemorySpaceBlock.java index 4012121576..d38679eea6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemorySpaceBlock.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemorySpaceBlock.java @@ -50,7 +50,7 @@ public class DBTraceProgramViewMemorySpaceBlock extends AbstractDBTraceProgramVi } @Override - public int getPermissions() { + public int getFlags() { return MemoryBlock.READ | MemoryBlock.WRITE | MemoryBlock.EXECUTE; } @@ -119,6 +119,16 @@ public class DBTraceProgramViewMemorySpaceBlock extends AbstractDBTraceProgramVi throw new UnsupportedOperationException(); } + @Override + public boolean isArtificial() { + return false; + } + + @Override + public void setArtificial(boolean a) { + throw new UnsupportedOperationException(); + } + @Override public String getSourceName() { return "Trace"; // TODO: What does this method actually do? diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java index d0e67cdff7..975509feef 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java @@ -116,7 +116,7 @@ public class DBTraceProgramViewRegisterMemoryBlock implements MemoryBlock { } @Override - public int getPermissions() { + public int getFlags() { return MemoryBlock.READ | MemoryBlock.WRITE; } @@ -220,6 +220,16 @@ public class DBTraceProgramViewRegisterMemoryBlock implements MemoryBlock { throw new UnsupportedOperationException(); } + @Override + public boolean isArtificial() { + return false; + } + + @Override + public void setArtificial(boolean a) { + throw new UnsupportedOperationException(); + } + @Override public String getSourceName() { return "Trace"; // TODO: What does this method actually do? diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm index af5d704f95..fdfb1e15c0 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm @@ -62,26 +62,11 @@

Overlay - Each of the above memory block types may optionally be created as an Overlay block. One or more memory blocks may be defined - within the same overlay address space. - - - An overlay memory block may be created in two ways: - *

- - - - If this option is selected, the block is created in a new - overlay address space.  Overlay blocks can serve various - purposes where a memory range may contain different data/code or map to different areas of memory - at any given point in time or processor state.   Note that - overlay blocks are fixed and may not be moved, split, merged or expanded.  In addition, Overlays - do not relocate with image base changes and have significant limitations in conjunction with + within the same overlay address space where the Overlayed Space is reflected in the memory map table. + Overlay blocks can serve various + purposes where a memory range may contain different data/code at any given point in time + or processor state.   Note that Overlay blocks + do not relocate with image base changes and have some limitations in conjunction with decompilation and analysis.

To view the Memory Map, select Window @@ -123,6 +108,9 @@

X * - Indicates execute permission.

Volatile * - Indicates a region of volatile I/O Memory.

+ +

Artificial * - Indicates an artificial memory block which has been fabricated to + facilitate analysis.

Overlayed Space - If the block is an overlay block this column indicates the name of the overlayed physical memory space. This field will be empty for non-overlay blocks.

@@ -200,6 +188,13 @@

The volatile setting of a memory block can be changed by left-clicking on the checkbox.

+ +

Change Artificial Setting

+ +
+

The artificial setting of a memory block can be changed by left-clicking on the + checkbox.

+

Initialize Memory Block

@@ -266,7 +261,11 @@

Execute - Sets the execute permission.

-

Volatile - Marks this block as volatile I/O memory.

+

Volatile - Marks a block as volatile I/O memory.

+ +

Artificial - Marks a memory block as artificial. This may be useful when a + block is required to facilitate analysis but does not exist in the same form within a + running/loaded process state.

Overlay - Creates the block as an overlay block. An overlay memory block may be created in two ways: diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png index 4d198fc7f7..a5fd31ff6f 100644 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMappedBlock.png differ diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png index 0812e81550..ac077c9b3a 100644 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/AddMemoryBlock.png differ diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png index e1614e91a3..df5b6e8c05 100644 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png and b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/images/MemoryMap.png differ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java index ef7d8aecef..d98b702b44 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/memory/AbstractAddMemoryBlockCmd.java @@ -28,7 +28,7 @@ import ghidra.util.exception.*; /** * Base command class for adding memory blocks. */ -abstract class AbstractAddMemoryBlockCmd implements Command { +public abstract class AbstractAddMemoryBlockCmd implements Command { protected String message; protected final String name; protected final String comment; @@ -42,6 +42,8 @@ abstract class AbstractAddMemoryBlockCmd implements Command { protected final boolean isVolatile; protected final boolean isOverlay; + private boolean isArtificial = false; + AbstractAddMemoryBlockCmd(String name, String comment, String source, Address start, long length, boolean read, boolean write, boolean execute, boolean isVolatile, boolean isOverlay) { @@ -57,6 +59,15 @@ abstract class AbstractAddMemoryBlockCmd implements Command { this.isOverlay = isOverlay; } + /** + * Prior to command execution the block's artificial attribute state may be specified + * and will be applied to the new memory block. + * @param a block artificial attribute state + */ + public void setArtificial(boolean a) { + isArtificial = a; + } + @Override public String getStatusMsg() { return message; @@ -67,9 +78,8 @@ abstract class AbstractAddMemoryBlockCmd implements Command { return "Add Memory Block"; } - protected abstract MemoryBlock createMemoryBlock(Memory memory) - throws LockException, MemoryConflictException, AddressOverflowException, - CancelledException; + protected abstract MemoryBlock createMemoryBlock(Memory memory) throws LockException, + MemoryConflictException, AddressOverflowException, CancelledException; @Override public boolean applyTo(DomainObject obj) { @@ -82,6 +92,7 @@ abstract class AbstractAddMemoryBlockCmd implements Command { block.setWrite(write); block.setExecute(execute); block.setVolatile(isVolatile); + block.setArtificial(isArtificial); block.setSourceName(source); renameFragment(program, block.getStart()); return true; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/memory/MemoryMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/memory/MemoryMergeManager.java index af5feab5a3..3f61909112 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/memory/MemoryMergeManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/memory/MemoryMergeManager.java @@ -196,7 +196,7 @@ public class MemoryMergeManager implements MergeResolver { if (isNameConflict(i)) { conflictList.add(new ConflictInfo(i, true, false, false)); } - if (isPermissionConflict(i)) { + if (isFlagsConflict(i)) { conflictList.add(new ConflictInfo(i, false, true, false)); } if (isCommentConflict(i)) { @@ -233,7 +233,8 @@ public class MemoryMergeManager implements MergeResolver { String myName = myBlocks[index].getName(); String origName = origBlocks[index].getName(); - if (!myName.equals(origName) && !latestName.equals(origName) && !myName.equals(latestName)) { + if (!myName.equals(origName) && !latestName.equals(origName) && + !myName.equals(latestName)) { return true; } return false; @@ -244,13 +245,12 @@ public class MemoryMergeManager implements MergeResolver { * LATEST and MY programs. * @param index block index */ - private boolean isPermissionConflict(int index) { - int latestPermissions = latestBlocks[index].getPermissions(); - int myPermissions = myBlocks[index].getPermissions(); - int origPermissions = origBlocks[index].getPermissions(); + private boolean isFlagsConflict(int index) { + int latestFlags = latestBlocks[index].getFlags(); + int myFlags = myBlocks[index].getFlags(); + int origFlags = origBlocks[index].getFlags(); - if (myPermissions != origPermissions && latestPermissions != origPermissions && - myPermissions != latestPermissions) { + if (myFlags != origFlags && latestFlags != origFlags && myFlags != latestFlags) { return true; } return false; @@ -363,27 +363,21 @@ public class MemoryMergeManager implements MergeResolver { if (info.nameConflict) { title = "Resolve Name Conflict"; - latestStr = - "Use Block name '" + latestBlocks[info.index].getName() + "' (" + - MergeConstants.LATEST_TITLE + ")"; - myStr = - "Use Block name '" + getUniqueBlockName(myBlocks[info.index].getName()) + "' (" + - MergeConstants.MY_TITLE + ")"; - origStr = - "Use Block name '" + origBlocks[info.index].getName() + "' (" + - MergeConstants.ORIGINAL_TITLE + ")"; + latestStr = "Use Block name '" + latestBlocks[info.index].getName() + "' (" + + MergeConstants.LATEST_TITLE + ")"; + myStr = "Use Block name '" + getUniqueBlockName(myBlocks[info.index].getName()) + + "' (" + MergeConstants.MY_TITLE + ")"; + origStr = "Use Block name '" + origBlocks[info.index].getName() + "' (" + + MergeConstants.ORIGINAL_TITLE + ")"; } else if (info.permissionConflict) { - title = "Resolve Permissions Conflict"; - latestStr = - "Use '" + getPermissionString(latestBlocks[info.index]) + "' (" + - MergeConstants.LATEST_TITLE + ")"; - myStr = - "Use '" + getPermissionString(myBlocks[info.index]) + "' (" + - MergeConstants.MY_TITLE + ")"; - origStr = - "Use '" + getPermissionString(origBlocks[info.index]) + "' (" + - MergeConstants.ORIGINAL_TITLE + ")"; + title = "Resolve Flags Conflict"; + latestStr = "Use '" + getFlagsString(latestBlocks[info.index]) + "' (" + + MergeConstants.LATEST_TITLE + ")"; + myStr = "Use '" + getFlagsString(myBlocks[info.index]) + "' (" + + MergeConstants.MY_TITLE + ")"; + origStr = "Use '" + getFlagsString(origBlocks[info.index]) + "' (" + + MergeConstants.ORIGINAL_TITLE + ")"; } else { // comment conflict @@ -393,7 +387,8 @@ public class MemoryMergeManager implements MergeResolver { myStr = myBlocks[info.index].getComment(); origStr = origBlocks[info.index].getComment(); } - if ((memoryDetailChoice == ASK_USER) && conflictOption == ASK_USER && mergeManager != null) { + if ((memoryDetailChoice == ASK_USER) && conflictOption == ASK_USER && + mergeManager != null) { title = title + " (Block index " + info.index + ")"; showMergePanel(panelID, title, latestStr, myStr, origStr); } @@ -428,6 +423,7 @@ public class MemoryMergeManager implements MergeResolver { resultBlocks[info.index].setWrite(sourceBlock.isWrite()); resultBlocks[info.index].setExecute(sourceBlock.isExecute()); resultBlocks[info.index].setVolatile(sourceBlock.isVolatile()); + resultBlocks[info.index].setArtificial(sourceBlock.isArtificial()); } else { resultBlocks[info.index].setComment(sourceBlock.getComment()); @@ -456,8 +452,8 @@ public class MemoryMergeManager implements MergeResolver { Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); } mergeManager.setApplyEnabled(false); - mergeManager.showComponent(mergePanel, "MemoryMerge", new HelpLocation( - HelpTopics.REPOSITORY, "MemoryConflict")); + mergeManager.showComponent(mergePanel, "MemoryMerge", + new HelpLocation(HelpTopics.REPOSITORY, "MemoryConflict")); // block until the user either cancels or hits the "Apply" button // on the merge dialog... // when the "Apply" button is hit, get the user's selection @@ -465,7 +461,7 @@ public class MemoryMergeManager implements MergeResolver { } - private String getPermissionString(MemoryBlock block) { + private String getFlagsString(MemoryBlock block) { StringBuffer sb = new StringBuffer(); sb.append("Read = "); sb.append(block.isExecute()); @@ -478,6 +474,9 @@ public class MemoryMergeManager implements MergeResolver { sb.append(", "); sb.append("Volatile = "); sb.append(block.isVolatile()); + sb.append(", "); + sb.append("Artificial = "); + sb.append(block.isArtificial()); return sb.toString(); } @@ -501,7 +500,7 @@ public class MemoryMergeManager implements MergeResolver { } } } - if (!isPermissionConflict(index)) { + if (!isFlagsConflict(index)) { boolean permission = myBlocks[index].isRead(); if (permission != origBlocks[index].isRead()) { resultBlocks[index].setRead(permission); @@ -534,6 +533,14 @@ public class MemoryMergeManager implements MergeResolver { progressUpdated = true; } } + permission = myBlocks[index].isArtificial(); + if (permission != origBlocks[index].isArtificial()) { + resultBlocks[index].setArtificial(permission); + if (!progressUpdated) { + currentMonitor.setProgress(++progressIndex); + progressUpdated = true; + } + } } if (!isCommentConflict(index)) { String myComment = myBlocks[index].getComment(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java index 03aa973861..032ae5d25c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/GolangSymbolAnalyzer.java @@ -136,7 +136,8 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { } if (analyzerOptions.propagateRtti) { - Msg.info(this, "Golang symbol analyzer: scheduling RTTI propagation after reference analysis"); + Msg.info(this, + "Golang symbol analyzer: scheduling RTTI propagation after reference analysis"); aam.schedule(new PropagateRttiBackgroundCommand(goBinary), AnalysisPriority.REFERENCE_ANALYSIS.after().priority()); } @@ -408,6 +409,7 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { MemoryBlockUtils.createUninitializedBlock(program, false, "ARTIFICAL_GOLANG_CONTEXT", mbStart, len, "Artifical memory block created to hold golang context data types", null, true, true, false, null); + newMB.setArtificial(true); return newMB.getStart(); } @@ -567,8 +569,8 @@ public class GolangSymbolAnalyzer extends AbstractAnalyzer { } record CallSiteInfo(Reference ref, Function callingFunc, Function calledFunc, - Register register, - java.util.function.Function returnTypeMapper) {} + Register register, java.util.function.Function returnTypeMapper) { + } private GoRttiMapper goBinary; private MarkupSession markupSession; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableAnalyzer.java index 1647641938..d7fa17101c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTableAnalyzer.java @@ -107,10 +107,10 @@ public class AddressTableAnalyzer extends AbstractAnalyzer { processorHasLowBitCode = PseudoDisassembler.hasLowBitCodeModeInAddrValues(program); // don't align based on instruction start rules, data is important too. // if do this, will miss, runs of ptrs to data/code/data/code/.... - // ptrAlignment = program.getLanguage().getInstructionAlignment(); - // if (processorHasLowBitCode) { - // ptrAlignment = 1; - // } + // ptrAlignment = program.getLanguage().getInstructionAlignment(); + // if (processorHasLowBitCode) { + // ptrAlignment = 1; + // } return (addrSize == 32 || addrSize == 64); } @@ -164,8 +164,9 @@ public class AddressTableAnalyzer extends AbstractAnalyzer { continue; } - Bookmark bookmark = program.getBookmarkManager().getBookmark( - tableEntry.getTopAddress(), BookmarkType.ANALYSIS, "Address Table"); + Bookmark bookmark = program.getBookmarkManager() + .getBookmark(tableEntry.getTopAddress(), BookmarkType.ANALYSIS, + "Address Table"); // nothing to see here, already done. if (!ignoreBookmarks && bookmark != null) { @@ -186,9 +187,10 @@ public class AddressTableAnalyzer extends AbstractAnalyzer { // put info bookmark in if (createBookmarksEnabled) { - program.getBookmarkManager().setBookmark(tableEntry.getTopAddress(), - BookmarkType.ANALYSIS, "Address Table", - "Address table[" + tableEntry.getNumberAddressEntries() + "] created"); + program.getBookmarkManager() + .setBookmark(tableEntry.getTopAddress(), BookmarkType.ANALYSIS, + "Address Table", "Address table[" + + tableEntry.getNumberAddressEntries() + "] created"); } // if all are valid code, disassemble @@ -268,8 +270,7 @@ public class AddressTableAnalyzer extends AbstractAnalyzer { // AddressSet badBlocks = new AddressSet(); for (MemoryBlock memoryBlock : blocks) { - if (memoryBlock.isWrite() || memoryBlock.isRead() || memoryBlock.isExecute() || - memoryBlock.isVolatile()) { + if (memoryBlock.isWrite() || memoryBlock.isRead() || memoryBlock.isExecute()) { continue; } @@ -339,15 +340,16 @@ public class AddressTableAnalyzer extends AbstractAnalyzer { AddressIterator addrIter = addrSet.getAddresses(true); long maxBytes = addrSet.getNumAddresses(); - - MemoryBufferImpl buffer = new MemoryBufferImpl(memory, addrSet.getMinAddress(), (int) (maxBytes > 1024 ? 1024 : maxBytes)); + + MemoryBufferImpl buffer = new MemoryBufferImpl(memory, addrSet.getMinAddress(), + (int) (maxBytes > 1024 ? 1024 : maxBytes)); while (addrIter.hasNext()) { Address start = addrIter.next(); // skip over anything that smells like a unicode string // - int strLen = getWStrLen(buffer, start, (int)(maxBytes / 2)); + int strLen = getWStrLen(buffer, start, (int) (maxBytes / 2)); if (strLen > 4) { int numBytes = strLen * 2; addrIter = skipBytes(addrIter, addrSet, start, numBytes); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java index 78aba20b5b..b34c472ac2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockDialog.java @@ -65,6 +65,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener { private JCheckBox writeCB; private JCheckBox executeCB; private JCheckBox volatileCB; + private JCheckBox artificialCB; private JCheckBox overlayCB; private RegisterField initialValueField; private JLabel initialValueLabel; @@ -108,6 +109,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener { writeCB.setSelected(model.isWrite()); executeCB.setSelected(model.isExecute()); volatileCB.setSelected(model.isVolatile()); + artificialCB.setSelected(model.isArtificial()); overlayCB.setSelected(model.isOverlay()); } @@ -169,6 +171,11 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener { volatileCB.setSelected(model.isVolatile()); volatileCB.addActionListener(e -> model.setVolatile(volatileCB.isSelected())); + artificialCB = new GCheckBox("Artificial"); + artificialCB.setName("Artificial"); + artificialCB.setSelected(model.isArtificial()); + artificialCB.addActionListener(e -> model.setArtificial(artificialCB.isSelected())); + overlayCB = new GCheckBox("Overlay"); overlayCB.setName("Overlay"); overlayCB.setSelected(model.isOverlay()); @@ -180,6 +187,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener { panel.add(writeCB); panel.add(executeCB); panel.add(volatileCB); + panel.add(artificialCB); panel.add(overlayCB); return panel; @@ -320,6 +328,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener { writeCB.setSelected(model.isWrite()); executeCB.setSelected(model.isExecute()); volatileCB.setSelected(model.isVolatile()); + artificialCB.setSelected(model.isArtificial()); overlayCB.setSelected(model.isOverlay()); setOkEnabled(false); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java index 469e8f1376..ecb9be0f45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/AddBlockModel.java @@ -18,7 +18,6 @@ package ghidra.app.plugin.core.memory; import javax.swing.event.ChangeListener; import ghidra.app.cmd.memory.*; -import ghidra.framework.cmd.Command; import ghidra.framework.plugintool.PluginTool; import ghidra.program.database.mem.ByteMappingScheme; import ghidra.program.database.mem.FileBytes; @@ -55,6 +54,7 @@ class AddBlockModel { private boolean isWrite; private boolean isExecute; private boolean isVolatile; + private boolean isArtificial; private InitializedType initializedType; private String comment; private FileBytes fileBytes; @@ -125,6 +125,7 @@ class AddBlockModel { isExecute = false; isVolatile = false; isOverlay = false; + isArtificial = false; schemeDestByteCount = blockType == MemoryBlockType.BIT_MAPPED ? 8 : 1; schemeSrcByteCount = 1; initializedType = InitializedType.UNINITIALIZED; @@ -148,6 +149,10 @@ class AddBlockModel { this.isVolatile = b; } + void setArtificial(boolean b) { + this.isArtificial = b; + } + void setOverlay(boolean b) { this.isOverlay = b; validateInfo(); @@ -226,6 +231,10 @@ class AddBlockModel { return isVolatile; } + boolean isArtificial() { + return isArtificial; + } + boolean isOverlay() { return isOverlay; } @@ -240,7 +249,8 @@ class AddBlockModel { if (!isValid) { return false; } - Command cmd = createAddBlockCommand(); + AbstractAddMemoryBlockCmd cmd = createAddBlockCommand(); + cmd.setArtificial(isArtificial); if (!tool.execute(cmd, program)) { message = cmd.getStatusMsg(); return false; @@ -248,7 +258,7 @@ class AddBlockModel { return true; } - Command createAddBlockCommand() { + AbstractAddMemoryBlockCmd createAddBlockCommand() { String source = ""; switch (blockType) { case BIT_MAPPED: @@ -267,7 +277,7 @@ class AddBlockModel { } } - private Command createNonMappedMemoryBlock(String source) { + private AbstractAddMemoryBlockCmd createNonMappedMemoryBlock(String source) { switch (initializedType) { case INITIALIZED_FROM_FILE_BYTES: return new AddFileBytesMemoryBlockCmd(blockName, comment, source, startAddr, length, @@ -293,8 +303,8 @@ class AddBlockModel { private void validateInfo() { message = ""; isValid = hasValidName() && hasValidStartAddress() && hasValidLength() && - hasNoMemoryConflicts() && hasMappedAddressIfNeeded() && - hasInitialValueIfNeeded() && hasFileBytesInfoIfNeeded() && isOverlayIfOtherSpace(); + hasNoMemoryConflicts() && hasMappedAddressIfNeeded() && hasInitialValueIfNeeded() && + hasFileBytesInfoIfNeeded() && isOverlayIfOtherSpace(); } private boolean hasFileBytesInfoIfNeeded() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java index 48f38bdf99..6d7f18c136 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapManager.java @@ -363,6 +363,7 @@ class MemoryMapManager { newBlock.setWrite(bigBlock.isWrite()); newBlock.setExecute(bigBlock.isExecute()); newBlock.setVolatile(bigBlock.isVolatile()); + newBlock.setArtificial(bigBlock.isArtificial()); newBlock.setSourceName("Resized Memory Block"); } else { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java index 4190477859..5bed0d0691 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java @@ -51,12 +51,13 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr final static byte WRITE = 5; final static byte EXECUTE = 6; final static byte VOLATILE = 7; - final static byte OVERLAY = 8; - final static byte BLOCK_TYPE = 9; - final static byte INIT = 10; - final static byte BYTE_SOURCE = 11; - final static byte SOURCE = 12; - final static byte COMMENT = 13; + final static byte ARTIFICIAL = 8; + final static byte OVERLAY = 9; + final static byte BLOCK_TYPE = 10; + final static byte INIT = 11; + final static byte BYTE_SOURCE = 12; + final static byte SOURCE = 13; + final static byte COMMENT = 14; final static String NAME_COL = "Name"; final static String START_COL = "Start"; @@ -66,6 +67,7 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr final static String WRITE_COL = "W"; final static String EXECUTE_COL = "X"; final static String VOLATILE_COL = "Volatile"; + final static String ARTIFICIAL_COL = "Artificial"; final static String OVERLAY_COL = "Overlayed Space"; final static String BLOCK_TYPE_COL = "Type"; final static String INIT_COL = "Initialized"; @@ -80,9 +82,9 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr private List memList; private MemoryMapProvider provider; - private final static String COLUMN_NAMES[] = - { NAME_COL, START_COL, END_COL, LENGTH_COL, READ_COL, WRITE_COL, EXECUTE_COL, VOLATILE_COL, - OVERLAY_COL, BLOCK_TYPE_COL, INIT_COL, BYTE_SOURCE_COL, SOURCE_COL, COMMENT_COL }; + private final static String COLUMN_NAMES[] = { NAME_COL, START_COL, END_COL, LENGTH_COL, + READ_COL, WRITE_COL, EXECUTE_COL, VOLATILE_COL, ARTIFICIAL_COL, OVERLAY_COL, BLOCK_TYPE_COL, + INIT_COL, BYTE_SOURCE_COL, SOURCE_COL, COMMENT_COL }; MemoryMapModel(MemoryMapProvider provider, Program program) { super(START); @@ -124,7 +126,7 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr @Override public boolean isSortable(int columnIndex) { if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE || - columnIndex == VOLATILE || columnIndex == INIT) { + columnIndex == VOLATILE || columnIndex == ARTIFICIAL || columnIndex == INIT) { return false; } return true; @@ -163,7 +165,7 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr @Override public Class getColumnClass(int columnIndex) { if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE || - columnIndex == VOLATILE || columnIndex == INIT) { + columnIndex == VOLATILE || columnIndex == ARTIFICIAL || columnIndex == INIT) { return Boolean.class; } return String.class; @@ -178,6 +180,8 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr case WRITE: case EXECUTE: case VOLATILE: + case ARTIFICIAL: + return true; case COMMENT: return true; case INIT: @@ -267,6 +271,14 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr }); break; } + case ARTIFICIAL: { + program.withTransaction("Set Artificial State", () -> { + boolean value = ((Boolean) aValue).booleanValue(); + block.setArtificial(value); + provider.setStatusText(""); + }); + break; + } case INIT: MemoryBlockType blockType = block.getType(); if (blockType == MemoryBlockType.BIT_MAPPED || @@ -428,6 +440,8 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr return block.isExecute() ? Boolean.TRUE : Boolean.FALSE; case VOLATILE: return block.isVolatile() ? Boolean.TRUE : Boolean.FALSE; + case ARTIFICIAL: + return block.isArtificial() ? Boolean.TRUE : Boolean.FALSE; case OVERLAY: return getOverlayBaseSpaceName(block); case INIT: @@ -554,29 +568,21 @@ class MemoryMapModel extends AbstractSortedTableModel implements Pr case LENGTH: return (int) (b1.getSize() - b2.getSize()); case READ: - int b1r = (b1.isRead() ? 1 : -1); - int b2r = (b2.isRead() ? 1 : -1); - return (b1r - b2r); + return Boolean.compare(b1.isRead(), b2.isRead()); case WRITE: - int b1w = (b1.isWrite() ? 1 : -1); - int b2w = (b2.isWrite() ? 1 : -1); - return (b1w - b2w); + return Boolean.compare(b1.isWrite(), b2.isWrite()); case EXECUTE: - int b1x = (b1.isExecute() ? 1 : -1); - int b2x = (b2.isExecute() ? 1 : -1); - return (b1x - b2x); + return Boolean.compare(b1.isExecute(), b2.isExecute()); case VOLATILE: - int b1v = (b1.isVolatile() ? 1 : -1); - int b2v = (b2.isVolatile() ? 1 : -1); - return (b1v - b2v); + return Boolean.compare(b1.isVolatile(), b2.isVolatile()); + case ARTIFICIAL: + return Boolean.compare(b1.isArtificial(), b2.isArtificial()); case OVERLAY: String ov1 = getOverlayBaseSpaceName(b1); String ov2 = getOverlayBaseSpaceName(b2); return ov1.compareTo(ov2); case INIT: - int b1init = (b1.isInitialized() ? 1 : -1); - int b2init = (b2.isInitialized() ? 1 : -1); - return (b1init - b2init); + return Boolean.compare(b1.isInitialized(), b2.isInitialized()); //case BYTE_SOURCE: - handled by default comparator diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java index d10b3c4dfd..6004315da1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java @@ -480,6 +480,13 @@ class MemoryMapProvider extends ComponentProviderAdapter { column.setResizable(false); } + column = table.getColumn(MemoryMapModel.ARTIFICIAL_COL); + if (column != null) { + column.setMaxWidth(65); + column.setMinWidth(65); + column.setResizable(false); + } + column = table.getColumn(MemoryMapModel.BLOCK_TYPE_COL); if (column != null) { column.setMinWidth(25); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringsAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringsAnalyzer.java index 59f5ca18fe..e386f33e77 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringsAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringsAnalyzer.java @@ -109,6 +109,7 @@ public class StringsAnalyzer extends AbstractAnalyzer { public static enum Alignment { ALIGN_1(1), ALIGN_2(2), ALIGN_4(4); + private int alignment; Alignment(int alignment) { @@ -349,7 +350,10 @@ public class StringsAnalyzer extends AbstractAnalyzer { AddressSet addresses = new AddressSet(); for (MemoryBlock memBlock : blocks) { - if (memBlock.getPermissions() > 0) { + if (!memBlock.isLoaded()) { + continue; + } + if (memBlock.isWrite() || memBlock.isRead() || memBlock.isExecute()) { addresses = addresses.union(new AddressSet(memBlock.getStart(), memBlock.getEnd())); } } @@ -581,14 +585,15 @@ public class StringsAnalyzer extends AbstractAnalyzer { modelName = options.getString(MODELFILE_OPTION_NAME, MODEL_DEFAULT_NAME); setTrigramFileName(modelName); - minStringLength = options.getEnum(MINIMUM_STRING_LENGTH_OPTION_NAME, - MINIMUM_STRING_LENGTH_DEFAULT_VALUE).getMinLength(); + minStringLength = + options.getEnum(MINIMUM_STRING_LENGTH_OPTION_NAME, MINIMUM_STRING_LENGTH_DEFAULT_VALUE) + .getMinLength(); requireNullEnd = options.getBoolean(REQUIRE_NULL_TERMINATION_OPTION_NAME, REQUIRE_NULL_TERMINATION_DEFAULT_VALUE); - startAlignment = options.getEnum(START_ALIGNMENT_OPTION_NAME, - START_ALIGNMENT_DEFAULT_VALUE).getAlignment(); + startAlignment = options.getEnum(START_ALIGNMENT_OPTION_NAME, START_ALIGNMENT_DEFAULT_VALUE) + .getAlignment(); setStringEndAlignment( options.getInt(END_ALIGNMENT_OPTION_NAME, END_ALIGNMENT_DEFAULT_VALUE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/ThreadEnvironmentBlock.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/ThreadEnvironmentBlock.java index 1eda299cb0..c2d97eabe4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/ThreadEnvironmentBlock.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/ThreadEnvironmentBlock.java @@ -706,9 +706,9 @@ public class ThreadEnvironmentBlock { * @throws CodeUnitInsertionException for problems laying down the structure on the block * @throws InvalidInputException for problems with the symbol name attached to the TEB */ - public void createBlockAndStructure() throws MemoryConflictException, LockException, - IllegalArgumentException, AddressOverflowException, CodeUnitInsertionException, - InvalidInputException { + public void createBlockAndStructure() + throws MemoryConflictException, LockException, IllegalArgumentException, + AddressOverflowException, CodeUnitInsertionException, InvalidInputException { Memory memory = program.getMemory(); MemoryBlock block = memory.getBlock(BLOCK_NAME); if (block != null) { @@ -722,6 +722,7 @@ public class ThreadEnvironmentBlock { block = memory.createUninitializedBlock(BLOCK_NAME, tebAddress, blockSize, false); } block.setWrite(true); + block.setArtificial(true); LayDownStructure laydown = new LayDownStructure(is64Bit); create(laydown); if (is64Bit) { @@ -806,6 +807,7 @@ public class ThreadEnvironmentBlock { null, false); } block1.setWrite(true); + block1.setArtificial(true); LayDownFlat laydown = new LayDownFlat(program, tebAddress, is64Bit); create(laydown); Data data = program.getListing().getDataAt(tebAddress.add(is64Bit ? 0x30 : 0x18)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java index d2841d8189..ea251ffcff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java @@ -349,6 +349,9 @@ public class CoffLoader extends AbstractLibrarySupportLoader { // assume any value in external is writable. block.setWrite(true); + // Mark block as an artificial fabrication + block.setArtificial(true); + Address current = externalAddressStart; while (current.compareTo(externalAddress) < 0) { createUndefined(program.getListing(), program.getMemory(), current, @@ -745,8 +748,8 @@ public class CoffLoader extends AbstractLibrarySupportLoader { } } - private void handleRelocationError(Program program, Address address, - Short relocationType, String message, Exception causeToReport) { + private void handleRelocationError(Program program, Address address, Short relocationType, + String message, Exception causeToReport) { String bookmarkMessage = String.format("Failed to apply COFF Relocation type 0x%x: %s", relocationType, message); program.getBookmarkManager() diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java index 186a116582..ddbdd50868 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java @@ -1546,6 +1546,10 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { // assume any value in external is writable. block.setWrite(true); + + // Mark block as an artificial fabrication + block.setArtificial(true); + block.setSourceName(BLOCK_SOURCE_NAME); block.setComment( "NOTE: This block is artificial and allows ELF Relocations to work correctly"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java index 5561843494..3ea9c5c61f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java @@ -105,8 +105,8 @@ public class MachoProgramBuilder { */ public static void buildProgram(Program program, ByteProvider provider, FileBytes fileBytes, MessageLog log, TaskMonitor monitor) throws Exception { - MachoProgramBuilder machoProgramBuilder = new MachoProgramBuilder(program, provider, - fileBytes, log, monitor); + MachoProgramBuilder machoProgramBuilder = + new MachoProgramBuilder(program, provider, fileBytes, log, monitor); machoProgramBuilder.build(); } @@ -154,7 +154,7 @@ public class MachoProgramBuilder { fixupProgramTree(null); // should be done last to account for new memory blocks setCompiler(); } - + /** * Sets the image base * @@ -339,8 +339,7 @@ public class MachoProgramBuilder { * @param suffix An optional suffix that will get appended to tree segment and segment nodes * @throws Exception if there was a problem fixing up the Program Tree */ - protected void fixupProgramTree(String suffix) - throws Exception { + protected void fixupProgramTree(String suffix) throws Exception { if (suffix == null) { suffix = ""; } @@ -399,7 +398,7 @@ public class MachoProgramBuilder { section.getSectionName() + suffix)); sectionFragment.move(sectionStart, sectionEnd); } - + // If the sections fully filled the segment, we can remove the now-empty segment if (segmentFragment.isEmpty()) { segmentModule.removeChild(segmentFragment.getName()); @@ -456,7 +455,7 @@ public class MachoProgramBuilder { log.appendMsg("Unable to determine entry point."); } } - + protected boolean processExports(MachHeader header) throws Exception { monitor.setMessage("Processing exports..."); @@ -501,7 +500,7 @@ public class MachoProgramBuilder { } return !exports.isEmpty(); - } + } protected void processNewExport(Address baseAddr, ExportEntry export, String name) throws AddressOutOfBoundsException, Exception { @@ -680,6 +679,10 @@ public class MachoProgramBuilder { start, undefinedSymbols.size() * machoHeader.getAddressSize(), false); // assume any value in external is writable. block.setWrite(true); + + // Mark block as an artificial fabrication + block.setArtificial(true); + block.setSourceName(BLOCK_SOURCE_NAME); block.setComment( "NOTE: This block is artificial and is used to make relocations work correctly"); @@ -792,14 +795,15 @@ public class MachoProgramBuilder { } } - private void processBindings(BindingTable bindingTable, List libraryPaths) throws Exception { + private void processBindings(BindingTable bindingTable, List libraryPaths) + throws Exception { DataConverter converter = DataConverter.getInstance(program.getLanguage().isBigEndian()); SymbolTable symbolTable = program.getSymbolTable(); List bindings = bindingTable.getBindings(); List threadedBindings = bindingTable.getThreadedBindings(); List segments = machoHeader.getAllSegments(); - + if (threadedBindings != null) { DyldChainedFixups dyldChainedFixups = new DyldChainedFixups(program, machoHeader, libraryPaths, log, monitor); @@ -834,7 +838,7 @@ public class MachoProgramBuilder { Address addr = space.getAddress(segments.get(binding.getSegmentIndex()).getVMaddress() + binding.getSegmentOffset()); - + fixupExternalLibrary(binding.getLibraryOrdinal(), symbol, libraryPaths); boolean success = false; @@ -1103,16 +1107,16 @@ public class MachoProgramBuilder { } /** - * Processes the section relocations from all {@link Section}s. - * - * @throws CancelledException if the operation was cancelled. - */ - protected void processSectionRelocations() throws CancelledException { - monitor.setMessage("Processing section relocations..."); + * Processes the section relocations from all {@link Section}s. + * + * @throws CancelledException if the operation was cancelled. + */ + protected void processSectionRelocations() throws CancelledException { + monitor.setMessage("Processing section relocations..."); LinkedHashMap relocationMap = new LinkedHashMap<>(); - for (Section section : machoHeader.getAllSections()) { - monitor.checkCancelled(); + for (Section section : machoHeader.getAllSections()) { + monitor.checkCancelled(); MemoryBlock sectionMemoryBlock = getMemoryBlock(section); if (sectionMemoryBlock == null) { @@ -1124,54 +1128,54 @@ public class MachoProgramBuilder { } for (RelocationInfo relocationInfo : section.getRelocations()) { - monitor.checkCancelled(); + monitor.checkCancelled(); Address address = sectionMemoryBlock.getStart().add(relocationInfo.getAddress()); relocationMap.put(relocationInfo, address); } } - performRelocations(relocationMap); + performRelocations(relocationMap); } /** - * Processes the external relocations from all {@link DynamicSymbolTableCommand}s. - * - * @throws CancelledException if the operation was cancelled. - */ - protected void processExternalRelocations() throws CancelledException { + * Processes the external relocations from all {@link DynamicSymbolTableCommand}s. + * + * @throws CancelledException if the operation was cancelled. + */ + protected void processExternalRelocations() throws CancelledException { monitor.setMessage("Processing external relocations..."); LinkedHashMap relocationMap = new LinkedHashMap<>(); - for (DynamicSymbolTableCommand cmd : machoHeader - .getLoadCommands(DynamicSymbolTableCommand.class)) { - monitor.checkCancelled(); - for (RelocationInfo relocationInfo : cmd.getExternalRelocations()) { - monitor.checkCancelled(); - relocationMap.put(relocationInfo, space.getAddress(relocationInfo.getAddress())); - } - } - performRelocations(relocationMap); + for (DynamicSymbolTableCommand cmd : machoHeader + .getLoadCommands(DynamicSymbolTableCommand.class)) { + monitor.checkCancelled(); + for (RelocationInfo relocationInfo : cmd.getExternalRelocations()) { + monitor.checkCancelled(); + relocationMap.put(relocationInfo, space.getAddress(relocationInfo.getAddress())); + } + } + performRelocations(relocationMap); } /** - * Processes the local relocations from all {@link DynamicSymbolTableCommand}s. - * - * @throws CancelledException if the operation was cancelled. - */ - protected void processLocalRelocations() throws CancelledException { + * Processes the local relocations from all {@link DynamicSymbolTableCommand}s. + * + * @throws CancelledException if the operation was cancelled. + */ + protected void processLocalRelocations() throws CancelledException { monitor.setMessage("Processing local relocations..."); LinkedHashMap relocationMap = new LinkedHashMap<>(); - for (DynamicSymbolTableCommand cmd : machoHeader - .getLoadCommands(DynamicSymbolTableCommand.class)) { - monitor.checkCancelled(); - for (RelocationInfo relocationInfo : cmd.getLocalRelocations()) { - monitor.checkCancelled(); - relocationMap.put(relocationInfo, space.getAddress(relocationInfo.getAddress())); - } - } - performRelocations(relocationMap); + for (DynamicSymbolTableCommand cmd : machoHeader + .getLoadCommands(DynamicSymbolTableCommand.class)) { + monitor.checkCancelled(); + for (RelocationInfo relocationInfo : cmd.getLocalRelocations()) { + monitor.checkCancelled(); + relocationMap.put(relocationInfo, space.getAddress(relocationInfo.getAddress())); + } + } + performRelocations(relocationMap); } protected List processLibraries() throws Exception { @@ -1215,7 +1219,7 @@ public class MachoProgramBuilder { if (program.getSymbolTable().getLibrarySymbol(Library.UNKNOWN) == null) { program.getSymbolTable().createExternalLibrary(Library.UNKNOWN, SourceType.IMPORTED); } - + return libraryPaths; } @@ -1257,23 +1261,23 @@ public class MachoProgramBuilder { * @throws CancelledException if the operation was cancelled. */ private void performRelocations(LinkedHashMap relocationMap) - throws CancelledException { + throws CancelledException { if (relocationMap.isEmpty()) { return; } - MachoRelocationHandler handler = MachoRelocationHandlerFactory.getHandler(machoHeader); + MachoRelocationHandler handler = MachoRelocationHandlerFactory.getHandler(machoHeader); if (handler == null) { log.appendMsg(String.format("No relocation handler for machine type 0x%x", machoHeader.getCpuType())); } - Iterator iter = relocationMap.keySet().iterator(); - while (iter.hasNext()) { - RelocationInfo relocationInfo = iter.next(); - Address address = relocationMap.get(relocationInfo); - MachoRelocation relocation = null; + Iterator iter = relocationMap.keySet().iterator(); + while (iter.hasNext()) { + RelocationInfo relocationInfo = iter.next(); + Address address = relocationMap.get(relocationInfo); + MachoRelocation relocation = null; RelocationResult result = RelocationResult.FAILURE; if (handler != null) { @@ -1281,7 +1285,7 @@ public class MachoProgramBuilder { ? new MachoRelocation(program, machoHeader, address, relocationInfo, iter.next()) : new MachoRelocation(program, machoHeader, address, relocationInfo); - try { + try { result = handler.relocate(relocation); if (result.status() == Status.UNSUPPORTED) { @@ -1291,9 +1295,9 @@ public class MachoProgramBuilder { } } catch (MemoryAccessException e) { - handleRelocationError(address, String.format( + handleRelocationError(address, String.format( "Relocation failure at address %s: error accessing memory.", address)); - } + } catch (RelocationException e) { handleRelocationError(address, String.format( "Relocation failure at address %s: %s", address, e.getMessage())); @@ -1306,18 +1310,19 @@ public class MachoProgramBuilder { msg = String.format("Relocation failure at address %s: %s", address, msg); handleRelocationError(address, msg); Msg.error(this, msg, e); - } + } } program.getRelocationTable() .add(address, result.status(), relocationInfo.getType(), - new long[] { relocationInfo.getValue(), - relocationInfo.getLength(), relocationInfo.isPcRelocated() ? 1 : 0, - relocationInfo.isExternal() ? 1 : 0, relocationInfo.isScattered() ? 1 : 0 }, + new long[] { relocationInfo.getValue(), relocationInfo.getLength(), + relocationInfo.isPcRelocated() ? 1 : 0, + relocationInfo.isExternal() ? 1 : 0, + relocationInfo.isScattered() ? 1 : 0 }, result.byteLength(), relocation != null ? relocation.getTargetDescription() : null); } } - + /** * Marks up {@link LoadCommand} dadta * @@ -1338,10 +1343,10 @@ public class MachoProgramBuilder { * @param message The error message */ private void handleRelocationError(Address address, String message) { - program.getBookmarkManager() - .setBookmark(address, BookmarkType.ERROR, "Relocations", message); - log.appendMsg(message); - } + program.getBookmarkManager() + .setBookmark(address, BookmarkType.ERROR, "Relocations", message); + log.appendMsg(message); + } private void addLibrary(String library) { library = library.replaceAll(" ", "_"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java index a0a38f7e53..1c20444cba 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java @@ -256,8 +256,8 @@ public class NeLoader extends AbstractOrdinalSupportLoader { } MemoryBlock block; if (length > 0) { - block = MemoryBlockUtils.createInitializedBlock(program, false, - name, addr, fileBytes, offset, length, "", "", r, w, x, log); + block = MemoryBlockUtils.createInitializedBlock(program, false, name, addr, + fileBytes, offset, length, "", "", r, w, x, log); if (length < minalloc) { // Things actually rely on the block being padded out with real 0's, so we // must expand it @@ -354,8 +354,7 @@ public class NeLoader extends AbstractOrdinalSupportLoader { int length = resource.getFileLengthShifted(); if (length > 0) { MemoryBlockUtils.createInitializedBlock(program, false, "Rsrc" + (id++), - addr, fileBytes, offset, length, "", "", true, - false, false, log); + addr, fileBytes, offset, length, "", "", true, false, false, log); } } catch (AddressOverflowException e) { @@ -445,8 +444,12 @@ public class NeLoader extends AbstractOrdinalSupportLoader { String comment = ""; String source = ""; // This isn't a real block, just place holder addresses, so don't create an initialized block - MemoryBlockUtils.createUninitializedBlock(program, false, MemoryBlock.EXTERNAL_BLOCK_NAME, - addr, length, comment, source, true, false, false, log); + MemoryBlock block = MemoryBlockUtils.createUninitializedBlock(program, false, + MemoryBlock.EXTERNAL_BLOCK_NAME, addr, length, comment, source, true, false, false, + log); + + // Mark block as an artificial fabrication + block.setArtificial(true); for (int i = 0; i < names.length; ++i) { String moduleName = names[i].getString(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java index b5d0fb9cfb..50c6ffd37d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java @@ -204,7 +204,7 @@ public class OmfLoader extends AbstractProgramWrapperLoader { int method, index, locationType = -1; locAddress = null; - if(fixup.getDataBlock() == null) { + if (fixup.getDataBlock() == null) { continue; // If no data block don't try to fixup } try { @@ -613,6 +613,9 @@ public class OmfLoader extends AbstractProgramWrapperLoader { // assume any value in external is writable. block.setWrite(true); + // Mark block as an artificial fabrication + block.setArtificial(true); + Address current = externalAddressStart; while (current.compareTo(externalAddress) < 0) { createUndefined(program.getListing(), program.getMemory(), current, diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java index d41c30ae83..eb5ea454b8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MemoryMapXmlMgr.java @@ -52,8 +52,7 @@ class MemoryMapXmlMgr { /////////////////////////////////////////////////////////////////////////////////////// void read(XmlPullParser parser, boolean overwriteConflicts, TaskMonitor monitor, - String directory) - throws SAXParseException, FileNotFoundException, CancelledException { + String directory) throws SAXParseException, FileNotFoundException, CancelledException { XmlElement element = parser.next(); element = parser.next(); @@ -71,8 +70,7 @@ class MemoryMapXmlMgr { } private void processMemoryBlock(XmlElement memorySectionElement, XmlPullParser parser, - String directory, Program program, TaskMonitor monitor) - throws FileNotFoundException { + String directory, Program program, TaskMonitor monitor) throws FileNotFoundException { String name = memorySectionElement.getAttribute("NAME"); String addrStr = memorySectionElement.getAttribute("START_ADDR"); @@ -91,6 +89,9 @@ class MemoryMapXmlMgr { String volatility = memorySectionElement.getAttribute("VOLATILE"); boolean isVolatile = "y".equals(volatility); + String artificial = memorySectionElement.getAttribute("ARTIFICIAL"); + boolean isArtificial = "y".equals(artificial); + String comment = memorySectionElement.getAttribute("COMMENT"); try { @@ -124,12 +125,12 @@ class MemoryMapXmlMgr { element = parser.peek();//get next start of contents or end of section } if (overlayName != null) { - MemoryBlock block = - MemoryBlockUtils.createInitializedBlock(program, true, overlayName, addr, - new ByteArrayInputStream(bytes), - bytes.length, comment, null, r, w, x, log, monitor); + MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, true, + overlayName, addr, new ByteArrayInputStream(bytes), bytes.length, comment, + null, r, w, x, log, monitor); if (block != null) { block.setVolatile(isVolatile); + block.setArtificial(isArtificial); if (!name.equals(overlayName)) { block.setName(name); } @@ -138,8 +139,8 @@ class MemoryMapXmlMgr { else { MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false, - name, addr, new ByteArrayInputStream(bytes), bytes.length, comment, null, - r, w, x, log, monitor); + name, addr, new ByteArrayInputStream(bytes), bytes.length, comment, null, r, + w, x, log, monitor); if (block != null) { block.setVolatile(isVolatile); } @@ -297,6 +298,10 @@ class MemoryMapXmlMgr { attrs.addAttribute("VOLATILE", true); } + if (block.isArtificial()) { + attrs.addAttribute("ARTIFICIAL", true); + } + writer.startElement("MEMORY_SECTION", attrs); if (block.getType() == MemoryBlockType.BIT_MAPPED) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryBlockDiff.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryBlockDiff.java index 3d3e925928..6a2ffaa530 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryBlockDiff.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryBlockDiff.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +22,8 @@ import ghidra.util.SystemUtilities; * MemoryBlockDiff determines the types of differences between two memory blocks. */ public class MemoryBlockDiff { - + + //@formatter:off public static final int NAME = 0x001; public static final int START_ADDRESS = 0x002; public static final int END_ADDRESS = 0x004; @@ -32,16 +32,18 @@ public class MemoryBlockDiff { public static final int WRITE = 0x020; public static final int EXECUTE = 0x040; public static final int VOLATILE = 0x080; - public static final int TYPE = 0x100; - public static final int INIT = 0x200; - public static final int SOURCE = 0x400; - public static final int COMMENT = 0x800; - public static final int ALL = 0xFFF; - + public static final int ARTIFICIAL = 0x100; + public static final int TYPE = 0x200; + public static final int INIT = 0x400; + public static final int SOURCE = 0x800; + public static final int COMMENT = 0x1000; + public static final int ALL = 0x1FFF; + //@formatter:on + private MemoryBlock block1; private MemoryBlock block2; private int diffFlags; - + /** * Constructor. MemoryBlockDiff determines the types of differences * between two memory blocks. @@ -57,139 +59,149 @@ public class MemoryBlockDiff { MemoryBlock getBlock1() { return block1; } - + MemoryBlock getBlock2() { return block2; } - + /** * Returns true if the memory block names differ. */ public boolean isNameDifferent() { return (diffFlags & NAME) != 0; } - + /** * Returns true if the start addresses of the memory blocks differ. */ public boolean isStartAddressDifferent() { return (diffFlags & START_ADDRESS) != 0; } - + /** * Returns true if the end addresses of the memory blocks differ. */ public boolean isEndAddressDifferent() { return (diffFlags & END_ADDRESS) != 0; } - + /** * Returns true if the sizes of the memory blocks differ. */ public boolean isSizeDifferent() { return (diffFlags & SIZE) != 0; } - + /** * Returns true if the memory blocks Read flags differ. */ public boolean isReadDifferent() { return (diffFlags & READ) != 0; } - + /** * Returns true if the memory blocks Write flags differ. */ public boolean isWriteDifferent() { return (diffFlags & WRITE) != 0; } - + /** * Returns true if the memory blocks Execute flags differ. */ public boolean isExecDifferent() { return (diffFlags & EXECUTE) != 0; } - + /** * Returns true if the memory blocks Volatile flags differ. */ public boolean isVolatileDifferent() { return (diffFlags & VOLATILE) != 0; } - + + /** + * Returns true if the memory blocks Artificial flags differ. + */ + public boolean isArtificialDifferent() { + return (diffFlags & ARTIFICIAL) != 0; + } + /** * Returns true if the type for the memory blocks differ. */ public boolean isTypeDifferent() { return (diffFlags & TYPE) != 0; } - + /** * Returns true if the initialization of the memory blocks isn't the same. */ public boolean isInitDifferent() { return (diffFlags & INIT) != 0; } - + /** * Returns true if the source for the memory blocks differ. */ public boolean isSourceDifferent() { return (diffFlags & SOURCE) != 0; } - + /** * Returns true if the comments on the memory blocks differ. */ public boolean isCommentDifferent() { return (diffFlags & COMMENT) != 0; } - + /** * Gets a string representation of the types of memory differences for this MemoryBlockDiff. */ public String getDifferencesAsString() { StringBuffer buf = new StringBuffer(); - if((diffFlags & NAME) != 0) { + if ((diffFlags & NAME) != 0) { buf.append("Name "); } - if((diffFlags & START_ADDRESS) != 0) { + if ((diffFlags & START_ADDRESS) != 0) { buf.append("StartAddress "); } - if((diffFlags & END_ADDRESS) != 0) { + if ((diffFlags & END_ADDRESS) != 0) { buf.append("EndAddress "); } - if((diffFlags & SIZE) != 0) { + if ((diffFlags & SIZE) != 0) { buf.append("Size "); } - if((diffFlags & READ) != 0) { + if ((diffFlags & READ) != 0) { buf.append("R "); } - if((diffFlags & WRITE) != 0) { + if ((diffFlags & WRITE) != 0) { buf.append("W "); } - if((diffFlags & EXECUTE) != 0) { + if ((diffFlags & EXECUTE) != 0) { buf.append("X "); } - if((diffFlags & VOLATILE) != 0) { + if ((diffFlags & VOLATILE) != 0) { buf.append("Volatile "); } - if((diffFlags & TYPE) != 0) { + if ((diffFlags & ARTIFICIAL) != 0) { + buf.append("Artificial "); + } + if ((diffFlags & TYPE) != 0) { buf.append("Type "); } - if((diffFlags & INIT) != 0) { + if ((diffFlags & INIT) != 0) { buf.append("Initialized "); } - if((diffFlags & SOURCE) != 0) { + if ((diffFlags & SOURCE) != 0) { buf.append("Source "); } - if((diffFlags & COMMENT) != 0) { + if ((diffFlags & COMMENT) != 0) { buf.append("Comment "); } return buf.toString(); } - + /** * Gets an integer value that has bits set as flags indicating the types of differences * that exist between the two memory blocks. @@ -207,9 +219,9 @@ public class MemoryBlockDiff { if (block2 == null) { return ALL; } - + int flags = 0; - if(!block1.getName().equals(block2.getName())) { + if (!block1.getName().equals(block2.getName())) { flags |= NAME; } if (!block1.getStart().equals(block2.getStart())) { @@ -233,6 +245,9 @@ public class MemoryBlockDiff { if (block1.isVolatile() != block2.isVolatile()) { flags |= VOLATILE; } + if (block1.isArtificial() != block2.isArtificial()) { + flags |= ARTIFICIAL; + } if (!block1.getType().equals(block2.getType())) { flags |= TYPE; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java index 99a007e792..8fab4d6b42 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java @@ -31,14 +31,14 @@ import ghidra.util.task.TaskMonitor; * types of differences. */ public class MemoryDiff { - + private Program program1; private Program program2; private Memory memory1; private Memory memory2; private AddressRange[] ranges; private MemoryBlockDiff[] diffs; - + /** * Constructs an object for determining memory differences between two programs. * @param p1 the first program @@ -46,8 +46,7 @@ public class MemoryDiff { * @throws ProgramConflictException if the program memory can't be compared because the programs * are based on different languages. */ - public MemoryDiff(Program p1, Program p2) - throws ProgramConflictException { + public MemoryDiff(Program p1, Program p2) throws ProgramConflictException { program1 = p1; program2 = p2; memory1 = program1.getMemory(); @@ -55,7 +54,7 @@ public class MemoryDiff { computeRanges(); computeDifferences(); } - + /** * Gets the first program that is part of this MemoryDiff. * @return the first program @@ -63,7 +62,7 @@ public class MemoryDiff { public Program getProgram1() { return program1; } - + /** * Gets the second program that is part of this MemoryDiff. * @return the second program @@ -71,7 +70,7 @@ public class MemoryDiff { public Program getProgram2() { return program2; } - + /** * Determines the address ranges that the two programs memories must be broken into for * properly comparing the programs. Each of these address ranges will exist in the first @@ -82,12 +81,12 @@ public class MemoryDiff { ProgramMemoryComparator memComp = new ProgramMemoryComparator(program1, program2); ArrayList rangeList = new ArrayList(); AddressRangeIterator rangeIter = memComp.getAddressRanges(); - while(rangeIter.hasNext()) { + while (rangeIter.hasNext()) { rangeList.add(rangeIter.next()); } ranges = rangeList.toArray(new AddressRange[rangeList.size()]); } - + /** * Gets the number of address ranges that the two programs memories are broken into for * comparing the programs. @@ -96,7 +95,7 @@ public class MemoryDiff { public int getNumRanges() { return ranges.length; } - + /** * Gets the address range as indicated by index. The index is zero based. Address ranges are * in order from the minimum address to the maximum address range. @@ -106,7 +105,7 @@ public class MemoryDiff { public AddressRange getRange(int index) { return ranges[index]; } - + /** * Gets the memory difference flags for the address range as indicated by index. * @param index the index of the address range to get the difference flags for. @@ -115,7 +114,7 @@ public class MemoryDiff { public MemoryBlockDiff getDifferenceInfo(int index) { return diffs[index]; } - + /** * Determines the memory differences and sets the flags for each associated address range. */ @@ -128,7 +127,7 @@ public class MemoryDiff { diffs[i] = new MemoryBlockDiff(block1, block2); } } - + /** * Gets a string representation of the types of memory differences that exist for the memory * block that contains the indicated address. @@ -143,30 +142,30 @@ public class MemoryDiff { MemoryBlockDiff info = getDifferenceInfo(index); return info.getDifferencesAsString(); } - + /** * Gets the index of the address range containing the indicated address, * if it is contained in the list; - * otherwise, (-(insertion point) - 1). + * otherwise, (-(insertion point) - 1). * @param address the address whose range we are interested in finding. * @return the index of the address range. */ private int getAddressRangeIndex(Address address) { int low = 0; - int high = diffs.length-1; - + int high = diffs.length - 1; + while (low <= high) { - int mid = (low + high) >> 1; - AddressRange range = ranges[mid]; - if (range.contains(address)) { - return mid; - } - else if (address.compareTo(range.getMinAddress()) < 0) { - high = mid - 1; - } - else { - low = mid + 1; - } + int mid = (low + high) >> 1; + AddressRange range = ranges[mid]; + if (range.contains(address)) { + return mid; + } + else if (address.compareTo(range.getMinAddress()) < 0) { + high = mid - 1; + } + else { + low = mid + 1; + } } return -(low + 1); // not found. } @@ -187,7 +186,7 @@ public class MemoryDiff { } return rangeDiffs.toArray(new AddressRange[rangeDiffs.size()]); } - + /** * Determines whether the two memory blocks are the same. * @param block1 the first program's memory block @@ -201,7 +200,7 @@ public class MemoryDiff { else if (block2 == null) { return false; } - if(!block1.getName().equals(block2.getName())) { + if (!block1.getName().equals(block2.getName())) { return false; } if (!block1.getStart().equals(block2.getStart())) { @@ -213,7 +212,7 @@ public class MemoryDiff { if (block1.getSize() != block2.getSize()) { return false; } - if (block1.getPermissions() != block2.getPermissions()) { + if (block1.getFlags() != block2.getFlags()) { return false; } if (!block1.getType().equals(block2.getType())) { @@ -233,8 +232,7 @@ public class MemoryDiff { } return true; } - - + public boolean merge(int row, int mergeFields, TaskMonitor monitor) { if ((mergeFields & MemoryBlockDiff.ALL) == 0) { return false; @@ -246,8 +244,8 @@ public class MemoryDiff { MemoryBlock block1 = blockDiff.getBlock1(); MemoryBlock block2 = blockDiff.getBlock2(); AddressRange range = ranges[row]; - if (shouldMerge(mergeFields, MemoryBlockDiff.START_ADDRESS) - && blockDiff.isStartAddressDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.START_ADDRESS) && + blockDiff.isStartAddressDifferent()) { if (block1 == null) { // Add all or part of a block. Address start2 = block2.getStart(); @@ -271,7 +269,7 @@ public class MemoryDiff { return true; } catch (Exception e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); + Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); } return false; } @@ -295,64 +293,63 @@ public class MemoryDiff { memory1.removeBlock(blockToRemove, monitor); } return true; - } catch (LockException e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); - } catch (NotFoundException e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); - } catch (AddressOutOfBoundsException e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); - } catch (MemoryBlockException e) { + } + catch (LockException e) { + Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); + } + catch (NotFoundException e) { + Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); + } + catch (AddressOutOfBoundsException e) { + Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); + } + catch (MemoryBlockException e) { Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); } return false; } } - if (shouldMerge(mergeFields, MemoryBlockDiff.END_ADDRESS) - && blockDiff.isEndAddressDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.END_ADDRESS) && + blockDiff.isEndAddressDifferent()) { // TODO } - if (shouldMerge(mergeFields, MemoryBlockDiff.SIZE) - && blockDiff.isSizeDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.SIZE) && blockDiff.isSizeDifferent()) { // TODO } - if (shouldMerge(mergeFields, MemoryBlockDiff.TYPE) - && blockDiff.isTypeDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.TYPE) && blockDiff.isTypeDifferent()) { // TODO } - if (shouldMerge(mergeFields, MemoryBlockDiff.INIT) - && blockDiff.isInitDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.INIT) && blockDiff.isInitDifferent()) { // TODO } - if (shouldMerge(mergeFields, MemoryBlockDiff.NAME) - && blockDiff.isNameDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.NAME) && blockDiff.isNameDifferent()) { try { block1.setName(block2.getName()); - } catch (LockException e) { - Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); + } + catch (LockException e) { + Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); } } - if (shouldMerge(mergeFields, MemoryBlockDiff.READ) - && blockDiff.isReadDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.READ) && blockDiff.isReadDifferent()) { block1.setRead(block2.isRead()); } - if (shouldMerge(mergeFields, MemoryBlockDiff.WRITE) - && blockDiff.isWriteDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.WRITE) && blockDiff.isWriteDifferent()) { block1.setWrite(block2.isWrite()); } - if (shouldMerge(mergeFields, MemoryBlockDiff.EXECUTE) - && blockDiff.isExecDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.EXECUTE) && blockDiff.isExecDifferent()) { block1.setExecute(block2.isExecute()); } - if (shouldMerge(mergeFields, MemoryBlockDiff.VOLATILE) - && blockDiff.isVolatileDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.VOLATILE) && blockDiff.isVolatileDifferent()) { block1.setVolatile(block2.isVolatile()); } - if (shouldMerge(mergeFields, MemoryBlockDiff.SOURCE) - && blockDiff.isSourceDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.ARTIFICIAL) && + blockDiff.isArtificialDifferent()) { + block1.setArtificial(block2.isArtificial()); + } + if (shouldMerge(mergeFields, MemoryBlockDiff.SOURCE) && blockDiff.isSourceDifferent()) { block1.setSourceName(block2.getSourceName()); } - if (shouldMerge(mergeFields, MemoryBlockDiff.COMMENT) - && blockDiff.isCommentDifferent()) { + if (shouldMerge(mergeFields, MemoryBlockDiff.COMMENT) && blockDiff.isCommentDifferent()) { block1.setComment(block2.getComment()); } return true; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryTypeProgramLocationBasedTableColumn.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryTypeProgramLocationBasedTableColumn.java index 1aa42f8873..df76dc0fea 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryTypeProgramLocationBasedTableColumn.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/MemoryTypeProgramLocationBasedTableColumn.java @@ -111,6 +111,7 @@ public class MemoryTypeProgramLocationBasedTableColumn updateForWrite(block, buffy, tooltipBuffy); updateForExecute(block, buffy, tooltipBuffy); updateForVolatile(block, buffy, tooltipBuffy); + updateForArtificial(block, buffy, tooltipBuffy); } private void updateForVolatile(MemoryBlock block, StringBuilder buffy, @@ -128,6 +129,21 @@ public class MemoryTypeProgramLocationBasedTableColumn tooltipBuffy.append(HTMLUtilities.spaces(2)).append("Volatile
"); } + private void updateForArtificial(MemoryBlock block, StringBuilder buffy, + StringBuilder tooltipBuffy) { + + if (block.isArtificial()) { + buffy.append("A"); + tooltipBuffy.append(""); + } + else { + buffy.append(HTMLUtilities.colorString(disabledColor, "A")); + tooltipBuffy.append(""); + } + + tooltipBuffy.append(HTMLUtilities.spaces(2)).append("Artificial
"); + } + private void updateForExecute(MemoryBlock block, StringBuilder buffy, StringBuilder tooltipBuffy) { @@ -186,7 +202,7 @@ public class MemoryTypeProgramLocationBasedTableColumn private class MemoryTypeComparator implements Comparator { @Override public int compare(MemoryBlock o1, MemoryBlock o2) { - return o1.getPermissions() - o2.getPermissions(); + return o1.getFlags() - o2.getFlags(); } } } diff --git a/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD b/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD index d7410bd633..c0e72decdf 100644 --- a/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD +++ b/Ghidra/Features/Base/src/main/resources/PROGRAM.DTD @@ -66,6 +66,7 @@ + diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/memory/MemoryMergeManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/memory/MemoryMergeManagerTest.java index c0ba76f89b..42546aef63 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/memory/MemoryMergeManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/memory/MemoryMergeManagerTest.java @@ -219,7 +219,7 @@ public class MemoryMergeManagerTest extends AbstractMergeTest { blocks[4].setRead(false); blocks[4].setWrite(false); blocks[4].setExecute(false); - + try { blocks[4].setName("special-debug"); } @@ -269,6 +269,7 @@ public class MemoryMergeManagerTest extends AbstractMergeTest { assertTrue(!blocks[4].isWrite()); assertTrue(!blocks[4].isExecute()); assertTrue(!blocks[4].isVolatile()); + assertTrue(!blocks[4].isArtificial()); } @Test diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java index 9c1a61dd28..7bbaa46fff 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/mem/MemoryManagerTest.java @@ -239,6 +239,12 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("Hello", block1.getComment()); assertEquals(block1, mem.getBlock(addr(5))); + block1.setArtificial(false); + assertTrue(!block1.isArtificial()); + + block1.setArtificial(true); + assertTrue(block1.isArtificial()); + block1.setVolatile(false); assertTrue(!block1.isVolatile()); @@ -473,6 +479,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest { assertNotNull(newBlock); assertEquals(block.getName() + ".copy", newBlock.getName()); assertEquals(addr(500), newBlock.getStart()); + assertEquals(block.isArtificial(), newBlock.isArtificial()); assertEquals(block.isVolatile(), newBlock.isVolatile()); assertEquals(block.isExecute(), newBlock.isExecute()); assertEquals(block.isRead(), newBlock.isRead()); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java index 787e8be331..ddccdb0656 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemoryBlock.java @@ -32,7 +32,7 @@ class MyTestMemoryBlock implements MemoryBlock { } @Override - public int getPermissions() { + public int getFlags() { throw new UnsupportedOperationException(); } @@ -136,6 +136,16 @@ class MyTestMemoryBlock implements MemoryBlock { throw new UnsupportedOperationException(); } + @Override + public boolean isArtificial() { + throw new UnsupportedOperationException(); + } + + @Override + public void setArtificial(boolean a) { + throw new UnsupportedOperationException(); + } + @Override public String getSourceName() { throw new UnsupportedOperationException(); diff --git a/Ghidra/Features/Sarif/src/main/java/sarif/export/mm/ExtMemoryMap.java b/Ghidra/Features/Sarif/src/main/java/sarif/export/mm/ExtMemoryMap.java index 0abb9dcc4a..99fad1e725 100644 --- a/Ghidra/Features/Sarif/src/main/java/sarif/export/mm/ExtMemoryMap.java +++ b/Ghidra/Features/Sarif/src/main/java/sarif/export/mm/ExtMemoryMap.java @@ -30,10 +30,12 @@ public class ExtMemoryMap implements IsfObject { String kind; String comment; boolean isVolatile; + boolean isArtificial; String type; String location; - public ExtMemoryMap(AddressRange range, MemoryBlock block, MemoryMapBytesFile bf, boolean write) throws IOException { + public ExtMemoryMap(AddressRange range, MemoryBlock block, MemoryMapBytesFile bf, boolean write) + throws IOException { String permissions = ""; if (block.isRead()) { @@ -54,12 +56,17 @@ public class ExtMemoryMap implements IsfObject { if (block.isVolatile()) { isVolatile = true; } + if (block.isArtificial()) { + isArtificial = true; + } type = block.getType().name(); - if (block.getType() == MemoryBlockType.BIT_MAPPED || block.getType() == MemoryBlockType.BYTE_MAPPED) { + if (block.getType() == MemoryBlockType.BIT_MAPPED || + block.getType() == MemoryBlockType.BYTE_MAPPED) { // bit mapped blocks can only have one sub-block MemoryBlockSourceInfo info = block.getSourceInfos().get(0); location = info.getMappedRange().get().getMinAddress().toString(); - } else if (block.isInitialized() && write) { + } + else if (block.isInitialized() && write) { location = bf.getFileName() + ":" + bf.getOffset(); bf.writeBytes(range); } diff --git a/Ghidra/Features/Sarif/src/main/java/sarif/managers/MemoryMapSarifMgr.java b/Ghidra/Features/Sarif/src/main/java/sarif/managers/MemoryMapSarifMgr.java index 3d136840d9..6d2368cfe4 100644 --- a/Ghidra/Features/Sarif/src/main/java/sarif/managers/MemoryMapSarifMgr.java +++ b/Ghidra/Features/Sarif/src/main/java/sarif/managers/MemoryMapSarifMgr.java @@ -68,26 +68,27 @@ public class MemoryMapSarifMgr extends SarifMgr { //////////////////////////// @Override - public boolean read(Map result, SarifProgramOptions options, TaskMonitor monitor) - throws CancelledException { + public boolean read(Map result, SarifProgramOptions options, + TaskMonitor monitor) throws CancelledException { try { processMemoryBlock(result, programMgr.getDirectory(), program, monitor); return true; - } catch (FileNotFoundException | AddressOverflowException e) { + } + catch (FileNotFoundException | AddressOverflowException e) { log.appendException(e); } return false; } - private void processMemoryBlock(Map result, String directory, Program program, TaskMonitor monitor) - throws FileNotFoundException, AddressOverflowException { + private void processMemoryBlock(Map result, String directory, Program program, + TaskMonitor monitor) throws FileNotFoundException, AddressOverflowException { String name = (String) result.get("name"); AddressSet set = SarifUtils.getLocations(result, program, null); Address blockAddress = set.getMinAddress(); if (set.getNumAddressRanges() != 1) { - throw new RuntimeException( - "Unexpected number of ranges for block @ " + blockAddress + ": " + set.getNumAddressRanges()); + throw new RuntimeException("Unexpected number of ranges for block @ " + blockAddress + + ": " + set.getNumAddressRanges()); } int length = (int) set.getMaxAddress().subtract(blockAddress) + 1; @@ -100,6 +101,7 @@ public class MemoryMapSarifMgr extends SarifMgr { boolean x = permissions.indexOf("x") >= 0; boolean isVolatile = (boolean) result.get("isVolatile"); + boolean isArtificial = (boolean) result.get("isArtificial"); String comment = (String) result.get("comment"); String type = (String) result.get("type"); @@ -110,33 +112,41 @@ public class MemoryMapSarifMgr extends SarifMgr { MemoryBlock block = null; if (type.equals("DEFAULT")) { if (loc == null) { - block = MemoryBlockUtils.createUninitializedBlock(program, false, name, blockAddress, length, - comment, null, r, w, x, log); - } else { + block = MemoryBlockUtils.createUninitializedBlock(program, false, name, + blockAddress, length, comment, null, r, w, x, log); + } + else { String[] split = loc.split(":"); String fileName = split[0]; int fileOffset = Integer.parseInt(split[1]); byte[] bytes = setData(directory, fileName, fileOffset, length, log); - block = MemoryBlockUtils.createInitializedBlock(program, false, name, blockAddress, - new ByteArrayInputStream(bytes), bytes.length, comment, null, r, w, x, log, monitor); + block = MemoryBlockUtils.createInitializedBlock(program, false, name, + blockAddress, new ByteArrayInputStream(bytes), bytes.length, comment, null, + r, w, x, log, monitor); } - } else if (type.equals("BIT_MAPPED")) { + } + else if (type.equals("BIT_MAPPED")) { Address sourceAddr = factory.getAddress(loc); - block = MemoryBlockUtils.createBitMappedBlock(program, name, blockAddress, sourceAddr, length, comment, - comment, r, w, x, false, log); - } else if (type.equals("BYTE_MAPPED")) { + block = MemoryBlockUtils.createBitMappedBlock(program, name, blockAddress, + sourceAddr, length, comment, comment, r, w, x, false, log); + } + else if (type.equals("BYTE_MAPPED")) { Address sourceAddr = factory.getAddress(loc); - block = MemoryBlockUtils.createByteMappedBlock(program, name, blockAddress, sourceAddr, length, comment, - comment, r, w, x, false, log); - } else { + block = MemoryBlockUtils.createByteMappedBlock(program, name, blockAddress, + sourceAddr, length, comment, comment, r, w, x, false, log); + } + else { throw new RuntimeException("Unexpected type value - " + type); } if (block != null) { block.setVolatile(isVolatile); + block.setArtificial(isArtificial); } - } catch (FileNotFoundException e) { + } + catch (FileNotFoundException e) { throw e; - } catch (Exception e) { + } + catch (Exception e) { log.appendException(e); } } @@ -160,7 +170,8 @@ public class MemoryMapSarifMgr extends SarifMgr { } pos += readLen; } - } catch (IndexOutOfBoundsException e) { + } + catch (IndexOutOfBoundsException e) { log.appendMsg("Read exceeded array length " + length); } return bytes; @@ -170,8 +181,8 @@ public class MemoryMapSarifMgr extends SarifMgr { // SARIF WRITE CURRENT DTD // ///////////////////////////// - void write(JsonArray results, AddressSetView addrs, TaskMonitor monitor, boolean isWriteContents, String filePath) - throws IOException, CancelledException { + void write(JsonArray results, AddressSetView addrs, TaskMonitor monitor, + boolean isWriteContents, String filePath) throws IOException, CancelledException { monitor.setMessage("Writing MEMORY MAP ..."); List> request = new ArrayList<>(); @@ -179,7 +190,8 @@ public class MemoryMapSarifMgr extends SarifMgr { while (iter.hasNext()) { monitor.checkCancelled(); AddressRange ranges = iter.next(); - RangeBlock rb = new RangeBlock(program.getAddressFactory(), program.getMemory(), ranges); + RangeBlock rb = + new RangeBlock(program.getAddressFactory(), program.getMemory(), ranges); for (int i = 0; i < rb.getRanges().length; ++i) { AddressRange range = rb.getRanges()[i]; MemoryBlock block = rb.getBlocks()[i]; @@ -190,16 +202,19 @@ public class MemoryMapSarifMgr extends SarifMgr { try { bf = isWriteContents ? new MemoryMapBytesFile(program, filePath) : null; writeAsSARIF(request, bf, isWriteContents, results); - } finally { + } + finally { if (isWriteContents) { bf.close(); } } } - public static void writeAsSARIF(List> request, MemoryMapBytesFile bytes, - boolean isWriteContents, JsonArray results) throws IOException { - SarifMemoryMapWriter writer = new SarifMemoryMapWriter(request, null, bytes, isWriteContents); + public static void writeAsSARIF(List> request, + MemoryMapBytesFile bytes, boolean isWriteContents, JsonArray results) + throws IOException { + SarifMemoryMapWriter writer = + new SarifMemoryMapWriter(request, null, bytes, isWriteContents); new TaskLauncher(new SarifWriterTask(SUBKEY, writer, results), null); } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/validator/MemoryBlocksValidator.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/validator/MemoryBlocksValidator.java index 7b760d9d61..ed69a3200c 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/validator/MemoryBlocksValidator.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/validator/MemoryBlocksValidator.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -69,13 +68,13 @@ public class MemoryBlocksValidator extends VTPreconditionValidator { sourceProgram.getMemory().getBlock(destBlocks[i].getName()); if (matchingABlock != null) { numMatchingNames++; - int sourcePerm = matchingABlock.getPermissions(); - if (sourcePerm == destBlocks[i].getPermissions()) { + int sourceFlags = matchingABlock.getFlags(); + if (sourceFlags == destBlocks[i].getFlags()) { numMatches++; } else { warnings.append("Block " + destProgName + ":" + blockName + - " doesn't match permissions of " + sourceProgName + ":" + blockName + "\n"); + " has different flags than " + sourceProgName + ":" + blockName + "\n"); status = ConditionStatus.Warning; } } @@ -102,10 +101,12 @@ public class MemoryBlocksValidator extends VTPreconditionValidator { } } if (numMatchingNames == numBlocksNeededForPerfectMatch) { - warnings.append("\nSUMMARY: Number and names of blocks match but not all permissions match."); + warnings.append( + "\nSUMMARY: Number and names of blocks match but not all permissions match."); } else { - warnings.append("\nSUMMARY: Number, names, and permissions of blocks do not all match"); + warnings.append( + "\nSUMMARY: Number, names, and permissions of blocks do not all match"); } } return new ConditionResult(status, warnings.toString()); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java index 408335cbef..f7de363fb5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/generic/MemoryBlockDefinition.java @@ -47,7 +47,7 @@ public class MemoryBlockDefinition { private boolean readPermission = true; private boolean writePermission = true; private boolean executePermission = false; - private boolean volatilePermission = false; + private boolean isVolatile = false; /** * Construct MemoryBlockDefinition using a text-based specified. @@ -107,7 +107,7 @@ public class MemoryBlockDefinition { readPermission = mode.indexOf('r') >= 0; writePermission = mode.indexOf('w') >= 0; executePermission = mode.indexOf('x') >= 0; - volatilePermission = mode.indexOf('v') >= 0; + isVolatile = mode.indexOf('v') >= 0; } try { length = XmlUtilities.parseInt(lengthString); @@ -186,7 +186,7 @@ public class MemoryBlockDefinition { block.setRead(readPermission); block.setWrite(writePermission); block.setExecute(executePermission); - block.setVolatile(volatilePermission); + block.setVolatile(isVolatile); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java index d3558209cc..722c4faa50 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java @@ -117,8 +117,8 @@ public class MemoryBlockDB implements MemoryBlock { } @Override - public int getPermissions() { - return record.getByteValue(MemoryMapDBAdapter.PERMISSIONS_COL); + public int getFlags() { + return record.getByteValue(MemoryMapDBAdapter.FLAGS_COL); } @Override @@ -224,7 +224,7 @@ public class MemoryBlockDB implements MemoryBlock { @Override public boolean isRead() { - return (record.getByteValue(MemoryMapDBAdapter.PERMISSIONS_COL) & READ) != 0; + return (record.getByteValue(MemoryMapDBAdapter.FLAGS_COL) & READ) != 0; } @Override @@ -232,8 +232,9 @@ public class MemoryBlockDB implements MemoryBlock { memMap.lock.acquire(); try { checkValid(); - setPermissionBit(READ, r); - memMap.fireBlockChanged(this); + if (setFlagBit(READ, r)) { + memMap.fireBlockChanged(this); + } } finally { memMap.lock.release(); @@ -242,7 +243,7 @@ public class MemoryBlockDB implements MemoryBlock { @Override public boolean isWrite() { - return (record.getByteValue(MemoryMapDBAdapter.PERMISSIONS_COL) & WRITE) != 0; + return (record.getByteValue(MemoryMapDBAdapter.FLAGS_COL) & WRITE) != 0; } @Override @@ -250,8 +251,9 @@ public class MemoryBlockDB implements MemoryBlock { memMap.lock.acquire(); try { checkValid(); - setPermissionBit(WRITE, w); - memMap.fireBlockChanged(this); + if (setFlagBit(WRITE, w)) { + memMap.fireBlockChanged(this); + } } finally { memMap.lock.release(); @@ -260,7 +262,7 @@ public class MemoryBlockDB implements MemoryBlock { @Override public boolean isExecute() { - return (record.getByteValue(MemoryMapDBAdapter.PERMISSIONS_COL) & EXECUTE) != 0; + return (record.getByteValue(MemoryMapDBAdapter.FLAGS_COL) & EXECUTE) != 0; } @Override @@ -268,9 +270,10 @@ public class MemoryBlockDB implements MemoryBlock { memMap.lock.acquire(); try { checkValid(); - setPermissionBit(EXECUTE, x); - memMap.blockExecuteChanged(this); - memMap.fireBlockChanged(this); + if (setFlagBit(EXECUTE, x)) { + memMap.blockExecuteChanged(this); + memMap.fireBlockChanged(this); + } } finally { memMap.lock.release(); @@ -282,11 +285,13 @@ public class MemoryBlockDB implements MemoryBlock { memMap.lock.acquire(); try { checkValid(); - setPermissionBit(READ, read); - setPermissionBit(WRITE, write); - setPermissionBit(EXECUTE, execute); - memMap.blockExecuteChanged(this); - memMap.fireBlockChanged(this); + boolean changed = setFlagBit(READ, read); + changed |= setFlagBit(WRITE, write); + changed |= setFlagBit(EXECUTE, execute); + if (changed) { + memMap.blockExecuteChanged(this); + memMap.fireBlockChanged(this); + } } finally { memMap.lock.release(); @@ -295,7 +300,7 @@ public class MemoryBlockDB implements MemoryBlock { @Override public boolean isVolatile() { - return (record.getByteValue(MemoryMapDBAdapter.PERMISSIONS_COL) & VOLATILE) != 0; + return (record.getByteValue(MemoryMapDBAdapter.FLAGS_COL) & VOLATILE) != 0; } @Override @@ -303,8 +308,28 @@ public class MemoryBlockDB implements MemoryBlock { memMap.lock.acquire(); try { checkValid(); - setPermissionBit(VOLATILE, v); - memMap.fireBlockChanged(this); + if (setFlagBit(VOLATILE, v)) { + memMap.fireBlockChanged(this); + } + } + finally { + memMap.lock.release(); + } + } + + @Override + public boolean isArtificial() { + return (record.getByteValue(MemoryMapDBAdapter.FLAGS_COL) & ARTIFICIAL) != 0; + } + + @Override + public void setArtificial(boolean a) { + memMap.lock.acquire(); + try { + checkValid(); + if (setFlagBit(ARTIFICIAL, a)) { + memMap.fireBlockChanged(this); + } } finally { memMap.lock.release(); @@ -430,21 +455,28 @@ public class MemoryBlockDB implements MemoryBlock { } } - private void setPermissionBit(int permBitMask, boolean enable) { - byte p = record.getByteValue(MemoryMapDBAdapter.PERMISSIONS_COL); + private boolean setFlagBit(int flagBitMask, boolean enable) { + byte p = record.getByteValue(MemoryMapDBAdapter.FLAGS_COL); if (enable) { - p |= permBitMask; + if ((p & flagBitMask) == flagBitMask) { + return false; // no change + } + p |= flagBitMask; } else { - p &= ~permBitMask; + if ((p & flagBitMask) == 0) { + return false; // no change + } + p &= ~flagBitMask; } - record.setByteValue(MemoryMapDBAdapter.PERMISSIONS_COL, p); + record.setByteValue(MemoryMapDBAdapter.FLAGS_COL, p); try { adapter.updateBlockRecord(record); } catch (IOException e) { memMap.dbError(e); } + return true; } @Override @@ -634,8 +666,7 @@ public class MemoryBlockDB implements MemoryBlock { splitBlocks.addAll(subList); subList.clear(); } - return adapter.createBlock(getName() + ".split", addr, newLength, getPermissions(), - splitBlocks); + return adapter.createBlock(getName() + ".split", addr, newLength, getFlags(), splitBlocks); } private int getIndexOfSubBlockToSplit(long offset) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java index eebec0a423..6003b44fc9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java @@ -901,7 +901,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener { mappedAddr = info.getMappedRange().get().getMinAddress(); } MemoryBlockDB newBlock = adapter.createBlock(block.getType(), name, start, length, - mappedAddr, block.isInitialized(), block.getPermissions(), mappingScheme); + mappedAddr, block.isInitialized(), block.getFlags(), mappingScheme); allAddrSet.add(newBlock.getStart(), newBlock.getEnd()); initializeBlocks(); fireBlockAdded(newBlock); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapter.java index adaeabc237..9d46bfbcde 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapter.java @@ -35,7 +35,7 @@ abstract class MemoryMapDBAdapter { static final int NAME_COL = MemoryMapDBAdapterV3.V3_NAME_COL; static final int COMMENTS_COL = MemoryMapDBAdapterV3.V3_COMMENTS_COL; static final int SOURCE_COL = MemoryMapDBAdapterV3.V3_SOURCE_COL; - static final int PERMISSIONS_COL = MemoryMapDBAdapterV3.V3_PERMISSIONS_COL; + static final int FLAGS_COL = MemoryMapDBAdapterV3.V3_FLAGS_COL; static final int START_ADDR_COL = MemoryMapDBAdapterV3.V3_START_ADDR_COL; static final int LENGTH_COL = MemoryMapDBAdapterV3.V3_LENGTH_COL; static final int SEGMENT_COL = MemoryMapDBAdapterV3.V3_SEGMENT_COL; @@ -130,7 +130,7 @@ abstract class MemoryMapDBAdapter { if (block.isInitialized()) { DBBuffer buf = block.getBuffer(); newBlock = newAdapter.createInitializedBlock(block.getName(), block.getStart(), - buf, block.getPermissions()); + buf, block.getFlags()); } else { Address mappedAddress = null; @@ -141,7 +141,7 @@ abstract class MemoryMapDBAdapter { } newBlock = newAdapter.createBlock(block.getType(), block.getName(), block.getStart(), - block.getSize(), mappedAddress, false, block.getPermissions(), 0); + block.getSize(), mappedAddress, false, block.getFlags(), 0); } newBlock.setComment(block.getComment()); newBlock.setSourceName(block.getSourceName()); @@ -185,26 +185,26 @@ abstract class MemoryMapDBAdapter { * @param startAddr the start address of the block. * @param is data source or null for zero initialization * @param length size of block - * @param permissions the new block permissions + * @param flags the new block flags * @return new memory block - * @throws IOException + * @throws IOException if a database IO error occurs. * @throws AddressOverflowException if block length is too large for the underlying space */ abstract MemoryBlockDB createInitializedBlock(String name, Address startAddr, InputStream is, - long length, int permissions) throws AddressOverflowException, IOException; + long length, int flags) throws AddressOverflowException, IOException; /** * Creates a new initialized block object * @param name the name of the block * @param startAddr the start address of the block. * @param buf the DBBuffer used to hold the bytes for the block. - * @param permissions the new block permissions + * @param flags the new block flags * @return new memory block * @throws IOException if a database IO error occurs. * @throws AddressOverflowException if block length is too large for the underlying space */ abstract MemoryBlockDB createInitializedBlock(String name, Address startAddr, DBBuffer buf, - int permissions) throws AddressOverflowException, IOException; + int flags) throws AddressOverflowException, IOException; /** * Creates a new memory block that doesn't have associated bytes. @@ -216,14 +216,14 @@ abstract class MemoryMapDBAdapter { * the block. (used for bit/byte-mapped blocks only) * @param initializeBytes if true, creates a database buffer for storing the * bytes in the block (applies to initialized default blocks only) - * @param permissions the new block permissions + * @param flags the new block flags * @param encodedMappingScheme byte mapping scheme (used by byte-mapped blocks only) * @return new memory block * @throws IOException if a database IO error occurs. * @throws AddressOverflowException if block length is too large for the underlying space */ abstract MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, - long length, Address mappedAddress, boolean initializeBytes, int permissions, + long length, Address mappedAddress, boolean initializeBytes, int flags, int encodedMappingScheme) throws AddressOverflowException, IOException; /** @@ -289,13 +289,13 @@ abstract class MemoryMapDBAdapter { * @param name the name of the block * @param startAddress the start address of the block * @param length the length of the block - * @param permissions the permissions for the block + * @param flags the flags for the block * @param splitBlocks the list of subBlock objects that make up this block * @return the new MemoryBlock * @throws IOException if a database error occurs */ protected abstract MemoryBlockDB createBlock(String name, Address startAddress, long length, - int permissions, List splitBlocks) throws IOException; + int flags, List splitBlocks) throws IOException; /** * Creates a new memory block using a FileBytes @@ -304,12 +304,12 @@ abstract class MemoryMapDBAdapter { * @param length the length of the block * @param fileBytes the {@link FileBytes} object that provides the bytes for this block * @param offset the offset into the {@link FileBytes} object - * @param permissions the permissions for the block + * @param flags the flags for the block * @return the new MemoryBlock * @throws IOException if a database error occurs * @throws AddressOverflowException if block length is too large for the underlying space */ protected abstract MemoryBlockDB createFileBytesBlock(String name, Address startAddress, - long length, FileBytes fileBytes, long offset, int permissions) + long length, FileBytes fileBytes, long offset, int flags) throws IOException, AddressOverflowException; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV0.java index a34a7133f6..e7864cc245 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV0.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV0.java @@ -106,15 +106,15 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter { RecordIterator it = table.iterator(); while (it.hasNext()) { DBRecord rec = it.next(); - int permissions = 0; + int flags = 0; if (rec.getBooleanValue(V0_IS_READ_COL)) { - permissions |= MemoryBlock.READ; + flags |= MemoryBlock.READ; } if (rec.getBooleanValue(V0_IS_WRITE_COL)) { - permissions |= MemoryBlock.WRITE; + flags |= MemoryBlock.WRITE; } if (rec.getBooleanValue(V0_IS_EXECUTE_COL)) { - permissions |= MemoryBlock.EXECUTE; + flags |= MemoryBlock.EXECUTE; } Address start = addrFactory.oldGetAddressFromLong(rec.getLongValue(V0_START_ADDR_COL)); long startAddr = addrMap.getKey(start, false); @@ -131,7 +131,7 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter { blockRecord.setString(NAME_COL, rec.getString(V0_NAME_COL)); blockRecord.setString(COMMENTS_COL, rec.getString(V0_COMMENTS_COL)); blockRecord.setString(SOURCE_COL, rec.getString(V0_SOURCE_NAME_COL)); - blockRecord.setByteValue(PERMISSIONS_COL, (byte) permissions); + blockRecord.setByteValue(FLAGS_COL, (byte) flags); blockRecord.setLongValue(START_ADDR_COL, startAddr); blockRecord.setLongValue(LENGTH_COL, length); blockRecord.setIntValue(SEGMENT_COL, segment); @@ -195,13 +195,13 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter { @Override MemoryBlockDB createInitializedBlock(String name, Address startAddr, InputStream is, - long length, int permissions) throws IOException { + long length, int flags) throws IOException { throw new UnsupportedOperationException(); } @Override - MemoryBlockDB createInitializedBlock(String name, Address startAddr, DBBuffer buf, - int permissions) throws IOException { + MemoryBlockDB createInitializedBlock(String name, Address startAddr, DBBuffer buf, int flags) + throws IOException { throw new UnsupportedOperationException(); } @@ -231,8 +231,7 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter { @Override MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, - long length, Address overlayAddr, boolean initializeBytes, int permissions, - int mappingScheme) + long length, Address overlayAddr, boolean initializeBytes, int flags, int mappingScheme) throws IOException { throw new UnsupportedOperationException(); } @@ -267,14 +266,14 @@ class MemoryMapDBAdapterV0 extends MemoryMapDBAdapter { } @Override - protected MemoryBlockDB createBlock(String name, Address addr, long length, int permissions, + protected MemoryBlockDB createBlock(String name, Address addr, long length, int flags, List splitBlocks) { throw new UnsupportedOperationException(); } @Override protected MemoryBlockDB createFileBytesBlock(String name, Address startAddress, long length, - FileBytes fileBytes, long offset, int permissions) + FileBytes fileBytes, long offset, int flags) throws IOException, AddressOverflowException { throw new UnsupportedOperationException(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV1.java index 29e9bd54e9..8e4060a8cc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV1.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV1.java @@ -45,9 +45,6 @@ class MemoryMapDBAdapterV1 extends MemoryMapDBAdapterV0 { // "Source Block ID","Segment"}); // - /** - * @param handle - */ MemoryMapDBAdapterV1(DBHandle handle, MemoryMapDB memMap) throws VersionException, IOException { super(handle, memMap, VERSION); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV2.java index 00ce73cdab..35b751a29f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV2.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV2.java @@ -63,7 +63,6 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter { // new String[] { "Name", "Comments", "Source Name", "Permissions", "Start Address", // "Block Type", "Overlay Address", "Length", "Chain Buffer ID", "Segment" }); - protected MemoryMapDBAdapterV2(DBHandle handle, MemoryMapDB memMap) throws VersionException, IOException { this.handle = handle; @@ -86,7 +85,7 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter { RecordIterator it = table.iterator(); while (it.hasNext()) { DBRecord rec = it.next(); - int permissions = rec.getByteValue(V2_PERMISSIONS_COL); + int flags = rec.getByteValue(V2_PERMISSIONS_COL); long startAddr = rec.getLongValue(V2_START_ADDR_COL); long length = rec.getLongValue(V2_LENGTH_COL); @@ -99,7 +98,7 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter { blockRecord.setString(NAME_COL, rec.getString(V2_NAME_COL)); blockRecord.setString(COMMENTS_COL, rec.getString(V2_COMMENTS_COL)); blockRecord.setString(SOURCE_COL, rec.getString(V2_SOURCE_COL)); - blockRecord.setByteValue(PERMISSIONS_COL, (byte) permissions); + blockRecord.setByteValue(FLAGS_COL, (byte) flags); blockRecord.setLongValue(START_ADDR_COL, startAddr); blockRecord.setLongValue(LENGTH_COL, length); blockRecord.setIntValue(SEGMENT_COL, segment); @@ -149,22 +148,21 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter { } @Override - MemoryBlockDB createInitializedBlock(String name, Address startAddr, DBBuffer buf, - int permissions) throws AddressOverflowException, IOException { + MemoryBlockDB createInitializedBlock(String name, Address startAddr, DBBuffer buf, int flags) + throws AddressOverflowException, IOException { throw new UnsupportedOperationException(); } @Override MemoryBlockDB createInitializedBlock(String name, Address startAddr, InputStream is, - long length, int permissions) throws AddressOverflowException, IOException { + long length, int flags) throws AddressOverflowException, IOException { throw new UnsupportedOperationException(); } @Override MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, - long length, Address mappedAddress, boolean initializeBytes, int permissions, - int mappingScheme) - throws AddressOverflowException, IOException { + long length, Address mappedAddress, boolean initializeBytes, int flags, + int mappingScheme) throws AddressOverflowException, IOException { throw new UnsupportedOperationException(); } @@ -223,14 +221,14 @@ class MemoryMapDBAdapterV2 extends MemoryMapDBAdapter { } @Override - protected MemoryBlockDB createBlock(String name, Address addr, long length, int permissions, + protected MemoryBlockDB createBlock(String name, Address addr, long length, int flags, List splitBlocks) { throw new UnsupportedOperationException(); } @Override protected MemoryBlockDB createFileBytesBlock(String name, Address startAddress, long length, - FileBytes fileBytes, long offset, int permissions) + FileBytes fileBytes, long offset, int flags) throws IOException, AddressOverflowException { throw new UnsupportedOperationException(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV3.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV3.java index 7cacfc57d2..c20972a878 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV3.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDBAdapterV3.java @@ -39,7 +39,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { static final int V3_NAME_COL = 0; static final int V3_COMMENTS_COL = 1; static final int V3_SOURCE_COL = 2; - static final int V3_PERMISSIONS_COL = 3; + static final int V3_FLAGS_COL = 3; static final int V3_START_ADDR_COL = 4; static final int V3_LENGTH_COL = 5; static final int V3_SEGMENT_COL = 6; @@ -60,7 +60,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { static Schema V3_BLOCK_SCHEMA = new Schema(V3_VERSION, "Key", new Field[] { StringField.INSTANCE, StringField.INSTANCE, StringField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE }, - new String[] { "Name", "Comments", "Source Name", "Permissions", "Start Address", "Length", + new String[] { "Name", "Comments", "Source Name", "Flags", "Start Address", "Length", "Segment" }); static Schema V3_SUB_BLOCK_SCHEMA = new Schema(V3_VERSION, "Key", @@ -116,8 +116,8 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { void refreshMemory() throws IOException { Map> subBlockMap = getSubBlockMap(); - Map blockMap = memoryBlocks.stream().collect( - Collectors.toMap(MemoryBlockDB::getID, Function.identity())); + Map blockMap = memoryBlocks.stream() + .collect(Collectors.toMap(MemoryBlockDB::getID, Function.identity())); List newBlocks = new ArrayList<>(); RecordIterator it = memBlockTable.iterator(); @@ -163,14 +163,14 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { @Override MemoryBlockDB createInitializedBlock(String name, Address startAddr, InputStream is, - long length, int permissions) throws AddressOverflowException, IOException { + long length, int flags) throws AddressOverflowException, IOException { // TODO verify that it is necessary to pre-define all segments in the address map updateAddressMapForAllAddresses(startAddr, length); List subBlocks = new ArrayList<>(); try { - DBRecord blockRecord = createMemoryBlockRecord(name, startAddr, length, permissions); + DBRecord blockRecord = createMemoryBlockRecord(name, startAddr, length, flags); long key = blockRecord.getKey(); int numFullBlocks = (int) (length / maxSubBlockSize); int lastSubBlockSize = (int) (length % maxSubBlockSize); @@ -201,30 +201,30 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { @Override MemoryBlockDB createBlock(MemoryBlockType blockType, String name, Address startAddr, - long length, Address mappedAddress, boolean initializeBytes, int permissions, + long length, Address mappedAddress, boolean initializeBytes, int flags, int encodedMappingScheme) throws AddressOverflowException, IOException { if (blockType == MemoryBlockType.BIT_MAPPED) { - return createBitMappedBlock(name, startAddr, length, mappedAddress, permissions); + return createBitMappedBlock(name, startAddr, length, mappedAddress, flags); } if (blockType == MemoryBlockType.BYTE_MAPPED) { - return createByteMappedBlock(name, startAddr, length, mappedAddress, permissions, + return createByteMappedBlock(name, startAddr, length, mappedAddress, flags, encodedMappingScheme); } // DEFAULT block type if (initializeBytes) { - return createInitializedBlock(name, startAddr, null, length, permissions); + return createInitializedBlock(name, startAddr, null, length, flags); } - return createUninitializedBlock(name, startAddr, length, permissions); + return createUninitializedBlock(name, startAddr, length, flags); } @Override - MemoryBlockDB createInitializedBlock(String name, Address startAddr, DBBuffer buf, - int permissions) throws AddressOverflowException, IOException { + MemoryBlockDB createInitializedBlock(String name, Address startAddr, DBBuffer buf, int flags) + throws AddressOverflowException, IOException { updateAddressMapForAllAddresses(startAddr, buf.length()); List subBlocks = new ArrayList<>(); - DBRecord blockRecord = createMemoryBlockRecord(name, startAddr, buf.length(), permissions); + DBRecord blockRecord = createMemoryBlockRecord(name, startAddr, buf.length(), flags); long key = blockRecord.getKey(); DBRecord subRecord = @@ -239,11 +239,11 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { } MemoryBlockDB createUninitializedBlock(String name, Address startAddress, long length, - int permissions) throws IOException, AddressOverflowException { + int flags) throws IOException, AddressOverflowException { updateAddressMapForAllAddresses(startAddress, length); List subBlocks = new ArrayList<>(); - DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, permissions); + DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, flags); long key = blockRecord.getKey(); DBRecord subRecord = createSubBlockRecord(key, 0, length, V3_SUB_TYPE_UNINITIALIZED, 0, 0); @@ -256,9 +256,9 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { } @Override - protected MemoryBlockDB createBlock(String name, Address startAddress, long length, - int permissions, List splitBlocks) throws IOException { - DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, permissions); + protected MemoryBlockDB createBlock(String name, Address startAddress, long length, int flags, + List splitBlocks) throws IOException { + DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, flags); long key = blockRecord.getKey(); long startingOffset = 0; @@ -274,26 +274,26 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { } MemoryBlockDB createBitMappedBlock(String name, Address startAddress, long length, - Address mappedAddress, int permissions) throws IOException, AddressOverflowException { + Address mappedAddress, int flags) throws IOException, AddressOverflowException { return createMappedBlock(V3_SUB_TYPE_BIT_MAPPED, name, startAddress, length, mappedAddress, - permissions, 0); + flags, 0); } MemoryBlockDB createByteMappedBlock(String name, Address startAddress, long length, - Address mappedAddress, int permissions, int mappingScheme) + Address mappedAddress, int flags, int mappingScheme) throws IOException, AddressOverflowException { return createMappedBlock(V3_SUB_TYPE_BYTE_MAPPED, name, startAddress, length, mappedAddress, - permissions, mappingScheme); + flags, mappingScheme); } @Override protected MemoryBlockDB createFileBytesBlock(String name, Address startAddress, long length, - FileBytes fileBytes, long offset, int permissions) + FileBytes fileBytes, long offset, int flags) throws IOException, AddressOverflowException { updateAddressMapForAllAddresses(startAddress, length); List subBlocks = new ArrayList<>(); - DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, permissions); + DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, flags); long key = blockRecord.getKey(); DBRecord subRecord = createSubBlockRecord(key, 0, length, V3_SUB_TYPE_FILE_BYTES, @@ -307,13 +307,12 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { } private MemoryBlockDB createMappedBlock(byte type, String name, Address startAddress, - long length, Address mappedAddress, int permissions, - int mappingScheme) + long length, Address mappedAddress, int flags, int mappingScheme) throws IOException, AddressOverflowException { updateAddressMapForAllAddresses(startAddress, length); List subBlocks = new ArrayList<>(); - DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, permissions); + DBRecord blockRecord = createMemoryBlockRecord(name, startAddress, length, flags); long key = blockRecord.getKey(); long encoded = addrMap.getKey(mappedAddress, true); @@ -377,12 +376,12 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter { } private DBRecord createMemoryBlockRecord(String name, Address startAddr, long length, - int permissions) { + int flags) { DBRecord record = V3_BLOCK_SCHEMA.createRecord(memBlockTable.getKey()); record.setString(V3_NAME_COL, name); record.setLongValue(V3_START_ADDR_COL, addrMap.getKey(startAddr, true)); record.setLongValue(V3_LENGTH_COL, length); - record.setByteValue(V3_PERMISSIONS_COL, (byte) permissions); + record.setByteValue(V3_FLAGS_COL, (byte) flags); record.setIntValue(V3_SEGMENT_COL, getSegment(startAddr)); return record; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java index 946bbd6223..86033b0f93 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java @@ -46,17 +46,22 @@ public interface MemoryBlock extends Serializable, Comparable { */ public static final String EXTERNAL_BLOCK_NAME = "EXTERNAL"; - // Memory block permission bits + // Memory block flag bits + // NOTE: These are used by stored Flags with DB (8-bits) and + // should be changed other than to add values. + public static int ARTIFICIAL = 0x10; public static int VOLATILE = 0x8; public static int READ = 0x4; public static int WRITE = 0x2; public static int EXECUTE = 0x1; /** - * Returns block permissions as a bit mask. Permission bits defined as READ, WRITE, EXECUTE and - * VOLATILE + * Returns block flags (i.e., permissions and attributes) as a bit mask. + * These bits defined as {@link #READ}, {@link #WRITE}, {@link #EXECUTE}, {@link #VOLATILE}, + * {@link #ARTIFICIAL}. + * @return block flag bits */ - public int getPermissions(); + public int getFlags(); /** * Get memory data in the form of an InputStream. Null is returned for thos memory blocks which @@ -107,6 +112,8 @@ public interface MemoryBlock extends Serializable, Comparable { /** * Get the name of this block + * + * @return block name */ public String getName(); @@ -122,6 +129,8 @@ public interface MemoryBlock extends Serializable, Comparable { /** * Get the comment associated with this block. + * + * @return block comment string */ public String getComment(); @@ -134,6 +143,8 @@ public interface MemoryBlock extends Serializable, Comparable { /** * Returns the value of the read property associated with this block + * + * @return true if enabled else false */ public boolean isRead(); @@ -146,6 +157,8 @@ public interface MemoryBlock extends Serializable, Comparable { /** * Returns the value of the write property associated with this block + * + * @return true if enabled else false */ public boolean isWrite(); @@ -158,6 +171,8 @@ public interface MemoryBlock extends Serializable, Comparable { /** * Returns the value of the execute property associated with this block + * + * @return true if enabled else false */ public boolean isExecute(); @@ -178,18 +193,41 @@ public interface MemoryBlock extends Serializable, Comparable { public void setPermissions(boolean read, boolean write, boolean execute); /** - * Returns the value of the volatile property associated with this block. This attribute is + * Returns the volatile attribute state of this block. This attribute is * generally associated with block of I/O regions of memory. + * + * @return true if enabled else false */ public boolean isVolatile(); /** - * Sets the volatile property associated with this block. + * Sets the volatile attribute state associated of this block. This attribute is + * generally associated with block of I/O regions of memory. * - * @param v the value to set the volatile property to. + * @param v the volatile attribute state. */ public void setVolatile(boolean v); + /** + * Returns the artificial attribute state of this block. This attribute is + * generally associated with blocks which have been fabricated to facilitate + * analysis but do not exist in the same form within a running/loaded process + * state. + * + * @return true if enabled else false + */ + public boolean isArtificial(); + + /** + * Sets the artificial attribute state associated with this block. This attribute is + * generally associated with blocks which have been fabricated to facilitate + * analysis but do not exist in the same form within a running/loaded process + * state. + * + * @param a the artificial attribute state. + */ + public void setArtificial(boolean a); + /** * Get the name of the source of this memory block. * @@ -208,6 +246,7 @@ public interface MemoryBlock extends Serializable, Comparable { * Returns the byte at the given address in this block. * * @param addr the address. + * @return byte value from this block and specified address * @throws MemoryAccessException if any of the requested bytes are uninitialized. * @throws IllegalArgumentException if the Address is not in this block. */ @@ -246,6 +285,7 @@ public interface MemoryBlock extends Serializable, Comparable { * Puts the given byte at the given address in this block. * * @param addr the address. + * @param b byte value * @throws MemoryAccessException if the block is uninitialized * @throws IllegalArgumentException if the Address is not in this block. */ diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java index 6be0695ec5..986840fc30 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java @@ -46,7 +46,7 @@ public class MemoryBlockStub implements MemoryBlock { } @Override - public int getPermissions() { + public int getFlags() { throw new UnsupportedOperationException(); } @@ -150,6 +150,16 @@ public class MemoryBlockStub implements MemoryBlock { throw new UnsupportedOperationException(); } + @Override + public boolean isArtificial() { + throw new UnsupportedOperationException(); + } + + @Override + public void setArtificial(boolean a) { + throw new UnsupportedOperationException(); + } + @Override public boolean isOverlay() { return false; diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/mem/MemBlockDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/mem/MemBlockDBTest.java index f676677139..78bbaea4a9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/mem/MemBlockDBTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/mem/MemBlockDBTest.java @@ -92,7 +92,7 @@ public class MemBlockDBTest extends AbstractGenericTest { assertEquals(false, block.isMapped()); assertNull(block.getComment()); assertNull(block.getSourceName()); - assertEquals(MemoryBlock.READ, block.getPermissions()); + assertEquals(MemoryBlock.READ, block.getFlags()); List sourceInfos = block.getSourceInfos(); @@ -192,7 +192,7 @@ public class MemBlockDBTest extends AbstractGenericTest { assertEquals(true, block.isMapped()); assertNull(block.getComment()); assertNull(block.getSourceName()); - assertEquals(MemoryBlock.READ, block.getPermissions()); + assertEquals(MemoryBlock.READ, block.getFlags()); List sourceInfos = block.getSourceInfos(); @@ -228,7 +228,7 @@ public class MemBlockDBTest extends AbstractGenericTest { assertEquals(true, block.isMapped()); assertNull(block.getComment()); assertNull(block.getSourceName()); - assertEquals(MemoryBlock.READ, block.getPermissions()); + assertEquals(MemoryBlock.READ, block.getFlags()); List sourceInfos = block.getSourceInfos(); @@ -264,7 +264,7 @@ public class MemBlockDBTest extends AbstractGenericTest { assertEquals(false, block.isMapped()); assertNull(block.getComment()); assertNull(block.getSourceName()); - assertEquals(MemoryBlock.READ, block.getPermissions()); + assertEquals(MemoryBlock.READ, block.getFlags()); List sourceInfos = block.getSourceInfos(); diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationContext.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationContext.java index ac88f85aa0..a7f4416720 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationContext.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationContext.java @@ -310,6 +310,10 @@ class MIPS_ElfRelocationContext extends ElfRelocationContext