From 3a4fade0292b9b8776c6195467b70a8f25a3b1c7 Mon Sep 17 00:00:00 2001 From: Christoph Egger Date: Tue, 24 Mar 2015 16:45:27 +0100 Subject: [PATCH] (De)serialization of Comments serialization and deserialization of global comments. Local comments need to go within the function and are not yet implemented. Also includes several tests --- CMakeLists.txt | 1 + src/core/Comment.cxx | 67 ++++++++++++++++ src/core/InformationManager.cxx | 36 ++++++++- src/core/tests/CommentTest.cxx | 79 +++++++++++++++++++ src/gui/widgets/BasicBlockWidget.cxx | 4 +- testdata/core/Comment/invalid/400580.xml | 4 + .../Comment/invalid/additionalAttribute.xml | 5 ++ testdata/core/Comment/invalid/noAddress.xml | 3 + testdata/core/Comment/invalid/noText.xml | 3 + .../core/Comment/invalid/wrongAttribute.xml | 4 + testdata/core/Comment/valid/400580.xml | 4 + 11 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 src/core/tests/CommentTest.cxx create mode 100644 testdata/core/Comment/invalid/400580.xml create mode 100644 testdata/core/Comment/invalid/additionalAttribute.xml create mode 100644 testdata/core/Comment/invalid/noAddress.xml create mode 100644 testdata/core/Comment/invalid/noText.xml create mode 100644 testdata/core/Comment/invalid/wrongAttribute.xml create mode 100644 testdata/core/Comment/valid/400580.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index e72d439..cbc597f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ set(fridatest_SOURCES src/test.cxx src/core/tests/BasicBlockTest.cxx src/core/tests/FunctionTest.cxx + src/core/tests/CommentTest.cxx ${frida_SOURCES} ) diff --git a/src/core/Comment.cxx b/src/core/Comment.cxx index d6fedfb..e864ef6 100644 --- a/src/core/Comment.cxx +++ b/src/core/Comment.cxx @@ -26,3 +26,70 @@ uint64_t Comment::getAddress() { Function* Comment::getLocation() { return location; } + +void Comment::serialize(QXmlStreamWriter& stream) { + stream.writeStartElement("comment"); + + stream.writeTextElement("address", QString::number(address, 16)); + stream.writeTextElement("text", text.c_str()); + + stream.writeEndElement(); // "comment" +} + +Comment* Comment::deserialize(QXmlStreamReader& stream, InformationManager* manager, Function* function) { + Q_ASSERT(stream.name() == "comment"); + + QString text; + uint64_t address = 0; + Comment* comment; + + while (QXmlStreamReader::NoToken != stream.readNext()) { + while (QXmlStreamReader::Characters == stream.tokenType() && + stream.isWhitespace()) + stream.readNext(); + if (QXmlStreamReader::EndElement == stream.tokenType()) + break; + + if(QXmlStreamReader::StartElement != stream.tokenType()) + return NULL; + + if (stream.name() == "text") { + stream.readNext(); + if (QXmlStreamReader::Characters != stream.tokenType()) + return NULL; + + text = stream.text().toString(); + stream.readNext(); + + if(QXmlStreamReader::EndElement != stream.tokenType()) + return NULL; + } + if (stream.name() == "address") { + stream.readNext(); + if (QXmlStreamReader::Characters != stream.tokenType()) + return NULL; + + address = stream.text().toULongLong(NULL, 16); + stream.readNext(); + + if(QXmlStreamReader::EndElement != stream.tokenType()) + return NULL; + } + } + + if (address == 0 or text == "") + return NULL; + + if (function) + comment = manager->newLocalComment(address, function); + else + comment = manager->newGlobalComment(address); + + comment->text = text.toStdString(); + + assert(stream.name() == "comment"); + + manager->finishComment(comment); + return comment; +} + diff --git a/src/core/InformationManager.cxx b/src/core/InformationManager.cxx index 6179f5f..485aacd 100644 --- a/src/core/InformationManager.cxx +++ b/src/core/InformationManager.cxx @@ -73,10 +73,21 @@ void InformationManager::load(const std::string& filename) { file.open(QIODevice::ReadOnly); if(info.name != "binary") { - QXmlStreamReader reader(&file); - assert(QXmlStreamReader::StartDocument == reader.readNext()); - assert(QXmlStreamReader::StartElement == reader.readNext()); - Function::deserialize(reader, this); + if (info.name.startsWith("comment:")) { + QXmlStreamReader reader(&file); + auto starttoken = reader.readNext(); + auto elementtoken = reader.readNext(); + assert(QXmlStreamReader::StartDocument == starttoken); + assert(QXmlStreamReader::StartElement == elementtoken); + Comment::deserialize(reader, this); + } else { + QXmlStreamReader reader(&file); + auto starttoken = reader.readNext(); + auto elementtoken = reader.readNext(); + assert(QXmlStreamReader::StartDocument == starttoken); + assert(QXmlStreamReader::StartElement == elementtoken); + Function::deserialize(reader, this); + } } file.close(); } @@ -117,6 +128,23 @@ void InformationManager::save(const std::string& filename) { stream.writeEndDocument(); outZipFile.close(); } + for (auto commentpair : comments) { + Comment* comment = commentpair.second; + if (!comment->isLocal()) { + QuaZipNewInfo zipinfo(QString("comment:%1").arg(comment->getAddress(), 0, 16)); + zipinfo.setPermissions(static_cast(0x6444)); + outZipFile.open(QIODevice::WriteOnly, zipinfo); + QXmlStreamWriter stream(&outZipFile); + stream.setAutoFormatting(true); + stream.setAutoFormattingIndent(-1); + stream.writeStartDocument(); + + comment->serialize(stream); + + stream.writeEndDocument(); + outZipFile.close(); + } + } zip.close(); } diff --git a/src/core/tests/CommentTest.cxx b/src/core/tests/CommentTest.cxx new file mode 100644 index 0000000..870402a --- /dev/null +++ b/src/core/tests/CommentTest.cxx @@ -0,0 +1,79 @@ +#include + +#include "gui/qt.hxx" +#include "core/InformationManager.hxx" +#include "core/BasicBlock.hxx" +#include "core/Comment.hxx" +#include + +extern char * TEST_DATA_DIRECTORY; + +TEST(CommentTest, deserializeValidInstance) { + InformationManager manager; + QDir directory(QString("%1/%2").arg(TEST_DATA_DIRECTORY,"/core/Comment/valid/")); + QStringList filters; + filters << "*.xml"; + directory.setNameFilters(filters); + + for (auto fileinfo : directory.entryInfoList()) { + if (false == fileinfo.isFile()) + continue; + + QFile file(fileinfo.absoluteFilePath()); + file.open(QFile::ReadOnly | QFile::Text); + QXmlStreamReader reader(&file); + reader.readNextStartElement(); + + Comment* c = Comment::deserialize(reader, &manager); + ASSERT_NE((void*)NULL, (void*)c); + EXPECT_EQ(fileinfo.baseName().toULongLong(NULL, 16), c->getAddress()); + } +} + +TEST(CommentTest, deserializeInvalidInstance) { + InformationManager manager; + QDir directory(QString("%1/%2").arg(TEST_DATA_DIRECTORY,"/core/Comment/invalid/")); + QStringList filters; + filters << "*.xml"; + directory.setNameFilters(filters); + + for (auto fileinfo : directory.entryInfoList()) { + if (false == fileinfo.isFile()) + continue; + + QFile file(fileinfo.absoluteFilePath()); + file.open(QFile::ReadOnly | QFile::Text); + QXmlStreamReader reader(&file); + reader.readNextStartElement(); + + Comment* c = Comment::deserialize(reader, &manager); + ASSERT_EQ((void*)NULL, (void*)c); + } +} + +TEST(CommentTest, serializeThenDeserializeIsIdentity) { + InformationManager manager; + Comment* c = manager.newGlobalComment(0x42234223); + + for (QString text : QStringList({"αβγδ", "", "ä"})) { + c->setText(text.toStdString()); + + QTemporaryFile tmpfile; + + { + tmpfile.open(); + QXmlStreamWriter writer(&tmpfile); + c->serialize(writer); + } + tmpfile.seek(0); + { + tmpfile.open(); + QXmlStreamReader reader(&tmpfile); + reader.readNextStartElement(); + Comment* d = Comment::deserialize(reader, &manager); + ASSERT_NE((void*)NULL, (void*)d); + EXPECT_STREQ(c->getText().c_str(), d->getText().c_str()); + EXPECT_EQ(0x42234223, d->getAddress()); + } + } +} diff --git a/src/gui/widgets/BasicBlockWidget.cxx b/src/gui/widgets/BasicBlockWidget.cxx index bdddd52..efa7ec3 100644 --- a/src/gui/widgets/BasicBlockWidget.cxx +++ b/src/gui/widgets/BasicBlockWidget.cxx @@ -30,7 +30,7 @@ void CustomQGraphicsTextItem::addComment(int row, bool global) { if (global) { comment = parent->block->getManager()->newGlobalComment(address); } else { - comment = parent->block->getManager()->newLocalComment(address, NULL); + comment = parent->block->getManager()->newLocalComment(address, (Function*)0x23); } comment->setText(dialog.result().toStdString()); parent->block->getManager()->finishComment(comment); @@ -195,7 +195,7 @@ QString BasicBlockWidget::formatComments(Instruction* inst) { QString comments; for (Comment* c: inst->comments()) { comments += "
"; - comments += c->getText().c_str(); + comments += QString(c->getText().c_str()).toHtmlEscaped(); } return (comments == "" ? "" : ";; ") + comments.trimmed(); } diff --git a/testdata/core/Comment/invalid/400580.xml b/testdata/core/Comment/invalid/400580.xml new file mode 100644 index 0000000..0a4daee --- /dev/null +++ b/testdata/core/Comment/invalid/400580.xml @@ -0,0 +1,4 @@ + + 400580 + <test> ist auch ein test!! &wasaucheimmer; + diff --git a/testdata/core/Comment/invalid/additionalAttribute.xml b/testdata/core/Comment/invalid/additionalAttribute.xml new file mode 100644 index 0000000..1162e70 --- /dev/null +++ b/testdata/core/Comment/invalid/additionalAttribute.xml @@ -0,0 +1,5 @@ + +
400580
+ <test> ist auch ein test!! &wasaucheimmer; + SuperCowPowers! +
diff --git a/testdata/core/Comment/invalid/noAddress.xml b/testdata/core/Comment/invalid/noAddress.xml new file mode 100644 index 0000000..43469a2 --- /dev/null +++ b/testdata/core/Comment/invalid/noAddress.xml @@ -0,0 +1,3 @@ + + <test> ist auch ein test!! &wasaucheimmer; + diff --git a/testdata/core/Comment/invalid/noText.xml b/testdata/core/Comment/invalid/noText.xml new file mode 100644 index 0000000..24bd89c --- /dev/null +++ b/testdata/core/Comment/invalid/noText.xml @@ -0,0 +1,3 @@ + +
400580
+
diff --git a/testdata/core/Comment/invalid/wrongAttribute.xml b/testdata/core/Comment/invalid/wrongAttribute.xml new file mode 100644 index 0000000..0a4daee --- /dev/null +++ b/testdata/core/Comment/invalid/wrongAttribute.xml @@ -0,0 +1,4 @@ + + 400580 + <test> ist auch ein test!! &wasaucheimmer; + diff --git a/testdata/core/Comment/valid/400580.xml b/testdata/core/Comment/valid/400580.xml new file mode 100644 index 0000000..6f92f1c --- /dev/null +++ b/testdata/core/Comment/valid/400580.xml @@ -0,0 +1,4 @@ + +
400580
+ <test> ist auch ein test!! &wasaucheimmer; +
-- 2.39.2