GP-2291 Support for unions through partial containers

This commit is contained in:
caheckman 2022-08-24 11:46:46 -04:00
parent d3efd60d54
commit cb9c12894e
21 changed files with 678 additions and 182 deletions

View file

@ -742,7 +742,7 @@ public class HighFunctionDBUtil {
* pieces for building the dynamic LocalVariable. This method clears out any preexisting
* union facet with the same dynamic hash and firstUseOffset.
* @param function is the function affected by the union facet
* @param dt is the parent data-type, either the union or a pointer to it
* @param dt is the parent data-type; a union, a pointer to a union, or a partial union
* @param fieldNum is the ordinal of the desired union field
* @param addr is the first use address of the facet
* @param hash is the dynamic hash
@ -752,6 +752,9 @@ public class HighFunctionDBUtil {
*/
public static void writeUnionFacet(Function function, DataType dt, int fieldNum, Address addr,
long hash, SourceType source) throws InvalidInputException, DuplicateNameException {
if (dt instanceof PartialUnion) {
dt = ((PartialUnion) dt).getParent();
}
int firstUseOffset = (int) addr.subtract(function.getEntryPoint());
String symbolName = UnionFacetSymbol.buildSymbolName(fieldNum, addr);
boolean nameCollision = false;

View file

@ -0,0 +1,122 @@
/* ###
* 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.program.model.pcode;
import javax.help.UnsupportedOperationException;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
/**
* A data-type representing an unspecified piece of a parent Union data-type. This is used
* internally by the decompiler to label Varnodes representing partial symbols, where the
* part is known to be contained in a Union data-type. Within the isolated context of a Varnode,
* its not possible to resolve to a specific field of the Union because the Varnode may be used
* in multiple ways.
*/
public class PartialUnion extends AbstractDataType {
private DataType unionDataType; // Either a Union or a Typedef of a Union
private int offset; // Offset in bytes of partial within parent
private int size; // Number of bytes in partial
PartialUnion(DataTypeManager dtm, DataType parent, int off, int sz) {
super(CategoryPath.ROOT, "partialunion", dtm);
unionDataType = parent;
offset = off;
size = sz;
}
/**
* @return the Union data-type of which this is a part
*/
public DataType getParent() {
return unionDataType;
}
/**
* @return the offset, in bytes, of this part within its parent Union
*/
public int getOffset() {
return offset;
}
@Override
public DataType clone(DataTypeManager dtm) {
// Internal to the PcodeDataTypeManager
throw new UnsupportedOperationException("may not be cloned");
}
@Override
public int getLength() {
return size;
}
@Override
public String getDescription() {
return "Partial Union (internal)";
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return null; // Should not be placed on memory
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return null; // Should not be placed on memory
}
@Override
public SettingsDefinition[] getSettingsDefinitions() {
return unionDataType.getSettingsDefinitions();
}
@Override
public Settings getDefaultSettings() {
return unionDataType.getDefaultSettings();
}
@Override
public DataType copy(DataTypeManager dtm) {
// Internal to the PcodeDataTypeManager
throw new UnsupportedOperationException("may not be copied");
}
@Override
public Class<?> getValueClass(Settings settings) {
return unionDataType.getValueClass(settings);
}
@Override
public boolean isEquivalent(DataType dt) {
if (dt == null || !(dt instanceof PartialUnion)) {
return false;
}
PartialUnion op = (PartialUnion) dt;
if (offset != op.offset || size != op.size) {
return false;
}
return unionDataType.isEquivalent(op.unionDataType);
}
@Override
public int getAlignment() {
return 0;
}
}

View file

@ -251,6 +251,13 @@ public class PcodeDataTypeManager {
decoder.closeElement(el);
return AbstractFloatDataType.getFloatDataType(size, progDataTypes);
}
else if (meta.equals("partunion")) {
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
int offset = (int) decoder.readSignedInteger(ATTRIB_OFFSET);
DataType dt = decodeDataType(decoder);
decoder.closeElement(el);
return new PartialUnion(progDataTypes, dt, offset, size);
}
else { // We typically reach here if the decompiler invents a new type
// probably an unknown with a non-standard size
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);