diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractCInitAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractCInitAnalyzer.java deleted file mode 100644 index d8b306e816..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractCInitAnalyzer.java +++ /dev/null @@ -1,236 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.plugin.core.analysis; - -import ghidra.app.services.*; -import ghidra.app.util.importer.MessageLog; -import ghidra.framework.store.LockException; -import ghidra.program.model.address.*; -import ghidra.program.model.lang.Processor; -import ghidra.program.model.listing.*; -import ghidra.program.model.mem.*; -import ghidra.program.model.util.CodeUnitInsertionException; -import ghidra.util.Msg; -import ghidra.util.exception.AssertException; -import ghidra.util.exception.NotFoundException; -import ghidra.util.task.TaskMonitor; - -public abstract class AbstractCInitAnalyzer extends AbstractAnalyzer { - - private static final String DESCRIPTION = - "Initializes the .bss uninitilized memory using data from the .cinit section."; - - private String[] supportProcessors; - - private static final String CINIT = ".cinit"; - - public AbstractCInitAnalyzer(String analyzerName, String... supportProcessors) { - super(analyzerName, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); - this.supportProcessors = supportProcessors; - setDefaultEnablement(true); - setPriority(AnalysisPriority.FORMAT_ANALYSIS.before().before()); - } - - private boolean isSupportedProcessor(Processor processor) { - String processorName = processor.toString(); - for (String pname : supportProcessors) { - if (processorName.equals(pname)) { - return true; - } - } - return false; - } - - @Override - public boolean canAnalyze(Program p) { - if (!isSupportedProcessor(p.getLanguage().getProcessor())) { - return false; - } - Memory mem = p.getMemory(); - MemoryBlock cinitBlock = mem.getBlock(CINIT); - if (cinitBlock == null || !cinitBlock.isInitialized()) { - return false; - } - return true; - } - - public static class CInitRecord { - - private final Address cinitRecordAddr; - private final Address sourceDataAddr; - private final Address targetAddr; - private final int dataLength; - private final Address nextRecordAddr; - - /** - * Constructor - * @param cinitRecordAddr start of record address - * @param sourceDataAddr address within .cinit section where initialization - * data will be copied from - * @param targetAddr address within .bss section where initialization - * data will be copied to. A null value will cause this record - * to be skipped. - * @param dataLength number of bytes contained within initialization data - * @param nextRecordAddr address of next .cinit record - */ - public CInitRecord(Address cinitRecordAddr, Address sourceDataAddr, Address targetAddr, - int dataLength, Address nextRecordAddr) { - this.cinitRecordAddr = cinitRecordAddr; - this.sourceDataAddr = sourceDataAddr; - this.targetAddr = targetAddr; - this.dataLength = dataLength; - this.nextRecordAddr = nextRecordAddr; - } - - /** - * @return start of record address - */ - public Address getStartOfRecord() { - return cinitRecordAddr; - } - - /** - * @return true if record is terminal and contains no initialization - * data - */ - public boolean isTerminalRecord() { - return getDataLength() == 0; - } - - /** - * @return address within .bss section where initialization - * data will be copied to. A null value will cause this record - * to be skipped. - */ - public Address getTargetAddress() { - return targetAddr; - } - - /** - * @return address within .cinit section where initialization - * data will be copied from - */ - public Address getSourceDataAddress() { - return sourceDataAddr; - } - - /** - * @return number of bytes contained within initialization data - */ - public int getDataLength() { - return dataLength; - } - - /** - * @return address of next .cinit record - */ - public Address getNextRecordAddress() { - return nextRecordAddr; - } - } - - /** - * Get .cinint record and apply record data structure to program - * @param program - * @param cinitRecordAddr address of a .cinit record - * @return record object - */ - protected abstract CInitRecord getCinitRecord(Program program, Address cinitRecordAddr) - throws CodeUnitInsertionException, AddressOverflowException; - - public synchronized boolean added(Program p, AddressSetView set, TaskMonitor monitor, - MessageLog log) { - - Memory mem = p.getMemory(); - MemoryBlock cinitBlock = mem.getBlock(CINIT); - if (cinitBlock == null || !set.contains(cinitBlock.getStart())) { - return true; - } - - BookmarkManager bookmarkManager = p.getBookmarkManager(); - - Address addr = cinitBlock.getStart(); - - MemoryBlock block = null; - try { - while (addr.compareTo(cinitBlock.getEnd()) < 0) { - - CInitRecord initRec = getCinitRecord(p, addr); - if (initRec.isTerminalRecord()) { - break; - } - - addr = initRec.getNextRecordAddress(); - - Address dataAddr = initRec.getTargetAddress(); - if (dataAddr == null) { - continue; - } - - Address initDataAddr = initRec.getSourceDataAddress(); - int byteLen = initRec.getDataLength(); - - block = mem.getBlock(dataAddr); - if (block == null) { - Msg.error(this, "Failed to initialize data at " + dataAddr + - " - no memory defined"); - continue; - } - - if (!block.isInitialized()) { - mem.convertToInitialized(block, (byte) 0); - block.setWrite(true); - } - - // Read .cinit bytes and copy to intended target address - byte[] bytes = new byte[byteLen]; - if (byteLen != cinitBlock.getBytes(initDataAddr, bytes)) { - // we created data - should not have problem reading bytes - throw new MemoryAccessException("unexpected end of .cinit block"); - } - - Msg.debug(this, byteLen + "-bytes at " + dataAddr + - " initialized from .cinit data at " + initDataAddr); - - block.putBytes(dataAddr, bytes); - - bookmarkManager.setBookmark(dataAddr, BookmarkType.ANALYSIS, "Data Initilized", - byteLen + "-bytes initialized from .cinit data at " + initDataAddr); - - } - } - catch (MemoryAccessException e) { - Msg.error(this, "Error occured during block initialization: " + e.getMessage()); - } - catch (CodeUnitInsertionException e) { - Msg.error(this, "Failed to create .cinit data structure: " + e.getMessage()); - } - catch (AddressOverflowException e) { - Msg.error(this, "Unexpected end of .cinit block"); - } - catch (LockException e) { - Msg.showError(this, null, getName() + " Failed", getName() + - " requires exclusive check-out to perform " + block.getName() + - " memory block initialization"); - return false; - } - catch (NotFoundException e) { - throw new AssertException(e); // Unexpected - } - - return true; - } -} 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 7d3c399b70..3f3eb928ac 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 @@ -507,7 +507,9 @@ public class StringsAnalyzer extends AbstractAnalyzer { for (int i = 0; i < padLength; i++) { address = address.next(); - + if (address == null) { + return 0; + } CodeUnit cu = listing.getCodeUnitContaining(address); if (cu == null) { return 0; // null implies there cannot be data here diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java index 3357d8e607..4cb29b279d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java @@ -187,11 +187,10 @@ public class StringDataInstance { this.buf = buf; this.charsetName = getCharsetNameFromDataTypeOrSettings(dataType, settings); this.charSize = CharsetInfo.getInstance().getCharsetCharSize(charsetName); - // TODO: determine padding of char data type from the dataOrg() - this.paddedCharSize = charSize; // stringDataType.getPaddedCharSize(charSize); - + // NOTE: for now only handle padding for charSize == 1 + this.paddedCharSize = + charSize == 1 ? getDataOrganization(dataType).getCharSize() : charSize; this.stringLayout = getLayoutFromDataType(dataType); - this.showTranslation = TRANSLATION.isShowTranslated(settings); this.translatedValue = TRANSLATION.getTranslatedValue(settings); this.renderSetting = RENDER.getEnumValue(settings); @@ -214,6 +213,17 @@ public class StringDataInstance { this.endianSetting = copyFrom.endianSetting; } + private static DataOrganization getDataOrganization(DataType dataType) { + // The dataType should be correspond to the target program + if (dataType != null) { + DataTypeManager dtm = dataType.getDataTypeManager(); + if (dtm != null) { + return dtm.getDataOrganization(); + } + } + return DataOrganizationImpl.getDefaultOrganization(); + } + private static StringLayoutEnum getLayoutFromDataType(DataType dataType) { if (dataType instanceof AbstractStringDataType) { return ((AbstractStringDataType) dataType).getStringLayout(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/util/AcyclicCallGraphBuilder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/util/AcyclicCallGraphBuilder.java index d893398b7c..da6ba36c77 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/util/AcyclicCallGraphBuilder.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/util/AcyclicCallGraphBuilder.java @@ -66,7 +66,7 @@ public class AcyclicCallGraphBuilder { public AcyclicCallGraphBuilder(Program program, Collection functions, boolean killThunks) { this.program = program; - functionSet = new HashSet
(); + functionSet = new HashSet<>(); for (Function function : functions) { if (killThunks) { if (function.isThunk()) { @@ -87,9 +87,9 @@ public class AcyclicCallGraphBuilder { public DependencyGraph
getDependencyGraph(TaskMonitor monitor) throws CancelledException { - DependencyGraph
graph = new DependencyGraph
(); + DependencyGraph
graph = new DependencyGraph<>(); Deque
startPoints = findStartPoints(); - Set
unprocessed = new TreeSet
(functionSet); // reliable processing order + Set
unprocessed = new TreeSet<>(functionSet); // reliable processing order while (!unprocessed.isEmpty()) { monitor.checkCanceled(); @@ -111,7 +111,7 @@ public class AcyclicCallGraphBuilder { } private Deque
findStartPoints() { - Deque
startPoints = new LinkedList
(); + Deque
startPoints = new LinkedList<>(); // populate startPoints with functions that have no callers or are an entry point for (Address address : functionSet) { @@ -131,7 +131,7 @@ public class AcyclicCallGraphBuilder { node.children[0] = thunkedfunc.getEntryPoint(); return; } - ArrayList
children = new ArrayList
(); + ArrayList
children = new ArrayList<>(); ReferenceManager referenceManager = program.getReferenceManager(); AddressIterator referenceSourceIterator = referenceManager.getReferenceSourceIterator(function.getBody(), true); @@ -142,7 +142,7 @@ public class AcyclicCallGraphBuilder { Address toAddr = ref.getToAddress(); if (ref.getReferenceType().isCall()) { Function childfunc = fmanage.getFunctionAt(toAddr); - if (killThunks) { + if (childfunc != null && killThunks) { if (childfunc.isThunk()) { childfunc = childfunc.getThunkedFunction(true); toAddr = childfunc.getEntryPoint(); @@ -205,7 +205,7 @@ public class AcyclicCallGraphBuilder { private static Set
findFunctions(Program program, AddressSetView set, boolean killThunks) { - Set
functionStarts = new HashSet
(); + Set
functionStarts = new HashSet<>(); FunctionIterator functions = program.getFunctionManager().getFunctions(set, true); for (Function function : functions) { @@ -227,14 +227,15 @@ public class AcyclicCallGraphBuilder { @Override public String toString() { - return address == null ? "" : address.toString() + - (children == null ? " " : " " + Arrays.toString(children)); + return address == null ? "" + : address.toString() + + (children == null ? " " : " " + Arrays.toString(children)); } } private static class VisitStack { - private Set
inStack = new HashSet
(); - private Deque stack = new LinkedList(); + private Set
inStack = new HashSet<>(); + private Deque stack = new LinkedList<>(); public VisitStack(Address functionEntry) { push(functionEntry);