1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
// Copyright 2017 The Chromium Authors
// 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 "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(const RegionBuffer&) = delete;
RegionBuffer& operator=(const RegionBuffer&) = delete;
~RegionBuffer() override {}
// BasicBuffer:
const uint8_t* data() const override { return region_.start(); }
size_t length() const override { return region_.length(); }
private:
Region region_;
};
// 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(const CourgetteFlow&) = delete;
CourgetteFlow& operator=(const CourgetteFlow&) = delete;
~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_;
};
} // namespace courgette
#endif // COURGETTE_COURGETTE_FLOW_H_
|