/* ### * 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 "loadimage_xml.hh" #include "translate.hh" namespace ghidra { AttributeId ATTRIB_ARCH = AttributeId("arch",135); ElementId ELEM_BINARYIMAGE = ElementId("binaryimage",230); ElementId ELEM_BYTECHUNK = ElementId("bytechunk",231); /// \param f is the (path to the) underlying XML file /// \param el is the parsed form of the file LoadImageXml::LoadImageXml(const string &f,const Element *el) : LoadImage(f) { manage = (const AddrSpaceManager *)0; rootel = el; // Extract architecture information if (rootel->getName() != "binaryimage") throw LowlevelError("Missing binaryimage tag in "+filename); archtype = el->getAttributeValue("arch"); } /// Encode the byte chunks and symbols as elements /// \param encoder is the stream encoder void LoadImageXml::encode(Encoder &encoder) const { encoder.openElement(ELEM_BINARYIMAGE); encoder.writeString(ATTRIB_ARCH, archtype); map >::const_iterator iter1; for(iter1=chunk.begin();iter1!=chunk.end();++iter1) { const vector &vec((*iter1).second); if (vec.size() == 0) continue; encoder.openElement(ELEM_BYTECHUNK); (*iter1).first.getSpace()->encodeAttributes(encoder,(*iter1).first.getOffset()); if (readonlyset.find((*iter1).first) != readonlyset.end()) encoder.writeBool(ATTRIB_READONLY, "true"); ostringstream s; s << '\n' << setfill('0'); for(int4 i=0;i::const_iterator iter2; for(iter2=addrtosymbol.begin();iter2!=addrtosymbol.end();++iter2) { encoder.openElement(ELEM_SYMBOL); (*iter2).first.getSpace()->encodeAttributes(encoder,(*iter2).first.getOffset()); encoder.writeString(ATTRIB_NAME, (*iter2).second); encoder.closeElement(ELEM_SYMBOL); } encoder.closeElement(ELEM_BINARYIMAGE); } /// \param m is for looking up address space void LoadImageXml::open(const AddrSpaceManager *m) { manage = m; uint4 sz; // unused size // Read parsed xml file XmlDecode decoder(m,rootel); uint4 elemId = decoder.openElement(ELEM_BINARYIMAGE); for(;;) { uint4 subId = decoder.openElement(); if (subId == 0) break; if (subId==ELEM_SYMBOL) { AddrSpace *base = decoder.readSpace(ATTRIB_SPACE); Address addr(base,base->decodeAttributes(decoder,sz)); string nm = decoder.readString(ATTRIB_NAME); addrtosymbol[addr] = nm; } else if (subId == ELEM_BYTECHUNK) { AddrSpace *base = decoder.readSpace(ATTRIB_SPACE); Address addr(base,base->decodeAttributes(decoder,sz)); map >::iterator chnkiter; vector &vec( chunk[addr] ); vec.clear(); decoder.rewindAttributes(); for(;;) { uint4 attribId = decoder.getNextAttributeId(); if (attribId == 0) break; if (attribId == ATTRIB_READONLY) if (decoder.readBool()) readonlyset.insert(addr); } istringstream is(decoder.readString(ATTRIB_CONTENT)); int4 val; char c1,c2; is >> ws; c1 = is.get(); c2 = is.get(); while((c1>0)&&(c2>0)) { if (c1 <= '9') c1 = c1 - '0'; else if (c1 <= 'F') c1 = c1 + 10 - 'A'; else c1 = c1 + 10 - 'a'; if (c2 <= '9') c2 = c2 - '0'; else if (c2 <= 'F') c2 = c2 + 10 - 'A'; else c2 = c2 + 10 - 'a'; val = c1*16 + c2; vec.push_back((uint1)val); is >> ws; c1 = is.get(); c2 = is.get(); } } else throw LowlevelError("Unknown LoadImageXml tag"); decoder.closeElement(subId); } decoder.closeElement(elemId); pad(); } void LoadImageXml::clear(void) { archtype.clear(); manage = (const AddrSpaceManager *)0; chunk.clear(); addrtosymbol.clear(); } void LoadImageXml::pad(void) { map >::iterator iter,lastiter; // Search for completely redundant chunks if (chunk.empty()) return; lastiter = chunk.begin(); iter = lastiter; ++iter; while(iter!=chunk.end()) { if ((*lastiter).first.getSpace() == (*iter).first.getSpace()) { uintb end1 = (*lastiter).first.getOffset() + (*lastiter).second.size() - 1; uintb end2 = (*iter).first.getOffset() + (*iter).second.size() - 1; if (end1 >= end2) { chunk.erase(iter); iter = lastiter; ++iter; continue; } } lastiter = iter; ++iter; } iter = chunk.begin(); while(iter!=chunk.end()) { Address endaddr = (*iter).first + (*iter).second.size(); if (endaddr < (*iter).first) { ++iter; continue; // All the way to end of space } ++iter; int4 maxsize = 512; uintb room = endaddr.getSpace()->getHighest() - endaddr.getOffset() + 1; if ((uintb)maxsize > room) maxsize = (int4)room; if ((iter!=chunk.end())&&((*iter).first.getSpace()==endaddr.getSpace())) { if (endaddr.getOffset() >= (*iter).first.getOffset()) continue; room = (*iter).first.getOffset() - endaddr.getOffset(); if ((uintb)maxsize > room) maxsize = (int4)room; } vector &vec( chunk[endaddr] ); for(int4 i=0;i >::const_iterator iter; Address curaddr; bool emptyhit = false; curaddr = addr; iter = chunk.upper_bound(curaddr); // First one greater than if (iter != chunk.begin()) --iter; // Last one less or equal while((size>0)&&(iter!=chunk.end())) { const vector &chnk((*iter).second); int4 chnksize = chnk.size(); int4 over = curaddr.overlap(0,(*iter).first,chnksize); if (over!=-1) { if (chnksize-over > size) chnksize = over+size; for(int4 i=over;i0)||emptyhit) { ostringstream errmsg; errmsg << "Bytes at "; curaddr.printRaw(errmsg); errmsg << " are not mapped"; throw DataUnavailError(errmsg.str()); } } void LoadImageXml::openSymbols(void) const { cursymbol = addrtosymbol.begin(); } bool LoadImageXml::getNextSymbol(LoadImageFunc &record) const { if (cursymbol == addrtosymbol.end()) return false; record.name = (*cursymbol).second; record.address = (*cursymbol).first; ++cursymbol; return true; } void LoadImageXml::getReadonly(RangeList &list) const { map >::const_iterator iter; // List all the readonly chunks for(iter=chunk.begin();iter!=chunk.end();++iter) { if (readonlyset.find((*iter).first) != readonlyset.end()) { const vector &chnk((*iter).second); uintb start = (*iter).first.getOffset(); uintb stop = start + chnk.size() - 1; list.insertRange((*iter).first.getSpace(),start,stop); } } } void LoadImageXml::adjustVma(long adjust) { map >::iterator iter1; map::iterator iter2; map > newchunk; map newsymbol; for(iter1=chunk.begin();iter1!=chunk.end();++iter1) { AddrSpace *spc = (*iter1).first.getSpace(); int4 off = AddrSpace::addressToByte(adjust,spc->getWordSize()); Address newaddr = (*iter1).first + off; newchunk[newaddr] = (*iter1).second; } chunk = newchunk; for(iter2=addrtosymbol.begin();iter2!=addrtosymbol.end();++iter2) { AddrSpace *spc = (*iter2).first.getSpace(); int4 off = AddrSpace::addressToByte(adjust,spc->getWordSize()); Address newaddr = (*iter2).first + off; newsymbol[newaddr] = (*iter2).second; } addrtosymbol = newsymbol; } } // End namespace ghidra