/* ### * 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 "cpool.hh" namespace ghidra { AttributeId ATTRIB_A = AttributeId("a",80); AttributeId ATTRIB_B = AttributeId("b",81); AttributeId ATTRIB_LENGTH = AttributeId("length",82); AttributeId ATTRIB_TAG = AttributeId("tag",83); ElementId ELEM_CONSTANTPOOL = ElementId("constantpool",109); ElementId ELEM_CPOOLREC = ElementId("cpoolrec",110); ElementId ELEM_REF = ElementId("ref",111); ElementId ELEM_TOKEN = ElementId("token",112); /// Encode the constant pool object description as a \ element. /// \param encoder is the stream encoder void CPoolRecord::encode(Encoder &encoder) const { encoder.openElement(ELEM_CPOOLREC); if (tag == pointer_method) encoder.writeString(ATTRIB_TAG, "method"); else if (tag == pointer_field) encoder.writeString(ATTRIB_TAG, "field"); else if (tag == instance_of) encoder.writeString(ATTRIB_TAG, "instanceof"); else if (tag == array_length) encoder.writeString(ATTRIB_TAG, "arraylength"); else if (tag == check_cast) encoder.writeString(ATTRIB_TAG, "checkcast"); else if (tag == string_literal) encoder.writeString(ATTRIB_TAG, "string"); else if (tag == class_reference) encoder.writeString(ATTRIB_TAG, "classref"); else encoder.writeString(ATTRIB_TAG, "primitive"); if (isConstructor()) encoder.writeBool(ATTRIB_CONSTRUCTOR, true); if (isDestructor()) encoder.writeBool(ATTRIB_DESTRUCTOR, true); if (tag == primitive) { encoder.openElement(ELEM_VALUE); encoder.writeUnsignedInteger(ATTRIB_CONTENT, value); encoder.closeElement(ELEM_VALUE); } if (byteData != (uint1 *)0) { encoder.openElement(ELEM_DATA); encoder.writeSignedInteger(ATTRIB_LENGTH, byteDataLen); int4 wrap = 0; ostringstream s; for(int4 i=0;i 15) { s << '\n'; wrap = 0; } } encoder.writeString(ATTRIB_CONTENT, s.str()); encoder.closeElement(ELEM_DATA); } else { encoder.openElement(ELEM_TOKEN); encoder.writeString(ATTRIB_CONTENT, token); encoder.closeElement(ELEM_TOKEN); } type->encode(encoder); encoder.closeElement(ELEM_CPOOLREC); } /// Initialize \b this CPoolRecord instance from a \ element. /// \param decoder is the stream decoder /// \param typegrp is the TypeFactory used to resolve data-types void CPoolRecord::decode(Decoder &decoder,TypeFactory &typegrp) { tag = primitive; // Default tag value = 0; flags = 0; uint4 elemId = decoder.openElement(ELEM_CPOOLREC); for(;;) { uint4 attribId = decoder.getNextAttributeId(); if (attribId == 0) break; if (attribId == ATTRIB_TAG) { string tagstring = decoder.readString(); if (tagstring == "method") tag = pointer_method; else if (tagstring == "field") tag = pointer_field; else if (tagstring == "instanceof") tag = instance_of; else if (tagstring == "arraylength") tag = array_length; else if (tagstring == "checkcast") tag = check_cast; else if (tagstring == "string") tag = string_literal; else if (tagstring == "classref") tag = class_reference; } else if (attribId == ATTRIB_CONSTRUCTOR) { if (decoder.readBool()) flags |= CPoolRecord::is_constructor; } else if (attribId == ATTRIB_DESTRUCTOR) { if (decoder.readBool()) flags |= CPoolRecord::is_destructor; } } uint4 subId; if (tag == primitive) { // First tag must be value subId = decoder.openElement(ELEM_VALUE); value = decoder.readUnsignedInteger(ATTRIB_CONTENT); decoder.closeElement(subId); } subId = decoder.openElement(); if (subId == ELEM_TOKEN) token = decoder.readString(ATTRIB_CONTENT); else { byteDataLen = decoder.readSignedInteger(ATTRIB_LENGTH); istringstream s3(decoder.readString(ATTRIB_CONTENT)); byteData = new uint1[byteDataLen]; for(int4 i=0;i> ws >> hex >> val; byteData[i] = (uint1)val; } } decoder.closeElement(subId); if (tag == string_literal && (byteData == (uint1 *)0)) throw LowlevelError("Bad constant pool record: missing "); if (flags != 0) { bool isConstructor = ((flags & is_constructor)!=0); bool isDestructor = ((flags & is_destructor)!=0); type = typegrp.decodeTypeWithCodeFlags(decoder,isConstructor,isDestructor); } else type = typegrp.decodeType(decoder); decoder.closeElement(elemId); } void ConstantPool::putRecord(const vector &refs,uint4 tag,const string &tok,Datatype *ct) { CPoolRecord *newrec = createRecord(refs); newrec->tag = tag; newrec->token = tok; newrec->type = ct; } const CPoolRecord *ConstantPool::decodeRecord(const vector &refs,Decoder &decoder,TypeFactory &typegrp) { CPoolRecord *newrec = createRecord(refs); newrec->decode(decoder,typegrp); return newrec; } /// The reference is encoded as a \ element. /// \param encoder is the stream encoder void ConstantPoolInternal::CheapSorter::encode(Encoder &encoder) const { encoder.openElement(ELEM_REF); encoder.writeUnsignedInteger(ATTRIB_A, a); encoder.writeUnsignedInteger(ATTRIB_B, b); encoder.closeElement(ELEM_REF); } /// Restore \b this \e reference from a \ element /// \param decoder is the stream decoder void ConstantPoolInternal::CheapSorter::decode(Decoder &decoder) { uint4 elemId = decoder.openElement(ELEM_REF); a = decoder.readUnsignedInteger(ATTRIB_A); b = decoder.readUnsignedInteger(ATTRIB_B); decoder.closeElement(elemId); } CPoolRecord *ConstantPoolInternal::createRecord(const vector &refs) { CheapSorter sorter(refs); pair::iterator,bool> res; res = cpoolMap.emplace(piecewise_construct,forward_as_tuple(sorter),forward_as_tuple()); if (res.second == false) throw LowlevelError("Creating duplicate entry in constant pool: "+(*res.first).second.getToken()); return &(*res.first).second; } const CPoolRecord *ConstantPoolInternal::getRecord(const vector &refs) const { CheapSorter sorter(refs); map::const_iterator iter = cpoolMap.find(sorter); if (iter == cpoolMap.end()) return (CPoolRecord *)0; return &(*iter).second; } void ConstantPoolInternal::encode(Encoder &encoder) const { map::const_iterator iter; encoder.openElement(ELEM_CONSTANTPOOL); for(iter=cpoolMap.begin();iter!=cpoolMap.end();++iter) { (*iter).first.encode(encoder); (*iter).second.encode(encoder); } encoder.closeElement(ELEM_CONSTANTPOOL); } void ConstantPoolInternal::decode(Decoder &decoder,TypeFactory &typegrp) { uint4 elemId = decoder.openElement(ELEM_CONSTANTPOOL); while(decoder.peekElement() != 0) { CheapSorter sorter; sorter.decode(decoder); vector refs; sorter.apply(refs); CPoolRecord *newrec = createRecord(refs); newrec->decode(decoder,typegrp); } decoder.closeElement(elemId); } } // End namespace ghidra