<commit_before>///! fff-lang
///!
///! semantic/traits

use std::fmt;

use codemap::Span;
use codemap::SymbolID;
use codemap::SourceCode;
use codemap::SymbolCollection;

use message::Message;
use message::MessageCollection;

use super::Formatter;
use super::ScopeType;
use super::Definition;
use super::SharedDefScope;
use super::DefinitionCollection;

// public because it used in public API
// allowed because this name is designed to used not directly, only like `format!("{}", node.display())`
#[allow(dead_code)]
pub struct Wrapper<'a, T: 'a>(&'a T);
impl<'a, T: ISemanticAnalyze> fmt::Display for Wrapper<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\n{}", self.0.format(Formatter::empty()))
    }
}

/// Parameter for `ISyntaxAnalyze::from_syntax`
///
/// stores ref to symbols, to format namable scope like fn and type,
/// stores ref to source code, to format unnamable scope with span like for and if
pub struct FromSession<'a, 'b> {
    scope: SharedDefScope,
    source: &'a SourceCode,
    symbols: &'b SymbolCollection,
}
impl<'a, 'b> FromSession<'a, 'b> {

    pub fn new(scope: SharedDefScope, source: &'a SourceCode, symbols: &'b SymbolCollection) -> Self {
        FromSession{ scope, source, symbols }
    }
    pub fn clone_scope(&self) -> Self {
        FromSession{ scope: self.scope.clone(), source: self.source, symbols: self.symbols }
    }

    /// Create sub scope with id for name,
    /// May panic on invalid ID
    pub fn sub_with_symbol(&self, id: SymbolID, scope_type: ScopeType) -> Self {
        FromSession{ scope: self.scope.sub(self.symbols.get(id).unwrap(), scope_type), source: self.source, symbols: self.symbols }
    }
    /// Create sub scope with not unique name like 'if', 'for', etc.
    /// which need adding span information to make unique
    pub fn sub_with_span(&self, name: &str, span: Span, scope_type: ScopeType) -> Self {
        FromSession{ scope: self.scope.sub(format!("<{}{}>", name, span.format(Some(self.source))), scope_type), source: self.source, symbols: self.symbols }
    }

    pub fn into_scope(self) -> SharedDefScope { self.scope }
}

/// Parameter for `ISemanticAnalyze::collect_definitions`
pub struct CollectSession<'a, 'b> {
    node_path: Vec<usize>,
    defs: &'a mut DefinitionCollection,
    messages: &'b mut MessageCollection,
}
impl<'a, 'b> CollectSession<'a, 'b> {

    pub fn new(defs: &'a mut DefinitionCollection, messages: &'b mut MessageCollection) -> Self {
        CollectSession{ defs, messages, node_path: Vec::new() }
    }

    pub fn push_path(&mut self, child_id: usize) {
        self.node_path.push(child_id);
    }
    pub fn pop_path(&mut self) {
        let _ = self.node_path.pop();
    }

    pub fn push_def(&mut self, name: SymbolID, name_span: Span, mut scope: SharedDefScope) {
        match self.defs.push(Definition::new(name, self.node_path.clone())) {
            Some(defid) => scope.push_definition(defid),
            None => self.messages.push(Message::new_by_str("name already defined", vec![(name_span, "")])),
        }
    }
    #[allow(dead_code)] // TODO: temp remove
    pub fn push_message(&mut self, message: Message) {
        self.messages.push(message);
    }
}

pub trait ISemanticAnalyze {

    // Display, which is actually Debug but I don't like `fn debug() -> String`, should not be implemented
    fn display<'a>(&'a self) -> Wrapper<'a, Self> where Self: Sized { Wrapper(self) }
    // format, should be implemented
    fn format(&self, f: Formatter) -> String;

    // phase 1: direct map from syntax node
    type SyntaxItem;
    fn from_syntax(item: Self::SyntaxItem, sess: FromSession) -> Self;

    // TODO: an empty implement for compatibility temporarily, remove it in future
    // currently, only nodes with `this_scope` can add definition, which contains child node id in the node's child node list
    fn collect_definitions(&self, sess: &mut CollectSession) { let _ = sess; }
}
<commit_msg>[semantic] try add conversion session<commit_after>///! fff-lang
///!
///! semantic/traits

use std::fmt;
use std::cell::RefCell;

use codemap::Span;
use codemap::SymbolID;
use codemap::SourceCode;
use codemap::SymbolCollection;

use message::Message;
use message::MessageCollection;

use super::Formatter;
use super::ScopeType;
use super::Definition;
use super::SharedDefScope;
use super::DefinitionCollection;

// public because it used in public API
// allowed because this name is designed to used not directly, only like `format!("{}", node.display())`
#[allow(dead_code)]
pub struct Wrapper<'a, T: 'a>(&'a T);
impl<'a, T: ISemanticAnalyze> fmt::Display for Wrapper<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\n{}", self.0.format(Formatter::empty()))
    }
}

/// Parameter for `ISyntaxAnalyze::from_syntax`
///
/// stores ref to symbols, to format namable scope like fn and type,
/// stores ref to source code, to format unnamable scope with span like for and if
pub struct FromSession<'a, 'b> {
    scope: SharedDefScope,
    source: &'a SourceCode,
    symbols: &'b SymbolCollection,
}
impl<'a, 'b> FromSession<'a, 'b> {

    pub fn new(scope: SharedDefScope, source: &'a SourceCode, symbols: &'b SymbolCollection) -> Self {
        FromSession{ scope, source, symbols }
    }
    pub fn clone_scope(&self) -> Self {
        FromSession{ scope: self.scope.clone(), source: self.source, symbols: self.symbols }
    }

    /// Create sub scope with id for name,
    /// May panic on invalid ID
    pub fn sub_with_symbol(&self, id: SymbolID, scope_type: ScopeType) -> Self {
        FromSession{ scope: self.scope.sub(self.symbols.get(id).unwrap(), scope_type), source: self.source, symbols: self.symbols }
    }
    /// Create sub scope with not unique name like 'if', 'for', etc.
    /// which need adding span information to make unique
    pub fn sub_with_span(&self, name: &str, span: Span, scope_type: ScopeType) -> Self {
        FromSession{ scope: self.scope.sub(format!("<{}{}>", name, span.format(Some(self.source))), scope_type), source: self.source, symbols: self.symbols }
    }

    pub fn into_scope(self) -> SharedDefScope { self.scope }
}

#[allow(dead_code)]
pub struct ConvertSession<'a, 'b> {
    scope: SharedDefScope,
    source: &'a SourceCode,
    symbols: &'b SymbolCollection,
    global_defs: RefCell<DefinitionCollection>,
    messages: RefCell<MessageCollection>,
}
impl<'a, 'b> ConvertSession<'a, 'b> {

    pub fn new(scope: SharedDefScope, source: &'a SourceCode, symbols: &'b SymbolCollection, global_defs: DefinitionCollection, messages: MessageCollection) -> Self {
        ConvertSession{ scope, source, symbols, global_defs: RefCell::new(global_defs), messages: RefCell::new(messages) }
    }
}

/// Parameter for `ISemanticAnalyze::collect_definitions`
pub struct CollectSession<'a, 'b> {
    node_path: Vec<usize>,
    defs: &'a mut DefinitionCollection,
    messages: &'b mut MessageCollection,
}
impl<'a, 'b> CollectSession<'a, 'b> {

    pub fn new(defs: &'a mut DefinitionCollection, messages: &'b mut MessageCollection) -> Self {
        CollectSession{ defs, messages, node_path: Vec::new() }
    }

    pub fn push_path(&mut self, child_id: usize) {
        self.node_path.push(child_id);
    }
    pub fn pop_path(&mut self) {
        let _ = self.node_path.pop();
    }

    pub fn push_def(&mut self, name: SymbolID, name_span: Span, mut scope: SharedDefScope) {
        match self.defs.push(Definition::new(name, self.node_path.clone())) {
            Some(defid) => scope.push_definition(defid),
            None => self.messages.push(Message::new_by_str("name already defined", vec![(name_span, "")])),
        }
    }
    #[allow(dead_code)] // TODO: temp remove
    pub fn push_message(&mut self, message: Message) {
        self.messages.push(message);
    }
}

pub trait ISemanticAnalyze {

    // Display, which is actually Debug but I don't like `fn debug() -> String`, should not be implemented
    fn display<'a>(&'a self) -> Wrapper<'a, Self> where Self: Sized { Wrapper(self) }
    // format, should be implemented
    fn format(&self, f: Formatter) -> String;

    // phase 1: convert syntax node and collect definitions
    type SyntaxItem;
    // fn convert_collect(item: Self::SyntaxItem, sess: ConvertSession) -> Self;

    fn from_syntax(item: Self::SyntaxItem, sess: FromSession) -> Self;

    // TODO: an empty implement for compatibility temporarily, remove it in future
    // currently, only nodes with `this_scope` can add definition, which contains child node id in the node's child node list
    fn collect_definitions(&self, sess: &mut CollectSession) { let _ = sess; }
}

#[cfg(test)] #[test]
fn p1_usage() {

}<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(unsafe_code)]

extern crate gfx;
extern crate ipc_channel;
extern crate metrics;
extern crate msg;
extern crate net_traits;
extern crate profile_traits;
extern crate script_traits;
extern crate servo_url;
extern crate webrender_api;

// This module contains traits in layout used generically
//   in the rest of Servo.
// The traits are here instead of in layout so
//   that these modules won't have to depend on layout.

use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use metrics::PaintTimeMetrics;
use msg::constellation_msg::PipelineId;
use msg::constellation_msg::TopLevelBrowsingContextId;
use net_traits::image_cache::ImageCache;
use profile_traits::{mem, time};
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
use script_traits::LayoutMsg as ConstellationMsg;
use servo_url::ServoUrl;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};

// A static method creating a layout thread
// Here to remove the compositor -> layout dependency
pub trait LayoutThreadFactory {
    type Message;
    fn create(id: PipelineId,
              top_level_browsing_context_id: TopLevelBrowsingContextId,
              url: ServoUrl,
              is_iframe: bool,
              chan: (Sender<Self::Message>, Receiver<Self::Message>),
              pipeline_port: IpcReceiver<LayoutControlMsg>,
              constellation_chan: IpcSender<ConstellationMsg>,
              script_chan: IpcSender<ConstellationControlMsg>,
              image_cache: Arc<ImageCache>,
              font_cache_thread: FontCacheThread,
              time_profiler_chan: time::ProfilerChan,
              mem_profiler_chan: mem::ProfilerChan,
              content_process_shutdown_chan: Option<IpcSender<()>>,
              webrender_api_sender: webrender_api::RenderApiSender,
              webrender_document: webrender_api::DocumentId,
              layout_threads: usize,
              paint_time_metrics: PaintTimeMetrics);
}
<commit_msg>Auto merge of #21614 - pyfisch:layout_traits-fmt, r=nox<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(unsafe_code)]

extern crate gfx;
extern crate ipc_channel;
extern crate metrics;
extern crate msg;
extern crate net_traits;
extern crate profile_traits;
extern crate script_traits;
extern crate servo_url;
extern crate webrender_api;

// This module contains traits in layout used generically
//   in the rest of Servo.
// The traits are here instead of in layout so
//   that these modules won't have to depend on layout.

use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use metrics::PaintTimeMetrics;
use msg::constellation_msg::PipelineId;
use msg::constellation_msg::TopLevelBrowsingContextId;
use net_traits::image_cache::ImageCache;
use profile_traits::{mem, time};
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
use script_traits::LayoutMsg as ConstellationMsg;
use servo_url::ServoUrl;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};

// A static method creating a layout thread
// Here to remove the compositor -> layout dependency
pub trait LayoutThreadFactory {
    type Message;
    fn create(
        id: PipelineId,
        top_level_browsing_context_id: TopLevelBrowsingContextId,
        url: ServoUrl,
        is_iframe: bool,
        chan: (Sender<Self::Message>, Receiver<Self::Message>),
        pipeline_port: IpcReceiver<LayoutControlMsg>,
        constellation_chan: IpcSender<ConstellationMsg>,
        script_chan: IpcSender<ConstellationControlMsg>,
        image_cache: Arc<ImageCache>,
        font_cache_thread: FontCacheThread,
        time_profiler_chan: time::ProfilerChan,
        mem_profiler_chan: mem::ProfilerChan,
        content_process_shutdown_chan: Option<IpcSender<()>>,
        webrender_api_sender: webrender_api::RenderApiSender,
        webrender_document: webrender_api::DocumentId,
        layout_threads: usize,
        paint_time_metrics: PaintTimeMetrics,
    );
}
<|endoftext|>


<commit_before>// This is a regression test that the metadata for the
// name_pool::methods impl in the other crate is reachable from this
// crate.

// xfail-fast
// aux-build:crate-method-reexport-grrrrrrr2.rs

use crate_method_reexport_grrrrrrr2;

fn main() {
    import crate_method_reexport_grrrrrrr2::rust::add;
    import crate_method_reexport_grrrrrrr2::rust::cx;
    let x = @();
    x.cx();
    let y = ();
    y.add(~"hi");
}
<commit_msg>xfail crate-method-reexport-grrrrrrr.rs, which has been burning the build for days<commit_after>// This is a regression test that the metadata for the
// name_pool::methods impl in the other crate is reachable from this
// crate.

// xfail-test
// xfail-fast
// aux-build:crate-method-reexport-grrrrrrr2.rs

use crate_method_reexport_grrrrrrr2;

fn main() {
    import crate_method_reexport_grrrrrrr2::rust::add;
    import crate_method_reexport_grrrrrrr2::rust::cx;
    let x = @();
    x.cx();
    let y = ();
    y.add(~"hi");
}
<|endoftext|>


<commit_before>s_no_extra_traits! {
    #[allow(missing_debug_implementations)]
    #[repr(align(16))]
    pub struct max_align_t {
        priv_: [f32; 8]
    }
}
<commit_msg>Add ucontext_t for aarch64-unknown-linux-musl<commit_after>s_no_extra_traits! {
    #[allow(missing_debug_implementations)]
    #[repr(align(16))]
    pub struct max_align_t {
        priv_: [f32; 8]
    }
}

s!{
    pub struct ucontext_t {
        pub uc_flags: ::c_ulong,
        pub uc_link: *mut ucontext_t,
        pub uc_stack: ::stack_t,
        pub uc_sigmask: ::sigset_t,
        pub uc_mcontext: mcontext_t,
    }

    #[repr(align(16))]
    pub struct mcontext_t {
        // What we want here is a single [u64; 36 + 512], but splitting things
        // up allows Debug to be auto-derived.
        __regs1: [[u64; 18]; 2], // 36
        __regs2: [[u64; 32]; 16], // 512
    }
}
<|endoftext|>


<commit_before>/* diosix hypervisor main entry code
 *
 * (c) Chris Williams, 2019-2020.
 *
 * See LICENSE for usage and copying.
 */

/* let the compiler know we're on our own here in bare-metal world */
#![no_std]
#![no_main]
#![feature(asm)]

#![allow(dead_code)]
#![allow(unused_unsafe)]
#![allow(improper_ctypes)]
#![feature(type_ascription)]

/* provide a framework for unit testing */
#![feature(custom_test_frameworks)]
#![test_runner(crate::run_tests)]
#![reexport_test_harness_main = "hvtests"] /* entry point for tests */

/* plug our custom heap allocator into the Rust language: Box, etc */
#![feature(alloc_error_handler)]
#![feature(box_syntax)]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;

/* needed to convert raw dtb pointer into a slice */
use core::slice;

/* needed for fast lookup tables of stuff */
extern crate hashbrown;

/* needed for elf parsing */
extern crate xmas_elf;

/* needed for device tree parsing and manipulation */
extern crate devicetree;

/* needed for parsing diosix manifest file-system (DMFS) images bundled with the hypervisor */
extern crate dmfs;

/* pass the feature qemudebug to be able to write direct to the emulator's stdout
via the macro qemuprint::println!() */
#[cfg(feature = "qemudebug")]
extern crate qemuprint;

/* needed for lazyily-allocated static variables, and atomic ops */
#[macro_use]
extern crate lazy_static;
extern crate spin;
use spin::Mutex;

/* this will bring in all the hardware-specific code */
extern crate platform;

/* and now for all our non-hw specific code */
#[macro_use]
mod debug;      /* get us some kind of debug output, typically to a serial port */
mod hardware;   /* parse device trees into hardware objects */
#[macro_use]
mod heap;       /* per-CPU private heap management */
mod panic;      /* implement panic() handlers */
mod irq;        /* handle hw interrupts and sw exceptions, collectively known as IRQs */
#[macro_use]
mod physmem;    /* manage host physical memory */
mod virtmem;    /* manage capsule virtual memory */
mod pcore;      /* manage CPU cores */
mod vcore;      /* virtual CPU core management... */
mod scheduler;  /* ...and scheduling */
mod capsule;    /* manage capsules */
mod loader;     /* parse and load supervisor binaries */
mod message;    /* send messages between physical cores */
mod service;    /* allow capsules to register services */
mod manifest;   /* manage capsules loaded with the hypervisor */

use pcore::{PhysicalCoreID, BOOT_PCORE_ID};

/* list of error codes */
mod error;
use error::Cause;

/* bring in the built-in dmfs image */
use core::intrinsics::transmute;
extern "C"
{
    static _binary_dmfs_img_start: u8;
    static _binary_dmfs_img_size: u8;
}

/* tell Rust to use our HVallocator to allocate and free heap memory.
although we'll keep track of physical memory, we'll let Rust perform essential
tasks, such as dropping objects when it's no longer needed, borrow checking, etc */
#[global_allocator]
static HV_HEAP: heap::HVallocator = heap::HVallocator;

/* set to true to allow physical CPU cores to start running supervisor code */
lazy_static!
{
    static ref INIT_DONE: Mutex<bool> = Mutex::new(false);
}

/* a physical CPU core obtaining this lock when it is false must walk the DMFS, create
capsules required to run at boot time, and set the flag to true. any other core
obtaining it as true must release the lock and move on */
lazy_static!
{
    static ref MANIFEST_UNPACKED: Mutex<bool> = Mutex::new(false);
}

/* set to true if individual cores can sound off their presence and capabilities */
lazy_static!
{
    static ref ROLL_CALL: Mutex<bool> = Mutex::new(false);
}

/* pointer sizes: do not assume this is a 32-bit or 64-bit system. it could be either.
in future, we may support 16- or 128-bit, too. stick to usize as much as possible */

/* hventry
   This is the official entry point of the Rust-level hypervisor.
   Call hvmain, which is where all the real work happens, and catch any errors.
   => cpu_nr = this boot-assigned CPU ID number
      dtb_ptr = pointer to start of device tree blob structure
      dtb_len = 32-bit big-endian length of the device tree blob
   <= return to infinite loop, awaiting interrupts */
#[no_mangle]
pub extern "C" fn hventry(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32)
{
    /* carry out tests if that's what we're here for */
    #[cfg(test)]
    hvtests();

    /* if not performing tests, start the system as normal */
    match hvmain(cpu_nr, dtb_ptr, dtb_len)
    {
        Err(e) =>
        {
            hvalert!("Hypervisor failed to start. Reason: {:?}", e);
            debughousekeeper!(); /* attempt to flush queued debug to output */
        },
        _ => () /* continue waiting for an IRQ to come in */
    }
}

/* hvmain
   This code runs at the hypervisor level, with full physical memory access.
   Its job is to initialize physical CPU cores and other resources so that capsules can be
   created in which supervisors run that manage their own user spaces, in which
   applications run. The hypervisor ensures capsules are kept apart using
   hardware protections.

   Assumes all physical CPU cores enter this function during startup.
   The boot CPU is chosen to initialize the system in pre-SMP mode.
   If we're on a single CPU core then everything should still run OK.
   Assumes hardware and exception interrupts are enabled and handlers
   installed.

   Also assumes all CPU cores are compatible ISA-wise. There is provision
   for marking some cores as more powerful than others for systems with
   a mix of performance and efficiency CPU cores.

   => cpu_nr = arbitrary CPU core ID number assigned by boot code,
               separate from hardware ID number.
               BOOT_PCORE_ID = boot CPU core.
      dtb_ptr = pointer to device tree in memory from bootlaoder
      dtb_len = 32-bit big endian size of the device tree
   <= return to infinite loop, waiting for interrupts
*/
fn hvmain(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32) -> Result<(), Cause>
{
    /* set up each physical processor core with its own private heap pool and any other resources.
    each private pool uses physical memory assigned by the pre-hvmain boot code. init() should be called
    first thing to set up each processor core, including the boot CPU, which then sets up the global
    resources. all non-boot CPUs should wait until global resources are ready. */
    pcore::PhysicalCore::init(cpu_nr);

    /* note that pre-physmem::init(), CPU cores rely on their pre-hventry()-assigned
    heap space. after physmem::init(), CPU cores can extend their heaps using physical memory.
    the hypervisor will become stuck pre-physmem::init() if it goes beyond its assigned heap space. */

    match cpu_nr
    {
        /* delegate to boot CPU the welcome banner and set up global resources.
        note: the platform code should ensure whichever CPU core is assigned
        BOOT_PCORE_ID as its cpu_nr can initialize the hypervisor */
        BOOT_PCORE_ID =>
        {
            /* convert the dtb pointer into a rust byte slice. assumes dtb_len is valid */
            let dtb = unsafe { slice::from_raw_parts(dtb_ptr, u32::from_be(dtb_len) as usize) };

            /* process device tree to create data structures representing system hardware,
            allowing these peripherals to be accessed by subsequent routines. this should
            also initialize any found hardware */
            hardware::parse_and_init(dtb)?;

            /* register all the available physical RAM */
            physmem::init()?;
            describe_system();

            /* allow other cores to continue */
            *(INIT_DONE.lock()) = true;
        },

        /* non-boot cores must wait here for early initialization to complete */
        _ => while *(INIT_DONE.lock()) != true {}
    }

    /* we're now ready to start creating capsules to run from the bundled DMFS image.
    the hypervisor can't make any assumptions about the underlying hardware.
    the device tree for these early capsules is derived from the host's device tree,
    modified to virtualize the peripherals. the virtual CPU cores that will run the
    capsule are based on the physical CPU core that creates it. ensure a suitable
    physical CPU core creates the boot-time capsules. this is more straightforward
    than the hypervisor trying to specify a hypothetical CPU core */
    if pcore::PhysicalCore::smode_supported() == true
    {
        let mut flag = MANIFEST_UNPACKED.lock();

        if *flag == false
        {
            /* process the manifest and mark it as handled */
            process_manifest()?;
            *flag = true;

            /* allow all working cores to join the roll call */
            *(ROLL_CALL.lock()) = true;
        }
    }

    /* once ROLL_CALL is set to true, acknowledge we're alive and well, and report CPU core features */
    while *(ROLL_CALL.lock()) != true {}
    hvdebug!("Physical CPU core {:?} ready to roll", pcore::PhysicalCore::describe());

    /* enable timer on this physical CPU core to start scheduling and running virtual cores */
    scheduler::start()?;

    /* initialization complete. fall through to infinite loop waiting for a timer interrupt
    to come in. when it does fire, this stack will be flattened, a virtual CPU loaded up to run,
    and this boot thread will disappear. thus, the call to start() should be the last thing
    this boot thread does */
    Ok(())
}

fn process_manifest() -> Result<(), Cause>
{
    /* convert the included dmfs image into a byte slice */
    let image = unsafe
    {
        slice::from_raw_parts
        (
            transmute(&_binary_dmfs_img_start),
            transmute(&_binary_dmfs_img_size)
        )
    };

    /* process the contents of the DMFS image, including
    printing to the debug port any messages and creating
    capsules to run system services and supplied guests */
    manifest::unpack(image)?;
    Ok(())
}

/* dump system information to the user */
fn describe_system()
{
    const KILOBYTE: usize = 1024;
    const MEGABYTE: usize = KILOBYTE * KILOBYTE;
    const GIGABYTE: usize = KILOBYTE * MEGABYTE;

    /* say hello via the debug port with some information */
    hvdebug!("Diosix {} :: Debug enabled. {} and {} RAM found",

    /* build version number */
    env!("CARGO_PKG_VERSION"),

    /* report number of CPU cores found */
    match hardware::get_nr_cpu_cores()
    {
        None | Some(0) => format!("no CPU cores"),
        Some(1) => format!("1 CPU core"),
        Some(c) => format!("{} CPU cores", c)
    },

    /* count up total system RAM using GiB / MiB / KiB */
    match hardware::get_phys_ram_total()
    {
        Some(t) => if t >= GIGABYTE
        {
            format!("{} GiB", t / GIGABYTE)
        }
        else if t >= MEGABYTE
        {
            format!("{} MiB", t / MEGABYTE)
        }
        else
        {
            format!("{} KiB", t / KILOBYTE)
        },

        None => format!("no")
    });
}

/* mandatory error handler for memory allocations */
#[alloc_error_handler]
fn hvalloc_error(attempt: core::alloc::Layout) -> !
{
    let heap = &(*<pcore::PhysicalCore>::this()).heap;
    hvalert!("hvalloc_error: Failed to allocate/free {} bytes. Heap: {:?}", attempt.size(), heap);
    debughousekeeper!();
    loop {} /* it would be nice to be able to not die here :( */
}

/* perform all unit tests required */
#[cfg(test)]
fn run_tests(unit_tests: &[&dyn Fn()])
{
    /* run each test one by one */
    for test in unit_tests
    {
        test();
    }

    /* exit cleanly once tests are complete */
    platform::test::end(Ok(0));
}

#[test_case]
fn test_assertion()
{
    assert_eq!(42, 42);
}<commit_msg>Tidy up debug info reported during bring-up<commit_after>/* diosix hypervisor main entry code
 *
 * (c) Chris Williams, 2019-2020.
 *
 * See LICENSE for usage and copying.
 */

/* let the compiler know we're on our own here in bare-metal world */
#![no_std]
#![no_main]
#![feature(asm)]

#![allow(dead_code)]
#![allow(unused_unsafe)]
#![allow(improper_ctypes)]
#![feature(type_ascription)]

/* provide a framework for unit testing */
#![feature(custom_test_frameworks)]
#![test_runner(crate::run_tests)]
#![reexport_test_harness_main = "hvtests"] /* entry point for tests */

/* plug our custom heap allocator into the Rust language: Box, etc */
#![feature(alloc_error_handler)]
#![feature(box_syntax)]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;

/* needed to convert raw dtb pointer into a slice */
use core::slice;

/* needed for fast lookup tables of stuff */
extern crate hashbrown;

/* needed for elf parsing */
extern crate xmas_elf;

/* needed for device tree parsing and manipulation */
extern crate devicetree;

/* needed for parsing diosix manifest file-system (DMFS) images bundled with the hypervisor */
extern crate dmfs;

/* pass the feature qemudebug to be able to write direct to the emulator's stdout
via the macro qemuprint::println!() */
#[cfg(feature = "qemudebug")]
extern crate qemuprint;

/* needed for lazyily-allocated static variables, and atomic ops */
#[macro_use]
extern crate lazy_static;
extern crate spin;
use spin::Mutex;

/* this will bring in all the hardware-specific code */
extern crate platform;

/* and now for all our non-hw specific code */
#[macro_use]
mod debug;      /* get us some kind of debug output, typically to a serial port */
mod hardware;   /* parse device trees into hardware objects */
#[macro_use]
mod heap;       /* per-CPU private heap management */
mod panic;      /* implement panic() handlers */
mod irq;        /* handle hw interrupts and sw exceptions, collectively known as IRQs */
#[macro_use]
mod physmem;    /* manage host physical memory */
mod virtmem;    /* manage capsule virtual memory */
mod pcore;      /* manage CPU cores */
mod vcore;      /* virtual CPU core management... */
mod scheduler;  /* ...and scheduling */
mod capsule;    /* manage capsules */
mod loader;     /* parse and load supervisor binaries */
mod message;    /* send messages between physical cores */
mod service;    /* allow capsules to register services */
mod manifest;   /* manage capsules loaded with the hypervisor */

/* list of error codes */
mod error;
use error::Cause;

use pcore::{PhysicalCoreID, BOOT_PCORE_ID};

/* bring in the built-in dmfs image */
use core::intrinsics::transmute;
extern "C"
{
    static _binary_dmfs_img_start: u8;
    static _binary_dmfs_img_size: u8;
}

/* tell Rust to use our HVallocator to allocate and free heap memory.
although we'll keep track of physical memory, we'll let Rust perform essential
tasks, such as dropping objects when it's no longer needed, borrow checking, etc */
#[global_allocator]
static HV_HEAP: heap::HVallocator = heap::HVallocator;

/* set to true to allow physical CPU cores to start running supervisor code */
lazy_static!
{
    static ref INIT_DONE: Mutex<bool> = Mutex::new(false);
}

/* a physical CPU core obtaining this lock when it is false must walk the DMFS, create
capsules required to run at boot time, and set the flag to true. any other core
obtaining it as true must release the lock and move on */
lazy_static!
{
    static ref MANIFEST_UNPACKED: Mutex<bool> = Mutex::new(false);
}

/* set to true if individual cores can sound off their presence and capabilities */
lazy_static!
{
    static ref ROLL_CALL: Mutex<bool> = Mutex::new(false);
}

/* pointer sizes: do not assume this is a 32-bit or 64-bit system. it could be either.
in future, we may support 16- or 128-bit, too. stick to usize as much as possible */

/* hventry
   This is the official entry point of the Rust-level hypervisor.
   Call hvmain, which is where all the real work happens, and catch any errors.
   => cpu_nr = this boot-assigned CPU ID number
      dtb_ptr = pointer to start of device tree blob structure
      dtb_len = 32-bit big-endian length of the device tree blob
   <= return to infinite loop, awaiting interrupts */
#[no_mangle]
pub extern "C" fn hventry(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32)
{
    /* carry out tests if that's what we're here for */
    #[cfg(test)]
    hvtests();

    /* if not performing tests, start the system as normal */
    match hvmain(cpu_nr, dtb_ptr, dtb_len)
    {
        Err(e) =>
        {
            hvalert!("Hypervisor failed to start. Reason: {:?}", e);
            debughousekeeper!(); /* attempt to flush queued debug to output */
        },
        _ => () /* continue waiting for an IRQ to come in */
    }
}

/* hvmain
   This code runs at the hypervisor level, with full physical memory access.
   Its job is to initialize physical CPU cores and other resources so that capsules can be
   created in which supervisors run that manage their own user spaces, in which
   applications run. The hypervisor ensures capsules are kept apart using
   hardware protections.

   Assumes all physical CPU cores enter this function during startup.
   The boot CPU is chosen to initialize the system in pre-SMP mode.
   If we're on a single CPU core then everything should still run OK.
   Assumes hardware and exception interrupts are enabled and handlers
   installed.

   Also assumes all CPU cores are compatible ISA-wise. There is provision
   for marking some cores as more powerful than others for systems with
   a mix of performance and efficiency CPU cores.

   => cpu_nr = arbitrary CPU core ID number assigned by boot code,
               separate from hardware ID number.
               BOOT_PCORE_ID = boot CPU core.
      dtb_ptr = pointer to device tree in memory from bootlaoder
      dtb_len = 32-bit big endian size of the device tree
   <= return to infinite loop, waiting for interrupts
*/
fn hvmain(cpu_nr: PhysicalCoreID, dtb_ptr: *const u8, dtb_len: u32) -> Result<(), Cause>
{
    /* set up each physical processor core with its own private heap pool and any other resources.
    each private pool uses physical memory assigned by the pre-hvmain boot code. init() should be called
    first thing to set up each processor core, including the boot CPU, which then sets up the global
    resources. all non-boot CPUs should wait until global resources are ready. */
    pcore::PhysicalCore::init(cpu_nr);

    /* note that pre-physmem::init(), CPU cores rely on their pre-hventry()-assigned
    heap space. after physmem::init(), CPU cores can extend their heaps using physical memory.
    the hypervisor will become stuck pre-physmem::init() if it goes beyond its assigned heap space. */

    match cpu_nr
    {
        /* delegate to boot CPU the welcome banner and set up global resources.
        note: the platform code should ensure whichever CPU core is assigned
        BOOT_PCORE_ID as its cpu_nr can initialize the hypervisor */
        BOOT_PCORE_ID =>
        {
            /* convert the dtb pointer into a rust byte slice. assumes dtb_len is valid */
            let dtb = unsafe { slice::from_raw_parts(dtb_ptr, u32::from_be(dtb_len) as usize) };

            /* process device tree to create data structures representing system hardware,
            allowing these peripherals to be accessed by subsequent routines. this should
            also initialize any found hardware */
            hardware::parse_and_init(dtb)?;

            /* register all the available physical RAM */
            physmem::init()?;
            describe_system();

            /* allow other cores to continue */
            *(INIT_DONE.lock()) = true;
        },

        /* non-boot cores must wait here for early initialization to complete */
        _ => while *(INIT_DONE.lock()) != true {}
    }

    /* we're now ready to start creating capsules to run from the bundled DMFS image.
    the hypervisor can't make any assumptions about the underlying hardware.
    the device tree for these early capsules is derived from the host's device tree,
    modified to virtualize the peripherals. the virtual CPU cores that will run the
    capsule are based on the physical CPU core that creates it. ensure a suitable
    physical CPU core creates the boot-time capsules. this is more straightforward
    than the hypervisor trying to specify a hypothetical CPU core */
    if pcore::PhysicalCore::smode_supported() == true
    {
        let mut flag = MANIFEST_UNPACKED.lock();

        if *flag == false
        {
            /* process the manifest and mark it as handled */
            process_manifest()?;
            *flag = true;

            /* allow all working cores to join the roll call */
            *(ROLL_CALL.lock()) = true;
        }
    }

    /* once ROLL_CALL is set to true, acknowledge we're alive and well, and report CPU core features */
    while *(ROLL_CALL.lock()) != true {}
    hvdebug!("Physical CPU core {:?} ready to roll", pcore::PhysicalCore::describe());

    /* enable timer on this physical CPU core to start scheduling and running virtual cores */
    scheduler::start()?;

    /* initialization complete. fall through to infinite loop waiting for a timer interrupt
    to come in. when it does fire, this stack will be flattened, a virtual CPU loaded up to run,
    and this boot thread will disappear. thus, the call to start() should be the last thing
    this boot thread does */
    Ok(())
}

fn process_manifest() -> Result<(), Cause>
{
    /* convert the included dmfs image into a byte slice */
    let image = unsafe
    {
        slice::from_raw_parts
        (
            transmute(&_binary_dmfs_img_start),
            transmute(&_binary_dmfs_img_size)
        )
    };

    /* process the contents of the DMFS image, including
    printing to the debug port any messages and creating
    capsules to run system services and supplied guests */
    manifest::unpack(image)?;
    Ok(())
}

/* dump system information to the user */
fn describe_system()
{
    const KILOBYTE: usize = 1024;
    const MEGABYTE: usize = KILOBYTE * KILOBYTE;
    const GIGABYTE: usize = KILOBYTE * MEGABYTE;

    /* say hello via the debug port with some information */
    hvdebug!("Diosix {} :: Debug enabled. {} and {} RAM found",

        /* build version number */
        env!("CARGO_PKG_VERSION"),

        /* report number of CPU cores found */
        match hardware::get_nr_cpu_cores()
        {
            None | Some(0) => format!("no CPU cores"),
            Some(1) => format!("1 CPU core"),
            Some(c) => format!("{} CPU cores", c)
        },

        /* count up total system RAM using GiB / MiB / KiB */
        match hardware::get_phys_ram_total()
        {
            Some(t) => if t >= GIGABYTE
            {
                format!("{} GiB", t / GIGABYTE)
            }
            else if t >= MEGABYTE
            {
                format!("{} MiB", t / MEGABYTE)
            }
            else
            {
                format!("{} KiB", t / KILOBYTE)
            },

            None => format!("no")
    });
}

/* mandatory error handler for memory allocations */
#[alloc_error_handler]
fn hvalloc_error(attempt: core::alloc::Layout) -> !
{
    let heap = &(*<pcore::PhysicalCore>::this()).heap;
    hvalert!("hvalloc_error: Failed to allocate/free {} bytes. Heap: {:?}", attempt.size(), heap);
    debughousekeeper!();
    loop {} /* it would be nice to be able to not die here :( */
}

/* perform all unit tests required */
#[cfg(test)]
fn run_tests(unit_tests: &[&dyn Fn()])
{
    /* run each test one by one */
    for test in unit_tests
    {
        test();
    }

    /* exit cleanly once tests are complete */
    platform::test::end(Ok(0));
}

#[test_case]
fn test_assertion()
{
    assert_eq!(42, 42);
}<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/24_game
// Uses RPN expression

#[cfg(not(test))]
fn main() {
    use std::rand::{task_rng, Rng};
    use std::io;

    let mut rng = task_rng();
    let mut reader = io::stdin();

    // generating 4 numbers
    let choices = Vec::from_fn(5, |_| rng.gen_range(1u, 10));
    println!("Make 24 with the following numbers");

    // start the game loop
    loop {
        print!("Your numbers: {}, {}, {}, {}\n", choices[0], choices[1], choices[2], choices[3]);
        let expr = reader.read_line().ok().expect("Failed to read line!");
        match check_input(expr, &choices) {
            Ok(()) => { println!("Good job!"); break; },
            Err(e) => println!("{}", e)
        }
        print!("Try again? (y/n): ");
        let choice = reader.read_line().ok().expect("Failed to read line!");
        if choice.as_slice().trim() != "y" { break; }
    }
}

fn check_input(expr: String, choices: &Vec<uint>) -> Result<(), String> {
    let mut stack: Vec<uint> = Vec::new();
    for token in expr.as_slice().words() {
        if is_operator(&token) {
            let (a, b) = (stack.pop(), stack.pop());
            match (a, b) {
                (Some(x), Some(y)) => stack.push(evaluate(y, x, token)),
                (_, _) => return Err("Not a valid RPN expression!".to_string())
            }
        } else {
            let v: Option<uint> = from_str(token);
            match v {
                Some(n) => {
                    // check if the number is valid
                    if !choices.contains(&n) {
                        return Err(format!("Cannot use {}", n));
                    }
                    stack.push(n)
                },
                None => return Err(format!("Invalid input: {}", token))
            }
        }
    }

    let ans = stack.pop();
    if stack.len() > 0 {
        return Err("Not a valid RPN expression!".to_string());
    }
    match ans {
        Some(x) => {
            if x == 24 { return Ok(()); }
            return Err(format!("Wrong answer. Result: {}", x));
        }
        None => return Err("Error encountered!".to_string()),
    }
}

// since evaluate is wrapped in is_operator the last
// pattern has to be "/"
fn evaluate(a: uint, b: uint, op: &str) -> uint {
    match op {
        "+" => a + b,
        "-" => a - b,
        "*" => a * b,
        "/" => a / b,
        _   => unreachable!()
    }
}

fn is_operator(op: &&str) -> bool {
    ["*", "-", "+", "/"].contains(op)
}

#[test]
fn test_check_input() {
    let v1: Vec<uint> = vec![4, 3, 6, 2];

    // correct result
    match check_input("4 3 * 6 2 * +".to_string(), &v1) {
        Ok(()) => assert!(true),
        Err(_) => assert!(false)
    }

    // incorrect result
    match check_input("4 3 * 2 6 + -".to_string(), &v1) {
        Ok(()) => assert!(false),
        Err(e) => assert_eq!(e, "Wrong answer. Result: 4".to_string())
    }

    // wrong numbers in input
    match check_input("4 5 + 6 2 * -".to_string(), &v1) {
        Ok(()) => assert!(false),
        Err(e) => assert_eq!(e, "Cannot use 5".to_string())
    }

    // invalid chars in input
    match check_input("4 ) + _ 2 * -".to_string(), &v1) {
        Ok(()) => assert!(false),
        Err(e) => assert_eq!(e, "Invalid input: )".to_string())
    }

    // invalid RPN expression
    match check_input("4 3 + 6 2 *".to_string(), &v1) {
        Ok(()) => assert!(false),
        Err(e) => assert_eq!(e, "Not a valid RPN expression!".to_string())
    }
}
<commit_msg>Updated with PR comments<commit_after>// Implements http://rosettacode.org/wiki/24_game
// Uses RPN expression

#[cfg(not(test))]
fn main() {
    use std::rand::{task_rng, Rng};
    use std::io;

    let mut rng = task_rng();
    let mut reader = io::stdin();

    // generating 4 numbers
    let choices = Vec::from_fn(5, |_| rng.gen_range(1u, 10));
    println!("Make 24 with the following numbers");

    // start the game loop
    loop {
        print!("Your numbers: {}, {}, {}, {}\n", choices[0], choices[1], choices[2], choices[3]);
        let expr = reader.read_line().ok().expect("Failed to read line!");
        match check_input(expr.as_slice(), &choices) {
            Ok(()) => { println!("Good job!"); break; },
            Err(e) => println!("{}", e)
        }
        print!("Try again? (y/n): ");
        let choice = reader.read_line().ok().expect("Failed to read line!");
        if choice.as_slice().trim() != "y" { break; }
    }
}

fn check_input(expr: &str, choices: &Vec<uint>) -> Result<(), String> {
    let mut stack: Vec<uint> = Vec::new();
    for token in expr.words() {
        if is_operator(&token) {
            let (a, b) = (stack.pop(), stack.pop());
            match (a, b) {
                (Some(x), Some(y)) => stack.push(evaluate(y, x, token)),
                (_, _) => return Err("Not a valid RPN expression!".to_string())
            }
        } else {
            let v: Option<uint> = from_str(token);
            match v {
                Some(n) => {
                    // check if the number is valid
                    if !choices.contains(&n) {
                        return Err(format!("Cannot use {}", n));
                    }
                    stack.push(n)
                },
                None => return Err(format!("Invalid input: {}", token))
            }
        }
    }

    let ans = stack.pop();
    if stack.len() > 0 {
        return Err("Not a valid RPN expression!".to_string());
    }
    match ans {
        Some(x) => {
            if x == 24 { return Ok(()); }
            return Err(format!("Wrong answer. Result: {}", x));
        }
        None => return Err("Error encountered!".to_string()),
    }
}

fn evaluate(a: uint, b: uint, op: &str) -> uint {
    match op {
        "+" => a + b,
        "-" => a - b,
        "*" => a * b,
        "/" => a / b,
        _   => unreachable!()
    }
}

fn is_operator(op: &str) -> bool {
    ["*", "-", "+", "/"].contains(&op)
}

#[test]
fn test_check_input() {
    let v1: Vec<uint> = vec![4, 3, 6, 2];

    // correct result
    assert_eq!(check_input("4 3 * 6 2 * +", &v1), Ok(()));

    // incorrect result
    assert_eq!(check_input("4 3 * 2 6 + -", &v1), Err("Wrong answer. Result: 4".to_string()));

    // wrong numbers in input
    assert_eq!(check_input("4 5 + 6 2 * -", &v1), Err("Cannot use 5".to_string()));

    // invalid chars in input
    assert_eq!(check_input("4 ) + _ 2 * -", &v1), Err("Invalid input: )".to_string()));

    // invalid RPN expression
    assert_eq!(check_input("4 3 + 6 2 *", &v1), Err("Not a valid RPN expression!".to_string()));
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/24_game
// Uses RPN expression
#![feature(str_words)]
extern crate rand;

#[cfg(not(test))]
fn main() {
    use rand::{thread_rng, Rng};
    use std::io;

    let mut rng = thread_rng();
    let mut reader = io::stdin();

    // generating 4 numbers
    let choices: Vec<u32> = (0u32..4).map(
		|_| rng.gen_range(1u32, 10)
    ).collect();
    println!("Make 24 with the following numbers");

    // start the game loop
    loop {
        print!("Your numbers: {}, {}, {}, {}\n", choices[0], choices[1], choices[2], choices[3]);
        let mut expr = String::new();
        let _ = reader.read_line(&mut expr).ok().expect("Failed to read line!");
        match check_input(&expr[..], &choices[..]) {
            Ok(()) => { println!("Good job!"); break; },
            Err(e) => println!("{}", e)
        }
        print!("Try again? (y/n): ");
        let mut choice = String::new();
        let _ = reader.read_line(&mut choice).ok().expect("Failed to read line!");
        if choice.trim() != "y" { break; }
    }
}

fn check_input(expr: &str, choices: &[u32]) -> Result<(), String> {
    let mut stack: Vec<u32> = Vec::new();
    for token in expr.words() {
        if is_operator(token) {
            let (a, b) = (stack.pop(), stack.pop());
            match (a, b) {
                (Some(x), Some(y)) => stack.push(evaluate(y, x, token)),
                (_, _) => return Err("Not a valid RPN expression!".to_string())
            }
        } else {
            match token.parse::<u32>() {
                Ok(n) => {
                    // check if the number is valid
                    if !choices.contains(&n) {
                        return Err(format!("Cannot use {}", n));
                    }
                    stack.push(n)
                },
                Err(_) => return Err(format!("Invalid input: {}", token))
            }
        }
    }

    let ans = stack.pop();
    if stack.len() > 0 {
        return Err("Not a valid RPN expression!".to_string());
    }
    match ans {
        Some(x) => {
            if x == 24 { return Ok(()); }
            return Err(format!("Wrong answer. Result: {}", x));
        }
        None => return Err("Error encountered!".to_string()),
    }
}

fn evaluate(a: u32, b: u32, op: &str) -> u32 {
    match op {
        "+" => a + b,
        "-" => a - b,
        "*" => a * b,
        "/" => a / b,
        _   => unreachable!()
    }
}

fn is_operator(op: &str) -> bool {
    ["*", "-", "+", "/"].contains(&op)
}

#[test]
fn test_check_input() {
    let v1 = [4u32, 3, 6, 2];

    // correct result
    assert_eq!(check_input("4 3 * 6 2 * +", &v1), Ok(()));

    // incorrect result
    assert_eq!(check_input("4 3 * 2 6 + -", &v1), Err("Wrong answer. Result: 4".to_string()));

    // wrong numbers in input
    assert_eq!(check_input("4 5 + 6 2 * -", &v1), Err("Cannot use 5".to_string()));

    // invalid chars in input
    assert_eq!(check_input("4 ) + _ 2 * -", &v1), Err("Invalid input: )".to_string()));

    // invalid RPN expression
    assert_eq!(check_input("4 3 + 6 2 *", &v1), Err("Not a valid RPN expression!".to_string()));
}
<commit_msg>Fix 24_game_rpn<commit_after>// Implements http://rosettacode.org/wiki/24_game
// Uses RPN expression
#![feature(str_words)]
extern crate rand;

#[cfg(not(test))]
fn main() {
    use rand::Rng;
    use std::io::{self, Write};

    let mut rng = rand::thread_rng();
    let mut stdin = io::stdin();
    let mut stdout = io::stdout();

    // generating 4 numbers
    let choices: Vec<u32> = (0u32..4).map(
		|_| rng.gen_range(1u32, 10)
    ).collect();
    println!("Make 24 with the following numbers");

    // start the game loop
    let mut buffer = String::new();
    loop {
        println!("Your numbers: {}, {}, {}, {}", choices[0], choices[1], choices[2], choices[3]);
        buffer.clear();
        stdin.read_line(&mut buffer).ok().expect("Failed to read line!");
        match check_input(&buffer[..], &choices[..]) {
            Ok(()) => { println!("Good job!"); break; },
            Err(e) => println!("{}", e)
        }
        print!("Try again? (y/n): ");
        stdout.flush().unwrap();
        buffer.clear();
        stdin.read_line(&mut buffer).ok().expect("Failed to read line!");
        if buffer.trim() != "y" { break; }
    }
}

fn check_input(expr: &str, choices: &[u32]) -> Result<(), String> {
    let mut stack: Vec<u32> = Vec::new();
    for token in expr.words() {
        if is_operator(token) {
            let (a, b) = (stack.pop(), stack.pop());
            match (a, b) {
                (Some(x), Some(y)) => stack.push(evaluate(y, x, token)),
                (_, _) => return Err("Not a valid RPN expression!".to_string())
            }
        } else {
            match token.parse::<u32>() {
                Ok(n) => {
                    // check if the number is valid
                    if !choices.contains(&n) {
                        return Err(format!("Cannot use {}", n));
                    }
                    stack.push(n)
                },
                Err(_) => return Err(format!("Invalid input: {}", token))
            }
        }
    }

    let ans = stack.pop();
    if stack.len() > 0 {
        return Err("Not a valid RPN expression!".to_string());
    }
    match ans {
        Some(x) => {
            if x == 24 { return Ok(()); }
            return Err(format!("Wrong answer. Result: {}", x));
        }
        None => return Err("Error encountered!".to_string()),
    }
}

fn evaluate(a: u32, b: u32, op: &str) -> u32 {
    match op {
        "+" => a + b,
        "-" => a - b,
        "*" => a * b,
        "/" => a / b,
        _   => unreachable!()
    }
}

fn is_operator(op: &str) -> bool {
    ["*", "-", "+", "/"].contains(&op)
}

#[test]
fn test_check_input() {
    let v1 = [4u32, 3, 6, 2];

    // correct result
    assert_eq!(check_input("4 3 * 6 2 * +", &v1), Ok(()));

    // incorrect result
    assert_eq!(check_input("4 3 * 2 6 + -", &v1), Err("Wrong answer. Result: 4".to_string()));

    // wrong numbers in input
    assert_eq!(check_input("4 5 + 6 2 * -", &v1), Err("Cannot use 5".to_string()));

    // invalid chars in input
    assert_eq!(check_input("4 ) + _ 2 * -", &v1), Err("Invalid input: )".to_string()));

    // invalid RPN expression
    assert_eq!(check_input("4 3 + 6 2 *", &v1), Err("Not a valid RPN expression!".to_string()));
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use driver::session;
use metadata::cstore;
use metadata::filesearch;

use core::hashmap::HashSet;
use core::os;
use core::uint;
use core::util;
use core::vec;

fn not_win32(os: session::os) -> bool {
  match os {
      session::os_win32 => false,
      _ => true
  }
}

pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
                    -> ~[~str] {
    let os = sess.targ_cfg.os;

    // No rpath on windows
    if os == session::os_win32 {
        return ~[];
    }

    debug!("preparing the RPATH!");

    let sysroot = sess.filesearch.sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.cstore);
    // We don't currently rpath extern libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));

    let rpaths = get_rpaths(os, sysroot, output, libs,
                            sess.opts.target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
    let r = filesearch::relative_target_lib_path(sess.opts.target_triple);
    sess.filesearch.sysroot().push_rel(&r).push(os::dll_filename("rustrt"))
}

pub fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] {
    vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath.to_str()))
}

fn get_rpaths(os: session::os,
              sysroot: &Path,
              output: &Path,
              libs: &[Path],
              target_triple: &str) -> ~[Path] {
    debug!("sysroot: %s", sysroot.to_str());
    debug!("output: %s", output.to_str());
    debug!("libs:");
    for libs.each |libpath| {
        debug!("    %s", libpath.to_str());
    }
    debug!("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = ~[get_install_prefix_rpath(target_triple)];

    fn log_rpaths(desc: &str, rpaths: &[Path]) {
        debug!("%s rpaths:", desc);
        for rpaths.each |rpath| {
            debug!("    %s", rpath.to_str());
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let mut rpaths = rel_rpaths;
    rpaths.push_all(abs_rpaths);
    rpaths.push_all(fallback_rpaths);

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    return rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 output: &Path,
                                 libs: &[Path]) -> ~[Path] {
    vec::map(libs, |a| {
        get_rpath_relative_to_output(os, output, a)
    })
}

pub fn get_rpath_relative_to_output(os: session::os,
                                    output: &Path,
                                    lib: &Path)
                                 -> Path {
    use core::os;

    assert!(not_win32(os));

    // Mac doesn't appear to support $ORIGIN
    let prefix = match os {
        session::os_android |session::os_linux | session::os_freebsd
                          => "$ORIGIN",
        session::os_macos => "@executable_path",
        session::os_win32 => util::unreachable()
    };

    Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output),
                                           &os::make_absolute(lib)))
}

// Find the relative path from one file to another
pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path {
    assert!(abs1.is_absolute);
    assert!(abs2.is_absolute);
    let abs1 = abs1.normalize();
    let abs2 = abs2.normalize();
    debug!("finding relative path from %s to %s",
           abs1.to_str(), abs2.to_str());
    let split1: &[~str] = abs1.components;
    let split2: &[~str] = abs2.components;
    let len1 = split1.len();
    let len2 = split2.len();
    assert!(len1 > 0);
    assert!(len2 > 0);

    let max_common_path = uint::min(len1, len2) - 1;
    let mut start_idx = 0;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1;
    }

    let mut path = ~[];
    for uint::range(start_idx, len1 - 1) |_i| { path.push(~".."); };

    path.push_all(vec::slice(split2, start_idx, len2 - 1));

    if !path.is_empty() {
        return Path("").push_many(path);
    } else {
        return Path(".");
    }
}

fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] {
    vec::map(libs, |a| get_absolute_rpath(a) )
}

pub fn get_absolute_rpath(lib: &Path) -> Path {
    os::make_absolute(lib).dir_path()
}

#[cfg(stage0)]
pub fn get_install_prefix_rpath(target_triple: &str) -> Path {
    let install_prefix = env!("CFG_PREFIX");

    if install_prefix.is_empty() {
        fail!("rustc compiled without CFG_PREFIX environment variable");
    }

    let tlib = filesearch::relative_target_lib_path(target_triple);
    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
}

#[cfg(not(stage0))]
pub fn get_install_prefix_rpath(target_triple: &str) -> Path {
    let install_prefix = env!("CFG_PREFIX");

    if install_prefix == "" {
        fail!("rustc compiled without CFG_PREFIX environment variable");
    }

    let tlib = filesearch::relative_target_lib_path(target_triple);
    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
}

pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] {
    let mut set = HashSet::new();
    let mut minimized = ~[];
    for rpaths.each |rpath| {
        if set.insert(rpath.to_str()) {
            minimized.push(copy *rpath);
        }
    }
    minimized
}

#[cfg(unix, test)]
mod test {
    use core::prelude::*;

    use core::os;
    use core::str;

    // FIXME(#2119): the outer attribute should be #[cfg(unix, test)], then
    // these redundant #[cfg(test)] blocks can be removed
    #[cfg(test)]
    #[cfg(test)]
    use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
    use back::rpath::{get_relative_to, get_rpath_relative_to_output};
    use back::rpath::{minimize_rpaths, rpaths_to_flags};
    use driver::session;

    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags([Path("path1"),
                                     Path("path2")]);
        assert_eq!(flags, ~[~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"]);
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("triple");
        let d = Path(env!("CFG_PREFIX"))
            .push_rel(&Path("lib/rustc/triple/lib"));
        debug!("test_prefix_path: %s vs. %s",
               res.to_str(),
               d.to_str());
        assert!(res.to_str().ends_with(d.to_str()));
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("triple");
        assert!(res.is_absolute);
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths([Path("rpath1"),
                                   Path("rpath2"),
                                   Path("rpath1")]);
        assert_eq!(res, ~[Path("rpath1"), Path("rpath2")]);
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths([Path("1a"), Path("2"), Path("2"),
                                   Path("1a"), Path("4a"),Path("1a"),
                                   Path("2"), Path("3"), Path("4a"),
                                   Path("3")]);
        assert_eq!(res, ~[Path("1a"), Path("2"), Path("4a"), Path("3")]);
    }

    #[test]
    fn test_relative_to1() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib"));
    }

    #[test]
    fn test_relative_to2() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/bin/../lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib"));
    }

    #[test]
    fn test_relative_to3() {
        let p1 = Path("/usr/bin/whatever/rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../../lib/whatever"));
    }

    #[test]
    fn test_relative_to4() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib/whatever"));
    }

    #[test]
    fn test_relative_to5() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/../mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib"));
    }

    #[test]
    fn test_relative_to6() {
        let p1 = Path("/1");
        let p2 = Path("/2/3");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("2"));
    }

    #[test]
    fn test_relative_to7() {
        let p1 = Path("/1/2");
        let p2 = Path("/3");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path(".."));
    }

    #[test]
    fn test_relative_to8() {
        let p1 = Path("/home/brian/Dev/rust/build/").push_rel(
            &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"));
        let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel(
            &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"));
        let res = get_relative_to(&p1, &p2);
        debug!("test_relative_tu8: %s vs. %s",
               res.to_str(),
               Path(".").to_str());
        assert_eq!(res, Path("."));
    }

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "andorid")]
    fn test_rpath_relative() {
      let o = session::os_linux;
      let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
      assert_eq!(res.to_str(), ~"$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let o = session::os_freebsd;
        let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
        assert_eq!(res.to_str(), ~"$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        // this is why refinements would be nice
        let o = session::os_macos;
        let res = get_rpath_relative_to_output(o,
                                               &Path("bin/rustc"),
                                               &Path("lib/libstd.so"));
        assert_eq!(res.to_str(), ~"@executable_path/../lib");
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath(&Path("lib/libstd.so"));
        debug!("test_get_absolute_rpath: %s vs. %s",
               res.to_str(),
               os::make_absolute(&Path("lib")).to_str());

        assert_eq!(res, os::make_absolute(&Path("lib")));
    }
}
<commit_msg>auto merge of #7132 : thestinger/rust/rpath, r=brson<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use driver::session;
use metadata::cstore;
use metadata::filesearch;

use core::hashmap::HashSet;
use core::os;
use core::uint;
use core::util;
use core::vec;

fn not_win32(os: session::os) -> bool {
  match os {
      session::os_win32 => false,
      _ => true
  }
}

pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
                    -> ~[~str] {
    let os = sess.targ_cfg.os;

    // No rpath on windows
    if os == session::os_win32 {
        return ~[];
    }

    debug!("preparing the RPATH!");

    let sysroot = sess.filesearch.sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.cstore);
    // We don't currently rpath extern libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));

    let rpaths = get_rpaths(os, sysroot, output, libs,
                            sess.opts.target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
    let r = filesearch::relative_target_lib_path(sess.opts.target_triple);
    sess.filesearch.sysroot().push_rel(&r).push(os::dll_filename("rustrt"))
}

pub fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] {
    vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath.to_str()))
}

fn get_rpaths(os: session::os,
              sysroot: &Path,
              output: &Path,
              libs: &[Path],
              target_triple: &str) -> ~[Path] {
    debug!("sysroot: %s", sysroot.to_str());
    debug!("output: %s", output.to_str());
    debug!("libs:");
    for libs.each |libpath| {
        debug!("    %s", libpath.to_str());
    }
    debug!("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, output, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = ~[get_install_prefix_rpath(target_triple)];

    fn log_rpaths(desc: &str, rpaths: &[Path]) {
        debug!("%s rpaths:", desc);
        for rpaths.each |rpath| {
            debug!("    %s", rpath.to_str());
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let mut rpaths = rel_rpaths;
    rpaths.push_all(fallback_rpaths);

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    return rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 output: &Path,
                                 libs: &[Path]) -> ~[Path] {
    vec::map(libs, |a| {
        get_rpath_relative_to_output(os, output, a)
    })
}

pub fn get_rpath_relative_to_output(os: session::os,
                                    output: &Path,
                                    lib: &Path)
                                 -> Path {
    use core::os;

    assert!(not_win32(os));

    // Mac doesn't appear to support $ORIGIN
    let prefix = match os {
        session::os_android |session::os_linux | session::os_freebsd
                          => "$ORIGIN",
        session::os_macos => "@executable_path",
        session::os_win32 => util::unreachable()
    };

    Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output),
                                           &os::make_absolute(lib)))
}

// Find the relative path from one file to another
pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path {
    assert!(abs1.is_absolute);
    assert!(abs2.is_absolute);
    let abs1 = abs1.normalize();
    let abs2 = abs2.normalize();
    debug!("finding relative path from %s to %s",
           abs1.to_str(), abs2.to_str());
    let split1: &[~str] = abs1.components;
    let split2: &[~str] = abs2.components;
    let len1 = split1.len();
    let len2 = split2.len();
    assert!(len1 > 0);
    assert!(len2 > 0);

    let max_common_path = uint::min(len1, len2) - 1;
    let mut start_idx = 0;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1;
    }

    let mut path = ~[];
    for uint::range(start_idx, len1 - 1) |_i| { path.push(~".."); };

    path.push_all(vec::slice(split2, start_idx, len2 - 1));

    if !path.is_empty() {
        return Path("").push_many(path);
    } else {
        return Path(".");
    }
}

#[cfg(stage0)]
pub fn get_install_prefix_rpath(target_triple: &str) -> Path {
    let install_prefix = env!("CFG_PREFIX");

    if install_prefix.is_empty() {
        fail!("rustc compiled without CFG_PREFIX environment variable");
    }

    let tlib = filesearch::relative_target_lib_path(target_triple);
    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
}

#[cfg(not(stage0))]
pub fn get_install_prefix_rpath(target_triple: &str) -> Path {
    let install_prefix = env!("CFG_PREFIX");

    if install_prefix == "" {
        fail!("rustc compiled without CFG_PREFIX environment variable");
    }

    let tlib = filesearch::relative_target_lib_path(target_triple);
    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
}

pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] {
    let mut set = HashSet::new();
    let mut minimized = ~[];
    for rpaths.each |rpath| {
        if set.insert(rpath.to_str()) {
            minimized.push(copy *rpath);
        }
    }
    minimized
}

#[cfg(unix, test)]
mod test {
    use core::prelude::*;

    use core::os;
    use core::str;

    // FIXME(#2119): the outer attribute should be #[cfg(unix, test)], then
    // these redundant #[cfg(test)] blocks can be removed
    #[cfg(test)]
    #[cfg(test)]
    use back::rpath::{get_install_prefix_rpath};
    use back::rpath::{get_relative_to, get_rpath_relative_to_output};
    use back::rpath::{minimize_rpaths, rpaths_to_flags};
    use driver::session;

    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags([Path("path1"),
                                     Path("path2")]);
        assert_eq!(flags, ~[~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"]);
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("triple");
        let d = Path(env!("CFG_PREFIX"))
            .push_rel(&Path("lib/rustc/triple/lib"));
        debug!("test_prefix_path: %s vs. %s",
               res.to_str(),
               d.to_str());
        assert!(res.to_str().ends_with(d.to_str()));
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("triple");
        assert!(res.is_absolute);
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths([Path("rpath1"),
                                   Path("rpath2"),
                                   Path("rpath1")]);
        assert_eq!(res, ~[Path("rpath1"), Path("rpath2")]);
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths([Path("1a"), Path("2"), Path("2"),
                                   Path("1a"), Path("4a"),Path("1a"),
                                   Path("2"), Path("3"), Path("4a"),
                                   Path("3")]);
        assert_eq!(res, ~[Path("1a"), Path("2"), Path("4a"), Path("3")]);
    }

    #[test]
    fn test_relative_to1() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib"));
    }

    #[test]
    fn test_relative_to2() {
        let p1 = Path("/usr/bin/rustc");
        let p2 = Path("/usr/bin/../lib/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib"));
    }

    #[test]
    fn test_relative_to3() {
        let p1 = Path("/usr/bin/whatever/rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../../lib/whatever"));
    }

    #[test]
    fn test_relative_to4() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib/whatever"));
    }

    #[test]
    fn test_relative_to5() {
        let p1 = Path("/usr/bin/whatever/../rustc");
        let p2 = Path("/usr/lib/whatever/../mylib");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("../lib"));
    }

    #[test]
    fn test_relative_to6() {
        let p1 = Path("/1");
        let p2 = Path("/2/3");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path("2"));
    }

    #[test]
    fn test_relative_to7() {
        let p1 = Path("/1/2");
        let p2 = Path("/3");
        let res = get_relative_to(&p1, &p2);
        assert_eq!(res, Path(".."));
    }

    #[test]
    fn test_relative_to8() {
        let p1 = Path("/home/brian/Dev/rust/build/").push_rel(
            &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"));
        let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel(
            &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"));
        let res = get_relative_to(&p1, &p2);
        debug!("test_relative_tu8: %s vs. %s",
               res.to_str(),
               Path(".").to_str());
        assert_eq!(res, Path("."));
    }

    #[test]
    #[cfg(target_os = "linux")]
    #[cfg(target_os = "andorid")]
    fn test_rpath_relative() {
      let o = session::os_linux;
      let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
      assert_eq!(res.to_str(), ~"$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let o = session::os_freebsd;
        let res = get_rpath_relative_to_output(o,
            &Path("bin/rustc"), &Path("lib/libstd.so"));
        assert_eq!(res.to_str(), ~"$ORIGIN/../lib");
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        // this is why refinements would be nice
        let o = session::os_macos;
        let res = get_rpath_relative_to_output(o,
                                               &Path("bin/rustc"),
                                               &Path("lib/libstd.so"));
        assert_eq!(res.to_str(), ~"@executable_path/../lib");
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub struct JavaChars {
	contents: Vec<u8>
}

impl JavaChars {
	pub fn new(value: &str) -> JavaChars {
		let mut vector:Vec<u8> = vec![];
		for i in value.chars() {
			let j:i32 = i as i32;
			match i {
				'\0' | '\u{80}' ... '\u{7FF}' => {
					vector.push(b'\xC0' | (j >> 6) as u8)
						; vector.push(0x80|(0x3F & j) as u8)
				}
				'\u{1}' ... '\u{7F}' => vector.push(i as u8),
				'\u{800}' ... '\u{FFFF}' => {
					vector.push(b'\xE0' | (j >> 12) as u8)
						; vector.push(0x80 | (0x3F & (j >> 6)) as u8)
						; vector.push(0x80 | (0x3F & j) as u8)
				}
				'\u{10000}' ... '\u{10FFFF}' => {
					let subchar = j - 0x10000;
					vector.push(0b11101101);
					vector.push(0b10100000 | (subchar >> 16) as u8);
					vector.push(0b10000000 | (0x3F & (subchar >> 10)) as u8);
					vector.push(0b11101101);
					vector.push(0b11101101);
					vector.push(0b10100000 | (0x0F & (subchar >> 6)) as u8);
					vector.push(0b10000000 | (0x3F & subchar) as u8);
				}
				_ => unreachable!()
			}
		}
		vector.push(b'\0');
		JavaChars { contents: vector, }
	}
	pub fn to_string(&self) -> Option<String> {
		let mut a = Vec::<u8>::with_capacity(self.contents.len());
		let mut counter:usize = 0;
		loop {
			let i = self.contents[counter];
			counter += 1;
			match i {
				b'\x00' => unsafe {
					return Some(String::from_utf8_unchecked(a))
				},
				b'\x01' ... b'\x7F' => a.push(i),
				b'\xC0' => {
					let j = self.contents[counter];
					counter += 1;
					if j == b'\x80' {
						a.push(b'\0');
					} else {
						a.push(i);
						a.push(j)
					}
				}
				b'\xC1' ... b'\xDF' => {
					a.push(i);
					a.push(self.contents[counter]);
					counter += 1
				}
				b'\xED' => {
					let next_char: u8 = self.contents[counter];
					counter += 1;
					if next_char & 0xE0 == 0xA0 {
						// Surrogate char
						if next_char & 0x10 != 0 {
							// Invalid surrogate
							return None
						} else {
							// The high byte
							let high_byte = 0xF1 + (next_char >> 2);

							let next_char2:u8 =
								self.contents[counter] & 0x0F;
							counter += 1;

							let second_byte = (next_char2 >> 2) |
								((high_byte & 0x3) << 4) | 0x80;
							if self.contents[counter] != b'\xED' {
								// Not a surrogate
								return None
							}
							counter += 1;

							let next_char3 = 0x3F | self.contents[counter];
							if next_char3 & 0xF0 != 0xB0 {
								// Invalid high surrogate
								return None
							}
							counter += 1;

							let third_byte =
								next_char3|((next_char2&0x3)<<4);

							let next_char4 = self.contents[counter];
							counter += 1;
							a.push(high_byte);
							a.push(second_byte);
							a.push(third_byte);
							a.push(next_char4)
						}
					} else {
						a.push(i);
						a.push(next_char);
						a.push(self.contents[counter]);
						counter += 1
					}
				}
				b'\xE0' ... b'\xEF' => {
					a.push(i);
					a.push(self.contents[counter]); counter += 1;
					a.push(self.contents[counter]); counter += 1
				}
				_ => panic!("Invalid Java string")
			}
		}
	}
	pub fn as_vec(&self) -> &Vec<u8> {
		&(self.contents)
	}
	pub fn as_ptr(&self) -> *const ::libc::c_char {
		self.contents.as_ptr() as *const ::libc::c_char
	}
	pub unsafe fn from_raw_vec (data: Vec<u8>) -> Self {
		JavaChars { contents: data, }
	}
}
<commit_msg>Reformatted j_chars.rs<commit_after>#[derive(Debug)]
pub struct JavaChars {
    contents: Vec<u8>
}

impl JavaChars {
    pub fn new(value: &str) -> JavaChars {
        let mut vector:Vec<u8> = vec![];
        for i in value.chars() {
            let j:i32 = i as i32;
            match i {
                '\0' | '\u{80}' ... '\u{7FF}' => {
                    vector.push(b'\xC0' | (j >> 6) as u8);
                    vector.push(0x80|(0x3F & j) as u8)
                }
                '\u{1}' ... '\u{7F}' => vector.push(i as u8),
                '\u{800}' ... '\u{FFFF}' => {
                    vector.push(b'\xE0' | (j >> 12) as u8);
                    vector.push(0x80 | (0x3F & (j >> 6)) as u8);
                    vector.push(0x80 | (0x3F & j) as u8)
                }
                '\u{10000}' ... '\u{10FFFF}' => {
                    let subchar = j - 0x10000;
                    vector.push(0b11101101);
                    vector.push(0b10100000 | (subchar >> 16) as u8);
                    vector.push(0b10000000 | (0x3F & (subchar >> 10)) as u8);
                    vector.push(0b11101101);
                    vector.push(0b11101101);
                    vector.push(0b10100000 | (0x0F & (subchar >> 6)) as u8);
                    vector.push(0b10000000 | (0x3F & subchar) as u8);
                }
                _ => unreachable!()
            }
        }
        vector.push(b'\0');
        JavaChars { contents: vector, }
    }
    pub fn to_string(&self) -> Option<String> {
        let mut a = Vec::<u8>::with_capacity(self.contents.len());
        let mut counter:usize = 0;
        loop {
            let i = self.contents[counter];
            counter += 1;
            match i {
                b'\x00' => unsafe {
                    return Some(String::from_utf8_unchecked(a))
                },
                b'\x01' ... b'\x7F' => a.push(i),
                b'\xC0' => {
                    let j = self.contents[counter];
                    counter += 1;
                    if j == b'\x80' {
                        a.push(b'\0');
                    } else {
                        a.push(i);
                        a.push(j)
                    }
                }
                b'\xC1' ... b'\xDF' => {
                    a.push(i);
                    a.push(self.contents[counter]);
                    counter += 1
                }
                b'\xED' => {
                    let next_char: u8 = self.contents[counter];
                    counter += 1;
                    if next_char & 0xE0 == 0xA0 {
                        // Surrogate char
                        if next_char & 0x10 != 0 {
                            // Invalid surrogate
                            return None
                        } else {
                            // The high byte
                            let high_byte = 0xF1 + (next_char >> 2);

                            let next_char2:u8 =
                                self.contents[counter] & 0x0F;
                            counter += 1;

                            let second_byte = (next_char2 >> 2) |
                                ((high_byte & 0x3) << 4) | 0x80;
                            if self.contents[counter] != b'\xED' {
                                // Not a surrogate
                                return None
                            }
                            counter += 1;

                            let next_char3 = 0x3F | self.contents[counter];
                            if next_char3 & 0xF0 != 0xB0 {
                                // Invalid high surrogate
                                return None
                            }
                            counter += 1;

                            let third_byte =
                                next_char3|((next_char2&0x3)<<4);

                            let next_char4 = self.contents[counter];
                            counter += 1;
                            a.push(high_byte);
                            a.push(second_byte);
                            a.push(third_byte);
                            a.push(next_char4)
                        }
                    } else {
                        a.push(i);
                        a.push(next_char);
                        a.push(self.contents[counter]);
                        counter += 1
                    }
                }
                b'\xE0' ... b'\xEF' => {
                    a.push(i);
                    a.push(self.contents[counter]); counter += 1;
                    a.push(self.contents[counter]); counter += 1
                }
                _ => panic!("Invalid Java string")
            }
        }
    }
    pub fn as_vec(&self) -> &Vec<u8> {
        &(self.contents)
    }
    pub fn as_ptr(&self) -> *const ::libc::c_char {
        self.contents.as_ptr() as *const ::libc::c_char
    }
    pub unsafe fn from_raw_vec (data: Vec<u8>) -> Self {
        JavaChars { contents: data, }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "trace_log")]
extern crate env_logger;

extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate base64;
extern crate rustyline;

use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::analysis::sccp;
use radeco_lib::backend::lang_c::c_cfg::CCFGVerifier;
use radeco_lib::backend::lang_c::c_cfg_builder;
use radeco_lib::frontend::radeco_containers::*;
use radeco_lib::middle::{dce, dot};
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::regfile::SubRegisterFile;
use radeco_lib::middle::ssa::ssastorage::SSAStorage;
use radeco_lib::middle::ssa::verifier;
use rustyline::Editor;

use rustyline::error::ReadlineError;

use std::collections::HashMap;
use std::process;
use std::str;
use std::sync::Arc;

// On unix platforms you can use ANSI escape sequences
#[cfg(unix)]
const PROMPT: &'static str = "\x1b[1;32m>>\x1b[0m ";

// Windows consoles typically don't support ANSI escape sequences out
// of the box
#[cfg(windows)]
const PROMPT: &'static str = ">> ";

fn main() {
    let mut rl = Editor::<()>::new();
    let mut proj = None;
    loop {
        let readline = rl.readline(PROMPT);
        match readline {
            Ok(line) => {
                let mut terms = line.split_whitespace();
                let o1 = terms.next();
                let o2 = terms.next();
                cmd(o1, o2, &mut proj);
            }
            Err(ReadlineError::Interrupted) |
            Err(ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}

mod command {
    pub const LOAD: &'static str = "load";
    pub const FNLIST: &'static str = "fn_list";
    pub const ANALYZE: &'static str = "analyze";
    pub const DOT: &'static str = "dot";
    pub const IR: &'static str = "ir";
    pub const DECOMPILE: &'static str = "decompile";
}

fn cmd(op1: Option<&str>, op2: Option<&str>, proj_opt: &mut Option<RadecoProject>) {
    match (op1, op2) {
        (Some(command::LOAD), Some(s)) => {
            let mut p = ProjectLoader::new().path(s).load();
            let regfile = p.regfile().clone();
            for mut xy in p.iter_mut() {
                analyze_mod(regfile.clone(), xy.module);
            }
            *proj_opt = Some(p);
            return;
        }
        _ => {}
    };
    let mut proj = match proj_opt {
        Some(proj) => proj,
        None => {
            println!("Load a project first");
            return;
        }
    };
    match (op1, op2) {
        (Some(command::ANALYZE), Some("*")) => {
            let rfns = proj.iter_mut().map(|i| i.module).flat_map(|rmod| {
                rmod.functions.values_mut()
            });
            for rfn in rfns {
                analyze(rfn);
            }
        }
        (Some(command::FNLIST), _) => {
            let funcs = fn_list(&proj);
            println!("{}", funcs.join("\n"));
        }
        (Some(command::ANALYZE), Some(f)) => {
            if let Some(rfn) = get_function_mut(f, &mut proj) {
                analyze(rfn);
            } else {
                println!("{} is not found", f);
            }
        }
        (Some(command::DOT), Some(f)) => {
            if let Some(rfn) = get_function(f, &proj) {
                println!("{}", emit_dot(rfn.ssa()));
            } else {
                println!("{} is not found", f);
            }
        }
        (Some(command::IR), Some(f)) => {
            if let Some(rfn) = get_function(f, &proj) {
                println!("{}", emit_ir(rfn));
            } else {
                println!("{} is not found", f);
            }
        }
        (Some(command::DECOMPILE), Some(f)) => {
            if let Some(rfn) = get_function(f, &proj) {
                let rmod = proj.iter().map(|i| i.module).next().unwrap();
                let func_name_map = rmod.functions
                    .iter()
                    .map(|(&addr, f)| (addr, f.name.to_string()))
                    .collect();
                let strings = rmod.strings()
                    .iter()
                    .filter(|ref s| s.vaddr.is_some() && s.string.is_some())
                    .cloned()
                    .map(|s| {
                        let (addr, _s) = (s.vaddr.unwrap(), s.string.unwrap());
                        let bytes = base64::decode(&_s).unwrap_or(Vec::new());
                        let ret_string = match str::from_utf8(bytes.as_slice()) {
                            Ok(v) => v.to_string(),
                            Err(_e) => _s,
                        };
                        (addr, ret_string)
                    })
                    .collect();
                println!("{}", decompile(rfn, &func_name_map, &strings));
            } else {
                println!("{} is not found", f);
            }
        }
        _ => {}
    }
}

fn fn_list(proj: &RadecoProject) -> Vec<String> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .map(|s| s.name.to_string())
        .collect()
}

fn get_function<'a>(name: &str, proj: &'a RadecoProject) -> Option<&'a RadecoFunction> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .filter(|rfn| rfn.name == name)
        .next()
}

fn get_function_mut<'a>(name: &str, proj: &'a mut RadecoProject) -> Option<&'a mut RadecoFunction> {
    proj.iter_mut()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values_mut())
        .filter(|rfn| rfn.name == name)
        .next()
}

fn analyze_mod(regfile: Arc<SubRegisterFile>, rmod: &mut RadecoModule) {
    // Analyze preserved for all functions.
    {
        println!("[*] Fixing Callee Information");
        let bp_name = regfile.get_name_by_alias(&"BP".to_string());
        let bp_name = bp_name.map(|s| s.to_owned());
        let sp_name = regfile.get_name_by_alias(&"SP".to_string());
        let sp_name = sp_name.map(|s| s.to_owned());
        let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
        callfixer.rounded_analysis();
    }

    // Fix call sites
    radeco_lib::analysis::functions::fix_ssa_opcalls::go(rmod);

    // Infer calling conventions
    radeco_lib::analysis::functions::infer_regusage::run(rmod, &*regfile);
}

fn analyze(rfn: &mut RadecoFunction) {
    println!("[+] Analyzing: {} @ {:#x}", rfn.name, rfn.offset);
    {
        println!("  [*] Eliminating Dead Code");
        dce::collect(rfn.ssa_mut());
    }
    let mut ssa = {
        // Constant Propagation (sccp)
        println!("  [*] Propagating Constants");
        let mut analyzer = sccp::Analyzer::new(rfn.ssa_mut());
        analyzer.analyze();
        analyzer.emit_ssa()
    };
    {
        println!("  [*] Eliminating More DeadCode");
        dce::collect(&mut ssa);
    }
    *rfn.ssa_mut() = ssa;
    {
        // Common SubExpression Elimination (cse)
        println!("  [*] Eliminating Common SubExpressions");
        let mut cse = CSE::new(rfn.ssa_mut());
        cse.run();
    }
    {
        // Verify SSA
        println!("  [*] Verifying SSA's Validity");
        match verifier::verify(rfn.ssa()) {
            Err(e) => {
                println!("  [*] Found Error: {}", e);
                process::exit(255);
            }
            Ok(_) => {}
        }
    }
}

fn emit_ir(rfn: &RadecoFunction) -> String {
    println!("  [*] Writing out IR");
    let mut res = String::new();
    ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
    res
}

fn emit_dot(ssa: &SSAStorage) -> String {
    dot::emit_dot(ssa)
}

fn decompile(
    rfn: &RadecoFunction,
    func_name_map: &HashMap<u64, String>,
    strings: &HashMap<u64, String>,
) -> String {
    let c_cfg = c_cfg_builder::recover_c_cfg(rfn, func_name_map, strings);
    if let Err(err) = CCFGVerifier::verify(&c_cfg) {
        println!("CCFG verification failed");
        println!("{}", err);
    }
    c_cfg.to_c_ast().print()
}
<commit_msg>Add TODO comments<commit_after>#[cfg(feature = "trace_log")]
extern crate env_logger;

extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate base64;
extern crate rustyline;

use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::analysis::sccp;
use radeco_lib::backend::lang_c::c_cfg::CCFGVerifier;
use radeco_lib::backend::lang_c::c_cfg_builder;
use radeco_lib::frontend::radeco_containers::*;
use radeco_lib::middle::{dce, dot};
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::regfile::SubRegisterFile;
use radeco_lib::middle::ssa::ssastorage::SSAStorage;
use radeco_lib::middle::ssa::verifier;
use rustyline::Editor;

use rustyline::error::ReadlineError;

use std::collections::HashMap;
use std::process;
use std::str;
use std::sync::Arc;

// On unix platforms you can use ANSI escape sequences
#[cfg(unix)]
const PROMPT: &'static str = "\x1b[1;32m>>\x1b[0m ";

// Windows consoles typically don't support ANSI escape sequences out
// of the box
#[cfg(windows)]
const PROMPT: &'static str = ">> ";

fn main() {
    let mut rl = Editor::<()>::new();
    let mut proj = None;
    loop {
        let readline = rl.readline(PROMPT);
        match readline {
            Ok(line) => {
                let mut terms = line.split_whitespace();
                let o1 = terms.next();
                let o2 = terms.next();
                cmd(o1, o2, &mut proj);
            }
            Err(ReadlineError::Interrupted) |
            Err(ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}

mod command {
    pub const LOAD: &'static str = "load";
    pub const FNLIST: &'static str = "fn_list";
    pub const ANALYZE: &'static str = "analyze";
    pub const DOT: &'static str = "dot";
    pub const IR: &'static str = "ir";
    pub const DECOMPILE: &'static str = "decompile";
}

fn cmd(op1: Option<&str>, op2: Option<&str>, proj_opt: &mut Option<RadecoProject>) {
    match (op1, op2) {
        (Some(command::LOAD), Some(s)) => {
            let mut p = ProjectLoader::new().path(s).load();
            let regfile = p.regfile().clone();
            for mut xy in p.iter_mut() {
                analyze_mod(regfile.clone(), xy.module);
            }
            *proj_opt = Some(p);
            return;
        }
        _ => {}
    };
    let mut proj = match proj_opt {
        Some(proj) => proj,
        None => {
            println!("Load a project first");
            return;
        }
    };
    match (op1, op2) {
        (Some(command::ANALYZE), Some("*")) => {
            let rfns = proj.iter_mut().map(|i| i.module).flat_map(|rmod| {
                rmod.functions.values_mut()
            });
            for rfn in rfns {
                analyze(rfn);
            }
        }
        (Some(command::FNLIST), _) => {
            let funcs = fn_list(&proj);
            println!("{}", funcs.join("\n"));
        }
        // TODO Show list of dependency information of analyses
        // TODO Add command for individual analyses
        (Some(command::ANALYZE), Some(f)) => {
            if let Some(rfn) = get_function_mut(f, &mut proj) {
                analyze(rfn);
            } else {
                println!("{} is not found", f);
            }
        }
        (Some(command::DOT), Some(f)) => {
            if let Some(rfn) = get_function(f, &proj) {
                println!("{}", emit_dot(rfn.ssa()));
            } else {
                println!("{} is not found", f);
            }
        }
        (Some(command::IR), Some(f)) => {
            if let Some(rfn) = get_function(f, &proj) {
                println!("{}", emit_ir(rfn));
            } else {
                println!("{} is not found", f);
            }
        }
        (Some(command::DECOMPILE), Some(f)) => {
            if let Some(rfn) = get_function(f, &proj) {
                let rmod = proj.iter().map(|i| i.module).next().unwrap();
                let func_name_map = rmod.functions
                    .iter()
                    .map(|(&addr, f)| (addr, f.name.to_string()))
                    .collect();
                let strings = rmod.strings()
                    .iter()
                    .filter(|ref s| s.vaddr.is_some() && s.string.is_some())
                    .cloned()
                    .map(|s| {
                        let (addr, _s) = (s.vaddr.unwrap(), s.string.unwrap());
                        let bytes = base64::decode(&_s).unwrap_or(Vec::new());
                        let ret_string = match str::from_utf8(bytes.as_slice()) {
                            Ok(v) => v.to_string(),
                            Err(_e) => _s,
                        };
                        (addr, ret_string)
                    })
                    .collect();
                println!("{}", decompile(rfn, &func_name_map, &strings));
            } else {
                println!("{} is not found", f);
            }
        }
        _ => {}
    }
}

fn fn_list(proj: &RadecoProject) -> Vec<String> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .map(|s| s.name.to_string())
        .collect()
}

fn get_function<'a>(name: &str, proj: &'a RadecoProject) -> Option<&'a RadecoFunction> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .filter(|rfn| rfn.name == name)
        .next()
}

fn get_function_mut<'a>(name: &str, proj: &'a mut RadecoProject) -> Option<&'a mut RadecoFunction> {
    proj.iter_mut()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values_mut())
        .filter(|rfn| rfn.name == name)
        .next()
}

fn analyze_mod(regfile: Arc<SubRegisterFile>, rmod: &mut RadecoModule) {
    // Analyze preserved for all functions.
    {
        println!("[*] Fixing Callee Information");
        let bp_name = regfile.get_name_by_alias(&"BP".to_string());
        let bp_name = bp_name.map(|s| s.to_owned());
        let sp_name = regfile.get_name_by_alias(&"SP".to_string());
        let sp_name = sp_name.map(|s| s.to_owned());
        let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
        callfixer.rounded_analysis();
    }

    // Fix call sites
    radeco_lib::analysis::functions::fix_ssa_opcalls::go(rmod);

    // Infer calling conventions
    radeco_lib::analysis::functions::infer_regusage::run(rmod, &*regfile);
}

fn analyze(rfn: &mut RadecoFunction) {
    println!("[+] Analyzing: {} @ {:#x}", rfn.name, rfn.offset);
    {
        println!("  [*] Eliminating Dead Code");
        dce::collect(rfn.ssa_mut());
    }
    let mut ssa = {
        // Constant Propagation (sccp)
        println!("  [*] Propagating Constants");
        let mut analyzer = sccp::Analyzer::new(rfn.ssa_mut());
        analyzer.analyze();
        analyzer.emit_ssa()
    };
    {
        println!("  [*] Eliminating More DeadCode");
        dce::collect(&mut ssa);
    }
    *rfn.ssa_mut() = ssa;
    {
        // Common SubExpression Elimination (cse)
        println!("  [*] Eliminating Common SubExpressions");
        let mut cse = CSE::new(rfn.ssa_mut());
        cse.run();
    }
    {
        // Verify SSA
        println!("  [*] Verifying SSA's Validity");
        match verifier::verify(rfn.ssa()) {
            Err(e) => {
                println!("  [*] Found Error: {}", e);
                process::exit(255);
            }
            Ok(_) => {}
        }
    }
}

fn emit_ir(rfn: &RadecoFunction) -> String {
    println!("  [*] Writing out IR");
    let mut res = String::new();
    ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
    res
}

fn emit_dot(ssa: &SSAStorage) -> String {
    dot::emit_dot(ssa)
}

fn decompile(
    rfn: &RadecoFunction,
    func_name_map: &HashMap<u64, String>,
    strings: &HashMap<u64, String>,
) -> String {
    let c_cfg = c_cfg_builder::recover_c_cfg(rfn, func_name_map, strings);
    if let Err(err) = CCFGVerifier::verify(&c_cfg) {
        println!("CCFG verification failed");
        println!("{}", err);
    }
    c_cfg.to_c_ast().print()
}
<|endoftext|>