mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-25 16:19:35 +08:00
Merge remote-tracking branch
'origin/GP-877_dev747368_fixedlen_leb128_datatypes--SQUASHED
This commit is contained in:
+5
-70
@@ -15,13 +15,10 @@
|
||||
*/
|
||||
package ghidra.app.plugin.exceptionhandlers.gcc;
|
||||
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.UnsignedLeb128DataType;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.util.AddressTranslationException;
|
||||
|
||||
/**
|
||||
@@ -35,9 +32,6 @@ abstract class AbstractDwarfEHDecoder implements DwarfEHDecoder {
|
||||
protected static DWordDataType DWORD_DATA_TYPE = DWordDataType.dataType;
|
||||
protected static QWordDataType QWORD_DATA_TYPE = QWordDataType.dataType;
|
||||
|
||||
protected static SignedLeb128DataType SLEB_DATA_TYPE = SignedLeb128DataType.dataType;
|
||||
protected static UnsignedLeb128DataType ULEB_DATA_TYPE = UnsignedLeb128DataType.dataType;
|
||||
|
||||
protected final DwarfEHDataApplicationMode appMode;
|
||||
protected final boolean isIndirect;
|
||||
|
||||
@@ -222,70 +216,6 @@ abstract class AbstractDwarfEHDecoder implements DwarfEHDecoder {
|
||||
return buf.getBytes(buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned LEB128-encoded value from <code>program</code> at <code>addr</code>
|
||||
* @param program Program to read from
|
||||
* @param addr Address to read from
|
||||
* @throws MemoryAccessException if the data can't be read
|
||||
*/
|
||||
protected long read_leb128(Program program, Address addr) throws MemoryAccessException {
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
Scalar scalar =
|
||||
(Scalar) uleb.getValue(buf, uleb.getDefaultSettings(), uleb.getLength(buf, -1));
|
||||
return scalar.getUnsignedValue();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned LEB128-encoded value from <code>program</code> at the address of <code>buf</code>
|
||||
* @param buf Buffer to read from
|
||||
* @param length Unused
|
||||
* @throws MemoryAccessException if the data can't be read
|
||||
*/
|
||||
protected long read_leb128(MemBuffer buf, int length) throws MemoryAccessException {
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
|
||||
Scalar scalar =
|
||||
(Scalar) uleb.getValue(buf, uleb.getDefaultSettings(), uleb.getLength(buf, -1));
|
||||
return scalar.getUnsignedValue();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a signed LEB128-encoded value from <code>program</code> at <code>addr</code>
|
||||
* @param program Program to read from
|
||||
* @param addr Address to read from
|
||||
* @throws MemoryAccessException if the data can't be read
|
||||
*/
|
||||
protected long read_sleb128(Program program, Address addr) throws MemoryAccessException {
|
||||
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
Scalar scalar =
|
||||
(Scalar) sleb.getValue(buf, sleb.getDefaultSettings(), sleb.getLength(buf, -1));
|
||||
return scalar.getSignedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a signed LEB128-encoded value from <code>program</code> at the address of <code>buf</code>
|
||||
* @param buf Buffer to read from
|
||||
* @param length Number of bytes to read
|
||||
* @param buffer Destination buffer to read into
|
||||
* @throws MemoryAccessException if the data can't be read
|
||||
*/
|
||||
protected long read_sleb128(MemBuffer buf, int length) throws MemoryAccessException {
|
||||
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
|
||||
Scalar scalar =
|
||||
(Scalar) sleb.getValue(buf, sleb.getDefaultSettings(), sleb.getLength(buf, -1));
|
||||
return scalar.getSignedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DWARF-encoded address value as stored by the context
|
||||
* @param context Stores program location and decode parameters
|
||||
@@ -373,6 +303,11 @@ abstract class AbstractDwarfEHDecoder implements DwarfEHDecoder {
|
||||
|
||||
/**
|
||||
* Decode an integer value according to parameters stored in the <code>context</code> object.
|
||||
* <p>
|
||||
* Implementations should duplicate the result of the call to doDecode in
|
||||
* {@link DwarfDecodeContext#setDecodedValue(Object, int)}, as well as the underlying length of
|
||||
* the data item that was decoded.
|
||||
*
|
||||
* @param context Stores program location and decode parameters
|
||||
* @return the integer value
|
||||
* @throws MemoryAccessException if the data can't be read
|
||||
|
||||
+12
-32
@@ -18,15 +18,13 @@ package ghidra.app.plugin.exceptionhandlers.gcc;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.UnsignedLeb128DataType;
|
||||
import ghidra.app.util.bin.LEB128Info;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.VoidDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.MemoryBufferImpl;
|
||||
|
||||
/**
|
||||
* Generate instances of DwarfEHDecoder suitable for various pointer-encodings.
|
||||
@@ -235,25 +233,15 @@ public class DwarfDecoderFactory {
|
||||
Program program = context.getProgram();
|
||||
Address addr = context.getAddress();
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
|
||||
int numAvailBytes = uleb.getLength(buf, -1);
|
||||
|
||||
Scalar scalar = (Scalar) uleb.getValue(buf, uleb.getDefaultSettings(), numAvailBytes);
|
||||
long offset = scalar.getUnsignedValue();
|
||||
int readLen = uleb.getLength(buf, numAvailBytes);
|
||||
|
||||
context.setDecodedValue(offset, readLen);
|
||||
|
||||
return offset;
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
context.setDecodedValue(uleb128.asLong(), uleb128.getLength());
|
||||
return uleb128.asLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(Program program) {
|
||||
return ULEB_DATA_TYPE;
|
||||
return UnsignedLeb128DataType.dataType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class DW_EH_PE_udata2_Decoder extends AbstractUnsignedDwarfEHDecoder {
|
||||
@@ -407,23 +395,15 @@ public class DwarfDecoderFactory {
|
||||
Program program = context.getProgram();
|
||||
Address addr = context.getAddress();
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
LEB128Info sleb128 = GccAnalysisUtils.readSLEB128Info(program, addr);
|
||||
context.setDecodedValue(sleb128.asLong(), sleb128.getLength());
|
||||
|
||||
int numAvailBytes = sleb.getLength(buf, -1);
|
||||
|
||||
Scalar scalar = (Scalar) sleb.getValue(buf, sleb.getDefaultSettings(), numAvailBytes);
|
||||
long offset = scalar.getSignedValue();
|
||||
int readLen = sleb.getLength(buf, numAvailBytes);
|
||||
|
||||
context.setDecodedValue(offset, readLen);
|
||||
|
||||
return offset;
|
||||
return sleb128.asLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(Program program) {
|
||||
return SLEB_DATA_TYPE;
|
||||
return SignedLeb128DataType.dataType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-43
@@ -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,12 +15,12 @@
|
||||
*/
|
||||
package ghidra.app.plugin.exceptionhandlers.gcc;
|
||||
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.UnsignedLeb128DataType;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
||||
/**
|
||||
* Utility methods for use by the gcc exception handling analysis.
|
||||
@@ -79,62 +78,49 @@ public class GccAnalysisUtils {
|
||||
* @param buffer the array to save the bytes that were read.
|
||||
* @throws MemoryAccessException if the expected number of bytes can't be read.
|
||||
*/
|
||||
public static void readBytes(Program program, Address addr, byte[] buffer) throws MemoryAccessException {
|
||||
public static void readBytes(Program program, Address addr, byte[] buffer)
|
||||
throws MemoryAccessException {
|
||||
program.getMemory().getBytes(addr, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned little endian base 128 integer from memory.
|
||||
*
|
||||
* @param program the program with memory to be read.
|
||||
* @param addr the address in memory to begin reading the unsigned LEB128.
|
||||
* @return the unsigned LEB128 integer.
|
||||
* @return {@link LEB128Info} (value + metadata)
|
||||
*/
|
||||
public static long readULEB128(Program program, Address addr) {
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
Scalar scalar = (Scalar) uleb.getValue(buf, uleb.getDefaultSettings(), uleb.getLength(buf, -1));
|
||||
return scalar.getUnsignedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of an unsigned little endian base 128 integer.
|
||||
* @param program the program with memory to be read.
|
||||
* @param addr the address in memory to begin reading the unsigned LEB128.
|
||||
* @return the length of the unsigned LEB128 integer.
|
||||
*/
|
||||
public static int getULEB128Length(Program program, Address addr) {
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
return uleb.getLength(buf, -1);
|
||||
public static LEB128Info readULEB128Info(Program program, Address addr)
|
||||
throws MemoryAccessException {
|
||||
LEB128Info uleb128 = readLEB128Info(program, addr, false);
|
||||
return uleb128;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an signed little endian base 128 integer from memory.
|
||||
*
|
||||
* @param program the program with memory to be read.
|
||||
* @param addr the address in memory to begin reading the signed LEB128.
|
||||
* @return the signed LEB128 integer.
|
||||
* @return {@link LEB128Info} (value + metadata)
|
||||
*/
|
||||
public static long readSLEB128(Program program, Address addr) {
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
Scalar scalar = (Scalar) sleb.getValue(buf, sleb.getDefaultSettings(), sleb.getLength(buf, -1));
|
||||
return scalar.getUnsignedValue();
|
||||
public static LEB128Info readSLEB128Info(Program program, Address addr)
|
||||
throws MemoryAccessException {
|
||||
LEB128Info sleb128 = readLEB128Info(program, addr, true);
|
||||
return sleb128;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of a signed little endian base 128 integer.
|
||||
* @param program the program with memory to be read.
|
||||
* @param addr the address in memory to begin reading the signed LEB128.
|
||||
* @return the length of the signed LEB128 integer.
|
||||
*/
|
||||
public static int getSLEB128Length(Program program, Address addr) {
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
private static LEB128Info readLEB128Info(Program program, Address addr, boolean isSigned)
|
||||
throws MemoryAccessException {
|
||||
try (MemoryByteProvider mbp =
|
||||
new MemoryByteProvider(program.getMemory(), addr.getAddressSpace())) {
|
||||
BinaryReader br = new BinaryReader(mbp, !program.getMemory().isBigEndian());
|
||||
br.setPointerIndex(addr.getOffset());
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
return sleb.getLength(buf, -1);
|
||||
return LEB128Info.readValue(br, isSigned);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new MemoryAccessException("Error reading LEB128 value at " + addr.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-168
@@ -1,168 +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.exceptionhandlers.gcc.datatype;
|
||||
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
|
||||
/**
|
||||
* LEB128 is an integer compression system resulting in variable-length byte sequence.
|
||||
* An abstract base class for a little endian base 128 integer data type.
|
||||
*/
|
||||
public abstract class AbstractLeb128DataType extends BuiltIn implements Dynamic {
|
||||
|
||||
/** The maximum length in bytes of a leb128 data type. */
|
||||
public static final int MAX_LEB128_ENCODED_VALUE_LEN = 8;
|
||||
|
||||
private static final FormatSettingsDefinition FORMAT = FormatSettingsDefinition.DEF_HEX;
|
||||
private static final PaddingSettingsDefinition PADDING = PaddingSettingsDefinition.DEF;
|
||||
|
||||
private static SettingsDefinition[] SETTINGS_DEFS = { FORMAT, PADDING };
|
||||
|
||||
private final boolean signed;
|
||||
|
||||
/**
|
||||
* Base constructor for a little endian based 128 data type.
|
||||
* @param name name of the leb128 data type that extends this class.
|
||||
* @param signed true if it is signed. false if unsigned.
|
||||
* @param dtm the data type manager to associate with this data type.
|
||||
*/
|
||||
public AbstractLeb128DataType(String name, boolean signed, DataTypeManager dtm) {
|
||||
super(null, name, dtm);
|
||||
this.signed = signed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
|
||||
return SETTINGS_DEFS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Dwarf LEB128-Encoded Number";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength(MemBuffer buf, int maxLength) {
|
||||
|
||||
if (maxLength < 1 || maxLength > MAX_LEB128_ENCODED_VALUE_LEN) {
|
||||
maxLength = MAX_LEB128_ENCODED_VALUE_LEN;
|
||||
}
|
||||
|
||||
byte[] data = new byte[maxLength];
|
||||
int availBytes = buf.getBytes(data, 0);
|
||||
int numRead = 0;
|
||||
byte curByte = 0;
|
||||
while ((numRead < availBytes) && (numRead < data.length)) {
|
||||
curByte = data[numRead];
|
||||
numRead++;
|
||||
if ((curByte & 0x80) == 0) {
|
||||
break; // End of LEB128.
|
||||
}
|
||||
}
|
||||
return numRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
byte[] data = new byte[length];
|
||||
if (buf.getBytes(data, 0) != length) {
|
||||
return null;
|
||||
}
|
||||
int numRead = 0;
|
||||
int shift = 0;
|
||||
byte curByte = 0;
|
||||
long val = 0;
|
||||
|
||||
if (data.length >= 1) {
|
||||
do {
|
||||
curByte = data[numRead];
|
||||
numRead++;
|
||||
val |= ((curByte & 0x7f) << shift);
|
||||
shift += 7;
|
||||
}
|
||||
while ((curByte & 0x80) != 0 && numRead < data.length);
|
||||
|
||||
if (signed && ((curByte & 0x40) != 0)) {
|
||||
// val |= (-1 << (shift - 7)) << 7;
|
||||
val |= -1 << shift;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new Scalar(numRead * 8, val, signed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
|
||||
int format = FORMAT.getFormat(settings);
|
||||
boolean padded = PADDING.isPadded(settings);
|
||||
|
||||
int size = getLength(buf, length);
|
||||
if (size <= 0 && length <= 0) {
|
||||
return "??";
|
||||
}
|
||||
|
||||
Scalar val = (Scalar) getValue(buf, settings, length);
|
||||
if (val == null) {
|
||||
return "??";
|
||||
}
|
||||
|
||||
int radix;
|
||||
String prefix = "";
|
||||
String postfix = "";
|
||||
switch (format) {
|
||||
default:
|
||||
case FormatSettingsDefinition.HEX:
|
||||
radix = 16;
|
||||
postfix = "h";
|
||||
break;
|
||||
case FormatSettingsDefinition.DECIMAL:
|
||||
radix = 10;
|
||||
break;
|
||||
case FormatSettingsDefinition.BINARY:
|
||||
radix = 2;
|
||||
postfix = "b";
|
||||
break;
|
||||
case FormatSettingsDefinition.OCTAL:
|
||||
radix = 8;
|
||||
postfix = "o";
|
||||
break;
|
||||
}
|
||||
|
||||
String valStr = val.toString(radix, padded, true /* showSign */, prefix, "");
|
||||
return valStr.toUpperCase() + postfix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getReplacementBaseType() {
|
||||
return ByteDataType.dataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSpecifyLength() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+10
-6
@@ -97,7 +97,7 @@ public class EhFrameHeaderSection {
|
||||
DwarfEHDecoder fdeCountDecoder = getFdeCountDecoder(eh_frame_hdr);
|
||||
Address fdeCountAddress = curAddress;
|
||||
|
||||
curAddress = processEncodedFdeCount(fdeCountAddress, fdeCountDecoder);
|
||||
curAddress = markupEncodedFdeCount(fdeCountAddress, fdeCountDecoder);
|
||||
|
||||
int fdeTableCnt = getFdeTableCount(fdeCountAddress, curMemBlock, fdeCountDecoder);
|
||||
if (fdeTableCnt > 0) {
|
||||
@@ -113,8 +113,12 @@ public class EhFrameHeaderSection {
|
||||
* @param curAddress address of the FDE count field
|
||||
* @param fdeDecoder decoder to use in determining data type for this field
|
||||
* @return the next address after the FDE count field
|
||||
* @throws MemoryAccessException
|
||||
*/
|
||||
private Address processEncodedFdeCount(Address curAddress, DwarfEHDecoder fdeDecoder) {
|
||||
private Address markupEncodedFdeCount(Address curAddress, DwarfEHDecoder fdeDecoder)
|
||||
throws MemoryAccessException {
|
||||
DwarfDecodeContext ctx = new DwarfDecodeContext(program, curAddress);
|
||||
long unused = fdeDecoder.decode(ctx); // we only parse to get the length of the integer
|
||||
|
||||
/* Create the Encoded FDE count member */
|
||||
DataType encDataType = fdeDecoder.getDataType(program);
|
||||
@@ -126,7 +130,7 @@ public class EhFrameHeaderSection {
|
||||
new SetCommentCmd(curAddress, CodeUnit.EOL_COMMENT, "Encoded FDE count");
|
||||
commentCmd.applyTo(program);
|
||||
|
||||
curAddress = curAddress.add(encDataType.getLength());
|
||||
curAddress = curAddress.add(ctx.getEncodedLength());
|
||||
return curAddress;
|
||||
}
|
||||
|
||||
@@ -153,8 +157,8 @@ public class EhFrameHeaderSection {
|
||||
/* Create the encoded Exception Handler Frame Pointer */
|
||||
DwarfEHDecoder frmPtrDecoder =
|
||||
DwarfDecoderFactory.getDecoder(eh_frame_hdr.getEh_FramePtrEncoding());
|
||||
Address frmPtrAddr =
|
||||
frmPtrDecoder.decodeAddress(new DwarfDecodeContext(program, curAddress, curMemBlock));
|
||||
DwarfDecodeContext ctx = new DwarfDecodeContext(program, curAddress, curMemBlock);
|
||||
Address frmPtrAddr = frmPtrDecoder.decodeAddress(ctx);
|
||||
|
||||
program.getReferenceManager().addMemoryReference(curAddress, frmPtrAddr, RefType.DATA,
|
||||
SourceType.ANALYSIS, 0);
|
||||
@@ -168,7 +172,7 @@ public class EhFrameHeaderSection {
|
||||
new SetCommentCmd(curAddress, CodeUnit.EOL_COMMENT, "Encoded eh_frame_ptr");
|
||||
commentCmd.applyTo(program);
|
||||
|
||||
curAddress = curAddress.add(frmPtrDataType.getLength());
|
||||
curAddress = curAddress.add(ctx.getEncodedLength());
|
||||
return curAddress;
|
||||
}
|
||||
|
||||
|
||||
+26
-34
@@ -21,13 +21,13 @@ import java.nio.ByteOrder;
|
||||
import ghidra.app.cmd.comments.SetCommentCmd;
|
||||
import ghidra.app.cmd.data.CreateArrayCmd;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.*;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.*;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.DwarfEncodingModeDataType;
|
||||
import ghidra.app.util.bin.LEB128Info;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOutOfBoundsException;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.Msg;
|
||||
@@ -280,18 +280,16 @@ public class Cie extends GccAnalysisClass {
|
||||
*/
|
||||
String comment = "(CIE) Code Alignment";
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
int encodedLen = uleb.getLength(buf, AbstractLeb128DataType.MAX_LEB128_ENCODED_VALUE_LEN);
|
||||
Object augLenObj = uleb.getValue(buf, uleb.getDefaultSettings(), encodedLen);
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
|
||||
codeAlignFactor = (int) ((Scalar) augLenObj).getUnsignedValue();
|
||||
codeAlignFactor = (int) uleb128.asLong();
|
||||
|
||||
createAndCommentData(program, addr, uleb, comment, CodeUnit.EOL_COMMENT);
|
||||
createAndCommentData(program, addr, UnsignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
curSize += encodedLen;
|
||||
curSize += uleb128.getLength();
|
||||
|
||||
return addr.add(encodedLen);
|
||||
return addr.add(uleb128.getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,18 +307,16 @@ public class Cie extends GccAnalysisClass {
|
||||
*/
|
||||
String comment = "(CIE) Data Alignment";
|
||||
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
int encodedLen = sleb.getLength(buf, -1);
|
||||
Object alignObj = sleb.getValue(buf, sleb.getDefaultSettings(), encodedLen);
|
||||
LEB128Info sleb128 = GccAnalysisUtils.readSLEB128Info(program, addr);
|
||||
|
||||
dataAlignFactor = (int) ((Scalar) alignObj).getSignedValue();
|
||||
dataAlignFactor = (int) sleb128.asLong();
|
||||
|
||||
createAndCommentData(program, addr, sleb, comment, CodeUnit.EOL_COMMENT);
|
||||
createAndCommentData(program, addr, SignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
curSize += encodedLen;
|
||||
curSize += sleb128.getLength();
|
||||
|
||||
return addr.add(encodedLen);
|
||||
return addr.add(sleb128.getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,16 +345,14 @@ public class Cie extends GccAnalysisClass {
|
||||
}
|
||||
else {
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
encodedDt = uleb;
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
|
||||
encodedDt = UnsignedLeb128DataType.dataType;
|
||||
// TODO Instead use the following data type once it can correctly determine the register.
|
||||
// encodedDt = new DwarfRegisterLeb128DataType();
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
encodedLen = uleb.getLength(buf, AbstractLeb128DataType.MAX_LEB128_ENCODED_VALUE_LEN);
|
||||
Object augLenObj = uleb.getValue(buf, uleb.getDefaultSettings(), encodedLen);
|
||||
|
||||
returnAddrRegister = (int) ((Scalar) augLenObj).getUnsignedValue();
|
||||
encodedLen = uleb128.getLength();
|
||||
returnAddrRegister = (int) uleb128.asLong();
|
||||
|
||||
}
|
||||
|
||||
@@ -383,18 +377,16 @@ public class Cie extends GccAnalysisClass {
|
||||
*/
|
||||
String comment = "(CIE) Augmentation Data Length";
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
int encodedLen = uleb.getLength(buf, AbstractLeb128DataType.MAX_LEB128_ENCODED_VALUE_LEN);
|
||||
Object augLenObj = uleb.getValue(buf, uleb.getDefaultSettings(), encodedLen);
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
|
||||
augmentationDataLength = (int) ((Scalar) augLenObj).getUnsignedValue();
|
||||
augmentationDataLength = (int) uleb128.asLong();
|
||||
|
||||
createAndCommentData(program, addr, uleb, comment, CodeUnit.EOL_COMMENT);
|
||||
createAndCommentData(program, addr, UnsignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
curSize += encodedLen;
|
||||
curSize += uleb128.getLength();
|
||||
|
||||
return addr.add(encodedLen);
|
||||
return addr.add(uleb128.getLength());
|
||||
|
||||
}
|
||||
|
||||
|
||||
+72
-47
@@ -18,6 +18,7 @@ package ghidra.app.plugin.exceptionhandlers.gcc.structures.ehFrame;
|
||||
|
||||
import ghidra.app.cmd.comments.SetCommentCmd;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.GccAnalysisUtils;
|
||||
import ghidra.app.util.bin.LEB128Info;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -99,6 +100,7 @@ public class DwarfCallFrameOpcodeParser {
|
||||
int operand1Len;
|
||||
long operand2;
|
||||
int operand2Len;
|
||||
LEB128Info uleb128;
|
||||
|
||||
while (curr.compareTo(limit) < 0) {
|
||||
|
||||
@@ -124,8 +126,10 @@ public class DwarfCallFrameOpcodeParser {
|
||||
break;
|
||||
case DW_CFA_offset:
|
||||
primaryOpcode = true;
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
@@ -177,12 +181,14 @@ public class DwarfCallFrameOpcodeParser {
|
||||
break;
|
||||
|
||||
case DW_CFA_offset_extended:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
operand2 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand2Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand2 = uleb128.asLong();
|
||||
operand2Len = uleb128.getLength();
|
||||
curr = curr.add(operand2Len);
|
||||
|
||||
sb.append(
|
||||
@@ -190,36 +196,41 @@ public class DwarfCallFrameOpcodeParser {
|
||||
break;
|
||||
|
||||
case DW_CFA_restore_extended:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_restore_extended reg[" + operand1 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_undefined:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_undefined reg[" + operand1 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_same_value:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_same_value reg[" + operand1 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_register:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
operand2 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand2Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand2 = uleb128.asLong();
|
||||
operand2Len = uleb128.getLength();
|
||||
curr = curr.add(operand2Len);
|
||||
|
||||
sb.append("DW_CFA_register reg[" + operand1 + "] reg[" + operand2 + "]");
|
||||
@@ -234,28 +245,32 @@ public class DwarfCallFrameOpcodeParser {
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
operand2 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand2Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand2 = uleb128.asLong();
|
||||
operand2Len = uleb128.getLength();
|
||||
curr = curr.add(operand2Len);
|
||||
|
||||
sb.append("DW_CFA_def_cfa reg[" + operand1 + "] offs[" + operand2 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa_register:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_def_cfa_register reg[" + operand1 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa_offset:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_def_cfa_offset offs[" + operand1 + "]");
|
||||
@@ -266,21 +281,23 @@ public class DwarfCallFrameOpcodeParser {
|
||||
break;
|
||||
|
||||
case DW_CFA_expression:
|
||||
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_expression reg[" + operand1 + "] BLOCK");
|
||||
break;
|
||||
|
||||
case DW_CFA_offset_extended_sf:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
operand2 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand2Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand2 = uleb128.asLong();
|
||||
operand2Len = uleb128.getLength();
|
||||
curr = curr.add(operand2Len);
|
||||
|
||||
sb.append("DW_CFA_offset_extended_sf reg[" + operand1 + "] offs[" +
|
||||
@@ -288,52 +305,60 @@ public class DwarfCallFrameOpcodeParser {
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa_sf:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
operand2 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand2Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand2 = uleb128.asLong();
|
||||
operand2Len = uleb128.getLength();
|
||||
curr = curr.add(operand2Len);
|
||||
|
||||
sb.append("DW_CFA_def_cfa_sf reg[" + operand1 + "] offs[" + operand2 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa_offset_sf:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_def_cfa_offset_sf offs[" + operand1 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_val_offset:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
operand2 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand2Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand2 = uleb128.asLong();
|
||||
operand2Len = uleb128.getLength();
|
||||
curr = curr.add(operand2Len);
|
||||
|
||||
sb.append("DW_CFA_val_offset [" + operand1 + "] [" + operand2 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_val_offset_sf:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
operand2 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand2Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand2 = uleb128.asLong();
|
||||
operand2Len = uleb128.getLength();
|
||||
curr = curr.add(operand2Len);
|
||||
|
||||
sb.append("DW_CFA_val_offset_sf [" + operand1 + "] [" + operand2 + "]");
|
||||
break;
|
||||
|
||||
case DW_CFA_val_expression:
|
||||
operand1 = GccAnalysisUtils.readULEB128(program, curr);
|
||||
operand1Len = GccAnalysisUtils.getULEB128Length(program, curr);
|
||||
uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
|
||||
operand1 = uleb128.asLong();
|
||||
operand1Len = uleb128.getLength();
|
||||
curr = curr.add(operand1Len);
|
||||
|
||||
sb.append("DW_CFA_val_expression [" + operand1 + "] BLOCK");
|
||||
|
||||
+7
-11
@@ -20,16 +20,14 @@ import ghidra.app.cmd.data.CreateArrayCmd;
|
||||
import ghidra.app.cmd.data.CreateDataCmd;
|
||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.*;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.UnsignedLeb128DataType;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.sections.CieSource;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.sections.DebugFrameSection;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.structures.gccexcepttable.LSDATable;
|
||||
import ghidra.app.util.opinion.ElfLoader;
|
||||
import ghidra.app.util.bin.LEB128Info;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
@@ -350,18 +348,16 @@ public class FrameDescriptionEntry extends GccAnalysisClass {
|
||||
*/
|
||||
String comment = "(FDE) Augmentation Data Length";
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
int encodedLen = uleb.getLength(buf, -1);
|
||||
Object augLenObj = uleb.getValue(buf, uleb.getDefaultSettings(), encodedLen);
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
|
||||
intAugmentationDataLength = (int) ((Scalar) augLenObj).getUnsignedValue();
|
||||
intAugmentationDataLength = (int) uleb128.asLong();
|
||||
|
||||
createAndCommentData(program, addr, uleb, comment, CodeUnit.EOL_COMMENT);
|
||||
createAndCommentData(program, addr, UnsignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
curSize += encodedLen;
|
||||
curSize += uleb128.getLength();
|
||||
|
||||
return addr.add(encodedLen);
|
||||
return addr.add(uleb128.getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+20
-30
@@ -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.
|
||||
@@ -17,15 +16,13 @@
|
||||
package ghidra.app.plugin.exceptionhandlers.gcc.structures.gccexcepttable;
|
||||
|
||||
import ghidra.app.cmd.comments.SetCommentCmd;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.GccAnalysisClass;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.RegionDescriptor;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.*;
|
||||
import ghidra.app.util.bin.LEB128Info;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.SignedLeb128DataType;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
@@ -66,8 +63,9 @@ public class LSDAActionRecord extends GccAnalysisClass {
|
||||
* it as an action record.
|
||||
* <br>Note: This method must get called before any of the "get..." methods.
|
||||
* @param address the start (minimum address) of this action record.
|
||||
* @throws MemoryAccessException
|
||||
*/
|
||||
public void create(Address address) {
|
||||
public void create(Address address) throws MemoryAccessException {
|
||||
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("action record's address cannot be null.");
|
||||
@@ -91,37 +89,28 @@ public class LSDAActionRecord extends GccAnalysisClass {
|
||||
nextAddress = addr;
|
||||
}
|
||||
|
||||
private Address createTypeFilter(Address addr) {
|
||||
private Address createTypeFilter(Address addr) throws MemoryAccessException {
|
||||
|
||||
String comment = "(LSDA Action Table) Type Filter";
|
||||
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
int encodedLen = sleb.getLength(buf, -1);
|
||||
Scalar typeFilterObj = (Scalar) sleb.getValue(buf, sleb.getDefaultSettings(), encodedLen);
|
||||
LEB128Info sleb128 = GccAnalysisUtils.readSLEB128Info(program, addr);
|
||||
|
||||
encodedLen = typeFilterObj.bitLength() / 8;
|
||||
typeFilter = (int) sleb128.asLong();
|
||||
|
||||
typeFilter = (int) typeFilterObj.getSignedValue();
|
||||
createAndCommentData(program, addr, SignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
createAndCommentData(program, addr, sleb, comment, CodeUnit.EOL_COMMENT);
|
||||
size += sleb128.getLength();
|
||||
|
||||
size += encodedLen;
|
||||
|
||||
return addr.add(encodedLen);
|
||||
return addr.add(sleb128.getLength());
|
||||
}
|
||||
|
||||
private Address createNextActionRef(Address addr) {
|
||||
private Address createNextActionRef(Address addr) throws MemoryAccessException {
|
||||
String comment = "(LSDA Action Table) Next-Action Reference";
|
||||
|
||||
SignedLeb128DataType sleb = SignedLeb128DataType.dataType;
|
||||
LEB128Info sleb128 = GccAnalysisUtils.readSLEB128Info(program, addr);
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
int encodedLen = sleb.getLength(buf, -1);
|
||||
Scalar nextDispObj = (Scalar) sleb.getValue(buf, sleb.getDefaultSettings(), encodedLen);
|
||||
encodedLen = nextDispObj.bitLength() / 8;
|
||||
|
||||
displacementToNext = (int) nextDispObj.getSignedValue();
|
||||
displacementToNext = (int) sleb128.asLong();
|
||||
|
||||
if (displacementToNext == 0) {
|
||||
nextActionAddress = Address.NO_ADDRESS;
|
||||
@@ -130,11 +119,12 @@ public class LSDAActionRecord extends GccAnalysisClass {
|
||||
nextActionAddress = addr.add(displacementToNext);
|
||||
}
|
||||
|
||||
createAndCommentData(program, addr, sleb, comment, CodeUnit.EOL_COMMENT);
|
||||
createAndCommentData(program, addr, SignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
size += encodedLen;
|
||||
size += sleb128.getLength();
|
||||
|
||||
return addr.add(encodedLen);
|
||||
return addr.add(sleb128.getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-1
@@ -22,6 +22,7 @@ import ghidra.app.plugin.exceptionhandlers.gcc.RegionDescriptor;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
@@ -59,8 +60,9 @@ public class LSDAActionTable {
|
||||
* <br>Note: This method must get called before any of the "get..." methods.
|
||||
* @param address the start (minimum address) of this action table.
|
||||
* @param maxAddress the end (maximum address) of this action table.
|
||||
* @throws MemoryAccessException
|
||||
*/
|
||||
public void create(Address address, Address maxAddress) {
|
||||
public void create(Address address, Address maxAddress) throws MemoryAccessException {
|
||||
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("action record's address cannot be null.");
|
||||
|
||||
+9
-15
@@ -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.
|
||||
@@ -18,13 +17,13 @@ package ghidra.app.plugin.exceptionhandlers.gcc.structures.gccexcepttable;
|
||||
|
||||
import ghidra.app.cmd.comments.SetCommentCmd;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.*;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.UnsignedLeb128DataType;
|
||||
import ghidra.app.util.bin.LEB128Info;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.UnsignedLeb128DataType;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -164,25 +163,20 @@ public class LSDACallSiteRecord extends GccAnalysisClass {
|
||||
return addr.add(encodedLen);
|
||||
}
|
||||
|
||||
private Address createAction(Address addr) {
|
||||
private Address createAction(Address addr) throws MemoryAccessException {
|
||||
String comment = "(LSDA Call Site) Action Table Offset";
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
|
||||
int encodedLen = uleb.getLength(buf, -1);
|
||||
|
||||
Object actionObj = uleb.getValue(buf, uleb.getDefaultSettings(), encodedLen);
|
||||
|
||||
actionOffset = (int) ((Scalar) actionObj).getUnsignedValue();
|
||||
encodedLen = ((Scalar) actionObj).bitLength() / 8;
|
||||
actionOffset = (int) uleb128.asLong();
|
||||
|
||||
if (actionOffset == 0) {
|
||||
comment += " (No action -- cleanup)";
|
||||
}
|
||||
|
||||
createAndCommentData(program, addr, uleb, comment, CodeUnit.EOL_COMMENT);
|
||||
return addr.add(encodedLen);
|
||||
createAndCommentData(program, addr, UnsignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
return addr.add(uleb128.getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+18
-28
@@ -17,14 +17,13 @@ package ghidra.app.plugin.exceptionhandlers.gcc.structures.gccexcepttable;
|
||||
|
||||
import ghidra.app.cmd.comments.SetCommentCmd;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.*;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.*;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.DwarfEncodingModeDataType;
|
||||
import ghidra.app.util.bin.LEB128Info;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.ByteDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -41,6 +40,7 @@ public class LSDAHeader extends GccAnalysisClass {
|
||||
|
||||
static final int OMITTED_ENCODING_TYPE = 0xFF;
|
||||
|
||||
|
||||
/* Class Members */
|
||||
private RegionDescriptor region;
|
||||
|
||||
@@ -140,7 +140,7 @@ public class LSDAHeader extends GccAnalysisClass {
|
||||
return addr.add(BYTE_LEN);
|
||||
}
|
||||
|
||||
private Address createTTypeOffset(Address addr) {
|
||||
private Address createTTypeOffset(Address addr) throws MemoryAccessException {
|
||||
String comment = "(LSDA) TType Offset";
|
||||
|
||||
DwarfEHDecoder decoder = DwarfDecoderFactory.getDecoder(ttypeEncoding);
|
||||
@@ -149,19 +149,15 @@ public class LSDAHeader extends GccAnalysisClass {
|
||||
return addr;
|
||||
}
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
|
||||
int encodedLen = uleb.getLength(buf, -1);
|
||||
|
||||
Object actionObj = uleb.getValue(buf, uleb.getDefaultSettings(), encodedLen);
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
|
||||
// this offset it based from *here*..
|
||||
ttypeOffset = (int) ((Scalar) actionObj).getUnsignedValue() + curSize;
|
||||
ttypeOffset = uleb128.asLong() + curSize;
|
||||
|
||||
createAndCommentData(program, addr, uleb, comment, CodeUnit.EOL_COMMENT);
|
||||
createAndCommentData(program, addr, UnsignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
return addr.add(encodedLen);
|
||||
return addr.add(uleb128.getLength());
|
||||
}
|
||||
|
||||
private Address createCallSiteTableEncoding(Address addr) throws MemoryAccessException {
|
||||
@@ -175,24 +171,18 @@ public class LSDAHeader extends GccAnalysisClass {
|
||||
return addr.add(BYTE_LEN);
|
||||
}
|
||||
|
||||
private Address createCallSiteTableLength(Address addr) {
|
||||
private Address createCallSiteTableLength(Address addr) throws MemoryAccessException {
|
||||
String comment = "(LSDA) Call Site Table Length";
|
||||
|
||||
UnsignedLeb128DataType uleb = UnsignedLeb128DataType.dataType;
|
||||
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
|
||||
|
||||
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), addr);
|
||||
callSiteTableLength = (int) uleb128.asLong();
|
||||
|
||||
int encodedLen = uleb.getLength(buf, AbstractLeb128DataType.MAX_LEB128_ENCODED_VALUE_LEN);
|
||||
|
||||
Object lenObj = uleb.getValue(buf, uleb.getDefaultSettings(), encodedLen);
|
||||
|
||||
callSiteTableLength = (int) (((Scalar) lenObj).getUnsignedValue());
|
||||
|
||||
createAndCommentData(program, addr, uleb, comment, CodeUnit.EOL_COMMENT);
|
||||
|
||||
curSize += encodedLen;
|
||||
return addr.add(encodedLen);
|
||||
createAndCommentData(program, addr, UnsignedLeb128DataType.dataType, comment,
|
||||
CodeUnit.EOL_COMMENT);
|
||||
|
||||
curSize += uleb128.getLength();
|
||||
return addr.add(uleb128.getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,6 +67,9 @@ public class BinaryReader {
|
||||
* <p>
|
||||
* When reading from the BinaryReader, use "readNext" methods to consume the location where
|
||||
* the object was located.
|
||||
* <p>
|
||||
* Implementations of this method should not return {@code null}, instead they should
|
||||
* throw an IOException.
|
||||
*
|
||||
* @param reader {@link BinaryReader}
|
||||
* @return new object
|
||||
@@ -75,6 +78,26 @@ public class BinaryReader {
|
||||
T get(BinaryReader reader) throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and returns an object from the current position in the specified input stream.
|
||||
* <p>
|
||||
*
|
||||
* @param <T> the type of object that will be returned
|
||||
*/
|
||||
public interface InputStreamReaderFunction<T> {
|
||||
/**
|
||||
* Reads from the specified input stream and returns a new object instance.
|
||||
* <p>
|
||||
* Implementations of this method should not return {@code null}, instead they should
|
||||
* throw an IOException.
|
||||
*
|
||||
* @param is an {@link InputStream} view of the BinaryReader
|
||||
* @return new object
|
||||
* @throws IOException if error reading
|
||||
*/
|
||||
T get(InputStream is) throws IOException;
|
||||
}
|
||||
|
||||
private final ByteProvider provider;
|
||||
private DataConverter converter;
|
||||
private long currentIndex;
|
||||
@@ -306,6 +329,18 @@ public class BinaryReader {
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InputStream that is a live view of the BinaryReader's position.
|
||||
* <p>
|
||||
* Any bytes read with the stream will affect the current position of the BinaryReader, and
|
||||
* any change to the BinaryReader's position will affect the next value the inputstream returns.
|
||||
*
|
||||
* @return {@link InputStream}
|
||||
*/
|
||||
public InputStream getInputStream() {
|
||||
return new BinaryReaderInputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at the next byte without incrementing
|
||||
* the current index.
|
||||
@@ -1034,6 +1069,22 @@ public class BinaryReader {
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a variable length / unknown format integer from the current position, using the
|
||||
* supplied reader function, returning it (if it fits) as a 32 bit java integer.
|
||||
*
|
||||
* @param func {@link InputStreamReaderFunction}
|
||||
* @return signed int32
|
||||
* @throws IOException if error reading or if the value does not fit into a 32 bit java int
|
||||
* @throws InvalidDataException if value can not be held in a java integer
|
||||
*/
|
||||
public int readNextVarInt(InputStreamReaderFunction<Long> func)
|
||||
throws IOException, InvalidDataException {
|
||||
long value = func.get(getInputStream());
|
||||
ensureInt32s(value);
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a variable length / unknown format unsigned integer from the current position, using
|
||||
* the supplied reader function, returning it (if it fits) as a 32 bit java integer.
|
||||
@@ -1050,6 +1101,22 @@ public class BinaryReader {
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a variable length / unknown format unsigned integer from the current position, using
|
||||
* the supplied reader function, returning it (if it fits) as a 32 bit java integer.
|
||||
*
|
||||
* @param func {@link InputStreamReaderFunction}
|
||||
* @return unsigned int32
|
||||
* @throws IOException if error reading data
|
||||
* @throws InvalidDataException if value can not be held in a java integer
|
||||
*/
|
||||
public int readNextUnsignedVarIntExact(InputStreamReaderFunction<Long> func)
|
||||
throws IOException, InvalidDataException {
|
||||
long value = func.get(getInputStream());
|
||||
ensureInt32u(value);
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an object from the current position, using the supplied reader function.
|
||||
*
|
||||
@@ -1063,12 +1130,25 @@ public class BinaryReader {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an object from the current position, using the supplied reader function.
|
||||
*
|
||||
* @param <T> type of the object that will be returned
|
||||
* @param func {@link InputStreamReaderFunction} that will read and return an object
|
||||
* @return new object of type T
|
||||
* @throws IOException if error reading
|
||||
*/
|
||||
public <T> T readNext(InputStreamReaderFunction<T> func) throws IOException {
|
||||
T obj = func.get(getInputStream());
|
||||
return obj;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
private static void ensureInt32u(long value) throws InvalidDataException {
|
||||
if (value < 0 || value > Integer.MAX_VALUE) {
|
||||
throw new InvalidDataException(
|
||||
"Value out of range for positive java 32 bit unsigned int: %s"
|
||||
.formatted(Long.toUnsignedString(value)));
|
||||
.formatted(Long.toUnsignedString(value)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1079,4 +1159,17 @@ public class BinaryReader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter between this BinaryReader and a InputStream.
|
||||
*/
|
||||
private class BinaryReaderInputStream extends InputStream {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!hasNext()) {
|
||||
return -1;
|
||||
}
|
||||
return readNextUnsignedByte();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.app.util.bin;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* Class to hold result of reading a {@link LEB128} value, along with size and position metadata.
|
||||
*/
|
||||
public class LEB128Info {
|
||||
|
||||
/**
|
||||
* Reads an unsigned LEB128 value from the BinaryReader and returns a {@link LEB128Info} instance
|
||||
* that contains the value along with size and position metadata.
|
||||
* <p>
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @return a {@link LEB128Info} instance with the read LEB128 value with metadata
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static LEB128Info unsigned(BinaryReader reader) throws IOException {
|
||||
return readValue(reader, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an signed LEB128 value from the BinaryReader and returns a {@link LEB128Info} instance
|
||||
* that contains the value along with size and position metadata.
|
||||
* <p>
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @return a {@link LEB128Info} instance with the read LEB128 value with metadata
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static LEB128Info signed(BinaryReader reader) throws IOException {
|
||||
return readValue(reader, true);
|
||||
}
|
||||
|
||||
private final long offset;
|
||||
private final long value;
|
||||
private final int byteLength;
|
||||
|
||||
private LEB128Info(long offset, long value, int byteLength) {
|
||||
this.offset = offset;
|
||||
this.value = value;
|
||||
this.byteLength = byteLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as an unsigned int32. If the actual value
|
||||
* is outside the positive range of a java int (ie. 0.. {@link Integer#MAX_VALUE}),
|
||||
* an exception is thrown.
|
||||
*
|
||||
* @return int in the range of 0 to {@link Integer#MAX_VALUE}
|
||||
* @throws IOException if value is outside range
|
||||
*/
|
||||
public int asUInt32() throws IOException {
|
||||
ensureInt32u(value);
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as an signed int32. If the actual value
|
||||
* is outside the range of a java int (ie. {@link Integer#MIN_VALUE}.. {@link Integer#MAX_VALUE}),
|
||||
* an exception is thrown.
|
||||
*
|
||||
* @return int in the range of {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}
|
||||
* @throws IOException if value is outside range
|
||||
*/
|
||||
public int asInt32() throws IOException {
|
||||
ensureInt32s(value);
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as a 64bit primitive long. Interpreting the signed-ness of the
|
||||
* value will depend on the way the value was read (ie. if {@link #signed(BinaryReader)}
|
||||
* vs. {@link #unsigned(BinaryReader)} was used).
|
||||
*
|
||||
* @return long value.
|
||||
*/
|
||||
public long asLong() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of the LEB128 value in the stream it was read from.
|
||||
*
|
||||
* @return stream offset of the LEB128 value
|
||||
*/
|
||||
public long getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that were used to store the LEB128 value in the stream
|
||||
* it was read from.
|
||||
*
|
||||
* @return number of bytes used to store the read LEB128 value
|
||||
*/
|
||||
public int getLength() {
|
||||
return byteLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("LEB128: value: %d, offset: %d, byteLength: %d", value, offset,
|
||||
byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a LEB128 value from the BinaryReader and returns a {@link LEB128Info} instance
|
||||
* that contains the value along with size and position metadata.
|
||||
* <p>
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @param isSigned true if the value is signed
|
||||
* @return a {@link LEB128Info} instance with the read LEB128 value with metadata
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static LEB128Info readValue(BinaryReader reader, boolean isSigned) throws IOException {
|
||||
long offset = reader.getPointerIndex();
|
||||
long value = LEB128.read(reader.getInputStream(), isSigned);
|
||||
int size = (int) (reader.getPointerIndex() - offset);
|
||||
return new LEB128Info(offset, value, size);
|
||||
}
|
||||
|
||||
|
||||
private static void ensureInt32u(long value) throws IOException {
|
||||
if (value < 0 || value > Integer.MAX_VALUE) {
|
||||
throw new InvalidDataException(
|
||||
"Value out of range for positive java 32 bit unsigned int: %s"
|
||||
.formatted(Long.toUnsignedString(value)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureInt32s(long value) throws IOException {
|
||||
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||
throw new InvalidDataException(
|
||||
"Value out of range for java 32 bit signed int: %d".formatted(value));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,6 +76,16 @@ public interface StructConverter {
|
||||
*/
|
||||
public final static DataType IBO64 = IBO64DataType.dataType;
|
||||
|
||||
/**
|
||||
* Reusable Unsigned LEB128 dynamic length data type
|
||||
*/
|
||||
public static final UnsignedLeb128DataType ULEB128 = UnsignedLeb128DataType.dataType;
|
||||
|
||||
/**
|
||||
* Reusable Signed LEB128 dynamic length data type
|
||||
*/
|
||||
public static final SignedLeb128DataType SLEB128 = SignedLeb128DataType.dataType;
|
||||
|
||||
/**
|
||||
* Returns a structure datatype representing the
|
||||
* contents of the implementor of this interface.
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.dwarf.line;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
public class FileEntry {
|
||||
private String fileName;
|
||||
@@ -31,9 +31,9 @@ public class FileEntry {
|
||||
if (fileName.length() == 0) {
|
||||
return;
|
||||
}
|
||||
directoryIndex = LEB128.readAsLong(reader, false);
|
||||
lastModifiedTime = LEB128.readAsLong(reader, false);
|
||||
fileLengthInBytes = LEB128.readAsLong(reader, false);
|
||||
directoryIndex = reader.readNext(LEB128::unsigned);
|
||||
lastModifiedTime = reader.readNext(LEB128::unsigned);
|
||||
fileLengthInBytes = reader.readNext(LEB128::unsigned);
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
|
||||
+8
-8
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.dwarf.line;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
public final class StatementProgramInstructions {
|
||||
|
||||
//Standard Opcodes
|
||||
@@ -93,7 +93,7 @@ public final class StatementProgramInstructions {
|
||||
}
|
||||
|
||||
private void executeExtended(int opcode) throws IOException {
|
||||
long length = LEB128.readAsLong(reader, false);
|
||||
long length = reader.readNext(LEB128::unsigned);
|
||||
|
||||
long oldIndex = reader.getPointerIndex();
|
||||
int extendedOpcode = reader.readNextByte();
|
||||
@@ -123,22 +123,22 @@ public final class StatementProgramInstructions {
|
||||
break;
|
||||
}
|
||||
case DW_LNS_advance_pc: {
|
||||
long value = LEB128.readAsLong(reader, false);
|
||||
long value = reader.readNext(LEB128::unsigned);
|
||||
machine.address += (value * prologue.getMinimumInstructionLength());
|
||||
break;
|
||||
}
|
||||
case DW_LNS_advance_line: {
|
||||
long value = LEB128.readAsLong(reader, false);
|
||||
long value = reader.readNext(LEB128::unsigned);
|
||||
machine.line += value;
|
||||
break;
|
||||
}
|
||||
case DW_LNS_set_file: {
|
||||
long value = LEB128.readAsLong(reader, false);
|
||||
long value = reader.readNext(LEB128::unsigned);
|
||||
machine.file = (int) value;
|
||||
break;
|
||||
}
|
||||
case DW_LNS_set_column: {
|
||||
long value = LEB128.readAsLong(reader, false);
|
||||
long value = reader.readNext(LEB128::unsigned);
|
||||
machine.column = (int) value;
|
||||
break;
|
||||
}
|
||||
|
||||
+7
-5
@@ -15,16 +15,18 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.dwarf4;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFChildren;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
|
||||
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class represents the 'schema' for a DWARF DIE record.
|
||||
* <p>
|
||||
@@ -43,11 +45,11 @@ public class DWARFAbbreviation
|
||||
TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
int ac = LEB128.readAsUInt32(reader);
|
||||
int ac = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
if (ac == 0) {
|
||||
return null;
|
||||
}
|
||||
int tag = LEB128.readAsUInt32(reader);
|
||||
int tag = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
DWARFChildren hasChildren = DWARFChildren.find((int) reader.readNextByte());
|
||||
|
||||
// Read each attribute specification until attribute and its value is 0
|
||||
|
||||
+6
-4
@@ -15,11 +15,12 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.dwarf4;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
|
||||
|
||||
import java.io.IOException;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
/**
|
||||
* Information about a single DWARF attribute.
|
||||
@@ -38,8 +39,9 @@ public class DWARFAttributeSpecification {
|
||||
* @throws IOException
|
||||
*/
|
||||
public static DWARFAttributeSpecification read(BinaryReader reader) throws IOException {
|
||||
int attribute = LEB128.readAsUInt32(reader);
|
||||
DWARFForm attributeForm = DWARFForm.find(LEB128.readAsUInt32(reader));
|
||||
int attribute = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
DWARFForm attributeForm =
|
||||
DWARFForm.find(reader.readNextUnsignedVarIntExact(LEB128::unsigned));
|
||||
|
||||
return attribute != 0 && attributeForm != DWARFForm.NULL
|
||||
? new DWARFAttributeSpecification(attribute, attributeForm) : null;
|
||||
|
||||
@@ -27,6 +27,7 @@ import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.DWARFUtil.LengthResult;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
|
||||
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
public class DWARFLine {
|
||||
private long unit_length;
|
||||
@@ -226,9 +227,9 @@ public class DWARFLine {
|
||||
|
||||
// This entry exists only if the length of the string is more than 0
|
||||
if (this.name.length() > 0) {
|
||||
this.directory_index = LEB128.readAsLong(reader, false);
|
||||
this.modification_time = LEB128.readAsLong(reader, false);
|
||||
this.length = LEB128.readAsLong(reader, false);
|
||||
this.directory_index = reader.readNext(LEB128::unsigned);
|
||||
this.modification_time = reader.readNext(LEB128::unsigned);
|
||||
this.length = reader.readNext(LEB128::unsigned);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -15,13 +15,15 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.dwarf4;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.attribs.*;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
|
||||
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
/**
|
||||
* A DWARF Debug Info Entry is a collection of {@link DWARFAttributeValue attributes}
|
||||
@@ -60,7 +62,7 @@ public class DebugInfoEntry {
|
||||
public static DebugInfoEntry read(BinaryReader reader, DWARFCompilationUnit unit,
|
||||
DWARFAttributeFactory attributeFactory) throws IOException {
|
||||
long offset = reader.getPointerIndex();
|
||||
int abbreviationCode = LEB128.readAsUInt32(reader);
|
||||
int abbreviationCode = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
// Check for terminator DIE
|
||||
if (abbreviationCode == 0) {
|
||||
|
||||
@@ -1,299 +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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteArrayProvider;
|
||||
|
||||
/**
|
||||
* Class to hold result of reading a LEB128 value, along with size and position metadata.
|
||||
* <p>
|
||||
* Note: If a LEB128 value that would result in a native value longer than 64bits is attempted to
|
||||
* be read, an {@link IOException} will be thrown, and the stream's position will be left at the last read byte.
|
||||
* <p>
|
||||
* If this was a valid (but overly large) LEB128, the caller's stream will be left still pointing to LEB data.
|
||||
* <p>
|
||||
*/
|
||||
public class LEB128 {
|
||||
|
||||
private final long offset;
|
||||
private final long value;
|
||||
private final int byteLength;
|
||||
|
||||
private LEB128(long offset, long value, int byteLength) {
|
||||
this.offset = offset;
|
||||
this.value = value;
|
||||
this.byteLength = byteLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as an unsigned int32. If the actual value
|
||||
* is outside the positive range of a java int (ie. 0.. {@link Integer#MAX_VALUE}),
|
||||
* an exception is thrown.
|
||||
*
|
||||
* @return int in the range of 0 to {@link Integer#MAX_VALUE}
|
||||
* @throws IOException if value is outside range
|
||||
*/
|
||||
public int asUInt32() throws IOException {
|
||||
ensureInt32u(value);
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as an signed int32. If the actual value
|
||||
* is outside the range of a java int (ie. {@link Integer#MIN_VALUE}.. {@link Integer#MAX_VALUE}),
|
||||
* an exception is thrown.
|
||||
*
|
||||
* @return int in the range of {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}
|
||||
* @throws IOException if value is outside range
|
||||
*/
|
||||
public int asInt32() throws IOException {
|
||||
ensureInt32s(value);
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as a 64bit primitive long. Interpreting the signed-ness of the
|
||||
* value will depend on the way the value was read (ie. if {@link #readSignedValue(BinaryReader)}
|
||||
* vs. {@link #readUnsignedValue(BinaryReader)} was used).
|
||||
*
|
||||
* @return long value.
|
||||
*/
|
||||
public long asLong() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of the LEB128 value in the stream it was read from.
|
||||
*
|
||||
* @return stream offset of the LEB128 value
|
||||
*/
|
||||
public long getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that were used to store the LEB128 value in the stream
|
||||
* it was read from.
|
||||
*
|
||||
* @return number of bytes used to store the read LEB128 value
|
||||
*/
|
||||
public int getLength() {
|
||||
return byteLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("LEB128: value: %d, offset: %d, byteLength: %d", value, offset,
|
||||
byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a LEB128 value from the BinaryReader and returns a {@link LEB128} instance
|
||||
* that contains the value along with size and position metadata.
|
||||
* <p>
|
||||
* See {@link #readAsLong(BinaryReader, boolean)}.
|
||||
*
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @param isSigned true if the value is signed
|
||||
* @return a {@link LEB128} instance with the read LEB128 value with metadata
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static LEB128 readValue(BinaryReader reader, boolean isSigned) throws IOException {
|
||||
long offset = reader.getPointerIndex();
|
||||
long value = LEB128.readAsLong(reader, isSigned);
|
||||
int size = (int) (reader.getPointerIndex() - offset);
|
||||
return new LEB128(offset, value, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned LEB128 value from the BinaryReader and returns a {@link LEB128} instance
|
||||
* that contains the value along with size and position metadata.
|
||||
* <p>
|
||||
* See {@link #readAsLong(BinaryReader, boolean)}.
|
||||
*
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @return a {@link LEB128} instance with the read LEB128 value with metadata
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static LEB128 readUnsignedValue(BinaryReader reader) throws IOException {
|
||||
return readValue(reader, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an signed LEB128 value from the BinaryReader and returns a {@link LEB128} instance
|
||||
* that contains the value along with size and position metadata.
|
||||
* <p>
|
||||
* See {@link #readAsLong(BinaryReader, boolean)}.
|
||||
*
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @return a {@link LEB128} instance with the read LEB128 value with metadata
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static LEB128 readSignedValue(BinaryReader reader) throws IOException {
|
||||
return readValue(reader, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a LEB128 signed number from the BinaryReader and returns it as a java 32 bit int.
|
||||
* <p>
|
||||
* If the value of the number can not fit in the int type, an {@link IOException} will
|
||||
* be thrown.
|
||||
*
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @return signed int32 value
|
||||
* @throws IOException if error reading bytes or value is outside the
|
||||
* range of a signed int32
|
||||
*/
|
||||
public static int readAsInt32(BinaryReader reader) throws IOException {
|
||||
long tmp = readAsLong(reader, true);
|
||||
ensureInt32s(tmp);
|
||||
return (int) tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a LEB128 unsigned number from the BinaryReader and returns it as a java 32 bit int.
|
||||
* <p>
|
||||
* If the value of the number can not fit in the positive range of the int type,
|
||||
* an {@link IOException} will be thrown.
|
||||
*
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @return unsigned int32 value 0..Integer.MAX_VALUE
|
||||
* @throws IOException if error reading bytes or value is outside the
|
||||
* positive range of a java 32 bit int (ie. 0..Integer.MAX_VALUE)
|
||||
*/
|
||||
public static int readAsUInt32(BinaryReader reader) throws IOException {
|
||||
long tmp = readAsLong(reader, false);
|
||||
ensureInt32u(tmp);
|
||||
return (int) tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a LEB128 number from the BinaryReader and returns it as a java 64 bit long int.
|
||||
* <p>
|
||||
* Large unsigned integers that use all 64 bits are be returned in a java native
|
||||
* 'long' type, which is signed. It is up to the caller to treat the value as unsigned.
|
||||
* <p>
|
||||
* Large integers that use more than 64 bits will cause an IOException to be thrown.
|
||||
* <p>
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @param isSigned true if the value is signed
|
||||
* @return long integer value. Caller must treat it as unsigned if isSigned parameter was
|
||||
* set to false
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static long readAsLong(BinaryReader reader, boolean isSigned) throws IOException {
|
||||
int nextByte = 0;
|
||||
int shift = 0;
|
||||
long value = 0;
|
||||
while (true) {
|
||||
nextByte = reader.readNextUnsignedByte();
|
||||
if (shift == 70 || (isSigned == false && shift == 63 && nextByte > 1)) {
|
||||
throw new IOException(
|
||||
"Unsupported LEB128 value, too large to fit in 64bit java long variable");
|
||||
}
|
||||
|
||||
// must cast to long before shifting otherwise shift values greater than 32 cause problems
|
||||
value |= ((long) (nextByte & 0x7F)) << shift;
|
||||
shift += 7;
|
||||
|
||||
if ((nextByte & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((isSigned) && (shift < Long.SIZE) && ((nextByte & 0x40) != 0)) {
|
||||
// 0x40 is the new 'high' sign bit since 0x80 is the continuation flag
|
||||
value |= (-1L << shift);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a LEB128 number from the BinaryReader and returns it as a java 64 bit long int.
|
||||
* <p>
|
||||
* Large unsigned integers that use all 64 bits are be returned in a java native
|
||||
* 'long' type, which is signed. It is up to the caller to treat the value as unsigned.
|
||||
* <p>
|
||||
* Large integers that use more than 64 bits will cause an IOException to be thrown.
|
||||
* <p>
|
||||
* @param reader {@link BinaryReader} to read bytes from
|
||||
* @return long integer value
|
||||
* @throws IOException if an I/O error occurs or value is outside the range of a java
|
||||
* 64 bit int
|
||||
*/
|
||||
public static long readUnsignedAsLong(BinaryReader reader) throws IOException {
|
||||
return readAsLong(reader, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a LEB128 number from a byte array and returns it as a long.
|
||||
* <p>
|
||||
* See {@link #readAsLong(BinaryReader, boolean)}.
|
||||
*
|
||||
* @param bytes the bytes representing the LEB128 number
|
||||
* @param isSigned true if the value is signed
|
||||
* @return long integer value. Caller must treat it as unsigned if isSigned parameter was
|
||||
* set to false
|
||||
* @throws IOException if error reading bytes or value is outside the
|
||||
* range of a java 64 bit int
|
||||
*/
|
||||
public static long decode(byte[] bytes, boolean isSigned) throws IOException {
|
||||
return decode(bytes, 0, isSigned);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a LEB128 number from a byte array and returns it as a long.
|
||||
* <p>
|
||||
* See {@link #readAsLong(BinaryReader, boolean)}.
|
||||
*
|
||||
* @param bytes the bytes representing the LEB128 number
|
||||
* @param offset offset in byte array of where to start reading bytes
|
||||
* @param isSigned true if the value is signed
|
||||
* @return long integer value. Caller must treat it as unsigned if isSigned parameter was
|
||||
* set to false
|
||||
* @throws IOException if error reading bytes or value is outside the
|
||||
* range of a java 64 bit int
|
||||
*/
|
||||
public static long decode(byte[] bytes, int offset, boolean isSigned) throws IOException {
|
||||
ByteArrayProvider bap = new ByteArrayProvider(bytes);
|
||||
BinaryReader br = new BinaryReader(bap, true);
|
||||
br.setPointerIndex(offset);
|
||||
return readAsLong(br, isSigned);
|
||||
}
|
||||
|
||||
private static void ensureInt32u(long value) throws IOException {
|
||||
if (value < 0 || value > Integer.MAX_VALUE) {
|
||||
throw new IOException("LEB128 value out of range for java 32 bit unsigned int: " +
|
||||
Long.toUnsignedString(value));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureInt32s(long value) throws IOException {
|
||||
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||
throw new IOException(
|
||||
"LEB128 value out of range for java 32 bit signed int: " +
|
||||
Long.toString(value));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+10
-7
@@ -18,10 +18,12 @@ package ghidra.app.util.bin.format.dwarf4.attribs;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.*;
|
||||
import ghidra.app.util.bin.format.dwarf4.DWARFCompilationUnit;
|
||||
import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -73,7 +75,7 @@ public class DWARFAttributeFactory {
|
||||
return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
|
||||
}
|
||||
case DW_FORM_ref_udata: {
|
||||
long uoffset = LEB128.readAsLong(reader, false);
|
||||
long uoffset = reader.readNext(LEB128::unsigned);
|
||||
return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
|
||||
}
|
||||
|
||||
@@ -103,7 +105,7 @@ public class DWARFAttributeFactory {
|
||||
return new DWARFBlobAttribute(reader.readNextByteArray(length));
|
||||
}
|
||||
case DW_FORM_block: {
|
||||
int length = LEB128.readAsUInt32(reader);
|
||||
int length = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
if (length < 0 || length > MAX_BLOCK4_SIZE) {
|
||||
throw new IOException("Invalid/bad dw_form_block size: " + length);
|
||||
}
|
||||
@@ -121,12 +123,12 @@ public class DWARFAttributeFactory {
|
||||
case DW_FORM_data8:
|
||||
return new DWARFNumericAttribute(reader.readNextLong());
|
||||
case DW_FORM_sdata:
|
||||
return new DWARFNumericAttribute(LEB128.readAsLong(reader, true));
|
||||
return new DWARFNumericAttribute(reader.readNext(LEB128::signed));
|
||||
case DW_FORM_udata:
|
||||
return new DWARFNumericAttribute(LEB128.readAsLong(reader, false));
|
||||
return new DWARFNumericAttribute(reader.readNext(LEB128::unsigned));
|
||||
|
||||
case DW_FORM_exprloc: {
|
||||
int length = LEB128.readAsUInt32(reader);
|
||||
int length = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
if (length < 0 || length > MAX_BLOCK4_SIZE) {
|
||||
throw new IOException("Invalid/bad dw_form_exprloc size: " + length);
|
||||
}
|
||||
@@ -157,7 +159,8 @@ public class DWARFAttributeFactory {
|
||||
|
||||
// Indirect Form
|
||||
case DW_FORM_indirect:
|
||||
DWARFForm formValue = DWARFForm.find(LEB128.readAsUInt32(reader));
|
||||
DWARFForm formValue =
|
||||
DWARFForm.find(reader.readNextUnsignedVarIntExact(LEB128::unsigned));
|
||||
DWARFAttributeValue value = read(reader, unit, formValue);
|
||||
|
||||
return new DWARFIndirectAttribute(value, formValue);
|
||||
|
||||
+5
-3
@@ -15,12 +15,14 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.dwarf4.expression;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.dwarf4.*;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
import ghidra.util.NumericUtilities;
|
||||
|
||||
/**
|
||||
@@ -137,9 +139,9 @@ public class DWARFExpression {
|
||||
case U_LONG:
|
||||
return reader.readNextLong(); /* & there is no mask for ulong */
|
||||
case S_LEB128:
|
||||
return LEB128.readAsLong(reader, true);
|
||||
return reader.readNext(LEB128::signed);
|
||||
case U_LEB128:
|
||||
return LEB128.readAsLong(reader, false);
|
||||
return reader.readNext(LEB128::unsigned);
|
||||
case SIZED_BLOB:
|
||||
throw new IOException("Can't read SIZED_BLOB as a Long value");
|
||||
case DWARF_INT:
|
||||
|
||||
+3
-15
@@ -17,12 +17,10 @@ package ghidra.app.util.bin.format.elf;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* <code>AndroidElfRelocationData</code> provides a dynamic LEB128 data
|
||||
@@ -33,7 +31,7 @@ import ghidra.program.model.data.DataTypeManager;
|
||||
* component instance. This functionality relies on the 1:1 relationship
|
||||
* between this dynamic datatype and the single component which references it.
|
||||
*/
|
||||
class AndroidElfRelocationData extends AbstractLeb128DataType {
|
||||
class AndroidElfRelocationData extends SignedLeb128DataType {
|
||||
|
||||
private final long relocationOffset;
|
||||
|
||||
@@ -44,7 +42,7 @@ class AndroidElfRelocationData extends AbstractLeb128DataType {
|
||||
* @param relocationOffset relocation offset associated with component.
|
||||
*/
|
||||
AndroidElfRelocationData(DataTypeManager dtm, long relocationOffset) {
|
||||
super("sleb128", true, dtm);
|
||||
super(dtm);
|
||||
this.relocationOffset = relocationOffset;
|
||||
}
|
||||
|
||||
@@ -54,21 +52,11 @@ class AndroidElfRelocationData extends AbstractLeb128DataType {
|
||||
throw new UnsupportedOperationException("may not be cloned");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMnemonic(Settings settings) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Android Packed Relocation Data for ELF";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
return "sleb128";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
|
||||
return null;
|
||||
|
||||
+30
-25
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.elf.AndroidElfRelocationTableDataType.LEB128Info;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
@@ -78,13 +78,15 @@ class AndroidElfRelocationGroup extends DynamicDataType {
|
||||
|
||||
ArrayList<DataTypeComponent> list = new ArrayList<>();
|
||||
|
||||
LEB128Info sleb128 = LEB128Info.parse(reader, true);
|
||||
long groupSize = sleb128.value;
|
||||
list.add(sleb128.getComponent(this, list.size(), "group_size", null));
|
||||
LEB128Info sleb128 = reader.readNext(LEB128Info::signed);
|
||||
long groupSize = sleb128.asLong();
|
||||
list.add(AndroidElfRelocationTableDataType.getLEB128Component(sleb128, this,
|
||||
list.size(), "group_size", null));
|
||||
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
long groupFlags = sleb128.value;
|
||||
list.add(sleb128.getComponent(this, list.size(), "group_flags", null));
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
long groupFlags = sleb128.asLong();
|
||||
list.add(AndroidElfRelocationTableDataType.getLEB128Component(sleb128, this,
|
||||
list.size(), "group_flags", null));
|
||||
|
||||
boolean groupedByInfo = (groupFlags & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
|
||||
boolean groupedByDelta = (groupFlags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
|
||||
@@ -93,23 +95,26 @@ class AndroidElfRelocationGroup extends DynamicDataType {
|
||||
|
||||
long groupOffsetDelta = 0;
|
||||
if (groupedByDelta) {
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
groupOffsetDelta = sleb128.value;
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
groupOffsetDelta = sleb128.asLong();
|
||||
|
||||
long minOffset = baseRelocOffset + groupOffsetDelta;
|
||||
String rangeStr = "First relocation offset: 0x" + Long.toHexString(minOffset);
|
||||
|
||||
list.add(sleb128.getComponent(this, list.size(), "group_offsetDelta", rangeStr));
|
||||
list.add(AndroidElfRelocationTableDataType.getLEB128Component(sleb128, this,
|
||||
list.size(), "group_offsetDelta", rangeStr));
|
||||
}
|
||||
|
||||
if (groupedByInfo) {
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
list.add(sleb128.getComponent(this, list.size(), "group_info", null));
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
list.add(AndroidElfRelocationTableDataType.getLEB128Component(sleb128, this,
|
||||
list.size(), "group_info", null));
|
||||
}
|
||||
|
||||
if (groupedByAddend && groupHasAddend) {
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
list.add(sleb128.getComponent(this, list.size(), "group_addend", null));
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
list.add(AndroidElfRelocationTableDataType.getLEB128Component(sleb128, this,
|
||||
list.size(), "group_addend", null));
|
||||
}
|
||||
|
||||
long relocOffset = baseRelocOffset;
|
||||
@@ -124,26 +129,26 @@ class AndroidElfRelocationGroup extends DynamicDataType {
|
||||
relocOffset += groupOffsetDelta;
|
||||
}
|
||||
else {
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
long baseOffset = relocOffset;
|
||||
relocOffset += sleb128.value;
|
||||
relocOffset += sleb128.asLong();
|
||||
DataTypeComponent dtc = new ReadOnlyDataTypeComponent(
|
||||
new AndroidElfRelocationOffset(dataMgr, baseOffset, relocOffset), this,
|
||||
sleb128.byteLength, list.size(), sleb128.offset, "reloc_offset_" + i,
|
||||
null);
|
||||
sleb128.getLength(), list.size(), (int) sleb128.getOffset(),
|
||||
"reloc_offset_" + i, null);
|
||||
list.add(dtc);
|
||||
}
|
||||
|
||||
if (!groupedByInfo) {
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
list.add(sleb128.getComponent(this, list.size(), "reloc_info_" + i, null,
|
||||
relocOffset));
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
list.add(AndroidElfRelocationTableDataType.getLEB128Component(sleb128, this,
|
||||
list.size(), "reloc_info_" + i, null, relocOffset));
|
||||
}
|
||||
|
||||
if (groupHasAddend && !groupedByAddend) {
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
list.add(sleb128.getComponent(this, list.size(), "reloc_addend_" + i, null,
|
||||
relocOffset));
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
list.add(AndroidElfRelocationTableDataType.getLEB128Component(sleb128, this,
|
||||
list.size(), "reloc_addend_" + i, null, relocOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -17,14 +17,12 @@ package ghidra.app.util.bin.format.elf;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.AbstractLeb128DataType;
|
||||
import ghidra.app.util.opinion.ElfLoader;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
|
||||
+23
-45
@@ -15,12 +15,11 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
@@ -64,41 +63,6 @@ public class AndroidElfRelocationTableDataType extends DynamicDataType {
|
||||
return "";
|
||||
}
|
||||
|
||||
static class LEB128Info {
|
||||
|
||||
final int offset;
|
||||
final long value;
|
||||
final int byteLength;
|
||||
|
||||
private LEB128Info(int offset, long value, int byteLength) {
|
||||
this.offset = offset;
|
||||
this.value = value;
|
||||
this.byteLength = byteLength;
|
||||
}
|
||||
|
||||
DataTypeComponent getComponent(DynamicDataType parent, int ordinal, String name,
|
||||
String comment, long relocOffset) {
|
||||
return new ReadOnlyDataTypeComponent(
|
||||
new AndroidElfRelocationData(parent.getDataTypeManager(), relocOffset), parent,
|
||||
byteLength, ordinal, offset, name, comment);
|
||||
}
|
||||
|
||||
DataTypeComponent getComponent(DynamicDataType parent, int ordinal, String name,
|
||||
String comment) {
|
||||
return new ReadOnlyDataTypeComponent(
|
||||
new SignedLeb128DataType(parent.getDataTypeManager()), parent, byteLength, ordinal,
|
||||
offset, name, comment);
|
||||
}
|
||||
|
||||
static LEB128Info parse(BinaryReader reader, boolean signed) throws IOException {
|
||||
long nextPos = reader.getPointerIndex();
|
||||
long value = LEB128.readAsLong(reader, signed);
|
||||
long pos = reader.getPointerIndex();
|
||||
int size = (int) (pos - nextPos);
|
||||
return new LEB128Info((int) nextPos, value, size);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataTypeComponent[] getAllComponents(MemBuffer buf) {
|
||||
|
||||
@@ -118,13 +82,13 @@ public class AndroidElfRelocationTableDataType extends DynamicDataType {
|
||||
null));
|
||||
reader.setPointerIndex(4);
|
||||
|
||||
LEB128Info sleb128 = LEB128Info.parse(reader, true);
|
||||
long remainingRelocations = sleb128.value;
|
||||
list.add(sleb128.getComponent(this, list.size(), "reloc_count", null));
|
||||
LEB128Info sleb128 = reader.readNext(LEB128Info::signed);
|
||||
long remainingRelocations = sleb128.asLong();
|
||||
list.add(getLEB128Component(sleb128, this, list.size(), "reloc_count", null));
|
||||
|
||||
sleb128 = LEB128Info.parse(reader, true);
|
||||
long baseRelocOffset = sleb128.value;
|
||||
list.add(sleb128.getComponent(this, list.size(), "reloc_baseOffset", null));
|
||||
sleb128 = reader.readNext(LEB128Info::signed);
|
||||
long baseRelocOffset = sleb128.asLong();
|
||||
list.add(getLEB128Component(sleb128, this, list.size(), "reloc_baseOffset", null));
|
||||
|
||||
int groupIndex = 0;
|
||||
long groupRelocOffset = baseRelocOffset;
|
||||
@@ -132,7 +96,7 @@ public class AndroidElfRelocationTableDataType extends DynamicDataType {
|
||||
// NOTE: assumes 2-GByte MemBuffer limit
|
||||
int offset = (int) reader.getPointerIndex();
|
||||
|
||||
long groupSize = LEB128.readAsLong(reader, true);
|
||||
long groupSize = reader.readNext(LEB128Info::signed).asLong();
|
||||
if (groupSize > remainingRelocations) {
|
||||
Msg.debug(this, "Group relocation count " + groupSize +
|
||||
" exceeded total count " + remainingRelocations);
|
||||
@@ -166,4 +130,18 @@ public class AndroidElfRelocationTableDataType extends DynamicDataType {
|
||||
}
|
||||
}
|
||||
|
||||
public static DataTypeComponent getLEB128Component(LEB128Info leb128, DynamicDataType parent,
|
||||
int ordinal, String name, String comment, long relocOffset) {
|
||||
return new ReadOnlyDataTypeComponent(
|
||||
new AndroidElfRelocationData(parent.getDataTypeManager(), relocOffset), parent,
|
||||
leb128.getLength(), ordinal, (int) leb128.getOffset(), name, comment);
|
||||
}
|
||||
|
||||
public static DataTypeComponent getLEB128Component(LEB128Info leb128, DynamicDataType parent,
|
||||
int ordinal, String name, String comment) {
|
||||
return new ReadOnlyDataTypeComponent(
|
||||
new SignedLeb128DataType(parent.getDataTypeManager()), parent, leb128.getLength(),
|
||||
ordinal, (int) leb128.getOffset(), name, comment);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-13
@@ -20,9 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
@@ -197,8 +195,8 @@ public class ElfRelocationTable implements ElfFileSection {
|
||||
|
||||
try {
|
||||
int relocationIndex = 0;
|
||||
long remainingRelocations = LEB128.readAsLong(reader, true); // reloc_count
|
||||
long offset = LEB128.readAsLong(reader, true); // reloc_baseOffset
|
||||
long remainingRelocations = reader.readNext(LEB128::signed); // reloc_count
|
||||
long offset = reader.readNext(LEB128::signed); // reloc_baseOffset
|
||||
|
||||
while (remainingRelocations > 0) {
|
||||
|
||||
@@ -206,7 +204,7 @@ public class ElfRelocationTable implements ElfFileSection {
|
||||
long addend = 0;
|
||||
|
||||
// group_size
|
||||
long groupSize = LEB128.readAsLong(reader, true);
|
||||
long groupSize = reader.readNext(LEB128::signed);
|
||||
if (groupSize > remainingRelocations) {
|
||||
elfHeader.logError("Group relocation count " + groupSize +
|
||||
" exceeded total count " + remainingRelocations);
|
||||
@@ -214,7 +212,7 @@ public class ElfRelocationTable implements ElfFileSection {
|
||||
}
|
||||
|
||||
// group_flags
|
||||
long groupFlags = LEB128.readAsLong(reader, true);
|
||||
long groupFlags = reader.readNext(LEB128::signed);
|
||||
boolean groupedByInfo =
|
||||
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
|
||||
boolean groupedByDelta = (groupFlags &
|
||||
@@ -225,28 +223,29 @@ public class ElfRelocationTable implements ElfFileSection {
|
||||
(groupFlags & AndroidElfRelocationGroup.RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
|
||||
|
||||
// group_offsetDelta (optional)
|
||||
long groupOffsetDelta = groupedByDelta ? LEB128.readAsLong(reader, true) : 0;
|
||||
long groupOffsetDelta = groupedByDelta ? reader.readNext(LEB128::signed) : 0;
|
||||
|
||||
// group_info (optional)
|
||||
long groupRInfo = groupedByInfo ? LEB128.readAsLong(reader, true) : 0;
|
||||
long groupRInfo = groupedByInfo ? reader.readNext(LEB128::signed) : 0;
|
||||
|
||||
if (groupedByAddend && groupHasAddend) {
|
||||
// group_addend (optional)
|
||||
addend += LEB128.readAsLong(reader, true);
|
||||
addend += reader.readNext(LEB128::signed);
|
||||
}
|
||||
|
||||
for (int i = 0; i < groupSize; i++) {
|
||||
// reloc_offset (optional)
|
||||
offset += groupedByDelta ? groupOffsetDelta : LEB128.readAsLong(reader, true);
|
||||
offset +=
|
||||
groupedByDelta ? groupOffsetDelta : reader.readNext(LEB128::signed);
|
||||
|
||||
// reloc_info (optional)
|
||||
long info = groupedByInfo ? groupRInfo : LEB128.readAsLong(reader, true);
|
||||
long info = groupedByInfo ? groupRInfo : reader.readNext(LEB128::signed);
|
||||
|
||||
long rAddend = 0;
|
||||
if (groupHasAddend) {
|
||||
if (!groupedByAddend) {
|
||||
// reloc_addend (optional)
|
||||
addend += LEB128.readAsLong(reader, true);
|
||||
addend += reader.readNext(LEB128::signed);
|
||||
}
|
||||
rAddend = addend;
|
||||
}
|
||||
|
||||
+1
-2
@@ -25,7 +25,6 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.MemoryByteProvider;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.app.util.bin.format.elf.info.ElfInfoItem;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.Address;
|
||||
@@ -330,7 +329,7 @@ public class GoBuildInfo implements ElfInfoItem {
|
||||
* @throws IOException if error
|
||||
*/
|
||||
private static byte[] varlenBytes(BinaryReader reader) throws IOException {
|
||||
int strLen = reader.readNextUnsignedVarIntExact(LEB128::readUnsignedAsLong);
|
||||
int strLen = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
byte[] bytes = reader.readNextByteArray(strLen);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
+12
-10
@@ -15,15 +15,17 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.macho.commands;
|
||||
|
||||
import static ghidra.app.util.bin.format.macho.commands.DyldInfoCommandConstants.*;
|
||||
import static ghidra.app.util.bin.format.macho.commands.DyldInfoCommandConstants.EXPORT_SYMBOL_FLAGS_REEXPORT;
|
||||
import static ghidra.app.util.bin.format.macho.commands.DyldInfoCommandConstants.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
/**
|
||||
* Mach-O export trie
|
||||
@@ -105,31 +107,31 @@ public class ExportTrie {
|
||||
private LinkedList<Node> parseNode(String name, int offset) throws IOException {
|
||||
LinkedList<Node> children = new LinkedList<>();
|
||||
reader.setPointerIndex(base + offset);
|
||||
int terminalSize = LEB128.readAsUInt32(reader);
|
||||
int terminalSize = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
long childrenIndex = reader.getPointerIndex() + terminalSize;
|
||||
if (terminalSize != 0) {
|
||||
long flags = LEB128.readAsLong(reader, false);
|
||||
long flags = reader.readNext(LEB128::unsigned);
|
||||
long address = 0;
|
||||
long other = 0;
|
||||
String importName = null;
|
||||
if ((flags & EXPORT_SYMBOL_FLAGS_REEXPORT) != 0) {
|
||||
other = LEB128.readAsLong(reader, false); // dylib ordinal
|
||||
other = reader.readNext(LEB128::unsigned); // dylib ordinal
|
||||
importName = reader.readNextAsciiString();
|
||||
}
|
||||
else {
|
||||
address = LEB128.readAsLong(reader, false);
|
||||
address = reader.readNext(LEB128::unsigned);
|
||||
if ((flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) != 0) {
|
||||
other = LEB128.readAsLong(reader, false);
|
||||
other = reader.readNext(LEB128::unsigned);
|
||||
}
|
||||
}
|
||||
ExportEntry export = new ExportEntry(name, address, flags, other, importName);
|
||||
exports.add(export);
|
||||
}
|
||||
reader.setPointerIndex(childrenIndex);
|
||||
int numChildren = LEB128.readAsUInt32(reader);
|
||||
int numChildren = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
for (int i = 0; i < numChildren; i++) {
|
||||
String childName = reader.readNextAsciiString();
|
||||
int childOffset = LEB128.readAsUInt32(reader);
|
||||
int childOffset = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
children.add(new Node(childName, childOffset));
|
||||
}
|
||||
return children;
|
||||
|
||||
+4
-3
@@ -15,14 +15,15 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.macho.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
/**
|
||||
* Represents a LC_FUNCTION_STARTS command.
|
||||
@@ -80,7 +81,7 @@ public class FunctionStartsCommand extends LinkEditDataCommand {
|
||||
|
||||
List<Long> offsets = new ArrayList<>();
|
||||
while (true) {
|
||||
long offset = LEB128.readAsLong(reader, false);
|
||||
long offset = reader.readNext(LEB128::unsigned);
|
||||
if (offset == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -274,6 +274,23 @@ public class BinaryReaderTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUint32Max() throws IOException {
|
||||
BinaryReader br = br(true, 0xff, 0xff, 0xff, 0x7f, 0xff);
|
||||
int value = br.readNextUnsignedIntExact();
|
||||
Assert.assertEquals(Integer.MAX_VALUE, value);
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void testUint32Overflow() throws IOException {
|
||||
// Test uint32 max overflow with 0xff_ff_ff_ff
|
||||
BinaryReader br = br(true, 0xff, 0xff, 0xff, 0xff, 0xff);
|
||||
int value = br.readNextUnsignedIntExact();
|
||||
Assert.fail(
|
||||
"Should not be able to read a value that is larger than what can fit in java 32 bit int: " +
|
||||
Integer.toUnsignedString(value));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// UTF-16 Unicode String
|
||||
// ------------------------------------------------------------------------------------
|
||||
@@ -546,4 +563,5 @@ public class BinaryReaderTest {
|
||||
BinaryReader br = br(true, -22, -87, 'A', 0);
|
||||
assertEquals("\ufffdA" /* unicode replacement char, 'A'*/, br.readUtf8String(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-13
@@ -17,9 +17,7 @@ package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -30,7 +28,7 @@ public class AnnotationElement implements StructConverter {
|
||||
private EncodedValue value;
|
||||
|
||||
public AnnotationElement(BinaryReader reader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
nameIndex = leb128.asUInt32();
|
||||
nameIndexLength = leb128.getLength();
|
||||
|
||||
@@ -50,22 +48,16 @@ public class AnnotationElement implements StructConverter {
|
||||
DataType encodeValueDataType = value.toDataType();
|
||||
|
||||
String name =
|
||||
"annotation_element" + "_" + nameIndexLength + "_" + encodeValueDataType.getName();
|
||||
"annotation_element_%d_%s".formatted(nameIndexLength, encodeValueDataType.getName());
|
||||
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
|
||||
structure.add(new ArrayDataType(BYTE, nameIndexLength, BYTE.getLength()), "nameIndex",
|
||||
null);
|
||||
structure.add(ULEB128, nameIndexLength, "nameIndex", null);
|
||||
|
||||
structure.add(encodeValueDataType, "value", null);
|
||||
|
||||
structure.setCategoryPath(new CategoryPath("/dex/annotation_element"));
|
||||
// try {
|
||||
// structure.setName( name + "_" + structure.getLength( ) );
|
||||
// }
|
||||
// catch ( Exception e ) {
|
||||
// // ignore
|
||||
// }
|
||||
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-27
@@ -15,19 +15,12 @@
|
||||
*/
|
||||
package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class ClassDataItem implements StructConverter {
|
||||
@@ -48,19 +41,19 @@ public class ClassDataItem implements StructConverter {
|
||||
private List<EncodedMethod> virtualMethods = new ArrayList<>();
|
||||
|
||||
public ClassDataItem(BinaryReader reader, DexHeader dexHeader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
staticFieldsSize = leb128.asUInt32();
|
||||
staticFieldsSizeLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
instanceFieldsSize = leb128.asUInt32();
|
||||
instanceFieldsSizeLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
directMethodsSize = leb128.asUInt32();
|
||||
directMethodsSizeLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
virtualMethodsSize = leb128.asUInt32();
|
||||
virtualMethodsSizeLength = leb128.getLength();
|
||||
|
||||
@@ -137,18 +130,13 @@ public class ClassDataItem implements StructConverter {
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
// int unique = 0;
|
||||
String name =
|
||||
"class_data_item" + "_" + staticFieldsSizeLength + "_" + instanceFieldsSizeLength +
|
||||
"_" + directMethodsSizeLength + "_" + virtualMethodsSizeLength;
|
||||
String name = "class_data_item_%d_%d_%d_%d".formatted(staticFieldsSizeLength,
|
||||
instanceFieldsSizeLength, directMethodsSizeLength, virtualMethodsSizeLength);
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(new ArrayDataType(BYTE, staticFieldsSizeLength, BYTE.getLength()),
|
||||
"static_fields", null);
|
||||
structure.add(new ArrayDataType(BYTE, instanceFieldsSizeLength, BYTE.getLength()),
|
||||
"instance_fields", null);
|
||||
structure.add(new ArrayDataType(BYTE, directMethodsSizeLength, BYTE.getLength()),
|
||||
"direct_methods", null);
|
||||
structure.add(new ArrayDataType(BYTE, virtualMethodsSizeLength, BYTE.getLength()),
|
||||
"virtual_methods", null);
|
||||
structure.add(ULEB128, staticFieldsSizeLength, "static_fields", null);
|
||||
structure.add(ULEB128, instanceFieldsSizeLength, "instance_fields", null);
|
||||
structure.add(ULEB128, directMethodsSizeLength, "direct_methods", null);
|
||||
structure.add(ULEB128, virtualMethodsSizeLength, "virtual_methods", null);
|
||||
// int index = 0;
|
||||
// for ( EncodedField field : staticFields ) {
|
||||
// DataType dataType = field.toDataType( );
|
||||
|
||||
+8
-14
@@ -17,9 +17,7 @@ package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -34,11 +32,11 @@ public class DebugInfoItem implements StructConverter {
|
||||
private byte[] stateMachineOpcodes;
|
||||
|
||||
public DebugInfoItem(BinaryReader reader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
lineStart = leb128.asUInt32();
|
||||
lineStartLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
parametersSize = leb128.asUInt32();
|
||||
parametersSizeLength = leb128.getLength();
|
||||
|
||||
@@ -46,7 +44,7 @@ public class DebugInfoItem implements StructConverter {
|
||||
parameterNamesLengths = new int[parametersSize];
|
||||
|
||||
for (int i = 0; i < parametersSize; ++i) {
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
|
||||
parameterNames[i] = leb128.asUInt32() - 1;// uleb128p1
|
||||
parameterNamesLengths[i] = leb128.getLength();
|
||||
@@ -102,16 +100,12 @@ public class DebugInfoItem implements StructConverter {
|
||||
|
||||
Structure structure = new StructureDataType(builder.toString(), 0);
|
||||
|
||||
structure.add(new ArrayDataType(BYTE, lineStartLength, BYTE.getLength()), "line_start",
|
||||
null);
|
||||
structure.add(new ArrayDataType(BYTE, parametersSizeLength, BYTE.getLength()),
|
||||
"parameters_size", null);
|
||||
structure.add(ULEB128, lineStartLength, "line_start", null);
|
||||
structure.add(ULEB128, parametersSizeLength, "parameters_size", null);
|
||||
|
||||
for (int i = 0; i < parametersSize; ++i) {
|
||||
ArrayDataType dataType =
|
||||
new ArrayDataType(BYTE, parameterNamesLengths[i], BYTE.getLength());
|
||||
structure.add(dataType, "parameter_" + i, null);
|
||||
builder.append(dataType.getLength() + "");
|
||||
structure.add(ULEB128, parameterNamesLengths[i], "parameter_" + i, null);
|
||||
builder.append("%d".formatted(parameterNamesLengths[i]));
|
||||
}
|
||||
|
||||
ArrayDataType stateMachineArray =
|
||||
|
||||
+13
-13
@@ -18,7 +18,7 @@ package ghidra.file.formats.android.dex.format;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.program.model.data.LEB128;
|
||||
|
||||
class DebugInfoStateMachineReader {
|
||||
private static final int MAX_SIZE = 0x10000; // 64k
|
||||
@@ -35,44 +35,44 @@ class DebugInfoStateMachineReader {
|
||||
return (int) (reader.getPointerIndex() - start);//done!
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_ADVANCE_PC: {
|
||||
LEB128.readAsUInt32(reader);
|
||||
reader.readNext(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_ADVANCE_LINE: {
|
||||
LEB128.readAsUInt32(reader);
|
||||
reader.readNext(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_START_LOCAL: {
|
||||
int register = LEB128.readAsUInt32(reader);
|
||||
int register = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
//TODO uleb128p1
|
||||
int name = LEB128.readAsUInt32(reader);
|
||||
int name = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
//TODO uleb128p1
|
||||
int type = LEB128.readAsUInt32(reader);
|
||||
int type = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
break;
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_START_LOCAL_EXTENDED: {
|
||||
int register = LEB128.readAsUInt32(reader);
|
||||
int register = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
//TODO uleb128p1
|
||||
int name = LEB128.readAsUInt32(reader);
|
||||
int name = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
//TODO uleb128p1
|
||||
int type = LEB128.readAsUInt32(reader);
|
||||
int type = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
//TODO uleb128p1
|
||||
int signature = LEB128.readAsUInt32(reader);
|
||||
int signature = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
|
||||
break;
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_END_LOCAL: {
|
||||
int register = LEB128.readAsUInt32(reader);
|
||||
int register = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_RESTART_LOCAL: {
|
||||
int register = LEB128.readAsUInt32(reader);
|
||||
int register = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_SET_PROLOGUE_END: {
|
||||
@@ -83,7 +83,7 @@ class DebugInfoStateMachineReader {
|
||||
}
|
||||
case DebugStateMachineOpCodes.DBG_SET_FILE: {
|
||||
//TODO uleb128p1
|
||||
int name = LEB128.readAsUInt32(reader);
|
||||
int name = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
+7
-9
@@ -15,12 +15,11 @@
|
||||
*/
|
||||
package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -33,11 +32,11 @@ public class EncodedAnnotation implements StructConverter {
|
||||
private List<AnnotationElement> elements = new ArrayList<>();
|
||||
|
||||
public EncodedAnnotation(BinaryReader reader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
typeIndex = leb128.asUInt32();
|
||||
typeIndexLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
size = leb128.asUInt32();
|
||||
sizeLength = leb128.getLength();
|
||||
|
||||
@@ -68,9 +67,8 @@ public class EncodedAnnotation implements StructConverter {
|
||||
|
||||
Structure structure = new StructureDataType(builder.toString(), 0);
|
||||
|
||||
structure.add(new ArrayDataType(BYTE, typeIndexLength, BYTE.getLength()), "typeIndex",
|
||||
null);
|
||||
structure.add(new ArrayDataType(BYTE, sizeLength, BYTE.getLength()), "size", null);
|
||||
structure.add(ULEB128, typeIndexLength, "typeIndex", null);
|
||||
structure.add(ULEB128, sizeLength, "size", null);
|
||||
|
||||
int index = 0;
|
||||
for (AnnotationElement element : elements) {
|
||||
|
||||
+5
-6
@@ -15,13 +15,12 @@
|
||||
*/
|
||||
package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -33,7 +32,7 @@ public class EncodedArray implements StructConverter {
|
||||
private byte[] values;
|
||||
|
||||
public EncodedArray(BinaryReader reader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
size = leb128.asUInt32();
|
||||
sizeLength = leb128.getLength();
|
||||
|
||||
@@ -57,7 +56,7 @@ public class EncodedArray implements StructConverter {
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
Structure structure = new StructureDataType("encoded_array_" + values.length, 0);
|
||||
structure.add(new ArrayDataType(BYTE, sizeLength, BYTE.getLength()), "size", null);
|
||||
structure.add(ULEB128, sizeLength, "size", null);
|
||||
if (values.length > 0) {
|
||||
structure.add(new ArrayDataType(BYTE, values.length, BYTE.getLength()), "values", null);
|
||||
}
|
||||
|
||||
+9
-11
@@ -15,13 +15,12 @@
|
||||
*/
|
||||
package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -34,7 +33,7 @@ public class EncodedCatchHandler implements StructConverter {
|
||||
private int catchAllAddressLength;
|
||||
|
||||
public EncodedCatchHandler(BinaryReader reader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readSignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::signed);
|
||||
size = leb128.asInt32();
|
||||
sizeLength = leb128.getLength();
|
||||
|
||||
@@ -43,7 +42,7 @@ public class EncodedCatchHandler implements StructConverter {
|
||||
}
|
||||
|
||||
if (size <= 0) {// This element is only present if size is non-positive.
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
catchAllAddress = leb128.asUInt32();
|
||||
catchAllAddressLength = leb128.getLength();
|
||||
}
|
||||
@@ -79,10 +78,10 @@ public class EncodedCatchHandler implements StructConverter {
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("encoded_catch_handler_" + sizeLength + "_" + catchAllAddressLength + "_" +
|
||||
handlers.size());
|
||||
builder.append("encoded_catch_handler_%d_%d_%d".formatted(sizeLength, catchAllAddressLength,
|
||||
handlers.size()));
|
||||
Structure structure = new StructureDataType(builder.toString(), 0);
|
||||
structure.add(new ArrayDataType(BYTE, sizeLength, BYTE.getLength()), "size", null);
|
||||
structure.add(ULEB128, sizeLength, "size", null);
|
||||
int index = 0;
|
||||
for (EncodedTypeAddressPair pair : handlers) {
|
||||
DataType dataType = pair.toDataType();
|
||||
@@ -90,8 +89,7 @@ public class EncodedCatchHandler implements StructConverter {
|
||||
builder.append(pair.getDataTypeIdString());
|
||||
}
|
||||
if (size <= 0) {// This element is only present if size is non-positive.
|
||||
structure.add(new ArrayDataType(BYTE, catchAllAddressLength, BYTE.getLength()),
|
||||
"catch_all_addr", null);
|
||||
structure.add(ULEB128, catchAllAddressLength, "catch_all_addr", null);
|
||||
}
|
||||
structure.setCategoryPath(new CategoryPath("/dex/encoded_catch_handler"));
|
||||
try {
|
||||
|
||||
+5
-6
@@ -15,13 +15,12 @@
|
||||
*/
|
||||
package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -32,7 +31,7 @@ public class EncodedCatchHandlerList implements StructConverter {
|
||||
private List<EncodedCatchHandler> handlers = new ArrayList<>();
|
||||
|
||||
public EncodedCatchHandlerList(BinaryReader reader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
size = leb128.asUInt32();
|
||||
sizeLength = leb128.getLength();
|
||||
|
||||
@@ -57,7 +56,7 @@ public class EncodedCatchHandlerList implements StructConverter {
|
||||
// int unique = 0;
|
||||
String name = "encoded_catch_handler_list" + "_" + sizeLength;
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(new ArrayDataType(BYTE, sizeLength, BYTE.getLength()), "size", null);
|
||||
structure.add(ULEB128, sizeLength, "size", null);
|
||||
// int index = 0;
|
||||
// for ( EncodedCatchHandler handler : handlers ) {
|
||||
// DataType dataType = handler.toDataType( );
|
||||
|
||||
+7
-10
@@ -17,9 +17,7 @@ package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -35,12 +33,12 @@ public class EncodedField implements StructConverter {
|
||||
|
||||
public EncodedField(BinaryReader reader) throws IOException {
|
||||
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
_fileOffset = leb128.getOffset();
|
||||
fieldIndexDifference = leb128.asUInt32();
|
||||
fieldIndexDifferenceLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
accessFlags = leb128.asUInt32();
|
||||
accessFlagsLength = leb128.getLength();
|
||||
}
|
||||
@@ -59,12 +57,11 @@ public class EncodedField implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "encoded_field_" + fieldIndexDifferenceLength + "_" + accessFlagsLength;
|
||||
String name =
|
||||
"encoded_field_%d_%d".formatted(fieldIndexDifferenceLength, accessFlagsLength);
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(new ArrayDataType(BYTE, fieldIndexDifferenceLength, BYTE.getLength()),
|
||||
"field_idx_diff", null);
|
||||
structure.add(new ArrayDataType(BYTE, accessFlagsLength, BYTE.getLength()), "accessFlags",
|
||||
null);
|
||||
structure.add(ULEB128, fieldIndexDifferenceLength, "field_idx_diff", null);
|
||||
structure.add(ULEB128, accessFlagsLength, "accessFlags", null);
|
||||
structure.setCategoryPath(new CategoryPath("/dex/encoded_field"));
|
||||
return structure;
|
||||
}
|
||||
|
||||
+10
-19
@@ -17,17 +17,11 @@ package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.file.formats.android.cdex.CDexCodeItem;
|
||||
import ghidra.file.formats.android.cdex.CDexHeader;
|
||||
import ghidra.file.formats.android.dex.util.DexUtil;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
@@ -51,16 +45,16 @@ public class EncodedMethod implements StructConverter {
|
||||
|
||||
public EncodedMethod(BinaryReader reader, DexHeader dexHeader) throws IOException {
|
||||
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
_fileOffset = leb128.getOffset();
|
||||
methodIndexDifference = leb128.asUInt32();
|
||||
methodIndexDifferenceLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
accessFlags = leb128.asUInt32();
|
||||
accessFlagsLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
codeOffset = leb128.asUInt32();
|
||||
codeOffsetLength = leb128.getLength();
|
||||
|
||||
@@ -115,15 +109,12 @@ public class EncodedMethod implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "encoded_method_" + methodIndexDifferenceLength + "_" + accessFlagsLength +
|
||||
"_" + codeOffsetLength;
|
||||
String name = "encoded_method_%d_%d_%d".formatted(methodIndexDifferenceLength,
|
||||
accessFlagsLength, codeOffsetLength);
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(new ArrayDataType(BYTE, methodIndexDifferenceLength, BYTE.getLength()),
|
||||
"method_idx_diff", null);
|
||||
structure.add(new ArrayDataType(BYTE, accessFlagsLength, BYTE.getLength()), "access_flags",
|
||||
null);
|
||||
structure.add(new ArrayDataType(BYTE, codeOffsetLength, BYTE.getLength()), "code_off",
|
||||
null);
|
||||
structure.add(ULEB128, methodIndexDifferenceLength, "method_idx_diff", null);
|
||||
structure.add(ULEB128, accessFlagsLength, "access_flags", null);
|
||||
structure.add(ULEB128, codeOffsetLength, "code_off", null);
|
||||
structure.setCategoryPath(new CategoryPath("/dex/encoded_method"));
|
||||
return structure;
|
||||
}
|
||||
|
||||
+6
-8
@@ -17,9 +17,7 @@ package ghidra.file.formats.android.dex.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -32,11 +30,11 @@ public class EncodedTypeAddressPair implements StructConverter {
|
||||
private int addressLength;// in bytes
|
||||
|
||||
public EncodedTypeAddressPair(BinaryReader reader) throws IOException {
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
typeIndex = leb128.asUInt32();
|
||||
typeIndexLength = leb128.getLength();
|
||||
|
||||
leb128 = LEB128.readUnsignedValue(reader);
|
||||
leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
address = leb128.asUInt32();
|
||||
addressLength = leb128.getLength();
|
||||
}
|
||||
@@ -60,9 +58,9 @@ public class EncodedTypeAddressPair implements StructConverter {
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
Structure structure = new StructureDataType(
|
||||
"encoded_type_addr_pair_" + typeIndexLength + "_" + addressLength, 0);
|
||||
structure.add(new ArrayDataType(BYTE, typeIndexLength, BYTE.getLength()), "type_idx", null);
|
||||
structure.add(new ArrayDataType(BYTE, addressLength, BYTE.getLength()), "addr", null);
|
||||
"encoded_type_addr_pair_%d_%d".formatted(typeIndexLength, addressLength), 0);
|
||||
structure.add(ULEB128, typeIndexLength, "type_idx", null);
|
||||
structure.add(ULEB128, addressLength, "addr", null);
|
||||
structure.setCategoryPath(new CategoryPath("/dex/encoded_type_addr_pair"));
|
||||
return structure;
|
||||
}
|
||||
|
||||
+4
-5
@@ -18,9 +18,7 @@ package ghidra.file.formats.android.dex.format;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.app.util.bin.format.dwarf4.LEB128;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.file.formats.android.dex.util.DexUtil;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
@@ -42,9 +40,10 @@ public class StringDataItem implements StructConverter {
|
||||
|
||||
reader = reader.clone(DexUtil.adjustOffset(stringItem.getStringDataOffset(), dexHeader));
|
||||
|
||||
LEB128 leb128 = LEB128.readUnsignedValue(reader);
|
||||
LEB128Info leb128 = reader.readNext(LEB128Info::unsigned);
|
||||
stringLength = leb128.asUInt32();
|
||||
lebLength = leb128.getLength();
|
||||
|
||||
long nullTermIndex =
|
||||
getIndexOfByteValue(reader, reader.getPointerIndex(), MAX_STRING_LEN, (byte) 0);
|
||||
actualLength = (int) (nullTermIndex - reader.getPointerIndex() + 1);
|
||||
@@ -72,7 +71,7 @@ public class StringDataItem implements StructConverter {
|
||||
@Override
|
||||
public DataType toDataType() {
|
||||
Structure structure = new StructureDataType("string_data_item_" + actualLength, 0);
|
||||
structure.add(new ArrayDataType(BYTE, lebLength, BYTE.getLength()), "utf16_size", null);
|
||||
structure.add(ULEB128, lebLength, "utf16_size", null);
|
||||
structure.add(UTF8, actualLength, "data", null);
|
||||
try {
|
||||
structure.setCategoryPath(new CategoryPath("/dex/string_data_item"));
|
||||
|
||||
+15
-7
@@ -28,6 +28,7 @@ public class FormatSettingsDefinition implements EnumSettingsDefinition {
|
||||
|
||||
//NOTE: if these strings change, the XML needs to changed also...
|
||||
private static final String[] choices = { "hex", "decimal", "binary", "octal", "char" };
|
||||
private static final String[] valuePostfix = { "h", "", "b", "o", "" };
|
||||
private static final int[] radix = { 16, 10, 2, 8, 0 };
|
||||
|
||||
protected static final String FORMAT = "format";
|
||||
@@ -52,7 +53,8 @@ public class FormatSettingsDefinition implements EnumSettingsDefinition {
|
||||
* Returns the format based on the specified settings
|
||||
*
|
||||
* @param settings the instance settings or null for default value.
|
||||
* @return the format value (HEX, DECIMAL, BINARY, OCTAL, CHAR)
|
||||
* @return the format value (HEX, DECIMAL, BINARY, OCTAL, CHAR), or HEX if invalid
|
||||
* data in the FORMAT settings value
|
||||
*/
|
||||
public int getFormat(Settings settings) {
|
||||
if (settings == null) {
|
||||
@@ -76,12 +78,18 @@ public class FormatSettingsDefinition implements EnumSettingsDefinition {
|
||||
* @return the format radix
|
||||
*/
|
||||
public int getRadix(Settings settings) {
|
||||
try {
|
||||
return radix[getFormat(settings)];
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
return 16;
|
||||
}
|
||||
return radix[getFormat(settings)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a descriptive string suffix that should be appended after converting a value
|
||||
* using the radix returned by {@link #getRadix(Settings)}.
|
||||
*
|
||||
* @param settings the instance settings
|
||||
* @return string suffix, such as "h" for HEX, "o" for octal
|
||||
*/
|
||||
public String getRepresentationPostfix(Settings settings) {
|
||||
return valuePostfix[getFormat(settings)];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/* ###
|
||||
* 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.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
/**
|
||||
* An abstract base class for a LEB128 variable length integer data type.
|
||||
* <p>
|
||||
* See {@link LEB128}.
|
||||
*/
|
||||
public abstract class AbstractLeb128DataType extends BuiltIn implements Dynamic {
|
||||
|
||||
/* package */ static final FormatSettingsDefinition FORMAT = FormatSettingsDefinition.DEF_HEX;
|
||||
|
||||
private static SettingsDefinition[] SETTINGS_DEFS = { FORMAT };
|
||||
|
||||
private final boolean signed;
|
||||
|
||||
/**
|
||||
* Base constructor for a little endian based 128 data type.
|
||||
* @param name name of the leb128 data type that extends this class.
|
||||
* @param signed true if it is signed. false if unsigned.
|
||||
* @param dtm the data type manager to associate with this data type.
|
||||
*/
|
||||
public AbstractLeb128DataType(String name, boolean signed, DataTypeManager dtm) {
|
||||
super(null, name, dtm);
|
||||
this.signed = signed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
|
||||
return SETTINGS_DEFS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength(MemBuffer buf, int maxLength) {
|
||||
if (maxLength < 0) {
|
||||
maxLength = LEB128.MAX_SUPPORTED_LENGTH;
|
||||
}
|
||||
try (InputStream is = buf.getInputStream(0, maxLength)) {
|
||||
return LEB128.getLength(is);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueClass(Settings settings) {
|
||||
return Scalar.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int maxLength) {
|
||||
if (maxLength < 0) {
|
||||
maxLength = LEB128.MAX_SUPPORTED_LENGTH;
|
||||
}
|
||||
|
||||
try (InputStream is = buf.getInputStream(0, maxLength)) {
|
||||
long val = LEB128.read(is, signed);
|
||||
return new Scalar(64 - Long.numberOfLeadingZeros(val), val, signed);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return null; // memory error, or more than 10 bytes long
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
|
||||
Scalar val = (Scalar) getValue(buf, settings, length);
|
||||
if (val == null) {
|
||||
return "??";
|
||||
}
|
||||
|
||||
int radix = FORMAT.getRadix(settings);
|
||||
String postfix = FORMAT.getRepresentationPostfix(settings);
|
||||
|
||||
String valStr = val.toString(radix, false, signed, "", "");
|
||||
return valStr.toUpperCase() + postfix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getReplacementBaseType() {
|
||||
return ByteDataType.dataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSpecifyLength() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
+11
-8
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
@@ -290,16 +291,18 @@ public interface DataType {
|
||||
public URL getDocs();
|
||||
|
||||
/**
|
||||
* Get the interpreted data value in the form of the appropriate Object for this DataType.
|
||||
* This method must return a value consistent with {@link #getValueClass(Settings)}.
|
||||
* Returns the interpreted data value as an instance of the
|
||||
* {@link #getValueClass(Settings) advertised value class}.
|
||||
* <p>
|
||||
* For instance, if this datatype is a {@link Pointer} an Address object or null should be returned.
|
||||
* A Byte, returns a {@link Scalar} object.
|
||||
* For instance, {@link Pointer} data types should return an Address object (or null), or
|
||||
* integer data types should return a {@link Scalar} object.
|
||||
*
|
||||
* @param buf the data buffer.
|
||||
* @param buf the data buffer
|
||||
* @param settings the settings to use.
|
||||
* @param length the number of bytes to get the value from.
|
||||
* @return the data Object.
|
||||
* @param length indicates the maximum number of bytes that may be consumed by a
|
||||
* {@link Dynamic} datatype, otherwise this value is ignored. A value of -1 may be specified
|
||||
* to allow a Dynamic datatype to determine the length based upon the actual data bytes
|
||||
* @return the data object, or null if data is invalid
|
||||
*/
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length);
|
||||
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/* ###
|
||||
* 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.io.*;
|
||||
|
||||
/**
|
||||
* Logic for reading LEB128 values.
|
||||
* <p>
|
||||
* LEB128 is a variable length integer encoding that uses 7 bits per byte, with the high bit
|
||||
* being reserved as a continuation flag, with the least significant bytes coming first
|
||||
* (<b>L</b>ittle <b>E</b>ndian <B>B</b>ase <b>128</b>).
|
||||
* <p>
|
||||
* This implementation only supports reading values that decode to at most 64 bits (to fit into
|
||||
* a java long).
|
||||
* <p>
|
||||
* When reading a value, you must already know if it was written as a signed or unsigned value to
|
||||
* be able to decode it correctly.
|
||||
*/
|
||||
public class LEB128 {
|
||||
/**
|
||||
* Max number of bytes that is supported by the deserialization code.
|
||||
*/
|
||||
public static final int MAX_SUPPORTED_LENGTH = 10;
|
||||
|
||||
/**
|
||||
* Reads an unsigned LEB128 variable length integer from the stream.
|
||||
*
|
||||
* @param is {@link InputStream} to get bytes from
|
||||
* @return leb128 value, as a long
|
||||
* @throws IOException if an I/O error occurs or decoded value is outside the range of a java
|
||||
* 64 bit int (or it used more than {@value #MAX_SUPPORTED_LENGTH} bytes to be encoded), or
|
||||
* there is an error or EOF getting a byte from the InputStream before reaching the end of the
|
||||
* encoded value
|
||||
*/
|
||||
public static long unsigned(InputStream is) throws IOException {
|
||||
return read(is, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a signed LEB128 variable length integer from the stream.
|
||||
*
|
||||
* @param is {@link InputStream} to get bytes from
|
||||
* @return leb128 value, as a long
|
||||
* @throws IOException if an I/O error occurs or decoded value is outside the range of a java
|
||||
* 64 bit int (or it used more than {@value #MAX_SUPPORTED_LENGTH} bytes to be encoded), or
|
||||
* there is an error or EOF getting a byte from the InputStream before reaching the end of the
|
||||
* encoded value
|
||||
*/
|
||||
public static long signed(InputStream is) throws IOException {
|
||||
return read(is, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a LEB128 number from the stream and returns it as a java 64 bit long int.
|
||||
* <p>
|
||||
* Large unsigned integers that use all 64 bits are returned in a java native
|
||||
* 'long' type, which is signed. It is up to the caller to treat the value as unsigned.
|
||||
* <p>
|
||||
* Large integers that use more than 64 bits will cause an IOException to be thrown.
|
||||
* <p>
|
||||
* @param is {@link InputStream} to get bytes from
|
||||
* @param isSigned true if the value is signed
|
||||
* @return long integer value. Caller must treat it as unsigned if isSigned parameter was
|
||||
* set to false
|
||||
* @throws IOException if an I/O error occurs or decoded value is outside the range of a java
|
||||
* 64 bit int (or it used more than {@value #MAX_SUPPORTED_LENGTH} bytes to be encoded), or
|
||||
* there is an error or EOF getting a byte from the InputStream before reaching the end of the
|
||||
* encoded value
|
||||
*/
|
||||
public static long read(InputStream is, boolean isSigned) throws IOException {
|
||||
int nextByte = 0;
|
||||
int shift = 0;
|
||||
long value = 0;
|
||||
while (true) {
|
||||
nextByte = is.read();
|
||||
if (nextByte < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
if (shift == 70 || (isSigned == false && shift == 63 && nextByte > 1)) {
|
||||
throw new IOException(
|
||||
"Unsupported LEB128 value, too large to fit in 64bit java long variable");
|
||||
}
|
||||
|
||||
// must cast to long before shifting otherwise shift values greater than 32 cause problems
|
||||
value |= ((long) (nextByte & 0x7F)) << shift;
|
||||
shift += 7;
|
||||
|
||||
if ((nextByte & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((isSigned) && (shift < Long.SIZE) && ((nextByte & 0x40) != 0)) {
|
||||
// 0x40 is the new 'high' sign bit since 0x80 is the continuation flag.
|
||||
// bitwise-or in all the sign-extension bits we need for the value
|
||||
value |= (-1L << shift);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the variable length LEB128 value.
|
||||
*
|
||||
* @param is InputStream to get bytes from
|
||||
* @return length of the LEB128 value, or -1 if the end of the value is not found
|
||||
* @throws IOException if error getting next byte from stream
|
||||
*/
|
||||
public static int getLength(InputStream is) throws IOException {
|
||||
int length = 0;
|
||||
int nextByte;
|
||||
while ((nextByte = is.read()) >= 0 && length < MAX_SUPPORTED_LENGTH) {
|
||||
length++;
|
||||
if ((nextByte & 0x80) == 0) {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a LEB128 number from a byte array and returns it as a long.
|
||||
* <p>
|
||||
* See {@link #read(InputStream, boolean)}
|
||||
*
|
||||
* @param bytes the bytes representing the LEB128 number
|
||||
* @param offset offset in byte array of where to start reading bytes
|
||||
* @param isSigned true if the value is signed
|
||||
* @return long integer value. Caller must treat it as unsigned if isSigned parameter was
|
||||
* set to false
|
||||
* @throws IOException if array offset is invalid, decoded value is outside the range of a java
|
||||
* 64 bit int (or it used more than {@value #MAX_SUPPORTED_LENGTH} bytes to be encoded), or
|
||||
* the end of the array was reached before reaching the end of the encoded value
|
||||
*/
|
||||
public static long decode(byte[] bytes, int offset, boolean isSigned) throws IOException {
|
||||
InputStream is = new ByteArrayInputStream(bytes, offset, bytes.length - offset);
|
||||
return read(is, isSigned);
|
||||
}
|
||||
|
||||
}
|
||||
+7
-15
@@ -13,16 +13,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.exceptionhandlers.gcc.datatype;
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
/**
|
||||
* A Signed Little Endian Base 128 integer data type.
|
||||
*/
|
||||
public class SignedLeb128DataType extends AbstractLeb128DataType {
|
||||
static {
|
||||
ClassTranslator.put("ghidra.app.plugin.exceptionhandlers.gcc.datatype.SignedLeb128DataType",
|
||||
SignedLeb128DataType.class.getName());
|
||||
}
|
||||
|
||||
/** A statically defined SignedLeb128DataType instance.*/
|
||||
public final static SignedLeb128DataType dataType = new SignedLeb128DataType();
|
||||
@@ -50,18 +52,8 @@ public class SignedLeb128DataType extends AbstractLeb128DataType {
|
||||
return new SignedLeb128DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMnemonic(Settings settings) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Signed Dwarf LEB128-Encoded Number";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
return "sleb128";
|
||||
return "Signed LEB128-Encoded Number";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user