From b9202411b9723b9160fd8620f715dacaa064d124 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Fri, 3 Mar 2023 11:47:37 -0500 Subject: [PATCH] GP-1379/3022 FloatFormat and BigFloat refactor in support of string parsing and 80-bit float format. Change float datatype naming to use number of bits instead of bytes. --- .../dbg/util/TargetDataTypeConverter.java | 3 + .../symbol/AbstractDBTraceVariableSymbol.java | 2 +- .../app/cmd/data/CreateDataBackgroundCmd.java | 45 +- .../CreateDataInStructureBackgroundCmd.java | 2 +- .../cmd/data/CreateDataInStructureCmd.java | 3 +- .../compositeeditor/CompositeEditorModel.java | 8 +- .../compositeeditor/CompositeViewerModel.java | 3 +- .../core/compositeeditor/DataTypeHelper.java | 6 +- .../InsertUndefinedAction.java | 3 +- .../compositeeditor/StructureEditorModel.java | 3 +- .../plugin/core/data/CreateArrayAction.java | 15 +- .../app/plugin/core/data/DataPlugin.java | 2 +- .../core/datamgr/DataOrganizationPanel.java | 494 -------------- .../core/datamgr/SizeAlignmentPanel.java | 156 ----- .../core/datapreview/DataTypePreview.java | 3 +- .../core/equate/ConvertToDoubleAction.java | 2 +- .../core/equate/ConvertToFloatAction.java | 2 +- .../core/function/CreateArrayAction.java | 15 +- .../function/editor/FunctionEditorModel.java | 2 + .../editor/StorageAddressEditorDialog.java | 1 + .../core/stackeditor/StackEditorModel.java | 10 +- .../dwarf4/next/DWARFDataTypeManager.java | 7 +- .../format/pe/cli/blobs/CliAbstractSig.java | 6 +- .../pe/cli/blobs/CliBlobCustomAttrib.java | 6 +- .../datatype/microsoft/RTTI0DataType.java | 8 +- .../app/util/demangler/DemangledDataType.java | 3 +- .../app/util/xml/DefinedDataXmlMgr.java | 2 +- .../support/ProcessorEmulatorTestAdapter.java | 4 +- .../DataTypePreviewPluginTest.java | 29 +- .../plugin/core/equate/EquatePlugin1Test.java | 2 +- .../script/GhidraScriptRealProgramTest.java | 5 +- .../actions/ConvertDoubleAction.java | 2 +- .../decompile/actions/ConvertFloatAction.java | 2 +- .../app/util/bin/format/pdb/PdbParser.java | 2 +- .../pdb/pdbapplicator/DataSymbolApplier.java | 2 +- .../PdbPrimitiveTypeApplicator.java | 14 +- .../opbehavior/OpBehaviorFloatAbsTest.java | 20 +- .../opbehavior/OpBehaviorFloatAddTest.java | 28 +- .../opbehavior/OpBehaviorFloatCeilTest.java | 20 +- .../opbehavior/OpBehaviorFloatDivTest.java | 16 +- .../OpBehaviorFloatFloat2FloatTest.java | 20 +- .../opbehavior/OpBehaviorFloatFloorTest.java | 24 +- .../OpBehaviorFloatInt2FloatTest.java | 16 +- .../opbehavior/OpBehaviorFloatMultTest.java | 16 +- .../opbehavior/OpBehaviorFloatNegTest.java | 20 +- .../opbehavior/OpBehaviorFloatRoundTest.java | 36 +- .../opbehavior/OpBehaviorFloatSqrtTest.java | 4 +- .../opbehavior/OpBehaviorFloatSubTest.java | 28 +- .../core/data/ProgramProviderContext.java | 3 +- .../ghidra/pcode/floatformat/BigFloat.java | 237 +++++-- .../ghidra/pcode/floatformat/FloatFormat.java | 632 ++++++++++++------ .../pcode/floatformat/FloatFormatFactory.java | 3 +- .../ghidra/program/database/code/DataDB.java | 3 +- .../ghidra/program/database/data/ArrayDB.java | 36 +- .../program/database/data/CompositeDB.java | 18 +- .../database/data/DataTypeUtilities.java | 1 + .../ghidra/program/database/data/EnumDB.java | 5 + .../database/data/FunctionDefinitionDB.java | 5 + .../program/database/data/PointerDB.java | 6 + .../program/database/data/StructureDB.java | 9 +- .../program/database/data/TypedefDB.java | 5 + .../ghidra/program/database/data/UnionDB.java | 7 +- .../model/data/AbstractComplexDataType.java | 9 +- .../program/model/data/AbstractDataType.java | 19 + .../data/AbstractPointerTypedefBuiltIn.java | 5 + .../model/data/AlignedComponentPacker.java | 2 +- .../program/model/data/ArrayDataType.java | 21 +- .../program/model/data/BitFieldDataType.java | 8 +- .../program/model/data/Complex16DataType.java | 6 +- .../program/model/data/Complex32DataType.java | 6 +- .../program/model/data/Complex8DataType.java | 6 +- .../model/data/CompositeDataTypeImpl.java | 18 +- .../model/data/CountedDynamicDataType.java | 4 +- .../program/model/data/DataOrganization.java | 35 +- .../model/data/DataOrganizationImpl.java | 65 +- .../ghidra/program/model/data/DataType.java | 42 +- .../model/data/DataTypeComponentImpl.java | 28 + .../program/model/data/DataTypeImpl.java | 39 ++ .../program/model/data/DataTypeInstance.java | 60 +- .../program/model/data/DataUtilities.java | 4 +- .../program/model/data/DoubleDataType.java | 13 +- .../program/model/data/EnumDataType.java | 5 + .../model/data/FactoryStructureDataType.java | 2 +- .../program/model/data/Float8DataType.java | 44 -- .../program/model/data/FloatDataType.java | 14 +- .../model/data/IndexedDynamicDataType.java | 4 +- .../model/data/LongDoubleDataType.java | 13 +- .../program/model/data/MetaDataType.java | 2 + .../model/data/NoisyStructureBuilder.java | 3 + .../program/model/data/PointerDataType.java | 5 + .../program/model/data/PointerTypedef.java | 5 + .../model/data/RepeatCountDataType.java | 3 +- .../model/data/RepeatedDynamicDataType.java | 3 +- .../model/data/StructuredDynamicDataType.java | 3 +- .../program/model/data/TypedefDataType.java | 5 + .../{ => floats}/AbstractFloatDataType.java | 181 +++-- .../model/data/floats/Float128DataType.java | 48 ++ .../data/{ => floats}/Float16DataType.java | 20 +- .../Float32DataType.java} | 30 +- .../Float64DataType.java} | 30 +- .../Float80DataType.java} | 30 +- .../ghidra/program/model/lang/ParamEntry.java | 1 + .../model/listing/VariableUtilities.java | 1 + .../program/model/pcode/MappedEntry.java | 2 +- .../program/model/pcode/PartialUnion.java | 5 + .../model/pcode/PcodeDataTypeManager.java | 2 + .../program/model/data/FloatDataTypeTest.java | 71 +- .../pcode/floatformat/FloatFormatTest.java | 547 ++++++++++----- .../model/data/Float10DataTypeTest.java | 89 --- .../model/data/Float80DataTypeTest.java | 160 +++++ .../program/model/data/StubDataType.java | 5 + .../68000/data/languages/68000.cspec | 2 +- .../x86/data/languages/x86-64-gcc.cspec | 4 +- .../x86/data/languages/x86borland.cspec | 2 +- .../x86/data/languages/x86delphi.cspec | 52 -- .../x86/data/languages/x86gcc.cspec | 4 +- 116 files changed, 2122 insertions(+), 1757 deletions(-) delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataOrganizationPanel.java delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/SizeAlignmentPanel.java delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float8DataType.java rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/{ => floats}/AbstractFloatDataType.java (54%) create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float128DataType.java rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/{ => floats}/Float16DataType.java (71%) rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/{Float10DataType.java => floats/Float32DataType.java} (54%) rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/{Float2DataType.java => floats/Float64DataType.java} (53%) rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/{Float4DataType.java => floats/Float80DataType.java} (53%) delete mode 100644 Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java create mode 100644 Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float80DataTypeTest.java diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/TargetDataTypeConverter.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/TargetDataTypeConverter.java index 33a7c7eac3..9d14d77dcb 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/TargetDataTypeConverter.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/TargetDataTypeConverter.java @@ -27,6 +27,7 @@ import ghidra.dbg.target.TargetDataTypeMember; import ghidra.dbg.target.TargetNamedDataType; import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.util.Msg; public class TargetDataTypeConverter { @@ -481,6 +482,8 @@ public class TargetDataTypeConverter { case SINT: return AbstractIntegerDataType.getSignedDataType(tPrimitive.getLength(), dtm); case FLOAT: + // TODO: lookup by length must use "raw" encoding size since "aligned" lengths + // may be duplicated across different float types. return AbstractFloatDataType.getFloatDataType(tPrimitive.getLength(), dtm); case COMPLEX: return AbstractComplexDataType.getComplexDataType(tPrimitive.getLength(), dtm); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java index 61ae964733..e4e6c8675e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java @@ -23,8 +23,8 @@ import db.DBRecord; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; -import ghidra.program.model.data.AbstractFloatDataType; import ghidra.program.model.data.DataType; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.program.model.pcode.Varnode; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataBackgroundCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataBackgroundCmd.java index dfe3b01571..bb550afa54 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataBackgroundCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataBackgroundCmd.java @@ -126,22 +126,51 @@ public class CreateDataBackgroundCmd extends BackgroundCommand { return true; } + private static Address alignAddress(Address addr, int alignment) { + if (addr == null) { + return null; + } + long mod = addr.getOffset() % alignment; + if (mod == 0) { + return addr; + } + try { + return addr.addNoWrap(alignment - mod); + } + catch (AddressOverflowException e) { + // ignore + } + return null; + } + private void createData(Address start, Address end, DataType dataType, Program p, - TaskMonitor monitor) throws AddressOverflowException, CodeUnitInsertionException { + TaskMonitor monitor) throws CodeUnitInsertionException { + + int alignment = 1; + if (newDataType.getLength() != newDataType.getAlignedLength()) { + // datatypes whose length does not match their aligned-length must + // be properly aligned to account for padding (e.g., x86-32 80-bit floats) + alignment = newDataType.getAlignment(); + } + + int initialProgress = bytesApplied; Listing listing = p.getListing(); listing.clearCodeUnits(start, end, false); - int length = (int) end.subtract(start) + 1; - while (start.compareTo(end) <= 0) { + Address nextAddr = alignAddress(start, alignment); + int length = (int) end.subtract(nextAddr) + 1; + while (nextAddr != null && nextAddr.compareTo(end) <= 0) { if (monitor.isCancelled()) { return; } - Data d = listing.createData(start, dataType, length); - int dataLen = d.getLength(); - start = start.addNoWrap(dataLen); - length -= dataLen; - bytesApplied += dataLen; + Data d = listing.createData(nextAddr, dataType, length); + Address maxDataAddr = d.getMaxAddress(); + bytesApplied = initialProgress + (int) maxDataAddr.subtract(start) + 1; + nextAddr = alignAddress(maxDataAddr.next(), alignment); + if (nextAddr != null) { + length = (int) end.subtract(nextAddr) + 1; + } monitor.setProgress(bytesApplied); if (++numDataCreated % 10000 == 0) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureBackgroundCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureBackgroundCmd.java index f0b6751017..23a1a9be29 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureBackgroundCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureBackgroundCmd.java @@ -133,7 +133,7 @@ public class CreateDataInStructureBackgroundCmd extends BackgroundCommand { // MemBuffer memBuf = new ProgramStructureProviderContext(program,addr, // struct, struct.getComponent(index).getOffset()); DataTypeInstance dti = - DataTypeInstance.getDataTypeInstance(newDataType, length); + DataTypeInstance.getDataTypeInstance(newDataType, length, true); if (dti == null || dti.getLength() > length) { break; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureCmd.java index 62ab576b35..2db0b3fa8d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/CreateDataInStructureCmd.java @@ -114,7 +114,8 @@ public class CreateDataInStructureCmd implements Command { else { // MemBuffer memBuf = new ProgramStructureProviderContext(program,addr, // struct, dataComp.getParentOffset()); - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(newDataType, -1); + DataTypeInstance dti = + DataTypeInstance.getDataTypeInstance(newDataType, -1, true); struct.replace(index, dti.getDataType(), dti.getLength()); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java index 1c795f79d8..4a8b7bbf1d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java @@ -212,7 +212,7 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen } DataType resultDt = DataUtilities.reconcileAppliedDataType(currentDt, dt, true); - int resultLen = resultDt.getLength(); + int resultLen = resultDt.getAlignedLength(); if (resultDt instanceof Dynamic) { resultLen = DataTypeHelper.requestDtSize(getProvider(), resultDt.getDisplayName(), @@ -222,7 +222,7 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen throw new InvalidDataTypeException("Data types of size 0 are not allowed."); } - return DataTypeInstance.getDataTypeInstance(resultDt, resultLen); + return DataTypeInstance.getDataTypeInstance(resultDt, resultLen, true); } /** @@ -1172,7 +1172,7 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen dtName = dt.getDisplayName(); if (dtString.equals(dtName)) { return DataTypeInstance.getDataTypeInstance(element.getDataType(), - element.getLength()); + element.getLength(), true); } } @@ -1204,7 +1204,7 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen if (maxLength > 0 && newLength > maxLength) { throw new UsrException(newDt.getDisplayName() + " doesn't fit."); } - return DataTypeInstance.getDataTypeInstance(newDt, newLength); + return DataTypeInstance.getDataTypeInstance(newDt, newLength, true); } @SuppressWarnings("unused") // the exception is thrown by subclasses diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java index 83acb51fb7..a27044bf12 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java @@ -570,7 +570,8 @@ abstract class CompositeViewerModel extends AbstractTableModel else if (columnIndex == getDataTypeColumn()) { DataType dt = dtc.getDataType(); int dtLen = dt.getLength(); - return DataTypeInstance.getDataTypeInstance(dt, (dtLen > 0) ? dtLen : dtc.getLength()); + return DataTypeInstance.getDataTypeInstance(dt, (dtLen > 0) ? dtLen : dtc.getLength(), + true); } else if (columnIndex == getNameColumn()) { value = dtc.getFieldName(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java index 3cad1320c8..3e4a4a69cc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java @@ -146,7 +146,7 @@ public class DataTypeHelper { throw new InvalidDataTypeException( "Data type " + dt.getDisplayName() + " has no size and is not allowed."); } - return DataTypeInstance.getDataTypeInstance(dt, dtLen); + return DataTypeInstance.getDataTypeInstance(dt, dtLen, true); } public static int requestDtSize(CompositeEditorProvider provider, String dtName, @@ -203,7 +203,7 @@ public class DataTypeHelper { int maxBytes = model.getMaxReplaceLength(index); return requestBytes(model, dt, maxBytes); } - return DataTypeInstance.getDataTypeInstance(dt, length); + return DataTypeInstance.getDataTypeInstance(dt, length, true); } public static DataTypeInstance requestBytes(CompositeEditorModel model, DataType dt, @@ -228,7 +228,7 @@ public class DataTypeHelper { if (size >= 1) { model.setLastNumBytes(size); - return DataTypeInstance.getDataTypeInstance(dt, size); + return DataTypeInstance.getDataTypeInstance(dt, size, true); } return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java index abafcab546..89cdcf2d08 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java @@ -59,7 +59,8 @@ public class InsertUndefinedAction extends CompositeEditorTableAction { DataType undefinedDt = model.viewComposite.isPackingEnabled() ? Undefined1DataType.dataType : DataType.DEFAULT; - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(undefinedDt, -1); + DataTypeInstance dti = + DataTypeInstance.getDataTypeInstance(undefinedDt, -1, false); model.insert(index, dti.getDataType(), dti.getLength()); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java index 362a1813ed..da56b5b09b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java @@ -161,7 +161,8 @@ class StructureEditorModel extends CompEditorModel { else if (columnIndex == getDataTypeColumn()) { DataType dt = dtc.getDataType(); int dtLen = dt.getLength(); - return DataTypeInstance.getDataTypeInstance(dt, (dtLen > 0) ? dtLen : dtc.getLength()); + return DataTypeInstance.getDataTypeInstance(dt, (dtLen > 0) ? dtLen : dtc.getLength(), + true); } else if (columnIndex == getNameColumn()) { value = dtc.getFieldName(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateArrayAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateArrayAction.java index a9af994281..35061eea45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateArrayAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateArrayAction.java @@ -141,7 +141,7 @@ class CreateArrayAction extends ListingContextAction { } int length = sel.getByteLength(); - int numElements = length / dt.getLength(); + int numElements = length / dt.getAlignedLength(); Command cmd = new CreateArrayInStructureCmd(from.getAddress(), numElements, dt, from.getComponentPath()); @@ -161,7 +161,7 @@ class CreateArrayAction extends ListingContextAction { } length += dtc.getLength(); } - return length / dt.getLength(); + return length / dt.getAlignedLength(); } private int getMaxElements(Structure struct, int index, DataType dt) { @@ -171,7 +171,7 @@ class CreateArrayAction extends ListingContextAction { DataTypeComponent dtc = struct.getComponent(index++); length += dtc.getLength(); } - return length / dt.getLength(); + return length / dt.getAlignedLength(); } private void createArrayAtAddress(Program program, Address addr) { @@ -210,10 +210,13 @@ class CreateArrayAction extends ListingContextAction { return; } DataType dt = data.getDataType(); - int dtLength = data.getLength(); + int elementLength = data.getLength(); + if (!(dt instanceof Dynamic)) { + elementLength = dt.getAlignedLength(); + } int length = (int) range.getLength(); - int numElements = length / dtLength; - CreateArrayCmd cmd = new CreateArrayCmd(addr, numElements, dt, dtLength); + int numElements = length / elementLength; + CreateArrayCmd cmd = new CreateArrayCmd(addr, numElements, dt, elementLength); if (!tool.execute(cmd, program)) { tool.setStatusInfo(cmd.getStatusMsg()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataPlugin.java index 835c92196d..191b4aefd1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/DataPlugin.java @@ -501,7 +501,7 @@ public class DataPlugin extends Plugin implements DataService { } DataTypeInstance dataTypeInstance = DataTypeInstance.getDataTypeInstance(dataType, - new DumbMemBufferImpl(program.getMemory(), start)); + new DumbMemBufferImpl(program.getMemory(), start), false); if (dataTypeInstance == null) { tool.setStatusInfo("Unallowed data type at " + start + ": " + dataType.getName()); return -1; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataOrganizationPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataOrganizationPanel.java deleted file mode 100644 index 4e1213e488..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataOrganizationPanel.java +++ /dev/null @@ -1,494 +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.datamgr; - -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import docking.widgets.checkbox.GCheckBox; -import docking.widgets.label.GLabel; -import ghidra.program.model.data.DataOrganizationImpl; -import ghidra.util.layout.PairLayout; - -public class DataOrganizationPanel extends JPanel { - - JCheckBox charIsSignedCheckbox; - JTextField charSizeComponent; - JTextField wcharSizeComponent; - JTextField shortSizeComponent; - JTextField integerSizeComponent; - JTextField longSizeComponent; - JTextField longLongSizeComponent; - JTextField floatSizeComponent; - JTextField doubleSizeComponent; - JTextField longDoubleSizeComponent; - - JTextField absoluteMaxAlignComponent; - JTextField machineAlignComponent; - JTextField defaultAlignComponent; - JTextField pointerAlignComponent; - - DataOrganizationImpl dataOrganization; - - public DataOrganizationPanel() { - super(new PairLayout(3, 5)); - setUpAbsoluteMaxAlignment(); - setUpMachineAlignment(); - setUpDefaultAlignment(); - setUpPointerAlignment(); - setUpSignedChar(); - setUpCharSize(); - setUpWideCharSize(); - setUpShortSize(); - setUpIntegerSize(); - setUpLongSize(); - setUpLongLongSize(); - setUpFloatSize(); - setUpDoubleSize(); - setUpLongDoubleSize(); - - add(new GLabel("")); - add(new GLabel("")); - add(new GLabel("Absolute Max Alignment")); - add(absoluteMaxAlignComponent); - add(new GLabel("Machine Alignment")); - add(machineAlignComponent); - add(new GLabel("Default Alignment")); - add(defaultAlignComponent); - add(new GLabel("Default Pointer Alignment")); - add(pointerAlignComponent); - - add(new GLabel("")); - add(new GLabel("")); - add(new GLabel("Signed-Char:")); - add(charIsSignedCheckbox); - add(new GLabel("Char Size")); - add(charSizeComponent); - add(new GLabel("Wide-Char Size")); - add(wcharSizeComponent); - add(new GLabel("Short Size")); - add(shortSizeComponent); - add(new GLabel("Integer Size")); - add(integerSizeComponent); - add(new GLabel("Long Size")); - add(longSizeComponent); - add(new GLabel("LongLong Size")); - add(longLongSizeComponent); - add(new GLabel("Float Size")); - add(floatSizeComponent); - add(new GLabel("Double Size")); - add(doubleSizeComponent); - add(new GLabel("LongDouble Size")); - add(longDoubleSizeComponent); - add(new GLabel("")); - add(new GLabel("")); - } - - public void setOrganization(DataOrganizationImpl dataOrganization) { - this.dataOrganization = dataOrganization; - - int absoluteMaxAlignment = dataOrganization.getAbsoluteMaxAlignment(); - int machineAlignment = dataOrganization.getMachineAlignment(); - int defaultAlignment = dataOrganization.getDefaultAlignment(); - int defaultPointerAlignment = dataOrganization.getDefaultPointerAlignment(); - - int charSize = dataOrganization.getCharSize(); - int wcharSize = dataOrganization.getWideCharSize(); - int shortSize = dataOrganization.getShortSize(); - int integerSize = dataOrganization.getIntegerSize(); - int longSize = dataOrganization.getLongSize(); - int longLongSize = dataOrganization.getLongLongSize(); - int floatSize = dataOrganization.getFloatSize(); - int doubleSize = dataOrganization.getDoubleSize(); - int longDoubleSize = dataOrganization.getLongDoubleSize(); - - String maxAlignString = - (absoluteMaxAlignment == 0) ? "none" : Integer.toString(absoluteMaxAlignment); - absoluteMaxAlignComponent.setText(maxAlignString); - machineAlignComponent.setText(Integer.toString(machineAlignment)); - defaultAlignComponent.setText(Integer.toString(defaultAlignment)); - pointerAlignComponent.setText(Integer.toString(defaultPointerAlignment)); - - charSizeComponent.setText(Integer.toString(charSize)); - wcharSizeComponent.setText(Integer.toString(wcharSize)); - shortSizeComponent.setText(Integer.toString(shortSize)); - integerSizeComponent.setText(Integer.toString(integerSize)); - longSizeComponent.setText(Integer.toString(longSize)); - longLongSizeComponent.setText(Integer.toString(longLongSize)); - floatSizeComponent.setText(Integer.toString(floatSize)); - doubleSizeComponent.setText(Integer.toString(doubleSize)); - longDoubleSizeComponent.setText(Integer.toString(longDoubleSize)); - } - - private void setUpSignedChar() { - charIsSignedCheckbox = new GCheckBox(); - charIsSignedCheckbox.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - updateSignedChar(); - } - }); - } - - private void setUpCharSize() { - charSizeComponent = new JTextField(3); - charSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedCharSize(); - } - }); - charSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedCharSize(); - } - }); - } - - private void setUpWideCharSize() { - wcharSizeComponent = new JTextField(3); - wcharSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedWideCharSize(); - } - }); - wcharSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedWideCharSize(); - } - }); - } - - private void setUpShortSize() { - shortSizeComponent = new JTextField(3); - shortSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedShortSize(); - } - }); - shortSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedShortSize(); - } - }); - } - - private void setUpIntegerSize() { - integerSizeComponent = new JTextField(3); - integerSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedIntegerSize(); - } - }); - integerSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedIntegerSize(); - } - }); - } - - private void setUpLongSize() { - longSizeComponent = new JTextField(3); - longSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedLongSize(); - } - }); - longSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedLongSize(); - } - }); - } - - private void setUpLongLongSize() { - longLongSizeComponent = new JTextField(3); - longLongSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedLongLongSize(); - } - }); - longLongSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedLongLongSize(); - } - }); - } - - private void setUpFloatSize() { - floatSizeComponent = new JTextField(3); - floatSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedFloatSize(); - } - }); - floatSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedFloatSize(); - } - }); - } - - private void setUpDoubleSize() { - doubleSizeComponent = new JTextField(3); - doubleSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedDoubleSize(); - } - }); - doubleSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedDoubleSize(); - } - }); - } - - private void setUpLongDoubleSize() { - longDoubleSizeComponent = new JTextField(3); - longDoubleSizeComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedLongDoubleSize(); - } - }); - longDoubleSizeComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedLongDoubleSize(); - } - }); - } - - private void setUpAbsoluteMaxAlignment() { - absoluteMaxAlignComponent = new JTextField(3); - absoluteMaxAlignComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedAbsoluteMaxAlignment(); - } - }); - absoluteMaxAlignComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedAbsoluteMaxAlignment(); - } - }); - } - - private void setUpMachineAlignment() { - machineAlignComponent = new JTextField(3); - machineAlignComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedMachineAlignment(); - } - }); - machineAlignComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedMachineAlignment(); - } - }); - } - - private void setUpDefaultAlignment() { - defaultAlignComponent = new JTextField(3); - defaultAlignComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedDefaultAlignment(); - } - }); - defaultAlignComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedDefaultAlignment(); - } - }); - } - - private void setUpPointerAlignment() { - pointerAlignComponent = new JTextField(3); - pointerAlignComponent.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - updatedDefaultPointerAlignment(); - } - }); - pointerAlignComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // TODO - } - - @Override - public void focusLost(FocusEvent e) { - updatedDefaultPointerAlignment(); - } - }); - } - - protected void updateSignedChar() { - boolean isSigned = charIsSignedCheckbox.isSelected(); - dataOrganization.setCharIsSigned(isSigned); - } - - protected void updatedCharSize() { - int charSize = Integer.decode(charSizeComponent.getText()).intValue(); - dataOrganization.setCharSize(charSize); - } - - protected void updatedWideCharSize() { - int wcharSize = Integer.decode(wcharSizeComponent.getText()).intValue(); - dataOrganization.setWideCharSize(wcharSize); - } - - protected void updatedShortSize() { - int shortSize = Integer.decode(shortSizeComponent.getText()).intValue(); - dataOrganization.setShortSize(shortSize); - } - - protected void updatedIntegerSize() { - int integerSize = Integer.decode(integerSizeComponent.getText()).intValue(); - dataOrganization.setIntegerSize(integerSize); - } - - protected void updatedLongSize() { - int longSize = Integer.decode(longSizeComponent.getText()).intValue(); - dataOrganization.setLongSize(longSize); - } - - protected void updatedLongLongSize() { - int longLongSize = Integer.decode(longLongSizeComponent.getText()).intValue(); - dataOrganization.setLongLongSize(longLongSize); - } - - protected void updatedFloatSize() { - int floatSize = Integer.decode(floatSizeComponent.getText()).intValue(); - dataOrganization.setFloatSize(floatSize); - } - - protected void updatedDoubleSize() { - int doubleSize = Integer.decode(doubleSizeComponent.getText()).intValue(); - dataOrganization.setDoubleSize(doubleSize); - } - - protected void updatedLongDoubleSize() { - int longDoubleSize = Integer.decode(longDoubleSizeComponent.getText()).intValue(); - dataOrganization.setLongDoubleSize(longDoubleSize); - } - - protected void updatedAbsoluteMaxAlignment() { - String maxAlignString = absoluteMaxAlignComponent.getText().toLowerCase(); - int absoluteMax = - ("none".equals(maxAlignString)) ? 0 : Integer.decode(maxAlignString).intValue(); - dataOrganization.setAbsoluteMaxAlignment(absoluteMax); - } - - protected void updatedMachineAlignment() { - int machineAlignment = Integer.decode(machineAlignComponent.getText()).intValue(); - dataOrganization.setMachineAlignment(machineAlignment); - } - - protected void updatedDefaultAlignment() { - int defaultAlignment = Integer.decode(defaultAlignComponent.getText()).intValue(); - dataOrganization.setDefaultAlignment(defaultAlignment); - } - - protected void updatedDefaultPointerAlignment() { - int defaultPointerAlignment = Integer.decode(pointerAlignComponent.getText()).intValue(); - dataOrganization.setDefaultPointerAlignment(defaultPointerAlignment); - } - -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/SizeAlignmentPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/SizeAlignmentPanel.java deleted file mode 100644 index 6efc835b38..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/SizeAlignmentPanel.java +++ /dev/null @@ -1,156 +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.datamgr; - -import java.awt.BorderLayout; -import java.awt.Dimension; - -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.event.TableModelListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableModel; - -import ghidra.program.model.data.DataOrganizationImpl; -import ghidra.util.Msg; -import ghidra.util.exception.NoValueException; -import ghidra.util.table.GhidraTable; - -public class SizeAlignmentPanel extends JPanel { - - GhidraTable table; - DataOrganizationImpl dataOrganization; - - public SizeAlignmentPanel() { - super(new BorderLayout()); - TableModel tableModel = new SizeAlignmentTableModel(); - table = new GhidraTable(tableModel); - table.setAutoEditEnabled(true); - JScrollPane sp = new JScrollPane(table); - table.setPreferredScrollableViewportSize(new Dimension(200, 80)); - add(sp, BorderLayout.CENTER); - } - - public void setOrganization(DataOrganizationImpl dataOrganization) { - this.dataOrganization = dataOrganization; - ((SizeAlignmentTableModel) table.getModel()).fireTableDataChanged(); - } - - class SizeAlignmentTableModel extends AbstractTableModel { - - private final String[] columnNames = new String[] { "Size", "Alignment" }; - private final int SIZE_COLUMN = 0; - private final int ALIGNMENT_COLUMN = 1; - - SizeAlignmentTableModel() { - super(); - } - - @Override - public void addTableModelListener(TableModelListener l) { - // TODO Auto-generated method stub - - } - - @Override - public Class getColumnClass(int columnIndex) { - return Integer.class; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public String getColumnName(int columnIndex) { - return columnNames[columnIndex]; - } - - @Override - public int getRowCount() { - return dataOrganization.getSizeAlignmentCount() + 1; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - int[] sizes = dataOrganization.getSizes(); - if (rowIndex < sizes.length) { - int size = sizes[rowIndex]; - if (columnIndex == SIZE_COLUMN) { - return size; - } - else if (columnIndex == ALIGNMENT_COLUMN) { - try { - return dataOrganization.getSizeAlignment(size); - } - catch (NoValueException e) { - return null; - } - } - } - return null; - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - if (rowIndex == dataOrganization.getSizeAlignmentCount()) { - return columnIndex == SIZE_COLUMN; - } - return columnIndex == ALIGNMENT_COLUMN; - } - - @Override - public void removeTableModelListener(TableModelListener l) { - // TODO Auto-generated method stub - - } - - @Override - public void setValueAt(Object value, int rowIndex, int columnIndex) { - if (value == null) { - return; - } - int[] sizes = dataOrganization.getSizes(); - if (rowIndex < sizes.length) { - int alignment = ((Integer) value).intValue(); - int size = sizes[rowIndex]; - dataOrganization.setSizeAlignment(size, alignment); - } - if (rowIndex == sizes.length) { - int size = ((Integer) value).intValue(); - // Check that we don't already have this size. - try { - dataOrganization.getSizeAlignment(size); - setStatusMessage("An alignment is already defined for a size of " + size + "."); - return; - } - catch (NoValueException e) { - // Actually don't want to find a value so we can set one below. - } - int alignment = size; // Set the alignment to match the size initially. - dataOrganization.setSizeAlignment(size, alignment); - fireTableDataChanged(); - } - } - } - - public void setStatusMessage(String message) { - // TODO Change this to write to the status line in the dialog. - Msg.showError(this, this, "Invalid Input", message); - } - -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreview.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreview.java index 89bec3f921..c53b584ed2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreview.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreview.java @@ -41,7 +41,8 @@ class DataTypePreview implements Preview { public String getPreview(Memory memory, Address addr) { try { MemBuffer mb = new DumbMemBufferImpl(memory, addr); - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dt, mb, MAX_PREVIEW_LENGTH); + DataTypeInstance dti = + DataTypeInstance.getDataTypeInstance(dt, mb, MAX_PREVIEW_LENGTH, false); if (dti == null) { return ""; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java index 82545588e9..1bf6353fb6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToDoubleAction.java @@ -42,7 +42,7 @@ public class ConvertToDoubleAction extends AbstractConvertAction { try { FloatFormat format = FloatFormatFactory.getFloatFormat(dataOrganization.getDoubleSize()); - return format.round(format.getHostFloat(s.getBigInteger())); + return format.round(format.decodeBigFloat(s.getBigInteger())); } catch (UnsupportedFloatFormatException e) { return null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java index 63121d40e7..068730c1db 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/ConvertToFloatAction.java @@ -41,7 +41,7 @@ public class ConvertToFloatAction extends AbstractConvertAction { DataOrganization dataOrganization = program.getDataTypeManager().getDataOrganization(); try { FloatFormat format = FloatFormatFactory.getFloatFormat(dataOrganization.getFloatSize()); - return format.round(format.getHostFloat(s.getBigInteger())); + return format.round(format.decodeBigFloat(s.getBigInteger())); } catch (UnsupportedFloatFormatException e) { return null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CreateArrayAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CreateArrayAction.java index a4d65ce347..31c1adf85e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CreateArrayAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/CreateArrayAction.java @@ -100,16 +100,19 @@ class CreateArrayAction extends ListingContextAction { Variable var = varLoc.getVariable(); if (var.isStackVariable()) { DataType dt = var.getDataType(); - int len = var.getLength(); - int defaultElements = plugin.getMaxStackVariableSize(fun, var); - if (defaultElements <= 0) { - defaultElements = 1; + if (dt.getLength() < 1) { + return; } - int n = getNumElements(dt, Integer.MAX_VALUE, defaultElements); + int availableLen = plugin.getMaxStackVariableSize(fun, var); + if (availableLen <= 0) { + availableLen = 1; + } + int maxElements = availableLen / var.getDataType().getAlignedLength(); + int n = getNumElements(dt, Integer.MAX_VALUE, maxElements); if (n == 0) { return; } - Array array = new ArrayDataType(dt, n, len); + Array array = new ArrayDataType(dt, n, -1); plugin.createData(array, context, true, true); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java index 9738c72714..229dc60db4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java @@ -22,6 +22,7 @@ import ghidra.app.util.cparser.C.ParseException; import ghidra.app.util.parser.FunctionSignatureParser; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.lang.*; import ghidra.program.model.listing.*; import ghidra.program.model.listing.Function.FunctionUpdateType; @@ -1206,6 +1207,7 @@ public class FunctionEditorModel { catch (InvalidInputException e) { // ignore } + setFunctionData(f); isInParsingMode = false; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageAddressEditorDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageAddressEditorDialog.java index ecb59ff7d9..d93e25a9bb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageAddressEditorDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageAddressEditorDialog.java @@ -33,6 +33,7 @@ import ghidra.app.util.datatype.DataTypeSelectionEditor; import ghidra.app.util.datatype.NavigationDirection; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.util.HelpLocation; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java index d90d9c3c32..df158a4e1b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java @@ -202,7 +202,7 @@ public class StackEditorModel extends CompositeEditorModel { dt = element.getDataType(); dtLen = dt.getLength(); return DataTypeInstance.getDataTypeInstance(dt, - (dtLen > 0) ? dtLen : element.getLength()); + (dtLen > 0) ? dtLen : element.getLength(), true); case NAME: String fieldName = getFieldNameAtRow(rowIndex, (StackFrameDataType) viewComposite); if (fieldName == null) { @@ -1127,7 +1127,7 @@ public class StackEditorModel extends CompositeEditorModel { OffsetPairs offsetSelection = getRelOffsetSelection(); int transID = startTransaction("Apply Data Type \"" + dt.getName() + "\""); try { - fieldEdited(DataTypeInstance.getDataTypeInstance(dt, dtLength), index, + fieldEdited(DataTypeInstance.getDataTypeInstance(dt, dtLength, true), index, getDataTypeColumn()); setRelOffsetSelection(offsetSelection); } @@ -1157,7 +1157,7 @@ public class StackEditorModel extends CompositeEditorModel { if (max == Integer.MAX_VALUE) { return Integer.MAX_VALUE; } - return max / dtc.getLength(); + return max / dtc.getDataType().getAlignedLength(); } @Override @@ -1320,7 +1320,7 @@ public class StackEditorModel extends CompositeEditorModel { dtName = dt.getDisplayName(); if (dtString.equals(dtName)) { return DataTypeInstance.getDataTypeInstance(element.getDataType(), - element.getLength()); + element.getLength(), true); } } @@ -1346,7 +1346,7 @@ public class StackEditorModel extends CompositeEditorModel { if (maxLength > 0 && newLength > maxLength) { throw new UsrException(newDt.getDisplayName() + " doesn't fit."); } - return DataTypeInstance.getDataTypeInstance(newDt, newLength); + return DataTypeInstance.getDataTypeInstance(newDt, newLength, true); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java index b2437cf07c..c1cb3cb9be 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java @@ -25,6 +25,7 @@ import ghidra.app.util.bin.format.dwarf4.encoding.*; import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException; import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeImporter.DWARFDataType; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.listing.Program; import ghidra.util.Msg; @@ -381,7 +382,7 @@ public class DWARFDataTypeManager { String mangledName = null; if (name != null) { dt = baseDataTypes.get(name); - if (dt != null && dt.getLength() == dwarfSize && + if (dt != null && dt.getAlignedLength() == dwarfSize && isEncodingCompatible(dwarfEncoding, dt)) { return dt; } @@ -394,6 +395,9 @@ public class DWARFDataTypeManager { dt = switch (dwarfEncoding) { case DWARFEncoding.DW_ATE_address -> baseDataTypeVoid; // TODO: Check if bytesize != 0 - may want to make a void pointer case DWARFEncoding.DW_ATE_boolean -> dwarfSize == 1 ? baseDataTypeBool : null; + // TODO: Float lookup by length must use "raw" encoding size since "aligned" lengths + // may be duplicated across different float types. Lookup by name is preferred. + // May need to add name lookup capability to AbstractFloatDataType case DWARFEncoding.DW_ATE_float -> AbstractFloatDataType.getFloatDataType(dwarfSize, getCorrectDTMForFixedLengthTypes(name, dwarfSize)); case DWARFEncoding.DW_ATE_signed -> AbstractIntegerDataType.getSignedDataType(dwarfSize, @@ -426,6 +430,7 @@ public class DWARFDataTypeManager { return dt; } + private DataTypeManager getCorrectDTMForFixedLengthTypes(String name, int dwarfSize) { // If the requested name of the base type appears to have a bitsize string // embedded in it, this chunk of code will switch between using the normal DTM diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliAbstractSig.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliAbstractSig.java index 9897ffc86a..a0d1d486a6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliAbstractSig.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliAbstractSig.java @@ -25,6 +25,8 @@ import ghidra.app.util.bin.format.pe.cli.streams.CliStreamMetadata; import ghidra.app.util.bin.format.pe.cli.tables.*; import ghidra.app.util.bin.format.pe.cli.tables.indexes.CliIndexTypeDefOrRef; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.Float32DataType; +import ghidra.program.model.data.floats.Float64DataType; import ghidra.util.exception.InvalidInputException; public abstract class CliAbstractSig extends CliBlob implements CliRepresentable { @@ -139,9 +141,9 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable return UnsignedIntegerDataType.dataType; case ELEMENT_TYPE_R4: - return Float4DataType.dataType; + return Float32DataType.dataType; case ELEMENT_TYPE_R8: - return Float8DataType.dataType; + return Float64DataType.dataType; case ELEMENT_TYPE_I8: return LongLongDataType.dataType; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java index f27e125b47..a28a9fad82 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java @@ -32,6 +32,8 @@ import ghidra.app.util.bin.format.pe.cli.tables.CliTableMethodDef.CliMethodDefRo import ghidra.app.util.bin.format.pe.cli.tables.CliTypeTable; import ghidra.app.util.bin.format.pe.cli.tables.indexes.CliIndexCustomAttributeType; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.Float32DataType; +import ghidra.program.model.data.floats.Float64DataType; import ghidra.util.Msg; import ghidra.util.exception.InvalidInputException; @@ -410,12 +412,12 @@ public class CliBlobCustomAttrib extends CliBlob { case ELEMENT_TYPE_R4: addFixedArg(processFixedArgs, baseTypeCode, - reader.readNextByteArray(Float4DataType.dataType.getLength())); + reader.readNextByteArray(Float32DataType.dataType.getLength())); break; case ELEMENT_TYPE_R8: addFixedArg(processFixedArgs, baseTypeCode, - reader.readNextByteArray(Float8DataType.dataType.getLength())); + reader.readNextByteArray(Float64DataType.dataType.getLength())); break; case ELEMENT_TYPE_STRING: diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/RTTI0DataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/RTTI0DataType.java index 23b498a8e0..d0f1511ba7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/RTTI0DataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/microsoft/RTTI0DataType.java @@ -15,8 +15,7 @@ */ package ghidra.app.util.datatype.microsoft; -import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAbsoluteAddress; -import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.is64Bit; +import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsImpl; @@ -111,7 +110,7 @@ public class RTTI0DataType extends RTTIDataType { Address nameAddress = start.add(nameOffset); MemoryBufferImpl nameBuf = new MemoryBufferImpl(buf.getMemory(), nameAddress, 1024); DataTypeInstance dti = - DataTypeInstance.getDataTypeInstance(new TerminatedStringDataType(), nameBuf); + DataTypeInstance.getDataTypeInstance(new TerminatedStringDataType(), nameBuf, false); if (dti != null) { comps[2] = new ReadOnlyDataTypeComponent(dti.getDataType(), this, dti.getLength(), 2, @@ -178,7 +177,8 @@ public class RTTI0DataType extends RTTIDataType { WrappedMemBuffer nameBuf = null; try { nameBuf = new WrappedMemBuffer(buf, getNameOffset(buf.getMemory().getProgram())); - dti = DataTypeInstance.getDataTypeInstance(new TerminatedStringDataType(), nameBuf); + dti = DataTypeInstance.getDataTypeInstance(new TerminatedStringDataType(), nameBuf, + false); } catch (AddressOutOfBoundsException e) { // ignore diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java index 4be03fb360..7c389cda9a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledDataType.java @@ -25,6 +25,7 @@ import org.apache.commons.lang3.StringUtils; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; +import ghidra.program.model.data.floats.Float128DataType; import ghidra.program.model.symbol.Namespace; /** @@ -283,7 +284,7 @@ public class DemangledDataType extends DemangledType { dt = FloatDataType.dataType; } else if (FLOAT128.equals(name)) { - dt = new TypedefDataType(FLOAT128, Float16DataType.dataType); + dt = new TypedefDataType(FLOAT128, Float128DataType.dataType); } else if (DOUBLE.equals(name)) { dt = DoubleDataType.dataType; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DefinedDataXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DefinedDataXmlMgr.java index 62dc99923e..f12a983a9b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DefinedDataXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DefinedDataXmlMgr.java @@ -149,7 +149,7 @@ class DefinedDataXmlMgr { private void clearExistingData(Address addr, int size, DataType dt, Listing listing) { DumbMemBufferImpl buf = new DumbMemBufferImpl(program.getMemory(), addr); - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dt, buf, size); + DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dt, buf, size, false); if (dti != null) { boolean doClear = false; Address maxAddr = addr.add(dti.getLength() - 1); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java index f26e95e0d4..f3ed945cdb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java @@ -784,7 +784,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E false) : LittleEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, false); - BigDecimal val = ff.round(ff.getHostFloat(encoding)); + BigDecimal val = ff.round(ff.decodeBigFloat(encoding)); return val.toString(); } } @@ -879,7 +879,7 @@ public abstract class ProcessorEmulatorTestAdapter extends TestCase implements E if (reg != null && floatRegSet.contains(reg)) { FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(size); BigDecimal hostFloat = - floatFormat.round(floatFormat.getHostFloat(new BigInteger(1, values))); + floatFormat.round(floatFormat.decodeBigFloat(new BigInteger(1, values))); floatStr = " (" + hostFloat.toString() + ")"; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPluginTest.java index 575f6e7370..9bfa4df093 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPluginTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.*; import org.junit.*; -import ghidra.app.events.ProgramActivatedPluginEvent; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.app.plugin.core.datapreview.DataTypePreviewPlugin.DTPPTableModel; @@ -174,6 +173,7 @@ public class DataTypePreviewPluginTest extends AbstractGhidraHeadedIntegrationTe // integerSize = 4; // longSize = 4; // defaultAlignment = 1; + // alignment per size: 2->2, 4->4, 8->4 plugin.addDataType(IntegerDataType.dataType); plugin.addDataType(LongDataType.dataType); @@ -190,12 +190,11 @@ public class DataTypePreviewPluginTest extends AbstractGhidraHeadedIntegrationTe assertEquals(6, model.getRowCount()); Program program = buildProgram(); - DataOrganizationImpl dataOrganization = - (DataOrganizationImpl) program.getDataTypeManager().getDataOrganization(); - + (DataOrganizationImpl) program.getCompilerSpec().getDataOrganization(); dataOrganization.setLongSize(8); + // Open program in tool and goto tested memory location env.open(program); gotoService.goTo(addr(program, 0x100df26)); @@ -210,19 +209,23 @@ public class DataTypePreviewPluginTest extends AbstractGhidraHeadedIntegrationTe assertEquals("61004D00200065h", model.getValueAt(4, DTPPTableModel.PREVIEW_COL));// 8-byte long at offset 4 assertEquals("72h", model.getValueAt(5, DTPPTableModel.PREVIEW_COL));// 2-byte short at offset 12 - // deactivate program - plugin.getTool().firePluginEvent(new ProgramActivatedPluginEvent("Test", null)); - waitForPostedSwingRunnables(); + env.close(program); + // Re-create program with mutated data-organization to simulate shift to 3-byte aligned types // NOTE: Altering data organization on-the-fly is not supported - dataOrganization.setDefaultAlignment(2); + + // alignment map should jive with 3-byte mutliple primitive type sizes + dataOrganization.clearSizeAlignmentMap(); + dataOrganization.setSizeAlignment(1, 1); + dataOrganization.setSizeAlignment(3, 3); + dataOrganization.setSizeAlignment(6, 6); dataOrganization.setShortSize(3); dataOrganization.setIntegerSize(3); dataOrganization.setLongSize(6); - // activate program - plugin.getTool().firePluginEvent(new ProgramActivatedPluginEvent("Test", program)); - waitForPostedSwingRunnables(); + // Open program in tool and goto tested memory location + program = buildProgram(); + env.open(program); gotoService.goTo(addr(program, 0x100df26)); @@ -231,8 +234,8 @@ public class DataTypePreviewPluginTest extends AbstractGhidraHeadedIntegrationTe assertEquals("680054h", model.getValueAt(2, DTPPTableModel.PREVIEW_COL));// 3-byte short assertEquals("680054h", model.getValueAt(3, DTPPTableModel.PREVIEW_COL));// 3-byte int at offset 0 - assertEquals("4D00200065h", model.getValueAt(4, DTPPTableModel.PREVIEW_COL));// 6-byte long at offset 4 - assertEquals("720061h", model.getValueAt(5, DTPPTableModel.PREVIEW_COL));// 3-byte short at offset 10 + assertEquals("61004D0020h", model.getValueAt(4, DTPPTableModel.PREVIEW_COL));// 6-byte long at offset 6 + assertEquals("670072h", model.getValueAt(5, DTPPTableModel.PREVIEW_COL));// 3-byte short at offset 12 } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java index 537921988e..75cc258037 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/equate/EquatePlugin1Test.java @@ -863,7 +863,7 @@ public class EquatePlugin1Test extends AbstractGhidraHeadedIntegrationTest { } else if (name.indexOf("Float") >= 0) { assertTrue(popupPath[1].startsWith("Float")); - assertTrue(popupPath[1].endsWith(" 5.605194E-45")); + assertTrue(popupPath[1].endsWith(" 5.6051939E-45")); } else { fail("Unhandled Convert item: " + name); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/script/GhidraScriptRealProgramTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/script/GhidraScriptRealProgramTest.java index ddb316cdcd..f37b09f12e 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/script/GhidraScriptRealProgramTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/script/GhidraScriptRealProgramTest.java @@ -23,6 +23,7 @@ import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin; import ghidra.app.plugin.core.script.GhidraScriptMgrPlugin; import ghidra.framework.plugintool.PluginTool; +import ghidra.pcode.floatformat.BigFloat; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.*; @@ -400,13 +401,13 @@ public class GhidraScriptRealProgramTest extends AbstractGhidraHeadedIntegration address = script.toAddr(0x010085a7); data = script.createFloat(address); assertNotNull(data); - assertEquals(-1.4682312f, data.getValue()); + assertEquals("-1.468231", ((BigFloat) data.getValue()).toString()); script.clearListing(address); address = script.toAddr(0x010085a9); data = script.createDouble(address); assertNotNull(data); - assertEquals(-8.373196719664668E298, data.getValue()); + assertEquals("-8.37319671966467E+298", ((BigFloat) data.getValue()).toString()); script.clearListing(address); } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertDoubleAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertDoubleAction.java index a894f983d6..64fb76abbd 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertDoubleAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertDoubleAction.java @@ -64,7 +64,7 @@ public class ConvertDoubleAction extends ConvertConstantAction { private static BigDecimal value(int size, Scalar s) { try { FloatFormat format = FloatFormatFactory.getFloatFormat(size); - return format.round(format.getHostFloat(s.getBigInteger())); + return format.round(format.decodeBigFloat(s.getBigInteger())); } catch (UnsupportedFloatFormatException e) { return null; diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertFloatAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertFloatAction.java index ba33fb2de9..3aed950432 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertFloatAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ConvertFloatAction.java @@ -64,7 +64,7 @@ public class ConvertFloatAction extends ConvertConstantAction { private static BigDecimal value(int size, Scalar s) { try { FloatFormat format = FloatFormatFactory.getFloatFormat(size); - return format.round(format.getHostFloat(s.getBigInteger())); + return format.round(format.decodeBigFloat(s.getBigInteger())); } catch (UnsupportedFloatFormatException e) { return null; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java index 397fb2fb03..e153a7bb67 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java @@ -794,7 +794,7 @@ public class PdbParser { void createData(Address address, DataType dataType, MessageLog log) { DumbMemBufferImpl memBuffer = new DumbMemBufferImpl(program.getMemory(), address); - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dataType, memBuffer); + DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dataType, memBuffer, false); if (dti == null) { log.appendMsg("PDB", "Failed to apply datatype " + dataType.getName() + " at " + address); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index 6e6dd95ee8..f6fc4d1b2e 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -115,7 +115,7 @@ public class DataSymbolApplier extends MsSymbolApplier { //TODO: might want to do an ApplyDatatypeCmd here!!! DumbMemBufferImpl memBuffer = new DumbMemBufferImpl(applicator.getProgram().getMemory(), address); - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dataType, memBuffer); + DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dataType, memBuffer, false); if (dti == null) { applicator.appendLogMsg( "Error: Failed to apply datatype " + dataType.getName() + " at " + address); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java index f391b82841..afedefb47d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java @@ -20,6 +20,7 @@ import java.util.*; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.util.exception.AssertException; /** @@ -516,21 +517,24 @@ public class PdbPrimitiveTypeApplicator { return getRealType(16, "float128"); } - /* + /** * First get type from "other" list, which are typedefs to underlying primitives. If it does * not exist, then find the proper underlying primitive, create the typedef, and cache this * newly minted (typedef) unique primitive type. + * @param rawSize "raw" encoding size in bytes + * @param name assigned type name */ - private DataType getRealType(int size, String name) { + private DataType getRealType(int rawSize, String name) { DataType dataType = otherPrimitives.get(name); if (dataType != null) { return dataType; } - dataType = floatGhidraPrimitives.get(size); + dataType = floatGhidraPrimitives.get(rawSize); DataType resolved; if (dataType == null) { - resolved = resolve(AbstractFloatDataType.getFloatDataType(size, getDataTypeManager())); - floatGhidraPrimitives.put(size, resolved); + resolved = + resolve(AbstractFloatDataType.getFloatDataType(rawSize, getDataTypeManager())); + floatGhidraPrimitives.put(rawSize, resolved); if (resolved instanceof Undefined) { // Not a real type implemented in Ghidra. DataType type = createTypedef(name, resolved); resolved = resolve(type); diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java index bf1a407cb2..b3f32c9623 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAbsTest.java @@ -38,23 +38,23 @@ public class OpBehaviorFloatAbsTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(2.5); long result = op.evaluateUnary(8, 8, ff.opAbs(a)); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -66,23 +66,23 @@ public class OpBehaviorFloatAbsTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java index 4a7f4267c1..6daa0bfbd5 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatAddTest.java @@ -39,32 +39,32 @@ public class OpBehaviorFloatAddTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(1.234); long b = ff.getEncoding(1.123); long result = op.evaluateBinary(8, 8, a, b);// 1.234 + 1.123 - Assert.assertEquals(2.357, ff.getHostFloat(result), 0); + Assert.assertEquals(2.357, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-1.123); result = op.evaluateBinary(8, 8, a, b);// -1.123 + 1.123 - Assert.assertEquals(0d, ff.getHostFloat(result), 0); + Assert.assertEquals(0d, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// +INFINITY + 1.123 - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + 1.123 - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + -INFINITY - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + +INFINITY - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); b = ff.getEncoding(1.123); result = op.evaluateBinary(8, 8, a, b);// NaN + 1.123 - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -77,32 +77,32 @@ public class OpBehaviorFloatAddTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(1.234d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.123d)); BigInteger result = op.evaluateBinary(8, 8, a, b);// 1.234 + 1.123 - Assert.assertEquals(ff.getBigFloat(2.357), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.357), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-1.123d)); result = op.evaluateBinary(8, 8, a, b);// -1.123 + 1.123 - Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigInfinity(false)); result = op.evaluateBinary(8, 8, a, b);// +INFINITY + 1.123 - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + 1.123 - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + -INFINITY - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getEncoding(ff.getBigInfinity(false)); result = op.evaluateBinary(8, 8, a, b);// -INFINITY + +INFINITY - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); b = ff.getEncoding(ff.getBigFloat(1.123d)); result = op.evaluateBinary(8, 8, a, b);// NaN + 1.123 - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java index 119c360acc..29cd37cc61 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatCeilTest.java @@ -38,23 +38,23 @@ public class OpBehaviorFloatCeilTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(2.5); long result = ff.opCeil(a); - Assert.assertEquals(3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -66,23 +66,23 @@ public class OpBehaviorFloatCeilTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java index 76d484ee4e..85649639e4 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatDivTest.java @@ -39,19 +39,19 @@ public class OpBehaviorFloatDivTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(3.75); long b = ff.getEncoding(1.5); long result = ff.opDiv(a, b); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); b = ff.getEncoding(0); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-3.75); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NaN); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -64,19 +64,19 @@ public class OpBehaviorFloatDivTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(3.75d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); b = ff.getBigZeroEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-3.75d)); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigNaNEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java index b67798e0f3..1ecd39a17d 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloat2FloatTest.java @@ -39,23 +39,23 @@ public class OpBehaviorFloatFloat2FloatTest extends AbstractOpBehaviorTest { long a = ff4.getEncoding(1.75); long result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(1.75, ff8.getHostFloat(result), 0); + Assert.assertEquals(1.75, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(-1.75); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(-1.75, ff8.getHostFloat(result), 0); + Assert.assertEquals(-1.75, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(Float.POSITIVE_INFINITY); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff8.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(Float.NEGATIVE_INFINITY); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff8.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(Float.NaN); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(Double.NaN, ff8.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff8.decodeHostFloat(result), 0); } @Test @@ -68,23 +68,23 @@ public class OpBehaviorFloatFloat2FloatTest extends AbstractOpBehaviorTest { BigInteger a = ff4.getEncoding(ff4.getBigFloat(1.75d)); BigInteger result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(ff8.getBigFloat(1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(1.75d), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigFloat(-1.75d)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(ff8.getBigFloat(-1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(-1.75d), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigInfinity(false)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(ff8.getBigInfinity(false), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(false), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigInfinity(true)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(ff8.getBigInfinity(true), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(true), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigNaN(false)); result = op.evaluateUnary(8, 4, a); - Assert.assertEquals(ff8.getBigNaN(false), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigNaN(false), ff8.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java index 8841e3fd45..1d13db78d0 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatFloorTest.java @@ -38,27 +38,27 @@ public class OpBehaviorFloatFloorTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(2.5); long result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.0); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(-3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -70,27 +70,27 @@ public class OpBehaviorFloatFloorTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.0d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java index bb93e7bcca..3d506b61f6 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatInt2FloatTest.java @@ -41,19 +41,19 @@ public class OpBehaviorFloatInt2FloatTest extends AbstractOpBehaviorTest { long result = op.evaluateUnary(4, 4, 2); Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used - Assert.assertEquals(2.0d, ff.getHostFloat(result), 0); + Assert.assertEquals(2.0d, ff.decodeHostFloat(result), 0); result = op.evaluateUnary(4, 4, -2); Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used - Assert.assertEquals(-2.0d, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0d, ff.decodeHostFloat(result), 0); result = op.evaluateUnary(4, 4, 0); Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used - Assert.assertEquals(0d, ff.getHostFloat(result), 0); + Assert.assertEquals(0d, ff.decodeHostFloat(result), 0); result = op.evaluateUnary(4, 4, 0x0ffffffffL); Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used - Assert.assertEquals(-1.0d, ff.getHostFloat(result), 0); + Assert.assertEquals(-1.0d, ff.decodeHostFloat(result), 0); } @Test @@ -67,20 +67,20 @@ public class OpBehaviorFloatInt2FloatTest extends AbstractOpBehaviorTest { BigInteger result = op.evaluateUnary(4, 4, BigInteger.valueOf(2)); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.decodeBigFloat(result)); result = op.evaluateUnary(4, 4, BigInteger.valueOf(-2)); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); result = op.evaluateUnary(4, 4, BigInteger.ZERO); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.decodeBigFloat(result)); BigInteger NEG_ONE = Utils.bytesToBigInteger( new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 4, false, false); result = op.evaluateUnary(4, 4, NEG_ONE); - Assert.assertEquals(ff.getBigFloat(-1.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-1.0d), ff.decodeBigFloat(result)); } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java index fb83fa3f8a..3d7a4f3022 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatMultTest.java @@ -39,19 +39,19 @@ public class OpBehaviorFloatMultTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(2.5); long b = ff.getEncoding(1.5); long result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(3.75, ff.getHostFloat(result), 0); + Assert.assertEquals(3.75, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NaN); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -64,19 +64,19 @@ public class OpBehaviorFloatMultTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigFloat(3.75d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.75d), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigNaNEncoding(false); result = op.evaluateBinary(8, 8, a, b); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java index 257507e6eb..c2143f7dde 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatNegTest.java @@ -38,23 +38,23 @@ public class OpBehaviorFloatNegTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(2.5); long result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(-2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -66,23 +66,23 @@ public class OpBehaviorFloatNegTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java index 37eaab782a..90ef4cdfbd 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatRoundTest.java @@ -38,39 +38,39 @@ public class OpBehaviorFloatRoundTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(2.5); long result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(2.25); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(2.75); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.25); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.75); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(-3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -82,39 +82,39 @@ public class OpBehaviorFloatRoundTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(2.25d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(2.75d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.25d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.75d)); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = op.evaluateUnary(8, 8, a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java index 2836a0e4bf..d30c91ef47 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSqrtTest.java @@ -37,7 +37,7 @@ public class OpBehaviorFloatSqrtTest extends AbstractOpBehaviorTest { long longbits = ff.getEncoding(2.0); longbits = op.evaluateUnary(8, 8, longbits); - double d = ff.getHostFloat(longbits); + double d = ff.decodeHostFloat(longbits); Assert.assertEquals("1.414213562373095", Double.toString(d).substring(0, 17)); } @@ -52,7 +52,7 @@ public class OpBehaviorFloatSqrtTest extends AbstractOpBehaviorTest { BigFloat big = ff.getBigFloat(2.0); BigInteger encoding = ff.getEncoding(big); encoding = op.evaluateUnary(8, 8, encoding); - BigFloat result = ff.getHostFloat(encoding); + BigFloat result = ff.decodeBigFloat(encoding); Assert.assertEquals("1.414213562373095", ff.round(result).toString()); } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java index f0966507c6..b9dee62599 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/opbehavior/OpBehaviorFloatSubTest.java @@ -39,32 +39,32 @@ public class OpBehaviorFloatSubTest extends AbstractOpBehaviorTest { long a = ff.getEncoding(1.5); long b = ff.getEncoding(1.25); long result = op.evaluateBinary(8, 8, a, b);// 1.5 - 1.25 - Assert.assertEquals(0.25, ff.getHostFloat(result), 0); + Assert.assertEquals(0.25, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-1.25); result = op.evaluateBinary(8, 8, a, b);// -1.25 - 1.25 - Assert.assertEquals(-2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// +INFINITY - 1.25 - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - 1.25 - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NEGATIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - -INFINITY - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.POSITIVE_INFINITY); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - +INFINITY - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); b = ff.getEncoding(1.25); result = op.evaluateBinary(8, 8, a, b);// NaN - 1.25 - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -77,32 +77,32 @@ public class OpBehaviorFloatSubTest extends AbstractOpBehaviorTest { BigInteger a = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.25d)); BigInteger result = op.evaluateBinary(8, 8, a, b);// 1.5 - 1.25 - Assert.assertEquals(ff.getBigFloat(0.25d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(0.25d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-1.25d)); result = op.evaluateBinary(8, 8, a, b);// -1.25 - 1.25 - Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = op.evaluateBinary(8, 8, a, b);// +INFINITY - 1.25 - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - 1.25 - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(true); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - -INFINITY - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(false); result = op.evaluateBinary(8, 8, a, b);// -INFINITY - +INFINITY - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); b = ff.getEncoding(ff.getBigFloat(1.25d)); result = op.evaluateBinary(8, 8, a, b);// NaN - 1.25 - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/core/data/ProgramProviderContext.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/core/data/ProgramProviderContext.java index f6f148a340..80c3c7b391 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/core/data/ProgramProviderContext.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/core/data/ProgramProviderContext.java @@ -57,7 +57,8 @@ public class ProgramProviderContext implements DataTypeProviderContext { } DataType dt = data.getDataType(); - int length = data.getLength(); + int length = DataTypeComponentImpl.getPreferredComponentLength(dt, + Math.max(data.getLength(), dt.getAlignedLength())); String label = null; Symbol symbol = data.getPrimarySymbol(); if (symbol != null && !symbol.isDynamic()) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/BigFloat.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/BigFloat.java index b8c8b68e28..7d452a0300 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/BigFloat.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/BigFloat.java @@ -15,8 +15,9 @@ */ package ghidra.pcode.floatformat; -import java.math.BigDecimal; -import java.math.BigInteger; +import java.math.*; +import java.util.HashMap; +import java.util.Map; /** * An IEEE 754 floating point class. @@ -31,8 +32,20 @@ import java.math.BigInteger; * *

Operations compute exact result then round to nearest even. */ -public strictfp class BigFloat implements Comparable { - final int fracbits; // there are fracbits+1 significant bits. +public class BigFloat implements Comparable { + + public static final String INFINITY = "Infinity"; + public static final String POSITIVE_INFINITY = "+" + INFINITY; + public static final String NEGATIVE_INFINITY = "-" + INFINITY; + public static final String NAN = "NaN"; + + private static final int INFINITE_SCALE = -(64 * 1024); + public static final BigDecimal BIG_POSITIVE_INFINITY = + new BigDecimal(BigInteger.ONE, INFINITE_SCALE); + public static final BigDecimal BIG_NEGATIVE_INFINITY = + (new BigDecimal(BigInteger.ONE, INFINITE_SCALE)).negate(); + + final int fracbits; // number of significant mantissa bits including implied msb if relavent final int expbits; // # bits used for exponent final int maxScale; @@ -40,19 +53,22 @@ public strictfp class BigFloat implements Comparable { FloatKind kind; - // -1, +1 - int sign; - // normal numbers have unscaled.bitLength() = fracbits+1 + int sign; // -1, +1 + + // normal numbers have unscaled.bitLength() = fracbits+1 // subnormal numbers have scale=0 and unscaled.bitLength() <= fracbits BigInteger unscaled; int scale; + private static Map defaultDisplayContextMap = new HashMap<>(); + /** * Construct a BigFloat. If kind is FINITE, the value is sign*unscaled*2^(scale-fracbits). *

* NOTE: Requires that normal values are constructed in a normal form as with denormal values. * - * @param fracbits number of fractional bits (positive non-zero value) + * @param fracbits number of fractional bits (positive non-zero value; includes additional + * implied bit if relavent). * @param expbits maximum number of bits in exponent (positive non-zero value) * @param kind the Kind, FINITE, INFINITE, ... * @param sign +1 or -1 @@ -71,8 +87,8 @@ public strictfp class BigFloat implements Comparable { this.maxScale = (1 << (expbits - 1)) - 1; this.minScale = 1 - this.maxScale; - if (unscaled.bitLength() > (fracbits + 1)) { - throw new IllegalArgumentException("unscaled value exceeds " + (fracbits + 1) + + if (unscaled.bitLength() > fracbits) { + throw new IllegalArgumentException("unscaled value exceeds " + fracbits + " bits in length (length=" + unscaled.bitLength() + ")"); } if (scale < minScale || scale > maxScale) { @@ -182,7 +198,7 @@ public strictfp class BigFloat implements Comparable { */ public static BigFloat infinity(int fracbits, int expbits, int sign) { return new BigFloat(fracbits, expbits, FloatKind.INFINITE, sign, - BigInteger.ONE.shiftLeft(fracbits), (1 << (expbits - 1)) - 1); + BigInteger.ONE.shiftLeft(fracbits - 1), (1 << (expbits - 1)) - 1); } /** @@ -223,7 +239,7 @@ public strictfp class BigFloat implements Comparable { * @return {@code true} if this BigFloat is FINITE and normal. */ public boolean isNormal() { - return kind == FloatKind.FINITE && unscaled.bitLength() == (fracbits + 1); + return kind == FloatKind.FINITE && unscaled.bitLength() == fracbits; } /** @@ -236,7 +252,7 @@ public strictfp class BigFloat implements Comparable { */ public boolean isDenormal() { return kind == FloatKind.FINITE && !unscaled.equals(BigInteger.ZERO) && - unscaled.bitLength() <= fracbits; + unscaled.bitLength() < fracbits; } /** @@ -263,7 +279,7 @@ public strictfp class BigFloat implements Comparable { return; } - int extrabits = Math.max(unscaled.bitLength() - (fracbits + 1), minScale - scale); + int extrabits = Math.max(unscaled.bitLength() - fracbits, minScale - scale); if (extrabits <= 0) { throw new AssertionError("Rounding with no extra bits of precision"); @@ -279,7 +295,7 @@ public strictfp class BigFloat implements Comparable { if (midbitset && (eps || odd)) { unscaled = unscaled.add(BigInteger.ONE); // handle overflowing carry - if (unscaled.bitLength() > fracbits + 1) { + if (unscaled.bitLength() > fracbits) { assert (unscaled.bitLength() == unscaled.getLowestSetBit() + 1); unscaled = unscaled.shiftRight(1); scale += 1; @@ -295,14 +311,15 @@ public strictfp class BigFloat implements Comparable { if (kind != FloatKind.FINITE || unscaled.signum() == 0) { throw new AssertionError("lead bit of non-finite or zero"); } - return unscaled.bitLength() - fracbits + scale; + return unscaled.bitLength() - fracbits + scale + 1; } /** * If finite, the returned BigDecimal is exactly equal to this. If not finite, one of the * FloatFormat.BIG_* constants is returned. * - * @return a BigDecimal + * @return a BigDecimal or null if value is NaN (i.e., {@link FloatKind#QUIET_NAN} or + * {@link FloatKind#SIGNALING_NAN}). */ public BigDecimal toBigDecimal() { switch (kind) { @@ -312,7 +329,7 @@ public strictfp class BigFloat implements Comparable { } int unusedBits = Math.max(unscaled.getLowestSetBit(), 0); BigInteger val = unscaled; - int iscale = scale - fracbits; + int iscale = scale - fracbits + 1; BigDecimal x; if (iscale >= -unusedBits) { x = new BigDecimal(val.shiftLeft(iscale)); @@ -330,11 +347,10 @@ public strictfp class BigFloat implements Comparable { } return x; case INFINITE: - return sign < 0 ? FloatFormat.BIG_NEGATIVE_INFINITY - : FloatFormat.BIG_POSITIVE_INFINITY; + return sign < 0 ? BIG_NEGATIVE_INFINITY : BIG_POSITIVE_INFINITY; case QUIET_NAN: case SIGNALING_NAN: - return FloatFormat.BIG_NaN; + return null; default: throw new AssertionError("unknown BigFloat kind: " + kind); } @@ -359,15 +375,16 @@ public strictfp class BigFloat implements Comparable { String binary; if (this.isNormal()) { binary = "1." + unscaled.toString(2).substring(1); - ascale += (unscaled.bitLength() - (fracbits + 1)); + ascale += (unscaled.bitLength() - fracbits); } else { // subnormal - assert (unscaled.bitLength() <= fracbits); + assert (unscaled.bitLength() < fracbits); if (unscaled.equals(BigInteger.ZERO)) { return String.format("%s0b0.0", s); } binary = - "0." + "0".repeat(fracbits - unscaled.bitLength()) + unscaled.toString(2); + "0." + "0".repeat(fracbits - unscaled.bitLength() - 1) + + unscaled.toString(2); } binary = binary.replaceAll("0*$", ""); if (binary.endsWith(".")) { @@ -497,7 +514,7 @@ public strictfp class BigFloat implements Comparable { // nbits(x) - nbits(y) <= nbits(x/y) <= nbits(x) - nbits(y) + 1 // so // this + lshift - other = fracbits+2 => - int lshift = fracbits + 2 + other.unscaled.bitLength() - this.unscaled.bitLength(); + int lshift = fracbits + 1 + other.unscaled.bitLength() - this.unscaled.bitLength(); this.upscale(lshift); BigInteger qr[] = this.unscaled.divideAndRemainder(other.unscaled); @@ -505,7 +522,7 @@ public strictfp class BigFloat implements Comparable { BigInteger r = qr[1]; this.sign *= other.sign; - this.scale -= other.scale - fracbits; + this.scale -= other.scale - fracbits + 1; this.unscaled = q; this.internalRound(r.signum() != 0); } @@ -545,9 +562,9 @@ public strictfp class BigFloat implements Comparable { // this and other are finite this.sign *= other.sign; this.unscaled = this.unscaled.multiply(other.unscaled); - this.scale += other.scale - fracbits; + this.scale += other.scale - fracbits + 1; - this.scaleUpTo(fracbits + 2); + this.scaleUpTo(fracbits + 1); this.internalRound(false); } @@ -639,10 +656,10 @@ public strictfp class BigFloat implements Comparable { protected void add0(BigFloat other) { int d = this.scale - other.scale; - if (d > fracbits + 1) { + if (d > fracbits) { return; } - else if (d < -(fracbits + 1)) { + else if (d < -fracbits) { this.copyFrom(other); return; } @@ -664,7 +681,7 @@ public strictfp class BigFloat implements Comparable { this.scale = a.scale - 1; this.unscaled = a.unscaled.shiftLeft(1).add(b.unscaled.shiftRight(d - 1)); - scaleUpTo(fracbits + 2); + scaleUpTo(fracbits + 1); internalRound(residue); } @@ -672,10 +689,10 @@ public strictfp class BigFloat implements Comparable { protected void sub0(BigFloat other) { int d = this.scale - other.scale; - if (d > fracbits + 2) { + if (d > fracbits + 1) { return; } - else if (d < -(fracbits + 2)) { + else if (d < -(fracbits + 1)) { this.copyFrom(other); return; } @@ -710,7 +727,7 @@ public strictfp class BigFloat implements Comparable { this.sign *= -1; this.unscaled = this.unscaled.negate(); } - scaleUpTo(fracbits + 2); + scaleUpTo(fracbits + 1); internalRound(residue); } @@ -751,11 +768,11 @@ public strictfp class BigFloat implements Comparable { BigInteger bit; //// force at least fracbits+2 bits of precision in the result - int sigbits = 2 * fracbits + 3; + int sigbits = 2 * fracbits + 2; this.scaleUpTo(sigbits); // scale+fracbits needs to be even for the sqrt computation - if (((scale + fracbits) & 1) != 0) { + if (((scale + fracbits - 1) & 1) != 0) { upscale(1); } @@ -778,7 +795,7 @@ public strictfp class BigFloat implements Comparable { } unscaled = result; - scale = (scale + fracbits) / 2; + scale = (scale + fracbits - 1) / 2; internalRound(residue.signum() != 0); } @@ -790,7 +807,7 @@ public strictfp class BigFloat implements Comparable { makeZero(); return; } - int nbitsUnderOne = fracbits - scale; + int nbitsUnderOne = fracbits - scale - 1; unscaled = unscaled.shiftRight(nbitsUnderOne).shiftLeft(nbitsUnderOne); } @@ -798,7 +815,7 @@ public strictfp class BigFloat implements Comparable { private void makeOne() { kind = FloatKind.FINITE; scale = 0; - unscaled = BigInteger.ONE.shiftLeft(fracbits); + unscaled = BigInteger.ONE.shiftLeft(fracbits - 1); } // ceil, ignoring sign @@ -811,7 +828,7 @@ public strictfp class BigFloat implements Comparable { return; } - int nbitsUnderOne = fracbits - scale; + int nbitsUnderOne = fracbits - scale - 1; boolean increment = unscaled.getLowestSetBit() < nbitsUnderOne; unscaled = unscaled.shiftRight(nbitsUnderOne).shiftLeft(nbitsUnderOne); if (increment) { @@ -819,7 +836,7 @@ public strictfp class BigFloat implements Comparable { } // if we carry to a new bit, change the scale - if (unscaled.bitLength() > fracbits + 1) { + if (unscaled.bitLength() > fracbits) { upscale(-1); } } @@ -945,7 +962,7 @@ public strictfp class BigFloat implements Comparable { * @return the truncated integer form of this BigFloat */ public BigInteger toBigInteger() { - BigInteger res = unscaled.shiftRight(fracbits - scale); + BigInteger res = unscaled.shiftRight(fracbits - scale - 1); if (sign < 0) { return res.negate(); } @@ -967,7 +984,7 @@ public strictfp class BigFloat implements Comparable { */ public void round() { BigFloat half = new BigFloat(fracbits, expbits, FloatKind.FINITE, +1, - BigInteger.ONE.shiftLeft(fracbits), -1); + BigInteger.ONE.shiftLeft(fracbits - 1), -1); add(half); floor(); } @@ -1018,4 +1035,138 @@ public strictfp class BigFloat implements Comparable { return this.sign * this.unscaled.compareTo(other.unscaled); } + private String formatSpecialCase() { + if (isNaN()) { + return NAN; + } + if (isInfinite()) { + return sign < 0 ? NEGATIVE_INFINITY : POSITIVE_INFINITY; + } + return null; + } + + /** + * Perform rounding and conversion to BigDecimal prior to generating + * a formatted decimal string of the specified BigFloat value. + * A default generated {@link MathContext} is used. + * @return decimal string representation + */ + @Override + public String toString() { + String special = formatSpecialCase(); + if (special != null) { + return special; + } + BigDecimal bd = toBigDecimal(); + bd = bd.round(getDefaultDisplayContext(fracbits)); + return bd.toString(); + } + + /** + * Perform rounding and conversion to BigDecimal prior to generating + * a formatted decimal string of the specified BigFloat value. + * @param displayContext display context used for rounding and precision. + * @return decimal string representation + */ + public String toString(MathContext displayContext) { + String special = formatSpecialCase(); + if (special != null) { + return special; + } + BigDecimal bd = toBigDecimal(); + bd = bd.round(displayContext); + return bd.toString(); + } + + /** + * Perform appropriate rounding and conversion to BigDecimal prior to generating + * a formatted decimal string of the specified BigFloat value. + * See {@link #toString(FloatFormat, boolean)}, + * {@link FloatFormat#toDecimalString(BigFloat)} and + * {@link FloatFormat#toDecimalString(BigFloat, boolean)}. + * @param ff float format + * @param compact if true the precision will be reduced to a form which is still equivalent at + * the binary encoding level for the specified FloatFormat. + * @return decimal string representation + */ + public String toString(FloatFormat ff, boolean compact) { + String special = formatSpecialCase(); + if (special != null) { + return special; + } + BigDecimal bd = toBigDecimal(); + bd = bd.round(ff.getDisplayContext()); + + String str = bd.toString(); + int precision = bd.precision(); + int bdScale = bd.scale(); + + // Generate compact representation if requested + if (compact && precision > 2) { + BigInteger encoding = ff.getEncoding(this); + for (String newStr = str; newStr != null;) { + newStr = removeFractionalDigit(newStr, 1, false); + if (newStr != null) { + bd = new BigDecimal(newStr); + bd = bd.setScale(bdScale); // avoid scale change which may alter encoding + BigFloat bf = ff.getBigFloat(bd); + if (encoding.equals(ff.getEncoding(bf))) { + str = newStr; + } + else { + newStr = null; // stop compaction + } + } + } + } + // Strip trailing zeros + str = stripTrailingZeros(str, 1); + // Ensure decimal point is present + if (str.indexOf('.') < 0) { + str += ".0"; + } + return str; + } + + private String stripTrailingZeros(String decStr, int minDigits) { + String str = decStr; + while (true) { + String nextStr = removeFractionalDigit(str, 1, true); + if (nextStr == null) { + break; + } + str = nextStr; + } + return str; + } + + private String removeFractionalDigit(String decStr, int minDigits, boolean stripZeroDigitOnly) { + int decimalPointIx = decStr.indexOf('.'); + if (decimalPointIx < 0) { + return null; + } + int expIx = decStr.toUpperCase().indexOf('E'); + String exp = ""; + if (expIx > 0) { + exp = decStr.substring(expIx); + decStr = decStr.substring(0, expIx); + } + if (decStr.length() - decimalPointIx - 1 <= minDigits) { + return null; + } + int lastDigitIndex = decStr.length() - 1; + if (stripZeroDigitOnly && decStr.charAt(lastDigitIndex) != '0') { + return null; + } + // discard last mantissa digit + return decStr.substring(0, lastDigitIndex) + exp; + } + + private static synchronized MathContext getDefaultDisplayContext(int fracBits) { + return defaultDisplayContextMap.computeIfAbsent(fracBits, n -> { + int precision = (int) (0.30103 * fracBits); // log10(2) * mantissa bits + return new MathContext(precision, RoundingMode.HALF_EVEN); + }); + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java index 72418b438d..7e61e34304 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java @@ -17,16 +17,17 @@ package ghidra.pcode.floatformat; import java.math.*; +import javax.help.UnsupportedOperationException; + import ghidra.pcode.utils.Utils; import ghidra.util.SystemUtilities; -public strictfp class FloatFormat { - private static final int INFINITE_SCALE = -(64 * 1024); - public static final BigDecimal BIG_NaN = null; - public static final BigDecimal BIG_POSITIVE_INFINITY = - new BigDecimal(BigInteger.ONE, INFINITE_SCALE); - public static final BigDecimal BIG_NEGATIVE_INFINITY = - (new BigDecimal(BigInteger.ONE, INFINITE_SCALE)).negate(); +/** + * {@link FloatFormat} provides IEEE 754 floating-point encoding formats in support of + * floating-point data types and floating-point emulation. A combination of Java + * float/double and {@link BigFloat} are used to facilitate floating-point operations. + */ +public class FloatFormat { static final FloatFormat JAVA_FLOAT_FORMAT = new FloatFormat(4); static final FloatFormat JAVA_DOUBLE_FORMAT = new FloatFormat(8); @@ -35,6 +36,7 @@ public strictfp class FloatFormat { private final int signbit_pos; // Bit position of signbit private final int frac_pos; // (lowest) bit position of fractional part private final int frac_size; // Number of bits in fractional part + private final int effective_frac_size; // Number of bits in fractional part includes jimplied bit private final int exp_pos; // (lowest) bit position of exponent private final int exp_size; // Number of bits in exponent private final int bias; // What to add to real exponent to get encoding @@ -51,27 +53,13 @@ public strictfp class FloatFormat { */ public final BigFloat minValue; - // used in string conversion + // display precision/rounding context consistent with BigDecimal use private final MathContext displayContext; public int getSize() { return size; } - /** - * Round {@code bigFloat} using this format's displayContext. - * - * @param bigFloat any BigFloat - * @return a BigDecimal rounded according to this format's displayContext - */ - public BigDecimal round(BigFloat bigFloat) { - BigDecimal bigDecimal = bigFloat.toBigDecimal(); - if (bigDecimal == null) { - return null; - } - return bigDecimal.round(displayContext); - } - // Set format for given size according to IEEE 754 standards FloatFormat(int sz) throws UnsupportedFloatFormatException { size = sz; @@ -84,7 +72,7 @@ public strictfp class FloatFormat { frac_size = 10; bias = 15; jbitimplied = true; - displayContext = new MathContext(7, RoundingMode.HALF_EVEN); + displayContext = new MathContext(4, RoundingMode.HALF_EVEN); } else if (size == 4) { signbit_pos = 31; @@ -94,7 +82,7 @@ public strictfp class FloatFormat { frac_size = 23; bias = 127; jbitimplied = true; - displayContext = new MathContext(7, RoundingMode.HALF_EVEN); + displayContext = new MathContext(8, RoundingMode.HALF_EVEN); } else if (size == 8) { signbit_pos = 63; @@ -114,45 +102,75 @@ public strictfp class FloatFormat { frac_size = 112; bias = 16383; jbitimplied = true; - displayContext = new MathContext(33, RoundingMode.HALF_EVEN); + displayContext = new MathContext(34, RoundingMode.HALF_EVEN); + } + else if (size == 32) { + signbit_pos = 255; + exp_pos = 236; + exp_size = 19; + frac_pos = 0; + frac_size = 236; + bias = 262143; + jbitimplied = true; + displayContext = new MathContext(71, RoundingMode.HALF_EVEN); } else if (size == 10) { + /** + * 80-bit double extended precision format + * See https://en.wikipedia.org/wiki/Extended_precision + */ signbit_pos = 79; exp_pos = 64; exp_size = 15; frac_pos = 0; frac_size = 64; bias = 16383; - jbitimplied = true; - displayContext = new MathContext(18, RoundingMode.HALF_EVEN); - } - else if (size == 12) { // For the Motorola 68000, extended precision, in which bits 80 to 63 are always 0. - // Note that m68k internal floating point regs are 80-bits, but 96 bits are moved to/from memory. - // Also note this is not IEEE format. - signbit_pos = 95; - exp_pos = 80; - exp_size = 15; - frac_pos = 16; - frac_size = 64; - bias = 16383; - jbitimplied = true; + jbitimplied = false; displayContext = new MathContext(18, RoundingMode.HALF_EVEN); } else { throw new UnsupportedFloatFormatException(sz); } + + if (!jbitimplied && size <= 8) { + throw new IllegalArgumentException( + "Small format implementation assumes jbitimplied=true"); + } + + effective_frac_size = frac_size + (jbitimplied ? 1 : 0); maxexponent = (1 << exp_size) - 1; - maxValue = new BigFloat(frac_size, exp_size, FloatKind.FINITE, +1, - BigInteger.ONE.shiftLeft(frac_size + 1).subtract(BigInteger.ONE), + // jbitimplied assumed true + maxValue = new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, +1, + BigInteger.ONE.shiftLeft(effective_frac_size).subtract(BigInteger.ONE), (1 << (exp_size - 1)) - 1); - minValue = new BigFloat(frac_size, exp_size, FloatKind.FINITE, +1, BigInteger.ONE, - 2 - (1 << (exp_size - 1))); + minValue = new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, +1, BigInteger.ONE, + 2 - (1 << (exp_size - 1))); + } + + MathContext getDisplayContext() { + return displayContext; + } + + /** + * Get the maximum finite {@link BigFloat} value for this format + * @return maximum finite {@link BigFloat} value + */ + public BigFloat getMaxBigFloat() { + return maxValue; + } + + /** + * Get the minimum finite subnormal {@link BigFloat} value for this format + * @return minimum finite subnormal {@link BigFloat} value + */ + public BigFloat getMinBigFloat() { + return minValue; } // Create a double given sign, 8-byte normalized mantissa, and unbiased scale - static double createFloat(boolean sgn, long mantissa, int scale) { + static double createDouble(boolean sgn, long mantissa, int scale) { long exp = scale + 1023; long bits = mantissa >>> 11;// 11 = 64 (long size) - 52 (frac size) - 1 (jbit)) if (exp != 1) { // normal @@ -166,10 +184,10 @@ public strictfp class FloatFormat { return Double.longBitsToDouble(bits); } - FloatKind extractKind(long l) { - int exp = extractExponentCode(l); + FloatKind extractKind(long encoding) { + int exp = extractExponentCode(encoding); if (exp == maxexponent) { - long frac = extractFractionalCode(l); + long frac = extractFractionalCode(encoding); if (frac == 0L) { return FloatKind.INFINITE; } @@ -181,6 +199,21 @@ public strictfp class FloatFormat { return FloatKind.FINITE; } + private FloatKind extractKind(BigInteger l) { + int exp = extractExponentCode(l); + if (exp == maxexponent) { + BigInteger frac = extractFractionalCode(l); + if (BigInteger.ZERO.equals(frac)) { + return FloatKind.INFINITE; + } + if (BigInteger.ONE.equals(frac.shiftRight(frac_size - 1))) { + return FloatKind.QUIET_NAN; + } + return FloatKind.SIGNALING_NAN; + } + return FloatKind.FINITE; + } + // Extract bits encoding fractional and return un-normalized long value private long extractFractionalCode(long x) { long mask = (1L << frac_size) - 1; @@ -254,7 +287,8 @@ public strictfp class FloatFormat { } public BigFloat getBigZero(boolean sgn) { - return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1, BigInteger.ZERO, + return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1, + BigInteger.ZERO, 2 - (1 << (exp_size - 1))); } @@ -265,7 +299,7 @@ public strictfp class FloatFormat { } public BigFloat getBigInfinity(boolean sgn) { - return BigFloat.infinity(frac_size, exp_size, sgn ? -1 : 1); + return BigFloat.infinity(effective_frac_size, exp_size, sgn ? -1 : 1); } public long getNaNEncoding(boolean sgn) { @@ -283,30 +317,35 @@ public strictfp class FloatFormat { } public BigFloat getBigNaN(boolean sgn) { - return BigFloat.quietNaN(frac_size, exp_size, sgn ? -1 : 1); + return BigFloat.quietNaN(effective_frac_size, exp_size, sgn ? -1 : 1); } public BigFloat getBigFloat(float f) { BigFloat bf = FloatFormat.toBigFloat(f); - return new BigFloat(frac_size, exp_size, bf.kind, bf.sign, - bf.unscaled.shiftLeft(frac_size - bf.fracbits), bf.scale); + return new BigFloat(effective_frac_size, exp_size, bf.kind, bf.sign, + bf.unscaled.shiftLeft(effective_frac_size - bf.fracbits), bf.scale); } public BigFloat getBigFloat(double d) { BigFloat bf = FloatFormat.toBigFloat(d); - return new BigFloat(frac_size, exp_size, bf.kind, bf.sign, - bf.unscaled.shiftLeft(frac_size - bf.fracbits), bf.scale); + return new BigFloat(effective_frac_size, exp_size, bf.kind, bf.sign, + bf.unscaled.shiftLeft(effective_frac_size - bf.fracbits), bf.scale); } /** * Decode {@code encoding} to a BigFloat using this format. * - * NB: this method should not be used if {@link #size}>8 + * The method {@link #decodeBigFloat(BigInteger)} should be used for encodings + * larger than 8 bytes. * * @param encoding the encoding * @return the decoded value as a BigFloat */ - public BigFloat getBigFloat(long encoding) { + public BigFloat decodeBigFloat(long encoding) { + if (size > 8) { + throw new UnsupportedOperationException( + "method not supported for float size of " + size); + } boolean sgn = extractSign(encoding); int exp = extractExponentCode(encoding); long frac = extractFractionalCode(encoding); @@ -320,13 +359,15 @@ public strictfp class FloatFormat { } else { scale = exp - bias; - unscaled = unscaled.setBit(frac_size); + if (jbitimplied) { + unscaled = unscaled.setBit(frac_size); + } } } else { scale = 0; } - return new BigFloat(frac_size, exp_size, kind, sgn ? -1 : 1, unscaled, scale); + return new BigFloat(effective_frac_size, exp_size, kind, sgn ? -1 : 1, unscaled, scale); } /** @@ -338,6 +379,10 @@ public strictfp class FloatFormat { * @return the decoded value as a SmallFloatData */ SmallFloatData getSmallFloatData(long encoding) { + if (size > 8) { + throw new UnsupportedOperationException( + "method not supported for float size of " + size); + } boolean sgn = extractSign(encoding); int exp = extractExponentCode(encoding); long frac = extractFractionalCode(encoding); @@ -351,17 +396,20 @@ public strictfp class FloatFormat { } else { scale = exp - bias; - unscaled |= 1L << frac_size; + if (jbitimplied) { + unscaled |= 1L << frac_size; + } } } else { scale = 0; } - return new SmallFloatData(frac_size, exp_size, kind, sgn ? -1 : 1, unscaled, scale); + return new SmallFloatData(effective_frac_size, exp_size, kind, sgn ? -1 : 1, unscaled, + scale); } // Convert floating point encoding into host's double if size <= 8 - public double getHostFloat(long encoding) { + public double decodeHostFloat(long encoding) { boolean sgn = extractSign(encoding); int exp = extractExponentCode(encoding); long frac = extractFractionalCode(encoding); @@ -388,37 +436,42 @@ public strictfp class FloatFormat { mantissa |= 0x8000000000000000L; // set bit in at top of normalized frac } - return createFloat(sgn, mantissa, exp); + return createDouble(sgn, mantissa, exp); } - public BigFloat getHostFloat(BigInteger encoding) { + public BigFloat decodeBigFloat(BigInteger encoding) { boolean sgn = extractSign(encoding); int sign = sgn ? -1 : 1; BigInteger frac = extractFractionalCode(encoding); int exp = extractExponentCode(encoding); if (exp == 0) { // subnormals + // NOTE: 80-bit (size=10) encoding is implementation dependant + // See: https://en.wikipedia.org/wiki/Extended_precision if (frac.signum() == 0) { - return BigFloat.zero(frac_size, exp_size, sign); + return BigFloat.zero(effective_frac_size, exp_size, sign); } - return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sign, frac, 1 - bias); + return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sign, frac, + 1 - bias); } else if (exp == maxexponent) { + // NOTE: 80-bit (size=10) encoding is implementation dependant + // See: https://en.wikipedia.org/wiki/Extended_precision if (frac.signum() == 0) { // Floating point infinity - return BigFloat.infinity(frac_size, exp_size, sign); + return BigFloat.infinity(effective_frac_size, exp_size, sign); } - return BigFloat.quietNaN(frac_size, exp_size, sign); + return BigFloat.quietNaN(effective_frac_size, exp_size, sign); } if (jbitimplied) { frac = frac.setBit(frac_size); } - return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sign, frac, exp - bias); + return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sign, frac, + exp - bias); } // Convert host's double into floating point encoding if size <= 8 public long getEncoding(double host) { SmallFloatData value = FloatFormat.getSmallFloatData(host); - switch (value.kind) { case QUIET_NAN: case SIGNALING_NAN: @@ -434,33 +487,33 @@ public strictfp class FloatFormat { int exp; long fraction; - // handle the case where jbitimplied == true - if (jbitimplied) { - int lb_unscaled = leadBit(value.unscaled); - if (value.scale - value.fracbits + lb_unscaled >= 1 - bias) { - // normal case - exp = value.scale - value.fracbits + lb_unscaled + bias; - fraction = roundToLeadBit(value.unscaled, frac_size); - // if carry.. - if (leadBit(fraction) > frac_size) { - fraction = fraction >>> 1; - exp += 1; - } + int lb_unscaled = leadBit(value.unscaled); + if (value.scale - value.fracbits + lb_unscaled >= -bias) { + // normal case + exp = value.scale - value.fracbits + 1 + lb_unscaled + bias; + fraction = roundToLeadBit(value.unscaled, frac_size); + // if carry.. + if (leadBit(fraction) > frac_size) { + fraction = fraction >>> 1; + exp += 1; + } + if (jbitimplied) { fraction &= (1L << frac_size) - 1; } - else { - // subnormal - exp = 0; - int n = value.scale - value.fracbits + lb_unscaled - 1 + bias + frac_size; - if (n < 0) { - // XXX is it possible to round up to a non-zero in this situation? - return getZeroEncoding(value.sign < 0); - } - fraction = roundToLeadBit(value.unscaled, n); // XXX round into normal case? - } + } + else if (!jbitimplied) { + // subnormals are not supported + return getZeroEncoding(value.sign < 0); } else { - throw new AssertionError("Unexpected jbitimplied==false"); + // subnormal + exp = 0; + int n = value.scale - value.fracbits + lb_unscaled + bias + frac_size; + if (n < 0) { + // XXX is it possible to round up to a non-zero in this situation? + return getZeroEncoding(value.sign < 0); + } + fraction = roundToLeadBit(value.unscaled, n); // XXX round into normal case? } if (exp >= maxexponent) { return getInfinityEncoding(value.sign < 0); @@ -493,33 +546,34 @@ public strictfp class FloatFormat { int exp; BigInteger fraction; - // handle the case where jbitimplied == true - if (jbitimplied) { - int lb_unscaled = leadBit(value.unscaled); - if (value.scale - value.fracbits + lb_unscaled >= 1 - bias) { - // normal case - exp = value.scale - value.fracbits + lb_unscaled + bias; - fraction = roundToLeadBit(value.unscaled, frac_size); - // if carry.. - if (leadBit(fraction) > frac_size) { - fraction = fraction.shiftRight(1); - exp += 1; - } + int lb_unscaled = leadBit(value.unscaled); + if (value.scale - value.fracbits + lb_unscaled >= -bias) { + // normal case + exp = value.scale - value.fracbits + 1 + lb_unscaled + bias; + int leadBit = frac_size - (jbitimplied ? 0 : 1); + fraction = roundToLeadBit(value.unscaled, leadBit); + // if carry.. + if (leadBit(fraction) > frac_size) { + fraction = fraction.shiftRight(1); + exp += 1; + } + if (jbitimplied) { fraction = fraction.clearBit(frac_size); } - else { - // subnormal - exp = 0; - int n = value.scale - value.fracbits + lb_unscaled - 1 + bias + frac_size; - if (n < 0) { - // XXX is it possible to round up to a non-zero in this situation? - return getBigZeroEncoding(value.sign < 0); - } - fraction = roundToLeadBit(value.unscaled, n); - } + } + else if (!jbitimplied) { + // subnormals are not supported + return getBigZeroEncoding(value.sign < 0); } else { - throw new AssertionError("Unexpected jbitimplied==false"); + // subnormal + exp = 0; + int n = value.scale - value.fracbits + lb_unscaled + bias + frac_size; + if (n < 0) { + // XXX is it possible to round up to a non-zero in this situation? + return getBigZeroEncoding(value.sign < 0); + } + fraction = roundToLeadBit(value.unscaled, n); } if (exp >= maxexponent) { return getBigInfinityEncoding(value.sign < 0); @@ -532,15 +586,52 @@ public strictfp class FloatFormat { return result; } + /** + * Round {@code bigFloat} using this format's displayContext. + * + * @param bigFloat any BigFloat + * @return a BigDecimal rounded according to this format's displayContext + */ + public BigDecimal round(BigFloat bigFloat) { + BigDecimal bigDecimal = bigFloat.toBigDecimal(); + if (bigDecimal == null) { + return null; + } + return bigDecimal.round(displayContext); + } + + /** + * Perform appropriate rounding and conversion to BigDecimal prior to generating + * a formatted decimal string of the specified BigFloat value. + * @param bigFloat value + * @return decimal string representation + */ + public String toDecimalString(BigFloat bigFloat) { + return bigFloat.toString(this, false); + } + + /** + * Perform appropriate rounding and conversion to BigDecimal prior to generating + * a formatted decimal string of the specified BigFloat value. + * @param bigFloat value + * @param compact if true the precision will be reduced to a form which is still equivalent at + * the binary encoding level for this format. Enabling this will incur additional overhead. + * @return decimal string representation + */ + public String toDecimalString(BigFloat bigFloat, boolean compact) { + return bigFloat.toString(this, compact); + } + /** * Convert an encoded value to a binary floating point representation. + * This is intended for diagnostic purposes only. * * NB: this method should not be used if {@link #size}>8 * * @param encoding the encoding of a floating point value in this format * @return a binary string representation of the encoded floating point {@code encoding} */ - public String toBinaryString(long encoding) { + private String toBinaryString(long encoding) { boolean sgn = extractSign(encoding); int exp = extractExponentCode(encoding); long frac = extractFractionalCode(encoding); @@ -568,6 +659,7 @@ public strictfp class FloatFormat { if (binary.isEmpty()) { binary = "0"; } + String s = sgn ? "-" : ""; if (exp == 0) { // subnormal @@ -580,19 +672,69 @@ public strictfp class FloatFormat { } /** - * @param f a float - * @return BigFloat equal to {@code f} + * Convert an encoded value to a binary floating point representation. + * This is intended for diagnostic purposes only. + * + * @param encoding the encoding of a floating point value in this format + * @return a binary string representation of the encoded floating point {@code encoding} */ - public static BigFloat toBigFloat(float f) { - return JAVA_FLOAT_FORMAT.getBigFloat(0xffffffffl & Float.floatToRawIntBits(f)); + private String toBinaryString(BigInteger encoding) { + boolean sgn = extractSign(encoding); + int exp = extractExponentCode(encoding); + BigInteger frac = extractFractionalCode(encoding); + FloatKind kind = extractKind(encoding); + + switch (kind) { + case INFINITE: + if (sgn) { + return "-inf"; + } + return "+inf"; + case QUIET_NAN: + return "qNaN"; + case SIGNALING_NAN: + return "sNaN"; + case FINITE: + break; + default: + throw new AssertionError("unexpected kind"); + + } + + String binary = frac.toString(2); + binary = "0".repeat(frac_size - binary.length()) + binary; + binary = binary.replaceAll("0*$", ""); + if (binary.isEmpty()) { + binary = "0"; + } + + String s = sgn ? "-" : ""; + + if (exp == 0) { // subnormal + if (BigInteger.ZERO.equals(frac)) { + return String.format("%s0b0.0", s); + } + return String.format("%s0b0.%s * 2^%d", s, binary, -bias + 1); + } + return String.format("%s0b1.%s * 2^%d", s, binary, exp - bias); } /** + * Convert a native float to {@link BigFloat} using 4-byte IEEE 754 encoding + * @param f a float + * @return {@link BigFloat} equal to {@code f} + */ + public static BigFloat toBigFloat(float f) { + return JAVA_FLOAT_FORMAT.decodeBigFloat(0xffffffffl & Float.floatToRawIntBits(f)); + } + + /** + * Convert a native double to {@link BigFloat} using 8-byte IEEE 754 encoding * @param d a double - * @return BigFloat equal to {@code f} + * @return {@link BigFloat} equal to {@code f} */ public static BigFloat toBigFloat(double d) { - return JAVA_DOUBLE_FORMAT.getBigFloat(Double.doubleToRawLongBits(d)); + return JAVA_DOUBLE_FORMAT.decodeBigFloat(Double.doubleToRawLongBits(d)); } static SmallFloatData getSmallFloatData(double d) { @@ -600,21 +742,35 @@ public strictfp class FloatFormat { } /** + * Get 4-byte binary encoding for the specified native float value. + * This is intended for diagnostic purposes only. * @param f a float * @return binary representation of {@code f} */ - public static String toBinaryString(float f) { + static String toBinaryString(float f) { return JAVA_FLOAT_FORMAT.toBinaryString(0xffffffffl & Float.floatToRawIntBits(f)); } /** + * Get 8-byte binary encoding for the specified native double value. + * This is intended for diagnostic purposes only. * @param d a double * @return binary representation of {@code f} */ - public static String toBinaryString(double d) { + static String toBinaryString(double d) { return JAVA_DOUBLE_FORMAT.toBinaryString(Double.doubleToRawLongBits(d)); } + /** + * Get binary encoding for the specified rounded {@link BigFloat} value. + * This is intended for diagnostic purposes only. + * @param value floating point value + * @return binary representation of {@code value} + */ + String toBinaryString(BigFloat value) { + return toBinaryString(getEncoding(value)); + } + private static int leadBit(BigInteger i) { return i.bitLength() - 1; } @@ -688,10 +844,10 @@ public strictfp class FloatFormat { final int scale; /** - * Construct SmallFloat Data. - * If kind is FINITE, the value is sign*unscaled*2^(scale-fracbits) + * Construct SmallFloat Data. (similar to BigFloat) * - * @param fracbits number of fractional bits + * @param fracbits number of fractional bits (positive non-zero value; includes additional + * implied bit if relavent). * @param expbits maximum number of bits in exponent * @param kind the Kind, FINITE, INFINITE, ... * @param sign +1 or -1 @@ -700,6 +856,7 @@ public strictfp class FloatFormat { */ public SmallFloatData(int fracbits, int expbits, FloatKind kind, int sign, long unscaled, int scale) { + // FIXME check use and changes to fracbits this.fracbits = fracbits; this.expbits = expbits; this.kind = kind; @@ -723,15 +880,15 @@ public strictfp class FloatFormat { // The long methods should not be used when size>8. public long opEqual(long a, long b) { // a == b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); long res = (val1 == val2) ? 1 : 0; return res; } public BigInteger opEqual(BigInteger a, BigInteger b) { // a == b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); if (fa.isNaN() || fb.isNaN()) { return BigInteger.ZERO; } @@ -740,15 +897,15 @@ public strictfp class FloatFormat { } public long opNotEqual(long a, long b) { // a != b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); long res = (val1 != val2) ? 1 : 0; return res; } public BigInteger opNotEqual(BigInteger a, BigInteger b) { // a != b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); if (fa.isNaN() | fb.isNaN()) { return BigInteger.ONE; } @@ -757,127 +914,127 @@ public strictfp class FloatFormat { } public long opLess(long a, long b) { // a < b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); long res = (val1 < val2) ? 1 : 0; return res; } public BigInteger opLess(BigInteger a, BigInteger b) { // a < b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); BigInteger res = (fa.compareTo(fb) < 0) ? BigInteger.ONE : BigInteger.ZERO; return res; } public long opLessEqual(long a, long b) { // a <= b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); long res = (val1 <= val2) ? 1 : 0; return res; } public BigInteger opLessEqual(BigInteger a, BigInteger b) { // a <= b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); BigInteger res = (fa.compareTo(fb) <= 0) ? BigInteger.ONE : BigInteger.ZERO; return res; } // true if a is "not a number" public long opNan(long a) { - double val = getHostFloat(a); + double val = decodeHostFloat(a); long res = Double.isNaN(val) ? 1 : 0; return res; } public BigInteger opNan(BigInteger a) { - BigFloat val = getHostFloat(a); + BigFloat val = decodeBigFloat(a); BigInteger res = (val.isNaN()) ? BigInteger.ONE : BigInteger.ZERO; return res; } public long opAdd(long a, long b) { // a + b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); return getEncoding(val1 + val2); } public BigInteger opAdd(BigInteger a, BigInteger b) { // a + b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); fa.add(fb); return getEncoding(fa); } public long opSub(long a, long b) { // a - b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); return getEncoding(val1 - val2); } public BigInteger opSub(BigInteger a, BigInteger b) { // a - b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); fa.sub(fb); return getEncoding(fa); } public long opDiv(long a, long b) { // a / b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); return getEncoding(val1 / val2); } public BigInteger opDiv(BigInteger a, BigInteger b) { // a / b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); fa.div(fb); return getEncoding(fa); } public long opMult(long a, long b) { // a * b - double val1 = getHostFloat(a); - double val2 = getHostFloat(b); + double val1 = decodeHostFloat(a); + double val2 = decodeHostFloat(b); return getEncoding(val1 * val2); } public BigInteger opMult(BigInteger a, BigInteger b) { // a * b - BigFloat fa = getHostFloat(a); - BigFloat fb = getHostFloat(b); + BigFloat fa = decodeBigFloat(a); + BigFloat fb = decodeBigFloat(b); fa.mul(fb); return getEncoding(fa); } public long opNeg(long a) { // -a - double val = getHostFloat(a); + double val = decodeHostFloat(a); return getEncoding(-val); } public BigInteger opNeg(BigInteger a) { - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); fa.negate(); return getEncoding(fa); } public long opAbs(long a) { // absolute value of a - double val = getHostFloat(a); + double val = decodeHostFloat(a); return getEncoding(Math.abs(val)); } public BigInteger opAbs(BigInteger a) { - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); fa.abs(); return getEncoding(fa); } public long opSqrt(long a) { // square root of a - double val = getHostFloat(a); + double val = decodeHostFloat(a); return getEncoding(Math.sqrt(val)); } public BigInteger opSqrt(BigInteger a) { - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); fa.sqrt(); return getEncoding(fa); } @@ -897,29 +1054,29 @@ public strictfp class FloatFormat { else { a = Utils.convertToUnsignedValue(a, sizein); } - return getEncoding(valueOf(a)); + return getEncoding(getBigFloat(a)); } public long opFloat2Float(long a, FloatFormat outformat) { // convert between floating // point precisions - double val = getHostFloat(a); + double val = decodeHostFloat(a); return outformat.getEncoding(val); } public BigInteger opFloat2Float(BigInteger a, FloatFormat outformat) { // convert between floating - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); return outformat.getEncoding(fa); } public long opTrunc(long a, int sizeout) { // convert floating point to integer - double val = getHostFloat(a); + double val = decodeHostFloat(a); long res = (long) val; // Convert to integer res &= Utils.calc_mask(sizeout); // Truncate to proper size return res; } public BigInteger opTrunc(BigInteger a, int sizeout) { // convert floating point to integer - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); if (fa.isNaN()) { return BigInteger.ZERO; // consistent with Java Double->Long behavior } @@ -936,39 +1093,48 @@ public strictfp class FloatFormat { } public long opCeil(long a) { // integer ceiling of a - double val = getHostFloat(a); + double val = decodeHostFloat(a); return getEncoding(Math.ceil(val)); } public BigInteger opCeil(BigInteger a) { // integer ceiling of a - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); fa.ceil(); return getEncoding(fa); } public long opFloor(long a) { // integer floor of a - double val = getHostFloat(a); + double val = decodeHostFloat(a); return getEncoding(Math.floor(val)); } public BigInteger opFloor(BigInteger a) { // integer floor of a - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); fa.floor(); return getEncoding(fa); } public long opRound(long a) { // nearest integer to a - double val = getHostFloat(a); + double val = decodeHostFloat(a); return getEncoding(Math.floor(val + 0.5)); } public BigInteger opRound(BigInteger a) { // nearest integer to a - BigFloat fa = getHostFloat(a); + BigFloat fa = decodeBigFloat(a); fa.round(); return getEncoding(fa); } - public BigFloat valueOf(BigInteger value) { + public BigFloat getBigFloat(BigInteger value) { + + if (size == 8) { + double d = value.doubleValue(); + return getBigFloat(d); + } + if (size == 4) { + float f = value.floatValue(); + return getBigFloat(f); + } BigInteger unscaled = value; int sign = 1; @@ -977,18 +1143,110 @@ public strictfp class FloatFormat { unscaled = unscaled.negate(); } + int scale = effective_frac_size - 1; int ulen = unscaled.bitLength(); - int shift = frac_size + 1 - ulen; - - unscaled = unscaled.shiftLeft(shift); - - int scale = frac_size - shift; - - if (scale > bias) { - return BigFloat.infinity(frac_size, exp_size, sign); + if (ulen > effective_frac_size) { + int shift = effective_frac_size - ulen; // may produce +/- shift + unscaled = unscaled.shiftLeft(shift); + scale = effective_frac_size - shift - 1; + if (scale > bias) { + return BigFloat.infinity(effective_frac_size, exp_size, sign); + } } - return new BigFloat(frac_size, exp_size, FloatKind.FINITE, sign, unscaled, scale); + return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sign, unscaled, scale); + } + + /** + * Constructs a {@code BigFloat} initialized to the value + * represented by the specified decimal {@code String}, as performed + * by {@link BigDecimal#BigDecimal(String)}. Other values permitted + * are (case-insenstive): "NaN", "Infinity", "+Infinity", "-Infinity" + * (See {@link BigFloat#NAN}, {@link BigFloat#INFINITY}, {@link BigFloat#POSITIVE_INFINITY}, + * {@link BigFloat#NEGATIVE_INFINITY}). + * + * @param string the string to be parsed. + * @return value as a {@link BigFloat} + * @throws NullPointerException if the string is null + * @throws NumberFormatException if the string parse fails. + */ + public BigFloat getBigFloat(String string) throws NumberFormatException { + java.util.Objects.requireNonNull(string); + if (string.equalsIgnoreCase(BigFloat.NAN)) { + return BigFloat.quietNaN(effective_frac_size, exp_size, 1); + } + if (string.equalsIgnoreCase(BigFloat.INFINITY) || + string.equalsIgnoreCase(BigFloat.POSITIVE_INFINITY)) { + return BigFloat.infinity(effective_frac_size, exp_size, 1); + } + if (string.equalsIgnoreCase(BigFloat.NEGATIVE_INFINITY)) { + return BigFloat.infinity(effective_frac_size, exp_size, -1); + } + return getBigFloat(new BigDecimal(string)); + } + + /** + * Constructs a {@code BigFloat} initialized to the value + * represented by the specified {@code BigDecimal}. + * + * @param value the decimal value. + * @return value as a {@link BigFloat} + * @throws NullPointerException if the string is null + * @throws NumberFormatException if the string parse fails. + */ + public BigFloat getBigFloat(BigDecimal value) { + if (size == 8) { + return getBigFloat(value.doubleValue()); + } + if (size == 4) { + return getBigFloat(value.floatValue()); + } + + BigDecimal val = value; + if (val.equals(BigDecimal.ZERO)) { + return BigFloat.zero(effective_frac_size, exp_size); + } + + BigFloat bf; + int scale10 = val.scale(); + if (scale10 < 0) { + scale10 = -scale10; + BigInteger scalar = BigInteger.valueOf(10).pow(scale10); + if (scale10 / 0.3 > effective_frac_size) { // log10(2) = ~0.3 + // will be whole integer + BigInteger intVal = scalar.multiply(val.unscaledValue()); + bf = getBigFloat(intVal); + } + else { + // may have fractional value + BigFloat scalarBf = getBigFloat(scalar); + bf = getBigFloat(val.unscaledValue()); + bf.mul(scalarBf); + } + } + else if (scale10 / 0.3 >= bias) { // log10(2) = ~0.3 + // divide down in two passes to avoid divide by infinity for edge case + int s1 = scale10 / 2; + BigInteger bs1 = BigInteger.valueOf(10).pow(s1); + BigInteger bs2 = BigInteger.valueOf(10).pow(scale10 - s1); + BigFloat bf2 = getBigFloat(bs2); + if (bf2.isInfinite()) { // bf2 >= bf1 + return BigFloat.zero(effective_frac_size, exp_size, value.signum()); + } + BigFloat bf1 = getBigFloat(bs1); + bf = getBigFloat(val.unscaledValue()); + bf.div(bf1); + bf.div(bf2); + } + else { + BigInteger scalar = BigInteger.valueOf(10).pow(scale10); + BigFloat scalarBf = getBigFloat(scalar); + + BigInteger whole = val.unscaledValue(); + bf = getBigFloat(whole); + bf.div(scalarBf); + } + return bf; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormatFactory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormatFactory.java index 4e08d5f210..f8bd90cde8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormatFactory.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormatFactory.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. @@ -30,6 +29,7 @@ public class FloatFormatFactory { * Get float format * @param size format storage size in bytes * @return float format or null if size is not supported + * @throws UnsupportedFloatFormatException if specified size is unsupported */ public static synchronized FloatFormat getFloatFormat(int size) throws UnsupportedFloatFormatException { @@ -40,7 +40,6 @@ public class FloatFormatFactory { cache.put(size, format); } return format; - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java index 3d41a57d4f..b9b285b40e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/DataDB.java @@ -129,7 +129,8 @@ class DataDB extends CodeUnitDB implements Data { } private void computeLength() { - length = dataType.getLength(); + // NOTE: Data intentionally does not use aligned-length + length = dataType.getLength(); // undefined will never change their size if (dataType instanceof Undefined) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java index 8041ef50cb..cc9d7c57c4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java @@ -36,6 +36,7 @@ class ArrayDB extends DataTypeDB implements Array { private volatile String displayName; private ArrayDBAdapter adapter; + private int elementLength; // lazy initialization /** * Constructor @@ -52,6 +53,7 @@ class ArrayDB extends DataTypeDB implements Array { @Override protected String doGetName() { + elementLength = -1; // signal refresh by getElementLength() return DataTypeUtilities.getName(this, true); } @@ -74,6 +76,7 @@ class ArrayDB extends DataTypeDB implements Array { @Override protected boolean refresh() { try { + elementLength = -1; DBRecord rec = adapter.getRecord(key); if (rec != null) { record = rec; @@ -129,6 +132,11 @@ class ArrayDB extends DataTypeDB implements Array { return getNumElements() * getElementLength(); } + @Override + public int getAlignedLength() { + return getLength(); + } + @Override public String getDescription() { checkIsValid(); @@ -169,15 +177,23 @@ class ArrayDB extends DataTypeDB implements Array { @Override public int getElementLength() { - DataType dt = getDataType(); - int elementLen; - if (dt instanceof Dynamic) { - elementLen = record.getIntValue(ArrayDBAdapter.ARRAY_ELEMENT_LENGTH_COL); + lock.acquire(); + try { + checkIsValid(); + DataType dt = getDataType(); + if (elementLength < 0) { + if (dt instanceof Dynamic) { + elementLength = record.getIntValue(ArrayDBAdapter.ARRAY_ELEMENT_LENGTH_COL); + } + else { + elementLength = dt.getAlignedLength(); + } + } + return elementLength; } - else { - elementLen = dt.getLength(); + finally { + lock.release(); } - return elementLen; } @Override @@ -251,7 +267,7 @@ class ArrayDB extends DataTypeDB implements Array { if (newDt instanceof Dynamic || newDt instanceof FactoryDataType) { newDt = DataType.DEFAULT; } - int elementLength = newDt.getLength() < 0 ? oldElementLength : -1; + elementLength = newDt.getLength() < 0 ? oldElementLength : -1; record.setIntValue(ArrayDBAdapter.ARRAY_ELEMENT_LENGTH_COL, elementLength); try { adapter.updateRecord(record); @@ -288,7 +304,8 @@ class ArrayDB extends DataTypeDB implements Array { public void dataTypeSizeChanged(DataType dt) { lock.acquire(); try { - if (checkIsValid() && dt == getDataType()) { + if (checkIsValid() && dt == getDataType() && dt.getLength() > 0) { + elementLength = -1; notifySizeChanged(true); } } @@ -333,6 +350,7 @@ class ArrayDB extends DataTypeDB implements Array { @Override public void dataTypeDeleted(DataType dt) { if (getDataType() == dt) { + elementLength = -1; dataMgr.addDataTypeToDelete(key); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java index c27e3fe2ee..d17f64ce8c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java @@ -59,6 +59,11 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal { */ protected abstract void initialize(); + @Override + public final int getAlignedLength() { + return getLength(); + } + /** * Get the preferred length for a new component. For Unions and packed * structures the preferred component length for a fixed-length dataType @@ -78,18 +83,7 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal { if ((isPackingEnabled() || (this instanceof Union)) && !(dataType instanceof Dynamic)) { length = -1; // force use of datatype size } - int dtLength = dataType.getLength(); - if (length <= 0) { - length = dtLength; - } - else if (dtLength > 0 && dtLength < length) { - length = dtLength; - } - if (length <= 0) { - throw new IllegalArgumentException("Positive length must be specified for " + - dataType.getDisplayName() + " component"); - } - return length; + return DataTypeComponentImpl.getPreferredComponentLength(dataType, length); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java index 91f137e655..1e303fdd64 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java @@ -23,6 +23,7 @@ import ghidra.app.util.SymbolPathParser; import ghidra.docking.settings.Settings; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Namespace; import ghidra.util.UniversalID; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java index 1b1bc33bb3..5d32fcd8b1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java @@ -453,6 +453,11 @@ class EnumDB extends DataTypeDB implements Enum { } } + @Override + public int getAlignedLength() { + return getLength(); + } + @Override public String getDescription() { lock.acquire(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java index 9c1ccb91d2..94af56ce3f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FunctionDefinitionDB.java @@ -254,6 +254,11 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition { return -1; } + @Override + public int getAlignedLength() { + return -1; + } + @Override public String getDescription() { return "Function Signature Data Type"; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDB.java index 5ecedcfa4c..8cc2cef715 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/PointerDB.java @@ -207,6 +207,12 @@ class PointerDB extends DataTypeDB implements Pointer { } } + @Override + public int getAlignedLength() { + // assume pointers are never padded + return getLength(); + } + @Override public String getDescription() { lock.acquire(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java index 19987ba5ac..2858250ccf 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java @@ -1709,7 +1709,7 @@ class StructureDB extends CompositeDB implements StructureInternal { DataTypeComponent dtc = otherComponents[i]; DataType dt = resolvedDts[i]; // ancestry check already performed by caller - int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength(); + int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength(); if (length < 0 || dtc.isBitFieldComponent()) { // TODO: bitfield truncation/expansion may be an issue if data organization changes length = dtc.getLength(); @@ -1817,7 +1817,8 @@ class StructureDB extends CompositeDB implements StructureInternal { if (dtc.getDataType() == dt) { // assume no impact to bitfields since base types should not change size int dtcLen = dtc.getLength(); - int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength(); + int length = + DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength(); if (length < 0) { length = dtcLen; } @@ -1875,7 +1876,7 @@ class StructureDB extends CompositeDB implements StructureInternal { forceRepack |= isPacked; continue; } - int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength(); + int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength(); if (length < 0) { continue; // illegal condition - skip } @@ -2304,7 +2305,7 @@ class StructureDB extends CompositeDB implements StructureInternal { int nextIndex) throws IOException { int oldLen = comp.getLength(); - int len = DataTypeComponent.usesZeroLengthComponent(newDt) ? 0 : newDt.getLength(); + int len = DataTypeComponent.usesZeroLengthComponent(newDt) ? 0 : newDt.getAlignedLength(); if (len < 0) { len = oldLen; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java index 26603e5ff1..2fd7f22c51 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java @@ -154,6 +154,11 @@ class TypedefDB extends DataTypeDB implements TypeDef { return getDataType().getLength(); } + @Override + public int getAlignedLength() { + return getDataType().getAlignedLength(); + } + @Override public String getDescription() { return getDataType().getDescription(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java index 3072a52070..973b511e92 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java @@ -487,7 +487,7 @@ class UnionDB extends CompositeDB implements UnionInternal { if (dt instanceof BitFieldDataType) { dt = adjustBitField(dt); // in case base type changed } - int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength(); + int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength(); if (length < 0) { continue; // illegal condition - skip } @@ -533,7 +533,8 @@ class UnionDB extends CompositeDB implements UnionInternal { boolean changed = false; for (DataTypeComponentDB dtc : components) { if (dtc.getDataType() == dt) { - int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength(); + int length = + DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength(); if (length >= 0 && length != dtc.getLength()) { dtc.setLength(length, true); changed = true; @@ -824,7 +825,7 @@ class UnionDB extends CompositeDB implements UnionInternal { } else { int len = DataTypeComponent.usesZeroLengthComponent(newDt) ? 0 - : newDt.getLength(); + : newDt.getAlignedLength(); if (len < 0) { len = dtc.getLength(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractComplexDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractComplexDataType.java index bbb7088c82..b2c7000d51 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractComplexDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractComplexDataType.java @@ -19,6 +19,7 @@ import java.math.BigDecimal; import generic.complex.Complex; import ghidra.docking.settings.Settings; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.WrappedMemBuffer; @@ -86,9 +87,15 @@ public abstract class AbstractComplexDataType extends BuiltIn { return floatType.getLength() * 2; } + @Override + public int getAlignedLength() { + return getLength(); + } + @Override public String getDescription() { - return "The data type for a complex number: a + bi"; + return "The data type for a complex number: a + bi; consisting of two " + + floatType.getName() + " values"; } private static double toDouble(Object obj) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java index 2aa7b34763..99e3f6a146 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java @@ -78,6 +78,25 @@ public abstract class AbstractDataType implements DataType { : DataOrganizationImpl.getDefaultOrganization(); } + /** + * Get the {@link DataOrganization} which should be used by a {@link AbstractDataType} when + * associated with a specified {@link DataTypeManager dataMgr}. If a null + * {@code dataMgr} is specified the default {@link DataOrganization} will be returned. + * @param dataMgr datatype manager + * @return the {@link DataOrganization} which should be used by a {@link AbstractDataType} + * instance. + */ + protected static DataOrganization getDataOrganization(DataTypeManager dataMgr) { + DataOrganization dataOrganization = null; + if (dataMgr != null) { + dataOrganization = dataMgr.getDataOrganization(); + } + if (dataOrganization == null) { + dataOrganization = DataOrganizationImpl.getDefaultOrganization(); + } + return dataOrganization; + } + @Override public DataTypePath getDataTypePath() { // use methods instead of fields since they mey be overriden diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java index ba43d4fa1d..954f940567 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractPointerTypedefBuiltIn.java @@ -150,6 +150,11 @@ public abstract class AbstractPointerTypedefBuiltIn extends BuiltIn implements T return modelTypedef.getLength(); } + @Override + public int getAlignedLength() { + return modelTypedef.getAlignedLength(); + } + @Override public DataType getDataType() { return modelTypedef.getDataType(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedComponentPacker.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedComponentPacker.java index 06895671b5..13343fade2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedComponentPacker.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedComponentPacker.java @@ -299,7 +299,7 @@ class AlignedComponentPacker { int minOffset) { DataType componentDt = dataTypeComponent.getDataType(); - int dtSize = componentDt.isZeroLength() ? 0 : componentDt.getLength(); + int dtSize = componentDt.isZeroLength() ? 0 : componentDt.getAlignedLength(); if (dtSize < 0) { dtSize = dataTypeComponent.getLength(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java index f16b2e739d..b280085b17 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java @@ -56,6 +56,10 @@ public class ArrayDataType extends DataTypeImpl implements Array { public ArrayDataType(DataType dataType, int numElements, int elementLength, DataTypeManager dtm) { super(dataType.getCategoryPath(), "array", dtm); + if (dataType instanceof FactoryDataType) { + throw new IllegalArgumentException( + "Factory data type not permitted"); + } if (numElements < 0) { throw new IllegalArgumentException( "Number of array elements may not be negative [" + numElements + "]"); @@ -75,6 +79,9 @@ public class ArrayDataType extends DataTypeImpl implements Array { } this.elementLength = elementLength; } + else { + this.elementLength = dataType.getAlignedLength(); + } this.dataType = dataType; this.numElements = numElements; name = DataTypeUtilities.getName(this, true); @@ -168,6 +175,11 @@ public class ArrayDataType extends DataTypeImpl implements Array { return numElements * getElementLength(); } + @Override + public int getAlignedLength() { + return getLength(); + } + @Override public String getDescription() { return "Array of " + dataType.getDisplayName(); @@ -193,7 +205,8 @@ public class ArrayDataType extends DataTypeImpl implements Array { @Override public void dataTypeSizeChanged(DataType dt) { - if (dt == dataType) { + if (dt == dataType && dt.getLength() > 0) { + elementLength = dataType.getAlignedLength(); notifySizeChanged(); } } @@ -217,7 +230,7 @@ public class ArrayDataType extends DataTypeImpl implements Array { @Override public int getElementLength() { - return (dataType instanceof Dynamic) ? elementLength : dataType.getLength(); + return elementLength; } @Override @@ -246,7 +259,9 @@ public class ArrayDataType extends DataTypeImpl implements Array { dataType.removeParent(this); dataType = newDt; dataType.addParent(this); - elementLength = newDt.getLength() < 0 ? oldElementLength : -1; + if (dataType.getLength() >= 0) { + elementLength = dataType.getAlignedLength(); + } if (!getName().equals(oldName)) { notifyNameChanged(oldName); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java index 9a3d09b951..5b6acad76f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java @@ -15,9 +15,8 @@ */ package ghidra.program.model.data; -import java.util.*; - import java.math.BigInteger; +import java.util.*; import ghidra.docking.settings.*; import ghidra.program.model.mem.MemBuffer; @@ -336,6 +335,11 @@ public class BitFieldDataType extends AbstractDataType { return storageSize; } + @Override + public int getAlignedLength() { + return getLength(); + } + @Override public String getDescription() { StringBuffer sbuf = new StringBuffer(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex16DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex16DataType.java index 70d9c8db3a..22c6f9a6e9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex16DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex16DataType.java @@ -15,8 +15,10 @@ */ package ghidra.program.model.data; +import ghidra.program.model.data.floats.Float64DataType; + /** - * Provides a definition of a {@code complex} built-in data type consisting of two 8 byte floating point + * Provides a definition of a {@code complex} built-in data type consisting of two 64-bit floating point * numbers in the IEEE 754 double precision format. */ public class Complex16DataType extends AbstractComplexDataType { @@ -28,7 +30,7 @@ public class Complex16DataType extends AbstractComplexDataType { } public Complex16DataType(DataTypeManager dtm) { - super("complex16", Float8DataType.dataType, dtm); + super("complex16", Float64DataType.dataType, dtm); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex32DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex32DataType.java index 7acbdcd3ee..962733da77 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex32DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex32DataType.java @@ -15,8 +15,10 @@ */ package ghidra.program.model.data; +import ghidra.program.model.data.floats.Float128DataType; + /** - * Provides a definition of a {@code complex} built-in data type consisting of two 16 byte floating point + * Provides a definition of a {@code complex} built-in data type consisting of two 128-bit floating point * numbers in the IEEE 754 double precision format. */ public class Complex32DataType extends AbstractComplexDataType { @@ -28,7 +30,7 @@ public class Complex32DataType extends AbstractComplexDataType { } public Complex32DataType(DataTypeManager dtm) { - super("complex32", Float16DataType.dataType, dtm); + super("complex32", Float128DataType.dataType, dtm); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex8DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex8DataType.java index d30e9feb4e..9f13ea46de 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex8DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Complex8DataType.java @@ -15,8 +15,10 @@ */ package ghidra.program.model.data; +import ghidra.program.model.data.floats.Float32DataType; + /** - * Provides a definition of a {@code complex} built-in data type consisting of two 4 byte floating point + * Provides a definition of a {@code complex} built-in data type consisting of two 32-bit floating point * numbers in the IEEE 754 double precision format. */ @@ -29,7 +31,7 @@ public class Complex8DataType extends AbstractComplexDataType { } public Complex8DataType(DataTypeManager dtm) { - super("complex8", Float4DataType.dataType, dtm); + super("complex8", Float32DataType.dataType, dtm); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java index dedcad2a3e..f267648884 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java @@ -62,6 +62,11 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C description = ""; } + @Override + public final int getAlignedLength() { + return getLength(); + } + @Override public int getStoredPackingValue() { return packing; @@ -96,18 +101,7 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C if ((isPackingEnabled() || (this instanceof Union)) && !(dataType instanceof Dynamic)) { length = -1; // force use of datatype size } - int dtLength = dataType.getLength(); - if (length <= 0) { - length = dtLength; - } - else if (dtLength > 0 && dtLength < length) { - length = dtLength; - } - if (length <= 0) { - throw new IllegalArgumentException("Positive length must be specified for " + - dataType.getDisplayName() + " component"); - } - return length; + return DataTypeComponentImpl.getPreferredComponentLength(dataType, length); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CountedDynamicDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CountedDynamicDataType.java index 0af861f420..200bb5c8ef 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CountedDynamicDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CountedDynamicDataType.java @@ -79,7 +79,7 @@ public abstract class CountedDynamicDataType extends DynamicDataType { int n = (int) getCount(memory, start.add(counterOffset)); DataTypeComponent[] comps = new DataTypeComponent[n + 1]; - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, buf); + DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, buf, false); if (dti == null) { Msg.error(this, "ERROR: problem with data at " + buf.getAddress()); @@ -94,7 +94,7 @@ public abstract class CountedDynamicDataType extends DynamicDataType { try { newBuf.advance(countSize); for (int i = 1; i <= n; i++) { - dti = DataTypeInstance.getDataTypeInstance(baseStruct, buf); + dti = DataTypeInstance.getDataTypeInstance(baseStruct, buf, false); if (dti == null) { Msg.error(this, "ERROR: problem with data at " + buf.getAddress()); return null; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java index c15d05ba0b..1239457ccb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java @@ -15,7 +15,7 @@ */ package ghidra.program.model.data; -import ghidra.util.exception.NoValueException; +import java.util.Arrays; public interface DataOrganization { @@ -75,17 +75,17 @@ public interface DataOrganization { int getLongLongSize(); /** - * @return the size of a float primitive data type in bytes. + * @return the encoding size of a float primitive data type in bytes. */ int getFloatSize(); /** - * @return the size of a double primitive data type in bytes. + * @return the encoding size of a double primitive data type in bytes. */ int getDoubleSize(); /** - * @return the size of a long double primitive data type in bytes. + * @return the encoding size of a long double primitive data type in bytes. */ int getLongDoubleSize(); @@ -119,12 +119,14 @@ public interface DataOrganization { int getDefaultPointerAlignment(); /** - * Gets the alignment that is defined for a data type of the indicated size if one is defined. - * @param size the size of the data type + * Gets the primitive data alignment that is defined for the specified size. If no entry has + * been defined for the specified size alignment of the next smaller map entry will be returned. + * If the map is empty the {@link #getDefaultAlignment() default alignment}. The returned + * value will not exceed the {@link #getAbsoluteMaxAlignment() defined maximum alignment}. + * @param size the primitive data size * @return the alignment of the data type. - * @throws NoValueException if there isn't an alignment defined for the indicated size. */ - int getSizeAlignment(int size) throws NoValueException; + int getSizeAlignment(int size); /** * Get the composite bitfield packing information associated with this data organization. @@ -139,8 +141,8 @@ public interface DataOrganization { int getSizeAlignmentCount(); /** - * Gets the sizes that have an alignment specified. - * @return the sizes with alignments mapped to them. + * Gets the ordered list of sizes that have an alignment specified. + * @return the ordered list of sizes with alignments mapped to them. */ int[] getSizes(); @@ -213,19 +215,14 @@ public interface DataOrganization { } int[] keys = getSizes(); int[] op2keys = obj.getSizes(); - if (keys.length != op2keys.length) { + if (!Arrays.equals(keys, op2keys)) { return false; } - try { - for (int k : keys) { - if (getSizeAlignment(k) != obj.getSizeAlignment(k)) { - return false; - } + for (int k : keys) { + if (getSizeAlignment(k) != obj.getSizeAlignment(k)) { + return false; } } - catch (NoValueException ex) { - return false; - } return true; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java index b16292b30d..0c3090979b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java @@ -20,11 +20,11 @@ import static ghidra.program.model.pcode.ElementId.*; import java.io.IOException; import java.util.*; +import java.util.Map.Entry; import ghidra.program.database.DBStringMapAdapter; import ghidra.program.model.lang.Language; import ghidra.program.model.pcode.Encoder; -import ghidra.util.exception.NoValueException; import ghidra.util.xml.SpecXmlUtils; import ghidra.xml.XmlElement; import ghidra.xml.XmlPullParser; @@ -48,9 +48,9 @@ public class DataOrganizationImpl implements DataOrganization { public static final int DEFAULT_INT_SIZE = 4; public static final int DEFAULT_LONG_SIZE = 4; public static final int DEFAULT_LONG_LONG_SIZE = 8; - public static final int DEFAULT_FLOAT_SIZE = 4; - public static final int DEFAULT_DOUBLE_SIZE = 8; - public static final int DEFAULT_LONG_DOUBLE_SIZE = 8; + public static final int DEFAULT_FLOAT_SIZE = 4; // encoding size only + public static final int DEFAULT_DOUBLE_SIZE = 8; // encoding size only + public static final int DEFAULT_LONG_DOUBLE_SIZE = 8; // encoding size only // DBStringMapAdapter save/restore keys private static final String BIG_ENDIAN_NAME = "big_endian"; @@ -83,7 +83,7 @@ public class DataOrganizationImpl implements DataOrganization { /* * Map for determining the alignment of a data type based upon its size. */ - private final HashMap sizeAlignmentMap = new HashMap<>(); + private final TreeMap sizeAlignmentMap = new TreeMap<>(); /** * Creates a new default DataOrganization. This has a mapping which defines the alignment @@ -294,7 +294,7 @@ public class DataOrganizationImpl implements DataOrganization { } /** - * Defines the size of a float primitive data type. + * Defines the encoding size of a float primitive data type. * @param floatSize the size of a float. */ public void setFloatSize(int floatSize) { @@ -305,7 +305,7 @@ public class DataOrganizationImpl implements DataOrganization { } /** - * Defines the size of a double primitive data type. + * Defines the encoding size of a double primitive data type. * @param doubleSize the size of a double. */ public void setDoubleSize(int doubleSize) { @@ -319,7 +319,7 @@ public class DataOrganizationImpl implements DataOrganization { } /** - * Defines the size of a long double primitive data type. + * Defines the encoding size of a long double primitive data type. * @param longDoubleSize the size of a long double. */ public void setLongDoubleSize(int longDoubleSize) { @@ -409,15 +409,14 @@ public class DataOrganizationImpl implements DataOrganization { this.defaultPointerAlignment = defaultPointerAlignment; } - /** - * Gets the alignment that is defined for a data type of the indicated size if one is defined. - * @param size the size of the data type - * @return the alignment of the data type. - * @throws NoValueException if there isn't an alignment defined for the indicated size. - */ @Override - public int getSizeAlignment(int size) throws NoValueException { - return sizeAlignmentMap.get(size); + public int getSizeAlignment(int size) { + Entry floorEntry = sizeAlignmentMap.floorEntry(size); + int alignment = floorEntry != null ? floorEntry.getValue() : defaultAlignment; + if (absoluteMaxAlignment != 0) { + return Math.min(alignment, absoluteMaxAlignment); + } + return alignment; } /** @@ -500,7 +499,7 @@ public class DataOrganizationImpl implements DataOrganization { @Override public int getAlignment(DataType dataType) { - int dtSize = dataType.getLength(); + int dtSize = dataType.getAlignedLength(); if (dataType instanceof Dynamic || dataType instanceof FactoryDataType || dtSize <= 0) { return 1; } @@ -525,18 +524,15 @@ public class DataOrganizationImpl implements DataOrganization { BitFieldDataType bitfieldDt = (BitFieldDataType) dataType; return getAlignment(bitfieldDt.getBaseDataType()); } - // Otherwise get the alignment based on the size. - if (sizeAlignmentMap.containsKey(dtSize)) { - int sizeAlignment = sizeAlignmentMap.get(dtSize); - return ((absoluteMaxAlignment == 0) || (sizeAlignment < absoluteMaxAlignment)) - ? sizeAlignment - : absoluteMaxAlignment; - } - if (dataType instanceof Pointer) { + + // If pointer size not found in size alignment map use default pointer alignment + // TODO: this should probably be re-evaluated for its neccessity + if (!sizeAlignmentMap.containsKey(dtSize) && dataType instanceof Pointer) { return getDefaultPointerAlignment(); } - // Otherwise just assume the default alignment. - return getDefaultAlignment(); + + // Otherwise get the alignment based on the size. + return getSizeAlignment(dtSize); } /** @@ -551,7 +547,7 @@ public class DataOrganizationImpl implements DataOrganization { if (alignment <= 0) { return minimumOffset; } - if ((alignment & 1) == 0) { + if (isPowerOfTwo(alignment)) { // handle alignment which is a power-of-2 return alignment + ((minimumOffset - 1) & ~(alignment - 1)); } @@ -560,6 +556,10 @@ public class DataOrganizationImpl implements DataOrganization { return minimumOffset + adj; } + private static boolean isPowerOfTwo(int n) { + return (n & (n - 1)) == 0; + } + /** * Determines the least (lowest) common multiple of two numbers. * @param value1 the first number @@ -689,13 +689,8 @@ public class DataOrganizationImpl implements DataOrganization { } for (int size : dataOrg.getSizes()) { - try { - String key = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + "." + size; - dataMap.put(key, Integer.toString(dataOrg.getSizeAlignment(size))); - } - catch (NoValueException e) { - // skip entry - } + String key = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + "." + size; + dataMap.put(key, Integer.toString(dataOrg.getSizeAlignment(size))); } BitFieldPackingImpl.save(dataOrg.getBitFieldPacking(), dataMap, diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java index ae1ae0b567..016086360d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java @@ -15,9 +15,8 @@ */ package ghidra.program.model.data; -import java.util.Collection; - import java.net.URL; +import java.util.Collection; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsDefinition; @@ -227,17 +226,48 @@ public interface DataType { public String getMnemonic(Settings settings); /** - * Get the length (number of 8-bit bytes) of this DataType. + * Get the length of this DataType as a number of 8-bit bytes. *

- * NOTE: No datatype should ever return 0, even if {@link #isZeroLength()}, and only - * {@link Dynamic} datatypes should return -1. If {@link #isZeroLength()} is true a length of 1 - * should be returned. Where a zero-length datatype can be handled (e.g., {@link Composite}) the + * For primitive datatypes this reflects the smallest varnode which can be used to + * contain its value (i.e., raw data length). + *

+ * Example: For x86 32-bit gcc an 80-bit {@code long double} {@link #getLength() raw data length} + * of 10-bytes will fit within a floating point register while its {@link #getAlignedLength() aligned-length} + * of 12-bytes is used by the gcc compiler for data/array/component allocations to maintain alignment + * (i.e., {@code sizeof(long double)} ). + *

+ * NOTE: Other than the {@link VoidDataType}, no datatype should ever return 0, even if + * {@link #isZeroLength()}, and only {@link Dynamic}/{@link FactoryDataType} datatypes + * should return -1. If {@link #isZeroLength()} is true a length of 1 should be returned. + * Where a zero-length datatype can be handled (e.g., {@link Composite}) the * {@link #isZeroLength()} method should be used. * * @return the length of this DataType */ public int getLength(); + /** + * Get the aligned-length of this datatype as a number of 8-bit bytes. + *

+ * For primitive datatypes this is equivalent to the C/C++ "sizeof" operation within source code and + * should be used when determining {@link Array} element length or component sizing for a + * {@link Composite}. For {@link Pointer}, {@link Composite} and {@link Array} types this will + * return the same value as {@link #getLength()}. + *

+ * Example: For x86 32-bit gcc an 80-bit {@code long double} {@link #getLength() raw data length} + * of 10-bytes will fit within a floating point register while its {@link #getAlignedLength() aligned-length} + * of 12-bytes is used by the gcc compiler for data/array/component allocations to maintain alignment + * (i.e., {@code sizeof(long double)} ). + *

+ * NOTE: Other than the {@link VoidDataType}, no datatype should ever return 0, even if + * {@link #isZeroLength()}, and only {@link Dynamic} / {@link FactoryDataType} / + * {@link FunctionDefinition} datatypes should return -1. If {@link #isZeroLength()} is true + * a length of 1 should be returned. + * + * @return byte length of binary encoding. + */ + public int getAlignedLength(); + /** * Indicates this datatype is defined with a zero length. *

diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java index 403709ed27..690d72cfbe 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java @@ -347,4 +347,32 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali return InternalDataTypeComponent.toString(this); } + /** + * Get the preferred length for a new component. The length returned will be no + * larger than the specified length. + * + * @param dataType new component datatype + * @param length constrained length or -1 to force use of dataType size. + * Dynamic types such as string must have a positive length + * specified. + * @return preferred component length + */ + public static int getPreferredComponentLength(DataType dataType, int length) { + if (DataTypeComponent.usesZeroLengthComponent(dataType)) { + return 0; + } + int dtLength = dataType.getAlignedLength(); + if (length <= 0) { + length = dtLength; + } + else if (dtLength > 0 && dtLength < length) { + length = dtLength; + } + if (length <= 0) { + throw new IllegalArgumentException("Positive length must be specified for " + + dataType.getDisplayName() + " component"); + } + return length; + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeImpl.java index 79137ab7a8..59a7ef95a2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeImpl.java @@ -36,6 +36,8 @@ public abstract class DataTypeImpl extends AbstractDataType { // defaultSettings implementation established by its DataTypeManager. protected Settings defaultSettings; + private Integer alignedLength; + private List> parentList; private UniversalID universalID; private SourceArchive sourceArchive; @@ -91,6 +93,43 @@ public abstract class DataTypeImpl extends AbstractDataType { return getDataTypePath().getPath(); } + /** + * Return the aligned-length for a fixed length datatype. This is intended to produce a + * result consistent with the C/C++ {@code sizeof(type)} operation. Use of this method + * with {@link TypeDef} is not allowed. + * Whereas {@link #getLength()} corresponds to the raw type size which may be moved into + * a smaller register/varnode. Example: this frequently occurs with encoded floating-point + * data such as a 10-byte/80-bit encoding which is stored in memory as 12 or 16-bytes in order + * to maintain memory alignment constraints. + * @param dataType datatype + * @return aligned-length or -1 if not a fixed-length datatype + */ + private static int computeAlignedLength(DataType dataType) { + if ((dataType instanceof TypeDef) || (dataType instanceof Composite) || + (dataType instanceof Array)) { + // Typedefs must defer to base datatype for aligned-length determination + throw new UnsupportedOperationException(); + } + int len = dataType.getLength(); + if (len <= 0 || (dataType instanceof Pointer)) { + return len; + } + int align = dataType.getDataOrganization().getSizeAlignment(len); + int mod = len % align; + if (mod != 0) { + len += (align - mod); + } + return len; + } + + @Override + public int getAlignedLength() { + if (alignedLength == null) { + alignedLength = computeAlignedLength(this); + } + return alignedLength; + } + @Override public int getAlignment() { int length = getLength(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeInstance.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeInstance.java index 78e06d992b..560848301d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeInstance.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeInstance.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. @@ -16,6 +15,7 @@ */ package ghidra.program.model.data; +import ghidra.program.model.listing.Data; import ghidra.program.model.mem.MemBuffer; /** @@ -33,6 +33,9 @@ public class DataTypeInstance { /** * Create an instance of a data type with the given length. + *
+ * NOTE: fixed-length primitive datatypes assume {@link DataType#getLength() raw datatype length} + * intended for {@link Data} use. * * @param dt data type * @param length fixed length of the data type @@ -66,25 +69,44 @@ public class DataTypeInstance { this.length = length; } + @Override + public String toString() { + return dataType.toString(); + } + /** * Generate a data-type instance * Factory and Dynamic data-types are NOT handled. - * @param dataType - * @param buf + * @param dataType data type + * @param buf memory buffer + * @param useAlignedLength if true a fixed-length primitive data type will use its + * {@link DataType#getAlignedLength() aligned-length}, otherwise it will use its + * {@link DataType#getLength() raw length}. NOTE: This generally only relates to + * float datatypes whose raw encoding length may be shorter than their aligned-length + * generally corresponding to a compiler's "sizeof(type)" value. This should generally be + * true for {@link DataTypeComponent} and false for simple {@link Data} instances. * @return data-type instance or null if one could not be determined */ - public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf) { - return getDataTypeInstance(dataType, buf, -1); + public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf, + boolean useAlignedLength) { + return getDataTypeInstance(dataType, buf, -1, useAlignedLength); } /** * Attempt to create a fixed-length data-type instance. * Factory and non-sizable Dynamic data-types are NOT handled. - * @param dataType + * @param dataType data type * @param length length for sizable Dynamic data-types, otherwise ignored + * @param useAlignedLength if true a fixed-length primitive data type will use its + * {@link DataType#getAlignedLength() aligned-length}, otherwise it will use its + * {@link DataType#getLength() raw length}. NOTE: This generally only relates to + * float datatypes whose raw encoding length may be shorter than their aligned-length + * generally corresponding to a compiler's "sizeof(type)" value. This should generally be + * true for {@link DataTypeComponent} and false for simple {@link Data} instances. * @return data-type instance or null if unable to create instance. */ - public static DataTypeInstance getDataTypeInstance(DataType dataType, int length) { + public static DataTypeInstance getDataTypeInstance(DataType dataType, int length, + boolean useAlignedLength) { if (dataType == null) { return null; } @@ -105,6 +127,9 @@ public class DataTypeInstance { return null; } } + else if (useAlignedLength) { + length = dataType.getAlignedLength(); + } else { length = dataType.getLength(); } @@ -116,20 +141,26 @@ public class DataTypeInstance { return new DataTypeInstance(dataType, length); } - @Override - public String toString() { - return dataType.toString(); - } - /** * Attempt to create a data-type instance associated with a specific memory location. * Factory and Dynamic data-types are handled. + *
+ * NOTE: fixed-length primitive datatypes assume {@link DataType#getLength() raw datatype length} + * intended for {@link Data} use. + * * @param dataType * @param buf memory location * @param length length for sizable Dynamic data-types, otherwise ignored + * @param useAlignedLength if true a fixed-length primitive data type will use its + * {@link DataType#getAlignedLength() aligned-length}, otherwise it will use its + * {@link DataType#getLength() raw length}. NOTE: This generally only relates to + * float datatypes whose raw encoding length may be shorter than their aligned-length + * generally corresponding to a compiler's "sizeof(type)" value. This should generally be + * true for {@link DataTypeComponent} and false for simple {@link Data} instances. * @return data-type instance or null if unable to create instance. */ - public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf, int length) { + public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf, int length, + boolean useAlignedLength) { if (dataType instanceof FactoryDataType) { dataType = ((FactoryDataType) dataType).getDataType(buf); length = -1; // ignore user-specified length for factory use @@ -151,6 +182,9 @@ public class DataTypeInstance { Dynamic dynamicDataType = (Dynamic) dataType; length = dynamicDataType.getLength(buf, length); } + else if (useAlignedLength) { + length = dataType.getAlignedLength(); + } else { length = dataType.getLength(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java index 41172cb83b..4b88c7840d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java @@ -259,10 +259,10 @@ public final class DataUtilities { DataTypeInstance dti; if (length > 0 && (realType instanceof Dynamic) && ((Dynamic) realType).canSpecifyLength()) { - dti = DataTypeInstance.getDataTypeInstance(newType, memBuf, length); + dti = DataTypeInstance.getDataTypeInstance(newType, memBuf, length, false); } else { - dti = DataTypeInstance.getDataTypeInstance(newType, memBuf); + dti = DataTypeInstance.getDataTypeInstance(newType, memBuf, false); } if (dti == null) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DoubleDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DoubleDataType.java index c9d79568d5..ca5bd1435a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DoubleDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DoubleDataType.java @@ -15,6 +15,7 @@ */ package ghidra.program.model.data; +import ghidra.program.model.data.floats.AbstractFloatDataType; /** * Provides a definition of a Double within a program. @@ -31,7 +32,12 @@ public class DoubleDataType extends AbstractFloatDataType { } public DoubleDataType(DataTypeManager dtm) { - super("double", dtm); + super("double", getDataOrganization(dtm).getDoubleSize(), dtm); + } + + @Override + protected String buildDescription() { + return "Compiler-defined 'double' " + super.buildDescription(); } public DataType clone(DataTypeManager dtm) { @@ -46,9 +52,4 @@ public class DoubleDataType extends AbstractFloatDataType { return true; } - @Override - public int getLength() { - return getDataOrganization().getDoubleSize(); - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java index bb883e7b52..192e564c57 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java @@ -239,6 +239,11 @@ public class EnumDataType extends GenericDataType implements Enum { return length; } + @Override + public int getAlignedLength() { + return getLength(); + } + public void setLength(int newLength) { if (newLength == length) { return; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java index 3c2ac11b3f..d2c1eacede 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FactoryStructureDataType.java @@ -137,7 +137,7 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor protected DataTypeComponent addComponent(Structure es, DataType dt, String componentName) { - return es.add(dt, dt.getLength(), componentName, null); + return es.add(dt, dt.getAlignedLength(), componentName, null); } protected abstract void populateDynamicStructure(MemBuffer buf, Structure es); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float8DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float8DataType.java deleted file mode 100644 index f94e622d6c..0000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float8DataType.java +++ /dev/null @@ -1,44 +0,0 @@ -/* ### - * 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. - * 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.data; - -public class Float8DataType extends AbstractFloatDataType { - - public static final Float8DataType dataType = new Float8DataType(); - - public Float8DataType() { - this(null); - } - - public Float8DataType(DataTypeManager dtm) { - super("float8", dtm); - } - - @Override - public DataType clone(DataTypeManager dtm) { - if (dtm == getDataTypeManager()) { - return this; - } - return new Float8DataType(dtm); - } - - @Override - public int getLength() { - return 8; - } - -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FloatDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FloatDataType.java index 1067c281c2..8504a7901a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FloatDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FloatDataType.java @@ -15,6 +15,8 @@ */ package ghidra.program.model.data; +import ghidra.program.model.data.floats.AbstractFloatDataType; + /** * Provides a definition of a Float within a program. */ @@ -30,7 +32,12 @@ public class FloatDataType extends AbstractFloatDataType { } public FloatDataType(DataTypeManager dtm) { - super("float", dtm); + super("float", getDataOrganization(dtm).getFloatSize(), dtm); + } + + @Override + protected String buildDescription() { + return "Compiler-defined 'float' " + super.buildDescription(); } @Override @@ -46,9 +53,4 @@ public class FloatDataType extends AbstractFloatDataType { return true; } - @Override - public int getLength() { - return getDataOrganization().getFloatSize(); - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IndexedDynamicDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IndexedDynamicDataType.java index b519e1ac09..ea24a1237c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IndexedDynamicDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/IndexedDynamicDataType.java @@ -169,7 +169,7 @@ public abstract class IndexedDynamicDataType extends DynamicDataType { comps = new DataTypeComponent[2]; } MemoryBufferImpl newBuf = new MemoryBufferImpl(memory, buf.getAddress()); - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, newBuf); + DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, newBuf, false); if (dti == null) { Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress()); return null; @@ -183,7 +183,7 @@ public abstract class IndexedDynamicDataType extends DynamicDataType { int offset = countSize; newBuf = new MemoryBufferImpl(memory, buf.getAddress()); newBuf.advance(countSize); - dti = DataTypeInstance.getDataTypeInstance(data, newBuf); + dti = DataTypeInstance.getDataTypeInstance(data, newBuf, false); if (dti == null) { Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress()); return null; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDoubleDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDoubleDataType.java index 0af76c9f4e..5ca62c22fa 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDoubleDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/LongDoubleDataType.java @@ -15,6 +15,7 @@ */ package ghidra.program.model.data; +import ghidra.program.model.data.floats.AbstractFloatDataType; /** * Provides a definition of a Long Double within a program. @@ -31,7 +32,12 @@ public class LongDoubleDataType extends AbstractFloatDataType { } public LongDoubleDataType(DataTypeManager dtm) { - super("longdouble", dtm); + super("longdouble", getDataOrganization(dtm).getLongDoubleSize(), dtm); + } + + @Override + protected String buildDescription() { + return "Compiler-defined 'long double' " + super.buildDescription(); } public DataType clone(DataTypeManager dtm) { @@ -50,9 +56,4 @@ public class LongDoubleDataType extends AbstractFloatDataType { public boolean hasLanguageDependantLength() { return true; } - - @Override - public int getLength() { - return getDataOrganization().getLongDoubleSize(); - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MetaDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MetaDataType.java index fccda02918..fe80736638 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MetaDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MetaDataType.java @@ -15,6 +15,8 @@ */ package ghidra.program.model.data; +import ghidra.program.model.data.floats.AbstractFloatDataType; + public enum MetaDataType { // Enumerations are ordered in terms of how "specific" the data-type class is VOID, // "void" data-type diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/NoisyStructureBuilder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/NoisyStructureBuilder.java index e88712769e..c3e46b015e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/NoisyStructureBuilder.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/NoisyStructureBuilder.java @@ -31,6 +31,9 @@ import ghidra.program.model.pcode.PartialUnion; * In a conflict, less specific data-types are replaced. * After all information is collected a final Structure can be built by iterating over * the final field entries. + * + * NOTE: No attempt has been made to utilize {@link DataType#getAlignedLength()} when considering + * component type lengths. */ public class NoisyStructureBuilder { private TreeMap offsetToDataTypeMap = new TreeMap<>(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java index aafe82f788..9e95e70c48 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java @@ -171,6 +171,11 @@ public class PointerDataType extends BuiltIn implements Pointer { return length <= 0 ? getDataOrganization().getPointerSize() : length; } + @Override + public int getAlignedLength() { + return getLength(); + } + @Override public String getDefaultLabelPrefix() { return POINTER_LABEL_PREFIX; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java index 407e9f8b69..99b09e1f1f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypedef.java @@ -210,6 +210,11 @@ public class PointerTypedef extends GenericDataType implements TypeDef { return modelTypedef.getLength(); } + @Override + public int getAlignedLength() { + return modelTypedef.getAlignedLength(); + } + @Override public DataType getDataType() { return modelTypedef.getDataType(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatCountDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatCountDataType.java index 0defa2bb30..46e80f2411 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatCountDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatCountDataType.java @@ -60,7 +60,8 @@ public abstract class RepeatCountDataType extends DynamicDataType { MemoryBufferImpl newBuf = new MemoryBufferImpl(buf.getMemory(), buf.getAddress()); newBuf.advance(countSize); for (int i = 1; i < n; i++) { - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(repeatDataType, newBuf); + DataTypeInstance dti = + DataTypeInstance.getDataTypeInstance(repeatDataType, newBuf, false); if (dti == null) { Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress()); return null; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatedDynamicDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatedDynamicDataType.java index 11c3453c8b..ac269be21d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatedDynamicDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RepeatedDynamicDataType.java @@ -96,7 +96,8 @@ public abstract class RepeatedDynamicDataType extends DynamicDataType { try { newBuf.advance(countSize); while (moreComponents(memory, newBuf.getAddress())) { - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(baseStruct, newBuf); + DataTypeInstance dti = + DataTypeInstance.getDataTypeInstance(baseStruct, newBuf, false); if (dti == null) { Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress()); return null; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructuredDynamicDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructuredDynamicDataType.java index cd6663bf1c..0985d887e7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructuredDynamicDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructuredDynamicDataType.java @@ -102,7 +102,8 @@ public abstract class StructuredDynamicDataType extends DynamicDataType { MemoryBufferImpl newBuf = new MemoryBufferImpl(memory, buf.getAddress()); try { for (int i = 0; i < components.size(); i++) { - DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(components.get(i), newBuf); + DataTypeInstance dti = + DataTypeInstance.getDataTypeInstance(components.get(i), newBuf, false); if (dti == null) { Msg.error(this, "Invalid data at " + newBuf.getAddress()); return null; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java index 9f8547b0ba..ced937e924 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java @@ -209,6 +209,11 @@ public class TypedefDataType extends GenericDataType implements TypeDef { return dataType.getLength(); } + @Override + public int getAlignedLength() { + return dataType.getAlignedLength(); + } + @Override public String getRepresentation(MemBuffer buf, Settings settings, int length) { return dataType.getRepresentation(buf, settings, length); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractFloatDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/AbstractFloatDataType.java similarity index 54% rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractFloatDataType.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/AbstractFloatDataType.java index 5342dc492b..37a69a6fb3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractFloatDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/AbstractFloatDataType.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.program.model.data; +package ghidra.program.model.data.floats; -import java.math.BigDecimal; import java.math.BigInteger; import java.util.TreeMap; @@ -23,6 +22,7 @@ import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsDefinition; import ghidra.pcode.floatformat.*; import ghidra.pcode.utils.Utils; +import ghidra.program.model.data.*; import ghidra.program.model.mem.MemBuffer; /** @@ -30,61 +30,99 @@ import ghidra.program.model.mem.MemBuffer; */ public abstract class AbstractFloatDataType extends BuiltIn { - private final static long serialVersionUID = 1; - + // TODO: Add FloatDisplayPrecisionSettingsDefinition private static SettingsDefinition[] SETTINGS_DEFS = {}; - public AbstractFloatDataType(String name, DataTypeManager dtm) { - super(null, name, dtm); - } + private final FloatFormat floatFormat; + private final int encodedLength; + + private String description; /** - * - * @see ghidra.program.model.data.DataType#getMnemonic(Settings) + * Abstract float datatype constructor + * @param name name of the float datatype. + * @param encodedLength the floating encoding length as number of 8-bit bytes. + * @param dtm associated datatype manager which dictates the {@link DataOrganization} to + * be used. This argument may be null to adopt the default data organization. */ + public AbstractFloatDataType(String name, int encodedLength, DataTypeManager dtm) { + super(null, name, dtm); + if (encodedLength < 1) { + throw new IllegalArgumentException("Invalid encoded length: " + encodedLength); + } + this.encodedLength = encodedLength; + FloatFormat format = null; + try { + // Establish float format + format = FloatFormatFactory.getFloatFormat(getLength()); + } + catch (UnsupportedFloatFormatException e) { + // ignore + } + floatFormat = format; + } + @Override public String getMnemonic(Settings settings) { return name; } - /** - * - * @see ghidra.program.model.data.DataType#getDescription() - */ + protected final String buildIEEE754StandardDescription() { + StringBuilder buf = new StringBuilder("IEEE 754 floating-point type ("); + int bitLen = encodedLength * 8; + buf.append(Integer.toString(bitLen)); + buf.append("-bit / "); + buf.append(Integer.toString(encodedLength)); + buf.append("-byte format, aligned-length is "); + buf.append(Integer.toString(getAlignedLength())); + buf.append("-bytes)"); + return buf.toString(); + } + + protected String buildDescription() { + return buildIEEE754StandardDescription(); + } + @Override - public String getDescription() { - return "IEEE-754 Float"; + public final String getDescription() { + if (description == null) { + description = buildDescription(); + } + return description; + } + + @Override + public Class getValueClass(Settings settings) { + return BigFloat.class; } /** + * Get the encoded length (number of 8-bit bytes) of this float datatype. * - * @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer, - * ghidra.docking.settings.Settings, int) + * @return encoded length of this float datatype. */ @Override - public Object getValue(MemBuffer buf, Settings settings, int length) { + public final int getLength() { + return encodedLength; + } + + @Override + public BigFloat getValue(MemBuffer buf, Settings settings, int length) { try { int len = getLength(); // use type length (ignore length arg) - FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(len); + if (floatFormat == null) { + return null; + } byte[] bytes = new byte[len]; if (buf.getBytes(bytes, 0) != len) { return null; } if (len <= 8) { long value = Utils.bytesToLong(bytes, len, buf.isBigEndian()); - double doubleValue = floatFormat.getHostFloat(value); - switch (len) { - case 2: - // TODO: GP-1379 - return (short) doubleValue; - case 4: - return (float) doubleValue; - } - return doubleValue; + return floatFormat.decodeBigFloat(value); } BigInteger value = Utils.bytesToBigInteger(bytes, len, buf.isBigEndian(), false); - BigDecimal decValue = floatFormat.round(floatFormat.getHostFloat(value)); - return decValue; + return floatFormat.decodeBigFloat(value); } catch (UnsupportedFloatFormatException e) { return null; @@ -93,31 +131,25 @@ public abstract class AbstractFloatDataType extends BuiltIn { @Override public boolean isEncodable() { - int length = getLength(); - return length == 4 || length == 8; + return floatFormat != null; } @Override public byte[] encodeValue(Object value, MemBuffer buf, Settings settings, int length) throws DataTypeEncodeException { + // value expected as Number or BigFloat object try { int len = getLength(); - if (length != -1 && length != len) { - throw new DataTypeEncodeException("Length mismatch", value, this); + if (floatFormat == null) { + throw new DataTypeEncodeException( + "Unsupported float format (" + len + " bytes)", value, this); } - FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(len); - if (len == 8 || len == 4) { - if (!(value instanceof Number)) { - throw new DataTypeEncodeException( - "length-" + len + " float requires Number type", value, this); - } + if ((len == 8 || len == 4) && (value instanceof Number)) { double doubleValue = ((Number) value).doubleValue(); long encoding = floatFormat.getEncoding(doubleValue); return Utils.longToBytes(encoding, len, buf.isBigEndian()); } if (!(value instanceof BigFloat)) { - // TODO: BigFloat really ought to have a valueOf(double) method, or -- - // TODO: -- or BigFloat really ought to have a valueOf(BigDecimal) method throw new DataTypeEncodeException( "non-standard float length requires BigFloat type", value, this); } @@ -132,17 +164,13 @@ public abstract class AbstractFloatDataType extends BuiltIn { } } - /** - * - * @see ghidra.program.model.data.DataType#getRepresentation(MemBuffer, Settings, int) - */ @Override public String getRepresentation(MemBuffer buf, Settings settings, int length) { - Object obj = getValue(buf, settings, length); - if (obj == null) { + BigFloat value = getValue(buf, settings, length); + if (value == null) { return "??"; } - return obj.toString(); + return floatFormat != null ? floatFormat.toDecimalString(value, true) : value.toString(); } @Override @@ -150,16 +178,17 @@ public abstract class AbstractFloatDataType extends BuiltIn { throws DataTypeEncodeException { try { int len = getLength(); - if (length != -1 && length != len) { - throw new DataTypeEncodeException("Length mismatch", repr, this); + if (floatFormat == null) { + throw new DataTypeEncodeException( + "Unsupported float format (" + len + " bytes)", repr, this); } if (length == 8 || length == 4) { double doubleValue = Double.parseDouble(repr); return encodeValue(doubleValue, buf, settings, length); } - // TODO: BigFloat ought to have a parse(String) method, or valueOf(BigDecimal) - throw new DataTypeEncodeException( - "Cannot yet parse values of non-standard float length", repr, this); + BigFloat bf = floatFormat.getBigFloat(repr); + floatFormat.round(bf); + return encodeValue(bf, buf, settings, length); } catch (DataTypeEncodeException e) { throw e; @@ -169,9 +198,6 @@ public abstract class AbstractFloatDataType extends BuiltIn { } } - /** - * @see ghidra.program.model.data.BuiltIn#getBuiltInSettingsDefinitions() - */ @Override protected SettingsDefinition[] getBuiltInSettingsDefinitions() { return SETTINGS_DEFS; @@ -184,6 +210,8 @@ public abstract class AbstractFloatDataType extends BuiltIn { @Override public String getCTypeDeclaration(DataOrganization dataOrganization) { + // NOTE: There are a variety of naming conventions for fixed-length floats + // so we will just use our name and rely on user to edit to suit there needs. return hasLanguageDependantLength() ? null : name; } @@ -196,53 +224,60 @@ public abstract class AbstractFloatDataType extends BuiltIn { if (floatTypes == null) { // unsupported sizes filled-in with a null floatTypes = new TreeMap(); - floatTypes.put(2, Float2DataType.dataType); - floatTypes.put(4, Float4DataType.dataType); - floatTypes.put(8, Float8DataType.dataType); - floatTypes.put(10, Float10DataType.dataType); - floatTypes.put(16, Float16DataType.dataType); + floatTypes.put(Float16DataType.dataType.getLength(), Float16DataType.dataType); + floatTypes.put(Float32DataType.dataType.getLength(), Float32DataType.dataType); + floatTypes.put(Float64DataType.dataType.getLength(), Float64DataType.dataType); + floatTypes.put(Float80DataType.dataType.getLength(), Float80DataType.dataType); + floatTypes.put(Float128DataType.dataType.getLength(), Float128DataType.dataType); } return floatTypes; } /** - * Get a Float data-type instance of the requested size + * Get a Float data-type instance with the requested raw format size in bytes. It is important that the + * "raw" format size is specified since the {@link DataType#getAlignedLength() aligned-length} + * used by compilers (e.g., {@code sizeof()}) may be larger and duplicated across different + * float formats. Example: an 80-bit (10-byte) float may have an aligned-length of 12 or 16-bytes + * based upon alignment requirements of a given compiler. This can result in multiple float + * types having the same aligned-length. * - * @param size data type size, unsupported sizes will cause an undefined type to be returned. + * @param rawFormatByteSize raw float format size, unsupported sizes will cause an undefined + * type to be returned. * @param dtm optional program data-type manager, if specified a generic data-type will be - * returned if possible (i.e., float, double, long double). + * returned if possible (i.e., float, double, long double). * @return float data type of specified size */ - public static DataType getFloatDataType(int size, DataTypeManager dtm) { - if (size < 1) { + public static DataType getFloatDataType(int rawFormatByteSize, DataTypeManager dtm) { + if (rawFormatByteSize < 1) { return DefaultDataType.dataType; } if (dtm != null) { DataOrganization dataOrganization = dtm.getDataOrganization(); if (dataOrganization != null) { - if (size == dataOrganization.getFloatSize()) { + if (rawFormatByteSize == dataOrganization.getFloatSize()) { return FloatDataType.dataType.clone(dtm); } - if (size == dataOrganization.getDoubleSize()) { + if (rawFormatByteSize == dataOrganization.getDoubleSize()) { return DoubleDataType.dataType.clone(dtm); } - if (size == dataOrganization.getLongDoubleSize()) { + if (rawFormatByteSize == dataOrganization.getLongDoubleSize()) { return LongDoubleDataType.dataType.clone(dtm); } } } - DataType dt = getFloatTypes().get(size); + DataType dt = getFloatTypes().get(rawFormatByteSize); if (dt == null) { - return Undefined.getUndefinedDataType(size); + return Undefined.getUndefinedDataType(rawFormatByteSize); } return dt; } /** - * Returns all built-in float data-types + * Returns all built-in floating-point data types * * @param dtm optional program data-type manager, if specified generic data-types will be * returned in place of fixed-sized data-types. + * @return array of floating-point data types */ public static AbstractFloatDataType[] getFloatDataTypes(DataTypeManager dtm) { TreeMap floatMap = getFloatTypes(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float128DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float128DataType.java new file mode 100644 index 0000000000..8d2e12c2b2 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float128DataType.java @@ -0,0 +1,48 @@ +/* ### + * 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.data.floats; + +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.util.classfinder.ClassTranslator; + +public class Float128DataType extends AbstractFloatDataType { + + static { + // remap old byte-sized float to this bit-sized equivalent + ClassTranslator.put( + "ghidra.program.model.data.Float16DataType", Float128DataType.class.getName()); + } + + public static final Float128DataType dataType = new Float128DataType(); + + public Float128DataType() { + this(null); + } + + public Float128DataType(DataTypeManager dtm) { + super("float128", 16, dtm); + } + + @Override + public DataType clone(DataTypeManager dtm) { + if (dtm == getDataTypeManager()) { + return this; + } + return new Float128DataType(dtm); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float16DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float16DataType.java similarity index 71% rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float16DataType.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float16DataType.java index 226ad957f6..ed1eb33309 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float16DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float16DataType.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. @@ -14,10 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.program.model.data; +package ghidra.program.model.data.floats; + +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.util.classfinder.ClassTranslator; public class Float16DataType extends AbstractFloatDataType { + static { + // remap old byte-sized float to this bit-sized equivalent + ClassTranslator.put( + "ghidra.program.model.data.Float2DataType", Float16DataType.class.getName()); + } + public static final Float16DataType dataType = new Float16DataType(); public Float16DataType() { @@ -25,7 +34,7 @@ public class Float16DataType extends AbstractFloatDataType { } public Float16DataType(DataTypeManager dtm) { - super("float16", dtm); + super("float16", 2, dtm); } @Override @@ -36,9 +45,4 @@ public class Float16DataType extends AbstractFloatDataType { return new Float16DataType(dtm); } - @Override - public int getLength() { - return 16; - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float10DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float32DataType.java similarity index 54% rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float10DataType.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float32DataType.java index f7f59805f6..b474c5e199 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float10DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float32DataType.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. @@ -14,18 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.program.model.data; +package ghidra.program.model.data.floats; -public class Float10DataType extends AbstractFloatDataType { +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.util.classfinder.ClassTranslator; - public static final Float10DataType dataType = new Float10DataType(); +public class Float32DataType extends AbstractFloatDataType { - public Float10DataType() { + static { + // remap old byte-sized float to this bit-sized equivalent + ClassTranslator.put( + "ghidra.program.model.data.Float4DataType", Float32DataType.class.getName()); + } + + public static final Float32DataType dataType = new Float32DataType(); + + public Float32DataType() { this(null); } - public Float10DataType(DataTypeManager dtm) { - super("float10", dtm); + public Float32DataType(DataTypeManager dtm) { + super("float32", 4, dtm); } @Override @@ -33,12 +42,7 @@ public class Float10DataType extends AbstractFloatDataType { if (dtm == getDataTypeManager()) { return this; } - return new Float10DataType(dtm); - } - - @Override - public int getLength() { - return 10; + return new Float32DataType(dtm); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float2DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float64DataType.java similarity index 53% rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float2DataType.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float64DataType.java index ab1094d076..e47ac698c3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float2DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float64DataType.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. @@ -14,18 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.program.model.data; +package ghidra.program.model.data.floats; -public class Float2DataType extends AbstractFloatDataType { +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.util.classfinder.ClassTranslator; - public static final Float2DataType dataType = new Float2DataType(); +public class Float64DataType extends AbstractFloatDataType { - public Float2DataType() { + static { + // remap old byte-sized float to this bit-sized equivalent + ClassTranslator.put( + "ghidra.program.model.data.Float8DataType", Float64DataType.class.getName()); + } + + public static final Float64DataType dataType = new Float64DataType(); + + public Float64DataType() { this(null); } - public Float2DataType(DataTypeManager dtm) { - super("float2", dtm); + public Float64DataType(DataTypeManager dtm) { + super("float64", 8, dtm); } @Override @@ -33,12 +42,7 @@ public class Float2DataType extends AbstractFloatDataType { if (dtm == getDataTypeManager()) { return this; } - return new Float2DataType(dtm); - } - - @Override - public int getLength() { - return 2; + return new Float64DataType(dtm); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float4DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float80DataType.java similarity index 53% rename from Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float4DataType.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float80DataType.java index 56a2edd633..ce44c095b5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Float4DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/floats/Float80DataType.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. @@ -14,18 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.program.model.data; +package ghidra.program.model.data.floats; -public class Float4DataType extends AbstractFloatDataType { +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.util.classfinder.ClassTranslator; - public static final Float4DataType dataType = new Float4DataType(); +public class Float80DataType extends AbstractFloatDataType { - public Float4DataType() { + static { + // remap old byte-sized float to this bit-sized equivalent + ClassTranslator.put( + "ghidra.program.model.data.Float10DataType", Float80DataType.class.getName()); + } + + public static final Float80DataType dataType = new Float80DataType(); + + public Float80DataType() { this(null); } - public Float4DataType(DataTypeManager dtm) { - super("float4", dtm); + public Float80DataType(DataTypeManager dtm) { + super("float80", 10, dtm); } @Override @@ -33,12 +42,7 @@ public class Float4DataType extends AbstractFloatDataType { if (dtm == getDataTypeManager()) { return this; } - return new Float4DataType(dtm); - } - - @Override - public int getLength() { - return 4; + return new Float80DataType(dtm); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java index 5e58ed87be..bcf5c21328 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java @@ -26,6 +26,7 @@ import ghidra.app.plugin.processors.sleigh.VarnodeData; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.pcode.*; import ghidra.util.SystemUtilities; import ghidra.util.xml.SpecXmlUtils; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java index 8a86f81c15..d8c7c3feb8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java @@ -20,6 +20,7 @@ import java.util.*; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.lang.*; import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.Namespace; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedEntry.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedEntry.java index b701cbbe54..ff84ba3c02 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedEntry.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedEntry.java @@ -18,7 +18,7 @@ package ghidra.program.model.pcode; import java.io.IOException; import ghidra.program.model.address.Address; -import ghidra.program.model.data.AbstractFloatDataType; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.listing.Program; import ghidra.program.model.listing.VariableStorage; import ghidra.program.model.mem.MemoryBlock; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PartialUnion.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PartialUnion.java index b552f487ef..28686525c0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PartialUnion.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PartialUnion.java @@ -66,6 +66,11 @@ public class PartialUnion extends AbstractDataType { return size; } + @Override + public int getAlignedLength() { + return getLength(); + } + @Override public String getDescription() { return "Partial Union (internal)"; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java index f8be21d995..816536fbe3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java @@ -28,6 +28,7 @@ import ghidra.program.database.data.PointerTypedefInspector; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; +import ghidra.program.model.data.floats.AbstractFloatDataType; import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.DecompilerLanguage; import ghidra.program.model.listing.Program; @@ -249,6 +250,7 @@ public class PcodeDataTypeManager { else if (meta.equals("float")) { int size = (int) decoder.readSignedInteger(ATTRIB_SIZE); decoder.closeElement(el); + // NOTE: Float lookup by length must use "raw" encoding size since return AbstractFloatDataType.getFloatDataType(size, progDataTypes); } else if (meta.equals("partunion")) { diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FloatDataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FloatDataTypeTest.java index 2f91569cab..4e68231b0d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FloatDataTypeTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/FloatDataTypeTest.java @@ -20,6 +20,9 @@ import static org.junit.Assert.*; import org.junit.Test; import generic.test.AbstractGTest; +import ghidra.pcode.floatformat.*; +import ghidra.program.model.data.floats.Float32DataType; +import ghidra.program.model.data.floats.Float64DataType; import ghidra.program.model.mem.ByteMemBufferImpl; import ghidra.util.LittleEndianDataConverter; @@ -34,106 +37,110 @@ public class FloatDataTypeTest extends AbstractGTest { @Test public void testFloat4Extremes() { + FloatFormat ff = FloatFormatFactory.getFloatFormat(4); + int bits = Float.floatToRawIntBits(Float.NaN); byte[] bytes = getBytes(bits, 4); Object value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(Float.NaN, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals(ff.getBigNaN(false), value); bits = Float.floatToRawIntBits(Float.POSITIVE_INFINITY); bytes = getBytes(bits, 4); value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(Float.POSITIVE_INFINITY, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals(ff.getBigInfinity(false), value); bits = Float.floatToRawIntBits(Float.NEGATIVE_INFINITY); bytes = getBytes(bits, 4); value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(Float.NEGATIVE_INFINITY, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals(ff.getBigInfinity(true), value); bits = Float.floatToRawIntBits(0F); bytes = getBytes(bits, 4); value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(0F, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("0.0", ff.toDecimalString((BigFloat) value)); bits = Float.floatToRawIntBits(1F); bytes = getBytes(bits, 4); value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(1F, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("1.0", ff.toDecimalString((BigFloat) value)); bits = Float.floatToRawIntBits(-1F); bytes = getBytes(bits, 4); value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(-1F, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("-1.0", ff.toDecimalString((BigFloat) value)); bits = Float.floatToRawIntBits(555.555F); bytes = getBytes(bits, 4); value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(555.555F, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("555.55499", ff.toDecimalString((BigFloat) value, true)); bits = Float.floatToRawIntBits(-555.555F); bytes = getBytes(bits, 4); value = - Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(-555.555F, value); + Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("-555.55499", ff.toDecimalString((BigFloat) value, true)); } @Test public void testFloat8Extremes() { + FloatFormat ff = FloatFormatFactory.getFloatFormat(8); + long bits = Double.doubleToRawLongBits(Double.NaN); byte[] bytes = getBytes(bits, 8); Object value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(Double.NaN, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals(ff.getBigNaN(false), value); bits = Double.doubleToRawLongBits(Double.POSITIVE_INFINITY); bytes = getBytes(bits, 8); value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(Double.POSITIVE_INFINITY, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals(ff.getBigInfinity(false), value); bits = Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY); bytes = getBytes(bits, 8); value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(Double.NEGATIVE_INFINITY, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals(ff.getBigInfinity(true), value); bits = Double.doubleToRawLongBits(0D); bytes = getBytes(bits, 8); value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(0D, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("0.0", ff.toDecimalString((BigFloat) value)); bits = Double.doubleToRawLongBits(1D); bytes = getBytes(bits, 8); value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(1D, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("1.0", ff.toDecimalString((BigFloat) value)); bits = Double.doubleToRawLongBits(-1D); bytes = getBytes(bits, 8); value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(-1D, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("-1.0", ff.toDecimalString((BigFloat) value)); bits = Double.doubleToRawLongBits(555.555D); bytes = getBytes(bits, 8); value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(555.555D, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("555.5549999999999", ff.toDecimalString((BigFloat) value, true)); bits = Double.doubleToRawLongBits(-555.555D); bytes = getBytes(bits, 8); value = - Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); - assertEquals(-555.555D, value); + Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10); + assertEquals("-555.5549999999999", ff.toDecimalString((BigFloat) value, true)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java index cd0f805b02..b789bcedaf 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java @@ -17,14 +17,16 @@ package ghidra.pcode.floatformat; import static org.junit.Assert.*; -import java.math.*; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Random; -import org.junit.*; +import org.junit.Assert; +import org.junit.Test; import generic.test.AbstractGenericTest; -public strictfp class FloatFormatTest extends AbstractGenericTest { +public class FloatFormatTest extends AbstractGenericTest { public FloatFormatTest() { super(); @@ -38,8 +40,8 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { continue; } FloatFormat.SmallFloatData data = FloatFormat.getSmallFloatData(x); - double y = FloatFormat.createFloat(data.sign < 0, - data.unscaled << (64 - data.fracbits - 1), data.scale); + double y = FloatFormat.createDouble(data.sign < 0, + data.unscaled << (64 - data.fracbits), data.scale); Assert.assertEquals("case #" + Integer.toString(i), x, y, 0); ++i; } @@ -203,7 +205,7 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { } @Test - public strictfp void testDoubleRoundAtMidpoint() { + public void testDoubleRoundAtMidpoint() { // test even and odd float significands at extremes assertDoubleMidpointRound(false, 1, 1); assertDoubleMidpointRound(false, 1, 2); @@ -230,7 +232,7 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { } @Test - public strictfp void testBigRoundAtMidpoint() { + public void testBigRoundAtMidpoint() { // test even and odd float significands at extremes assertBigMidpointRound(false, 1, 1); assertBigMidpointRound(false, 1, 2); @@ -265,39 +267,39 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigFloat big = ff.getBigFloat(f); BigInteger encoding = ff.getEncoding(big); Assert.assertEquals(intbits, encoding.longValue()); - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); f = 3.75f; intbits = Float.floatToRawIntBits(f); big = ff.getBigFloat(f); encoding = ff.getEncoding(big); Assert.assertEquals((intbits) & 0xffffffffL, encoding.longValue()); - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); f = -4.5f; intbits = Float.floatToRawIntBits(f); big = ff.getBigFloat(f); encoding = ff.getEncoding(big); Assert.assertEquals((intbits) & 0xffffffffL, encoding.longValue()); - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); f = Float.POSITIVE_INFINITY; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(ff.getBigFloat(f)); Assert.assertEquals(intbits, encoding.longValue()); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(encoding)); f = Float.NEGATIVE_INFINITY; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(ff.getBigFloat(f)); Assert.assertEquals((intbits) & 0xffffffffL, encoding.longValue()); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(encoding)); f = Float.NaN; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(ff.getBigFloat(f)); Assert.assertEquals(intbits, encoding.longValue()); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(encoding)); /// 64-bit encoding @@ -307,74 +309,79 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { big = ff.getBigFloat(d); encoding = ff.getEncoding(big); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); d = 3.75d; longbits = Double.doubleToRawLongBits(d); big = ff.getBigFloat(d); encoding = ff.getEncoding(big); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); d = -4.5d; longbits = Double.doubleToRawLongBits(d); big = ff.getBigFloat(d); encoding = ff.getEncoding(big); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); d = Double.POSITIVE_INFINITY; longbits = Double.doubleToRawLongBits(d); encoding = ff.getBigInfinityEncoding(false); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(encoding)); d = Double.NEGATIVE_INFINITY; longbits = Double.doubleToRawLongBits(d); encoding = ff.getBigInfinityEncoding(true); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(encoding)); d = Double.NaN; longbits = Double.doubleToRawLongBits(d); encoding = ff.getBigNaNEncoding(false); Assert.assertEquals(longbits, encoding.longValue()); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(encoding)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(encoding)); /// 80-bit encoding ff = new FloatFormat(10); + big = ff.getBigFloat(1.0); + encoding = ff.getEncoding(big); + // use round trip to verify + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); + big = ff.getBigFloat(4.5); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigFloat(3.75); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigFloat(-4.5); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigInfinity(false); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigInfinity(true); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigNaN(false); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); /// 128-bit encoding @@ -382,32 +389,32 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { big = ff.getBigFloat(4.5); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigFloat(3.75); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigFloat(-4.5); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigInfinity(false); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigInfinity(true); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); big = ff.getBigNaN(false); encoding = ff.getEncoding(big); // use round trip to verify - Assert.assertEquals(big, ff.getHostFloat(encoding)); + Assert.assertEquals(big, ff.decodeBigFloat(encoding)); } @@ -421,43 +428,43 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { int intbits = Float.floatToRawIntBits(f); long encoding = ff.getEncoding(f); Assert.assertEquals(intbits, encoding); - Assert.assertEquals(f, (float) ff.getHostFloat(encoding), 0); + Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); f = 8.908155E-39f; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(f); Assert.assertEquals((intbits) & 0xffffffffL, encoding); - Assert.assertEquals(f, (float) ff.getHostFloat(encoding), 0); + Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); f = 3.75f; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(f); Assert.assertEquals((intbits) & 0xffffffffL, encoding); - Assert.assertEquals(f, (float) ff.getHostFloat(encoding), 0); + Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); f = -4.5f; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(f); Assert.assertEquals((intbits) & 0xffffffffL, encoding); - Assert.assertEquals(f, (float) ff.getHostFloat(encoding), 0); + Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); f = Float.POSITIVE_INFINITY; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(f); Assert.assertEquals(intbits, encoding); - Assert.assertEquals(f, (float) ff.getHostFloat(encoding), 0); + Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); f = Float.NEGATIVE_INFINITY; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(f); Assert.assertEquals((intbits) & 0xffffffffL, encoding); - Assert.assertEquals(f, (float) ff.getHostFloat(encoding), 0); + Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); f = Float.NaN; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(f); Assert.assertEquals(intbits, encoding); - Assert.assertEquals(f, (float) ff.getHostFloat(encoding), 0); + Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); /// 64-bit encoding @@ -466,48 +473,48 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long longbits = Double.doubleToRawLongBits(d); encoding = ff.getEncoding(d); Assert.assertEquals(longbits, encoding); - Assert.assertEquals(d, ff.getHostFloat(encoding), 0); + Assert.assertEquals(d, ff.decodeHostFloat(encoding), 0); d = 3.75d; longbits = Double.doubleToRawLongBits(d); encoding = ff.getEncoding(d); Assert.assertEquals(longbits, encoding); - Assert.assertEquals(d, ff.getHostFloat(encoding), 0); + Assert.assertEquals(d, ff.decodeHostFloat(encoding), 0); d = -4.5d; longbits = Double.doubleToRawLongBits(d); encoding = ff.getEncoding(d); Assert.assertEquals(longbits, encoding); - Assert.assertEquals(d, ff.getHostFloat(encoding), 0); + Assert.assertEquals(d, ff.decodeHostFloat(encoding), 0); d = Double.POSITIVE_INFINITY; longbits = Double.doubleToRawLongBits(d); encoding = ff.getEncoding(d); Assert.assertEquals(longbits, encoding); - Assert.assertEquals(d, ff.getHostFloat(encoding), 0); + Assert.assertEquals(d, ff.decodeHostFloat(encoding), 0); d = Double.NEGATIVE_INFINITY; longbits = Double.doubleToRawLongBits(d); encoding = ff.getEncoding(d); Assert.assertEquals(longbits, encoding); - Assert.assertEquals(d, ff.getHostFloat(encoding), 0); + Assert.assertEquals(d, ff.decodeHostFloat(encoding), 0); d = Double.NaN; longbits = Double.doubleToRawLongBits(d); encoding = ff.getEncoding(d); Assert.assertEquals(longbits, encoding); - Assert.assertEquals(d, ff.getHostFloat(encoding), 0); + Assert.assertEquals(d, ff.decodeHostFloat(encoding), 0); } @Test - public strictfp void testBigFloatFloatFormatRandom() { + public void testBigFloatFloatFormatRandom() { Random rand = new Random(1); FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(4); for (int i = 0; i < 1000; ++i) { float f = rand.nextFloat(); BigInteger encoding0 = BigInteger.valueOf(Float.floatToRawIntBits(f)); - BigFloat bf1 = floatFormat.getHostFloat(encoding0); + BigFloat bf1 = floatFormat.decodeBigFloat(encoding0); BigFloat bf2 = FloatFormat.toBigFloat(f); assertEquals(bf1.toString(), bf2.toString()); BigInteger encoding1 = floatFormat.getEncoding(bf1); @@ -517,14 +524,14 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { } @Test - public strictfp void testBigFloatDoubleFormatRandom() { + public void testBigFloatDoubleFormatRandom() { Random rand = new Random(1); FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(8); for (int i = 0; i < 1000; ++i) { double f = rand.nextFloat(); BigInteger encoding0 = BigInteger.valueOf(Double.doubleToLongBits(f)); - BigFloat bf1 = floatFormat.getHostFloat(encoding0); + BigFloat bf1 = floatFormat.decodeBigFloat(encoding0); BigFloat bf2 = FloatFormat.toBigFloat(f); assertEquals(bf1.toString(), bf2.toString()); BigInteger encoding1 = floatFormat.getEncoding(bf1); @@ -743,32 +750,32 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(1.234); long b = ff.getEncoding(1.123); long result = ff.opAdd(a, b);// 1.234 + 1.123 - Assert.assertEquals(2.357, ff.getHostFloat(result), 0); + Assert.assertEquals(2.357, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-1.123); result = ff.opAdd(a, b);// -1.123 + 1.123 - Assert.assertEquals(0d, ff.getHostFloat(result), 0); + Assert.assertEquals(0d, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opAdd(a, b);// +INFINITY + 1.123 - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opAdd(a, b);// -INFINITY + 1.123 - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opAdd(a, b);// -INFINITY + -INFINITY - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opAdd(a, b);// -INFINITY + +INFINITY - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); b = ff.getEncoding(1.123); result = ff.opAdd(a, b);// NaN + 1.123 - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -778,32 +785,32 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(1.234d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.123d)); BigInteger result = ff.opAdd(a, b);// 1.234 + 1.123 - Assert.assertEquals(ff.getBigFloat(2.357), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.357), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-1.123d)); result = ff.opAdd(a, b);// -1.123 + 1.123 - Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = ff.opAdd(a, b);// +INFINITY + 1.123 - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opAdd(a, b);// -INFINITY + 1.123 - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(true); result = ff.opAdd(a, b);// -INFINITY + -INFINITY - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(false); result = ff.opAdd(a, b);// -INFINITY + +INFINITY - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); b = ff.getEncoding(ff.getBigFloat(1.123d)); result = ff.opAdd(a, b);// NaN + 1.123 - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -813,32 +820,32 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(1.5); long b = ff.getEncoding(1.25); long result = ff.opSub(a, b);// 1.5 - 1.25 - Assert.assertEquals(0.25, ff.getHostFloat(result), 0); + Assert.assertEquals(0.25, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-1.25); result = ff.opSub(a, b);// -1.25 - 1.25 - Assert.assertEquals(-2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opSub(a, b);// +INFINITY - 1.25 - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opSub(a, b);// -INFINITY - 1.25 - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opSub(a, b);// -INFINITY - -INFINITY - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opSub(a, b);// -INFINITY - +INFINITY - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); b = ff.getEncoding(1.25); result = ff.opSub(a, b);// NaN - 1.25 - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -848,32 +855,32 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.25d)); BigInteger result = ff.opSub(a, b);// 1.5 - 1.25 - Assert.assertEquals(ff.getBigFloat(0.25d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(0.25d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-1.25d)); result = ff.opSub(a, b);// -1.25 - 1.25 - Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = ff.opSub(a, b);// +INFINITY - 1.25 - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opSub(a, b);// -INFINITY - 1.25 - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(true); result = ff.opSub(a, b);// -INFINITY - -INFINITY - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(false); result = ff.opSub(a, b);// -INFINITY - +INFINITY - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); b = ff.getEncoding(ff.getBigFloat(1.25d)); result = ff.opSub(a, b);// NaN - 1.25 - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -883,19 +890,19 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(3.75); long b = ff.getEncoding(1.5); long result = ff.opDiv(a, b); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); b = ff.getEncoding(0); result = ff.opDiv(a, b); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-3.75); result = ff.opDiv(a, b); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NaN); result = ff.opDiv(a, b); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -905,19 +912,19 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(3.75d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = ff.opDiv(a, b); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); b = ff.getBigZeroEncoding(false); result = ff.opDiv(a, b); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-3.75d)); result = ff.opDiv(a, b); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigNaNEncoding(false); result = ff.opDiv(a, b); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -927,19 +934,19 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(2.5); long b = ff.getEncoding(1.5); long result = ff.opMult(a, b); - Assert.assertEquals(3.75, ff.getHostFloat(result), 0); + Assert.assertEquals(3.75, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opMult(a, b); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opMult(a, b); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); b = ff.getEncoding(Double.NaN); result = ff.opMult(a, b); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -949,19 +956,19 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger b = ff.getEncoding(ff.getBigFloat(1.5d)); BigInteger result = ff.opMult(a, b); - Assert.assertEquals(ff.getBigFloat(3.75d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.75d), ff.decodeBigFloat(result)); b = ff.getBigInfinityEncoding(false); result = ff.opMult(a, b); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opMult(a, b); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); b = ff.getBigNaNEncoding(false); result = ff.opMult(a, b); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -970,23 +977,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(2.5); long result = ff.opNeg(a); - Assert.assertEquals(-2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = ff.opNeg(a); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opNeg(a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opNeg(a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = ff.opNeg(a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -995,23 +1002,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opNeg(a); - Assert.assertEquals(ff.getBigFloat(-2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.5d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opNeg(a); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = ff.opNeg(a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opNeg(a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = ff.opNeg(a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -1020,23 +1027,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(2.5); long result = ff.opAbs(a); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = ff.opAbs(a); - Assert.assertEquals(2.5, ff.getHostFloat(result), 0); + Assert.assertEquals(2.5, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opAbs(a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opAbs(a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = ff.opAbs(a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -1045,23 +1052,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opAbs(a); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opAbs(a); - Assert.assertEquals(ff.getBigFloat(2.5d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.5d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = ff.opAbs(a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opAbs(a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = ff.opAbs(a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -1069,8 +1076,8 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { FloatFormat ff = new FloatFormat(8); long longbits = ff.getEncoding(2.0); longbits = ff.opSqrt(longbits); - double d = ff.getHostFloat(longbits); - Assert.assertEquals("1.414213562373095", Double.toString(d).substring(0, 17)); + double d = ff.decodeHostFloat(longbits); + Assert.assertEquals("1.4142135623730951", Double.toString(d)); } @Test @@ -1079,7 +1086,7 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigFloat big = ff.getBigFloat(2.0); BigInteger encoding = ff.getEncoding(big); encoding = ff.opSqrt(encoding); - BigFloat result = ff.getHostFloat(encoding); + BigFloat result = ff.decodeBigFloat(encoding); Assert.assertEquals("1.414213562373095", ff.round(result).toString()); } @@ -1089,15 +1096,15 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long result = ff.opInt2Float(2, 4); Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used - Assert.assertEquals(2.0d, ff.getHostFloat(result), 0); + Assert.assertEquals(2.0d, ff.decodeHostFloat(result), 0); result = ff.opInt2Float(-2, 4); Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used - Assert.assertEquals(-2.0d, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0d, ff.decodeHostFloat(result), 0); result = ff.opInt2Float(0, 4); Assert.assertEquals(0, result & 0xffffffff00000000L);// verify that only 4-bytes are used - Assert.assertEquals(0d, ff.getHostFloat(result), 0); + Assert.assertEquals(0d, ff.decodeHostFloat(result), 0); } @Test @@ -1108,15 +1115,15 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger result = ff.opInt2Float(BigInteger.valueOf(2), 4, true); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.decodeBigFloat(result)); result = ff.opInt2Float(BigInteger.valueOf(-2), 4, true); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); result = ff.opInt2Float(BigInteger.ZERO, 4, true); assertTrue(result.compareTo(limit) < 0);// verify that only 4-bytes are used - Assert.assertEquals(ff.getBigZero(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigZero(false), ff.decodeBigFloat(result)); } @Test @@ -1157,23 +1164,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff4.getEncoding(1.75); long result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(1.75, ff8.getHostFloat(result), 0); + Assert.assertEquals(1.75, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(-1.75); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(-1.75, ff8.getHostFloat(result), 0); + Assert.assertEquals(-1.75, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(Float.POSITIVE_INFINITY); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff8.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(Float.NEGATIVE_INFINITY); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff8.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff8.decodeHostFloat(result), 0); a = ff4.getEncoding(Float.NaN); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(Double.NaN, ff8.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff8.decodeHostFloat(result), 0); } @@ -1184,23 +1191,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff4.getEncoding(ff4.getBigFloat(1.75d)); BigInteger result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(ff8.getBigFloat(1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(1.75d), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigFloat(-1.75d)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(ff8.getBigFloat(-1.75d), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigFloat(-1.75d), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigInfinity(false)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(ff8.getBigInfinity(false), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(false), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigInfinity(true)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(ff8.getBigInfinity(true), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigInfinity(true), ff8.decodeBigFloat(result)); a = ff4.getEncoding(ff4.getBigNaN(false)); result = ff4.opFloat2Float(a, ff8); - Assert.assertEquals(ff8.getBigNaN(false), ff8.getHostFloat(result)); + Assert.assertEquals(ff8.getBigNaN(false), ff8.decodeBigFloat(result)); } @Test @@ -1261,23 +1268,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(2.5); long result = ff.opCeil(a); - Assert.assertEquals(3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = ff.opCeil(a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opCeil(a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opCeil(a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = ff.opCeil(a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -1286,23 +1293,23 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opCeil(a); - Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opCeil(a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = ff.opCeil(a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opCeil(a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = ff.opCeil(a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -1311,27 +1318,27 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(2.5); long result = ff.opFloor(a); - Assert.assertEquals(2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.0); result = ff.opFloor(a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = ff.opFloor(a); - Assert.assertEquals(-3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opFloor(a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opFloor(a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = ff.opFloor(a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -1340,27 +1347,27 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opFloor(a); - Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.0d)); result = ff.opFloor(a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opFloor(a); - Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = ff.opFloor(a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opFloor(a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = ff.opFloor(a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } @Test @@ -1369,39 +1376,39 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { long a = ff.getEncoding(2.5); long result = ff.opRound(a); - Assert.assertEquals(3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(2.25); result = ff.opRound(a); - Assert.assertEquals(2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(2.75); result = ff.opRound(a); - Assert.assertEquals(3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.5); result = ff.opRound(a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.25); result = ff.opRound(a); - Assert.assertEquals(-2.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-2.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(-2.75); result = ff.opRound(a); - Assert.assertEquals(-3.0, ff.getHostFloat(result), 0); + Assert.assertEquals(-3.0, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.POSITIVE_INFINITY); result = ff.opRound(a); - Assert.assertEquals(Double.POSITIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.POSITIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NEGATIVE_INFINITY); result = ff.opRound(a); - Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NEGATIVE_INFINITY, ff.decodeHostFloat(result), 0); a = ff.getEncoding(Double.NaN); result = ff.opRound(a); - Assert.assertEquals(Double.NaN, ff.getHostFloat(result), 0); + Assert.assertEquals(Double.NaN, ff.decodeHostFloat(result), 0); } @Test @@ -1410,39 +1417,237 @@ public strictfp class FloatFormatTest extends AbstractGenericTest { BigInteger a = ff.getEncoding(ff.getBigFloat(2.5d)); BigInteger result = ff.opRound(a); - Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(2.25d)); result = ff.opRound(a); - Assert.assertEquals(ff.getBigFloat(2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(2.75d)); result = ff.opRound(a); - Assert.assertEquals(ff.getBigFloat(3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(3.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.5d)); result = ff.opRound(a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.25d)); result = ff.opRound(a); - Assert.assertEquals(ff.getBigFloat(-2.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-2.0d), ff.decodeBigFloat(result)); a = ff.getEncoding(ff.getBigFloat(-2.75d)); result = ff.opRound(a); - Assert.assertEquals(ff.getBigFloat(-3.0d), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigFloat(-3.0d), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(false); result = ff.opRound(a); - Assert.assertEquals(ff.getBigInfinity(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(false), ff.decodeBigFloat(result)); a = ff.getBigInfinityEncoding(true); result = ff.opRound(a); - Assert.assertEquals(ff.getBigInfinity(true), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigInfinity(true), ff.decodeBigFloat(result)); a = ff.getBigNaNEncoding(false); result = ff.opRound(a); - Assert.assertEquals(ff.getBigNaN(false), ff.getHostFloat(result)); + Assert.assertEquals(ff.getBigNaN(false), ff.decodeBigFloat(result)); } + private void doTestValueOfBigInteger(BigDecimal bdVal) { + FloatFormat ff = FloatFormatFactory.getFloatFormat(8); + bdVal = bdVal.round(ff.getDisplayContext()); + BigInteger biVal = bdVal.toBigInteger(); + BigFloat f = ff.getBigFloat(biVal); + BigDecimal bd = ff.round(f); + assertEquals(biVal, bd.toBigInteger()); + assertEquals(bdVal, bd); + } + + @Test + public void testValueOfBigInteger() { + FloatFormat ff = FloatFormatFactory.getFloatFormat(8); + assertEquals("0.0", ff.toDecimalString(ff.getBigFloat(BigInteger.ZERO))); + assertEquals("1.0", ff.toDecimalString(ff.getBigFloat(BigInteger.ONE))); + assertEquals("2.0", ff.toDecimalString(ff.getBigFloat(BigInteger.TWO))); + assertEquals("-1.0", ff.toDecimalString(ff.getBigFloat(BigInteger.ONE.negate()))); + assertEquals("-2.0", ff.toDecimalString(ff.getBigFloat(BigInteger.TWO.negate()))); + + doTestValueOfBigInteger(BigDecimal.valueOf(2.1234567890123456789e123)); + doTestValueOfBigInteger(BigDecimal.valueOf(2.1234567890123456789e123).negate()); + + // NOTE: BigDecimal.valueOf(Double.MAX_VALUE) produces a value greater than Double.MAX_VALUE + // doTestValueOfBigInteger(BigDecimal.valueOf(Double.MAX_VALUE)); + + + BigFloat bf = ff.decodeBigFloat(Double.doubleToRawLongBits(Double.MAX_VALUE)); + bf = ff.getBigFloat(bf.toBigInteger()); + assertEquals("1.797693134862316E+308", ff.toDecimalString(bf)); + + // step just beyond Double.MAX_VALUE - still decodes the same + BigDecimal maxBd = BigDecimal.valueOf(Double.MAX_VALUE); + BigInteger v = + BigDecimal.valueOf(maxBd.unscaledValue().longValue() + 1, maxBd.scale()).toBigInteger(); + BigFloat f = ff.getBigFloat(v); + assertEquals("1.797693134862316E+308", ff.toDecimalString(f, true)); + + // step far beyond Double.MAX_VALUE + v = BigDecimal.valueOf(1, -309).toBigInteger(); + f = ff.getBigFloat(v); + assertEquals("+Infinity", ff.toDecimalString(f, true)); + } + + private void doTestValueOfBigDecimal(BigDecimal v) { + doTestValueOfBigDecimal(v, null); + } + + private void doTestValueOfBigDecimal(BigDecimal v, String expect) { + FloatFormat ff = FloatFormatFactory.getFloatFormat(8); + if (expect == null) { + expect = v.round(ff.getDisplayContext()).toString(); + if (expect.indexOf('.') < 0) { + expect += ".0"; + } + } + BigFloat bf = ff.getBigFloat(v); + + assertEquals(expect, ff.toDecimalString(bf, true)); + + String encExpect = FloatFormat.toBinaryString(v.doubleValue()); + String enc = ff.toBinaryString(bf); + if (!encExpect.equals(enc)) { + System.out.println("Unexpected encoding: " + enc + + "\nExpected encoding: " + encExpect); + fail("Unexpected encoding"); + } + } + + @Test + public void testValueOfBigDecimal() { + + doTestValueOfBigDecimal(BigDecimal.valueOf(0)); + doTestValueOfBigDecimal(BigDecimal.valueOf(1)); + doTestValueOfBigDecimal(BigDecimal.valueOf(2)); + doTestValueOfBigDecimal(BigDecimal.valueOf(2.123456789)); + doTestValueOfBigDecimal(BigDecimal.valueOf(2.1234567890123456789)); + doTestValueOfBigDecimal(BigDecimal.valueOf(2.1234567890123456789E+123)); + doTestValueOfBigDecimal(BigDecimal.valueOf(-1)); + doTestValueOfBigDecimal(BigDecimal.valueOf(-2)); + doTestValueOfBigDecimal(BigDecimal.valueOf(-2.123456789)); + doTestValueOfBigDecimal(BigDecimal.valueOf(-2.1234567890123456789)); + doTestValueOfBigDecimal(BigDecimal.valueOf(-2.1234567890123456789E+123)); + + // Java appears to exceed IEEE 754 decimal precision of 16 by producing + // "1.7976931348623157E+308" + + doTestValueOfBigDecimal(BigDecimal.valueOf(Double.MAX_VALUE)); + + doTestValueOfBigDecimal(BigDecimal.valueOf(2.1234567890123456789E-123)); + doTestValueOfBigDecimal(BigDecimal.valueOf(-2.1234567890123456789E-123)); + + // NOTE: Java Double.MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324 + // corresponds to the minimum subnormal decoded value of the raw representation. + // The value 4.9e-324 is the shortest compact representation which retains the same + // encoded value. + + doTestValueOfBigDecimal(BigDecimal.valueOf(Double.MIN_VALUE)); + + // step just beyond Double.MAX_VALUE - still decodes the same + + FloatFormat ff = FloatFormatFactory.getFloatFormat(8); + + BigDecimal maxBd = BigDecimal.valueOf(Double.MAX_VALUE); + BigDecimal v = new BigDecimal(maxBd.unscaledValue().add(BigInteger.ONE), maxBd.scale()); + BigFloat f = ff.getBigFloat(v); + assertEquals(BigDecimal.valueOf(Double.MAX_VALUE).round(ff.getDisplayContext()).toString(), + ff.toDecimalString(f, true)); + + // step far beyond Double.MAX_VALUE + v = new BigDecimal(maxBd.unscaledValue(), maxBd.scale() * 2); + f = ff.getBigFloat(v); + assertEquals("+Infinity", ff.toDecimalString(f)); + + // step just beyond Double.MIN_VALUE - still decodes the same + BigDecimal minBd = BigDecimal.valueOf(Double.MIN_VALUE); + v = new BigDecimal(minBd.unscaledValue().add(BigInteger.ONE), minBd.scale()); + f = ff.getBigFloat(v); + assertEquals(BigDecimal.valueOf(Double.MIN_VALUE).round(ff.getDisplayContext()).toString(), + ff.toDecimalString(f, true)); + + // step far beyond Double.MIN_VALUE + v = new BigDecimal(minBd.unscaledValue(), minBd.scale() * 2); + f = ff.getBigFloat(v); + assertEquals("0.0", ff.toDecimalString(f)); + + } + + private void doTestValueOfDecimalString(String str) { + doTestValueOfDecimalString(str, null); + } + + private void doTestValueOfDecimalString(String str, String expect) { + // str should be expected if "expect" not specified + FloatFormat ff = FloatFormatFactory.getFloatFormat(8); + if (expect == null) { + // perform double-double conversion + BigFloat bf = ff.decodeBigFloat(Double.doubleToRawLongBits(Double.valueOf(str))); + expect = ff.toDecimalString(bf); // done to ensure consistent non-compact formatting + } + BigFloat f = ff.getBigFloat(str); + assertEquals(expect, ff.toDecimalString(f)); + } + + @Test + public void testValueOfDecimalString() { + + doTestValueOfDecimalString("0"); + doTestValueOfDecimalString("1"); + doTestValueOfDecimalString("2"); + doTestValueOfDecimalString("3.141592653589793238462643"); + doTestValueOfDecimalString("2.123456789"); + doTestValueOfDecimalString("2.1234567890123456789"); + doTestValueOfDecimalString("2.1234567890123456789E+123"); + doTestValueOfDecimalString("-1"); + doTestValueOfDecimalString("-2"); + doTestValueOfDecimalString("-2.123456789"); + doTestValueOfDecimalString("-2.1234567890123456789"); + doTestValueOfDecimalString("-2.1234567890123456789E+123"); + + doTestValueOfDecimalString(BigDecimal.valueOf(Double.MAX_VALUE).toString()); + + // NOTE: compensated for minor precision issue + doTestValueOfDecimalString("2.1234567890123456789E-123"); + doTestValueOfDecimalString("-2.1234567890123456789E-123"); + + doTestValueOfDecimalString(BigDecimal.valueOf(Double.MIN_VALUE).toString()); + + // step just beyond Double.MAX_VALUE + doTestValueOfDecimalString("1.7976931348623159E+308", "+Infinity"); + + // step far beyond Double.MAX_VALUE + doTestValueOfDecimalString("2.2e350", "+Infinity"); + + // step just beyond Double.MIN_VALUE - still decodes the same + doTestValueOfDecimalString("4.98e-324"); + + // step far beyond Double.MIN_VALUE + doTestValueOfDecimalString("5.1e-350"); + + } + + @Test + public void testDoubleDecodeWithToString() { + FloatFormat ff = FloatFormatFactory.getFloatFormat(8); + assertEquals("9.346009625593543E-307", + ff.toDecimalString(ff.decodeBigFloat(0x0065006700610050L))); + assertEquals("2.123456789012346", + ff.toDecimalString(ff.decodeBigFloat(0x4000FCD6E9BA37B3L))); + assertEquals("0.3", + ff.toDecimalString(ff.decodeBigFloat(0x3FD3333333333333L))); + } + + @Test + public void testFloatDecodeWithToString() { + FloatFormat ff = FloatFormatFactory.getFloatFormat(4); + assertEquals("-1.4682312", + ff.toDecimalString(ff.decodeBigFloat(0xbfbbef00L), true)); + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java deleted file mode 100644 index 2eb5822b08..0000000000 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float10DataTypeTest.java +++ /dev/null @@ -1,89 +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.program.model.data; - -import java.math.*; - -import org.junit.Assert; -import org.junit.Test; - -import generic.test.AbstractGTest; -import ghidra.pcode.floatformat.FloatFormat; -import ghidra.program.model.mem.ByteMemBufferImpl; - -public class Float10DataTypeTest extends AbstractGTest { - - @Test - public void testGetValue() { - - byte[] bytes = bytes(0x7f, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0x7fff0000000000000000 = +infinity - Object value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, value); - - bytes = bytes(0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0xffff0000000000000000 = -infinity - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, value); - - bytes = bytes(0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7fff8000000000000000 = NaN - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals(FloatFormat.BIG_NaN, value); - - // Really small values - - MathContext mc = new MathContext(18, RoundingMode.UP); - - bytes = bytes(0, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x00018000000000000000 = approaches 0 - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("5.04315471466814026E-4932", ((BigDecimal) value).round(mc).toString()); - - bytes = bytes(0x80, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x00018000000000000000 = approaches 0 - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("-5.04315471466814026E-4932", - ((BigDecimal) value).round(mc).toString()); - - // Really big values - - bytes = bytes(0x7f, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7ffe8000000000000000 = approaches +infinity - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("8.92298621517923824E+4931", ((BigDecimal) value).round(mc).toString()); - - bytes = bytes(0xff, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7ffe8000000000000000 = approaches -infinity - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals("-8.92298621517923824E+4931", - ((BigDecimal) value).round(mc).toString()); - - // Values within the range of Double - - bytes = bytes(0x40, 1, 0x20, 0, 0, 0, 0, 0, 0, 0); // 0x40002000000000000000 = approaches -infinity - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals(BigDecimal.valueOf(4.5), ((BigDecimal) value).stripTrailingZeros()); - - bytes = bytes(0xc0, 1, 0x20, 0, 0, 0, 0, 0, 0, 0); // 0x40002000000000000000 = approaches -infinity - value = - Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); - Assert.assertEquals(BigDecimal.valueOf(-4.5), ((BigDecimal) value).stripTrailingZeros()); - - } - -} diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float80DataTypeTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float80DataTypeTest.java new file mode 100644 index 0000000000..1d3540c72a --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/Float80DataTypeTest.java @@ -0,0 +1,160 @@ +/* ### + * 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.data; + +import static org.junit.Assert.*; + +import org.junit.Assert; +import org.junit.Test; + +import generic.test.AbstractGTest; +import ghidra.pcode.floatformat.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.floats.Float80DataType; +import ghidra.program.model.mem.ByteMemBufferImpl; +import ghidra.program.model.mem.MemBuffer; + +public class Float80DataTypeTest extends AbstractGTest { + + @Test + public void testGetValue() { + + FloatFormat ff = FloatFormatFactory.getFloatFormat(10); + + byte[] bytes = bytes(0x7f, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0x7fff0000000000000000 = +infinity + BigFloat value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals(ff.getBigInfinity(false), value); + Assert.assertEquals("+Infinity", ff.toDecimalString(value, true)); + + bytes = bytes(0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0xffff0000000000000000 = -infinity + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals(ff.getBigInfinity(true), value); + Assert.assertEquals("-Infinity", ff.toDecimalString(value, true)); + + bytes = bytes(0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7fff8000000000000000 = NaN + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals(ff.getBigNaN(false), value); + Assert.assertEquals("NaN", ff.toDecimalString(value, true)); + + // small values + // initially produced by gcc for little-edian then byte-reversed here + + bytes = bytes(0x3c, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals("2.22507385850720138E-308", + ff.toDecimalString(value, true)); + + bytes = bytes(0xbc, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals("-2.22507385850720138E-308", + ff.toDecimalString(value, true)); + + // Really small values - subnormal minimum for decode only - approaches zero + + bytes = bytes(0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + assertEquals(ff.minValue, value); + Assert.assertEquals("3.6E-4951", ff.toDecimalString(value, true)); + + bytes = bytes(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 1); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals("-3.6E-4951", ff.toDecimalString(value, true)); + + // Really big values maximum - approaches -infinity + + bytes = bytes(0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + assertEquals(ff.maxValue, value); + Assert.assertEquals("1.18973149535723177E+4932", ff.toDecimalString(value, true)); + + bytes = bytes(0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals("-1.18973149535723177E+4932", ff.toDecimalString(value, true)); + + // Values within the range of Double + + // pi - 3.14159265358979323 + // initially produced by gcc for little-edian then byte-reversed here + + bytes = bytes(0x40, 0, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc0, 0); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals("3.14159265358979312", ff.toDecimalString(value, true)); + + bytes = bytes(0xc0, 0, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc0, 0); + value = + Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); + Assert.assertEquals("-3.14159265358979312", ff.toDecimalString(value, true)); + + } + + private static MemBuffer buf(boolean bigEndian, int... vals) { + return new ByteMemBufferImpl(Address.NO_ADDRESS, bytes(vals), bigEndian); + } + + private static final MemBuffer BE = buf(true, 0); + + @Test + public void testEncodeValue() throws Exception { + + FloatFormat ff = FloatFormatFactory.getFloatFormat(10); + + byte[] bytes = bytes(0x7f, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0x7fff0000000000000000 = +infinity + assertArrayEquals(bytes, + Float80DataType.dataType.encodeValue(ff.getBigFloat("+Infinity"), BE, null, -1)); + + bytes = bytes(0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0xffff0000000000000000 = -infinity + assertArrayEquals(bytes, + Float80DataType.dataType.encodeValue(ff.getBigFloat("-Infinity"), BE, null, -1)); + + bytes = bytes(0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7fff8000000000000000 = NaN + assertArrayEquals(bytes, + Float80DataType.dataType.encodeValue(ff.getBigFloat("NaN"), BE, null, -1)); + + // NOTE: Multiple byte[] values can render the same decimal string + + bytes = Float80DataType.dataType + .encodeValue(ff.getBigFloat("5.04315471466814026E-4932"), BE, null, -1); + assertEquals("5.04315471466814026E-4932", Float80DataType.dataType + .getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1)); + + bytes = Float80DataType.dataType.encodeValue(ff.getBigFloat("-5.04315471466814026E-4932"), + BE, null, -1); + assertEquals("-5.04315471466814026E-4932", Float80DataType.dataType + .getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1)); + + bytes = Float80DataType.dataType + .encodeValue(ff.getBigFloat("8.92298621517923824E+4931"), BE, null, -1); + assertEquals("8.92298621517923824E+4931", Float80DataType.dataType + .getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1)); + + bytes = Float80DataType.dataType.encodeValue(ff.getBigFloat("-8.92298621517923824E+4931"), + BE, null, -1); + assertEquals("-8.92298621517923824E+4931", Float80DataType.dataType + .getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1)); + + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/StubDataType.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/StubDataType.java index 4a803fa912..0db346441c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/StubDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/StubDataType.java @@ -134,6 +134,11 @@ public class StubDataType implements DataType { throw new UnsupportedOperationException(); } + @Override + public int getAlignedLength() { + throw new UnsupportedOperationException(); + } + @Override public boolean isZeroLength() { throw new UnsupportedOperationException(); diff --git a/Ghidra/Processors/68000/data/languages/68000.cspec b/Ghidra/Processors/68000/data/languages/68000.cspec index 1a4e77c522..fe7c760943 100644 --- a/Ghidra/Processors/68000/data/languages/68000.cspec +++ b/Ghidra/Processors/68000/data/languages/68000.cspec @@ -14,7 +14,7 @@ - + diff --git a/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec b/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec index eb803c488e..7b7ca23010 100644 --- a/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec +++ b/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec @@ -2,7 +2,6 @@ - @@ -14,12 +13,13 @@ - + + diff --git a/Ghidra/Processors/x86/data/languages/x86borland.cspec b/Ghidra/Processors/x86/data/languages/x86borland.cspec index 55213bc79f..c17bca6962 100644 --- a/Ghidra/Processors/x86/data/languages/x86borland.cspec +++ b/Ghidra/Processors/x86/data/languages/x86borland.cspec @@ -14,7 +14,7 @@ - + diff --git a/Ghidra/Processors/x86/data/languages/x86delphi.cspec b/Ghidra/Processors/x86/data/languages/x86delphi.cspec index 1700e2d78e..8f0424825d 100644 --- a/Ghidra/Processors/x86/data/languages/x86delphi.cspec +++ b/Ghidra/Processors/x86/data/languages/x86delphi.cspec @@ -1,27 +1,6 @@ - @@ -117,35 +96,4 @@ - - diff --git a/Ghidra/Processors/x86/data/languages/x86gcc.cspec b/Ghidra/Processors/x86/data/languages/x86gcc.cspec index dd3254b923..bcd049d2d2 100644 --- a/Ghidra/Processors/x86/data/languages/x86gcc.cspec +++ b/Ghidra/Processors/x86/data/languages/x86gcc.cspec @@ -2,7 +2,6 @@ - @@ -14,12 +13,13 @@ - + +