#include "comment.hh"
#include "funcdata.hh"
Comment::Comment(uint4 tp,const Address &fad,const Address &ad,int4 uq,const string &txt) :
type(tp), uniq(uq), funcaddr(fad), addr(ad), text(txt), emitted(false)
{
}
void Comment::saveXml(ostream &s) const
{
string tpname = Comment::decodeCommentType(type);
s << "<comment";
a_v(s,"type",tpname);
s << ">\n";
s << " <addr";
funcaddr.getSpace()->saveXmlAttributes(s,funcaddr.getOffset());
s << "/>\n";
s << " <addr";
addr.getSpace()->saveXmlAttributes(s,addr.getOffset());
s << "/>\n";
s << " <text>";
xml_escape(s,text.c_str());
s << " </text>\n";
s << "</comment>\n";
}
void Comment::restoreXml(const Element *el,const AddrSpaceManager *manage)
{
emitted = false;
type = 0;
type = Comment::encodeCommentType(el->getAttributeValue("type"));
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
funcaddr = Address::restoreXml(*iter,manage);
++iter;
addr = Address::restoreXml(*iter,manage);
++iter;
if (iter != list.end())
text = (*iter)->getContent();
}
uint4 Comment::encodeCommentType(const string &name)
{
if (name == "user1")
return Comment::user1;
if (name == "user2")
return Comment::user2;
if (name == "user3")
return Comment::user3;
if (name == "header")
return Comment::header;
if (name == "warning")
return Comment::warning;
if (name == "warningheader")
return Comment::warningheader;
throw LowlevelError("Unknown comment type: "+name);
}
string Comment::decodeCommentType(uint4 val)
{
switch(val) {
case user1:
return "user1";
case user2:
return "user2";
case user3:
return "user3";
case header:
return "header";
case warning:
return "warning";
case warningheader:
return "warningheader";
default:
break;
}
throw LowlevelError("Unknown comment type");
}
bool CommentOrder::operator()(const Comment *a,const Comment *b) const
{
if (a->getFuncAddr() != b->getFuncAddr())
return (a->getFuncAddr() < b->getFuncAddr());
if (a->getAddr() != b->getAddr())
return (a->getAddr() < b->getAddr());
if (a->getUniq() != b->getUniq())
return (a->getUniq() < b->getUniq());
return false;
}
CommentDatabaseInternal::CommentDatabaseInternal(void)
: CommentDatabase()
{
}
CommentDatabaseInternal::~CommentDatabaseInternal(void)
{
CommentSet::iterator iter;
for(iter=commentset.begin();iter!=commentset.end();++iter)
delete *iter;
}
void CommentDatabaseInternal::clear(void)
{
CommentSet::iterator iter;
for(iter=commentset.begin();iter!=commentset.end();++iter)
delete *iter;
commentset.clear();
}
void CommentDatabaseInternal::clearType(const Address &fad,uint4 tp)
{
Comment testcommbeg(0,fad,Address(Address::m_minimal),0,"");
Comment testcommend(0,fad,Address(Address::m_maximal),65535,"");
CommentSet::iterator iterbegin = commentset.lower_bound(&testcommbeg);
CommentSet::iterator iterend = commentset.lower_bound(&testcommend);
CommentSet::iterator iter;
while(iterbegin != iterend) {
iter = iterbegin;
++iter;
if (((*iterbegin)->getType()&tp)!=0) {
delete (*iterbegin);
commentset.erase(iterbegin);
}
iterbegin = iter;
}
}
void CommentDatabaseInternal::addComment(uint4 tp,const Address &fad,
const Address &ad,
const string &txt)
{
Comment *newcom = new Comment(tp,fad,ad,65535,txt);
CommentSet::iterator iter = commentset.lower_bound(newcom);
if (iter != commentset.begin())
--iter;
newcom->uniq = 0;
if (iter != commentset.end()) {
if (((*iter)->getAddr() == ad)&&((*iter)->getFuncAddr()==fad))
newcom->uniq = (*iter)->getUniq() + 1;
}
commentset.insert(newcom);
}
bool CommentDatabaseInternal::addCommentNoDuplicate(uint4 tp,const Address &fad,
const Address &ad,const string &txt)
{
Comment *newcom = new Comment(tp,fad,ad,65535,txt);
CommentSet::iterator iter = commentset.lower_bound(newcom);
newcom->uniq = 0; while(iter != commentset.begin()) {
--iter;
if (((*iter)->getAddr()==ad)&&((*iter)->getFuncAddr()==fad)) {
if ((*iter)->getText() == txt) { delete newcom;
return false;
}
if (newcom->uniq == 0)
newcom->uniq = (*iter)->getUniq() + 1;
}
else
break;
}
commentset.insert(newcom);
return true;
}
void CommentDatabaseInternal::deleteComment(Comment *com)
{
commentset.erase(com);
delete com;
}
CommentSet::const_iterator CommentDatabaseInternal::beginComment(const Address &fad) const
{
Comment testcomm(0,fad,Address(Address::m_minimal),0,"");
return commentset.lower_bound(&testcomm);
}
CommentSet::const_iterator CommentDatabaseInternal::endComment(const Address &fad) const
{
Comment testcomm(0,fad,Address(Address::m_maximal),65535,"");
return commentset.lower_bound(&testcomm);
}
void CommentDatabaseInternal::saveXml(ostream &s) const
{
CommentSet::const_iterator iter;
s << "<commentdb>\n";
for(iter=commentset.begin();iter!=commentset.end();++iter)
(*iter)->saveXml(s);
s << "</commentdb>\n";
}
void CommentDatabaseInternal::restoreXml(const Element *el,const AddrSpaceManager *manage)
{
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) {
Comment com;
com.restoreXml(*iter,manage);
addComment(com.getType(),com.getFuncAddr(),com.getAddr(),com.getText());
}
}
bool CommentSorter::findPosition(Subsort &subsort,Comment *comm,const Funcdata *fd)
{
if (comm->getType() == 0) return false;
const Address &fad( fd->getAddress() );
if (((comm->getType() & (Comment::header | Comment::warningheader))!=0)&&(comm->getAddr() == fad)) {
subsort.setHeader(header_basic);
return true;
}
PcodeOpTree::const_iterator opiter = fd->beginOp(comm->getAddr());
PcodeOp *backupOp = (PcodeOp *)0;
if (opiter != fd->endOpAll()) { PcodeOp *op = (*opiter).second;
BlockBasic *block = op->getParent();
if (block == (BlockBasic *)0)
throw LowlevelError("Dead op reaching CommentSorter");
if (block->contains(comm->getAddr())) { subsort.setBlock(block->getIndex(), (uint4)op->getSeqNum().getOrder());
return true;
}
if (comm->getAddr() == op->getAddr())
backupOp = op;
}
if (opiter != fd->beginOpAll()) { --opiter;
PcodeOp *op = (*opiter).second;
BlockBasic *block = op->getParent();
if (block == (BlockBasic *)0)
throw LowlevelError("Dead op reaching CommentSorter");
if (block->contains(comm->getAddr())) { subsort.setBlock(block->getIndex(),0xffffffff);
return true;
}
}
if (backupOp != (PcodeOp *)0) {
subsort.setBlock(backupOp->getParent()->getIndex(),(uint4)backupOp->getSeqNum().getOrder());
return true;
}
if (fd->beginOpAll() == fd->endOpAll()) { subsort.setBlock(0,0); return true;
}
if (displayUnplacedComments) {
subsort.setHeader(header_unplaced);
return true;
}
return false; }
void CommentSorter::setupFunctionList(uint4 tp,const Funcdata *fd,const CommentDatabase &db,bool displayUnplaced)
{
commmap.clear();
displayUnplacedComments = displayUnplaced;
if (tp == 0) return;
const Address &fad( fd->getAddress() );
CommentSet::const_iterator iter = db.beginComment(fad);
CommentSet::const_iterator lastiter = db.endComment(fad);
Subsort subsort;
subsort.pos = 0;
while(iter != lastiter) {
Comment *comm = *iter;
if (findPosition(subsort, comm, fd)) {
comm->setEmitted(false);
commmap[ subsort ] = comm;
subsort.pos += 1; }
++iter;
}
}
void CommentSorter::setupOpList(const PcodeOp *op)
{
if (op == (const PcodeOp *)0) { opstop = stop; return;
}
Subsort subsort;
subsort.index = op->getParent()->getIndex();
subsort.order = (uint4)op->getSeqNum().getOrder();
subsort.pos = 0xffffffff;
opstop = commmap.upper_bound(subsort);
}
void CommentSorter::setupBlockList(const FlowBlock *bl)
{
Subsort subsort;
subsort.index = bl->getIndex();
subsort.order = 0;
subsort.pos = 0;
start = commmap.lower_bound(subsort);
subsort.order = 0xffffffff;
subsort.pos = 0xffffffff;
stop = commmap.upper_bound(subsort);
}
void CommentSorter::setupHeader(uint4 headerType)
{
Subsort subsort;
subsort.index = -1;
subsort.order = headerType;
subsort.pos = 0;
start = commmap.lower_bound(subsort);
subsort.pos = 0xffffffff;
opstop = commmap.upper_bound(subsort);
}