<commit_before>#include "config.h"
#include "release.h"
#include "vm.hpp"
#include "call_frame.hpp"
#include "environment.hpp"
#include "signal.hpp"
#include "configuration.hpp"

#include "builtin/module.hpp"
#include "builtin/array.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/jit.hpp"
#include "builtin/module.hpp"
#include "builtin/module.hpp"
#include "builtin/native_method.hpp"
#include "builtin/string.hpp"
#include "builtin/thread.hpp"

#include <string>
#include <iostream>
#include <fcntl.h>

#include "util/logger.hpp"

#include "dtrace/dtrace.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#ifdef USE_EXECINFO
#include <execinfo.h>
#endif

#ifdef RBX_WINDOWS
#include "windows_compat.h"
#else
#include <dlfcn.h>
#include <sys/utsname.h>
#include <sys/select.h>
#endif

namespace rubinius {
  using namespace utilities;

  static SignalThread* signal_thread_ = 0;

  // Used by the segfault reporter. Calculated up front to avoid
  // crashing inside the crash handler.
  static struct utsname machine_info;

  SignalThread::SignalThread(STATE, Configuration& config)
    : InternalThread(state, "rbx.signal", InternalThread::eSmall)
    , shared_(state->shared())
    , target_(state->vm())
    , queued_signals_(0)
  {
    signal_thread_ = this;
    shared_.set_signal_handler(this);

    setup_default_handlers();
  }

  void SignalThread::initialize(STATE) {
    InternalThread::initialize(state);

    for(int i = 0; i < NSIG; i++) {
      pending_signals_[i] = 0;
    }

    worker_lock_.init();
    worker_cond_.init();
  }

  void SignalThread::wakeup(STATE) {
    InternalThread::wakeup(state);

    worker_cond_.signal();
  }

  void SignalThread::stop(STATE) {
    for(std::list<int>::iterator i = watched_signals_.begin();
        i != watched_signals_.end();
        ++i) {
      signal(*i, SIG_DFL);
    }

    InternalThread::stop(state);
  }

  void SignalThread::print_machine_info(PrintFunction function) {
    function("sysname: %s", machine_info.sysname);
    function("nodename: %s", machine_info.nodename);
    function("release: %s", machine_info.release);
    function("version: %s", machine_info.version);
    function("machine: %s", machine_info.machine);
  }

  void SignalThread::print_process_info(PrintFunction function) {
    function("user: %s", signal_thread_->shared().username.c_str());
    function("pid: %s", signal_thread_->shared().pid.c_str());
    function("program name: %s", RBX_PROGRAM_NAME);
    function("version: %s", RBX_VERSION);
    function("ruby version: %s", RBX_RUBY_VERSION);
    function("release date: %s", RBX_RELEASE_DATE);
    function("build revision: %s", RBX_BUILD_REV);
#if ENABLE_LLVM
    function("llvm version: %s", RBX_LLVM_VERSION);
#endif
    function("jit status: %s",
        CBOOL(signal_thread_->shared().env()->state->globals().jit.get()->enabled())
        ? "enabled" : "disabled");
  }

  void SignalThread::run(STATE) {
#ifndef RBX_WINDOWS
    sigset_t set;
    sigfillset(&set);
    pthread_sigmask(SIG_BLOCK, &set, NULL);
#endif

    GCTokenImpl gct;

    metrics().init(metrics::eRubyMetrics);

    while(!thread_exit_) {
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
        state->gc_independent(gct, 0);
        worker_cond_.wait(worker_lock_);
        // If we should exit now, don't try to become
        // dependent first but break and exit the thread
        if(thread_exit_) break;
      }
      state->gc_dependent(gct, 0);
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
      }

      target_->wakeup(state, gct, 0);
    }
  }

  void SignalThread::signal_handler(int sig) {
    signal_thread_->handle_signal(sig);
  }

  void SignalThread::handle_signal(int sig) {
    if(thread_exit_) return;

    target_->metrics().system_metrics.os_signals_received++;

    queued_signals_ = 1;
    pending_signals_[sig] = 1;

    target_->set_check_local_interrupts();

    if(target_->should_interrupt_with_signal()) {
      if(!pthread_equal(pthread_self(), target_->os_thread())) {
#ifdef RBX_WINDOWS
        // TODO: Windows
#else
        pthread_kill(target_->os_thread(), SIGVTALRM);
#endif
      }
    }

    worker_cond_.signal();
  }

  void SignalThread::add_signal(STATE, int sig, HandlerType type) {
    SYNC(state);
    utilities::thread::Mutex::LockGuard lg(worker_lock_);

#ifndef RBX_WINDOWS
    struct sigaction action;

    if(type == eDefault) {
      action.sa_handler = SIG_DFL;
      watched_signals_.remove(sig);
    } else if(type == eIgnore) {
      action.sa_handler = SIG_IGN;
      watched_signals_.push_back(sig);
    } else {
      action.sa_handler = signal_handler;
      watched_signals_.push_back(sig);
    }

    action.sa_flags = 0;
    sigfillset(&action.sa_mask);

    sigaction(sig, &action, NULL);
#endif
  }

  bool SignalThread::deliver_signals(STATE, CallFrame* call_frame) {
    queued_signals_ = 0;

    for(int i = 0; i < NSIG; i++) {
      if(pending_signals_[i] > 0) {
        pending_signals_[i] = 0;

        target_->metrics().system_metrics.os_signals_processed++;

        Array* args = Array::create(state, 1);
        args->set(state, 0, Fixnum::from(i));

        // Check whether the send raised an exception and
        // stop running the handlers if that happens
        if(!G(rubinius)->send(state, call_frame,
               state->symbol("received_signal"), args, cNil)) {
          if(state->thread_state()->raise_reason() == cException ||
             state->thread_state()->raise_reason() == cExit) {
            return false;
          }
        }
      }
    }

    return true;
  }

  void SignalThread::print_backtraces() {
    STATE = shared_.env()->state;
    ThreadList* threads = shared_.threads();

    for(ThreadList::iterator i = threads->begin(); i != threads->end(); ++i) {
      VM* vm = (*i)->as_vm();
      if(!vm) continue;

      if(vm->saved_call_frame()) {
        utilities::logger::fatal("--- Thread %d backtrace ---", vm->thread_id());
      }

      for(CallFrame* frame = vm->saved_call_frame(); frame; frame = frame->previous) {
        std::ostringstream stream;

        if(NativeMethodFrame* nmf = frame->native_method_frame()) {
          stream << static_cast<void*>(frame) << ": ";
          NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method()));
          if(nm && nm->name()->symbol_p()) {
            stream << "capi:" << nm->name()->debug_str(state) << " at ";
            stream << nm->file()->c_str(state);
          } else {
            stream << "unknown capi";
          }
        } else if(frame->compiled_code) {
          if(frame->is_block_p(state)) {
            stream << "__block__";
          } else {
            if(SingletonClass* sc = try_as<SingletonClass>(frame->module())) {
              Object* obj = sc->singleton();

              if(Module* mod = try_as<Module>(obj)) {
                stream << mod->debug_str(state) << ".";
              } else {
                if(obj == G(main)) {
                  stream << "MAIN.";
                } else {
                  stream << "#<" << obj->class_object(state)->debug_str(state) <<
                            ":" << (void*)obj->id(state)->to_native() << ">.";
                }
              }
            } else if(IncludedModule* im = try_as<IncludedModule>(frame->module())) {
              stream <<  im->module()->debug_str(state) << "#";
            } else {
              Symbol* name;
              std::string mod_name;

              if(frame->module()->nil_p()) {
                mod_name = frame->constant_scope()->module()->debug_str(state);
              } else {
                if((name = try_as<Symbol>(frame->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else if((name = try_as<Symbol>(
                          frame->constant_scope()->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else {
                  mod_name = "<anonymous module>";
                }
              }
              stream << mod_name << "#";
            }

            Symbol* name = try_as<Symbol>(frame->name());
            if(name) {
              stream << name->debug_str(state);
            } else {
              stream << frame->compiled_code->name()->debug_str(state);
            }
          }

          stream << " in ";
          if(Symbol* file_sym = try_as<Symbol>(frame->compiled_code->file())) {
            stream << file_sym->debug_str(state) << ":" << frame->line(state);
          } else {
            stream << "<unknown>";
          }

          stream << " (+" << frame->ip();
          if(frame->is_inline_frame()) {
            stream << " inline";
          } else if(frame->jitted_p()) {
            stream << " jit";
          }
          stream << ")";
        }

        utilities::logger::fatal(stream.str().c_str());
      }
    }
  }

  static void null_func(int sig) {}

#ifdef USE_EXECINFO
  static const char* rbx_signal_string(int sig) {
    switch(sig) {
    case SIGSEGV:
      return "SIGSEGV";
    case SIGBUS:
      return "SIGBUS";
    case SIGILL:
      return "SIGILL";
    case SIGABRT:
      return "SIGABRT";
    case SIGFPE:
      return "SIGFPE";
    default:
      return "UNKNOWN";
    }
  }

  static void abandon_ship_handler(int sig) {
    struct sigaction action;

    // Unset our handler for this signal.
    action.sa_handler = SIG_DFL;
    action.sa_flags = 0;
    sigaction(sig, &action, NULL);

    char* pause_env = getenv("RBX_PAUSE_ON_CRASH");

    if(pause_env) {
      long timeout = strtol(pause_env, NULL, 10);
      if(timeout <= 0) {
        timeout = 60;
      } else {
        timeout *= 60;
      }
      std::cerr << "\n========== CRASH (" << getpid();
      std::cerr << "), pausing for " << timeout << " seconds to attach debugger\n";
      sleep(timeout);
    }

#define RBX_ABORT_CALLSTACK_SIZE    128
    void* callstack[RBX_ABORT_CALLSTACK_SIZE];
    int i, frames = backtrace(callstack, RBX_ABORT_CALLSTACK_SIZE);
    char** symbols = backtrace_symbols(callstack, frames);

    logger::fatal("The Rubinius process is aborting with signal: %s",
                  rbx_signal_string(sig));
    logger::fatal("--- begin system info ---");
    signal_thread_->print_machine_info(logger::fatal);
    logger::fatal("--- end system info ---");

    logger::fatal("--- begin rubinius info ---");
    signal_thread_->print_process_info(logger::fatal);
    logger::fatal("--- end rubinius info ---");

    logger::fatal("--- begin system backtrace ---");
    for(i = 0; i < frames; i++) {
      logger::fatal("%s", symbols[i]);
    }
    logger::fatal("--- end system backtrace ---");

    logger::fatal("--- begin Ruby backtraces ---");
    signal_thread_->print_backtraces();
    logger::fatal("--- end Ruby backtraces ---");

    raise(sig);
  }
#endif

  void SignalThread::setup_default_handlers() {
#ifndef RBX_WINDOWS
    // Get the machine info.
    uname(&machine_info);

    struct sigaction action;
    action.sa_handler = null_func;
    action.sa_flags = 0;
    sigfillset(&action.sa_mask);
    sigaction(SIGVTALRM, &action, NULL);

    // Some extensions expect SIGALRM to be defined, because MRI does.
    // We'll just use a noop for it.
    action.sa_handler = null_func;
    sigaction(SIGALRM, &action, NULL);

    // Ignore sigpipe.
    action.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &action, NULL);

#ifdef USE_EXECINFO
    // If we have execinfo, setup some crash handlers
    if(!getenv("DISABLE_SEGV")) {
      action.sa_handler = abandon_ship_handler;
      sigaction(SIGSEGV, &action, NULL);
      sigaction(SIGBUS,  &action, NULL);
      sigaction(SIGILL,  &action, NULL);
      sigaction(SIGFPE,  &action, NULL);
      sigaction(SIGABRT, &action, NULL);
    }
#endif  // USE_EXEC_INFO
#else
    signal(SIGTERM, quit_handler);
#endif  // ifndef RBX_WINDOWS
  }
}
<commit_msg>Simplified node, process info logging format.<commit_after>#include "config.h"
#include "release.h"
#include "vm.hpp"
#include "call_frame.hpp"
#include "environment.hpp"
#include "signal.hpp"
#include "configuration.hpp"

#include "builtin/module.hpp"
#include "builtin/array.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/jit.hpp"
#include "builtin/module.hpp"
#include "builtin/module.hpp"
#include "builtin/native_method.hpp"
#include "builtin/string.hpp"
#include "builtin/thread.hpp"

#include <string>
#include <iostream>
#include <fcntl.h>

#include "util/logger.hpp"

#include "dtrace/dtrace.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#ifdef USE_EXECINFO
#include <execinfo.h>
#endif

#ifdef RBX_WINDOWS
#include "windows_compat.h"
#else
#include <dlfcn.h>
#include <sys/utsname.h>
#include <sys/select.h>
#endif

namespace rubinius {
  using namespace utilities;

  static SignalThread* signal_thread_ = 0;

  // Used by the segfault reporter. Calculated up front to avoid
  // crashing inside the crash handler.
  static struct utsname machine_info;

  SignalThread::SignalThread(STATE, Configuration& config)
    : InternalThread(state, "rbx.signal", InternalThread::eSmall)
    , shared_(state->shared())
    , target_(state->vm())
    , queued_signals_(0)
  {
    signal_thread_ = this;
    shared_.set_signal_handler(this);

    setup_default_handlers();
  }

  void SignalThread::initialize(STATE) {
    InternalThread::initialize(state);

    for(int i = 0; i < NSIG; i++) {
      pending_signals_[i] = 0;
    }

    worker_lock_.init();
    worker_cond_.init();
  }

  void SignalThread::wakeup(STATE) {
    InternalThread::wakeup(state);

    worker_cond_.signal();
  }

  void SignalThread::stop(STATE) {
    for(std::list<int>::iterator i = watched_signals_.begin();
        i != watched_signals_.end();
        ++i) {
      signal(*i, SIG_DFL);
    }

    InternalThread::stop(state);
  }

  void SignalThread::print_machine_info(PrintFunction function) {
    function("node info: %s %s", machine_info.nodename, machine_info.version);
  }

#define RBX_PROCESS_INFO_LEN    256

  void SignalThread::print_process_info(PrintFunction function) {
    const char* llvm_version;
    const char* jit_status;

#if ENABLE_LLVM
    llvm_version = RBX_LLVM_VERSION;
#else
    llvm_version = "LLVM Disabled";
#endif

    if(CBOOL(signal_thread_->shared().env()->state->globals().jit.get()->enabled())) {
      jit_status = "JIT";
    } else {
      jit_status = "JIT disabled";
    }

    char process_info[RBX_PROCESS_INFO_LEN];

    snprintf(process_info, RBX_PROCESS_INFO_LEN, "%s %s %s %s %s %s %.8s %s %s",
        signal_thread_->shared().username.c_str(),
        RBX_PROGRAM_NAME, signal_thread_->shared().pid.c_str(),
        RBX_VERSION, RBX_RUBY_VERSION, RBX_RELEASE_DATE, RBX_BUILD_REV,
        llvm_version, jit_status);

    function("process info: %s", process_info);
  }

  void SignalThread::run(STATE) {
#ifndef RBX_WINDOWS
    sigset_t set;
    sigfillset(&set);
    pthread_sigmask(SIG_BLOCK, &set, NULL);
#endif

    GCTokenImpl gct;

    metrics().init(metrics::eRubyMetrics);

    while(!thread_exit_) {
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
        state->gc_independent(gct, 0);
        worker_cond_.wait(worker_lock_);
        // If we should exit now, don't try to become
        // dependent first but break and exit the thread
        if(thread_exit_) break;
      }
      state->gc_dependent(gct, 0);
      {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);
        if(thread_exit_) break;
      }

      target_->wakeup(state, gct, 0);
    }
  }

  void SignalThread::signal_handler(int sig) {
    signal_thread_->handle_signal(sig);
  }

  void SignalThread::handle_signal(int sig) {
    if(thread_exit_) return;

    target_->metrics().system_metrics.os_signals_received++;

    queued_signals_ = 1;
    pending_signals_[sig] = 1;

    target_->set_check_local_interrupts();

    if(target_->should_interrupt_with_signal()) {
      if(!pthread_equal(pthread_self(), target_->os_thread())) {
#ifdef RBX_WINDOWS
        // TODO: Windows
#else
        pthread_kill(target_->os_thread(), SIGVTALRM);
#endif
      }
    }

    worker_cond_.signal();
  }

  void SignalThread::add_signal(STATE, int sig, HandlerType type) {
    SYNC(state);
    utilities::thread::Mutex::LockGuard lg(worker_lock_);

#ifndef RBX_WINDOWS
    struct sigaction action;

    if(type == eDefault) {
      action.sa_handler = SIG_DFL;
      watched_signals_.remove(sig);
    } else if(type == eIgnore) {
      action.sa_handler = SIG_IGN;
      watched_signals_.push_back(sig);
    } else {
      action.sa_handler = signal_handler;
      watched_signals_.push_back(sig);
    }

    action.sa_flags = 0;
    sigfillset(&action.sa_mask);

    sigaction(sig, &action, NULL);
#endif
  }

  bool SignalThread::deliver_signals(STATE, CallFrame* call_frame) {
    queued_signals_ = 0;

    for(int i = 0; i < NSIG; i++) {
      if(pending_signals_[i] > 0) {
        pending_signals_[i] = 0;

        target_->metrics().system_metrics.os_signals_processed++;

        Array* args = Array::create(state, 1);
        args->set(state, 0, Fixnum::from(i));

        // Check whether the send raised an exception and
        // stop running the handlers if that happens
        if(!G(rubinius)->send(state, call_frame,
               state->symbol("received_signal"), args, cNil)) {
          if(state->thread_state()->raise_reason() == cException ||
             state->thread_state()->raise_reason() == cExit) {
            return false;
          }
        }
      }
    }

    return true;
  }

  void SignalThread::print_backtraces() {
    STATE = shared_.env()->state;
    ThreadList* threads = shared_.threads();

    for(ThreadList::iterator i = threads->begin(); i != threads->end(); ++i) {
      VM* vm = (*i)->as_vm();
      if(!vm) continue;

      if(vm->saved_call_frame()) {
        utilities::logger::fatal("--- Thread %d backtrace ---", vm->thread_id());
      }

      for(CallFrame* frame = vm->saved_call_frame(); frame; frame = frame->previous) {
        std::ostringstream stream;

        if(NativeMethodFrame* nmf = frame->native_method_frame()) {
          stream << static_cast<void*>(frame) << ": ";
          NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method()));
          if(nm && nm->name()->symbol_p()) {
            stream << "capi:" << nm->name()->debug_str(state) << " at ";
            stream << nm->file()->c_str(state);
          } else {
            stream << "unknown capi";
          }
        } else if(frame->compiled_code) {
          if(frame->is_block_p(state)) {
            stream << "__block__";
          } else {
            if(SingletonClass* sc = try_as<SingletonClass>(frame->module())) {
              Object* obj = sc->singleton();

              if(Module* mod = try_as<Module>(obj)) {
                stream << mod->debug_str(state) << ".";
              } else {
                if(obj == G(main)) {
                  stream << "MAIN.";
                } else {
                  stream << "#<" << obj->class_object(state)->debug_str(state) <<
                            ":" << (void*)obj->id(state)->to_native() << ">.";
                }
              }
            } else if(IncludedModule* im = try_as<IncludedModule>(frame->module())) {
              stream <<  im->module()->debug_str(state) << "#";
            } else {
              Symbol* name;
              std::string mod_name;

              if(frame->module()->nil_p()) {
                mod_name = frame->constant_scope()->module()->debug_str(state);
              } else {
                if((name = try_as<Symbol>(frame->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else if((name = try_as<Symbol>(
                          frame->constant_scope()->module()->module_name()))) {
                  mod_name = name->debug_str(state);
                } else {
                  mod_name = "<anonymous module>";
                }
              }
              stream << mod_name << "#";
            }

            Symbol* name = try_as<Symbol>(frame->name());
            if(name) {
              stream << name->debug_str(state);
            } else {
              stream << frame->compiled_code->name()->debug_str(state);
            }
          }

          stream << " in ";
          if(Symbol* file_sym = try_as<Symbol>(frame->compiled_code->file())) {
            stream << file_sym->debug_str(state) << ":" << frame->line(state);
          } else {
            stream << "<unknown>";
          }

          stream << " (+" << frame->ip();
          if(frame->is_inline_frame()) {
            stream << " inline";
          } else if(frame->jitted_p()) {
            stream << " jit";
          }
          stream << ")";
        }

        utilities::logger::fatal(stream.str().c_str());
      }
    }
  }

  static void null_func(int sig) {}

#ifdef USE_EXECINFO
  static const char* rbx_signal_string(int sig) {
    switch(sig) {
    case SIGSEGV:
      return "SIGSEGV";
    case SIGBUS:
      return "SIGBUS";
    case SIGILL:
      return "SIGILL";
    case SIGABRT:
      return "SIGABRT";
    case SIGFPE:
      return "SIGFPE";
    default:
      return "UNKNOWN";
    }
  }

  static void abandon_ship_handler(int sig) {
    struct sigaction action;

    // Unset our handler for this signal.
    action.sa_handler = SIG_DFL;
    action.sa_flags = 0;
    sigaction(sig, &action, NULL);

    char* pause_env = getenv("RBX_PAUSE_ON_CRASH");

    if(pause_env) {
      long timeout = strtol(pause_env, NULL, 10);
      if(timeout <= 0) {
        timeout = 60;
      } else {
        timeout *= 60;
      }
      std::cerr << "\n========== CRASH (" << getpid();
      std::cerr << "), pausing for " << timeout << " seconds to attach debugger\n";
      sleep(timeout);
    }

#define RBX_ABORT_CALLSTACK_SIZE    128
    void* callstack[RBX_ABORT_CALLSTACK_SIZE];
    int i, frames = backtrace(callstack, RBX_ABORT_CALLSTACK_SIZE);
    char** symbols = backtrace_symbols(callstack, frames);

    logger::fatal("The Rubinius process is aborting with signal: %s",
                  rbx_signal_string(sig));
    logger::fatal("--- begin system info ---");
    signal_thread_->print_machine_info(logger::fatal);
    logger::fatal("--- end system info ---");

    logger::fatal("--- begin rubinius info ---");
    signal_thread_->print_process_info(logger::fatal);
    logger::fatal("--- end rubinius info ---");

    logger::fatal("--- begin system backtrace ---");
    for(i = 0; i < frames; i++) {
      logger::fatal("%s", symbols[i]);
    }
    logger::fatal("--- end system backtrace ---");

    logger::fatal("--- begin Ruby backtraces ---");
    signal_thread_->print_backtraces();
    logger::fatal("--- end Ruby backtraces ---");

    raise(sig);
  }
#endif

  void SignalThread::setup_default_handlers() {
#ifndef RBX_WINDOWS
    // Get the machine info.
    uname(&machine_info);

    struct sigaction action;
    action.sa_handler = null_func;
    action.sa_flags = 0;
    sigfillset(&action.sa_mask);
    sigaction(SIGVTALRM, &action, NULL);

    // Some extensions expect SIGALRM to be defined, because MRI does.
    // We'll just use a noop for it.
    action.sa_handler = null_func;
    sigaction(SIGALRM, &action, NULL);

    // Ignore sigpipe.
    action.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &action, NULL);

#ifdef USE_EXECINFO
    // If we have execinfo, setup some crash handlers
    if(!getenv("DISABLE_SEGV")) {
      action.sa_handler = abandon_ship_handler;
      sigaction(SIGSEGV, &action, NULL);
      sigaction(SIGBUS,  &action, NULL);
      sigaction(SIGILL,  &action, NULL);
      sigaction(SIGFPE,  &action, NULL);
      sigaction(SIGABRT, &action, NULL);
    }
#endif  // USE_EXEC_INFO
#else
    signal(SIGTERM, quit_handler);
#endif  // ifndef RBX_WINDOWS
  }
}
<|endoftext|>


<commit_before>// Copyright 2014 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <bsoncxx/oid.hpp>

#include <cstring>

#include <bson.h>

namespace bsoncxx {
BSONCXX_INLINE_NAMESPACE_BEGIN

oid::oid() : _is_valid(false) {
}

oid::oid(init_tag_t) : _is_valid(true) {
    bson_oid_t oid;
    bson_oid_init(&oid, nullptr);

    std::memcpy(_bytes, oid.bytes, sizeof(oid.bytes));
}

oid::oid(stdx::string_view str) : _is_valid(bson_oid_is_valid(str.data(), str.length())) {
    if (_is_valid) {
        bson_oid_t oid;
        bson_oid_init_from_string(&oid, str.data());
    }
}

oid::oid(const char* bytes, std::size_t len) : _is_valid(len == 12) {
    if (_is_valid) {
        std::memcpy(_bytes, bytes, sizeof(_bytes));
    }
}

std::string oid::to_string() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    return std::string(str);
}

oid::operator bool() const {
    return _is_valid;
}

std::time_t oid::get_time_t() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));

    return bson_oid_get_time_t(&oid);
}

const char* oid::bytes() const {
    return _bytes;
}

int oid_compare(const oid& lhs, const oid& rhs) {
    if (!lhs._is_valid || !rhs._is_valid) {
        if (lhs._is_valid) {
            return 1;
        } else if (rhs._is_valid) {
            return -1;
        } else {
            return 0;
        }
    }

    bson_oid_t lhs_oid;
    bson_oid_t rhs_oid;

    std::memcpy(lhs_oid.bytes, lhs.bytes(), sizeof(lhs_oid.bytes));
    std::memcpy(rhs_oid.bytes, rhs.bytes(), sizeof(rhs_oid.bytes));

    return bson_oid_compare(&lhs_oid, &rhs_oid);
}

bool operator<(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) < 0;
}

bool operator>(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) > 0;
}

bool operator<=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) <= 0;
}

bool operator>=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) >= 0;
}

bool operator==(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) == 0;
}

bool operator!=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) != 0;
}

std::ostream& operator<<(std::ostream& out, const oid& rhs) {
    bson_oid_t oid;
    std::memcpy(oid.bytes, rhs._bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    out << str;

    return out;
}

BSONCXX_INLINE_NAMESPACE_END
}  // namespace bsoncxx
<commit_msg>CXX-661 - Added missing memcpy in oid constructor.<commit_after>// Copyright 2014 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <bsoncxx/oid.hpp>

#include <cstring>

#include <bson.h>

namespace bsoncxx {
BSONCXX_INLINE_NAMESPACE_BEGIN

oid::oid() : _is_valid(false) {
}

oid::oid(init_tag_t) : _is_valid(true) {
    bson_oid_t oid;
    bson_oid_init(&oid, nullptr);

    std::memcpy(_bytes, oid.bytes, sizeof(oid.bytes));
}

oid::oid(stdx::string_view str) : _is_valid(bson_oid_is_valid(str.data(), str.length())) {
    if (_is_valid) {
        bson_oid_t oid;
        bson_oid_init_from_string(&oid, str.data());
        memcpy(_bytes, oid.bytes, sizeof(_bytes));
    }
}

oid::oid(const char* bytes, std::size_t len) : _is_valid(len == 12) {
    if (_is_valid) {
        std::memcpy(_bytes, bytes, sizeof(_bytes));
    }
}

std::string oid::to_string() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    return std::string(str);
}

oid::operator bool() const {
    return _is_valid;
}

std::time_t oid::get_time_t() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));

    return bson_oid_get_time_t(&oid);
}

const char* oid::bytes() const {
    return _bytes;
}

int oid_compare(const oid& lhs, const oid& rhs) {
    if (!lhs._is_valid || !rhs._is_valid) {
        if (lhs._is_valid) {
            return 1;
        } else if (rhs._is_valid) {
            return -1;
        } else {
            return 0;
        }
    }

    bson_oid_t lhs_oid;
    bson_oid_t rhs_oid;

    std::memcpy(lhs_oid.bytes, lhs.bytes(), sizeof(lhs_oid.bytes));
    std::memcpy(rhs_oid.bytes, rhs.bytes(), sizeof(rhs_oid.bytes));

    return bson_oid_compare(&lhs_oid, &rhs_oid);
}

bool operator<(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) < 0;
}

bool operator>(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) > 0;
}

bool operator<=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) <= 0;
}

bool operator>=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) >= 0;
}

bool operator==(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) == 0;
}

bool operator!=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) != 0;
}

std::ostream& operator<<(std::ostream& out, const oid& rhs) {
    bson_oid_t oid;
    std::memcpy(oid.bytes, rhs._bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    out << str;

    return out;
}

BSONCXX_INLINE_NAMESPACE_END
}  // namespace bsoncxx
<|endoftext|>


<commit_before>#include "Ch04.hpp"
#include "fp_manip.hpp"
#include <iostream>

namespace fmtgp
{

integer quotient_fibonacci(line_segment a, line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return integer{0};
    }

    auto orig_b = b;

    line_segment c = b;
    auto fib = std::make_pair(1, 1);
    do
    {
        line_segment tmp = c;
        c = b + c;
        b = tmp;
        fib = std::make_pair(fib.second, fib.second + fib.first);
    } while (a >= c);

    integer n{fib.first};
    auto bb = b;
    while (bb + orig_b < a)
    {
        ++n;
        bb += orig_b;
    }

    do
    {
        if (a >= b)
        {
            a = a - b;
        }

        line_segment tmp = c - b;
        c = b;
        b = tmp;

    } while (b < c);

    return n;
}

line_segment remainder_fibonacci(line_segment a, line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return a;
    }

    line_segment c = b;
    do
    {
        line_segment tmp = c;
        c = b + c;
        b = tmp;
    } while (a >= c);

    do
    {
        if (a >= b)
        {
            a = a - b;
        }
        line_segment tmp = c - b;
        c = b;
        b = tmp;
    } while (b < c);

    return a;
}

std::pair<integer, line_segment> quotient_remainder(line_segment a,
                                                    line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return {integer{0}, a};
    }

    line_segment c = largest_doubling(a, b);
    integer n{1};
    a = a - c;
    while (fp::not_equal(c, b))
    {
        c = half(c);
        n = n + n;
        if (c <= a)
        {
            a = a - c;
            n = n + 1;
        }
    }

    return {n, a};
}

integer quotient(line_segment a, line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return integer{0};
    }

    line_segment c = largest_doubling(a, b);

    integer n{1};
    a = a - c;
    while (fp::not_equal(c, b))
    {
        c = half(c);
        n = n + n;
        if (c <= a)
        {
            a = a - c;
            n = n + 1;
        }
    }
    return n;
}

line_segment remainder(line_segment a, line_segment b)
{
    // Precondition: b != 0
    if (a < b)
        return a;

    line_segment c = largest_doubling(a, b);
    a = a - c;
    while (fp::not_equal(c, b))
    {
        c = half(c);
        if (c <= a)
            a = a - c;
    }

    return a;
}

line_segment largest_doubling(line_segment a, line_segment b)
{
    // precondition: b != 0
    while (a - b >= b)
    {
        b = b + b;
    }
    return b;
}

line_segment half(line_segment a)
{
    return a / 2;
}

line_segment gcm_remainder(line_segment a, line_segment b)
{
    while (fp::not_equal(b, 0.0))
    {
        a = remainder(a, b);
        std::swap(a, b);
    }

    return a;
}

integer gcd(integer a, integer b)
{
    while (b != integer{0})
    {
        a = a % b;
        std::swap(a, b);
    }

    return a;
}

}
<commit_msg>[fmtgp] fibonacci quotient<commit_after>#include "Ch04.hpp"
#include "fp_manip.hpp"

namespace fmtgp
{

template <typename T>
void next_fib(std::pair<T,T>& fib)
{
    fib = std::make_pair(fib.second, fib.second + fib.first);
}

template<typename T>
void last_fib(std::pair<T,T>& fib)
{
    fib = std::make_pair(fib.second - fib.first, fib.first);
}

integer quotient_fibonacci(line_segment a, line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return integer{0};
    }

    auto fib_dvsr = std::make_pair(b, b);
    auto fib_base = std::make_pair(1, 1);

    do
    {
        next_fib(fib_dvsr);
        next_fib(fib_base);
    } while (a >= fib_dvsr.second);

    integer n{0};
    do
    {
        if (a >= fib_dvsr.first)
        {
            a = a - fib_dvsr.first;
            n += fib_base.first;
        }

        last_fib(fib_dvsr);
        last_fib(fib_base);

    } while (fib_dvsr.first < fib_dvsr.second);

    return n;
}

line_segment remainder_fibonacci(line_segment a, line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return a;
    }

    line_segment c = b;
    do
    {
        line_segment tmp = c;
        c = b + c;
        b = tmp;
    } while (a >= c);

    do
    {
        if (a >= b)
        {
            a = a - b;
        }
        line_segment tmp = c - b;
        c = b;
        b = tmp;
    } while (b < c);

    return a;
}

std::pair<integer, line_segment> quotient_remainder(line_segment a,
                                                    line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return {integer{0}, a};
    }

    line_segment c = largest_doubling(a, b);
    integer n{1};
    a = a - c;
    while (fp::not_equal(c, b))
    {
        c = half(c);
        n = n + n;
        if (c <= a)
        {
            a = a - c;
            n = n + 1;
        }
    }

    return {n, a};
}

integer quotient(line_segment a, line_segment b)
{
    // Precondition: b > 0
    if (a < b)
    {
        return integer{0};
    }

    line_segment c = largest_doubling(a, b);

    integer n{1};
    a = a - c;
    while (fp::not_equal(c, b))
    {
        c = half(c);
        n = n + n;
        if (c <= a)
        {
            a = a - c;
            n = n + 1;
        }
    }
    return n;
}

line_segment remainder(line_segment a, line_segment b)
{
    // Precondition: b != 0
    if (a < b)
        return a;

    line_segment c = largest_doubling(a, b);
    a = a - c;
    while (fp::not_equal(c, b))
    {
        c = half(c);
        if (c <= a)
            a = a - c;
    }

    return a;
}

line_segment largest_doubling(line_segment a, line_segment b)
{
    // precondition: b != 0
    while (a - b >= b)
    {
        b = b + b;
    }
    return b;
}

line_segment half(line_segment a)
{
    return a / 2;
}

line_segment gcm_remainder(line_segment a, line_segment b)
{
    while (fp::not_equal(b, 0.0))
    {
        a = remainder(a, b);
        std::swap(a, b);
    }

    return a;
}

integer gcd(integer a, integer b)
{
    while (b != integer{0})
    {
        a = a % b;
        std::swap(a, b);
    }

    return a;
}

}
<|endoftext|>


<commit_before>//
//  Copyright (C) 2015  Marcus Comstedt <marcus@mc.pp.se>
//
//  Permission to use, copy, modify, and/or distribute this software for any
//  purpose with or without fee is hereby granted, provided that the above
//  copyright notice and this permission notice appear in all copies.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <fstream>
#include <iostream>
#include <cstdint>
#include <memory>

#include <stdio.h>
#include <stdlib.h>

#define log(...) fprintf(stderr, __VA_ARGS__);
#define info(...) do { if (log_level > 0) fprintf(stderr, __VA_ARGS__); } while (0)
#define error(...) do { fprintf(stderr, "Error: " __VA_ARGS__); exit(1); } while (0)

int log_level = 0;

static const int NUM_IMAGES = 4;
static const int NUM_HEADERS = NUM_IMAGES + 1;
static const int HEADER_SIZE = 32;

static void align_offset(uint32_t &offset, int bits)
{
    uint32_t mask = (1 << bits) - 1;
    if (offset & mask)
        offset = (offset | mask) + 1;
}

static void write_byte(std::ostream &ofs, uint32_t &file_offset, uint8_t byte)
{
    ofs << byte;
    file_offset++;
}

static void write_bytes(std::ostream &ofs, uint32_t &file_offset,
                        const uint8_t *buf, size_t n)
{
    if (n > 0) {
        ofs.write(reinterpret_cast<const char*>(buf), n);
        file_offset += n;
    }
}

static void write_file(std::ostream &ofs, uint32_t &file_offset,
                       std::istream &ifs)
{
    const size_t bufsize = 8192;
    uint8_t *buffer = new uint8_t[bufsize];

    while(!ifs.eof()) {
        ifs.read(reinterpret_cast<char *>(buffer), bufsize);
        if (ifs.bad())
            error("Read error on input image");
        write_bytes(ofs, file_offset, buffer, ifs.gcount());
    }

    delete[] buffer;
}

static void pad_to(std::ostream &ofs, uint32_t &file_offset, uint32_t target)
{
    if (target < file_offset)
        error("Trying to pad backwards!\n");
    while(file_offset < target)
        write_byte(ofs, file_offset, 0xff);
}

class Image {
    std::ifstream ifs;
    uint32_t offs;

public:
    Image(const char *filename) : ifs(filename, std::ifstream::binary) {}

    size_t size();
    void write(std::ostream &ofs, uint32_t &file_offset);
    void place(uint32_t o) { offs = o; }
    uint32_t offset() const { return offs; }
};

size_t Image::size()
{
    ifs.seekg (0, ifs.end);
    size_t length = ifs.tellg();
    ifs.seekg (0, ifs.beg);
    return length;
}

void Image::write(std::ostream &ofs, uint32_t &file_offset)
{
    write_file(ofs, file_offset, ifs);
}

class Header {
    uint32_t image_offs;
    bool coldboot_flag;
    bool empty;
public:
    Header() : empty(true) {}
    Header(const Image &i) :
        image_offs(i.offset()), coldboot_flag(false), empty(false) {}
    void set_coldboot_flag() { coldboot_flag = true; }
    void write(std::ostream &ofs, uint32_t &file_offset);
};

void Header::write(std::ostream &ofs, uint32_t &file_offset)
{
    if (empty)
        return;

    // Preamble
    write_byte(ofs, file_offset, 0x7e);
    write_byte(ofs, file_offset, 0xaa);
    write_byte(ofs, file_offset, 0x99);
    write_byte(ofs, file_offset, 0x7e);

    // Boot mode
    write_byte(ofs, file_offset, 0x92);
    write_byte(ofs, file_offset, 0x00);
    write_byte(ofs, file_offset, (coldboot_flag? 0x10: 0x00));

    // Boot address
    write_byte(ofs, file_offset, 0x44);
    write_byte(ofs, file_offset, 0x03);
    write_byte(ofs, file_offset, (image_offs >> 16) & 0xff);
    write_byte(ofs, file_offset, (image_offs >> 8) & 0xff);
    write_byte(ofs, file_offset, image_offs & 0xff);

    // Bank offset
    write_byte(ofs, file_offset, 0x82);
    write_byte(ofs, file_offset, 0x00);
    write_byte(ofs, file_offset, 0x00);

    // Reboot
    write_byte(ofs, file_offset, 0x01);
    write_byte(ofs, file_offset, 0x08);

    // Zero out any unused bytes
    while (file_offset & (HEADER_SIZE - 1))
        write_byte(ofs, file_offset, 0x00);
}

void usage()
{
    log("\n");
    log("Usage: icemulti [options] input-files\n");
    log("\n");
    log(" -c\n");
    log(" coldboot mode, power on reset image is selected by CBSEL0/CBSEL1\n");
    log("\n");
    log(" -p0, -p1, -p2, -p3\n");
    log(" select power on reset image when not using coldboot mode\n");
    log("\n");
    log(" -a<n>, -A<n>\n");
    log(" align images at 2^<n> bytes. -A also aligns image 0.\n");
    log("\n");
    log(" -o filename\n");
    log(" write output image to file instead of stdout\n");
    log("\n");
    log(" -v\n");
    log(" verbose (repeat to increase verbosity)\n");
    log("\n");
    exit(1);
}

int main(int argc, char **argv)
{
    bool coldboot = false;
    int por_image = 0;
    int image_count = 0;
    int align_bits = 0;
    bool align_first = false;
    Header headers[NUM_HEADERS];
    std::unique_ptr<Image> images[NUM_IMAGES];
    const char *outfile_name = NULL;

    for (int i = 1; i < argc; i++)
    {
	if (argv[i][0] == '-' && argv[i][1]) {
            for (int j = 1; argv[i][j]; j++)
                if (argv[i][j] == 'c') {
                    coldboot = true;
                } else if (argv[i][j] == 'p' && argv[i][j+1]) {
                    por_image = argv[i][++j] - '0';
                } else if (argv[i][j] == 'a' || argv[i][j] == 'A') {
                    align_first = argv[i][j] == 'A';
                    if (argv[i][j+1])
                        align_bits = atoi(&argv[i][j+1]);
                    else if(i+1 < argc)
                        align_bits = atoi(argv[++i]);
                    else
                        usage();
                    break;
                } else if (argv[i][j] == 'o') {
                    if (argv[i][j+1])
                        outfile_name = &argv[i][j+1];
                    else if(i+1 < argc)
                        outfile_name = argv[++i];
                    else
                        usage();
                    break;
                } else if (argv[i][j] == 'v') {
                    log_level++;
                } else
                    usage();
            continue;
        }

        if (image_count >= NUM_IMAGES)
            error("Too many images supplied\n");
        images[image_count++].reset(new Image(argv[i]));
    }

    if (!image_count)
        usage();

    if (coldboot && por_image != 0)
        error("Can't select power on reset boot image in cold boot mode\n");

    if (por_image >= image_count)
        error("Specified non-existing image for power on reset\n");

    // Place images
    uint32_t offs = NUM_HEADERS * HEADER_SIZE;
    if (align_first)
        align_offset(offs, align_bits);
    for (int i=0; i<image_count; i++) {
        images[i]->place(offs);
        offs += images[i]->size();
        align_offset(offs, align_bits);
        info("Place image %d at %06x .. %06x.\n", i, int(images[i]->offset()), int(offs));
    }

    // Populate headers
    for (int i=0; i<image_count; i++)
        headers[i + 1] = Header(*images[i]);
    headers[0] = headers[por_image + 1];
    for (int i=image_count; i < NUM_IMAGES; i++)
        headers[i + 1] = headers[0];
    if (coldboot)
        headers[0].set_coldboot_flag();

    std::ofstream ofs;
    std::ostream *osp;

    if (outfile_name != NULL) {
        ofs.open(outfile_name, std::ofstream::binary);
        if (!ofs.is_open())
            error("Failed to open output file.\n");
        osp = &ofs;
    } else {
        osp = &std::cout;
    }

    uint32_t file_offset = 0;
    for (int i=0; i<NUM_HEADERS; i++)
    {
        pad_to(*osp, file_offset, i * HEADER_SIZE);
        headers[i].write(*osp, file_offset);
    }
    for (int i=0; i<image_count; i++)
    {
        pad_to(*osp, file_offset, images[i]->offset());
        images[i]->write(*osp, file_offset);
    }

    info("Done.\n");
    return 0;
}
<commit_msg>icemulti: Use standard macros for exit status<commit_after>//
//  Copyright (C) 2015  Marcus Comstedt <marcus@mc.pp.se>
//
//  Permission to use, copy, modify, and/or distribute this software for any
//  purpose with or without fee is hereby granted, provided that the above
//  copyright notice and this permission notice appear in all copies.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <fstream>
#include <iostream>
#include <cstdint>
#include <memory>

#include <stdio.h>
#include <stdlib.h>

#define log(...) fprintf(stderr, __VA_ARGS__);
#define info(...) do { if (log_level > 0) fprintf(stderr, __VA_ARGS__); } while (0)
#define error(...) do { fprintf(stderr, "Error: " __VA_ARGS__); exit(EXIT_FAILURE); } while (0)

int log_level = 0;

static const int NUM_IMAGES = 4;
static const int NUM_HEADERS = NUM_IMAGES + 1;
static const int HEADER_SIZE = 32;

static void align_offset(uint32_t &offset, int bits)
{
    uint32_t mask = (1 << bits) - 1;
    if (offset & mask)
        offset = (offset | mask) + 1;
}

static void write_byte(std::ostream &ofs, uint32_t &file_offset, uint8_t byte)
{
    ofs << byte;
    file_offset++;
}

static void write_bytes(std::ostream &ofs, uint32_t &file_offset,
                        const uint8_t *buf, size_t n)
{
    if (n > 0) {
        ofs.write(reinterpret_cast<const char*>(buf), n);
        file_offset += n;
    }
}

static void write_file(std::ostream &ofs, uint32_t &file_offset,
                       std::istream &ifs)
{
    const size_t bufsize = 8192;
    uint8_t *buffer = new uint8_t[bufsize];

    while(!ifs.eof()) {
        ifs.read(reinterpret_cast<char *>(buffer), bufsize);
        if (ifs.bad())
            error("Read error on input image");
        write_bytes(ofs, file_offset, buffer, ifs.gcount());
    }

    delete[] buffer;
}

static void pad_to(std::ostream &ofs, uint32_t &file_offset, uint32_t target)
{
    if (target < file_offset)
        error("Trying to pad backwards!\n");
    while(file_offset < target)
        write_byte(ofs, file_offset, 0xff);
}

class Image {
    std::ifstream ifs;
    uint32_t offs;

public:
    Image(const char *filename) : ifs(filename, std::ifstream::binary) {}

    size_t size();
    void write(std::ostream &ofs, uint32_t &file_offset);
    void place(uint32_t o) { offs = o; }
    uint32_t offset() const { return offs; }
};

size_t Image::size()
{
    ifs.seekg (0, ifs.end);
    size_t length = ifs.tellg();
    ifs.seekg (0, ifs.beg);
    return length;
}

void Image::write(std::ostream &ofs, uint32_t &file_offset)
{
    write_file(ofs, file_offset, ifs);
}

class Header {
    uint32_t image_offs;
    bool coldboot_flag;
    bool empty;
public:
    Header() : empty(true) {}
    Header(const Image &i) :
        image_offs(i.offset()), coldboot_flag(false), empty(false) {}
    void set_coldboot_flag() { coldboot_flag = true; }
    void write(std::ostream &ofs, uint32_t &file_offset);
};

void Header::write(std::ostream &ofs, uint32_t &file_offset)
{
    if (empty)
        return;

    // Preamble
    write_byte(ofs, file_offset, 0x7e);
    write_byte(ofs, file_offset, 0xaa);
    write_byte(ofs, file_offset, 0x99);
    write_byte(ofs, file_offset, 0x7e);

    // Boot mode
    write_byte(ofs, file_offset, 0x92);
    write_byte(ofs, file_offset, 0x00);
    write_byte(ofs, file_offset, (coldboot_flag? 0x10: 0x00));

    // Boot address
    write_byte(ofs, file_offset, 0x44);
    write_byte(ofs, file_offset, 0x03);
    write_byte(ofs, file_offset, (image_offs >> 16) & 0xff);
    write_byte(ofs, file_offset, (image_offs >> 8) & 0xff);
    write_byte(ofs, file_offset, image_offs & 0xff);

    // Bank offset
    write_byte(ofs, file_offset, 0x82);
    write_byte(ofs, file_offset, 0x00);
    write_byte(ofs, file_offset, 0x00);

    // Reboot
    write_byte(ofs, file_offset, 0x01);
    write_byte(ofs, file_offset, 0x08);

    // Zero out any unused bytes
    while (file_offset & (HEADER_SIZE - 1))
        write_byte(ofs, file_offset, 0x00);
}

void usage()
{
    log("\n");
    log("Usage: icemulti [options] input-files\n");
    log("\n");
    log(" -c\n");
    log(" coldboot mode, power on reset image is selected by CBSEL0/CBSEL1\n");
    log("\n");
    log(" -p0, -p1, -p2, -p3\n");
    log(" select power on reset image when not using coldboot mode\n");
    log("\n");
    log(" -a<n>, -A<n>\n");
    log(" align images at 2^<n> bytes. -A also aligns image 0.\n");
    log("\n");
    log(" -o filename\n");
    log(" write output image to file instead of stdout\n");
    log("\n");
    log(" -v\n");
    log(" verbose (repeat to increase verbosity)\n");
    log("\n");
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
    bool coldboot = false;
    int por_image = 0;
    int image_count = 0;
    int align_bits = 0;
    bool align_first = false;
    Header headers[NUM_HEADERS];
    std::unique_ptr<Image> images[NUM_IMAGES];
    const char *outfile_name = NULL;

    for (int i = 1; i < argc; i++)
    {
	if (argv[i][0] == '-' && argv[i][1]) {
            for (int j = 1; argv[i][j]; j++)
                if (argv[i][j] == 'c') {
                    coldboot = true;
                } else if (argv[i][j] == 'p' && argv[i][j+1]) {
                    por_image = argv[i][++j] - '0';
                } else if (argv[i][j] == 'a' || argv[i][j] == 'A') {
                    align_first = argv[i][j] == 'A';
                    if (argv[i][j+1])
                        align_bits = atoi(&argv[i][j+1]);
                    else if(i+1 < argc)
                        align_bits = atoi(argv[++i]);
                    else
                        usage();
                    break;
                } else if (argv[i][j] == 'o') {
                    if (argv[i][j+1])
                        outfile_name = &argv[i][j+1];
                    else if(i+1 < argc)
                        outfile_name = argv[++i];
                    else
                        usage();
                    break;
                } else if (argv[i][j] == 'v') {
                    log_level++;
                } else
                    usage();
            continue;
        }

        if (image_count >= NUM_IMAGES)
            error("Too many images supplied\n");
        images[image_count++].reset(new Image(argv[i]));
    }

    if (!image_count)
        usage();

    if (coldboot && por_image != 0)
        error("Can't select power on reset boot image in cold boot mode\n");

    if (por_image >= image_count)
        error("Specified non-existing image for power on reset\n");

    // Place images
    uint32_t offs = NUM_HEADERS * HEADER_SIZE;
    if (align_first)
        align_offset(offs, align_bits);
    for (int i=0; i<image_count; i++) {
        images[i]->place(offs);
        offs += images[i]->size();
        align_offset(offs, align_bits);
        info("Place image %d at %06x .. %06x.\n", i, int(images[i]->offset()), int(offs));
    }

    // Populate headers
    for (int i=0; i<image_count; i++)
        headers[i + 1] = Header(*images[i]);
    headers[0] = headers[por_image + 1];
    for (int i=image_count; i < NUM_IMAGES; i++)
        headers[i + 1] = headers[0];
    if (coldboot)
        headers[0].set_coldboot_flag();

    std::ofstream ofs;
    std::ostream *osp;

    if (outfile_name != NULL) {
        ofs.open(outfile_name, std::ofstream::binary);
        if (!ofs.is_open())
            error("Failed to open output file.\n");
        osp = &ofs;
    } else {
        osp = &std::cout;
    }

    uint32_t file_offset = 0;
    for (int i=0; i<NUM_HEADERS; i++)
    {
        pad_to(*osp, file_offset, i * HEADER_SIZE);
        headers[i].write(*osp, file_offset);
    }
    for (int i=0; i<image_count; i++)
    {
        pad_to(*osp, file_offset, images[i]->offset());
        images[i]->write(*osp, file_offset);
    }

    info("Done.\n");
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "painter.h"
#include "render_context.h"
#include "render_target/render_target.h"
#include "material.h"
#include "material_parameter.h"

using namespace Halley;

void Painter::startRender()
{
	verticesPending = 0;
	bytesPending = 0;
	doStartRender();
}

void Painter::endRender()
{
	flush();
	doEndRender();
}

void Painter::flush()
{
	flushPending();
}

void Painter::drawQuads(std::shared_ptr<Material> material, size_t numVertices, void* vertexData)
{
	assert(numVertices > 0);
	assert(numVertices % 4 == 0);
	assert(vertexData != nullptr);

	if (material != materialPending) {
		if (materialPending != std::shared_ptr<Material>()) {
			flushPending();
		}
		materialPending = material;
	}

	size_t dataSize = numVertices * material->getVertexStride();
	size_t requiredSize = dataSize + bytesPending;
	if (vertexBuffer.size() < requiredSize) {
		vertexBuffer.resize(requiredSize * 2);
	}

	memcpy(vertexBuffer.data() + bytesPending, vertexData, dataSize);

	verticesPending += numVertices;
	bytesPending += dataSize;
}

void Painter::bind(RenderContext& context)
{
	// Set render target
	auto& rt = context.getRenderTarget();
	rt.bind();

	// Set viewport
	auto viewPort = context.getViewPort();
	setViewPort(viewPort, viewPort != rt.getViewPort());

	// Set camera
	auto& cam = context.getCamera();
	cam.setViewArea(Vector2f(viewPort.getSize()));
	cam.updateProjection();
	projection = cam.getProjection();
}

void Painter::flushPending()
{
	if (verticesPending > 0) {
		executeDrawQuads(*materialPending, verticesPending, vertexBuffer.data());
	}

	// Reset
	bytesPending = 0;
	verticesPending = 0;
	materialPending.reset();
}

void Painter::executeDrawQuads(Material& material, size_t numVertices, void* vertexData)
{
	// Bind projection
	material["u_mvp"] = projection;

	// Load vertices
	setVertices(material, numVertices, vertexData);

	// Go through each pass
	for (int i = 0; i < material.getNumPasses(); i++) {
		// Bind pass
		material.bind(i, *this);

		// Draw
		drawQuads(int(numVertices / 4));
	}
}
<commit_msg>Replaced memcpy() in one of the performance bottlenecks.<commit_after>#include "painter.h"
#include "render_context.h"
#include "render_target/render_target.h"
#include "material.h"
#include "material_parameter.h"

using namespace Halley;

void Painter::startRender()
{
	verticesPending = 0;
	bytesPending = 0;
	doStartRender();
}

void Painter::endRender()
{
	flush();
	doEndRender();
}

void Painter::flush()
{
	flushPending();
}

template <typename T>
static void doMemcpyAlign(void* dstBytes, const void* srcBytes, size_t bytes)
{
	T* dst = reinterpret_cast<T*>(dstBytes);
	const T* src = reinterpret_cast<const T*>(srcBytes);
	const T* srcEnd = src + (bytes / sizeof(T));
	for (; src != srcEnd; ++src, ++dst) {
		*dst = *src;
	}
}

inline void memcpyAlign(void* dstBytes, const void* srcBytes, size_t bytes)
{
	if (bytes % sizeof(size_t) == 0) {
		// Use size_t aligned if possible
		doMemcpyAlign<size_t>(dstBytes, srcBytes, bytes);
	} else {
		// Data is always int-aligned, since numVertices % 4 == 0
		doMemcpyAlign<int>(dstBytes, srcBytes, bytes);
	}
}

void Painter::drawQuads(std::shared_ptr<Material> material, size_t numVertices, void* vertexData)
{
	assert(numVertices > 0);
	assert(numVertices % 4 == 0);
	assert(vertexData != nullptr);

	if (material != materialPending) {
		if (materialPending != std::shared_ptr<Material>()) {
			flushPending();
		}
		materialPending = material;
	}

	size_t dataSize = numVertices * material->getVertexStride();
	size_t requiredSize = dataSize + bytesPending;
	if (vertexBuffer.size() < requiredSize) {
		vertexBuffer.resize(requiredSize * 2);
	}

	memcpyAlign(vertexBuffer.data() + bytesPending, vertexData, dataSize);

	verticesPending += numVertices;
	bytesPending += dataSize;
}

void Painter::bind(RenderContext& context)
{
	// Set render target
	auto& rt = context.getRenderTarget();
	rt.bind();

	// Set viewport
	auto viewPort = context.getViewPort();
	setViewPort(viewPort, viewPort != rt.getViewPort());

	// Set camera
	auto& cam = context.getCamera();
	cam.setViewArea(Vector2f(viewPort.getSize()));
	cam.updateProjection();
	projection = cam.getProjection();
}

void Painter::flushPending()
{
	if (verticesPending > 0) {
		executeDrawQuads(*materialPending, verticesPending, vertexBuffer.data());
	}

	// Reset
	bytesPending = 0;
	verticesPending = 0;
	materialPending.reset();
}

void Painter::executeDrawQuads(Material& material, size_t numVertices, void* vertexData)
{
	// Bind projection
	material["u_mvp"] = projection;

	// Load vertices
	setVertices(material, numVertices, vertexData);

	// Go through each pass
	for (int i = 0; i < material.getNumPasses(); i++) {
		// Bind pass
		material.bind(i, *this);

		// Draw
		drawQuads(int(numVertices / 4));
	}
}
<|endoftext|>


<commit_before>// symbiosis: A hacky and lightweight compiler framework
//
#include "symbiosis.hpp"
#include <sys/stat.h>

#include <iostream>

#include <vector>

using namespace std;

namespace symbiosis {

  class exception : public std::exception {
    const char *what_;
  public:
    exception(const char *w) : what_(w) { }
    virtual ~exception() throw() { }
    virtual const char* what() const throw() { return what_; }
  };

  char *command_file = 0;;

  #define M10(v, b) #v #b
  #define M3(a,b) M10(a+1000, v),M10(a+2000, v), M10(a+3000, v),M10(a+4000, v)
  #define M2(a,b) M3(a+100, v) , M3(a+200, v) , M3(a+300, v) , M3(a+400, v)
  #define M1(a,b) M2(a+10, v) , M2(a+20, v) , M2(a+30, v) , M2(a+40, v)
  #define M(v) M1(1, v), M1(2, v), M1(3, v), M1(4, v), M1(5, v)

  uchar *virtual_code_start = 0;
  uchar *virtual_code_end = 0;

  uchar *out_code_start = 0;
  uchar *out_code_end = 0;
  uchar *out_c = 0;
  uchar *out_c0 = 0;

  uchar *virtual_strings_start = 0;
  uchar *virtual_strings_end = 0;
  uchar *out_strings_start = 0;
  uchar *out_strings_end = 0;
  uchar *out_s = 0;

  #define STRINGS_START "STRINGS_START"
  #define STRINGS_END "STRINGS_END"

  unsigned int _i32 = 0;

  const char* id::i32() {
    if (virtual_adr) { _i32 = (size_t)virtual_adr;
         //printf("virtual_adr: %x\n", _i32);
        return (const char*)&_i32; }
    if (type == T_UINT) return (const char*)&d.ui;
    return (const char*)&d.i;
  }
  const char* id::i64() {
    if (type == T_ULONG) return (const char*)&d.ul;
    return (const char*)&d.l;
  }
  vector<const char*> type_str = { "0:???", "int", "uint", "long", "ulong",
      "charp", "float", "double"};

  void id::describe() {
    if (type > type_str.size() - 1) {
      cout << "<id:" << type << ">";
    } else {
      cout << type_str[type];
    }
    cout << endl;
  }
  id  id::operator()(id i) { add_parameter(i); return i; }

  id_new::id_new(const char *p) : id(p) {
    virtual_adr = virtual_strings_start + (out_s - out_strings_start);
    virtual_size = strlen(p);
    if (out_s + virtual_size + 1 > out_strings_end)
        throw exception("Strings: Out of memory");
    memcpy(out_s, p, virtual_size + 1);
    //cout << "new string" << endl;
    out_s += virtual_size + 1;
  };

  const char *reserved_strings[] = { STRINGS_START,
  M(ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
  STRINGS_END };

#define FIND(v) { \
  pos = 0; \
  bool found = false; \
  for (size_t i = 0; !found && i < (input_size - v##_s); i++) { \
    for (int j = 0; j < v##_s; j++) { \
      if (buf[i + j] != v[j]) break; \
      if (j == v##_s - 1) { \
        pos = i; \
        found = true; \
      } \
    } \
  } }

  uchar buf[200 * 1024];
  FILE* input = 0;
  size_t input_size = 0;

  void find_space(uchar* start, size_t start_s,
      uchar* end, size_t end_s, uchar **out_start, uchar **out_end) {
    if (!input) {
      input = fopen(command_file, "r");
      if (!input) { fprintf(stderr, "Failed\n"); }
      input_size = fread(buf, 1, sizeof(buf), input);
    }
    size_t pos = 0, s = 0, e = 0;
    FIND(start); s = pos;
    FIND(end); e = pos;
    *out_start = &buf[s];
    *out_end = &buf[e];
    //printf("s: %zd, e:%zd, l:%zd\n", s, e, e - s);
  }

  void write() {
    FILE *out = fopen("a.out", "w");
    fwrite(buf, 1, input_size, out);
    fclose(out);
    printf("Writing a.out\n");
    chmod("a.out", 0777);
  }

  void dump(uchar* start, size_t s) {
    for (size_t i = 0; i < s; i++) {
      printf("%02x ", start[i]);
    }
    //printf("\n");
  }

  int parameter_count = 0;
  const char *register_parameters_intel_32[] = {
      "\xbf", /*edi*/ "\xbe", /*esi*/ "\xba" /*edx*/ };
  const char *register_parameters_arm_32[] = {
      "\xe5\x9f\x00", /*r0*/ "\xe5\x9f\x10", /*r1*/ "\xe5\x9f\x20" /*r2*/ };
  const char *register_parameters_intel_64[] = {
      "\x48\xbf" /*rdi*/, "\x48\xbe" ,/*rsi*/ "\x48\xba" /*rdx*/ };

  constexpr int parameters_max = 3;

  void emit(const char* _s, size_t _l = 0) {
    size_t l = _l > 0 ? _l : strlen(_s);
    uchar *s = (uchar *)_s; uchar *e = s + l;
    if (out_c + l > out_code_end) throw exception("Code: Out of memory");
    for (uchar * b  = s; b < e; b++, out_c++) {
      *out_c = *b;
    }
    dump(s, l);
  }

  bool intel() { return true; }
  bool arm() { return false; }

  id add_parameter(id p) {
    if (parameter_count >= parameters_max) {
      fprintf(stderr, "Too many parameters!\n");
      return p;
    }
    //cout << "parameter_count: " << parameter_count << " "; p.describe();
    if (p.is_integer() || p.is_charp()) {
      //cout << "is_integer" << endl;
      if (intel()) {
        //cout << "intel" << endl;
        if (p.is_32()) {
          //cout << "is_32" << endl;
          emit(register_parameters_intel_32[parameter_count]);
          emit(p.i32(), 4);
        } else if (p.is_64()) {
          //cout << "is_64" << endl;
          emit(register_parameters_intel_64[parameter_count]);
          emit(p.i64(), 8);
        }
      } else if (arm()) {
        emit(register_parameters_intel_32[parameter_count]);
      }
    }
    ++parameter_count;
    return p;
  }
  int __offset = 0;
  const char* call_offset(uchar *out_current_code_pos, void *__virt_f) {
    auto virt_f = (uchar*)__virt_f;
    ssize_t out_start_distance = out_current_code_pos - out_code_start;
    ssize_t virt_dist_from_code_start = virt_f - virtual_code_start;
    __offset = virt_dist_from_code_start - out_start_distance - 5;
    cout << "__virt_f: " << __virt_f << endl;
    //cout << "call_offset: " << __offset << " virt: " << virt_dist_from_code_start << " out: " << out_start_distance << endl;
    return (const char*)&__offset;
  }

  void jmp(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe9"); // JMP
    emit(call_offset(out_current_code_pos, f), 4);
  }

  void __call(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe8"); // call
    emit(call_offset(out_current_code_pos, f), 4);
    parameter_count = 0;
  }

  void __vararg_call(void *f) {
    emit("\x30\xc0"); // xor    al,al
    call(f);
  }

  size_t __p = 0;

  void f(const char *s, int i) {
    __p += (size_t)s + i;
  }

  bool am_i_pic() {
    printf("foo\n");
    uchar *p = (uchar *)am_i_pic;
    int i = 0;
    uchar c = 0;
    do {
      c = p[i++];
    } while (i < 10 && c != 0x48 && c != 0xbf);
    return c == 0x48;
  }

  void init(char *c, uchar *start, size_t ss, uchar *end, size_t es) {
    printf("am_i_pic: %d\n", am_i_pic());
    command_file = c;
    virtual_code_start = start;
    virtual_code_end = end;
    find_space(start, ss, end, es, &out_code_start,
        &out_code_end);
    //printf("code: %zu\n", out_code_end - out_code_start);
    virtual_strings_start = (uchar *)STRINGS_START;
    virtual_strings_end = (uchar *)STRINGS_END;
    out_c = out_code_start;
    find_space(virtual_strings_start, strlen(STRINGS_START),
        virtual_strings_end, strlen(STRINGS_END),
            &out_strings_start, &out_strings_end);
    //printf("strings: %zu\n", out_strings_end - out_strings_start);
    out_s = out_strings_start;
  }

  void finish() {
    jmp(virtual_code_end);
    write();
  }

}
<commit_msg>Declare pic flag.<commit_after>// symbiosis: A hacky and lightweight compiler framework
//
#include "symbiosis.hpp"
#include <sys/stat.h>

#include <iostream>

#include <vector>

using namespace std;

namespace symbiosis {

  bool am_i_pic = false;

  class exception : public std::exception {
    const char *what_;
  public:
    exception(const char *w) : what_(w) { }
    virtual ~exception() throw() { }
    virtual const char* what() const throw() { return what_; }
  };

  char *command_file = 0;;

  #define M10(v, b) #v #b
  #define M3(a,b) M10(a+1000, v),M10(a+2000, v), M10(a+3000, v),M10(a+4000, v)
  #define M2(a,b) M3(a+100, v) , M3(a+200, v) , M3(a+300, v) , M3(a+400, v)
  #define M1(a,b) M2(a+10, v) , M2(a+20, v) , M2(a+30, v) , M2(a+40, v)
  #define M(v) M1(1, v), M1(2, v), M1(3, v), M1(4, v), M1(5, v)

  uchar *virtual_code_start = 0;
  uchar *virtual_code_end = 0;

  uchar *out_code_start = 0;
  uchar *out_code_end = 0;
  uchar *out_c = 0;
  uchar *out_c0 = 0;

  uchar *virtual_strings_start = 0;
  uchar *virtual_strings_end = 0;
  uchar *out_strings_start = 0;
  uchar *out_strings_end = 0;
  uchar *out_s = 0;

  #define STRINGS_START "STRINGS_START"
  #define STRINGS_END "STRINGS_END"

  unsigned int _i32 = 0;

  const char* id::i32() {
    if (virtual_adr) { _i32 = (size_t)virtual_adr;
         //printf("virtual_adr: %x\n", _i32);
        return (const char*)&_i32; }
    if (type == T_UINT) return (const char*)&d.ui;
    return (const char*)&d.i;
  }
  const char* id::i64() {
    if (type == T_ULONG) return (const char*)&d.ul;
    return (const char*)&d.l;
  }
  vector<const char*> type_str = { "0:???", "int", "uint", "long", "ulong",
      "charp", "float", "double"};

  void id::describe() {
    if (type > type_str.size() - 1) {
      cout << "<id:" << type << ">";
    } else {
      cout << type_str[type];
    }
    cout << endl;
  }
  id  id::operator()(id i) { add_parameter(i); return i; }

  id_new::id_new(const char *p) : id(p) {
    virtual_adr = virtual_strings_start + (out_s - out_strings_start);
    virtual_size = strlen(p);
    if (out_s + virtual_size + 1 > out_strings_end)
        throw exception("Strings: Out of memory");
    memcpy(out_s, p, virtual_size + 1);
    //cout << "new string" << endl;
    out_s += virtual_size + 1;
  };

  const char *reserved_strings[] = { STRINGS_START,
  M(ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
  STRINGS_END };

#define FIND(v) { \
  pos = 0; \
  bool found = false; \
  for (size_t i = 0; !found && i < (input_size - v##_s); i++) { \
    for (int j = 0; j < v##_s; j++) { \
      if (buf[i + j] != v[j]) break; \
      if (j == v##_s - 1) { \
        pos = i; \
        found = true; \
      } \
    } \
  } }

  uchar buf[200 * 1024];
  FILE* input = 0;
  size_t input_size = 0;

  void find_space(uchar* start, size_t start_s,
      uchar* end, size_t end_s, uchar **out_start, uchar **out_end) {
    if (!input) {
      input = fopen(command_file, "r");
      if (!input) { fprintf(stderr, "Failed\n"); }
      input_size = fread(buf, 1, sizeof(buf), input);
    }
    size_t pos = 0, s = 0, e = 0;
    FIND(start); s = pos;
    FIND(end); e = pos;
    *out_start = &buf[s];
    *out_end = &buf[e];
    //printf("s: %zd, e:%zd, l:%zd\n", s, e, e - s);
  }

  void write() {
    FILE *out = fopen("a.out", "w");
    fwrite(buf, 1, input_size, out);
    fclose(out);
    printf("Writing a.out\n");
    chmod("a.out", 0777);
  }

  void dump(uchar* start, size_t s) {
    for (size_t i = 0; i < s; i++) {
      printf("%02x ", start[i]);
    }
    //printf("\n");
  }

  int parameter_count = 0;
  const char *register_parameters_intel_32[] = {
      "\xbf", /*edi*/ "\xbe", /*esi*/ "\xba" /*edx*/ };
  const char *register_parameters_arm_32[] = {
      "\xe5\x9f\x00", /*r0*/ "\xe5\x9f\x10", /*r1*/ "\xe5\x9f\x20" /*r2*/ };
  const char *register_parameters_intel_64[] = {
      "\x48\xbf" /*rdi*/, "\x48\xbe" ,/*rsi*/ "\x48\xba" /*rdx*/ };

  constexpr int parameters_max = 3;

  void emit(const char* _s, size_t _l = 0) {
    size_t l = _l > 0 ? _l : strlen(_s);
    uchar *s = (uchar *)_s; uchar *e = s + l;
    if (out_c + l > out_code_end) throw exception("Code: Out of memory");
    for (uchar * b  = s; b < e; b++, out_c++) {
      *out_c = *b;
    }
    dump(s, l);
  }

  bool intel() { return true; }
  bool arm() { return false; }

  id add_parameter(id p) {
    if (parameter_count >= parameters_max) {
      fprintf(stderr, "Too many parameters!\n");
      return p;
    }
    //cout << "parameter_count: " << parameter_count << " "; p.describe();
    if (p.is_integer() || p.is_charp()) {
      //cout << "is_integer" << endl;
      if (intel()) {
        //cout << "intel" << endl;
        if (p.is_32()) {
          //cout << "is_32" << endl;
          emit(register_parameters_intel_32[parameter_count]);
          emit(p.i32(), 4);
        } else if (p.is_64()) {
          //cout << "is_64" << endl;
          emit(register_parameters_intel_64[parameter_count]);
          emit(p.i64(), 8);
        }
      } else if (arm()) {
        emit(register_parameters_intel_32[parameter_count]);
      }
    }
    ++parameter_count;
    return p;
  }

  int __offset = 0;
  const char* call_offset(uchar *out_current_code_pos, void *__virt_f) {
    auto virt_f = (uchar*)__virt_f;
    ssize_t out_start_distance = out_current_code_pos - out_code_start;
    ssize_t virt_dist_from_code_start = virt_f - virtual_code_start;
    __offset = virt_dist_from_code_start - out_start_distance - 5;
    cout << "__virt_f: " << __virt_f << endl;
    //cout << "call_offset: " << __offset << " virt: " << virt_dist_from_code_start << " out: " << out_start_distance << endl;
    return (const char*)&__offset;
  }

  void jmp(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe9"); // JMP
    emit(call_offset(out_current_code_pos, f), 4);
  }

  void __call(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe8"); // call
    emit(call_offset(out_current_code_pos, f), 4);
    parameter_count = 0;
  }

  void __vararg_call(void *f) {
    emit("\x30\xc0"); // xor    al,al
    call(f);
  }

  size_t __p = 0;

  void f(const char *s, int i) {
    __p += (size_t)s + i;
  }

  bool __am_i_pic() {
    printf("foo\n");
    uchar *p = (uchar *)__am_i_pic;
    int i = 0;
    uchar c = 0;
    do {
      c = p[i++];
    } while (i < 10 && c != 0x48 && c != 0xbf);
    return c == 0x48;
  }

  void init(char *c, uchar *start, size_t ss, uchar *end, size_t es) {
    am_i_pic = __am_i_pic();
    printf("am_i_pic: %d\n", am_i_pic);
    command_file = c;
    virtual_code_start = start;
    virtual_code_end = end;
    find_space(start, ss, end, es, &out_code_start,
        &out_code_end);
    //printf("code: %zu\n", out_code_end - out_code_start);
    virtual_strings_start = (uchar *)STRINGS_START;
    virtual_strings_end = (uchar *)STRINGS_END;
    out_c = out_code_start;
    find_space(virtual_strings_start, strlen(STRINGS_START),
        virtual_strings_end, strlen(STRINGS_END),
            &out_strings_start, &out_strings_end);
    //printf("strings: %zu\n", out_strings_end - out_strings_start);
    out_s = out_strings_start;
  }

  void finish() {
    jmp(virtual_code_end);
    write();
  }

}
<|endoftext|>