blob: 8329742c6954f0429cbfb3462d295e3c21003a28 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COURGETTE_COURGETTE_FLOW_H_
#define COURGETTE_COURGETTE_FLOW_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "courgette/courgette.h"
#include "courgette/region.h"
#include "courgette/streams.h"
namespace courgette {
class AssemblyProgram;
class Disassembler;
class EncodedProgram;
// An adaptor for Region as BasicBuffer.
class RegionBuffer : public BasicBuffer {
public:
explicit RegionBuffer(const Region& region) : region_(region) {}
~RegionBuffer() override {}
// BasicBuffer:
const uint8_t* data() const override { return region_.start(); }
size_t length() const override { return region_.length(); }
private:
Region region_;
DISALLOW_COPY_AND_ASSIGN(RegionBuffer);
};
// CourgetteFlow stores Courgette data arranged into groups, and exposes
// "commands" that operate on them. On the first occurrence of an error, the
// Courgette error code is recorded, error messages are generated and stored,
// and all subsequent commands become no-op. This allows callers to concisely
// specify high-level logic with minimal code for error handling.
class CourgetteFlow {
public:
// A group of Courgette data, for a single executable. Takes negligible space
// when unused.
struct Data {
Data();
~Data();
std::unique_ptr<Disassembler> disassembler;
std::unique_ptr<AssemblyProgram> program;
std::unique_ptr<EncodedProgram> encoded;
SinkStreamSet sinks;
SourceStreamSet sources;
};
// Group enumeration into |data_*_| fields.
enum Group {
ONLY, // The only file processed.
OLD, // The "old" file during patching.
NEW, // The "new" file during patching.
};
CourgetteFlow();
~CourgetteFlow();
static const char* name(Group group);
Data* data(Group group); // Allows caller to modify.
bool ok();
bool failed();
Status status();
const std::string& message();
// Commands that perform no-op on error. This allows caller to concisely
// specify high-level logic, and perform a single error check at the end. Care
// must be taken w.r.t. error handling if |data()| is harvested between
// commands.
// Reads |buffer| to initialize |data(group)->sources|.
void ReadSourceStreamSetFromBuffer(Group group, const BasicBuffer& buffer);
// Reads |buffer| to initialize |data(group)->disassembler|.
void ReadDisassemblerFromBuffer(Group group, const BasicBuffer& buffer);
// Reads |opt_sources| if given, or else |data(group)->sources| to initialize
// |data(group).encoded|.
void ReadEncodedProgramFromSourceStreamSet(
Group group,
SourceStreamSet* opt_sources = nullptr);
// Uses |data(group)->disassembler| to initialize |data(group)->program|,
// passing |annotate| as initialization parameter (should be true if
// AdjustNewAssemblyProgramToMatchOld() gets called later).
void CreateAssemblyProgramFromDisassembler(Group group, bool annotate);
// Uses |data(group)->disassembler| and |data(group)->program| to initialize
// |data(group)->encoded|.
void CreateEncodedProgramFromDisassemblerAndAssemblyProgram(Group group);
// Serializese |data(group)->sinks| to |sink|.
void WriteSinkStreamFromSinkStreamSet(Group group, SinkStream* sink);
// Serializes |data(group)->encoded| to |opt_sinks| if given, or else to
// |data(group)->sinks|.
void WriteSinkStreamSetFromEncodedProgram(Group group,
SinkStreamSet* opt_sinks = nullptr);
// Converts |data(group)->encoded| to an exectuable and writes the result to
// |sink|.
void WriteExecutableFromEncodedProgram(Group group, SinkStream* sink);
// Adjusts |data(NEW)->program| Labels to match |data(OLD)->program| Labels.
void AdjustNewAssemblyProgramToMatchOld();
// Destructor commands to reduce memory usage.
void DestroyDisassembler(Group group);
void DestroyAssemblyProgram(Group group);
void DestroyEncodedProgram(Group group);
private:
// Utilities to process return values from Courgette functions, and assign
// |status_| and |message_|. Usage:
// if (!check(some_courgette_function(param1, ...)))
// setMessage("format string %s...", value1, ...);
// Reassigns |status_|, and returns true if |C_OK|.
bool check(Status new_status);
// check() alternative for functions that return true on success. On failure
// assigns |status_| to |failure_mode|.
bool check(bool success, Status failure_mode);
void setMessage(const char* format, ...);
Status status_ = C_OK;
std::string message_;
Data data_only_;
Data data_old_;
Data data_new_;
DISALLOW_COPY_AND_ASSIGN(CourgetteFlow);
};
} // namespace courgette
#endif // COURGETTE_COURGETTE_FLOW_H_