/* ### * 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. */ #include "translate.hh" #include "test.hh" namespace ghidra { class TestAddrSpaceManager : public AddrSpaceManager { public: TestAddrSpaceManager(Translate *t); }; class DummyTranslate : public Translate { public: virtual void initialize(DocumentStorage &store) {} virtual const VarnodeData &getRegister(const string &nm) const { throw LowlevelError("Cannot add register to DummyTranslate"); } virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; } virtual string getExactRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; } virtual void getAllRegisters(map ®list) const {} virtual void getUserOpNames(vector &res) const {} virtual int4 instructionLength(const Address &baseaddr) const { return -1; } virtual int4 oneInstruction(PcodeEmit &emit,const Address &baseaddr) const { return -1; } virtual int4 printAssembly(AssemblyEmit &emit,const Address &baseaddr) const { return -1; } }; class MarshalTestEnvironment { DummyTranslate translate; TestAddrSpaceManager addrSpaceManage; public: MarshalTestEnvironment(void); static void build(void); }; static AddrSpaceManager *spcManager = (AddrSpaceManager *)0; static MarshalTestEnvironment theEnviron; TestAddrSpaceManager::TestAddrSpaceManager(Translate *t) : AddrSpaceManager() { insertSpace(new AddrSpace(this,t,IPTR_PROCESSOR,"ram",t->isBigEndian(),8,1,3,AddrSpace::hasphysical,1,1)); } MarshalTestEnvironment::MarshalTestEnvironment(void) : translate(), addrSpaceManage(&translate) { } void MarshalTestEnvironment::build(void) { spcManager = &theEnviron.addrSpaceManage; } void test_signed_attributes(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { 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, 0x300000000); // 35-bits encoder.writeSignedInteger(ATTRIB_FORMAT, -0x30101010101); // 42-bits encoder.writeSignedInteger(ATTRIB_ID, 0x123456789011); // 49-bits encoder.writeSignedInteger(ATTRIB_INDEX, -0xf0f0f0f0f0f0f0); // 56-bits encoder.writeSignedInteger(ATTRIB_METATYPE, 0x7fffffffffffffff); // 63-bits encoder.closeElement(ELEM_ADDR); istringstream inStream(outStream.str()); decoder.ingestStream(inStream); uint4 el = decoder.openElement(ELEM_ADDR); uint4 flags = 0; for(;;) { uint4 attribId = decoder.getNextAttributeId(); if (attribId == 0) break; if (attribId == ATTRIB_ALIGN) { int8 val = decoder.readSignedInteger(); flags |= 1; ASSERT_EQUALS(val, 3); } else if (attribId == ATTRIB_BIGENDIAN) { int8 val = decoder.readSignedInteger(); flags |= 2; ASSERT_EQUALS(val, -0x100); } else if (attribId == ATTRIB_CONSTRUCTOR) { int8 val = decoder.readSignedInteger(); flags |= 4; ASSERT_EQUALS(val, 0x1fffff); } else if (attribId == ATTRIB_DESTRUCTOR) { int8 val = decoder.readSignedInteger(); flags |= 8; ASSERT_EQUALS(val, -0xabcdefa); } else if (attribId == ATTRIB_EXTRAPOP) { int8 val = decoder.readSignedInteger(); flags |= 0x10; ASSERT_EQUALS(val, 0x300000000); } else if (attribId == ATTRIB_FORMAT) { int8 val = decoder.readSignedInteger(); flags |= 0x20; ASSERT_EQUALS(val, -0x30101010101); } else if (attribId == ATTRIB_ID) { int8 val = decoder.readSignedInteger(); flags |= 0x40; ASSERT_EQUALS(val, 0x123456789011); } else if (attribId == ATTRIB_INDEX) { int8 val = decoder.readSignedInteger(); flags |= 0x80; ASSERT_EQUALS(val, -0xf0f0f0f0f0f0f0); } else if (attribId == ATTRIB_METATYPE) { int8 val = decoder.readSignedInteger(); flags |= 0x100; ASSERT_EQUALS(val, 0x7fffffffffffffff); } } decoder.closeElement(el); ASSERT_EQUALS(flags,0x1ff); } void test_unsigned_attributes(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { 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, 0x300000000); // 35-bits encoder.writeUnsignedInteger(ATTRIB_FORMAT, 0x30101010101); // 42-bits encoder.writeUnsignedInteger(ATTRIB_ID, 0x123456789011); // 49-bits encoder.writeUnsignedInteger(ATTRIB_INDEX, 0xf0f0f0f0f0f0f0); // 56-bits encoder.writeUnsignedInteger(ATTRIB_METATYPE, 0x7fffffffffffffff); // 63-bits encoder.writeUnsignedInteger(ATTRIB_MODEL, 0x8000000000000000); // 64-bits encoder.closeElement(ELEM_ADDR); istringstream inStream(outStream.str()); decoder.ingestStream(inStream); uint4 el = decoder.openElement(ELEM_ADDR); uint8 val = decoder.readUnsignedInteger(ATTRIB_ALIGN); ASSERT_EQUALS(val, 3); val = decoder.readUnsignedInteger(ATTRIB_BIGENDIAN); ASSERT_EQUALS(val, 0x100); val = decoder.readUnsignedInteger(ATTRIB_CONSTRUCTOR); ASSERT_EQUALS(val, 0x1fffff); val = decoder.readUnsignedInteger(ATTRIB_DESTRUCTOR); ASSERT_EQUALS(val, 0xabcdefa); val = decoder.readUnsignedInteger(ATTRIB_EXTRAPOP); ASSERT_EQUALS(val, 0x300000000); val = decoder.readUnsignedInteger(ATTRIB_FORMAT); ASSERT_EQUALS(val, 0x30101010101); val = decoder.readUnsignedInteger(ATTRIB_ID); ASSERT_EQUALS(val, 0x123456789011); val = decoder.readUnsignedInteger(ATTRIB_INDEX); ASSERT_EQUALS(val, 0xf0f0f0f0f0f0f0); val = decoder.readUnsignedInteger(ATTRIB_METATYPE); ASSERT_EQUALS(val, 0x7fffffffffffffff); val = decoder.readUnsignedInteger(ATTRIB_MODEL); ASSERT_EQUALS(val, 0x8000000000000000); decoder.closeElement(el); } TEST(marshal_signed_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_signed_attributes(outStream, encoder, decoder); } TEST(marshal_signed_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_signed_attributes(outStream, encoder, decoder); } TEST(marshal_unsigned_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_unsigned_attributes(outStream, encoder, decoder); } TEST(marshal_unsigned_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_unsigned_attributes(outStream, encoder, decoder); } void test_mixed_attributes(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { encoder.openElement(ELEM_ADDR); encoder.writeSignedInteger(ATTRIB_ALIGN, 456); encoder.writeString(ATTRIB_EXTRAPOP, "unknown"); encoder.closeElement(ELEM_ADDR); istringstream inStream(outStream.str()); decoder.ingestStream(inStream); int4 alignVal = -1; int4 extrapopVal = -1; uint4 el = decoder.openElement(ELEM_ADDR); for(;;) { uint4 attribId = decoder.getNextAttributeId(); if (attribId == 0) break; if (attribId == ATTRIB_ALIGN) alignVal = decoder.readSignedIntegerExpectString("00blah", 700); else if (attribId == ATTRIB_EXTRAPOP) extrapopVal = decoder.readSignedIntegerExpectString("unknown", 800); } decoder.closeElement(el); ASSERT_EQUALS(alignVal, 456); ASSERT_EQUALS(extrapopVal, 800); } TEST(marshal_mixed_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_mixed_attributes(outStream, encoder, decoder); } TEST(marshal_mixed_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_mixed_attributes(outStream, encoder, decoder); } void test_attributes(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { encoder.openElement(ELEM_DATA); encoder.writeBool(ATTRIB_ALIGN, true); encoder.writeBool(ATTRIB_BIGENDIAN, false); AddrSpace *spc = spcManager->getSpace(3); encoder.writeSpace(ATTRIB_SPACE, spc); encoder.writeString(ATTRIB_VAL,""); // Empty string encoder.writeString(ATTRIB_VALUE,"hello"); encoder.writeString(ATTRIB_CONSTRUCTOR,"<<\xe2\x82\xac>>&\"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); istringstream inStream(outStream.str()); decoder.ingestStream(inStream); uint4 el = decoder.openElement(ELEM_DATA); bool bval = decoder.readBool(ATTRIB_ALIGN); ASSERT(bval); bval = decoder.readBool(ATTRIB_BIGENDIAN); ASSERT(!bval); spc = decoder.readSpace(ATTRIB_SPACE); ASSERT_EQUALS(spc,spcManager->getSpace(3)); string val = decoder.readString(ATTRIB_VAL); ASSERT_EQUALS(val,""); val = decoder.readString(ATTRIB_VALUE); ASSERT_EQUALS(val,"hello"); val = decoder.readString(ATTRIB_CONSTRUCTOR); ASSERT_EQUALS(val,"<<\xe2\x82\xac>>&\"bl a h\'\\bleh\n\t"); val = decoder.readString(ATTRIB_DESTRUCTOR); ASSERT_EQUALS(val,longString); decoder.closeElement(el); } TEST(marshal_attribs_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_attributes(outStream, encoder, decoder); } TEST(marshal_attribs_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_attributes(outStream, encoder, decoder); } void test_hierarchy(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { 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 istringstream inStream(outStream.str()); decoder.ingestStream(inStream); uint4 el1 = decoder.openElement(ELEM_DATA); // Skip over the bool uint4 el2 = decoder.openElement(ELEM_INPUT); uint4 el3 = decoder.openElement(ELEM_OUTPUT); int4 val = decoder.readSignedInteger(ATTRIB_ID); ASSERT_EQUALS(val, 0x1000); uint4 el4 = decoder.peekElement(); ASSERT_EQUALS(el4, ELEM_DATA.getId()); decoder.openElement(); uint4 el5 = decoder.openElement(); ASSERT_EQUALS(el5, ELEM_DATA.getId()); uint4 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); } TEST(marshal_hierarchy_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_hierarchy(outStream, encoder, decoder); } TEST(marshal_hierarchy_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_hierarchy(outStream, encoder, decoder); } void test_unexpected_eof(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { encoder.openElement(ELEM_DATA); encoder.openElement(ELEM_INPUT); encoder.writeString(ATTRIB_NAME,"hello"); encoder.closeElement(ELEM_INPUT); bool sawUnexpectedError = false; try { istringstream inStream(outStream.str()); decoder.ingestStream(inStream); uint4 el1 = decoder.openElement(ELEM_DATA); uint4 el2 = decoder.openElement(ELEM_INPUT); decoder.closeElement(el2); decoder.closeElement(el1); } catch(DecoderError &err) { sawUnexpectedError = true; } ASSERT(sawUnexpectedError); } TEST(marshal_unexpected_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_unexpected_eof(outStream, encoder, decoder); } TEST(marshal_unexpected_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_unexpected_eof(outStream, encoder, decoder); } void test_noremaining(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { encoder.openElement(ELEM_INPUT); encoder.openElement(ELEM_OFF); encoder.closeElement(ELEM_OFF); encoder.closeElement(ELEM_INPUT); istringstream inStream(outStream.str()); decoder.ingestStream(inStream); decoder.openElement(ELEM_INPUT); uint4 el2 = decoder.openElement(ELEM_OFF); decoder.closeElement(el2); bool sawNoRemaining = false; try { el2 = decoder.openElement(ELEM_OFF); } catch(DecoderError &err) { sawNoRemaining = true; } ASSERT(sawNoRemaining); } void test_openmismatch(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { encoder.openElement(ELEM_INPUT); encoder.openElement(ELEM_OFF); encoder.closeElement(ELEM_OFF); encoder.closeElement(ELEM_INPUT); istringstream inStream(outStream.str()); decoder.ingestStream(inStream); decoder.openElement(ELEM_INPUT); bool sawOpenMismatch = false; try { decoder.openElement(ELEM_OUTPUT); } catch(DecoderError &err) { sawOpenMismatch = true; } ASSERT(sawOpenMismatch); } void test_closemismatch(ostringstream &outStream,Encoder &encoder,Decoder &decoder) { encoder.openElement(ELEM_INPUT); encoder.openElement(ELEM_OFF); encoder.closeElement(ELEM_OFF); encoder.closeElement(ELEM_INPUT); istringstream inStream(outStream.str()); decoder.ingestStream(inStream); uint4 el1 = decoder.openElement(ELEM_INPUT); bool sawCloseMismatch = false; try { decoder.closeElement(el1); } catch(DecoderError &err) { sawCloseMismatch = true; } ASSERT(sawCloseMismatch); } TEST(marshal_noremaining_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_noremaining(outStream, encoder, decoder); } TEST(marshal_noremaining_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_noremaining(outStream, encoder, decoder); } TEST(marshal_openmismatch_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_openmismatch(outStream, encoder, decoder); } TEST(marshal_openmismatch_xml) { ostringstream outStream; theEnviron.build(); XmlEncode encoder(outStream); XmlDecode decoder(spcManager); test_openmismatch(outStream, encoder, decoder); } TEST(marshal_closemismatch_packed) { ostringstream outStream; theEnviron.build(); PackedEncode encoder(outStream); PackedDecode decoder(spcManager); test_closemismatch(outStream, encoder, decoder); } TEST(marshal_bufferpad) { ASSERT_EQUALS(PackedDecode::BUFFER_SIZE,1024); ostringstream s; PackedEncode encoder(s); encoder.openElement(ELEM_INPUT); // 1-byte for(int4 i=0;i<511;++i) // 1022-bytes encoder.writeBool(ATTRIB_CONTENT, (i&1) == 0); encoder.closeElement(ELEM_INPUT); ASSERT_EQUALS(s.str().length(),1024); // Encoding should exactly fill one buffer istringstream s2(s.str()); PackedDecode decoder(spcManager); decoder.ingestStream(s2); uint4 el = decoder.openElement(ELEM_INPUT); for(int4 i=0;i<511;++i) { uint4 attribId = decoder.getNextAttributeId(); ASSERT_EQUALS(attribId,ATTRIB_CONTENT.getId()); bool val = decoder.readBool(); ASSERT_EQUALS(val, (i&1) == 0); } uint4 nextel = decoder.peekElement(); ASSERT_EQUALS(nextel,0); decoder.closeElement(el); } } // End namespace ghidra