1#ifndef ROSE_BinaryAnalysis_SerialIo_H
2#define ROSE_BinaryAnalysis_SerialIo_H
3#include <featureTests.h>
4#ifdef ROSE_ENABLE_BINARY_ANALYSIS
9#if defined(BOOST_WINDOWS)
11 #undef ROSE_SUPPORTS_SERIAL_IO
12#elif !defined(ROSE_HAVE_BOOST_SERIALIZATION_LIB)
14 #undef ROSE_SUPPORTS_SERIAL_IO
15#elif defined(__clang__)
16 #define ROSE_SUPPORTS_SERIAL_IO
17#elif defined(__GNUC__)
18 #if __GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNU_C_PATCHLEVEL__ <= 40204
20 #undef ROSE_SUPPORTS_SERIAL_IO
22 #define ROSE_SUPPORTS_SERIAL_IO
25 #define ROSE_SUPPORTS_SERIAL_IO
29#ifdef ROSE_SUPPORTS_SERIAL_IO
30#include <boost/archive/binary_iarchive.hpp>
31#include <boost/archive/binary_oarchive.hpp>
32#include <boost/archive/text_iarchive.hpp>
33#include <boost/archive/text_oarchive.hpp>
34#include <boost/archive/xml_iarchive.hpp>
35#include <boost/archive/xml_oarchive.hpp>
36#include <boost/iostreams/device/file_descriptor.hpp>
37#include <boost/iostreams/stream.hpp>
40#include <Rose/Progress.h>
41#include <Rose/Exception.h>
43#include <Sawyer/Message.h>
44#include <Sawyer/ProgressBar.h>
45#include <Sawyer/Synchronization.h>
47#include <boost/filesystem.hpp>
48#include <boost/lexical_cast.hpp>
49#include <boost/thread.hpp>
52namespace BinaryAnalysis {
150 mutable SAWYER_THREAD_TRAITS::Mutex mutex_;
168 progressBar_(
mlog[
Sawyer::Message::MARCH]), fd_(-1) {
170 progressBar_.
suffix(
" bytes");
223 virtual void open(
const boost::filesystem::path&) = 0;
253 void setIsOpen(
bool b);
276#ifdef ROSE_SUPPORTS_SERIAL_IO
277 boost::iostreams::file_descriptor_sink device_;
278 boost::iostreams::stream<boost::iostreams::file_descriptor_sink> file_;
279 boost::archive::binary_oarchive *binary_archive_;
280 boost::archive::text_oarchive *text_archive_;
281 boost::archive::xml_oarchive *xml_archive_;
285#ifdef ROSE_SUPPORTS_SERIAL_IO
286 SerialOutput(): binary_archive_(NULL), text_archive_(NULL), xml_archive_(NULL) {}
293 void open(
const boost::filesystem::path &fileName)
override;
330 void saveAstHelper(
SgNode*);
350 throw Exception(
"cannot save object when no file is open");
352 throw Exception(
"cannot save object because stream is in error state");
354#ifndef ROSE_SUPPORTS_SERIAL_IO
355 throw Exception(
"binary state files are not supported in this configuration");
356#elif defined(ROSE_DEBUG_SERIAL_IO)
357 std::string errorMessage;
358 asyncSave(objectTypeId,
object, &errorMessage);
361 std::string errorMessage;
362 boost::thread worker(startWorker<T>,
this, objectTypeId, &
object, &errorMessage);
364 progressBar_.
prefix(
"writing");
365 while (!worker.try_join_for(timeout)) {
366 off_t cur = ::lseek(fd_, 0, SEEK_CUR);
370 progressBar_.
value(cur);
375 if (!errorMessage.empty())
382 static void startWorker(
SerialOutput *saver,
Savable objectTypeId,
const T *
object, std::string *errorMessage) {
383 ASSERT_not_null(
object);
384 saver->asyncSave(objectTypeId, *
object, errorMessage);
389 void asyncSave(
Savable objectTypeId,
const T &
object, std::string *errorMessage) {
390 ASSERT_not_null(errorMessage);
391#ifndef ROSE_SUPPORTS_SERIAL_IO
392 ASSERT_not_reachable(
"not supported in this configuration");
394#if !defined(ROSE_DEBUG_SERIAL_IO)
397 std::string roseVersion = ROSE_PACKAGE_VERSION;
401 ASSERT_not_null(binary_archive_);
402 *binary_archive_ <<BOOST_SERIALIZATION_NVP(objectTypeId);
403 *binary_archive_ <<BOOST_SERIALIZATION_NVP(roseVersion);
404 *binary_archive_ <<BOOST_SERIALIZATION_NVP(
object);
407 ASSERT_not_null(text_archive_);
408 *text_archive_ <<BOOST_SERIALIZATION_NVP(objectTypeId);
409 *text_archive_ <<BOOST_SERIALIZATION_NVP(roseVersion);
410 *text_archive_ <<BOOST_SERIALIZATION_NVP(
object);
413 ASSERT_not_null(xml_archive_);
414 *xml_archive_ <<BOOST_SERIALIZATION_NVP(objectTypeId);
415 *xml_archive_ <<BOOST_SERIALIZATION_NVP(roseVersion);
416 *xml_archive_ <<BOOST_SERIALIZATION_NVP(
object);
420#if !defined(ROSE_DEBUG_SERIAL_IO)
421 }
catch (std::exception &e) {
422 *errorMessage = e.what();
424 *errorMessage =
"failed to write object to output stream";
445#ifdef ROSE_SUPPORTS_SERIAL_IO
447 boost::iostreams::file_descriptor_source device_;
448 boost::iostreams::stream<boost::iostreams::file_descriptor_source> file_;
449 boost::archive::binary_iarchive *binary_archive_;
450 boost::archive::text_iarchive *text_archive_;
451 boost::archive::xml_iarchive *xml_archive_;
455#ifdef ROSE_SUPPORTS_SERIAL_IO
456 SerialInput(): fileSize_(0), binary_archive_(NULL), text_archive_(NULL), xml_archive_(NULL) {}
463 void open(
const boost::filesystem::path &fileName)
override;
507 loadObject<T>(objectTypeId,
object);
513 throw Exception(
"cannot load object when no file is open");
515#ifndef ROSE_SUPPORTS_SERIAL_IO
516 throw Exception(
"binary state files are not supported in this configuration");
519 throw Exception(
"cannot read object because stream is in error state");
521 throw Exception(
"unexpected object type (expected " + boost::lexical_cast<std::string>(objectTypeId) +
522 " but read " + boost::lexical_cast<std::string>(
objectType()) +
")");
525 std::string errorMessage;
526#ifdef ROSE_DEBUG_SERIAL_IO
527 asyncLoad(
object, &errorMessage);
529 boost::thread worker(startWorker<T>,
this, &
object, &errorMessage);
531 progressBar_.
prefix(
"reading");
532 while (!worker.try_join_for(timeout)) {
534 off_t cur = ::lseek(fd_, 0, SEEK_CUR);
536 progressBar_.
value(cur);
544 if (!errorMessage.empty())
554 static void startWorker(
SerialInput *loader, T *
object, std::string *errorMessage) {
555 loader->asyncLoad(*
object, errorMessage);
560 void asyncLoad(T &
object, std::string *errorMessage) {
561 ASSERT_not_null(errorMessage);
562#ifndef ROSE_SUPPORTS_SERIAL_IO
563 ASSERT_not_reachable(
"not supported in this configuration");
565#if !defined(ROSE_DEBUG_SERIAL_IO)
568 std::string roseVersion;
571 ASSERT_not_null(binary_archive_);
572 *binary_archive_ >>BOOST_SERIALIZATION_NVP(roseVersion);
573 checkCompatibility(roseVersion);
574 *binary_archive_ >>BOOST_SERIALIZATION_NVP(
object);
577 ASSERT_not_null(text_archive_);
578 *text_archive_ >>BOOST_SERIALIZATION_NVP(roseVersion);
579 checkCompatibility(roseVersion);
580 *text_archive_ >>BOOST_SERIALIZATION_NVP(
object);
583 ASSERT_not_null(xml_archive_);
584 *xml_archive_ >>BOOST_SERIALIZATION_NVP(roseVersion);
585 checkCompatibility(roseVersion);
586 *xml_archive_ >>BOOST_SERIALIZATION_NVP(
object);
589#if !defined(ROSE_DEBUG_SERIAL_IO)
590 }
catch (
const std::exception &e) {
591 *errorMessage = e.what();
593 *errorMessage =
"failed to read object from input stream";
599 void checkCompatibility(
const std::string &fileVersion);
603 void advanceObjectType();
Errors thrown by this API.
Exception(const std::string &s)
Construct an exception with an error message.
Base class for binary state input and output.
virtual void close()=0
Detach a file.
virtual ~SerialIo()
Destructor.
Format
Format of the state file.
@ XML
The states are stored as XML, which is a very verbose and slow format.
@ TEXT
Textual binary state files use a custom format (Boost serialization format) that stores the data as A...
@ BINARY
Binary state files are smaller and faster than the other formats, but are not portable across archite...
void progress(const Progress::Ptr &)
Property: Progress reporter.
static Savable userSavable(unsigned offset)
Create a new Savable enum constant.
Format format() const
Property: File format.
Savable
Types of objects that can be saved.
@ END_OF_DATA
Marks the end of the data stream.
@ USER_DEFINED
First user-defined object number.
@ USER_DEFINED_LAST
Last user-defined object number.
@ ERROR
Marks that the stream has encountered an error condition.
@ PARTITIONER
Rose::BinaryAnalysis::Partitioner2::Partitioner.
@ AST
Abstract syntax tree.
@ NO_OBJECT
Object type for newly-initialized serializers.
Progress::Ptr progress() const
Property: Progress reporter.
virtual void open(const boost::filesystem::path &)=0
Attach a file.
Savable objectType() const
Type ID for next object.
bool isOpen() const
Whether a file is attached.
static Sawyer::Message::Facility mlog
Message facility.
void format(Format)
Property: File format.
Output binary analysis state.
SerialOutputPtr Ptr
Reference counting pointer.
static Ptr instance()
Factory method to create a new instance.
void saveObject(Savable objectTypeId, const T &object)
Save an object to the output stream.
void close() override
Detach a file.
void savePartitioner(const Partitioner2::PartitionerConstPtr &)
Save a binary analysis partitioner.
void open(const boost::filesystem::path &fileName) override
Attach a file.
void saveAst(SgAsmNode *)
Save a binary AST.
Base class for all ROSE exceptions.
A general, thread-safe way to report progress made on some task.
const std::string & prefix() const
String to show before the beginning of the bar.
Suffix suffix()
Property: suffix.
ValueType value() const
Value for the progress bar.
Base class for reference counted objects.
Reference-counting intrusive smart pointer.
Base class for all binary analysis IR nodes.
This class represents the base class for all IR nodes within Sage III.
Sawyer::SharedPointer< SerialOutput > SerialOutputPtr
Reference counting pointer.
Sawyer::SharedPointer< SerialIo > SerialIoPtr
Reference counting pointer.
Sawyer::SharedPointer< SerialInput > SerialInputPtr
Reference counting pointer.
double minimumUpdateInterval()
Minimum time between updates.
A single progress report.