mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-01-31 13:31:08 +00:00
GP-1793 - Updated the decompiler hover for structure fields to show the parent name and the offset in the parent
This commit is contained in:
parent
385529aa08
commit
c4054de5db
@ -215,7 +215,7 @@ public class DecompilerUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the function represented by the given token. This will be either the
|
||||
* Returns the function represented by the given token. This will be either the
|
||||
* decompiled function or a function referenced within the decompiled function.
|
||||
*
|
||||
* @param program the program
|
||||
@ -270,8 +270,8 @@ public class DecompilerUtils {
|
||||
|
||||
/**
|
||||
* Similar to {@link #getTokens(ClangNode, AddressSetView)}, but uses the tokens from
|
||||
* the given view fields. Sometimes the tokens in the model (represented by the
|
||||
* {@link ClangNode}) are different than the fields in the view (such as when a list of
|
||||
* the given view fields. Sometimes the tokens in the model (represented by the
|
||||
* {@link ClangNode}) are different than the fields in the view (such as when a list of
|
||||
* comment tokens are condensed into a single comment token).
|
||||
*
|
||||
* @param fields the fields to check
|
||||
@ -354,8 +354,7 @@ public class DecompilerUtils {
|
||||
public static AddressSet findClosestAddressSet(Program program, AddressSpace functionSpace,
|
||||
List<ClangToken> tokenList) {
|
||||
AddressSet addressSet = new AddressSet();
|
||||
for (int i = 0; i < tokenList.size(); ++i) {
|
||||
ClangToken tok = tokenList.get(i);
|
||||
for (ClangToken tok : tokenList) {
|
||||
addTokenAddressRangeToSet(addressSet, tok, functionSpace);
|
||||
}
|
||||
|
||||
@ -574,8 +573,8 @@ public class DecompilerUtils {
|
||||
}
|
||||
|
||||
Stack<ClangSyntaxToken> braceStack = new Stack<>();
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
ClangToken token = (ClangToken) list.get(i);
|
||||
for (ClangNode element : list) {
|
||||
ClangToken token = (ClangToken) element;
|
||||
if (token instanceof ClangSyntaxToken) {
|
||||
ClangSyntaxToken syntaxToken = (ClangSyntaxToken) token;
|
||||
|
||||
@ -637,7 +636,7 @@ public class DecompilerUtils {
|
||||
* sequence of tokens that are part of the comment and group them into a single
|
||||
* ClangCommentToken. This makes post processing on the full comment string easier.
|
||||
* A single comment string can contain white space that manifests as ClangSyntaxTokens
|
||||
* with white space as text.
|
||||
* with white space as text.
|
||||
* @param alltoks is the token stream
|
||||
* @param i is the position of the initial comment token
|
||||
* @param first is the initial comment token
|
||||
@ -750,6 +749,17 @@ public class DecompilerUtils {
|
||||
token = context.getTokenAtCursor();
|
||||
}
|
||||
|
||||
return getDataType(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data type for the given token
|
||||
*
|
||||
* @param token the token
|
||||
* @return the data type or null
|
||||
*/
|
||||
public static DataType getDataType(ClangToken token) {
|
||||
|
||||
Varnode varnode = DecompilerUtils.getVarnodeRef(token);
|
||||
if (varnode != null) {
|
||||
HighVariable highVariable = varnode.getHigh();
|
||||
|
@ -20,16 +20,19 @@ import javax.swing.JComponent;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.GhidraOptions;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.ClangFieldToken;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.component.ClangTextField;
|
||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.app.plugin.core.hover.AbstractConfigurableHover;
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.HighVariable;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.NumericUtilities;
|
||||
|
||||
public class DataTypeDecompilerHover extends AbstractConfigurableHover
|
||||
implements DecompilerHoverService {
|
||||
@ -73,44 +76,77 @@ public class DataTypeDecompilerHover extends AbstractConfigurableHover
|
||||
}
|
||||
|
||||
ClangToken token = ((ClangTextField) field).getToken(fieldLocation);
|
||||
|
||||
DataType dt = getDataType(token);
|
||||
DataType dt = DecompilerUtils.getDataType(token);
|
||||
if (dt == null) {
|
||||
dt = getDataType(token.Parent());
|
||||
return null;
|
||||
}
|
||||
|
||||
if (dt != null) {
|
||||
String toolTipText = ToolTipUtils.getToolTipText(dt);
|
||||
return createTooltipComponent(toolTipText);
|
||||
String toolTipText = null;
|
||||
if (token instanceof ClangFieldToken) {
|
||||
toolTipText = createFieldToolTipText((ClangFieldToken) token, dt);
|
||||
}
|
||||
else {
|
||||
toolTipText = ToolTipUtils.getToolTipText(dt);
|
||||
}
|
||||
return null;
|
||||
|
||||
return createTooltipComponent(toolTipText);
|
||||
}
|
||||
|
||||
private DataType getDataType(ClangNode node) {
|
||||
private String createFieldToolTipText(ClangFieldToken token, DataType parentType) {
|
||||
ClangFieldToken fieldToken = token;
|
||||
int offset = fieldToken.getOffset();
|
||||
DataType fieldType = getFieldDataType(fieldToken);
|
||||
|
||||
if (node instanceof ClangVariableDecl) {
|
||||
return ((ClangVariableDecl) node).getDataType();
|
||||
//
|
||||
// Parent: BarBar
|
||||
// Offset: 0x8
|
||||
// Field Name: fooField
|
||||
//
|
||||
|
||||
String BR = HTMLUtilities.BR;
|
||||
StringBuilder newContent = new StringBuilder();
|
||||
newContent.append("<TABLE>");
|
||||
|
||||
//@formatter:off
|
||||
newContent.append(
|
||||
row("Parent: ", HTMLUtilities.friendlyEncodeHTML(parentType.getName())));
|
||||
newContent.append(
|
||||
row("Offset: ", NumericUtilities.toHexString(offset)));
|
||||
newContent.append(
|
||||
row("Field Name: ", HTMLUtilities.friendlyEncodeHTML(token.getText())));
|
||||
//@formatter:on
|
||||
|
||||
newContent.append("</TABLE>");
|
||||
|
||||
newContent.append(BR).append("<HR WIDTH=\"95%\">").append(BR);
|
||||
|
||||
String toolTipText = ToolTipUtils.getToolTipText(fieldType);
|
||||
StringBuilder buffy = new StringBuilder(toolTipText);
|
||||
int start = HTMLUtilities.HTML.length();
|
||||
buffy.insert(start, newContent);
|
||||
return buffy.toString();
|
||||
}
|
||||
|
||||
private String row(String... cols) {
|
||||
StringBuilder sb = new StringBuilder("<TR>");
|
||||
for (String col : cols) {
|
||||
sb.append("<TD>").append(col).append("</TD>");
|
||||
}
|
||||
sb.append("</TR>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
if (node instanceof ClangReturnType) {
|
||||
return ((ClangReturnType) node).getDataType();
|
||||
}
|
||||
|
||||
if (node instanceof ClangTypeToken) {
|
||||
return ((ClangTypeToken) node).getDataType();
|
||||
}
|
||||
|
||||
if (node instanceof ClangVariableToken) {
|
||||
Varnode vn = ((ClangVariableToken) node).getVarnode();
|
||||
if (vn != null) {
|
||||
HighVariable high = vn.getHigh();
|
||||
if (high != null) {
|
||||
return high.getDataType();
|
||||
}
|
||||
public static DataType getFieldDataType(ClangFieldToken field) {
|
||||
DataType fieldDt = DataTypeUtils.getBaseDataType(field.getDataType());
|
||||
if (fieldDt instanceof Structure) {
|
||||
Structure parent = (Structure) fieldDt;
|
||||
int offset = field.getOffset();
|
||||
int n = parent.getLength();
|
||||
if (offset >= 0 && offset < n) {
|
||||
DataTypeComponent dtc = parent.getComponentAt(offset);
|
||||
fieldDt = dtc.getDataType();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return fieldDt;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.pcode.*;
|
||||
|
||||
/**
|
||||
* A base class that represents a variable from the decompiler. This is either a variable
|
||||
* A base class that represents a variable from the decompiler. This is either a variable
|
||||
* type or a variable with an optional field access.
|
||||
*/
|
||||
public abstract class DecompilerVariable {
|
||||
@ -51,7 +51,7 @@ public abstract class DecompilerVariable {
|
||||
return ((ClangTypeToken) variable).getDataType();
|
||||
}
|
||||
|
||||
// not sure if we need this; the type returned here is the structure and not the
|
||||
// not sure if we need this; the type returned here is the structure and not the
|
||||
// field's type
|
||||
// if (variable instanceof ClangFieldToken) {
|
||||
// return ((ClangFieldToken) variable).getDataType();
|
||||
@ -79,8 +79,8 @@ public abstract class DecompilerVariable {
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer the type of the first input varnode, unless that type is a 'void *'.
|
||||
// Usually, in that special case, the output varnode has the correct type information.
|
||||
// Prefer the type of the first input varnode, unless that type is a 'void *'.
|
||||
// Usually, in that special case, the output varnode has the correct type information.
|
||||
PcodeOp op = variable.getPcodeOp();
|
||||
dataType = getInputDataType(op);
|
||||
|
||||
@ -193,7 +193,7 @@ public abstract class DecompilerVariable {
|
||||
String castString = casts.isEmpty() ? "" : "\tcasts: " + casts + ",\n";
|
||||
//@formatter:off
|
||||
return "{\n" +
|
||||
castString +
|
||||
castString +
|
||||
"\tvariable: " + variable + ",\n" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
@ -27,11 +27,10 @@ import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Structure implementation for the Database.
|
||||
*
|
||||
*
|
||||
* Structure database implementation.
|
||||
*/
|
||||
class StructureDB extends CompositeDB implements StructureInternal {
|
||||
|
||||
@ -42,15 +41,6 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
private int numComponents; // If packed, this does not include the undefined components.
|
||||
private List<DataTypeComponentDB> components;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param dataMgr
|
||||
* @param cache
|
||||
* @param compositeAdapter
|
||||
* @param componentAdapter
|
||||
* @param record
|
||||
*/
|
||||
public StructureDB(DataTypeManagerDB dataMgr, DBObjectCache<DataTypeDB> cache,
|
||||
CompositeDBAdapter compositeAdapter, ComponentDBAdapter componentAdapter,
|
||||
DBRecord record) {
|
||||
@ -95,35 +85,36 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminate use of old trailing flex-array specification which is now specified using
|
||||
* a zero-element array. Due to the specification of a new array datatype this must handle
|
||||
* two cases when an old flex-array component is exists:
|
||||
* Eliminate use of old trailing flex-array specification which is now specified using a
|
||||
* zero-element array. Due to the specification of a new array datatype this must handle two
|
||||
* cases when an old flex-array component is exists:
|
||||
* <ol>
|
||||
* <li>read-only case: associated {@link DataTypeManagerDB} is not updateable. This is the normal
|
||||
* case for an open archive. A non-DB ArrayDataType must be employed with an immutable
|
||||
* <li>read-only case: associated {@link DataTypeManagerDB} is not updatable. This is the
|
||||
* normal case for an open archive. A non-DB ArrayDataType must be employed with an immutable
|
||||
* {@link DataTypeProxyComponentDB} in place of the flex-array component.</li>
|
||||
* <li>upgrade (open for update with open transaction): the flex-array record is modified to
|
||||
* to indicate an appropriate resolved zero-element array.
|
||||
* indicate an appropriate resolved zero-element array.
|
||||
* </ol>
|
||||
* <p>
|
||||
* NOTE: When {@link DataTypeManagerDB} is instantiated for update an upgrade must be forced based upon the
|
||||
* {@link CompositeDBAdapter#isFlexArrayMigrationRequired()} indicator. The upgrade logic
|
||||
* (see {@link DataTypeManagerDB#migrateOldFlexArrayComponentsIfRequired(ghidra.util.task.TaskMonitor)})
|
||||
* istantiates all structures within the databases with an open transaaction allowing this method
|
||||
* to perform the neccessary flex-array record migration.
|
||||
* NOTE: When {@link DataTypeManagerDB} is instantiated for update an upgrade must be forced
|
||||
* based upon the {@link CompositeDBAdapter#isFlexArrayMigrationRequired()} indicator. The
|
||||
* upgrade logic(see
|
||||
* {@link DataTypeManagerDB#migrateOldFlexArrayComponentsIfRequired(TaskMonitor)}) instantiates
|
||||
* all structures within the databases with an open transaction allowing this method to perform
|
||||
* the necessary flex-array record migration.
|
||||
* <p>
|
||||
* NOTE: The offset of the migrated flex array component and structure length may change during upgrade
|
||||
* when packing is enabled when the original packed structure length did not properly factor the flex-array
|
||||
* alignment. Repack does not occur in the read-only case.
|
||||
* NOTE: The offset of the migrated flex array component and structure length may change during
|
||||
* upgrade when packing is enabled when the original packed structure length did not properly
|
||||
* factor the flex-array alignment. Repack does not occur in the read-only case.
|
||||
*
|
||||
* @param oldFlexArrayRecord record which corresponds to an olf flex-array component
|
||||
* @param oldFlexArrayRecord record which corresponds to an old flex-array component
|
||||
* @throws IOException if a database error occurs
|
||||
*/
|
||||
private void migrateOldFlexArray(DBRecord oldFlexArrayRecord) throws IOException {
|
||||
long id = oldFlexArrayRecord.getLongValue(ComponentDBAdapter.COMPONENT_DT_ID_COL);
|
||||
DataType dt = dataMgr.getDataType(id); // could be BadDataType if built-in type is missing
|
||||
|
||||
// use zero-element array (need positive element length if dt is BadDataType)
|
||||
// use zero-element array (need positive element length if type is BadDataType)
|
||||
dt = new ArrayDataType(dt, 0, 1, dataMgr);
|
||||
|
||||
boolean repack = false;
|
||||
@ -206,13 +197,14 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
DataTypeComponentDB dtc = null;
|
||||
try {
|
||||
if (dataType == DataType.DEFAULT) {
|
||||
// assume non-packed structure - structre will grow by 1-byte below
|
||||
// assume non-packed structure - structure will grow by 1-byte below
|
||||
dtc = new DataTypeComponentDB(dataMgr, this, numComponents, structLength);
|
||||
}
|
||||
else {
|
||||
int componentLength = getPreferredComponentLength(dataType, length);
|
||||
DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key,
|
||||
componentLength, numComponents, structLength, name, comment);
|
||||
DBRecord rec =
|
||||
componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key,
|
||||
componentLength, numComponents, structLength, name, comment);
|
||||
dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
|
||||
dataType.addParent(this);
|
||||
components.add(dtc);
|
||||
@ -327,8 +319,9 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
length = getPreferredComponentLength(dataType, length);
|
||||
|
||||
int offset = getComponent(ordinal).getOffset();
|
||||
DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key, length,
|
||||
ordinal, offset, name, comment);
|
||||
DBRecord rec =
|
||||
componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key, length,
|
||||
ordinal, offset, name, comment);
|
||||
DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
|
||||
dataType.addParent(this);
|
||||
shiftOffsets(idx, 1, dtc.getLength());
|
||||
@ -553,8 +546,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a defined component at the specified index without
|
||||
* any alteration to other components.
|
||||
* Removes a defined component at the specified index without any alteration to other components.
|
||||
* @param index defined component index
|
||||
* @return the defined component which was removed.
|
||||
* @throws IOException if an IO error occurs
|
||||
@ -568,15 +560,15 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
|
||||
/**
|
||||
* Removes a defined component at the specified index.
|
||||
* If this corresponds to a zero-length or bit-field component it will
|
||||
* be cleared without an offset shift to the remaining components. Removal of
|
||||
* other component types will result in an offset and ordinal shift
|
||||
* to the remaining components. In the case of a non-packed
|
||||
* structure, the resulting shift will cause in a timestamp change
|
||||
* for this structure.
|
||||
* <p>
|
||||
* If this corresponds to a zero-length or bit-field component it will be cleared without an
|
||||
* offset shift to the remaining components. Removal of other component types will result in
|
||||
* an offset and ordinal shift to the remaining components. In the case of a non-packed
|
||||
* structure, the resulting shift will cause in a timestamp change for this structure.
|
||||
*
|
||||
* @param index defined component index
|
||||
* @param disableOffsetShift if false, and component is not a bit-field, an offset shift
|
||||
* and possible structure length change will be performed for non-packed structure.
|
||||
* @param disableOffsetShift if false, and component is not a bit-field, an offset shift and
|
||||
* possible structure length change will be performed for non-packed structure.
|
||||
*/
|
||||
private void doDeleteWithComponentShift(int index, boolean disableOffsetShift) {
|
||||
DataTypeComponentDB dtc = null;
|
||||
@ -657,8 +649,9 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
}
|
||||
|
||||
// update numComponents only
|
||||
components = newComponents;
|
||||
updateComposite(numComponents + ordinalAdjustment, -1, -1, true); // update numComponents only
|
||||
updateComposite(numComponents + ordinalAdjustment, -1, -1, true);
|
||||
|
||||
if (isPackingEnabled()) {
|
||||
if (!repack(false, true)) {
|
||||
@ -666,10 +659,11 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
}
|
||||
else {
|
||||
updateComposite(-1, structLength + offsetAdjustment, -1, true); // update length only
|
||||
// update length only
|
||||
updateComposite(-1, structLength + offsetAdjustment, -1, true);
|
||||
if (bitFieldRemoved) {
|
||||
repack(false, false);
|
||||
}
|
||||
}
|
||||
notifySizeChanged(false);
|
||||
}
|
||||
}
|
||||
@ -781,10 +775,11 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create copy of structure for target dtm (source archive information is discarded).
|
||||
* Create copy of structure for target data type manager (source archive information is
|
||||
* discarded).
|
||||
* <p>
|
||||
* WARNING! copying non-packed structures which contain bitfields can produce invalid results when
|
||||
* switching endianess due to the differences in packing order.
|
||||
* WARNING! copying non-packed structures which contain bitfields can produce invalid results
|
||||
* when switching endianness due to the differences in packing order.
|
||||
*
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
@ -799,9 +794,10 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cloned structure for target dtm preserving source archive information. WARNING!
|
||||
* cloning non-packed structures which contain bitfields can produce invalid results when
|
||||
* switching endianess due to the differences in packing order.
|
||||
* Create cloned structure for target data type manager preserving source archive information.
|
||||
* <p>
|
||||
* WARNING! cloning non-packed structures which contain bitfields can produce invalid results
|
||||
* when switching endianness due to the differences in packing order.
|
||||
*
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
@ -884,7 +880,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
throw new IndexOutOfBoundsException(ordinal);
|
||||
}
|
||||
int idx = Collections.binarySearch(components, Integer.valueOf(ordinal),
|
||||
OrdinalComparator.INSTANCE);
|
||||
OrdinalComparator.INSTANCE);
|
||||
if (idx >= 0) {
|
||||
DataTypeComponentDB dtc = components.remove(idx);
|
||||
dtc.getDataType().removeParent(this);
|
||||
@ -914,9 +910,11 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Backup from specified defined-component index to the first component which contains the specified offset.
|
||||
* @param index any defined component index which contains offset
|
||||
* @param offset offset within structure
|
||||
* Backup from specified defined-component index to the first component which contains the
|
||||
* specified offset.
|
||||
*
|
||||
* @param index any defined component index which contains offset.
|
||||
* @param offset offset within structure.
|
||||
* @return index of first defined component containing specific offset.
|
||||
*/
|
||||
private int backupToFirstComponentContainingOffset(int index, int offset) {
|
||||
@ -934,10 +932,12 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify defined-component index of the first non-zero-length component which contains the specified offset.
|
||||
* If only zero-length components exist, the last zero-length component which contains the offset will be returned.
|
||||
* @param index any defined component index which contains offset
|
||||
* @param offset offset within structure
|
||||
* Identify defined-component index of the first non-zero-length component which contains the
|
||||
* specified offset. If only zero-length components exist, the last zero-length component which
|
||||
* contains the offset will be returned.
|
||||
*
|
||||
* @param index any defined component index which contains offset.
|
||||
* @param offset offset within structure.
|
||||
* @return index of first defined component containing specific offset.
|
||||
*/
|
||||
private int indexOfFirstNonZeroLenComponentContainingOffset(int index, int offset) {
|
||||
@ -954,9 +954,11 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance from specified defined-component index to the last component which contains the specified offset.
|
||||
* @param index any defined component index which contains offset
|
||||
* @param offset offset within structure
|
||||
* Advance from specified defined-component index to the last component which contains the
|
||||
* specified offset.
|
||||
*
|
||||
* @param index any defined component index which contains offset.
|
||||
* @param offset offset within structure.
|
||||
* @return index of last defined component containing specific offset.
|
||||
*/
|
||||
private int advanceToLastComponentContainingOffset(int index, int offset) {
|
||||
@ -993,7 +995,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
shiftOffsets(-index - 1, -1, -1); // updates timestamp
|
||||
}
|
||||
else {
|
||||
// delete all components containing offset working backward from last such component
|
||||
// delete all components containing the offset working backward from the last such
|
||||
// component
|
||||
index = advanceToLastComponentContainingOffset(index, offset);
|
||||
DataTypeComponentDB dtc = components.get(index);
|
||||
while (dtc.containsOffset(offset)) {
|
||||
@ -1011,7 +1014,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearAtOffset(int offset) {
|
||||
lock.acquire();
|
||||
@ -1109,7 +1112,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<DataTypeComponent> getComponentsContaining(int offset) {
|
||||
lock.acquire();
|
||||
@ -1141,8 +1144,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
if (!hasSizedComponent && offset != structLength && !isPackingEnabled()) {
|
||||
// generate undefined componentfor padding offset within non-packed structure
|
||||
// if offset only occupied by zero-length component
|
||||
// generate undefined component for padding offset within non-packed structure if
|
||||
// offset only occupied by zero-length component
|
||||
list.add(generateUndefinedComponent(offset, index));
|
||||
}
|
||||
return list;
|
||||
@ -1155,8 +1158,9 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
/**
|
||||
* Generate an undefined component following a binary search across the defined components.
|
||||
* @param offset the offset within this structure which was searched for
|
||||
* @param missingComponentIndex the defined component binary search index result (must be negative)
|
||||
* @return undefined component
|
||||
* @param missingComponentIndex the defined component binary search index result (must be
|
||||
* negative)
|
||||
* @return undefined component
|
||||
*/
|
||||
private DataTypeComponentDB generateUndefinedComponent(int offset, int missingComponentIndex) {
|
||||
if (missingComponentIndex >= 0) {
|
||||
@ -1276,8 +1280,9 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
|
||||
length = getPreferredComponentLength(dataType, length);
|
||||
|
||||
DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key, length,
|
||||
ordinal, offset, name, comment);
|
||||
DBRecord rec =
|
||||
componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key, length,
|
||||
ordinal, offset, name, comment);
|
||||
dataType.addParent(this);
|
||||
DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
|
||||
shiftOffsets(index, 1 + additionalShift, length + additionalShift);
|
||||
@ -1335,15 +1340,16 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
// defined component
|
||||
DataTypeComponentDB origDtc = components.get(index);
|
||||
offset = origDtc.getOffset();
|
||||
|
||||
|
||||
if (isPackingEnabled() || length == 0) {
|
||||
// case 1: packed structure or zero-length replacement - do 1-for-1 replacement
|
||||
replacedComponents.add(origDtc);
|
||||
}
|
||||
else if (origDtc.getLength() == 0) {
|
||||
// case 2: replaced component is zero-length (like-for-like replacement handled by case 1 above
|
||||
throw new IllegalArgumentException(
|
||||
"Zero-length component may only be replaced with another zero-length component");
|
||||
// case 2: replaced component is zero-length (like-for-like replacement handled
|
||||
// by case 1 above
|
||||
throw new IllegalArgumentException("Zero-length component may only be " +
|
||||
"replaced with another zero-length component");
|
||||
}
|
||||
else if (origDtc.isBitFieldComponent()) {
|
||||
// case 3: replacing bit-field (must replace all bit-fields which overlap)
|
||||
@ -1371,7 +1377,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
}
|
||||
else {
|
||||
// case 4: sized component replacemnt - do 1-for-1 replacement
|
||||
// case 4: sized component replacement - do 1-for-1 replacement
|
||||
replacedComponents.add(origDtc);
|
||||
}
|
||||
}
|
||||
@ -1424,11 +1430,11 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
}
|
||||
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
|
||||
if (offset >= structLength) {
|
||||
throw new IllegalArgumentException(
|
||||
"Offset " + offset + " is beyond end of structure (" + structLength + ").");
|
||||
@ -1452,15 +1458,17 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
// case 1: only defined component(s) at offset are zero-length
|
||||
if (origDtc.getLength() == 0) {
|
||||
if (isPackingEnabled()) {
|
||||
// if packed: insert after zero-length component
|
||||
// if packed: insert after zero-length component
|
||||
return insert(index + 1, dataType, length, name, comment);
|
||||
}
|
||||
// if non-packed: replace undefined component which immediately follows the zero-length component
|
||||
// if non-packed: replace undefined component which immediately follows the
|
||||
// zero-length component
|
||||
replacedComponents.add(
|
||||
new DataTypeComponentDB(dataMgr, this, origDtc.getOrdinal() + 1, offset));
|
||||
}
|
||||
|
||||
// case 2: sized component at offset is bit-field (must replace all bit-fields which contain offset)
|
||||
// case 2: sized component at offset is bit-field (must replace all bit-fields
|
||||
// which contain offset)
|
||||
else if (origDtc.isBitFieldComponent()) {
|
||||
replacedComponents.add(origDtc);
|
||||
for (int i = index - 1; i >= 0; i--) {
|
||||
@ -1482,11 +1490,13 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
index = -index - 1;
|
||||
|
||||
if (isPackingEnabled()) {
|
||||
// case 4: if replacing padding for packed struction perform insert at correct ordinal
|
||||
// case 4: if replacing padding for packed structure perform insert at correct
|
||||
// ordinal
|
||||
return insert(index, dataType, length, name, comment);
|
||||
}
|
||||
|
||||
// case 5: replace undefined component at offset - compute undefined component to be replaced
|
||||
// case 5: replace undefined component at offset - compute undefined component to
|
||||
// be replaced
|
||||
int ordinal = offset;
|
||||
if (index > 0) {
|
||||
// use previous defined component to determine ordinal for undefined component
|
||||
@ -1529,10 +1539,10 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
*
|
||||
* @param dataType the structure to get the component information from.
|
||||
* @throws IllegalArgumentException if any of the component data types are not allowed to
|
||||
* replace a component in this composite data type. For example, suppose dt1
|
||||
* contains dt2. Therefore it is not valid to replace a dt2 component with dt1 since
|
||||
* this would cause a cyclic dependency.
|
||||
* @see ghidra.program.database.data.DataTypeDB#replaceWith(ghidra.program.model.data.DataType)
|
||||
* replace a component in this composite data type. For example, suppose dt1 contains dt2.
|
||||
* Therefore it is not valid to replace a dt2 component with dt1 since this would cause a
|
||||
* cyclic dependency.
|
||||
* @see DataTypeDB#replaceWith(DataType)
|
||||
*/
|
||||
@Override
|
||||
public void replaceWith(DataType dataType) {
|
||||
@ -1647,7 +1657,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
DataType dt = resolvedDts[i]; // ancestry check already performed by caller
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
|
||||
if (length < 0 || dtc.isBitFieldComponent()) {
|
||||
// TODO: bitfield truncation/expansion may be an issues if data organization changes
|
||||
// TODO: bitfield truncation/expansion may be an issue if data organization changes
|
||||
length = dtc.getLength();
|
||||
}
|
||||
else {
|
||||
@ -1967,10 +1977,10 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for available undefined bytes within a non-packed structure for a component
|
||||
* update with the specified ordinal.
|
||||
* @param lastOrdinalReplacedOrUpdated the ordinal of a component to be updated
|
||||
* or the last ordinal with in a sequence of components being replaced.
|
||||
* Check for available undefined bytes within a non-packed structure for a component update
|
||||
* with the specified ordinal.
|
||||
* @param lastOrdinalReplacedOrUpdated the ordinal of a component to be updated or the last
|
||||
* ordinal with in a sequence of components being replaced.
|
||||
* @param bytesNeeded number of additional bytes required to complete operation
|
||||
* @throws IllegalArgumentException if unable to identify/make sufficient space
|
||||
*/
|
||||
@ -1995,20 +2005,21 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
|
||||
/**
|
||||
* Replace the specified components with a new component containing the specified data type.
|
||||
* If {@link DataType#DEFAULT} is specified as the resolvedDataType only a clear operation
|
||||
* If {@link DataType#DEFAULT} is specified as the resolvedDataType only a clear operation
|
||||
* is performed.
|
||||
*
|
||||
* @param origComponents the original sequence of data type components in this structure
|
||||
* to be replaced. These components must be adjacent components in sequential order.
|
||||
* If an non-packed undefined component is specified no other component may be included.
|
||||
* @param origComponents the original sequence of data type components in this structure to be
|
||||
* replaced. These components must be adjacent components in sequential order. If an
|
||||
* non-packed undefined component is specified no other component may be included.
|
||||
* @param resolvedDataType the data type of the new component
|
||||
* @param newOffset offset of replacement component which must fall within origComponents bounds
|
||||
* @param newOffset offset of replacement component which must fall within origComponents
|
||||
* bounds
|
||||
* @param length the length of the new component
|
||||
* @param name the field name of the new component
|
||||
* @param comment the comment for the new component
|
||||
* @return the new component or null if only a clear operation was performed.
|
||||
* @throws IOException if database IO error occurs
|
||||
* @throws IllegalArgumentException if unable to identify/make sufficient space
|
||||
* @throws IllegalArgumentException if unable to identify/make sufficient space
|
||||
*/
|
||||
private DataTypeComponent replaceComponents(LinkedList<DataTypeComponentDB> origComponents,
|
||||
DataType resolvedDataType, int newOffset, int length, String name, String comment)
|
||||
@ -2151,8 +2162,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
checkAncestry(replacementDt);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO: should we use Undefined1 instead to avoid cases where
|
||||
// DEFAULT datatype can not be used (bitfield, aligned structure, etc.)
|
||||
// TODO: should we use Undefined1 instead to avoid cases where DEFAULT datatype can
|
||||
// not be used (bitfield, aligned structure, etc.)
|
||||
// TODO: failing silently is rather hidden
|
||||
replacementDt = DataType.DEFAULT;
|
||||
}
|
||||
@ -2293,8 +2304,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform structure member repack.
|
||||
* Perform lazy update of stored alignment introduced with v5 adapter.
|
||||
* Perform structure member repack. Perform lazy update of stored alignment introduced with v5
|
||||
* adapter.
|
||||
*/
|
||||
@Override
|
||||
protected boolean repack(boolean isAutoChange, boolean notify) {
|
||||
@ -2305,9 +2316,9 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
|
||||
int oldLength = structLength;
|
||||
int oldAlignment = getComputedAlignment(true); // ensure that alignment has been stored
|
||||
|
||||
|
||||
computedAlignment = -1; // clear cached alignment
|
||||
|
||||
|
||||
boolean changed;
|
||||
if (!isPackingEnabled()) {
|
||||
changed = adjustNonPackedComponents(!isAutoChange);
|
||||
@ -2319,7 +2330,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
changed |= updateComposite(components.size(), packResult.structureLength,
|
||||
packResult.alignment, !isAutoChange);
|
||||
}
|
||||
|
||||
|
||||
if (changed && notify) {
|
||||
if (oldLength != structLength) {
|
||||
notifySizeChanged(isAutoChange);
|
||||
|
Loading…
Reference in New Issue
Block a user