| // 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. |
| |
| #include "courgette/courgette_flow.h" |
| |
| #include <stdarg.h> |
| |
| #include <memory> |
| |
| #include "base/check.h" |
| #include "base/files/file_path.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/notreached.h" |
| #include "base/strings/stringprintf.h" |
| #include "courgette/assembly_program.h" |
| #include "courgette/disassembler.h" |
| #include "courgette/encoded_program.h" |
| #include "courgette/program_detector.h" |
| |
| namespace courgette { |
| |
| /******** CourgetteFlow::Data ********/ |
| |
| CourgetteFlow::Data::Data() = default; |
| |
| CourgetteFlow::Data::~Data() = default; |
| |
| /******** CourgetteFlow ********/ |
| |
| CourgetteFlow::CourgetteFlow() = default; |
| |
| CourgetteFlow::~CourgetteFlow() = default; |
| |
| // static |
| const char* CourgetteFlow::name(Group group) { |
| switch (group) { |
| case ONLY: |
| return "input"; |
| case OLD: |
| return "'old' input"; |
| case NEW: |
| return "'new' input"; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| return nullptr; |
| } |
| |
| CourgetteFlow::Data* CourgetteFlow::data(Group group) { |
| switch (group) { |
| case ONLY: |
| return &data_only_; |
| case OLD: |
| return &data_old_; |
| case NEW: |
| return &data_new_; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| return nullptr; |
| } |
| |
| bool CourgetteFlow::ok() { |
| return status_ == C_OK; |
| } |
| |
| bool CourgetteFlow::failed() { |
| return status_ != C_OK; |
| } |
| |
| Status CourgetteFlow::status() { |
| return status_; |
| } |
| |
| const std::string& CourgetteFlow::message() { |
| return message_; |
| } |
| |
| void CourgetteFlow::ReadSourceStreamSetFromBuffer(Group group, |
| const BasicBuffer& buffer) { |
| if (failed()) |
| return; |
| Data* d = data(group); |
| if (!check(d->sources.Init(buffer.data(), buffer.length()), |
| C_GENERAL_ERROR)) { |
| setMessage("Cannot read %s as SourceStreamSet.", name(group)); |
| } |
| } |
| |
| void CourgetteFlow::ReadDisassemblerFromBuffer(Group group, |
| const BasicBuffer& buffer) { |
| if (failed()) |
| return; |
| Data* d = data(group); |
| d->disassembler = DetectDisassembler(buffer.data(), buffer.length()); |
| if (!check(d->disassembler.get() != nullptr, C_INPUT_NOT_RECOGNIZED)) |
| setMessage("Cannot detect program for %s.", name(group)); |
| } |
| |
| void CourgetteFlow::ReadEncodedProgramFromSourceStreamSet( |
| Group group, |
| SourceStreamSet* opt_sources /* nullptr */) { |
| if (failed()) |
| return; |
| Data* d = data(group); |
| SourceStreamSet* sources = opt_sources ? opt_sources : &d->sources; |
| if (!check(ReadEncodedProgram(sources, &d->encoded))) |
| setMessage("Cannot read %s as encoded program.", name(group)); |
| } |
| |
| void CourgetteFlow::CreateAssemblyProgramFromDisassembler(Group group, |
| bool annotate) { |
| if (failed()) |
| return; |
| Data* d = data(group); |
| d->program = d->disassembler->CreateProgram(annotate); |
| if (!check(d->program.get() != nullptr, C_DISASSEMBLY_FAILED)) |
| setMessage("Cannot create AssemblyProgram for %s.", name(group)); |
| } |
| |
| void CourgetteFlow::CreateEncodedProgramFromDisassemblerAndAssemblyProgram( |
| Group group) { |
| if (failed()) |
| return; |
| Data* d = data(group); |
| d->encoded = std::make_unique<EncodedProgram>(); |
| if (!check(d->disassembler->DisassembleAndEncode(d->program.get(), |
| d->encoded.get()))) { |
| setMessage("Cannot disassemble to form EncodedProgram for %s.", |
| name(group)); |
| } |
| } |
| |
| void CourgetteFlow::WriteSinkStreamFromSinkStreamSet(Group group, |
| SinkStream* sink) { |
| DCHECK(sink); |
| if (failed()) |
| return; |
| if (!check(data(group)->sinks.CopyTo(sink), C_GENERAL_ERROR)) |
| setMessage("Cannnot combine serialized streams for %s.", name(group)); |
| } |
| |
| void CourgetteFlow::WriteSinkStreamSetFromEncodedProgram( |
| Group group, |
| SinkStreamSet* opt_sinks /* nullptr */) { |
| if (failed()) |
| return; |
| Data* d = data(group); |
| SinkStreamSet* sinks = opt_sinks ? opt_sinks : &d->sinks; |
| if (!check(WriteEncodedProgram(d->encoded.get(), sinks))) |
| setMessage("Cannot serialize encoded %s.", name(group)); |
| } |
| |
| void CourgetteFlow::WriteExecutableFromEncodedProgram(Group group, |
| SinkStream* sink) { |
| DCHECK(sink); |
| if (failed()) |
| return; |
| if (!check(Assemble(data(group)->encoded.get(), sink))) |
| setMessage("Cannot assemble %s.", name(group)); |
| } |
| |
| void CourgetteFlow::AdjustNewAssemblyProgramToMatchOld() { |
| if (failed()) |
| return; |
| if (!check(Adjust(*data_old_.program, data_new_.program.get()))) |
| setMessage("Cannot adjust %s to match %s.", name(OLD), name(NEW)); |
| } |
| |
| void CourgetteFlow::DestroyDisassembler(Group group) { |
| if (failed()) |
| return; |
| data(group)->disassembler.reset(); |
| } |
| |
| void CourgetteFlow::DestroyAssemblyProgram(Group group) { |
| if (failed()) |
| return; |
| data(group)->program.reset(); |
| } |
| |
| void CourgetteFlow::DestroyEncodedProgram(Group group) { |
| if (failed()) |
| return; |
| data(group)->encoded.reset(); |
| } |
| |
| bool CourgetteFlow::check(Status new_status) { |
| if (new_status == C_OK) |
| return true; |
| status_ = new_status; |
| return false; |
| } |
| |
| bool CourgetteFlow::check(bool success, Status failure_mode) { |
| if (success) |
| return true; |
| status_ = failure_mode; |
| return false; |
| } |
| |
| void CourgetteFlow::setMessage(const char* format, ...) { |
| va_list args; |
| va_start(args, format); |
| message_ = base::StringPrintV(format, args); |
| va_end(args); |
| } |
| |
| } // namespace courgette |