Merge remote-tracking branch 'origin/GP-3190_dev747368_remove_numberutils'

This commit is contained in:
Ryan Kurtz 2023-03-22 11:25:08 -04:00
commit 3da82f9ff9
7 changed files with 89 additions and 230 deletions

View file

@ -29,7 +29,6 @@ import ghidra.app.util.bin.format.dwarf4.encoding.*;
import ghidra.app.util.bin.format.dwarf4.expression.*;
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
import ghidra.util.Msg;
import ghidra.util.NumberUtil;
/**
* DIEAggregate groups related {@link DebugInfoEntry} records together in a single interface
@ -487,14 +486,13 @@ public class DIEAggregate {
}
DWARFAttributeValue attr = attrInfo.attr;
if (attr instanceof DWARFNumericAttribute) {
return assertValidInt(((DWARFNumericAttribute) attr).getValue());
if (attr instanceof DWARFNumericAttribute dnum) {
return assertValidInt(dnum.getValue());
}
else if (attr instanceof DWARFBlobAttribute) {
byte[] exprBytes = ((DWARFBlobAttribute) attr).getBytes();
else if (attr instanceof DWARFBlobAttribute dblob) {
byte[] exprBytes = dblob.getBytes();
DWARFExpressionEvaluator evaluator = DWARFExpressionEvaluator.create(getHeadFragment());
ghidra.app.util.bin.format.dwarf4.expression.DWARFExpression expr =
evaluator.readExpr(exprBytes);
DWARFExpression expr = evaluator.readExpr(exprBytes);
evaluator.evaluate(expr, 0);
return assertValidInt(evaluator.pop());
@ -523,11 +521,11 @@ public class DIEAggregate {
}
DWARFAttributeValue attr = attrInfo.attr;
if (attr instanceof DWARFNumericAttribute) {
return ((DWARFNumericAttribute) attr).getUnsignedValue();
if (attr instanceof DWARFNumericAttribute dnum) {
return dnum.getUnsignedValue();
}
else if (attr instanceof DWARFBlobAttribute) {
byte[] exprBytes = ((DWARFBlobAttribute) attr).getBytes();
else if (attr instanceof DWARFBlobAttribute dblob) {
byte[] exprBytes = dblob.getBytes();
DWARFExpressionEvaluator evaluator = DWARFExpressionEvaluator.create(getHeadFragment());
DWARFExpression expr = evaluator.readExpr(exprBytes);
@ -573,14 +571,13 @@ public class DIEAggregate {
}
DWARFAttributeValue attr = attrInfo.attr;
if (attr instanceof DWARFNumericAttribute) {
return assertValidUInt(((DWARFNumericAttribute) attr).getUnsignedValue());
if (attr instanceof DWARFNumericAttribute dnum) {
return assertValidUInt(dnum.getUnsignedValue());
}
else if (attr instanceof DWARFBlobAttribute) {
byte[] exprBytes = ((DWARFBlobAttribute) attr).getBytes();
else if (attr instanceof DWARFBlobAttribute dblob) {
byte[] exprBytes = dblob.getBytes();
DWARFExpressionEvaluator evaluator = DWARFExpressionEvaluator.create(getHeadFragment());
ghidra.app.util.bin.format.dwarf4.expression.DWARFExpression expr =
evaluator.readExpr(exprBytes);
DWARFExpression expr = evaluator.readExpr(exprBytes);
// DW_AT_data_member_location expects the address of the containing object
// to be on the stack before evaluation starts. We don't have that so we
@ -609,13 +606,13 @@ public class DIEAggregate {
public List<DWARFLocation> getAsLocation(int attribute) throws IOException {
AttrInfo attrInfo = findAttribute(attribute);
if (attrInfo == null) {
return Collections.EMPTY_LIST;
return List.of();
}
else if (attrInfo.attr instanceof DWARFNumericAttribute) {
return readDebugLocList(((DWARFNumericAttribute) attrInfo.attr).getUnsignedValue());
else if (attrInfo.attr instanceof DWARFNumericAttribute dnum) {
return readDebugLocList(dnum.getUnsignedValue());
}
else if (attrInfo.attr instanceof DWARFBlobAttribute) {
return _exprBytesAsLocation((DWARFBlobAttribute) attrInfo.attr);
else if (attrInfo.attr instanceof DWARFBlobAttribute dblob) {
return _exprBytesAsLocation(dblob);
}
else {
throw new UnsupportedOperationException(
@ -643,6 +640,10 @@ public class DIEAggregate {
/**
* Return a list of DWARF locations read from the debug_loc section.
* <p>
* The deserialization done here is very similar to {@link #parseDebugRange(int)}, but in this
* case also contains a blob payload per location.
*
* @param offset offset into the debug_loc section
* @return list of DWARF locations (address range and location expression)
* @throws IOException if an I/O error occurs
@ -650,9 +651,9 @@ public class DIEAggregate {
private List<DWARFLocation> readDebugLocList(long offset) throws IOException {
BinaryReader debug_loc = getCompilationUnit().getProgram().getDebugLocation();
List<DWARFLocation> ranges = new ArrayList<>();
List<DWARFLocation> results = new ArrayList<>();
if (debug_loc == null) {
return ranges;
return results;
}
debug_loc.setPointerIndex(offset);
@ -666,22 +667,22 @@ public class DIEAggregate {
// Loop through the debug_loc entry
while (debug_loc.getPointerIndex() < debug_loc.length()) {
Number beginning = DWARFUtil.readAddress(debug_loc, pointerSize);
Number ending = DWARFUtil.readAddress(debug_loc, pointerSize);
long beginning = DWARFUtil.readAddressAsLong(debug_loc, pointerSize);
long ending = DWARFUtil.readAddressAsLong(debug_loc, pointerSize);
// List end
if (beginning.longValue() == 0 && ending.longValue() == 0) {
if (beginning == 0 && ending == 0) {
break;
}
// Check to see if this is a base address entry
if (NumberUtil.equalsMaxUnsignedValue(beginning)) {
baseAddressOffset = ending.longValue();
if (beginning == -1) {
baseAddressOffset = ending;
continue;
}
// Size is 2 bytes
int size = debug_loc.readNextShort() & NumberUtil.UNSIGNED_SHORT_MASK;
int size = debug_loc.readNextUnsignedShort();
// Read the location description
byte[] location = debug_loc.readNextByteArray(size);
@ -690,19 +691,19 @@ public class DIEAggregate {
// greater-than the compunit's lowpc. This indicates the 'offset' isn't
// an offset, but already an absolute value. This occurs in some
// gcc dwarf compilation flag combinations.
boolean isBadOffset = (beginning.longValue() > cuBase);
boolean isBadOffset = (beginning > cuBase);
long absStart = beginning.longValue();
long absEnd = ending.longValue();
long absStart = beginning;
long absEnd = ending;
if (!isBadOffset) {
absStart += baseAddressOffset;
absEnd += baseAddressOffset;
}
// TODO: verify end addr calc with DWARFstd.pdf, inclusive vs exclusive
ranges.add(new DWARFLocation(new DWARFRange(absStart, absEnd + 1), location));
results.add(new DWARFLocation(new DWARFRange(absStart, absEnd + 1), location));
}
return ranges;
return results;
}
private List<DWARFLocation> _exprBytesAsLocation(DWARFBlobAttribute attr) {
@ -844,30 +845,29 @@ public class DIEAggregate {
reader.setPointerIndex(offset);
List<DWARFRange> ranges = new ArrayList<>();
long baseAddress = getCompilationUnit().getCompileUnit() != null &&
getCompilationUnit().getCompileUnit().getLowPC() != null
? getCompilationUnit().getCompileUnit().getLowPC().longValue()
DWARFCompileUnit dcu = getCompilationUnit().getCompileUnit();
long baseAddress = dcu != null && dcu.getLowPC() != null
? dcu.getLowPC().longValue()
: 0L;
while (reader.hasNext()) {
// Read the beginning and ending addresses
Number beginning = DWARFUtil.readAddress(reader, pointerSize);
Number ending = DWARFUtil.readAddress(reader, pointerSize); // dwarf end addrs are exclusive
long beginning = DWARFUtil.readAddressAsLong(reader, pointerSize);
long ending = DWARFUtil.readAddressAsLong(reader, pointerSize); // dwarf end addrs are exclusive
// End of the list
if (beginning.longValue() == 0 && ending.longValue() == 0) {
if (beginning == 0 && ending == 0) {
break;
}
// Check to see if this is a base address entry
if (NumberUtil.equalsMaxUnsignedValue(beginning)) {
baseAddress = ending.longValue();
if (beginning == -1) {
baseAddress = ending;
continue;
}
// Add the range to the list
ranges.add(new DWARFRange(baseAddress + beginning.longValue(),
baseAddress + ending.longValue()));
ranges.add(new DWARFRange(baseAddress + beginning, baseAddress + ending));
}
Collections.sort(ranges);
return ranges;
@ -896,9 +896,7 @@ public class DIEAggregate {
*/
public long getHighPC() throws IOException {
AttrInfo high = findAttribute(DWARFAttribute.DW_AT_high_pc);
if (high != null && high.attr instanceof DWARFNumericAttribute) {
DWARFNumericAttribute highVal = (DWARFNumericAttribute) high.attr;
if (high != null && high.attr instanceof DWARFNumericAttribute highVal) {
// if the DWARF attr was a DW_FORM_addr, it doesn't need fixing up
if (high.form == DWARFForm.DW_FORM_addr) {
return highVal.getUnsignedValue() + getProgram().getProgramBaseAddressFixup() - 1;
@ -935,11 +933,11 @@ public class DIEAggregate {
AttrInfo low = findAttribute(DWARFAttribute.DW_AT_low_pc);
AttrInfo high = findAttribute(DWARFAttribute.DW_AT_high_pc);
if (low != null && high != null && low.form == high.form &&
low.attr instanceof DWARFNumericAttribute &&
high.attr instanceof DWARFNumericAttribute) {
DWARFNumericAttribute lowVal = (DWARFNumericAttribute) low.attr;
DWARFNumericAttribute highVal = (DWARFNumericAttribute) high.attr;
low.attr instanceof DWARFNumericAttribute lowVal &&
high.attr instanceof DWARFNumericAttribute highVal) {
return lowVal.getValue() == highVal.getValue();
}
return false;
}

View file

@ -519,29 +519,6 @@ public class DWARFUtil {
throw new IOException("Unsupported variable-sized int: " + size);
}
/**
* Read the value of an address.
* @param reader BinaryReader pointing to the value to read
* @param pointerSize the size of a pointer
* @return the address value
* @throws IOException if an I/O error occurs
* @throws IllegalArgumentException if an unknown pointer size is given
*/
public static Number readAddress(BinaryReader reader, byte pointerSize) throws IOException {
switch (pointerSize) {
case 1:
return Byte.valueOf(reader.readNextByte());
case 2:
return Short.valueOf(reader.readNextShort());
case 4:
return Integer.valueOf(reader.readNextInt());
case 8:
return Long.valueOf(reader.readNextLong());
}
throw new IllegalArgumentException(
"Unknown pointer size: 0x" + Integer.toHexString(pointerSize));
}
/**
* Reads a variable-sized unsigned 'address' value from a {@link BinaryReader} and
* returns it as a 64 bit java long.
@ -588,8 +565,9 @@ public class DWARFUtil {
DWARFAttributeValue dwATObjectPointer =
paramDIEA.getParent().getAttribute(DWARFAttribute.DW_AT_object_pointer);
return dwATObjectPointer != null && dwATObjectPointer instanceof DWARFNumericAttribute &&
paramDIEA.hasOffset(((DWARFNumericAttribute) dwATObjectPointer).getUnsignedValue());
return dwATObjectPointer != null &&
dwATObjectPointer instanceof DWARFNumericAttribute dnum &&
paramDIEA.hasOffset(dnum.getUnsignedValue());
}
/**

View file

@ -1,49 +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.util.bin.format.dwarf4.attribs;
/**
* Stores a integer value (with ambiguous signedness) in a long, with a mask that will
* allow the consumer at a later time to treat the value as signed or unsigned.
* <p>
* When supplied with a long value that was originally a smaller integer with its high-bit
* set, java will sign-extend the value to 64 bits. To treat this as an unsigned
* value, the mask needs to match the bitwidth of the supplied value, and is used to return
* the relevant number of bits from the value. (See NumberUtil.UNSIGNED_BYTE_MASK, etc)
* <p>
* This allows us to simplify the storage of a variable sized int value
* (1 byte, 2 byte, 4 byte, 8 byte) using just a 8 byte long and an 8 byte mask.
*/
public class DWARFAmbigNumericAttribute extends DWARFNumericAttribute {
private final long mask;
public DWARFAmbigNumericAttribute(long value, long mask) {
super(value);
this.mask = mask;
}
@Override
public long getUnsignedValue() {
return value & mask;
}
@Override
public String toString() {
return String.format("DWARFAmbigNumericAttribute: natural=%d [%08x], unsigned=%s [%08x]",
value, value, Long.toUnsignedString(getUnsignedValue()), getUnsignedValue());
}
}

View file

@ -24,7 +24,6 @@ import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
import ghidra.app.util.bin.format.dwarf4.next.StringTable;
import ghidra.program.model.data.LEB128;
import ghidra.util.NumberUtil;
/**
* A factory for deserializing {@link DWARFAttributeValue dwarf attribute} from
@ -57,21 +56,21 @@ public class DWARFAttributeFactory {
switch (form) {
case DW_FORM_addr:
return new DWARFNumericAttribute(
DWARFUtil.readVarSizedULong(reader, unit.getPointerSize()));
reader.readNextUnsignedValue(unit.getPointerSize()));
case DW_FORM_ref1: {
long uoffset = DWARFUtil.readVarSizedULong(reader, 1);
long uoffset = reader.readNextUnsignedValue(1);
return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
}
case DW_FORM_ref2: {
long uoffset = DWARFUtil.readVarSizedULong(reader, 2);
long uoffset = reader.readNextUnsignedValue(2);
return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
}
case DW_FORM_ref4: {
long uoffset = DWARFUtil.readVarSizedULong(reader, 4);
long uoffset = reader.readNextUnsignedValue(4);
return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
}
case DW_FORM_ref8: {
long uoffset = DWARFUtil.readVarSizedULong(reader, 8);
long uoffset = reader.readNextUnsignedValue(8);
return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
}
case DW_FORM_ref_udata: {
@ -112,20 +111,17 @@ public class DWARFAttributeFactory {
return new DWARFBlobAttribute(reader.readNextByteArray(length));
}
case DW_FORM_data1:
return new DWARFAmbigNumericAttribute(reader.readNextByte(),
NumberUtil.UNSIGNED_BYTE_MASK);
return new DWARFNumericAttribute(8, reader.readNextByte(), true);
case DW_FORM_data2:
return new DWARFAmbigNumericAttribute(reader.readNextShort(),
NumberUtil.UNSIGNED_SHORT_MASK);
return new DWARFNumericAttribute(16, reader.readNextShort(), true);
case DW_FORM_data4:
return new DWARFAmbigNumericAttribute(reader.readNextInt(),
NumberUtil.UNSIGNED_INT_MASK);
return new DWARFNumericAttribute(32, reader.readNextInt(), true);
case DW_FORM_data8:
return new DWARFNumericAttribute(reader.readNextLong());
return new DWARFNumericAttribute(64, reader.readNextLong(), true);
case DW_FORM_sdata:
return new DWARFNumericAttribute(reader.readNext(LEB128::signed));
return new DWARFNumericAttribute(64, reader.readNext(LEB128::signed), true);
case DW_FORM_udata:
return new DWARFNumericAttribute(reader.readNext(LEB128::unsigned));
return new DWARFNumericAttribute(64, reader.readNext(LEB128::unsigned), false);
case DW_FORM_exprloc: {
int length = reader.readNextUnsignedVarIntExact(LEB128::unsigned);

View file

@ -15,32 +15,35 @@
*/
package ghidra.app.util.bin.format.dwarf4.attribs;
import ghidra.program.model.scalar.Scalar;
/**
* DWARF numeric attribute.
* <p>
* Use this class instead of {@link DWARFAmbigNumericAttribute} when the signed-ness
* of the raw value is known when deserializing the attribute from a stream.
* <p>
* Use {@link DWARFAmbigNumericAttribute} when the signed-ness of the raw value is only know
* to the code that is using the attribute value.
*/
public class DWARFNumericAttribute implements DWARFAttributeValue {
protected final long value;
public class DWARFNumericAttribute extends Scalar implements DWARFAttributeValue {
/**
* Creates a new numeric value, using 64 bits and marked as signed
*
* @param value long 64 bit value
*/
public DWARFNumericAttribute(long value) {
this.value = value;
this(64, value, true);
}
public long getValue() {
return value;
}
public long getUnsignedValue() {
return value;
/**
* Creates a new numeric value, using the specific bitLength and value.
*
* @param bitLength number of bits, valid values are 1..64, or 0 if value is also 0
* @param value value of the scalar, any bits that are set above bitLength will be ignored
* @param signed true for a signed value, false for an unsigned value.
*/
public DWARFNumericAttribute(int bitLength, long value, boolean signed) {
super(bitLength, value, signed);
}
@Override
public String toString() {
return String.format("DWARFNumericAttribute: %d [%08x]", value, value);
return String.format("DWARFNumericAttribute: %d [%08x]", getValue(), getValue());
}
}

View file

@ -24,7 +24,7 @@ import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import ghidra.util.NumberUtil;
import ghidra.util.NumericUtilities;
public class BinaryReaderTest {
@ -149,8 +149,7 @@ public class BinaryReaderTest {
assertEquals(1, br.readUnsignedShort(0));
assertEquals(Short.MAX_VALUE /* 0x7fff */, br.readUnsignedShort(2));
assertEquals(NumberUtil.UNSIGNED_SHORT_MASK /* ie. UNSIGNED_SHORT_MAX, 0xffff*/,
br.readUnsignedShort(4));
assertEquals(0xffff, br.readUnsignedShort(4));
assertEquals(Short.MAX_VALUE + 1 /* 0x8000 */, br.readUnsignedShort(6));
try {
br.readUnsignedShort(8);
@ -184,8 +183,7 @@ public class BinaryReaderTest {
assertEquals(1, br.readNextUnsignedShort());
assertEquals(Short.MAX_VALUE /* 0x7fff */, br.readNextUnsignedShort());
assertEquals(NumberUtil.UNSIGNED_SHORT_MASK /* ie. UNSIGNED_SHORT_MAX, 0xffff*/,
br.readNextUnsignedShort());
assertEquals(0xffff, br.readNextUnsignedShort());
assertEquals(Short.MAX_VALUE + 1 /* 0x8000 */, br.readNextUnsignedShort());
try {
br.readNextUnsignedShort();
@ -225,8 +223,7 @@ public class BinaryReaderTest {
assertEquals(1, br.readUnsignedInt(0));
assertEquals(Integer.MAX_VALUE, br.readUnsignedInt(4));
assertEquals(NumberUtil.UNSIGNED_INT_MASK /*ie. UNSIGNED_INT_MAX, 0xff_ff_ff_ff*/,
br.readUnsignedInt(8));
assertEquals(NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG, br.readUnsignedInt(8));
assertEquals((long) Integer.MAX_VALUE + 1 /* 0x80_00_00_00 */, br.readUnsignedInt(12));
try {
br.readUnsignedInt(16);
@ -262,8 +259,7 @@ public class BinaryReaderTest {
assertEquals(1, br.readNextUnsignedInt());
assertEquals(Integer.MAX_VALUE, br.readNextUnsignedInt());
assertEquals(NumberUtil.UNSIGNED_INT_MASK /*ie. UNSIGNED_INT_MAX, 0xff_ff_ff_ff*/,
br.readNextUnsignedInt());
assertEquals(NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG, br.readNextUnsignedInt());
assertEquals((long) Integer.MAX_VALUE + 1 /* 0x80_00_00_00 */, br.readNextUnsignedInt());
try {
br.readNextUnsignedInt();

View file

@ -1,63 +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.util;
public class NumberUtil {
public static final int UNSIGNED_BYTE_MASK = 0xff;
public static final int UNSIGNED_SHORT_MASK = 0xffff;
public static final long UNSIGNED_INT_MASK = 0xffffffffL;
//public static final long UNSIGNED_LONG_MASK = 0xffffffffffffffffL;
/**
* Get the unsigned value of a number.
* @param value the value stored in a signed number
* @return the unsigned value of the number
*/
public static Number getUnsignedValue(Number value) {
if (value instanceof Byte) {
return value.byteValue() & UNSIGNED_BYTE_MASK;
}
else if (value instanceof Short) {
return value.shortValue() & UNSIGNED_SHORT_MASK;
}
else if (value instanceof Integer) {
return value.intValue() & UNSIGNED_INT_MASK;
}
else if (value instanceof Long) {
// TODO: Is this valid?
if (value.longValue() < 0) {
return value.longValue() & 0xffffffffffffffffL;
}
return value;
}
throw new UnsupportedOperationException("Number instance not handled!");
}
/**
* Compare to the maximum unsigned value that the current number is holding.
* @param value the value stored in a signed number
* @return true if equal to the maximum and false otherwise
*/
public static boolean equalsMaxUnsignedValue(Number value) {
// All number types should be the max when equal to signed value -1 in two's complement
if (value.longValue() == -1) {
return true;
}
return false;
}
}