Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 43 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,34 @@ on:
- "*"

jobs:
build-native:
name: Build (Host)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
toolchain: [stable, nightly]
steps:
- name: Checkout Commit
uses: actions/checkout@v6

- name: Install Rust
run: |
rustup toolchain install ${{ matrix.toolchain }} --profile minimal
rustup default ${{ matrix.toolchain }}

- name: Build (No Default Features)
run: |
cargo build --no-default-features

- name: Build (Default Features)
run: |
cargo build

- name: Build (All Features)
run: |
cargo build --all-features

build:
runs-on: ubuntu-latest
strategy:
Expand All @@ -21,10 +49,10 @@ jobs:
uses: actions/checkout@v6

- name: Install Rust
uses: hecrj/setup-rust-action@v2
with:
targets: ${{ matrix.target }}
rust-version: ${{ matrix.toolchain }}
run: |
rustup toolchain install ${{ matrix.toolchain }} --profile minimal
rustup default ${{ matrix.toolchain }}
rustup target add ${{ matrix.target }}

- name: Build (No Default Features)
run: |
Expand All @@ -46,7 +74,9 @@ jobs:
uses: actions/checkout@v6

- name: Install Rust
uses: hecrj/setup-rust-action@v2
run: |
rustup toolchain install stable --profile minimal
rustup default stable

- name: Test (All Features)
run: |
Expand All @@ -60,9 +90,10 @@ jobs:
uses: actions/checkout@v6

- name: Install Rust
uses: hecrj/setup-rust-action@v2
with:
components: clippy
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup component add clippy

- name: Run Clippy
run: cargo clippy --all-features
Expand All @@ -75,9 +106,10 @@ jobs:
uses: actions/checkout@v6

- name: Install Rust
uses: hecrj/setup-rust-action@v2
with:
components: rustfmt
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup component add rustfmt

- name: Run cargo fmt
run: cargo fmt -- --check || true
8 changes: 3 additions & 5 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@ jobs:
uses: actions/checkout@v6

- name: Install Rust
uses: hecrj/setup-rust-action@v2
with:
components: rust-docs
rust-version: nightly
targets: wasm32-wasip1
run: |
rustup toolchain install nightly --profile minimal --component rust-docs --target wasm32-wasip1
rustup default nightly

- name: Build docs
run: RUSTDOCFLAGS="--cfg doc_cfg" cargo doc --all-features --target wasm32-wasip1
Expand Down
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ time = { version = "0.3.5", default-features = false }
libm = { version = "0.2.7", optional = true }
wasi = { version = "0.11.0+wasi-snapshot-preview1", default-features = false }

[target.'cfg(not(target_family = "wasm"))'.dependencies]
indexmap = "2.0.2"
proc-maps = { version = "0.4.0", default-features = false }
read-process-memory = { version = "0.1.4", default-features = false }
sysinfo = { version = "0.39.3", default-features = false, features = [
"multithread",
"system",
] }

[features]
alloc = []
derive = ["asr-derive"]
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ runtime.

[API Documentation](https://livesplit.org/asr/asr/)

Auto splitters can be compiled either to WebAssembly for sandboxed execution or
as native programs. WebAssembly builds use the runtime's import API. Native
builds interact with processes directly and receive timer integration through
the `asr::Runtime` trait.

## Native Execution

On non-WebAssembly targets, create an `asr::Runner` with an implementation of
`asr::Runtime` and run the auto splitter's asynchronous main function:

```rust
let mut runner = asr::Runner::new(my_runtime);
runner.run(auto_splitter());
```

The runner owns settings and tick scheduling. The runtime implementation
connects timer operations and logging to the embedding application. Existing
auto splitter code can continue using `Process`, `asr::timer`, `asr::settings`,
and the asynchronous helpers without being generic over the runtime.

There are two ways of defining an auto splitter.

## Defining an `update` function
Expand Down
2 changes: 1 addition & 1 deletion src/file_format/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ struct SymTab64 {
///
/// By using this function, the user must be aware of the following limitations:
/// - Only allocatable symbols and symbols used by the dynamic linker are exported
/// (.symtab is not loaded in memory at runtime)
/// (.symtab is not loaded in memory at runtime)
/// - Only 64-bit ELFs are supported (an empty iterator will be returned for 32-bit ELFs)
pub fn symbols(
process: &Process,
Expand Down
33 changes: 15 additions & 18 deletions src/file_format/macho.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! Support for parsing Mach-O format

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
use core::iter::FusedIterator;

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
use alloc::collections::BTreeMap;

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
use crate::{string::ArrayCString, Error};
use crate::{Address, PointerSize, Process};

Expand Down Expand Up @@ -36,18 +36,15 @@ fn scan_macho_page(process: &Process, range: (Address, u64)) -> Option<Address>
let first_page = addr + distance_to_page;
for i in 0..((len - distance_to_page) / PAGE_SIZE) {
let a = first_page + (i * PAGE_SIZE);
match process.read::<u32>(a) {
Ok(MH_MAGIC_64 | MH_CIGAM_64 | MH_MAGIC_32 | MH_CIGAM_32) => {
return Some(a);
}
_ => (),
if let Ok(MH_MAGIC_64 | MH_CIGAM_64 | MH_MAGIC_32 | MH_CIGAM_32) = process.read::<u32>(a) {
return Some(a);
}
}
None
}

/// Scans the range for pages that begin with Mach-O Magic
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
fn scan_macho_pages(
process: &Process,
range: (Address, u64),
Expand All @@ -72,13 +69,13 @@ fn scan_macho_pages(
// Constants for the cmd field of load commands, the type
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/EXTERNAL_HEADERS/mach-o/loader.h.auto.html
/// link-edit stab symbol table info
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
const LC_SYMTAB: u32 = 0x2;
/// 64-bit segment of this file to be mapped
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
const LC_SEGMENT_64: u32 = 0x19;

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
struct MachOFormatOffsets {
number_of_commands: u32,
load_commands: u32,
Expand All @@ -92,7 +89,7 @@ struct MachOFormatOffsets {
segcmd64_fileoff: u32,
}

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
impl MachOFormatOffsets {
const fn new() -> Self {
// offsets taken from:
Expand All @@ -114,15 +111,15 @@ impl MachOFormatOffsets {
}

/// A symbol exported into the current module.
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
pub struct Symbol {
/// The address associated with the current function
pub address: Address,
/// The address storing the name of the current function
name_addr: Address,
}

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
impl Symbol {
/// Tries to retrieve the name of the current function
pub fn get_name<const CAP: usize>(
Expand All @@ -135,15 +132,15 @@ impl Symbol {

/// Iterates over the exported symbols for a given module.
/// Only 64-bit Mach-O format is supported
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
pub fn symbols(process: &Process, range: (Address, u64)) -> impl FusedIterator<Item = Symbol> + '_ {
scan_macho_pages(process, range)
.filter_map(|page| macho_page_symbols(process, page))
.flatten()
.fuse()
}

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
fn macho_page_symbols(
process: &Process,
page: Address,
Expand Down Expand Up @@ -197,7 +194,7 @@ fn macho_page_symbols(
)
}

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
fn fileoff_to_vmaddr(map: &BTreeMap<u64, u64>, fileoff: u64) -> u64 {
map.iter()
.filter(|(&k, _)| k <= fileoff)
Expand Down
6 changes: 3 additions & 3 deletions src/file_format/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,15 +418,15 @@ impl FileVersion {
}

impl DataEntry {
fn is_rt_version(&self) -> bool {
const fn is_rt_version(&self) -> bool {
self.id == 0x10
}

fn is_directory(&self) -> bool {
const fn is_directory(&self) -> bool {
(self.offset & 0x80000000) != 0
}

fn get_offset(&self) -> u32 {
const fn get_offset(&self) -> u32 {
self.offset & 0x7FFFFFFF
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/future/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ mod time;
#[cfg(target_os = "wasi")]
pub use self::time::*;

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
mod task;
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
pub use self::task::*;

/// A future that yields back to the runtime and continues on the next tick. It's
Expand Down
12 changes: 6 additions & 6 deletions src/game_engine/unity/mono/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Support for attaching to Unity games that are using the standard Mono
//! backend.

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
use crate::file_format::macho;
use crate::{
file_format::{elf, pe},
Expand Down Expand Up @@ -54,11 +54,11 @@ impl Module {
let (module_range, format) = [
("mono.dll", BinaryFormat::PE),
("libmono.so", BinaryFormat::ELF),
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
("libmono.0.dylib", BinaryFormat::MachO),
("mono-2.0-bdwgc.dll", BinaryFormat::PE),
("libmonobdwgc-2.0.so", BinaryFormat::ELF),
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
("libmonobdwgc-2.0.dylib", BinaryFormat::MachO),
]
.into_iter()
Expand All @@ -69,7 +69,7 @@ impl Module {
let pointer_size = match format {
BinaryFormat::PE => pe::MachineType::read(process, mono_module)?.pointer_size()?,
BinaryFormat::ELF => elf::pointer_size(process, mono_module)?,
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
BinaryFormat::MachO => macho::pointer_size(process, module_range)?,
#[allow(unreachable_patterns)]
_ => return None,
Expand All @@ -96,7 +96,7 @@ impl Module {
})?
.address
}
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
BinaryFormat::MachO => {
macho::symbols(process, module_range)
.find(|symbol| {
Expand Down Expand Up @@ -125,7 +125,7 @@ impl Module {
.map(|addr| addr + 3)
.and_then(|addr| Some(addr + 0x4 + process.read::<i32>(addr).ok()?))?
}
#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
(PointerSize::Bit64, BinaryFormat::MachO) => {
const SIG_MONO_X86_64_MACHO: Signature<3> = Signature::new("48 8B 3D");
// 57 0f 00 d0 adrp x23,(page + 0x1ea000)
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![no_std]
#![cfg_attr(target_family = "wasm", no_std)]
#![warn(
clippy::complexity,
clippy::correctness,
Expand Down Expand Up @@ -124,7 +124,7 @@
//! }
//! ```

#[cfg(feature = "alloc")]
#[cfg(any(feature = "alloc", not(target_family = "wasm")))]
extern crate alloc;

mod primitives;
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ pub use memory_range::*;
pub use process::*;

mod memory_range;
#[cfg(not(target_family = "wasm"))]
mod native;
mod process;
mod sys;

pub mod settings;
pub mod timer;

#[cfg(not(target_family = "wasm"))]
pub use native::*;

/// An error returned by a runtime function.
#[derive(Debug)]
#[non_exhaustive]
Expand Down
Loading