| // 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_ |