mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-2358 Packed protocol for decompiler marshaling
This commit is contained in:
parent
6a1a649213
commit
79c3508f54
119 changed files with 4238 additions and 2207 deletions
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.processors.sleigh;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.symbol.*;
|
||||
|
@ -188,8 +189,9 @@ public abstract class PcodeEmit {
|
|||
* <li>last pcode op has fall-through</li>
|
||||
* <li>internal label used to branch beyond last pcode op</li>
|
||||
* </ul>
|
||||
* @throws IOException for stream errors emitting ops
|
||||
*/
|
||||
void resolveFinalFallthrough() {
|
||||
void resolveFinalFallthrough() throws IOException {
|
||||
try {
|
||||
if (fallOverride == null || fallOverride.equals(getStartAddress().add(fallOffset))) {
|
||||
return;
|
||||
|
@ -207,9 +209,10 @@ public abstract class PcodeEmit {
|
|||
dump(startAddress, PcodeOp.BRANCH, new VarnodeData[] { dest }, 1, null);
|
||||
}
|
||||
|
||||
abstract void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out);
|
||||
abstract void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out)
|
||||
throws IOException;
|
||||
|
||||
private boolean dumpBranchOverride(OpTpl opt) {
|
||||
private boolean dumpBranchOverride(OpTpl opt) throws IOException {
|
||||
int opcode = opt.getOpcode();
|
||||
VarnodeTpl[] inputs = opt.getInput();
|
||||
if (opcode == PcodeOp.CALL) {
|
||||
|
@ -227,7 +230,7 @@ public abstract class PcodeEmit {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void dumpNullReturn() {
|
||||
private void dumpNullReturn() throws IOException {
|
||||
|
||||
VarnodeTpl nullAddr =
|
||||
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.REAL, 0),
|
||||
|
@ -237,7 +240,7 @@ public abstract class PcodeEmit {
|
|||
dump(retOpt);
|
||||
}
|
||||
|
||||
private boolean dumpCallOverride(OpTpl opt, boolean returnAfterCall) {
|
||||
private boolean dumpCallOverride(OpTpl opt, boolean returnAfterCall) throws IOException {
|
||||
int opcode = opt.getOpcode();
|
||||
VarnodeTpl[] inputs = opt.getInput();
|
||||
if (opcode == PcodeOp.BRANCH) {
|
||||
|
@ -316,7 +319,7 @@ public abstract class PcodeEmit {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean dumpReturnOverride(OpTpl opt) {
|
||||
private boolean dumpReturnOverride(OpTpl opt) throws IOException {
|
||||
int opcode = opt.getOpcode();
|
||||
VarnodeTpl[] inputs = opt.getInput();
|
||||
|
||||
|
@ -416,7 +419,7 @@ public abstract class PcodeEmit {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean dumpFlowOverride(OpTpl opt) {
|
||||
private boolean dumpFlowOverride(OpTpl opt) throws IOException {
|
||||
if (flowOverride == null || opt.getOutput() != null) {
|
||||
return false; // only call, branch and return instructions can be affected
|
||||
}
|
||||
|
@ -483,8 +486,9 @@ public abstract class PcodeEmit {
|
|||
* We assume the location of the base pointer is in dyncache[1]
|
||||
* @param dyncache is the existing array
|
||||
* @param vn is the V_OFFSET_PLUS VarnodeTpl to adjust for
|
||||
* @throws IOException for stream errors emitting ops
|
||||
*/
|
||||
private void generatePointerAdd(VarnodeData[] dyncache, VarnodeTpl vn) {
|
||||
private void generatePointerAdd(VarnodeData[] dyncache, VarnodeTpl vn) throws IOException {
|
||||
long offsetPlus = vn.getOffset().getReal() & 0xffff;
|
||||
if (offsetPlus == 0) {
|
||||
return;
|
||||
|
@ -505,7 +509,7 @@ public abstract class PcodeEmit {
|
|||
dyncache[1] = tmpData;
|
||||
}
|
||||
|
||||
private void dump(OpTpl opt) {
|
||||
private void dump(OpTpl opt) throws IOException {
|
||||
|
||||
VarnodeData[] dyncache = null;
|
||||
VarnodeTpl vn, outvn;
|
||||
|
@ -581,7 +585,7 @@ public abstract class PcodeEmit {
|
|||
}
|
||||
|
||||
private void appendBuild(OpTpl bld, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
throws UnknownInstructionException, MemoryAccessException, IOException {
|
||||
// Recover operand index from build statement
|
||||
int index = (int) bld.getInput()[0].getOffset().getReal();
|
||||
Symbol sym = walker.getConstructor().getOperand(index).getDefiningSymbol();
|
||||
|
@ -612,8 +616,10 @@ public abstract class PcodeEmit {
|
|||
* @param op is the DELAYSLOT directive
|
||||
* @throws UnknownInstructionException for problems finding the delay slot Instruction
|
||||
* @throws MemoryAccessException for problems resolving details of the delay slot Instruction
|
||||
* @throws IOException for stream errors emitting ops
|
||||
*/
|
||||
private void delaySlot(OpTpl op) throws UnknownInstructionException, MemoryAccessException {
|
||||
private void delaySlot(OpTpl op)
|
||||
throws UnknownInstructionException, MemoryAccessException, IOException {
|
||||
|
||||
if (inDelaySlot) {
|
||||
throw new SleighException(
|
||||
|
@ -656,9 +662,10 @@ public abstract class PcodeEmit {
|
|||
* @param secnum is the section number of the section containing the CROSSBUILD directive
|
||||
* @throws UnknownInstructionException for problems finding the referenced Instruction
|
||||
* @throws MemoryAccessException for problems resolving details of the referenced Instruction
|
||||
* @throws IOException for stream errors emitting ops
|
||||
*/
|
||||
private void appendCrossBuild(OpTpl bld, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
throws UnknownInstructionException, MemoryAccessException, IOException {
|
||||
if (secnum >= 0) {
|
||||
throw new SleighException(
|
||||
"CROSSBUILD recursion problem for instruction at " + walker.getAddr());
|
||||
|
@ -698,7 +705,7 @@ public abstract class PcodeEmit {
|
|||
}
|
||||
|
||||
public void build(ConstructTpl construct, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
throws UnknownInstructionException, MemoryAccessException, IOException {
|
||||
if (construct == null) {
|
||||
throw new NotYetImplementedException(
|
||||
"Semantics for this instruction are not implemented");
|
||||
|
@ -739,9 +746,10 @@ public abstract class PcodeEmit {
|
|||
* @param secnum index of the section to be built
|
||||
* @throws MemoryAccessException for problems resolving details of the underlying Instruction
|
||||
* @throws UnknownInstructionException for problems finding the underlying Instruction
|
||||
* @throws IOException for stream errors emitting ops
|
||||
*/
|
||||
private void buildEmpty(Constructor ct, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
throws UnknownInstructionException, MemoryAccessException, IOException {
|
||||
int numops = ct.getNumOperands();
|
||||
|
||||
for (int i = 0; i < numops; ++i) {
|
||||
|
|
|
@ -15,22 +15,21 @@
|
|||
*/
|
||||
package ghidra.app.plugin.processors.sleigh;
|
||||
|
||||
import static ghidra.program.model.pcode.AttributeId.*;
|
||||
import static ghidra.program.model.pcode.ElementId.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.InstructionContext;
|
||||
import ghidra.program.model.lang.PackedBytes;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.PcodeOverride;
|
||||
import ghidra.program.model.pcode.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class PcodeEmitPacked extends PcodeEmit {
|
||||
public final static int unimpl_tag = 0x20, inst_tag = 0x21, op_tag = 0x22, void_tag = 0x23,
|
||||
spaceid_tag = 0x24, addrsz_tag = 0x25, end_tag = 0x60; // End of a number
|
||||
|
||||
public class LabelRef {
|
||||
public int opIndex; // Index of operation referencing the label
|
||||
|
@ -46,33 +45,32 @@ public class PcodeEmitPacked extends PcodeEmit {
|
|||
}
|
||||
}
|
||||
|
||||
private PackedBytes buf;
|
||||
private PatchEncoder encoder;
|
||||
private ArrayList<LabelRef> labelref = null;
|
||||
|
||||
/**
|
||||
* Pcode emitter constructor for producing a packed binary representation
|
||||
* for unimplemented or empty responses.
|
||||
*/
|
||||
public PcodeEmitPacked() {
|
||||
super();
|
||||
buf = new PackedBytes(64);
|
||||
}
|
||||
private boolean hasRelativePatch = false;
|
||||
|
||||
/**
|
||||
* Pcode emitter constructor for producing a packed binary representation.
|
||||
* @param encoder is the stream encoder to emit to
|
||||
* @param walk parser walker
|
||||
* @param ictx instruction contexts
|
||||
* @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions)
|
||||
* @param override required if pcode overrides are to be utilized
|
||||
*/
|
||||
public PcodeEmitPacked(ParserWalker walk, InstructionContext ictx, int fallOffset,
|
||||
PcodeOverride override) {
|
||||
public PcodeEmitPacked(PatchEncoder encoder, ParserWalker walk, InstructionContext ictx,
|
||||
int fallOffset, PcodeOverride override) {
|
||||
super(walk, ictx, fallOffset, override);
|
||||
buf = new PackedBytes(512);
|
||||
this.encoder = encoder;
|
||||
}
|
||||
|
||||
public PackedBytes getPackedBytes() {
|
||||
return buf;
|
||||
public void emitHeader() throws IOException {
|
||||
encoder.openElement(ELEM_INST);
|
||||
encoder.writeSignedInteger(ATTRIB_OFFSET, getFallOffset());
|
||||
AddressXML.encode(encoder, getStartAddress());
|
||||
}
|
||||
|
||||
public void emitTail() throws IOException {
|
||||
encoder.closeElement(ELEM_INST);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,8 +88,9 @@ public class PcodeEmitPacked extends PcodeEmit {
|
|||
mask >>>= (8 - ref.labelSize) * 8;
|
||||
res &= mask;
|
||||
}
|
||||
// We need to skip over op_tag, op_code, void_tag, addrsz_tag, and spc bytes
|
||||
insertOffset(ref.streampos + 5, res); // Insert the final offset into the stream
|
||||
if (!encoder.patchIntegerAttribute(ref.streampos, ATTRIB_OFFSET, res)) {
|
||||
throw new SleighException("PcodeEmitPacked: Unable to patch relative offset");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,92 +99,60 @@ public class PcodeEmitPacked extends PcodeEmit {
|
|||
*/
|
||||
@Override
|
||||
void addLabelRef() {
|
||||
// We know we need to do patching on a particular input parameter
|
||||
if (labelref == null) {
|
||||
labelref = new ArrayList<>();
|
||||
}
|
||||
// Delay putting in the LabelRef until we are ready to emit the parameter
|
||||
hasRelativePatch = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the LabelRef now that the next element written will be the parameter needing a patch
|
||||
*/
|
||||
private void addLabelRefDelayed() {
|
||||
int labelIndex = (int) incache[0].offset;
|
||||
int labelSize = incache[0].size;
|
||||
// Force the emitter to write out a maximum length encoding (12 bytes) of a long
|
||||
// Force the encoder to write out a maximum length encoding of a long
|
||||
// so that we have space to insert whatever value we need to when this relative is resolved
|
||||
incache[0].offset = -1;
|
||||
|
||||
labelref.add(new LabelRef(numOps, labelIndex, labelSize, buf.size()));
|
||||
labelref.add(new LabelRef(numOps, labelIndex, labelSize, encoder.size()));
|
||||
hasRelativePatch = false; // Mark patch as handled
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#dump(ghidra.program.model.address.Address, int, ghidra.app.plugin.processors.sleigh.VarnodeData[], int, ghidra.app.plugin.processors.sleigh.VarnodeData)
|
||||
*/
|
||||
@Override
|
||||
void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out) {
|
||||
void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out)
|
||||
throws IOException {
|
||||
opcode = checkOverrides(opcode, in);
|
||||
checkOverlays(opcode, in, isize, out);
|
||||
buf.write(op_tag);
|
||||
buf.write(opcode + 0x20);
|
||||
encoder.openElement(ELEM_OP);
|
||||
encoder.writeSignedInteger(ATTRIB_CODE, opcode);
|
||||
encoder.writeSignedInteger(ATTRIB_SIZE, isize);
|
||||
if (out == null) {
|
||||
buf.write(void_tag);
|
||||
encoder.openElement(ELEM_VOID);
|
||||
encoder.closeElement(ELEM_VOID);
|
||||
}
|
||||
else {
|
||||
dumpVarnodeData(out);
|
||||
out.encode(encoder);
|
||||
}
|
||||
int i = 0;
|
||||
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
|
||||
dumpSpaceId(in[0]);
|
||||
i = 1;
|
||||
}
|
||||
else if (hasRelativePatch) {
|
||||
addLabelRefDelayed();
|
||||
}
|
||||
for (; i < isize; ++i) {
|
||||
dumpVarnodeData(in[i]);
|
||||
in[i].encode(encoder);
|
||||
}
|
||||
buf.write(end_tag);
|
||||
encoder.closeElement(ELEM_OP);
|
||||
}
|
||||
|
||||
private void dumpSpaceId(VarnodeData v) {
|
||||
buf.write(spaceid_tag);
|
||||
int spcindex = ((int) v.offset >> AddressSpace.ID_UNIQUE_SHIFT);
|
||||
buf.write(spcindex + 0x20);
|
||||
}
|
||||
|
||||
private void dumpVarnodeData(VarnodeData v) {
|
||||
buf.write(addrsz_tag);
|
||||
int spcindex = v.space.getUnique();
|
||||
buf.write(spcindex + 0x20);
|
||||
dumpOffset(v.offset);
|
||||
buf.write(v.size + 0x20);
|
||||
}
|
||||
|
||||
public void write(int val) {
|
||||
buf.write(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode and dump an integer value to the packed byte stream
|
||||
* @param val is the integer to write
|
||||
*/
|
||||
public void dumpOffset(long val) {
|
||||
while (val != 0) {
|
||||
int chunk = (int) (val & 0x3f);
|
||||
val >>>= 6;
|
||||
buf.write(chunk + 0x20);
|
||||
}
|
||||
buf.write(end_tag);
|
||||
}
|
||||
|
||||
private void insertOffset(int streampos, long val) {
|
||||
while (val != 0) {
|
||||
if (buf.getByte(streampos) == end_tag) {
|
||||
throw new SleighException("Could not properly insert relative jump offset");
|
||||
}
|
||||
int chunk = (int) (val & 0x3f);
|
||||
val >>>= 6;
|
||||
buf.insertByte(streampos, chunk + 0x20);
|
||||
streampos += 1;
|
||||
}
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
if (buf.getByte(streampos) == end_tag) {
|
||||
return;
|
||||
}
|
||||
buf.insertByte(streampos, 0x20); // Zero fill
|
||||
streampos += 1;
|
||||
}
|
||||
throw new SleighException("Could not find terminator while inserting relative jump offset");
|
||||
private void dumpSpaceId(VarnodeData v) throws IOException {
|
||||
encoder.openElement(ELEM_SPACEID);
|
||||
encoder.writeSpaceId(ATTRIB_NAME, v.offset);
|
||||
encoder.closeElement(ELEM_SPACEID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.processors.sleigh;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.assembler.sleigh.sem.AssemblyResolvedPatterns;
|
||||
|
@ -1018,7 +1019,8 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override) {
|
||||
public void getPcodePacked(PatchEncoder encoder, InstructionContext context,
|
||||
PcodeOverride override) throws IOException {
|
||||
int fallOffset = getLength();
|
||||
try {
|
||||
SleighParserContext protoContext = (SleighParserContext) context.getParserContext();
|
||||
|
@ -1037,23 +1039,17 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
|||
}
|
||||
ParserWalker walker = new ParserWalker(protoContext);
|
||||
walker.baseState();
|
||||
PcodeEmitPacked emit = new PcodeEmitPacked(walker, context, fallOffset, override);
|
||||
emit.write(PcodeEmitPacked.inst_tag);
|
||||
emit.dumpOffset(emit.getFallOffset());
|
||||
|
||||
// Write out the sequence number as a space and an offset
|
||||
Address instrAddr = emit.getStartAddress();
|
||||
int spcindex = instrAddr.getAddressSpace().getUnique();
|
||||
emit.write(spcindex + 0x20);
|
||||
emit.dumpOffset(instrAddr.getOffset());
|
||||
PcodeEmitPacked emit =
|
||||
new PcodeEmitPacked(encoder, walker, context, fallOffset, override);
|
||||
|
||||
emit.emitHeader();
|
||||
emit.build(walker.getConstructor().getTempl(), -1);
|
||||
emit.resolveRelatives();
|
||||
if (!isindelayslot) {
|
||||
emit.resolveFinalFallthrough();
|
||||
}
|
||||
emit.write(PcodeEmitPacked.end_tag); // Terminate the inst_tag
|
||||
return emit.getPackedBytes();
|
||||
emit.emitTail();
|
||||
return;
|
||||
}
|
||||
catch (NotYetImplementedException e) {
|
||||
// unimpl
|
||||
|
@ -1061,10 +1057,10 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
|||
catch (Exception e) {
|
||||
Msg.error(this, "Pcode error at " + context.getAddress() + ": " + e.getMessage());
|
||||
}
|
||||
PcodeEmitPacked emit = new PcodeEmitPacked();
|
||||
emit.write(PcodeEmitPacked.unimpl_tag);
|
||||
emit.dumpOffset(length);
|
||||
return emit.getPackedBytes();
|
||||
encoder.clear();
|
||||
encoder.openElement(ElementId.ELEM_UNIMPL);
|
||||
encoder.writeSignedInteger(AttributeId.ATTRIB_OFFSET, length);
|
||||
encoder.closeElement(ElementId.ELEM_UNIMPL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.
|
||||
|
@ -20,15 +19,32 @@
|
|||
*/
|
||||
package ghidra.app.plugin.processors.sleigh;
|
||||
|
||||
import static ghidra.program.model.pcode.AttributeId.*;
|
||||
import static ghidra.program.model.pcode.ElementId.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.pcode.Encoder;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* All the resolved pieces of data needed to build a Varnode
|
||||
*/
|
||||
public class VarnodeData {
|
||||
public AddressSpace space;
|
||||
public long offset;
|
||||
public int size;
|
||||
|
||||
/**
|
||||
* Encode the data to stream as an \<addr> element
|
||||
* @param encoder is the stream encoder
|
||||
* @throws IOException for errors writing to the underlying stream
|
||||
*/
|
||||
public void encode(Encoder encoder) throws IOException {
|
||||
encoder.openElement(ELEM_ADDR);
|
||||
encoder.writeSpace(ATTRIB_SPACE, space);
|
||||
encoder.writeUnsignedInteger(ATTRIB_OFFSET, offset);
|
||||
encoder.writeSignedInteger(ATTRIB_SIZE, size);
|
||||
encoder.closeElement(ELEM_ADDR);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public class InjectContext {
|
|||
public InjectContext() {
|
||||
}
|
||||
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_CONTEXT);
|
||||
baseAddr = AddressXML.decode(decoder);
|
||||
callAddr = AddressXML.decode(decoder);
|
||||
|
|
|
@ -27,7 +27,6 @@ import ghidra.app.plugin.processors.sleigh.template.*;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.*;
|
||||
|
@ -171,11 +170,7 @@ public class InjectPayloadSleigh implements InjectPayload {
|
|||
setupParameters(context, walker);
|
||||
emit.build(pcodeTemplate, -1);
|
||||
}
|
||||
catch (UnknownInstructionException e) { // Should not be happening in a CallFixup
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
catch (MemoryAccessException e) { // Should not be happening in a CallFixup
|
||||
catch (Exception e) { // Should not be happening in a CallFixup
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
@ -236,8 +231,7 @@ public class InjectPayloadSleigh implements InjectPayload {
|
|||
public void encode(Encoder encoder) throws IOException {
|
||||
encoder.openElement(ELEM_PCODE);
|
||||
if (type == CALLMECHANISM_TYPE && subType >= 0) {
|
||||
encoder.writeString(ATTRIB_INJECT,
|
||||
(subType == 0) ? "uponentry" : "uponreturn");
|
||||
encoder.writeString(ATTRIB_INJECT, (subType == 0) ? "uponentry" : "uponreturn");
|
||||
}
|
||||
if (paramShift != 0) {
|
||||
encoder.writeSignedInteger(ATTRIB_PARAMSHIFT, paramShift);
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
*/
|
||||
package ghidra.program.model.lang;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.PcodeOverride;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
|
@ -293,12 +293,14 @@ public interface InstructionPrototype {
|
|||
public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override);
|
||||
|
||||
/**
|
||||
* Same as getPcode but returns the operations in a packed format to optimize transfer to other processes
|
||||
* Same as getPcode but emits the operations directly to an encoder to optimize transfer to other processes
|
||||
* @param encoder is the encoder receiving the operations
|
||||
* @param context the instruction context
|
||||
* @param override if not null, may indicate that different elements of the pcode generation are overridden
|
||||
* @return the set of packed bytes encoding the p-code
|
||||
* @throws IOException for errors writing to any stream underlying the encoder
|
||||
*/
|
||||
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override);
|
||||
public void getPcodePacked(PatchEncoder encoder, InstructionContext context,
|
||||
PcodeOverride override) throws IOException;
|
||||
|
||||
/**
|
||||
* Get an array of PCode operations (micro code) that a particular operand
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
*/
|
||||
package ghidra.program.model.lang;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.PcodeOverride;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
|
@ -155,8 +155,9 @@ public class InvalidPrototype implements InstructionPrototype, ParserContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override) {
|
||||
return null;
|
||||
public void getPcodePacked(PatchEncoder encoder, InstructionContext context,
|
||||
PcodeOverride override) throws IOException {
|
||||
// Does not emit anything
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -365,9 +365,9 @@ public class AddressXML {
|
|||
* Create an address from "space" and "offset" attributes of the current element
|
||||
* @param decoder is the stream decoder
|
||||
* @return the decoded Address
|
||||
* @throws PcodeXMLException for any problems decoding the stream
|
||||
* @throws DecoderException for any problems decoding the stream
|
||||
*/
|
||||
public static Address decodeFromAttributes(Decoder decoder) throws PcodeXMLException {
|
||||
public static Address decodeFromAttributes(Decoder decoder) throws DecoderException {
|
||||
AddressSpace spc = null;
|
||||
long offset = -1;
|
||||
for (;;) {
|
||||
|
@ -397,10 +397,10 @@ public class AddressXML {
|
|||
*
|
||||
* An empty \<addr> element, with no attributes, results in Address.NO_ADDRESS being returned.
|
||||
* @param decoder is the stream decoder
|
||||
* @return Address created from XML info
|
||||
* @throws PcodeXMLException for any problems decoding the stream
|
||||
* @return Address created from decode info
|
||||
* @throws DecoderException for any problems decoding the stream
|
||||
*/
|
||||
public static Address decode(Decoder decoder) throws PcodeXMLException {
|
||||
public static Address decode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement();
|
||||
if (el == ELEM_SPACEID.id()) {
|
||||
AddressSpace spc = decoder.readSpace(ATTRIB_NAME);
|
||||
|
@ -431,6 +431,7 @@ public class AddressXML {
|
|||
}
|
||||
decoder.closeElement(el);
|
||||
if (spc == null) {
|
||||
// EXTERNAL_SPACE is currently a placeholder for an unsupported decompiler address space
|
||||
return Address.NO_ADDRESS;
|
||||
}
|
||||
return spc.getAddress(offset);
|
||||
|
@ -586,7 +587,9 @@ public class AddressXML {
|
|||
encoder.openElement(ELEM_ADDR);
|
||||
encoder.writeSpace(ATTRIB_SPACE, AddressSpace.VARIABLE_SPACE);
|
||||
encoder.writeString(ATTRIB_PIECE1, encodeVarnodePiece(varnodes[0]));
|
||||
encoder.writeString(ATTRIB_PIECE2, encodeVarnodePiece(varnodes[1]));
|
||||
if (varnodes.length > 1) {
|
||||
encoder.writeString(ATTRIB_PIECE2, encodeVarnodePiece(varnodes[1]));
|
||||
}
|
||||
if (varnodes.length > 2) {
|
||||
encoder.writeString(ATTRIB_PIECE3, encodeVarnodePiece(varnodes[2]));
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* An annotation for a data element being transferred to/from a stream
|
||||
*
|
||||
|
@ -36,24 +34,24 @@ import java.util.HashMap;
|
|||
*/
|
||||
public record AttributeId(String name, int id) {
|
||||
|
||||
private static HashMap<String, AttributeId> lookupAttributeId = new HashMap<>();
|
||||
// private static HashMap<String, AttributeId> lookupAttributeId = new HashMap<>();
|
||||
|
||||
public AttributeId {
|
||||
// add new attribute to lookup map
|
||||
if (null != lookupAttributeId.put(name, this)) {
|
||||
throw new RuntimeException("Duplicate AttributeId: " + name);
|
||||
}
|
||||
}
|
||||
// public AttributeId {
|
||||
// // add new attribute to lookup map
|
||||
// if (null != lookupAttributeId.put(name, this)) {
|
||||
// throw new RuntimeException("Duplicate AttributeId: " + name);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Find the id associated with a specific attribute name
|
||||
* @param nm the attribute name
|
||||
* @return the associated id
|
||||
*/
|
||||
public static int find(String nm) {
|
||||
AttributeId res = lookupAttributeId.getOrDefault(nm, ATTRIB_UNKNOWN);
|
||||
return res.id;
|
||||
}
|
||||
// /**
|
||||
// * Find the id associated with a specific attribute name
|
||||
// * @param nm the attribute name
|
||||
// * @return the associated id
|
||||
// */
|
||||
// public static int find(String nm) {
|
||||
// AttributeId res = lookupAttributeId.getOrDefault(nm, ATTRIB_UNKNOWN);
|
||||
// return res.id;
|
||||
// }
|
||||
|
||||
// Common attributes. Attributes with multiple uses
|
||||
public static final AttributeId ATTRIB_CONTENT = new AttributeId("XMLcontent", 1);
|
||||
|
|
|
@ -49,7 +49,7 @@ public class BlockCondition extends BlockGraph {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void decodeHeader(Decoder decoder) throws PcodeXMLException {
|
||||
protected void decodeHeader(Decoder decoder) throws DecoderException {
|
||||
super.decodeHeader(decoder);
|
||||
String opcodename = decoder.readString(AttributeId.ATTRIB_OPCODE);
|
||||
try {
|
||||
|
|
|
@ -85,7 +85,7 @@ public class BlockCopy extends PcodeBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void decodeHeader(Decoder decoder) throws PcodeXMLException {
|
||||
protected void decodeHeader(Decoder decoder) throws DecoderException {
|
||||
super.decodeHeader(decoder);
|
||||
altindex = (int) decoder.readSignedInteger(AttributeId.ATTRIB_ALTINDEX);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ public class BlockGoto extends BlockGraph {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
super.decodeBody(decoder, resolver);
|
||||
int el = decoder.openElement(ELEM_TARGET);
|
||||
int target = (int) decoder.readSignedInteger(ATTRIB_INDEX);
|
||||
|
|
|
@ -156,7 +156,7 @@ public class BlockGraph extends PcodeBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
BlockMap newresolver = new BlockMap(resolver);
|
||||
super.decodeBody(decoder, newresolver);
|
||||
ArrayList<PcodeBlock> tmplist = new ArrayList<>();
|
||||
|
@ -182,9 +182,9 @@ public class BlockGraph extends PcodeBlock {
|
|||
/**
|
||||
* Decode all blocks and edges in this container from a stream.
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException if there are invalid encodings
|
||||
* @throws DecoderException if there are invalid encodings
|
||||
*/
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
BlockMap resolver = new BlockMap(decoder.getAddressFactory());
|
||||
decode(decoder, resolver);
|
||||
resolver.resolveGotoReferences();
|
||||
|
|
|
@ -66,7 +66,7 @@ public class BlockIfGoto extends BlockGraph {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
super.decodeBody(decoder, resolver);
|
||||
int el = decoder.openElement(ELEM_TARGET);
|
||||
int target = (int) decoder.readSignedInteger(ATTRIB_INDEX);
|
||||
|
|
|
@ -59,7 +59,7 @@ public class BlockMultiGoto extends BlockGraph {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
super.decodeBody(decoder, resolver);
|
||||
for (;;) {
|
||||
int el = decoder.peekElement();
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* An object that can ingest bytes from a stream in preparation for decoding
|
||||
*/
|
||||
public interface ByteIngest {
|
||||
|
||||
/**
|
||||
* Clear any previous cached bytes.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Open the ingester for receiving bytes. This establishes the description of the source of
|
||||
* the bytes and maximum number of bytes that can be read
|
||||
* @param max is the maximum number of bytes that can be read
|
||||
* @param source is the description of the byte source
|
||||
*/
|
||||
public void open(int max, String source);
|
||||
|
||||
/**
|
||||
* Ingest bytes from the stream up to (and including) the first 0 byte. This can be called
|
||||
* multiple times to read in bytes in different chunks.
|
||||
* An absolute limit is set on the number of bytes that can be ingested via the
|
||||
* max parameter to a previous call to open(), otherwise an exception is thrown.
|
||||
* @param inStream is the input stream to read from
|
||||
* @throws IOException for errors reading from the stream
|
||||
*/
|
||||
public void ingestStream(InputStream inStream) throws IOException;
|
||||
|
||||
/**
|
||||
* Formal indicator that ingesting of bytes is complete and processing can begin
|
||||
* @throws IOException for errors processing the underlying stream
|
||||
*/
|
||||
public void endIngest() throws IOException;
|
||||
|
||||
/**
|
||||
* @return true if no bytes have yet been ingested via ingestStream()
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
}
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
|
@ -35,41 +33,27 @@ import ghidra.program.model.address.AddressSpace;
|
|||
* whose data can be extracted using a read*(AttributeId) call that is passed the special ATTRIB_CONTENT id.
|
||||
* This attribute will not be traversed by getNextAttributeId().
|
||||
*/
|
||||
public interface Decoder {
|
||||
public interface Decoder extends ByteIngest {
|
||||
|
||||
public AddressFactory getAddressFactory();
|
||||
|
||||
/**
|
||||
* Clear any current decoding state.
|
||||
* Allows the same decoder to be reused. Object is ready for new call to ingestStream.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Prepare to decode a given stream.
|
||||
* Called once before any decoding. Currently this is assumed to make an internal copy of
|
||||
* the stream data, i.e. the input stream is cleared before any decoding takes place.
|
||||
* @param stream is the given input stream to be decode
|
||||
* @param source is a label describing the source of the input stream
|
||||
* @throws PcodeXMLException for errors reading the stream
|
||||
*/
|
||||
public void ingestStream(InputStream stream, String source) throws PcodeXMLException;
|
||||
|
||||
/**
|
||||
* Peek at the next child element of the current parent, without traversing in (opening) it.
|
||||
* The element id is returned, which can be compared to ElementId labels.
|
||||
* If there are no remaining child elements to traverse, 0 is returned.
|
||||
* @return the element id or 0
|
||||
* @throws DecoderException for an unexpected end of stream
|
||||
*/
|
||||
public int peekElement();
|
||||
public int peekElement() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Open (traverse into) the next child element of the current parent.
|
||||
* The child becomes the current parent.
|
||||
* The list of attributes is initialized for use with getNextAttributeId.
|
||||
* @return the id of the child element or 0 if there are no additional children
|
||||
* @throws DecoderException for an unexpected end of stream
|
||||
*/
|
||||
public int openElement();
|
||||
public int openElement() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Open (traverse into) the next child element, which must be of a specific type
|
||||
|
@ -77,35 +61,36 @@ public interface Decoder {
|
|||
* getNextAttributeId. The child must match the given element id or an exception is thrown.
|
||||
* @param elemId is the given element id to match
|
||||
* @return the id of the child element
|
||||
* @throws PcodeXMLException if the expected element is not the next element
|
||||
* @throws DecoderException if the expected element is not the next element
|
||||
*/
|
||||
public int openElement(ElementId elemId) throws PcodeXMLException;
|
||||
public int openElement(ElementId elemId) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Close the current element
|
||||
* The data for the current element is considered fully processed. If the element has additional
|
||||
* children, an exception is thrown. The stream must indicate the end of the element in some way.
|
||||
* @param id is the id of the element to close (which must be the current element)
|
||||
* @throws PcodeXMLException if not at end of expected element
|
||||
* @throws DecoderException if not at end of expected element
|
||||
*/
|
||||
public void closeElement(int id) throws PcodeXMLException;
|
||||
public void closeElement(int id) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Close the current element, skipping any child elements that have not yet been parsed.
|
||||
* This closes the given element, which must be current. If there are child elements that have
|
||||
* not been parsed, this is not considered an error, and they are skipped over in the parse.
|
||||
* @param id is the id of the element to close (which must be the current element)
|
||||
* @throws PcodeXMLException if the indicated element is not the current element
|
||||
* @throws DecoderException if the indicated element is not the current element
|
||||
*/
|
||||
public void closeElementSkipping(int id) throws PcodeXMLException;
|
||||
public void closeElementSkipping(int id) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Get the next attribute id for the current element
|
||||
* Attributes are automatically set up for traversal using this method, when the element is
|
||||
* opened. If all attributes have been traversed (or there are no attributes), 0 is returned.
|
||||
* @return the id of the next attribute or 0
|
||||
* @throws DecoderException for unexpected end of stream
|
||||
*/
|
||||
public int getNextAttributeId();
|
||||
public int getNextAttributeId() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Reset attribute traversal for the current element
|
||||
|
@ -119,9 +104,9 @@ public interface Decoder {
|
|||
* The last attribute, as returned by getNextAttributeId, is treated as a boolean, and its
|
||||
* value is returned.
|
||||
* @return the boolean value associated with the current attribute.
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public boolean readBool() throws PcodeXMLException;
|
||||
public boolean readBool() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Find and parse a specific attribute in the current element as a boolean value
|
||||
|
@ -131,18 +116,18 @@ public interface Decoder {
|
|||
* Parsing via getNextAttributeId is reset.
|
||||
* @param attribId is the specific attribute id to match
|
||||
* @return the boolean value
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public boolean readBool(AttributeId attribId) throws PcodeXMLException;
|
||||
public boolean readBool(AttributeId attribId) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Parse the current attribute as a signed integer value
|
||||
* The last attribute, as returned by getNextAttributeId, is treated as a signed integer,
|
||||
* and its value is returned.
|
||||
* @return the signed integer value associated with the current attribute.
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public long readSignedInteger() throws PcodeXMLException;
|
||||
public long readSignedInteger() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Find and parse a specific attribute in the current element as a signed integer
|
||||
|
@ -152,18 +137,18 @@ public interface Decoder {
|
|||
* Parsing via getNextAttributeId is reset.
|
||||
* @param attribId is the specific attribute id to match
|
||||
* @return the signed integer value
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public long readSignedInteger(AttributeId attribId) throws PcodeXMLException;
|
||||
public long readSignedInteger(AttributeId attribId) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Parse the current attribute as an unsigned integer value
|
||||
* The last attribute, as returned by getNextAttributeId, is treated as an unsigned integer,
|
||||
* and its value is returned.
|
||||
* @return the unsigned integer value associated with the current attribute.
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public long readUnsignedInteger() throws PcodeXMLException;
|
||||
public long readUnsignedInteger() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Find and parse a specific attribute in the current element as an unsigned integer
|
||||
|
@ -173,17 +158,17 @@ public interface Decoder {
|
|||
* Parsing via getNextAttributeId is reset.
|
||||
* @param attribId is the specific attribute id to match
|
||||
* @return the unsigned integer value
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public long readUnsignedInteger(AttributeId attribId) throws PcodeXMLException;
|
||||
public long readUnsignedInteger(AttributeId attribId) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Parse the current attribute as a string
|
||||
* The last attribute, as returned by getNextAttributeId, is returned as a string.
|
||||
* @return the string associated with the current attribute.
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public String readString() throws PcodeXMLException;
|
||||
public String readString() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Find the specific attribute in the current element and return it as a string
|
||||
|
@ -192,17 +177,17 @@ public interface Decoder {
|
|||
* and exception is thrown. Parse via getNextAttributeId is reset.
|
||||
* @param attribId is the specific attribute id to match
|
||||
* @return the string associated with the attribute
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public String readString(AttributeId attribId) throws PcodeXMLException;
|
||||
public String readString(AttributeId attribId) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Parse the current attribute as an address space
|
||||
* The last attribute, as returned by getNextAttributeId, is returned as an address space.
|
||||
* @return the address space associated with the current attribute.
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public AddressSpace readSpace() throws PcodeXMLException;
|
||||
public AddressSpace readSpace() throws DecoderException;
|
||||
|
||||
/**
|
||||
* Find the specific attribute in the current element and return it as an address space
|
||||
|
@ -211,16 +196,16 @@ public interface Decoder {
|
|||
* exception is thrown. Parse via getNextAttributeId is reset.
|
||||
* @param attribId is the specific attribute id to match
|
||||
* @return the address space associated with the attribute
|
||||
* @throws PcodeXMLException if the expected value is not present
|
||||
* @throws DecoderException if the expected value is not present
|
||||
*/
|
||||
public AddressSpace readSpace(AttributeId attribId) throws PcodeXMLException;
|
||||
public AddressSpace readSpace(AttributeId attribId) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Skip parsing of the next element
|
||||
* The element skipped is the one that would be opened by the next call to openElement.
|
||||
* @throws PcodeXMLException if there is no new element
|
||||
* @throws DecoderException if there is no new element
|
||||
*/
|
||||
public default void skipElement() throws PcodeXMLException {
|
||||
public default void skipElement() throws DecoderException {
|
||||
int elemId = openElement();
|
||||
closeElementSkipping(elemId);
|
||||
}
|
||||
|
|
|
@ -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,14 @@
|
|||
package ghidra.program.model.pcode;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Exception thrown when pcode cannot be restored from XML.
|
||||
* Exception thrown for errors decoding decompiler objects from stream
|
||||
*/
|
||||
public class PcodeXMLException extends PcodeException {
|
||||
public PcodeXMLException(String msg) {
|
||||
super("XML comms: "+msg);
|
||||
public class DecoderException extends PcodeException {
|
||||
public DecoderException(String msg) {
|
||||
super("Decoding error: " + msg);
|
||||
}
|
||||
public PcodeXMLException(String msg, Throwable cause) {
|
||||
super("XML comms: "+msg, cause);
|
||||
|
||||
public DecoderException(String msg, Throwable cause) {
|
||||
super("Decoding error: " + msg, cause);
|
||||
}
|
||||
}
|
|
@ -65,7 +65,7 @@ public class DynamicEntry extends SymbolEntry {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int addrel = decoder.openElement(ELEM_HASH);
|
||||
hash = decoder.readUnsignedInteger(ATTRIB_VAL);
|
||||
decoder.closeElement(addrel);
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* An annotation for a specific collection of hierarchical data
|
||||
*
|
||||
|
@ -28,28 +26,28 @@ import java.util.HashMap;
|
|||
* as an attribute.
|
||||
*
|
||||
* @param name unique element name
|
||||
* @param id unqiue element ID
|
||||
* @param id unique element ID
|
||||
*/
|
||||
public record ElementId(String name, int id) {
|
||||
|
||||
private static HashMap<String, ElementId> lookupElementId = new HashMap<>();
|
||||
// private static HashMap<String, ElementId> lookupElementId = new HashMap<>();
|
||||
|
||||
public ElementId {
|
||||
// add new element to lookup map
|
||||
if (null != lookupElementId.put(name, this)) {
|
||||
throw new RuntimeException("Duplicate ElementId instance: " + name);
|
||||
}
|
||||
}
|
||||
// public ElementId {
|
||||
// // add new element to lookup map
|
||||
// if (null != lookupElementId.put(name, this)) {
|
||||
// throw new RuntimeException("Duplicate ElementId instance: " + name);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Find the id associated with a specific element name
|
||||
* @param nm the element name
|
||||
* @return the associated id
|
||||
*/
|
||||
public static int find(String nm) {
|
||||
ElementId res = lookupElementId.getOrDefault(nm, ELEM_UNKNOWN);
|
||||
return res.id;
|
||||
}
|
||||
// /**
|
||||
// * Find the id associated with a specific element name
|
||||
// * @param nm the element name
|
||||
// * @return the associated id
|
||||
// */
|
||||
// public static int find(String nm) {
|
||||
// ElementId res = lookupElementId.getOrDefault(nm, ELEM_UNKNOWN);
|
||||
// return res.id;
|
||||
// }
|
||||
|
||||
public static final ElementId ELEM_DATA = new ElementId("data", 1);
|
||||
public static final ElementId ELEM_INPUT = new ElementId("input", 2);
|
||||
|
@ -364,5 +362,64 @@ public record ElementId(String name, int id) {
|
|||
// raw_arch
|
||||
// public static final ElementId ELEM_RAW_SAVEFILE = new ElementId("raw_savefile", 237);
|
||||
|
||||
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 251);
|
||||
// ghidra_arch
|
||||
public static final int COMMAND_ISNAMEUSED = 239;
|
||||
public static final ElementId ELEM_COMMAND_ISNAMEUSED =
|
||||
new ElementId("command_isnameused", COMMAND_ISNAMEUSED);
|
||||
public static final int COMMAND_GETBYTES = 240;
|
||||
public static final ElementId ELEM_COMMAND_GETBYTES =
|
||||
new ElementId("command_getbytes", COMMAND_GETBYTES);
|
||||
public static final int COMMAND_GETCALLFIXUP = 241;
|
||||
public static final ElementId ELEM_COMMAND_GETCALLFIXUP =
|
||||
new ElementId("command_getcallfixup", COMMAND_GETCALLFIXUP);
|
||||
public static final int COMMAND_GETCALLMECH = 242;
|
||||
public static final ElementId ELEM_COMMAND_GETCALLMECH =
|
||||
new ElementId("command_getcallmech", COMMAND_GETCALLMECH);
|
||||
public static final int COMMAND_GETCALLOTHERFIXUP = 243;
|
||||
public static final ElementId ELEM_COMMAND_GETCALLOTHERFIXUP =
|
||||
new ElementId("command_getcallotherfixup", COMMAND_GETCALLOTHERFIXUP);
|
||||
public static final int COMMAND_GETCODELABEL = 244;
|
||||
public static final ElementId ELEM_COMMAND_GETCODELABEL =
|
||||
new ElementId("command_getcodelabel", COMMAND_GETCODELABEL);
|
||||
public static final int COMMAND_GETCOMMENTS = 245;
|
||||
public static final ElementId ELEM_COMMAND_GETCOMMENTS =
|
||||
new ElementId("command_getcomments", COMMAND_GETCOMMENTS);
|
||||
public static final int COMMAND_GETCPOOLREF = 246;
|
||||
public static final ElementId ELEM_COMMAND_GETCPOOLREF =
|
||||
new ElementId("command_getcpoolref", COMMAND_GETCPOOLREF);
|
||||
public static final int COMMAND_GETDATATYPE = 247;
|
||||
public static final ElementId ELEM_COMMAND_GETDATATYPE =
|
||||
new ElementId("command_getdatatype", COMMAND_GETDATATYPE);
|
||||
public static final int COMMAND_GETEXTERNALREF = 248;
|
||||
public static final ElementId ELEM_COMMAND_GETEXTERNALREF =
|
||||
new ElementId("command_getexternalref", COMMAND_GETEXTERNALREF);
|
||||
public static final int COMMAND_GETMAPPEDSYMBOLS = 249;
|
||||
public static final ElementId ELEM_COMMAND_GETMAPPEDSYMBOLS =
|
||||
new ElementId("command_getmappedsymbols", COMMAND_GETMAPPEDSYMBOLS);
|
||||
public static final int COMMAND_GETNAMESPACEPATH = 250;
|
||||
public static final ElementId ELEM_COMMAND_GETNAMESPACEPATH =
|
||||
new ElementId("command_getnamespacepath", COMMAND_GETNAMESPACEPATH);
|
||||
public static final int COMMAND_GETPCODE = 251;
|
||||
public static final ElementId ELEM_COMMAND_GETPCODE =
|
||||
new ElementId("command_getpcode", COMMAND_GETPCODE);
|
||||
public static final int COMMAND_GETPCODEEXECUTABLE = 252;
|
||||
public static final ElementId ELEM_COMMAND_GETPCODEEXECUTABLE =
|
||||
new ElementId("command_getpcodeexecutable", COMMAND_GETPCODEEXECUTABLE);
|
||||
public static final int COMMAND_GETREGISTER = 253;
|
||||
public static final ElementId ELEM_COMMAND_GETREGISTER =
|
||||
new ElementId("command_getregister", COMMAND_GETREGISTER);
|
||||
public static final int COMMAND_GETREGISTERNAME = 254;
|
||||
public static final ElementId ELEM_COMMAND_GETREGISTERNAME =
|
||||
new ElementId("command_getregistername", COMMAND_GETREGISTERNAME);
|
||||
public static final int COMMAND_GETSTRINGDATA = 255;
|
||||
public static final ElementId ELEM_COMMAND_GETSTRINGDATA =
|
||||
new ElementId("command_getstring", COMMAND_GETSTRINGDATA);
|
||||
public static final int COMMAND_GETTRACKEDREGISTERS = 256;
|
||||
public static final ElementId ELEM_COMMAND_GETTRACKEDREGISTERS =
|
||||
new ElementId("command_gettrackedregisters", COMMAND_GETTRACKEDREGISTERS);
|
||||
public static final int COMMAND_GETUSEROPNAME = 257;
|
||||
public static final ElementId ELEM_COMMAND_GETUSEROPNAME =
|
||||
new ElementId("command_getuseropname", COMMAND_GETUSEROPNAME);
|
||||
|
||||
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 270);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
|
@ -102,8 +103,15 @@ public interface Encoder {
|
|||
void writeSpace(AttributeId attribId, AddressSpace spc) throws IOException;
|
||||
|
||||
/**
|
||||
* Return anything written to the encoder (since the last clear) as a byte array.
|
||||
* @return the array of bytes
|
||||
* Dump all the accumulated bytes in this encoder to the stream.
|
||||
* @param stream is the output stream
|
||||
* @throws IOException for errors during the write operation
|
||||
*/
|
||||
byte[] getBytes();
|
||||
public void writeTo(OutputStream stream) throws IOException;
|
||||
|
||||
/**
|
||||
* The encoder is considered empty if the writeTo() method would output zero bytes
|
||||
* @return true if there are no bytes in the encoder
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public class EquateSymbol extends HighSymbol {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int symel = decoder.openElement(ELEM_EQUATESYMBOL);
|
||||
decodeHeader(decoder);
|
||||
type = DataType.DEFAULT;
|
||||
|
|
|
@ -25,7 +25,6 @@ import ghidra.program.model.lang.*;
|
|||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -418,24 +417,23 @@ public class FunctionPrototype {
|
|||
* Decode the function prototype from a {@code <prototype>} element in the stream.
|
||||
* @param decoder is the stream decoder
|
||||
* @param dtmanage is the DataTypeManager used to parse data-type tags
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public void decodePrototype(Decoder decoder, PcodeDataTypeManager dtmanage)
|
||||
throws PcodeXMLException {
|
||||
throws DecoderException {
|
||||
int node = decoder.openElement(ELEM_PROTOTYPE);
|
||||
modelname = decoder.readString(ATTRIB_MODEL);
|
||||
PrototypeModel protoModel =
|
||||
dtmanage.getProgram().getCompilerSpec().getCallingConvention(modelname);
|
||||
if (protoModel == null) {
|
||||
throw new PcodeXMLException("Bad prototype model name: " + modelname);
|
||||
throw new DecoderException("Bad prototype model name: " + modelname);
|
||||
}
|
||||
hasThis = protoModel.hasThisPointer();
|
||||
String val = decoder.readString(ATTRIB_EXTRAPOP);
|
||||
if (val.equals("unknown")) {
|
||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
try {
|
||||
extrapop = (int) decoder.readSignedInteger(ATTRIB_EXTRAPOP);
|
||||
}
|
||||
else {
|
||||
extrapop = SpecXmlUtils.decodeInt(val);
|
||||
catch (DecoderException e) {
|
||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
}
|
||||
modellock = false;
|
||||
dotdotdot = false;
|
||||
|
|
|
@ -148,7 +148,7 @@ public class HighCodeSymbol extends HighSymbol {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
super.decode(decoder);
|
||||
symbol = null;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ public class HighConstant extends HighVariable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
//int el = decoder.openElement(ElementId.ELEM_HIGH);
|
||||
long symref = 0;
|
||||
for (;;) {
|
||||
|
|
|
@ -218,7 +218,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
return super.newVarnode(sz, addr, id);
|
||||
}
|
||||
|
||||
private void decodeHigh(Decoder decoder) throws PcodeXMLException {
|
||||
private void decodeHigh(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_HIGH);
|
||||
String classstring = decoder.readString(ATTRIB_CLASS);
|
||||
HighVariable var;
|
||||
|
@ -239,13 +239,13 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
var = new HighConstant(this);
|
||||
break;
|
||||
default:
|
||||
throw new PcodeXMLException("Unknown HighVariable class string: " + classstring);
|
||||
throw new DecoderException("Unknown HighVariable class string: " + classstring);
|
||||
}
|
||||
var.decode(decoder);
|
||||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
private void decodeHighlist(Decoder decoder) throws PcodeXMLException {
|
||||
private void decodeHighlist(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_HIGHLIST);
|
||||
while (decoder.peekElement() != 0) {
|
||||
decodeHigh(decoder);
|
||||
|
@ -254,11 +254,11 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int start = decoder.openElement(ELEM_FUNCTION);
|
||||
String name = decoder.readString(ATTRIB_NAME);
|
||||
if (!func.getName().equals(name)) {
|
||||
throw new PcodeXMLException("Function name mismatch: " + func.getName() + " + " + name);
|
||||
throw new DecoderException("Function name mismatch: " + func.getName() + " + " + name);
|
||||
}
|
||||
for (;;) {
|
||||
int subel = decoder.peekElement();
|
||||
|
@ -269,7 +269,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
Address addr = AddressXML.decode(decoder);
|
||||
addr = func.getEntryPoint().getAddressSpace().getOverlayAddress(addr);
|
||||
if (!func.getEntryPoint().equals(addr)) {
|
||||
throw new PcodeXMLException("Mismatched address in function tag");
|
||||
throw new DecoderException("Mismatched address in function tag");
|
||||
}
|
||||
}
|
||||
else if (subel == ELEM_PROTOTYPE.id()) {
|
||||
|
@ -298,7 +298,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
decoder.skipElement();
|
||||
}
|
||||
else {
|
||||
throw new PcodeXMLException("Unknown element in function");
|
||||
throw new DecoderException("Unknown element in function");
|
||||
}
|
||||
}
|
||||
decoder.closeElement(start);
|
||||
|
@ -308,9 +308,9 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
* Decode the Jump Table list for this function from the stream
|
||||
*
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
private void decodeJumpTableList(Decoder decoder) throws PcodeXMLException {
|
||||
private void decodeJumpTableList(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_JUMPTABLELIST);
|
||||
while (decoder.peekElement() != 0) {
|
||||
JumpTable table = new JumpTable(func.getEntryPoint().getAddressSpace());
|
||||
|
@ -422,7 +422,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
return reslocal;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new PcodeXMLException("Bad storage node", e);
|
||||
throw new DecoderException("Bad storage node", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ public class HighGlobal extends HighVariable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
// int el = decoder.openElement(ElementId.ELEM_HIGH);
|
||||
long symref = 0;
|
||||
offset = -1;
|
||||
|
@ -90,7 +90,7 @@ public class HighGlobal extends HighVariable {
|
|||
}
|
||||
symbol = globalMap.newSymbol(symref, addr, symbolType, symbolSize);
|
||||
if (symbol == null) {
|
||||
throw new PcodeXMLException("Bad global storage: " + addr.toString());
|
||||
throw new DecoderException("Bad global storage: " + addr.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class HighLocal extends HighVariable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
//int el = decoder.openElement(ElementId.ELEM_HIGH);
|
||||
long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF);
|
||||
offset = -1;
|
||||
|
@ -60,14 +60,14 @@ public class HighLocal extends HighVariable {
|
|||
break;
|
||||
}
|
||||
if (attribId == AttributeId.ATTRIB_OFFSET.id()) {
|
||||
offset = (int) decoder.readUnsignedInteger();
|
||||
offset = (int) decoder.readSignedInteger();
|
||||
break;
|
||||
}
|
||||
}
|
||||
decodeInstances(decoder);
|
||||
symbol = function.getLocalSymbolMap().getSymbol(symref);
|
||||
if (symbol == null) {
|
||||
throw new PcodeXMLException("HighLocal is missing symbol");
|
||||
throw new DecoderException("HighLocal is missing symbol");
|
||||
}
|
||||
if (offset < 0) {
|
||||
name = symbol.getName();
|
||||
|
|
|
@ -63,7 +63,7 @@ public class HighOther extends HighVariable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
// int el = decoder.openElement(ElementId.ELEM_HIGH);
|
||||
long symref = 0;
|
||||
offset = -1;
|
||||
|
|
|
@ -54,7 +54,7 @@ public class HighParam extends HighLocal {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
super.decode(decoder);
|
||||
HighSymbol sym = getSymbol();
|
||||
slot = sym.getCategoryIndex();
|
||||
|
|
|
@ -134,11 +134,11 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
* @see ghidra.program.model.pcode.PcodeSyntaxTree#readXML(org.jdom.Element)
|
||||
*/
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int start = decoder.openElement(ELEM_PARAMMEASURES);
|
||||
functionname = decoder.readString(ATTRIB_NAME);
|
||||
if (!func.getName().equals(functionname)) {
|
||||
throw new PcodeXMLException(
|
||||
throw new DecoderException(
|
||||
"Function name mismatch: " + func.getName() + " + " + functionname);
|
||||
}
|
||||
for (;;) {
|
||||
|
@ -151,7 +151,7 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
functionaddress =
|
||||
func.getEntryPoint().getAddressSpace().getOverlayAddress(functionaddress);
|
||||
if (!func.getEntryPoint().equals(functionaddress)) {
|
||||
throw new PcodeXMLException("Mismatched address in function tag");
|
||||
throw new DecoderException("Mismatched address in function tag");
|
||||
}
|
||||
}
|
||||
else if (subel == ELEM_PROTO.id()) {
|
||||
|
@ -173,7 +173,7 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
decodeParamMeasure(decoder, outputlist);
|
||||
}
|
||||
else {
|
||||
throw new PcodeXMLException("Unknown tag in parammeasures");
|
||||
throw new DecoderException("Unknown tag in parammeasures");
|
||||
}
|
||||
}
|
||||
decoder.closeElement(start);
|
||||
|
@ -183,10 +183,10 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
* Decode the inputs or outputs list for this function from a stream.
|
||||
* @param decoder is the stream decoder
|
||||
* @param pmlist is populated with the resulting list
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
private void decodeParamMeasure(Decoder decoder, List<ParamMeasure> pmlist)
|
||||
throws PcodeXMLException {
|
||||
throws DecoderException {
|
||||
int el = decoder.openElement();
|
||||
ParamMeasure pm = new ParamMeasure();
|
||||
pm.decode(decoder, this);
|
||||
|
|
|
@ -392,7 +392,7 @@ public class HighSymbol {
|
|||
}
|
||||
encoder.writeSignedInteger(ATTRIB_CAT, category);
|
||||
if (categoryIndex >= 0) {
|
||||
encoder.writeSignedInteger(ATTRIB_INDEX, categoryIndex);
|
||||
encoder.writeUnsignedInteger(ATTRIB_INDEX, categoryIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,7 +408,7 @@ public class HighSymbol {
|
|||
encoder.closeElement(ELEM_SYMBOL);
|
||||
}
|
||||
|
||||
protected void decodeHeader(Decoder decoder) throws PcodeXMLException {
|
||||
protected void decodeHeader(Decoder decoder) throws DecoderException {
|
||||
name = null;
|
||||
id = 0;
|
||||
typelock = false;
|
||||
|
@ -449,16 +449,16 @@ public class HighSymbol {
|
|||
}
|
||||
}
|
||||
if (id == 0) {
|
||||
throw new PcodeXMLException("missing unique symbol id");
|
||||
throw new DecoderException("missing unique symbol id");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode this symbol object and its associated mappings from the stream.
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int symel = decoder.openElement(ELEM_SYMBOL);
|
||||
decodeHeader(decoder);
|
||||
type = dtmanage.decodeDataType(decoder);
|
||||
|
@ -498,7 +498,7 @@ public class HighSymbol {
|
|||
entryList[0] = new MappedEntry(this, newStorage, entry.getPCAdress());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new PcodeXMLException("Unable to parse auto-parameter");
|
||||
throw new DecoderException("Unable to parse auto-parameter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -511,10 +511,10 @@ public class HighSymbol {
|
|||
* @param isGlobal is true if this symbol is being read into a global scope
|
||||
* @param high is the function model that will own the new symbol
|
||||
* @return the new symbol
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public static HighSymbol decodeMapSym(Decoder decoder, boolean isGlobal, HighFunction high)
|
||||
throws PcodeXMLException {
|
||||
throws DecoderException {
|
||||
HighSymbol res = null;
|
||||
int mapel = decoder.openElement(ELEM_MAPSYM);
|
||||
int symel = decoder.peekElement();
|
||||
|
|
|
@ -141,13 +141,13 @@ public abstract class HighVariable {
|
|||
* Decode the data-type and the Varnode instances of this HighVariable.
|
||||
* The "representative" Varnode is also populated.
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
protected void decodeInstances(Decoder decoder) throws PcodeXMLException {
|
||||
protected void decodeInstances(Decoder decoder) throws DecoderException {
|
||||
int repref = (int) decoder.readUnsignedInteger(AttributeId.ATTRIB_REPREF);
|
||||
Varnode rep = function.getRef(repref);
|
||||
if (rep == null) {
|
||||
throw new PcodeXMLException("Undefined varnode reference");
|
||||
throw new DecoderException("Undefined varnode reference");
|
||||
}
|
||||
|
||||
type = null;
|
||||
|
@ -188,7 +188,7 @@ public abstract class HighVariable {
|
|||
/**
|
||||
* Decode this HighVariable from a {@code <high>} element in the stream
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public abstract void decode(Decoder decoder) throws PcodeXMLException;
|
||||
public abstract void decode(Decoder decoder) throws DecoderException;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ public class JumpTable {
|
|||
return num;
|
||||
}
|
||||
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_LOADTABLE);
|
||||
size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
|
||||
num = (int) decoder.readSignedInteger(ATTRIB_NUM);
|
||||
|
@ -160,9 +160,9 @@ public class JumpTable {
|
|||
/**
|
||||
* Decode a JumpTable object from the stream.
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_JUMPTABLE);
|
||||
if (decoder.peekElement() == 0) { // Empty jumptable
|
||||
decoder.closeElement(el);
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class LinkedByteBuffer {
|
||||
|
||||
public static class Position {
|
||||
public ArrayIter seqIter;
|
||||
public byte[] array;
|
||||
public int current;
|
||||
|
||||
public void copy(Position pos) {
|
||||
seqIter = pos.seqIter;
|
||||
array = pos.array;
|
||||
current = pos.current;
|
||||
}
|
||||
|
||||
public final byte getByte() {
|
||||
return array[current];
|
||||
}
|
||||
|
||||
public final byte getBytePlus1() throws DecoderException {
|
||||
int plus1 = current + 1;
|
||||
if (plus1 == array.length) {
|
||||
ArrayIter iter = seqIter.next;
|
||||
if (iter == null) {
|
||||
throw new DecoderException("Unexpected end of stream");
|
||||
}
|
||||
return iter.array[0];
|
||||
}
|
||||
return array[plus1];
|
||||
}
|
||||
|
||||
public final byte getNextByte() throws DecoderException {
|
||||
byte res = array[current];
|
||||
current += 1;
|
||||
if (current != array.length) {
|
||||
return res;
|
||||
}
|
||||
seqIter = seqIter.next;
|
||||
if (seqIter == null) {
|
||||
throw new DecoderException("Unexpected end of stream");
|
||||
}
|
||||
array = seqIter.array;
|
||||
current = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
public final void advancePosition(int skip) throws DecoderException {
|
||||
while (array.length - current <= skip) {
|
||||
skip -= (array.length - current);
|
||||
seqIter = seqIter.next;
|
||||
if (seqIter == null) {
|
||||
throw new DecoderException("Unexpected end of stream");
|
||||
}
|
||||
array = seqIter.array;
|
||||
current = 0;
|
||||
}
|
||||
current += skip;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayIter {
|
||||
public ArrayIter next;
|
||||
public byte[] array;
|
||||
}
|
||||
|
||||
public final static int BUFFER_SIZE = 1024;
|
||||
|
||||
private ArrayIter initialBuffer;
|
||||
private int byteCount;
|
||||
private int maxCount;
|
||||
private ArrayIter currentBuffer;
|
||||
private int currentPos;
|
||||
private String source;
|
||||
|
||||
public LinkedByteBuffer(int max, String src) {
|
||||
initialBuffer = new ArrayIter();
|
||||
currentBuffer = initialBuffer;
|
||||
byteCount = 0;
|
||||
currentPos = 0;
|
||||
maxCount = max;
|
||||
initialBuffer.array = new byte[BUFFER_SIZE];
|
||||
initialBuffer.next = null;
|
||||
source = src;
|
||||
}
|
||||
|
||||
public void ingestStream(InputStream stream) throws IOException {
|
||||
int tok = stream.read();
|
||||
if (tok <= 0) {
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
if (byteCount > maxCount) {
|
||||
throw new IOException("Response buffer size exceded for: " + source);
|
||||
}
|
||||
do {
|
||||
if (currentPos == BUFFER_SIZE) {
|
||||
break;
|
||||
}
|
||||
currentBuffer.array[currentPos++] = (byte) tok;
|
||||
tok = stream.read();
|
||||
}
|
||||
while (tok > 0);
|
||||
byteCount += currentPos;
|
||||
if (tok <= 0) {
|
||||
return; // Reached terminator or end of stream, ingest is finished
|
||||
}
|
||||
// Set up next buffer
|
||||
currentBuffer.next = new ArrayIter();
|
||||
currentBuffer = currentBuffer.next;
|
||||
currentBuffer.array = new byte[BUFFER_SIZE];
|
||||
currentPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a particular byte to the buffer
|
||||
* @param val is the byte value to add
|
||||
*/
|
||||
public void pad(int val) {
|
||||
if (currentPos == BUFFER_SIZE) {
|
||||
byteCount += currentPos;
|
||||
currentBuffer.next = new ArrayIter();
|
||||
currentBuffer = currentBuffer.next;
|
||||
currentBuffer.array = new byte[1];
|
||||
currentPos = 0;
|
||||
}
|
||||
|
||||
currentBuffer.array[currentPos++] = (byte) val;
|
||||
}
|
||||
|
||||
public void getStartPosition(Position position) {
|
||||
position.array = initialBuffer.array;
|
||||
position.current = 0;
|
||||
position.seqIter = initialBuffer;
|
||||
}
|
||||
}
|
|
@ -265,9 +265,9 @@ public class LocalSymbolMap {
|
|||
* Decode a <mapsym> element from the stream.
|
||||
* @param decoder is the stream decoder
|
||||
* @return the reconstructed HighSymbol
|
||||
* @throws PcodeXMLException for problems sub tags
|
||||
* @throws DecoderException for problems sub tags
|
||||
*/
|
||||
private HighSymbol decodeSymbol(Decoder decoder) throws PcodeXMLException {
|
||||
private HighSymbol decodeSymbol(Decoder decoder) throws DecoderException {
|
||||
HighSymbol res = HighSymbol.decodeMapSym(decoder, false, func);
|
||||
insertSymbol(res);
|
||||
return res;
|
||||
|
@ -277,9 +277,9 @@ public class LocalSymbolMap {
|
|||
* Decode a local symbol scope from the stream
|
||||
*
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public void decodeScope(Decoder decoder) throws PcodeXMLException {
|
||||
public void decodeScope(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_LOCALDB);
|
||||
localSpace = decoder.readSpace(ATTRIB_MAIN);
|
||||
int scopeel = decoder.openElement(ELEM_SCOPE);
|
||||
|
@ -308,9 +308,9 @@ public class LocalSymbolMap {
|
|||
/**
|
||||
* Add mapped symbols to this LocalVariableMap, by decoding the <symbollist> and <mapsym> elements
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public void decodeSymbolList(Decoder decoder) throws PcodeXMLException {
|
||||
public void decodeSymbolList(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_SYMBOLLIST);
|
||||
ArrayList<HighSymbol> parms = new ArrayList<>();
|
||||
while (decoder.peekElement() != 0) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public class MappedDataEntry extends MappedEntry {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
super.decode(decoder);
|
||||
data = symbol.getProgram().getListing().getDataAt(storage.getMinAddress());
|
||||
}
|
||||
|
|
|
@ -54,14 +54,14 @@ public class MappedEntry extends SymbolEntry {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
HighFunction function = symbol.function;
|
||||
Program program = function.getFunction().getProgram();
|
||||
|
||||
int addrel = decoder.openElement(ElementId.ELEM_ADDR);
|
||||
int sz = symbol.type.getLength();
|
||||
if (sz == 0) {
|
||||
throw new PcodeXMLException(
|
||||
throw new DecoderException(
|
||||
"Invalid symbol 0-sized data-type: " + symbol.type.getName());
|
||||
}
|
||||
try {
|
||||
|
@ -76,7 +76,7 @@ public class MappedEntry extends SymbolEntry {
|
|||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new PcodeXMLException("Invalid storage: " + e.getMessage());
|
||||
throw new DecoderException("Invalid storage: " + e.getMessage());
|
||||
}
|
||||
decoder.closeElement(addrel);
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.lang;
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -25,6 +24,9 @@ import java.util.Arrays;
|
|||
* It allows the bytes to be edited in the middle of collection
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class PackedBytes {
|
||||
private byte[] out;
|
||||
private int bytecnt;
|
||||
|
@ -62,16 +64,31 @@ public class PackedBytes {
|
|||
*/
|
||||
public void write(int val) {
|
||||
int newcount = bytecnt + 1;
|
||||
if (newcount > out.length)
|
||||
if (newcount > out.length) {
|
||||
out = Arrays.copyOf(out, Math.max(out.length << 1, newcount));
|
||||
}
|
||||
out[bytecnt] = (byte) val;
|
||||
bytecnt = newcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump an array of bytes to the packed byte stream
|
||||
* @param byteArray is the byte array
|
||||
*/
|
||||
public void write(byte[] byteArray) {
|
||||
int newcount = bytecnt + byteArray.length;
|
||||
if (newcount > out.length) {
|
||||
out = Arrays.copyOf(out, Math.max(out.length << 1, newcount));
|
||||
}
|
||||
System.arraycopy(byteArray, 0, out, bytecnt, byteArray.length);
|
||||
bytecnt = newcount;
|
||||
}
|
||||
|
||||
public int find(int start, int val) {
|
||||
while (start < bytecnt) {
|
||||
if (out[start] == val)
|
||||
if (out[start] == val) {
|
||||
return start;
|
||||
}
|
||||
start += 1;
|
||||
}
|
||||
return -1;
|
||||
|
@ -80,7 +97,7 @@ public class PackedBytes {
|
|||
/**
|
||||
* Write the accumulated packed byte stream onto the output stream
|
||||
* @param s is the output stream receiving the bytes
|
||||
* @throws IOException
|
||||
* @throws IOException for stream errors
|
||||
*/
|
||||
public void writeTo(OutputStream s) throws IOException {
|
||||
s.write(out, 0, bytecnt);
|
|
@ -0,0 +1,502 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
/*
|
||||
* A byte-based decoder designed to marshal info to the decompiler efficiently
|
||||
* All bytes in the encoding are expected to be non-zero. Element encoding looks like
|
||||
* - 01xiiiii is an element start
|
||||
* - 10xiiiii is an element end
|
||||
* - 11xiiiii is an attribute start
|
||||
*
|
||||
* Where iiiii is the (first) 5 bits of the element/attribute id.
|
||||
* If x=0, the id is complete. If x=1, the next byte contains 7 more bits of the id: 1iiiiiii
|
||||
*
|
||||
* After an attribute start, there follows a type byte: ttttllll, where the first 4 bits indicate
|
||||
* the type of attribute and final 4 bits are a "length code". The types are:
|
||||
* - 1 = boolean (lengthcode=0 for false, lengthcode=1 for true)
|
||||
* - 2 = positive signed integer
|
||||
* - 3 = negative signed integer (stored in negated form)
|
||||
* - 4 = unsigned integer
|
||||
* - 5 = basic address space (encoded as the integer index of the space)
|
||||
* - 6 = special address space (lengthcode 0=>stack 1=>join 2=>fspec 3=>iop)
|
||||
* - 7 = string
|
||||
*
|
||||
* All attribute types except "boolean" and "special", have an encoded integer after the \e type byte.
|
||||
* The "length code", indicates the number bytes used to encode the integer,
|
||||
* 7-bits of info per byte, 1iiiiiii. A "length code" of 0 is used to encode and integer value
|
||||
* of 0, with no following bytes.
|
||||
*
|
||||
* For strings, the integer encoded after the \e type byte, is the actual length of the string. The
|
||||
* string data itself is stored immediately after the length integer using UTF8 format.
|
||||
* */
|
||||
public class PackedDecode implements Decoder {
|
||||
|
||||
public static final int HEADER_MASK = 0xc0;
|
||||
public static final int ELEMENT_START = 0x40;
|
||||
public static final int ELEMENT_END = 0x80;
|
||||
public static final int ATTRIBUTE = 0xc0;
|
||||
public static final int HEADEREXTEND_MASK = 0x20;
|
||||
public static final int ELEMENTID_MASK = 0x1f;
|
||||
public static final int RAWDATA_MASK = 0x7f;
|
||||
public static final int RAWDATA_BITSPERBYTE = 7;
|
||||
public static final int RAWDATA_MARKER = 0x80;
|
||||
public static final int TYPECODE_SHIFT = 4;
|
||||
public static final int LENGTHCODE_MASK = 0xf;
|
||||
public static final int TYPECODE_BOOLEAN = 1;
|
||||
public static final int TYPECODE_SIGNEDINT_POSITIVE = 2;
|
||||
public static final int TYPECODE_SIGNEDINT_NEGATIVE = 3;
|
||||
public static final int TYPECODE_UNSIGNEDINT = 4;
|
||||
public static final int TYPECODE_ADDRESSSPACE = 5;
|
||||
public static final int TYPECODE_SPECIALSPACE = 6;
|
||||
public static final int TYPECODE_STRING = 7;
|
||||
public static final int SPECIALSPACE_STACK = 0;
|
||||
public static final int SPECIALSPACE_JOIN = 1;
|
||||
public static final int SPECIALSPACE_FSPEC = 2;
|
||||
public static final int SPECIALSPACE_IOP = 3;
|
||||
public static final int SPECIALSPACE_SPACEBASE = 4;
|
||||
|
||||
private AddressFactory addrFactory;
|
||||
private AddressSpace[] spaces;
|
||||
private LinkedByteBuffer inStream;
|
||||
private LinkedByteBuffer.Position startPos;
|
||||
private LinkedByteBuffer.Position curPos;
|
||||
private LinkedByteBuffer.Position endPos;
|
||||
private boolean attributeRead;
|
||||
|
||||
public PackedDecode(AddressFactory addrFactory) {
|
||||
this.addrFactory = addrFactory;
|
||||
inStream = null;
|
||||
startPos = new LinkedByteBuffer.Position();
|
||||
curPos = new LinkedByteBuffer.Position();
|
||||
endPos = new LinkedByteBuffer.Position();
|
||||
buildAddrSpaceArray();
|
||||
}
|
||||
|
||||
private void buildAddrSpaceArray() {
|
||||
ArrayList<AddressSpace> spaceList = new ArrayList<>();
|
||||
AddressSpace[] allSpaces = addrFactory.getAllAddressSpaces();
|
||||
for (AddressSpace spc : allSpaces) {
|
||||
int type = spc.getType();
|
||||
if (type != AddressSpace.TYPE_CONSTANT && type != AddressSpace.TYPE_RAM &&
|
||||
type != AddressSpace.TYPE_REGISTER && type != AddressSpace.TYPE_UNIQUE &&
|
||||
type != AddressSpace.TYPE_OTHER) {
|
||||
continue;
|
||||
}
|
||||
int ind = spc.getUnique();
|
||||
while (spaceList.size() <= ind) {
|
||||
spaceList.add(null);
|
||||
}
|
||||
spaceList.set(ind, spc);
|
||||
}
|
||||
spaces = new AddressSpace[spaceList.size()];
|
||||
spaceList.toArray(spaces);
|
||||
}
|
||||
|
||||
private long readInteger(int len) throws DecoderException {
|
||||
long res = 0;
|
||||
while (len > 0) {
|
||||
res <<= RAWDATA_BITSPERBYTE;
|
||||
res |= (curPos.getNextByte() & RAWDATA_MASK);
|
||||
len -= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private void findMatchingAttribute(AttributeId attribId) throws DecoderException {
|
||||
curPos.copy(startPos);
|
||||
for (;;) {
|
||||
byte header1 = curPos.getByte();
|
||||
if ((header1 & HEADER_MASK) != ATTRIBUTE) {
|
||||
break;
|
||||
}
|
||||
int id = header1 & ELEMENTID_MASK;
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
id <<= RAWDATA_BITSPERBYTE;
|
||||
id |= (curPos.getBytePlus1() & RAWDATA_MASK);
|
||||
}
|
||||
if (attribId.id() == id) {
|
||||
return; // Found it
|
||||
}
|
||||
skipAttribute();
|
||||
}
|
||||
throw new DecoderException("Attribute " + attribId.name() + " is not present");
|
||||
}
|
||||
|
||||
private void skipAttribute() throws DecoderException {
|
||||
byte header1 = curPos.getNextByte(); // Attribute header
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
curPos.getNextByte(); // Extra byte for extended id
|
||||
}
|
||||
byte typeByte = curPos.getNextByte(); // Type (and length) byte
|
||||
int attribType = typeByte >> TYPECODE_SHIFT;
|
||||
if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE) {
|
||||
return; // has no additional data
|
||||
}
|
||||
int length = typeByte & LENGTHCODE_MASK; // Length of data in bytes
|
||||
if (attribType == TYPECODE_STRING) { // For a string
|
||||
length = (int) readInteger(length); // Read length field to get final length of string
|
||||
}
|
||||
curPos.advancePosition(length); // Skip -length- data
|
||||
}
|
||||
|
||||
private void skipAttributeRemaining(byte typeByte) throws DecoderException {
|
||||
int attribType = typeByte >> TYPECODE_SHIFT;
|
||||
if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE) {
|
||||
return; // has no additional data
|
||||
}
|
||||
int length = typeByte & LENGTHCODE_MASK; // Length of data in bytes
|
||||
if (attribType == TYPECODE_STRING) { // For a string
|
||||
length = (int) readInteger(length); // Read length field to get final length of string
|
||||
}
|
||||
curPos.advancePosition(length); // Skip -length- data
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressFactory getAddressFactory() {
|
||||
return addrFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
inStream = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(int max, String source) {
|
||||
inStream = new LinkedByteBuffer(max, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ingestStream(InputStream stream) throws IOException {
|
||||
inStream.ingestStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endIngest() {
|
||||
inStream.pad(ELEMENT_END);
|
||||
inStream.getStartPosition(endPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return (inStream == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekElement() throws DecoderException {
|
||||
byte header1 = endPos.getByte();
|
||||
if ((header1 & HEADER_MASK) != ELEMENT_START) {
|
||||
return 0;
|
||||
}
|
||||
int id = header1 & ELEMENTID_MASK;
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
id <<= RAWDATA_BITSPERBYTE;
|
||||
id |= (endPos.getBytePlus1() & RAWDATA_MASK);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int openElement() throws DecoderException {
|
||||
byte header1 = endPos.getByte();
|
||||
if ((header1 & HEADER_MASK) != ELEMENT_START) {
|
||||
return 0;
|
||||
}
|
||||
endPos.getNextByte();
|
||||
int id = header1 & ELEMENTID_MASK;
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
id <<= RAWDATA_BITSPERBYTE;
|
||||
id |= (endPos.getNextByte() & RAWDATA_MASK);
|
||||
}
|
||||
startPos.copy(endPos);
|
||||
curPos.copy(endPos);
|
||||
header1 = curPos.getByte();
|
||||
while ((header1 & HEADER_MASK) == ATTRIBUTE) {
|
||||
skipAttribute();
|
||||
header1 = curPos.getByte();
|
||||
}
|
||||
endPos.copy(curPos);
|
||||
curPos.copy(startPos);
|
||||
attributeRead = true; // "Last attribute was read" is vacuously true
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int openElement(ElementId elemId) throws DecoderException {
|
||||
int id = openElement();
|
||||
if (id != elemId.id()) {
|
||||
if (id == 0) {
|
||||
throw new DecoderException(
|
||||
"Expecting <" + elemId.name() + "> but did not scan an element");
|
||||
}
|
||||
throw new DecoderException("Expecting <" + elemId.name() + "> but id did not match");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElement(int id) throws DecoderException {
|
||||
byte header1 = endPos.getNextByte();
|
||||
if ((header1 & HEADER_MASK) != ELEMENT_END) {
|
||||
throw new DecoderException("Expecting element close");
|
||||
}
|
||||
int closeId = header1 & ELEMENTID_MASK;
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
closeId <<= RAWDATA_BITSPERBYTE;
|
||||
closeId |= (endPos.getNextByte() & RAWDATA_MASK);
|
||||
}
|
||||
if (id != closeId) {
|
||||
throw new DecoderException("Did not see expected closing element");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElementSkipping(int id) throws DecoderException {
|
||||
ArrayList<Integer> idstack = new ArrayList<>();
|
||||
idstack.add(id);
|
||||
do {
|
||||
int header1 = endPos.getByte() & HEADER_MASK;
|
||||
if (header1 == ELEMENT_END) {
|
||||
int pos = idstack.size() - 1;
|
||||
closeElement(idstack.get(pos));
|
||||
idstack.remove(pos);
|
||||
}
|
||||
else if (header1 == ELEMENT_START) {
|
||||
idstack.add(openElement());
|
||||
}
|
||||
else {
|
||||
throw new DecoderException("Corrupt stream");
|
||||
}
|
||||
}
|
||||
while (!idstack.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextAttributeId() throws DecoderException {
|
||||
if (!attributeRead) {
|
||||
skipAttribute();
|
||||
}
|
||||
byte header1 = curPos.getByte();
|
||||
if ((header1 & HEADER_MASK) != ATTRIBUTE) {
|
||||
return 0;
|
||||
}
|
||||
int id = header1 & ELEMENTID_MASK;
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
id <<= RAWDATA_BITSPERBYTE;
|
||||
id |= (curPos.getBytePlus1() & RAWDATA_MASK);
|
||||
}
|
||||
attributeRead = false;
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewindAttributes() {
|
||||
curPos.copy(startPos);
|
||||
attributeRead = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBool() throws DecoderException {
|
||||
byte header1 = curPos.getNextByte();
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
curPos.getNextByte();
|
||||
}
|
||||
byte typeByte = curPos.getNextByte();
|
||||
if ((typeByte >> TYPECODE_SHIFT) != TYPECODE_BOOLEAN) {
|
||||
throw new DecoderException("Expecting boolean attribute");
|
||||
}
|
||||
attributeRead = true;
|
||||
return ((typeByte & LENGTHCODE_MASK) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBool(AttributeId attribId) throws DecoderException {
|
||||
findMatchingAttribute(attribId);
|
||||
boolean res = readBool();
|
||||
curPos.copy(startPos);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readSignedInteger() throws DecoderException {
|
||||
byte header1 = curPos.getNextByte();
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
curPos.getNextByte();
|
||||
}
|
||||
byte typeByte = curPos.getNextByte();
|
||||
int typeCode = typeByte >> TYPECODE_SHIFT;
|
||||
long res;
|
||||
if (typeCode == TYPECODE_SIGNEDINT_POSITIVE) {
|
||||
res = readInteger(typeByte & LENGTHCODE_MASK);
|
||||
}
|
||||
else if (typeCode == TYPECODE_SIGNEDINT_NEGATIVE) {
|
||||
res = readInteger(typeByte & LENGTHCODE_MASK);
|
||||
res = -res;
|
||||
}
|
||||
else {
|
||||
skipAttributeRemaining(typeByte);
|
||||
throw new DecoderException("Expecting signed integer attribute");
|
||||
}
|
||||
attributeRead = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readSignedInteger(AttributeId attribId) throws DecoderException {
|
||||
findMatchingAttribute(attribId);
|
||||
long res = readSignedInteger();
|
||||
curPos.copy(startPos);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInteger() throws DecoderException {
|
||||
byte header1 = curPos.getNextByte();
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
curPos.getNextByte();
|
||||
}
|
||||
byte typeByte = curPos.getNextByte();
|
||||
int typeCode = typeByte >> TYPECODE_SHIFT;
|
||||
long res;
|
||||
if (typeCode == TYPECODE_UNSIGNEDINT) {
|
||||
res = readInteger(typeByte & 0xf);
|
||||
}
|
||||
else {
|
||||
skipAttributeRemaining(typeByte);
|
||||
throw new DecoderException("Expecting unsigned integer attribute");
|
||||
}
|
||||
attributeRead = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInteger(AttributeId attribId) throws DecoderException {
|
||||
findMatchingAttribute(attribId);
|
||||
long res = readUnsignedInteger();
|
||||
curPos.copy(startPos);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString() throws DecoderException {
|
||||
byte header1 = curPos.getNextByte();
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
curPos.getNextByte();
|
||||
}
|
||||
byte typeByte = curPos.getNextByte();
|
||||
int typeCode = typeByte >> TYPECODE_SHIFT;
|
||||
if (typeCode != TYPECODE_STRING) {
|
||||
skipAttributeRemaining(typeByte);
|
||||
throw new DecoderException("Expecting string attribute");
|
||||
}
|
||||
int length = typeByte & LENGTHCODE_MASK;
|
||||
length = (int) readInteger(length);
|
||||
|
||||
attributeRead = true;
|
||||
int curLen = curPos.array.length - curPos.current;
|
||||
if (curLen >= length) {
|
||||
String res = new String(curPos.array, curPos.current, length);
|
||||
curPos.advancePosition(length);
|
||||
return res;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder();
|
||||
String res = new String(curPos.array, curPos.current, curLen);
|
||||
buf.append(res);
|
||||
length -= curLen;
|
||||
curPos.advancePosition(curLen);
|
||||
while (length > 0) {
|
||||
curLen = curPos.array.length - curPos.current;
|
||||
if (curLen > length) {
|
||||
curLen = length;
|
||||
}
|
||||
res = new String(curPos.array, curPos.current, curLen);
|
||||
buf.append(res);
|
||||
length -= curLen;
|
||||
curPos.advancePosition(curLen);
|
||||
}
|
||||
res = buf.toString();
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(AttributeId attribId) throws DecoderException {
|
||||
findMatchingAttribute(attribId);
|
||||
String res = readString();
|
||||
curPos.copy(startPos);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace readSpace() throws DecoderException {
|
||||
byte header1 = curPos.getNextByte();
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
curPos.getNextByte();
|
||||
}
|
||||
byte typeByte = curPos.getNextByte();
|
||||
int typeCode = typeByte >> TYPECODE_SHIFT;
|
||||
AddressSpace spc = null;
|
||||
if (typeCode == TYPECODE_ADDRESSSPACE) {
|
||||
int res = (int) readInteger(typeByte & LENGTHCODE_MASK);
|
||||
if (res >= 0 && res < spaces.length) {
|
||||
spc = spaces[res];
|
||||
}
|
||||
if (spc == null) {
|
||||
throw new DecoderException("Unknown address space index");
|
||||
}
|
||||
}
|
||||
else if (typeCode == TYPECODE_SPECIALSPACE) {
|
||||
int specialCode = typeByte & LENGTHCODE_MASK;
|
||||
if (specialCode == SPECIALSPACE_STACK) {
|
||||
spc = addrFactory.getStackSpace();
|
||||
}
|
||||
else if (specialCode == SPECIALSPACE_JOIN) {
|
||||
spc = AddressSpace.VARIABLE_SPACE;
|
||||
}
|
||||
else if (specialCode == SPECIALSPACE_SPACEBASE) {
|
||||
// TODO: Add support for decompiler non-stack "register relative" spaces
|
||||
// We let the null address space get returned here. Its as if, no space
|
||||
// attribute is given in an <addr> element, resulting in NO_ADDRESS
|
||||
// spc = null;
|
||||
}
|
||||
else {
|
||||
throw new DecoderException("Cannot marshal special address space");
|
||||
}
|
||||
}
|
||||
else {
|
||||
skipAttributeRemaining(typeByte);
|
||||
throw new DecoderException("Expecting space attribute");
|
||||
}
|
||||
attributeRead = true;
|
||||
return spc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace readSpace(AttributeId attribId) throws DecoderException {
|
||||
findMatchingAttribute(attribId);
|
||||
AddressSpace res = readSpace();
|
||||
curPos.copy(startPos);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import static ghidra.program.model.pcode.PackedDecode.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
/**
|
||||
* A byte-based encoder designed to marshal to the decompiler efficiently
|
||||
* See {@code PackedDecode} for details of the encoding format
|
||||
*/
|
||||
public class PackedEncode implements PatchEncoder {
|
||||
private PackedBytes outStream;
|
||||
|
||||
private void writeHeader(int header, int id) {
|
||||
if (id > 0x1f) {
|
||||
header |= HEADEREXTEND_MASK;
|
||||
header |= (id >> RAWDATA_BITSPERBYTE);
|
||||
int extendByte = (id & RAWDATA_MASK) | RAWDATA_MARKER;
|
||||
outStream.write(header);
|
||||
outStream.write(extendByte);
|
||||
}
|
||||
else {
|
||||
header |= id;
|
||||
outStream.write(header);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInteger(int typeByte, long val) {
|
||||
byte lenCode;
|
||||
int sa;
|
||||
if (val <= 0) {
|
||||
if (val == 0) {
|
||||
lenCode = 0;
|
||||
sa = -1;
|
||||
}
|
||||
else {
|
||||
lenCode = 10;
|
||||
sa = 9 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
}
|
||||
else if (val < 0x800000000L) {
|
||||
if (val < 0x200000L) {
|
||||
if (val < 0x80L) {
|
||||
lenCode = 1; // 7-bits
|
||||
sa = 0;
|
||||
}
|
||||
else if (val < 0x4000L) {
|
||||
lenCode = 2; // 14-bits
|
||||
sa = RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
else {
|
||||
lenCode = 3; // 21-bits
|
||||
sa = 2 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
}
|
||||
else if (val < 0x10000000L) {
|
||||
lenCode = 4; // 28-bits
|
||||
sa = 3 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
else {
|
||||
lenCode = 5; // 35-bits
|
||||
sa = 4 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
}
|
||||
else if (val < 0x2000000000000L) {
|
||||
if (val < 0x40000000000L) {
|
||||
lenCode = 6;
|
||||
sa = 5 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
else {
|
||||
lenCode = 7;
|
||||
sa = 6 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (val < 0x100000000000000L) {
|
||||
lenCode = 8;
|
||||
sa = 7 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
else {
|
||||
lenCode = 9;
|
||||
sa = 8 * RAWDATA_BITSPERBYTE;
|
||||
}
|
||||
}
|
||||
typeByte |= lenCode;
|
||||
outStream.write(typeByte);
|
||||
for (; sa >= 0; sa -= RAWDATA_BITSPERBYTE) {
|
||||
long piece = (val >>> sa) & RAWDATA_MASK;
|
||||
piece |= RAWDATA_MARKER;
|
||||
outStream.write((int) piece);
|
||||
}
|
||||
}
|
||||
|
||||
public PackedEncode() {
|
||||
outStream = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
outStream = new PackedBytes(512);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openElement(ElementId elemId) throws IOException {
|
||||
writeHeader(ELEMENT_START, elemId.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElement(ElementId elemId) throws IOException {
|
||||
writeHeader(ELEMENT_END, elemId.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBool(AttributeId attribId, boolean val) throws IOException {
|
||||
writeHeader(ATTRIBUTE, attribId.id());
|
||||
int typeByte = val ? 0x11 : 0x10;
|
||||
outStream.write(typeByte);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSignedInteger(AttributeId attribId, long val) throws IOException {
|
||||
writeHeader(0xc0, attribId.id());
|
||||
int typeByte;
|
||||
long num;
|
||||
if (val < 0) {
|
||||
typeByte = (TYPECODE_SIGNEDINT_NEGATIVE << TYPECODE_SHIFT);
|
||||
num = -val;
|
||||
}
|
||||
else {
|
||||
typeByte = (TYPECODE_SIGNEDINT_POSITIVE << TYPECODE_SHIFT);
|
||||
num = val;
|
||||
}
|
||||
writeInteger(typeByte, num);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUnsignedInteger(AttributeId attribId, long val) throws IOException {
|
||||
writeHeader(ATTRIBUTE, attribId.id());
|
||||
writeInteger((TYPECODE_UNSIGNEDINT << TYPECODE_SHIFT), val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeString(AttributeId attribId, String val) throws IOException {
|
||||
byte[] bytes = val.getBytes();
|
||||
writeHeader(ATTRIBUTE, attribId.id());
|
||||
writeInteger((TYPECODE_STRING << TYPECODE_SHIFT), bytes.length);
|
||||
outStream.write(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSpace(AttributeId attribId, AddressSpace spc) throws IOException {
|
||||
writeHeader(ATTRIBUTE, attribId.id());
|
||||
switch (spc.getType()) {
|
||||
case AddressSpace.TYPE_CONSTANT:
|
||||
case AddressSpace.TYPE_RAM:
|
||||
case AddressSpace.TYPE_REGISTER:
|
||||
case AddressSpace.TYPE_UNIQUE:
|
||||
case AddressSpace.TYPE_OTHER:
|
||||
writeInteger((TYPECODE_ADDRESSSPACE << TYPECODE_SHIFT), spc.getUnique());
|
||||
break;
|
||||
case AddressSpace.TYPE_VARIABLE:
|
||||
outStream.write((TYPECODE_SPECIALSPACE << TYPECODE_SHIFT) | SPECIALSPACE_JOIN);
|
||||
break;
|
||||
case AddressSpace.TYPE_STACK:
|
||||
outStream.write((TYPECODE_SPECIALSPACE << TYPECODE_SHIFT) | SPECIALSPACE_STACK);
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Cannot marshal address space: " + spc.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream stream) throws IOException {
|
||||
outStream.writeTo(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return (outStream.size() == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return outStream.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSpaceId(AttributeId attribId, long spaceId) {
|
||||
writeHeader(ATTRIBUTE, attribId.id());
|
||||
int uniqueId = (int) spaceId >> AddressSpace.ID_UNIQUE_SHIFT;
|
||||
writeInteger((TYPECODE_ADDRESSSPACE << TYPECODE_SHIFT), uniqueId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the position after the open element directive at the given position.
|
||||
* @param pos is the given position
|
||||
* @return the next position or -1 if the current byte is not an open directive
|
||||
*/
|
||||
private int skipOpen(int pos) {
|
||||
int val = outStream.getByte(pos) & (HEADER_MASK | HEADEREXTEND_MASK);
|
||||
if (val == ELEMENT_START) {
|
||||
return pos + 1;
|
||||
}
|
||||
else if (val == (ELEMENT_START | HEADEREXTEND_MASK)) {
|
||||
return pos + 2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the integer at the given position.
|
||||
* @param pos is the given position
|
||||
* @param len is the length of the integer in 7-bit bytes
|
||||
* @return the integer
|
||||
*/
|
||||
private long readInteger(int pos, int len) {
|
||||
long res = 0;
|
||||
while (len > 0) {
|
||||
res <<= RAWDATA_BITSPERBYTE;
|
||||
res |= (outStream.getByte(pos) & RAWDATA_MASK);
|
||||
pos += 1;
|
||||
len -= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean patchIntegerAttribute(int pos, AttributeId attribId, long val) {
|
||||
int typeByte;
|
||||
int length;
|
||||
|
||||
pos = skipOpen(pos);
|
||||
if (pos < 0) {
|
||||
return false;
|
||||
}
|
||||
for (;;) {
|
||||
int header1 = outStream.getByte(pos); // Attribute header
|
||||
if ((header1 & HEADER_MASK) != ATTRIBUTE) {
|
||||
return false;
|
||||
}
|
||||
pos += 1;
|
||||
int curid = header1 & ELEMENTID_MASK;
|
||||
if ((header1 & HEADEREXTEND_MASK) != 0) {
|
||||
curid <<= RAWDATA_BITSPERBYTE;
|
||||
curid |= outStream.getByte(pos) & RAWDATA_MASK;
|
||||
pos += 1; // Extra byte for extended id
|
||||
}
|
||||
typeByte = outStream.getByte(pos) & 0xff; // Type (and length) byte
|
||||
pos += 1;
|
||||
int attribType = typeByte >> TYPECODE_SHIFT;
|
||||
if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE) {
|
||||
continue; // has no additional data
|
||||
}
|
||||
length = typeByte & LENGTHCODE_MASK; // Length of data in bytes
|
||||
if (attribType == TYPECODE_STRING) { // For a string
|
||||
length = (int) readInteger(pos, length); // Read length field to get final length of string
|
||||
}
|
||||
if (attribId.id() == curid) {
|
||||
break;
|
||||
}
|
||||
pos += length; // Skip -length- data
|
||||
}
|
||||
if (length != 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int sa = 9 * RAWDATA_BITSPERBYTE; sa >= 0; sa -= RAWDATA_BITSPERBYTE) {
|
||||
long piece = (val >>> sa) & RAWDATA_MASK;
|
||||
piece |= RAWDATA_MARKER;
|
||||
outStream.insertByte(pos, (int) piece);
|
||||
pos += 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -50,9 +50,9 @@ public class ParamMeasure {
|
|||
* Decode a ParamMeasure object from the stream.
|
||||
* @param decoder is the stream decoder
|
||||
* @param factory pcode factory
|
||||
* @throws PcodeXMLException for an invalid encoding
|
||||
* @throws DecoderException for an invalid encoding
|
||||
*/
|
||||
public void decode(Decoder decoder, PcodeFactory factory) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder, PcodeFactory factory) throws DecoderException {
|
||||
vn = Varnode.decode(decoder, factory);
|
||||
dt = factory.getDataTypeManager().decodeDataType(decoder);
|
||||
int rankel = decoder.openElement(ElementId.ELEM_RANK);
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
/**
|
||||
* This is an encoder that produces encodings that can be retroactively patched.
|
||||
* The contained encoding is expected to be byte based. The user can record a position
|
||||
* in the encoding by calling the size() method in the middle of encoding, and then later
|
||||
* use the returned offset to call the patchIntegerAttribute() method and modify the
|
||||
* encoding at the recorded position.
|
||||
*/
|
||||
public interface PatchEncoder extends Encoder {
|
||||
|
||||
/**
|
||||
* Write a given raw spaceid (as returned by AddressSpace.getSpaceID()) as an attribute.
|
||||
* The effect is the same as if writeSpace() was called with the AddressSpace matching
|
||||
* the spaceid, i.e. the decoder will read this as just space attribute.
|
||||
* @param attribId is the attribute
|
||||
* @param spaceId is the given spaceid
|
||||
*/
|
||||
public void writeSpaceId(AttributeId attribId, long spaceId);
|
||||
|
||||
/**
|
||||
* The returned value can be used as a position for later modification
|
||||
* @return the number of bytes written to this stream so far
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* Replace an integer attribute for the element at the given position.
|
||||
* The position is assumed to be at an open directive for the element containing the
|
||||
* attribute to be patched.
|
||||
* @param pos is the given position
|
||||
* @param attribId is the attribute to be patched
|
||||
* @param val is the new value to insert
|
||||
* @return true if the attribute is successfully patched
|
||||
*/
|
||||
public boolean patchIntegerAttribute(int pos, AttributeId attribId, long val);
|
||||
}
|
|
@ -166,28 +166,28 @@ public class PcodeBlock {
|
|||
* Decode a single edge
|
||||
* @param decoder is the stream decoder
|
||||
* @param resolver used to recover PcodeBlock reference
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public void decode(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_EDGE);
|
||||
label = 0; // Tag does not currently contain info about label
|
||||
int endIndex = (int) decoder.readSignedInteger(ATTRIB_END);
|
||||
point = resolver.findLevelBlock(endIndex);
|
||||
if (point == null) {
|
||||
throw new PcodeXMLException("Bad serialized edge in block graph");
|
||||
throw new DecoderException("Bad serialized edge in block graph");
|
||||
}
|
||||
reverse_index = (int) decoder.readSignedInteger(ATTRIB_REV);
|
||||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
public void decode(Decoder decoder, ArrayList<? extends PcodeBlock> blockList)
|
||||
throws PcodeXMLException {
|
||||
throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_EDGE);
|
||||
label = 0; // Tag does not currently contain info about label
|
||||
int endIndex = (int) decoder.readSignedInteger(ATTRIB_END);
|
||||
point = blockList.get(endIndex);
|
||||
if (point == null) {
|
||||
throw new PcodeXMLException("Bad serialized edge in block list");
|
||||
throw new DecoderException("Bad serialized edge in block list");
|
||||
}
|
||||
reverse_index = (int) decoder.readSignedInteger(ATTRIB_REV);
|
||||
decoder.closeElement(el);
|
||||
|
@ -248,9 +248,9 @@ public class PcodeBlock {
|
|||
* Decode the next input edge from the stream
|
||||
* @param decoder is the stream decoder
|
||||
* @param resolver is used to find PcodeBlocks
|
||||
* @throws PcodeXMLException for any invalid encoding
|
||||
* @throws DecoderException for any invalid encoding
|
||||
*/
|
||||
protected void decodeNextInEdge(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeNextInEdge(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
BlockEdge inEdge = new BlockEdge();
|
||||
intothis.add(inEdge);
|
||||
inEdge.decode(decoder, resolver);
|
||||
|
@ -265,10 +265,10 @@ public class PcodeBlock {
|
|||
* Decode the next input edge from the stream. Resolve block indices via a blockList
|
||||
* @param decoder is the stream decoder
|
||||
* @param blockList allows lookup of PcodeBlock via index
|
||||
* @throws PcodeXMLException for any invalid encoding
|
||||
* @throws DecoderException for any invalid encoding
|
||||
*/
|
||||
protected void decodeNextInEdge(Decoder decoder, ArrayList<? extends PcodeBlock> blockList)
|
||||
throws PcodeXMLException {
|
||||
throws DecoderException {
|
||||
BlockEdge inEdge = new BlockEdge();
|
||||
intothis.add(inEdge);
|
||||
inEdge.decode(decoder, blockList);
|
||||
|
@ -358,7 +358,7 @@ public class PcodeBlock {
|
|||
encoder.writeSignedInteger(ATTRIB_INDEX, index);
|
||||
}
|
||||
|
||||
protected void decodeHeader(Decoder decoder) throws PcodeXMLException {
|
||||
protected void decodeHeader(Decoder decoder) throws DecoderException {
|
||||
index = (int) decoder.readSignedInteger(ATTRIB_INDEX);
|
||||
}
|
||||
|
||||
|
@ -387,13 +387,13 @@ public class PcodeBlock {
|
|||
* Restore the any additional information beyond header and edges from stream
|
||||
* @param decoder is the stream decoder
|
||||
* @param resolver is for looking up edge references
|
||||
* @throws PcodeXMLException for invalid encoding
|
||||
* @throws DecoderException for invalid encoding
|
||||
*/
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
// No body to restore by default
|
||||
}
|
||||
|
||||
protected void decodeEdges(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeEdges(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
for (;;) {
|
||||
int el = decoder.peekElement();
|
||||
if (el != ELEM_EDGE.id()) {
|
||||
|
@ -420,9 +420,9 @@ public class PcodeBlock {
|
|||
* Decode this block from a stream
|
||||
* @param decoder is the stream decoder
|
||||
* @param resolver is the map from reference to block object
|
||||
* @throws PcodeXMLException for errors in the encoding
|
||||
* @throws DecoderException for errors in the encoding
|
||||
*/
|
||||
public void decode(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_BLOCK);
|
||||
decodeHeader(decoder);
|
||||
decodeBody(decoder, resolver);
|
||||
|
|
|
@ -127,7 +127,7 @@ public class PcodeBlockBasic extends PcodeBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
int rangelistel = decoder.openElement(ELEM_RANGELIST);
|
||||
for (;;) {
|
||||
int rangeel = decoder.peekElement();
|
||||
|
|
|
@ -165,9 +165,9 @@ public class PcodeDataTypeManager {
|
|||
* Decode a data-type from the stream
|
||||
* @param decoder is the stream decoder
|
||||
* @return the decoded data-type object
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public DataType decodeDataType(Decoder decoder) throws PcodeXMLException {
|
||||
public DataType decodeDataType(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement();
|
||||
if (el == ELEM_VOID.id()) {
|
||||
decoder.closeElement(el);
|
||||
|
@ -196,7 +196,7 @@ public class PcodeDataTypeManager {
|
|||
return findBaseType(name, id);
|
||||
}
|
||||
if (el != ELEM_TYPE.id()) {
|
||||
throw new PcodeXMLException("Expecting <type> element");
|
||||
throw new DecoderException("Expecting <type> element");
|
||||
}
|
||||
|
||||
if (name.length() != 0) {
|
||||
|
@ -258,7 +258,7 @@ public class PcodeDataTypeManager {
|
|||
return Undefined.getUndefinedDataType(size).clone(progDataTypes);
|
||||
}
|
||||
if (restype == null) {
|
||||
throw new PcodeXMLException("Unable to resolve DataType");
|
||||
throw new DecoderException("Unable to resolve DataType");
|
||||
}
|
||||
decoder.closeElementSkipping(el);
|
||||
return restype;
|
||||
|
|
|
@ -60,11 +60,11 @@ public interface PcodeFactory {
|
|||
* @param addr join address associated with pieces
|
||||
*
|
||||
* @return the decoded VariableStorage
|
||||
* @throws PcodeXMLException for an improperly encoded stream
|
||||
* @throws DecoderException for an improperly encoded stream
|
||||
* @throws InvalidInputException if the pieces are not valid storage locations
|
||||
*/
|
||||
public VariableStorage decodeVarnodePieces(Decoder decoder, Address addr)
|
||||
throws PcodeXMLException, InvalidInputException;
|
||||
throws DecoderException, InvalidInputException;
|
||||
|
||||
public Varnode createFromStorage(Address addr, VariableStorage storage, int logicalSize);
|
||||
|
||||
|
|
|
@ -420,21 +420,22 @@ public class PcodeOp {
|
|||
}
|
||||
|
||||
/**
|
||||
* Encode this PcodeOp to a stream as an \<op> element
|
||||
* Encode just the opcode and input/output Varnode data for this PcodeOp to a stream
|
||||
* as an \<op> element
|
||||
* @param encoder is the stream encoder
|
||||
* @param addrFactory is a factory for looking up encoded address spaces
|
||||
* @throws IOException for errors in the underlying stream
|
||||
*/
|
||||
public void encode(Encoder encoder, AddressFactory addrFactory) throws IOException {
|
||||
public void encodeRaw(Encoder encoder, AddressFactory addrFactory) throws IOException {
|
||||
encoder.openElement(ELEM_OP);
|
||||
encoder.writeSignedInteger(ATTRIB_CODE, opcode);
|
||||
seqnum.encode(encoder);
|
||||
encoder.writeSignedInteger(ATTRIB_SIZE, input.length);
|
||||
if (output == null) {
|
||||
encoder.openElement(ELEM_VOID);
|
||||
encoder.closeElement(ELEM_VOID);
|
||||
}
|
||||
else {
|
||||
output.encode(encoder);
|
||||
output.encodeRaw(encoder);
|
||||
}
|
||||
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
|
||||
int spaceId = (int) input[0].getOffset();
|
||||
|
@ -444,10 +445,10 @@ public class PcodeOp {
|
|||
encoder.closeElement(ELEM_SPACEID);
|
||||
}
|
||||
else if (input.length > 0) {
|
||||
input[0].encode(encoder);
|
||||
input[0].encodeRaw(encoder);
|
||||
}
|
||||
for (int i = 1; i < input.length; ++i) {
|
||||
input[i].encode(encoder);
|
||||
input[i].encodeRaw(encoder);
|
||||
}
|
||||
encoder.closeElement(ELEM_OP);
|
||||
}
|
||||
|
@ -459,9 +460,9 @@ public class PcodeOp {
|
|||
* @param pfact factory used to create p-code correctly
|
||||
*
|
||||
* @return new PcodeOp
|
||||
* @throws PcodeXMLException if encodings are invalid
|
||||
* @throws DecoderException if encodings are invalid
|
||||
*/
|
||||
public static PcodeOp decode(Decoder decoder, PcodeFactory pfact) throws PcodeXMLException {
|
||||
public static PcodeOp decode(Decoder decoder, PcodeFactory pfact) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_OP);
|
||||
int opc = (int) decoder.readSignedInteger(ATTRIB_CODE);
|
||||
SequenceNumber seqnum = SequenceNumber.decode(decoder);
|
||||
|
@ -480,7 +481,7 @@ public class PcodeOp {
|
|||
res = pfact.newOp(seqnum, opc, inputlist, output);
|
||||
}
|
||||
catch (UnknownInstructionException e) {
|
||||
throw new PcodeXMLException("Bad opcode: " + e.getMessage(), e);
|
||||
throw new DecoderException("Bad opcode: " + e.getMessage(), e);
|
||||
}
|
||||
decoder.closeElement(el);
|
||||
return res;
|
||||
|
|
|
@ -69,50 +69,49 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
|||
}
|
||||
|
||||
private static Varnode getVarnodePiece(String pieceStr, AddressFactory addrFactory)
|
||||
throws PcodeXMLException {
|
||||
throws DecoderException {
|
||||
// TODO: Can't handle register name since addrFactory can't handle this
|
||||
String[] varnodeTokens = pieceStr.split(":");
|
||||
if (varnodeTokens.length != 3) {
|
||||
throw new PcodeXMLException("Invalid XML addr piece: " + pieceStr);
|
||||
throw new DecoderException("Invalid \"join\" address piece: " + pieceStr);
|
||||
}
|
||||
AddressSpace space = addrFactory.getAddressSpace(varnodeTokens[0]);
|
||||
if (space == null) {
|
||||
throw new PcodeXMLException("Invalid XML addr, space not found: " + pieceStr);
|
||||
throw new DecoderException("Invalid space for \"join\" address piece: " + pieceStr);
|
||||
}
|
||||
if (!varnodeTokens[1].startsWith("0x")) {
|
||||
throw new PcodeXMLException("Invalid XML addr piece offset: " + pieceStr);
|
||||
throw new DecoderException("Invalid offset for \"join\" address piece: " + pieceStr);
|
||||
}
|
||||
long offset;
|
||||
try {
|
||||
offset = Long.parseUnsignedLong(varnodeTokens[1].substring(2), 16);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new PcodeXMLException("Invalid XML addr piece offset: " + pieceStr);
|
||||
throw new DecoderException("Invalid offset for \"join\" address piece: " + pieceStr);
|
||||
}
|
||||
int size;
|
||||
try {
|
||||
size = Integer.parseInt(varnodeTokens[2]);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new PcodeXMLException("Invalid XML addr piece size: " + pieceStr);
|
||||
throw new DecoderException("Invalid size for \"join\" address piece: " + pieceStr);
|
||||
}
|
||||
return new Varnode(space.getAddress(offset), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage decodeVarnodePieces(Decoder decoder, Address addr)
|
||||
throws PcodeXMLException, InvalidInputException {
|
||||
throws DecoderException, InvalidInputException {
|
||||
ArrayList<Varnode> list = new ArrayList<>();
|
||||
for (;;) {
|
||||
int attribId = decoder.getNextAttributeId();
|
||||
if (attribId == 0) {
|
||||
break;
|
||||
}
|
||||
else if (attribId >= ATTRIB_PIECE1.id() &&
|
||||
attribId <= ATTRIB_PIECE9.id()) {
|
||||
else if (attribId >= ATTRIB_PIECE1.id() && attribId <= ATTRIB_PIECE9.id()) {
|
||||
int index = attribId - ATTRIB_PIECE1.id();
|
||||
if (index != list.size()) {
|
||||
throw new PcodeXMLException("\"piece\" attributes must be in order");
|
||||
throw new DecoderException("\"piece\" attributes must be in order");
|
||||
}
|
||||
list.add(getVarnodePiece(decoder.readString(), decoder.getAddressFactory()));
|
||||
}
|
||||
|
@ -523,7 +522,7 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
|||
return op;
|
||||
}
|
||||
|
||||
private void decodeVarnode(Decoder decoder) throws PcodeXMLException {
|
||||
private void decodeVarnode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_VARNODES);
|
||||
for (;;) {
|
||||
int subId = decoder.peekElement();
|
||||
|
@ -535,7 +534,7 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
|||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
private void decodeBasicBlock(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
|
||||
private void decodeBasicBlock(Decoder decoder, BlockMap resolver) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_BLOCK);
|
||||
int order = 0;
|
||||
PcodeBlockBasic bl = new PcodeBlockBasic();
|
||||
|
@ -559,7 +558,7 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
|||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
private void decodeBlockEdge(Decoder decoder) throws PcodeXMLException {
|
||||
private void decodeBlockEdge(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_BLOCKEDGE);
|
||||
int blockInd = (int) decoder.readSignedInteger(ATTRIB_INDEX);
|
||||
PcodeBlockBasic curBlock = bblocks.get(blockInd);
|
||||
|
@ -573,7 +572,7 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
|||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
public void decode(Decoder decoder) throws PcodeXMLException {
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_AST);
|
||||
if (!vbank.isEmpty()) {
|
||||
clear();
|
||||
|
|
|
@ -150,9 +150,9 @@ public class SequenceNumber implements Comparable<SequenceNumber> {
|
|||
* @param decoder is the stream decoder
|
||||
*
|
||||
* @return new sequence number
|
||||
* @throws PcodeXMLException for an invalid encoding
|
||||
* @throws DecoderException for an invalid encoding
|
||||
*/
|
||||
public static SequenceNumber decode(Decoder decoder) throws PcodeXMLException {
|
||||
public static SequenceNumber decode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_SEQNUM);
|
||||
int uniq = -1;
|
||||
for (;;) {
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class StringIngest implements ByteIngest {
|
||||
|
||||
private ByteArrayOutputStream outStream;
|
||||
private String source;
|
||||
private int maxBytes;
|
||||
|
||||
public StringIngest() {
|
||||
outStream = null;
|
||||
source = null;
|
||||
maxBytes = 0;
|
||||
}
|
||||
|
||||
public StringIngest(int max, String src) {
|
||||
open(max, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(int max, String src) {
|
||||
maxBytes = max;
|
||||
source = src;
|
||||
outStream = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ingestStream(InputStream inStream) throws IOException {
|
||||
int tok = inStream.read();
|
||||
while (tok > 0) {
|
||||
outStream.write(tok);
|
||||
if (outStream.size() >= maxBytes) {
|
||||
throw new IOException("Buffer size exceeded: " + source);
|
||||
}
|
||||
tok = inStream.read();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endIngest() {
|
||||
// Nothing needs to be done
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
outStream = null;
|
||||
source = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return outStream.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return (outStream.size() == 0);
|
||||
}
|
||||
}
|
|
@ -43,9 +43,9 @@ public abstract class SymbolEntry {
|
|||
/**
|
||||
* Decode this entry from the stream. Typically more than one element is consumed.
|
||||
* @param decoder is the stream decoder
|
||||
* @throws PcodeXMLException for invalid encodings
|
||||
* @throws DecoderException for invalid encodings
|
||||
*/
|
||||
public abstract void decode(Decoder decoder) throws PcodeXMLException;
|
||||
public abstract void decode(Decoder decoder) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Encode this entry as (a set of) elements to the given stream
|
||||
|
@ -85,7 +85,7 @@ public abstract class SymbolEntry {
|
|||
return pcaddr;
|
||||
}
|
||||
|
||||
protected void decodeRangeList(Decoder decoder) throws PcodeXMLException {
|
||||
protected void decodeRangeList(Decoder decoder) throws DecoderException {
|
||||
int rangelistel = decoder.openElement(ELEM_RANGELIST);
|
||||
if (decoder.peekElement() != 0) {
|
||||
// we only use this to establish first-use
|
||||
|
|
|
@ -316,10 +316,11 @@ public class Varnode {
|
|||
}
|
||||
|
||||
/**
|
||||
* Encode just the raw storage info for this Varnode to stream
|
||||
* @param encoder is the stream encoder
|
||||
* @throws IOException for errors in the underlying stream
|
||||
*/
|
||||
public void encode(Encoder encoder) throws IOException {
|
||||
public void encodeRaw(Encoder encoder) throws IOException {
|
||||
AddressXML.encode(encoder, address, size);
|
||||
}
|
||||
|
||||
|
@ -329,9 +330,9 @@ public class Varnode {
|
|||
* @param decoder is the stream decoder
|
||||
* @param factory pcode factory used to create valid pcode
|
||||
* @return the new Varnode
|
||||
* @throws PcodeXMLException if XML is improperly formed
|
||||
* @throws DecoderException if the Varnode is improperly encoded
|
||||
*/
|
||||
public static Varnode decode(Decoder decoder, PcodeFactory factory) throws PcodeXMLException {
|
||||
public static Varnode decode(Decoder decoder, PcodeFactory factory) throws DecoderException {
|
||||
int el = decoder.peekElement();
|
||||
if (el == ELEM_VOID.id()) {
|
||||
decoder.openElement();
|
||||
|
@ -379,7 +380,7 @@ public class Varnode {
|
|||
factory.decodeVarnodePieces(decoder, addr);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new PcodeXMLException("Invalid varnode pieces: " + e.getMessage());
|
||||
throw new DecoderException("Invalid varnode pieces: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
decoder.rewindAttributes();
|
||||
|
@ -413,7 +414,7 @@ public class Varnode {
|
|||
}
|
||||
}
|
||||
}
|
||||
decoder.closeElement(sz);
|
||||
decoder.closeElement(el);
|
||||
return vn;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import static ghidra.program.model.pcode.AttributeId.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.xml.sax.*;
|
||||
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.*;
|
||||
|
||||
public class XmlDecode implements Decoder {
|
||||
|
||||
private XmlPullParser parser;
|
||||
private XmlElement currentEl;
|
||||
private Iterator<Map.Entry<String, String>> attribIterator;
|
||||
private String attribValue;
|
||||
private AddressFactory spcManager;
|
||||
|
||||
public XmlDecode(AddressFactory factory) {
|
||||
parser = null;
|
||||
currentEl = null;
|
||||
attribIterator = null;
|
||||
attribValue = null;
|
||||
spcManager = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressFactory getAddressFactory() {
|
||||
return spcManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
parser = null;
|
||||
currentEl = null;
|
||||
attribIterator = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ingestStream(InputStream stream, String source) throws PcodeXMLException {
|
||||
ErrorHandler handler = new ErrorHandler() {
|
||||
@Override
|
||||
public void error(SAXParseException exception) throws SAXException {
|
||||
Msg.error(this, "Error parsing " + source, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception) throws SAXException {
|
||||
Msg.error(this, "Fatal error parsing " + source, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(SAXParseException exception) throws SAXException {
|
||||
Msg.warn(this, "Warning parsing " + source, exception);
|
||||
}
|
||||
};
|
||||
try {
|
||||
parser = XmlPullParserFactory.create(stream, source, handler, false);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new PcodeXMLException("XML parsing error: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekElement() {
|
||||
XmlElement el = parser.peek();
|
||||
if (!el.isStart()) {
|
||||
return 0;
|
||||
}
|
||||
return ElementId.find(el.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int openElement() {
|
||||
XmlElement el = parser.softStart();
|
||||
if (el == null) {
|
||||
return 0;
|
||||
}
|
||||
currentEl = el;
|
||||
attribIterator = null;
|
||||
return ElementId.find(currentEl.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int openElement(ElementId elemId) throws PcodeXMLException {
|
||||
XmlElement el = parser.softStart(elemId.name());
|
||||
if (el == null) {
|
||||
throw new PcodeXMLException("Expecting element <" + elemId.name() + '>');
|
||||
}
|
||||
currentEl = el;
|
||||
attribIterator = null;
|
||||
return ElementId.find(currentEl.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElement(int id) throws PcodeXMLException {
|
||||
XmlElement el = parser.next();
|
||||
if (!el.isEnd()) {
|
||||
throw new PcodeXMLException("Expecting end, but got start <" + el.getName() + '>');
|
||||
}
|
||||
currentEl = null;
|
||||
// Only one possible element can be closed as enforced by SAXParser
|
||||
// so additional checks are somewhat redundant
|
||||
// int elemId = ElementId.find(el.getName());
|
||||
// if (elemId != id) {
|
||||
// throw new PcodeXMLException("Unexpected end, <" + el.getName() + '>');
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElementSkipping(int id) throws PcodeXMLException {
|
||||
currentEl = null;
|
||||
XmlElement el = parser.peek();
|
||||
if (el == null) {
|
||||
throw new PcodeXMLException("No more elements");
|
||||
}
|
||||
int level = el.getLevel();
|
||||
if (el.isStart()) {
|
||||
level -= 1;
|
||||
}
|
||||
for (;;) {
|
||||
el = parser.next();
|
||||
int curlevel = el.getLevel();
|
||||
if (curlevel > level) {
|
||||
continue;
|
||||
}
|
||||
if (curlevel < level) {
|
||||
throw new PcodeXMLException("Missing end element");
|
||||
}
|
||||
if (el.isEnd()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int elemId = ElementId.find(el.getName());
|
||||
if (elemId != id) {
|
||||
throw new PcodeXMLException("Unexpected element end: " + el.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextAttributeId() {
|
||||
if (attribIterator == null) {
|
||||
attribIterator = currentEl.getAttributeIterator();
|
||||
}
|
||||
if (!attribIterator.hasNext()) {
|
||||
return 0;
|
||||
}
|
||||
Map.Entry<String, String> entry = attribIterator.next();
|
||||
attribValue = entry.getValue();
|
||||
return AttributeId.find(entry.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewindAttributes() {
|
||||
attribIterator = null;
|
||||
}
|
||||
|
||||
private String readContent() throws PcodeXMLException {
|
||||
XmlElement el = parser.peek();
|
||||
if (el == null || !el.isEnd()) {
|
||||
throw new PcodeXMLException("Cannot request ATTRIB_CONTENT here");
|
||||
}
|
||||
return el.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBool() throws PcodeXMLException {
|
||||
return SpecXmlUtils.decodeBoolean(attribValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBool(AttributeId attribId) throws PcodeXMLException {
|
||||
String value;
|
||||
if (attribId == ATTRIB_CONTENT) {
|
||||
value = readContent();
|
||||
}
|
||||
else {
|
||||
value = currentEl.getAttribute(attribId.name());
|
||||
}
|
||||
if (value == null) {
|
||||
throw new PcodeXMLException("Missing attribute: " + attribId.name());
|
||||
}
|
||||
attribIterator = null;
|
||||
return SpecXmlUtils.decodeBoolean(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readSignedInteger() throws PcodeXMLException {
|
||||
return SpecXmlUtils.decodeLong(attribValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readSignedInteger(AttributeId attribId) throws PcodeXMLException {
|
||||
String value;
|
||||
if (attribId == ATTRIB_CONTENT) {
|
||||
value = readContent();
|
||||
}
|
||||
else {
|
||||
value = currentEl.getAttribute(attribId.name());
|
||||
}
|
||||
if (value == null) {
|
||||
throw new PcodeXMLException("Missing attribute: " + attribId.name());
|
||||
}
|
||||
attribIterator = null;
|
||||
return SpecXmlUtils.decodeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInteger() throws PcodeXMLException {
|
||||
return SpecXmlUtils.decodeLong(attribValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInteger(AttributeId attribId) throws PcodeXMLException {
|
||||
String value;
|
||||
if (attribId == ATTRIB_CONTENT) {
|
||||
value = readContent();
|
||||
}
|
||||
else {
|
||||
value = currentEl.getAttribute(attribId.name());
|
||||
}
|
||||
if (value == null) {
|
||||
throw new PcodeXMLException("Missing attribute: " + attribId.name());
|
||||
}
|
||||
attribIterator = null;
|
||||
return SpecXmlUtils.decodeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString() throws PcodeXMLException {
|
||||
return attribValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(AttributeId attribId) throws PcodeXMLException {
|
||||
String value;
|
||||
if (attribId == ATTRIB_CONTENT) {
|
||||
value = readContent();
|
||||
}
|
||||
else {
|
||||
value = currentEl.getAttribute(attribId.name());
|
||||
}
|
||||
if (value == null) {
|
||||
throw new PcodeXMLException("Missing attribute: " + attribId.name());
|
||||
}
|
||||
attribIterator = null;
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace readSpace() throws PcodeXMLException {
|
||||
return spcManager.getAddressSpace(attribValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace readSpace(AttributeId attribId) throws PcodeXMLException {
|
||||
String value;
|
||||
if (attribId == ATTRIB_CONTENT) {
|
||||
value = readContent();
|
||||
}
|
||||
else {
|
||||
value = currentEl.getAttribute(attribId.name());
|
||||
}
|
||||
if (value == null) {
|
||||
throw new PcodeXMLException("Missing attribute: " + attribId.name());
|
||||
}
|
||||
attribIterator = null;
|
||||
return spcManager.getAddressSpace(value);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,400 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import static ghidra.program.model.pcode.AttributeId.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
|
||||
/**
|
||||
* Lightweight XML decoder.
|
||||
* - Element and attribute identifiers must contain only letters or digits
|
||||
* - No XML comments
|
||||
* - No escape codes
|
||||
* - No content (except white space)
|
||||
*/
|
||||
public class XmlDecodeLight implements Decoder {
|
||||
|
||||
private AddressFactory addressFactory;
|
||||
private String raw;
|
||||
private int currentPos;
|
||||
private boolean startOpen;
|
||||
private int attribStart;
|
||||
private int currentElement;
|
||||
|
||||
public XmlDecodeLight(AddressFactory addrFactory) {
|
||||
addressFactory = addrFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressFactory getAddressFactory() {
|
||||
return addressFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
raw = null;
|
||||
}
|
||||
|
||||
public void ingestString(String data) {
|
||||
raw = data;
|
||||
currentPos = 0;
|
||||
startOpen = false;
|
||||
attribStart = -1;
|
||||
}
|
||||
|
||||
private int scanWhiteSpace(int start) throws PcodeXMLException {
|
||||
while (start < raw.length()) {
|
||||
char tok = raw.charAt(start);
|
||||
if (!Character.isWhitespace(tok)) {
|
||||
return start;
|
||||
}
|
||||
start += 1;
|
||||
}
|
||||
throw new PcodeXMLException("Premature end of stream");
|
||||
}
|
||||
|
||||
private int scanIdentifier(int start) throws PcodeXMLException {
|
||||
while (start < raw.length()) {
|
||||
char tok = raw.charAt(start);
|
||||
if (!Character.isLetterOrDigit(tok)) {
|
||||
return start;
|
||||
}
|
||||
start += 1;
|
||||
}
|
||||
throw new PcodeXMLException("Premature end of stream");
|
||||
}
|
||||
|
||||
private int scanToEndOfStart(int start) throws PcodeXMLException {
|
||||
int state = 0;
|
||||
while (start < raw.length()) {
|
||||
char tok = raw.charAt(start);
|
||||
if (state == 0) {
|
||||
if (tok == '/' || tok == '>') {
|
||||
return start;
|
||||
}
|
||||
if (tok == '\"') {
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
else if (state == 1) {
|
||||
if (tok == '\"') {
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
start += 1;
|
||||
}
|
||||
throw new PcodeXMLException("Premature end of stream");
|
||||
}
|
||||
|
||||
private String scanElement() throws PcodeXMLException {
|
||||
int pos = currentPos;
|
||||
if (startOpen) {
|
||||
pos = scanToEndOfStart(pos);
|
||||
if (raw.charAt(pos) == '>') {
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
pos = scanWhiteSpace(pos);
|
||||
if (raw.charAt(pos) != '<') {
|
||||
throw new PcodeXMLException("Expecting start of element");
|
||||
}
|
||||
pos += 1;
|
||||
if (pos < raw.length() && raw.charAt(pos) == '/') {
|
||||
return null;
|
||||
}
|
||||
pos = scanWhiteSpace(pos);
|
||||
int endPos = scanIdentifier(pos);
|
||||
if (pos == endPos) {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
currentPos = endPos;
|
||||
startOpen = true;
|
||||
return raw.substring(pos, endPos);
|
||||
}
|
||||
|
||||
private int scanQuote() throws PcodeXMLException {
|
||||
int pos = currentPos + 1;
|
||||
while (pos < raw.length()) {
|
||||
if (raw.charAt(pos) == '\"') {
|
||||
return pos + 1;
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
throw new PcodeXMLException("Premature end of stream");
|
||||
}
|
||||
|
||||
private String scanAttribute() throws PcodeXMLException {
|
||||
int pos = currentPos;
|
||||
currentPos = scanQuote();
|
||||
return raw.substring(pos + 1, currentPos - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ingestStream(InputStream stream, String source) throws PcodeXMLException {
|
||||
throw new PcodeXMLException("Unimplemented method");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekElement() {
|
||||
int savePos = currentPos;
|
||||
boolean saveStartOpen = startOpen;
|
||||
String el;
|
||||
try {
|
||||
el = scanElement();
|
||||
currentPos = savePos;
|
||||
startOpen = saveStartOpen;
|
||||
if (el == null) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
currentPos = savePos;
|
||||
startOpen = saveStartOpen;
|
||||
return 0;
|
||||
}
|
||||
return ElementId.find(el);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int openElement() {
|
||||
String el;
|
||||
try {
|
||||
el = scanElement();
|
||||
if (el == null) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
return 0;
|
||||
}
|
||||
attribStart = currentPos;
|
||||
currentElement = ElementId.find(el);
|
||||
return currentElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int openElement(ElementId elemId) throws PcodeXMLException {
|
||||
String el = scanElement();
|
||||
if (el == null) {
|
||||
throw new PcodeXMLException("Expecting start of " + elemId.name());
|
||||
}
|
||||
attribStart = currentPos;
|
||||
currentElement = ElementId.find(el);
|
||||
if (currentElement != elemId.id()) {
|
||||
throw new PcodeXMLException("Expecting element " + elemId.name());
|
||||
}
|
||||
return currentElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElement(int id) throws PcodeXMLException {
|
||||
int pos = currentPos;
|
||||
if (startOpen) {
|
||||
pos = scanToEndOfStart(currentPos);
|
||||
char tok = raw.charAt(pos);
|
||||
if (tok == '/') {
|
||||
pos += 1;
|
||||
if (pos >= raw.length()) {
|
||||
throw new PcodeXMLException("Premature end of stream");
|
||||
}
|
||||
if (raw.charAt(pos) != '>') {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
currentPos = pos + 1;
|
||||
if (id != currentElement) {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
startOpen = false;
|
||||
return;
|
||||
}
|
||||
if (tok != '>') {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
startOpen = false;
|
||||
}
|
||||
pos = scanWhiteSpace(pos);
|
||||
if (raw.charAt(pos) != '<') {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
pos += 1;
|
||||
if (pos >= raw.length() || raw.charAt(pos) != '/') {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
pos = scanWhiteSpace(pos + 1);
|
||||
int endpos = scanIdentifier(pos);
|
||||
String ident = raw.substring(pos, endpos);
|
||||
if (id != ElementId.find(ident)) {
|
||||
throw new PcodeXMLException("Expecting end token");
|
||||
}
|
||||
pos = scanWhiteSpace(endpos);
|
||||
if (raw.charAt(pos) != '>') {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
currentPos = pos + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElementSkipping(int id) throws PcodeXMLException {
|
||||
throw new PcodeXMLException("closeElementSkipping unimplemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextAttributeId() {
|
||||
if (!startOpen) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
int pos = scanWhiteSpace(currentPos);
|
||||
char tok = raw.charAt(pos);
|
||||
if (tok == '\"') {
|
||||
pos = scanQuote();
|
||||
pos = scanWhiteSpace(pos);
|
||||
tok = raw.charAt(pos);
|
||||
}
|
||||
if (tok == '>' || tok == '/') {
|
||||
currentPos = pos;
|
||||
return 0;
|
||||
}
|
||||
int endPos = scanIdentifier(pos);
|
||||
if (pos == endPos) {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
String ident = raw.substring(pos, endPos);
|
||||
pos = scanWhiteSpace(endPos);
|
||||
if (raw.charAt(pos) != '=') {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
pos = scanWhiteSpace(pos + 1);
|
||||
if (raw.charAt(pos) != '\"') {
|
||||
throw new PcodeXMLException("Parse error");
|
||||
}
|
||||
currentPos = pos;
|
||||
return AttributeId.find(ident);
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void findAttribute(AttributeId attribId) throws PcodeXMLException {
|
||||
currentPos = attribStart;
|
||||
startOpen = true;
|
||||
for (;;) {
|
||||
int id = getNextAttributeId();
|
||||
if (id == 0) {
|
||||
break;
|
||||
}
|
||||
if (id == attribId.id()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new PcodeXMLException("Missing attribute: " + attribId.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewindAttributes() {
|
||||
currentPos = attribStart;
|
||||
startOpen = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBool() throws PcodeXMLException {
|
||||
String value = scanAttribute();
|
||||
return SpecXmlUtils.decodeBoolean(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBool(AttributeId attribId) throws PcodeXMLException {
|
||||
findAttribute(attribId);
|
||||
String value = scanAttribute();
|
||||
currentPos = attribStart;
|
||||
startOpen = true;
|
||||
return SpecXmlUtils.decodeBoolean(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readSignedInteger() throws PcodeXMLException {
|
||||
String value = scanAttribute();
|
||||
return SpecXmlUtils.decodeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readSignedInteger(AttributeId attribId) throws PcodeXMLException {
|
||||
findAttribute(attribId);
|
||||
String value = scanAttribute();
|
||||
currentPos = attribStart;
|
||||
startOpen = true;
|
||||
return SpecXmlUtils.decodeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInteger() throws PcodeXMLException {
|
||||
String value = scanAttribute();
|
||||
return SpecXmlUtils.decodeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInteger(AttributeId attribId) throws PcodeXMLException {
|
||||
findAttribute(attribId);
|
||||
String value = scanAttribute();
|
||||
currentPos = attribStart;
|
||||
startOpen = true;
|
||||
return SpecXmlUtils.decodeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString() throws PcodeXMLException {
|
||||
return scanAttribute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(AttributeId attribId) throws PcodeXMLException {
|
||||
findAttribute(attribId);
|
||||
String value = scanAttribute();
|
||||
currentPos = attribStart;
|
||||
startOpen = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace readSpace() throws PcodeXMLException {
|
||||
String value = scanAttribute();
|
||||
AddressSpace spc = addressFactory.getAddressSpace(value);
|
||||
if (spc == null) {
|
||||
throw new PcodeXMLException("Unknown address space: " + value);
|
||||
}
|
||||
return spc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace readSpace(AttributeId attribId) throws PcodeXMLException {
|
||||
findAttribute(attribId);
|
||||
String value = scanAttribute();
|
||||
currentPos = attribStart;
|
||||
startOpen = true;
|
||||
AddressSpace spc = addressFactory.getAddressSpace(value);
|
||||
if (spc == null) {
|
||||
throw new PcodeXMLException("Unknown address space: " + value);
|
||||
}
|
||||
return spc;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@ package ghidra.program.model.pcode;
|
|||
import static ghidra.program.model.pcode.AttributeId.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
|
@ -168,7 +169,13 @@ public class XmlEncode implements Encoder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
return buffer.toString().getBytes();
|
||||
public void writeTo(OutputStream stream) throws IOException {
|
||||
byte[] res = buffer.toString().getBytes();
|
||||
stream.write(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return buffer.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,483 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import static ghidra.program.model.pcode.AttributeId.*;
|
||||
import static ghidra.program.model.pcode.ElementId.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.program.model.address.*;
|
||||
|
||||
public class EncodeDecodeTest extends AbstractGenericTest {
|
||||
|
||||
private AddressFactory addrFactory;
|
||||
|
||||
private void testSignedAttributes(Encoder encoder, Decoder decoder)
|
||||
throws DecoderException, IOException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_ADDR);
|
||||
encoder.writeSignedInteger(ATTRIB_ALIGN, 3); // 7-bits
|
||||
encoder.writeSignedInteger(ATTRIB_BIGENDIAN, -0x100); // 14-bits
|
||||
encoder.writeSignedInteger(ATTRIB_CONSTRUCTOR, 0x1fffff); // 21-bits
|
||||
encoder.writeSignedInteger(ATTRIB_DESTRUCTOR, -0xabcdefa); // 28-bits
|
||||
encoder.writeSignedInteger(ATTRIB_EXTRAPOP, 0x300000000L); // 35-bits
|
||||
encoder.writeSignedInteger(ATTRIB_FORMAT, -0x30101010101L); // 42-bits
|
||||
encoder.writeSignedInteger(ATTRIB_ID, 0x123456789011L); // 49-bits
|
||||
encoder.writeSignedInteger(ATTRIB_INDEX, -0xf0f0f0f0f0f0f0L); // 56-bits
|
||||
encoder.writeSignedInteger(ATTRIB_METATYPE, 0x7fffffffffffffffL); // 63-bits
|
||||
encoder.closeElement(ELEM_ADDR);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testSignedAttributes");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
int el = decoder.openElement(ELEM_ADDR);
|
||||
int flags = 0;
|
||||
for (;;) {
|
||||
int attribId = decoder.getNextAttributeId();
|
||||
if (attribId == 0) {
|
||||
break;
|
||||
}
|
||||
if (attribId == ATTRIB_ALIGN.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 1;
|
||||
assertEquals(val, 3);
|
||||
}
|
||||
else if (attribId == ATTRIB_BIGENDIAN.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 2;
|
||||
assertEquals(val, -0x100);
|
||||
}
|
||||
else if (attribId == ATTRIB_CONSTRUCTOR.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 4;
|
||||
assertEquals(val, 0x1fffff);
|
||||
}
|
||||
else if (attribId == ATTRIB_DESTRUCTOR.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 8;
|
||||
assertEquals(val, -0xabcdefa);
|
||||
}
|
||||
else if (attribId == ATTRIB_EXTRAPOP.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 0x10;
|
||||
assertEquals(val, 0x300000000L);
|
||||
}
|
||||
else if (attribId == ATTRIB_FORMAT.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 0x20;
|
||||
assertEquals(val, -0x30101010101L);
|
||||
}
|
||||
else if (attribId == ATTRIB_ID.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 0x40;
|
||||
assertEquals(val, 0x123456789011L);
|
||||
}
|
||||
else if (attribId == ATTRIB_INDEX.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 0x80;
|
||||
assertEquals(val, -0xf0f0f0f0f0f0f0L);
|
||||
}
|
||||
else if (attribId == ATTRIB_METATYPE.id()) {
|
||||
long val = decoder.readSignedInteger();
|
||||
flags |= 0x100;
|
||||
assertEquals(val, 0x7fffffffffffffffL);
|
||||
}
|
||||
}
|
||||
decoder.closeElement(el);
|
||||
assertEquals(flags, 0x1ff);
|
||||
}
|
||||
|
||||
private void testUnsignedAttributes(Encoder encoder, Decoder decoder)
|
||||
throws DecoderException, IOException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_ADDR);
|
||||
encoder.writeUnsignedInteger(ATTRIB_ALIGN, 3); // 7-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_BIGENDIAN, 0x100); // 14-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_CONSTRUCTOR, 0x1fffff); // 21-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_DESTRUCTOR, 0xabcdefa); // 28-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_EXTRAPOP, 0x300000000L); // 35-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_FORMAT, 0x30101010101L); // 42-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_ID, 0x123456789011L); // 49-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_INDEX, 0xf0f0f0f0f0f0f0L); // 56-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_METATYPE, 0x7fffffffffffffffL); // 63-bits
|
||||
encoder.writeUnsignedInteger(ATTRIB_MODEL, 0x8000000000000000L); // 64-bits
|
||||
encoder.closeElement(ELEM_ADDR);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testUnsignedAttributes");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
int el = decoder.openElement(ELEM_ADDR);
|
||||
long val = decoder.readUnsignedInteger(ATTRIB_ALIGN);
|
||||
assertEquals(val, 3);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_BIGENDIAN);
|
||||
assertEquals(val, 0x100);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_CONSTRUCTOR);
|
||||
assertEquals(val, 0x1fffff);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_DESTRUCTOR);
|
||||
assertEquals(val, 0xabcdefa);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_EXTRAPOP);
|
||||
assertEquals(val, 0x300000000L);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_FORMAT);
|
||||
assertEquals(val, 0x30101010101L);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_ID);
|
||||
assertEquals(val, 0x123456789011L);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_INDEX);
|
||||
assertEquals(val, 0xf0f0f0f0f0f0f0L);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_METATYPE);
|
||||
assertEquals(val, 0x7fffffffffffffffL);
|
||||
val = decoder.readUnsignedInteger(ATTRIB_MODEL);
|
||||
assertEquals(val, 0x8000000000000000L);
|
||||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
private void testAttributes(Encoder encoder, Decoder decoder)
|
||||
throws DecoderException, IOException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_DATA);
|
||||
encoder.writeBool(ATTRIB_ALIGN, true);
|
||||
encoder.writeBool(ATTRIB_BIGENDIAN, false);
|
||||
AddressSpace spc = addrFactory.getDefaultAddressSpace();
|
||||
encoder.writeSpace(ATTRIB_SPACE, spc);
|
||||
encoder.writeString(ATTRIB_VAL, ""); // Empty string
|
||||
encoder.writeString(ATTRIB_VALUE, "hello");
|
||||
encoder.writeString(ATTRIB_CONSTRUCTOR, "<<\u20ac>>&\"bl a h\'\\bleh\n\t");
|
||||
String longString =
|
||||
"one to three four five six seven eight nine ten eleven twelve thirteen " +
|
||||
"fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty one " +
|
||||
"blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah";
|
||||
encoder.writeString(ATTRIB_DESTRUCTOR, longString);
|
||||
encoder.closeElement(ELEM_DATA);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testAttributes");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
int el = decoder.openElement(ELEM_DATA);
|
||||
boolean bval = decoder.readBool(ATTRIB_ALIGN);
|
||||
assertTrue(bval);
|
||||
bval = decoder.readBool(ATTRIB_BIGENDIAN);
|
||||
assertTrue(!bval);
|
||||
spc = decoder.readSpace(ATTRIB_SPACE);
|
||||
assertEquals(spc, addrFactory.getDefaultAddressSpace());
|
||||
String val = decoder.readString(ATTRIB_VAL);
|
||||
assertEquals(val, "");
|
||||
val = decoder.readString(ATTRIB_VALUE);
|
||||
assertEquals(val, "hello");
|
||||
val = decoder.readString(ATTRIB_CONSTRUCTOR);
|
||||
assertEquals(val, "<<\u20ac>>&\"bl a h\'\\bleh\n\t");
|
||||
val = decoder.readString(ATTRIB_DESTRUCTOR);
|
||||
assertEquals(val, longString);
|
||||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
private void testHierarchy(Encoder encoder, Decoder decoder)
|
||||
throws IOException, DecoderException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_DATA); // el1
|
||||
encoder.writeBool(ATTRIB_CONTENT, true);
|
||||
encoder.openElement(ELEM_INPUT); // el2
|
||||
encoder.openElement(ELEM_OUTPUT); // el3
|
||||
encoder.writeSignedInteger(ATTRIB_ID, 0x1000);
|
||||
encoder.openElement(ELEM_DATA); // el4
|
||||
encoder.openElement(ELEM_DATA); // el5
|
||||
encoder.openElement(ELEM_OFF); // el6
|
||||
encoder.closeElement(ELEM_OFF);
|
||||
encoder.openElement(ELEM_OFF); // el6
|
||||
encoder.writeString(ATTRIB_ID, "blahblah");
|
||||
encoder.closeElement(ELEM_OFF);
|
||||
encoder.openElement(ELEM_OFF); // el6
|
||||
encoder.closeElement(ELEM_OFF);
|
||||
encoder.closeElement(ELEM_DATA); // close el5
|
||||
encoder.closeElement(ELEM_DATA); // close el4
|
||||
encoder.openElement(ELEM_SYMBOL); // skip4
|
||||
encoder.writeUnsignedInteger(ATTRIB_ID, 17);
|
||||
encoder.openElement(ELEM_TARGET); // skip5
|
||||
encoder.closeElement(ELEM_TARGET); // close skip5
|
||||
encoder.closeElement(ELEM_SYMBOL); // close skip4
|
||||
encoder.closeElement(ELEM_OUTPUT); // close el3
|
||||
encoder.closeElement(ELEM_INPUT); // close el2
|
||||
encoder.openElement(ELEM_INPUT); // el2
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_INPUT); // el2
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_INPUT); // el2
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_INPUT); // el2
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_INPUT); // el2
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_INPUT); // el2
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
encoder.closeElement(ELEM_DATA); // close el1
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testHierarchy");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
int el1 = decoder.openElement(ELEM_DATA);
|
||||
// Skip over the bool
|
||||
int el2 = decoder.openElement(ELEM_INPUT);
|
||||
int el3 = decoder.openElement(ELEM_OUTPUT);
|
||||
int val = (int) decoder.readSignedInteger(ATTRIB_ID);
|
||||
assertEquals(val, 0x1000);
|
||||
int el4 = decoder.peekElement();
|
||||
assertEquals(el4, ELEM_DATA.id());
|
||||
decoder.openElement();
|
||||
int el5 = decoder.openElement();
|
||||
assertEquals(el5, ELEM_DATA.id());
|
||||
int el6 = decoder.openElement(ELEM_OFF);
|
||||
decoder.closeElement(el6);
|
||||
el6 = decoder.openElement(ELEM_OFF);
|
||||
decoder.closeElement(el6);
|
||||
el6 = decoder.openElement(ELEM_OFF);
|
||||
decoder.closeElement(el6);
|
||||
decoder.closeElement(el5);
|
||||
decoder.closeElement(el4);
|
||||
decoder.closeElementSkipping(el3);
|
||||
decoder.closeElement(el2);
|
||||
el2 = decoder.openElement(ELEM_INPUT);
|
||||
decoder.closeElement(el2);
|
||||
el2 = decoder.openElement(ELEM_INPUT);
|
||||
decoder.closeElement(el2);
|
||||
decoder.closeElementSkipping(el1);
|
||||
}
|
||||
|
||||
private void testUnexpectedEof(Encoder encoder, Decoder decoder) throws IOException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_DATA);
|
||||
encoder.openElement(ELEM_INPUT);
|
||||
encoder.writeString(ATTRIB_NAME, "hello");
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
boolean sawUnexpectedError = false;
|
||||
try {
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testAttributes");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
int el1 = decoder.openElement(ELEM_DATA);
|
||||
int el2 = decoder.openElement(ELEM_INPUT);
|
||||
decoder.closeElement(el2);
|
||||
decoder.closeElement(el1);
|
||||
}
|
||||
catch (DecoderException err) {
|
||||
sawUnexpectedError = true;
|
||||
}
|
||||
assertTrue(sawUnexpectedError);
|
||||
}
|
||||
|
||||
public void testNoremaining(Encoder encoder, Decoder decoder)
|
||||
throws IOException, DecoderException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_OFF);
|
||||
encoder.closeElement(ELEM_OFF);
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testNoremaining");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
decoder.openElement(ELEM_INPUT);
|
||||
int el2 = decoder.openElement(ELEM_OFF);
|
||||
decoder.closeElement(el2);
|
||||
boolean sawNoRemaining = false;
|
||||
try {
|
||||
el2 = decoder.openElement(ELEM_OFF);
|
||||
}
|
||||
catch (DecoderException err) {
|
||||
sawNoRemaining = true;
|
||||
}
|
||||
assertTrue(sawNoRemaining);
|
||||
}
|
||||
|
||||
private void testOpenmismatch(Encoder encoder, Decoder decoder)
|
||||
throws IOException, DecoderException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_OFF);
|
||||
encoder.closeElement(ELEM_OFF);
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testOpenmismatch");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
decoder.openElement(ELEM_INPUT);
|
||||
boolean sawOpenMismatch = false;
|
||||
try {
|
||||
decoder.openElement(ELEM_OUTPUT);
|
||||
}
|
||||
catch (DecoderException err) {
|
||||
sawOpenMismatch = true;
|
||||
}
|
||||
assertTrue(sawOpenMismatch);
|
||||
}
|
||||
|
||||
private void testClosemismatch(Encoder encoder, Decoder decoder)
|
||||
throws IOException, DecoderException
|
||||
|
||||
{
|
||||
encoder.openElement(ELEM_INPUT);
|
||||
encoder.openElement(ELEM_OFF);
|
||||
encoder.closeElement(ELEM_OFF);
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
|
||||
decoder.open(1 << 20, "testClosemismatch");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
int el1 = decoder.openElement(ELEM_INPUT);
|
||||
boolean sawCloseMismatch = false;
|
||||
try {
|
||||
decoder.closeElement(el1);
|
||||
}
|
||||
catch (DecoderException err) {
|
||||
sawCloseMismatch = true;
|
||||
}
|
||||
assertTrue(sawCloseMismatch);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
AddressSpace spaces[] = new AddressSpace[4];
|
||||
spaces[0] = new GenericAddressSpace("ram", 32, AddressSpace.TYPE_RAM, 2);
|
||||
spaces[1] = new GenericAddressSpace("register", 32, AddressSpace.TYPE_REGISTER, 3);
|
||||
spaces[2] = new GenericAddressSpace("const", 32, AddressSpace.TYPE_CONSTANT, 0);
|
||||
spaces[3] = new GenericAddressSpace("unique", 32, AddressSpace.TYPE_UNIQUE, 1);
|
||||
|
||||
addrFactory = new DefaultAddressFactory(spaces);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarshalSignedPacked() throws DecoderException, IOException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testSignedAttributes(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalUnsignedPacked() throws DecoderException, IOException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testUnsignedAttributes(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalAttribsPacked() throws DecoderException, IOException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testAttributes(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalHierarchyPacked() throws DecoderException, IOException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testHierarchy(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalUnexpectedPacked() throws IOException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testUnexpectedEof(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalNoremainingPacked() throws IOException, DecoderException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testNoremaining(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalOpenmismatchPacked() throws IOException, DecoderException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testOpenmismatch(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalClosemismatchPacked() throws IOException, DecoderException {
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
testClosemismatch(encoder, decoder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalBufferpad() throws IOException, DecoderException {
|
||||
assertEquals(LinkedByteBuffer.BUFFER_SIZE, 1024);
|
||||
PackedEncode encoder = new PackedEncode();
|
||||
encoder.clear();
|
||||
encoder.openElement(ELEM_INPUT); // 1-byte
|
||||
for (int i = 0; i < 511; ++i) {
|
||||
encoder.writeBool(ATTRIB_CONTENT, (i & 1) == 0);
|
||||
}
|
||||
encoder.closeElement(ELEM_INPUT);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
encoder.writeTo(outStream);
|
||||
byte[] bytesOut = outStream.toByteArray();
|
||||
assertEquals(bytesOut.length, 1024); // Encoding should exactly fill one buffer
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(bytesOut);
|
||||
PackedDecode decoder = new PackedDecode(addrFactory);
|
||||
decoder.open(1 << 20, "marshalBufferpad");
|
||||
decoder.ingestStream(inStream);
|
||||
decoder.endIngest();
|
||||
int el = decoder.openElement(ELEM_INPUT);
|
||||
for (int i = 0; i < 511; ++i) {
|
||||
int attribId = decoder.getNextAttributeId();
|
||||
assertEquals(attribId, ATTRIB_CONTENT.id());
|
||||
boolean val = decoder.readBool();
|
||||
assertEquals(val, (i & 1) == 0);
|
||||
}
|
||||
int nextel = decoder.peekElement();
|
||||
assertEquals(nextel, 0);
|
||||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue