Skip to content
Closed
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ test.zip*
__pycache__
node_modules/
.cache/
.zig*
CACHEDIR.TARGET
.package-cache
.cargo/registry
65 changes: 65 additions & 0 deletions crates/libmwemu/src/api/abi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use crate::emu::Emu;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ApiAbi {
Aarch64,
X86_64,
}

impl ApiAbi {
#[inline]
pub fn from_emu(emu: &Emu) -> Self {
if emu.cfg.arch.is_x64() {
Self::X86_64
} else {
Self::Aarch64
}
}

#[inline]
pub fn arg(self, emu: &Emu, idx: usize) -> u64 {
match self {
Self::Aarch64 => {
let regs = emu.regs_aarch64();
regs.x.get(idx).copied().unwrap_or_else(|| {
panic!("AArch64 API arg{} is out of range", idx);
})
}
Self::X86_64 => match idx {
0 => {
let regs = emu.regs();
regs.rdi
}
1 => {
let regs = emu.regs();
regs.rsi
}
2 => {
let regs = emu.regs();
regs.rdx
}
3 => {
let regs = emu.regs();
regs.rcx
}
4 => {
let regs = emu.regs();
regs.r8
}
5 => {
let regs = emu.regs();
regs.r9
}
_ => panic!("x86_64 API arg{} is out of range", idx),
},
}
}

#[inline]
pub fn set_ret(self, emu: &mut Emu, value: u64) {
match self {
Self::Aarch64 => emu.regs_aarch64_mut().x[0] = value,
Self::X86_64 => emu.regs_mut().rax = value,
}
}
}
221 changes: 183 additions & 38 deletions crates/libmwemu/src/api/linux/libc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#[path = "../abi.rs"]
mod abi;

use crate::emu::Emu;
use abi::ApiAbi;

pub fn gateway(symbol: &str, emu: &mut Emu) {
match symbol {
"__libc_start_main" => api_libc_start_main(emu),
"__cxa_finalize" => api_cxa_finalize(emu),
"__cxa_atexit" => api_cxa_atexit(emu),
"__gmon_start__" => api_gmon_start(emu),
"printf" => api_printf(emu),
"fprintf" => api_fprintf(emu),
"puts" => api_puts(emu),
Expand Down Expand Up @@ -29,115 +37,252 @@ pub fn gateway(symbol: &str, emu: &mut Emu) {
}
}

fn api_libc_start_main(emu: &mut Emu) {
let abi = ApiAbi::from_emu(emu);
let main_fn = abi.arg(emu, 0);
let argc = abi.arg(emu, 1);
let argv = abi.arg(emu, 2);
let envp = argv.wrapping_add((argc + 1) * 8);

log::info!(
"{}** {} Linux API __libc_start_main(main=0x{:x}, argc={}, argv=0x{:x}) {}",
emu.colors.light_red,
emu.pos,
main_fn,
argc,
argv,
emu.colors.nc
);

if !emu.cfg.arch.is_x64() {
log::warn!(
"linuxapi libc: __libc_start_main bridge is only implemented for x86_64 right now"
);
abi.set_ret(emu, 0);
return;
}

match emu.linux_call64(main_fn, &[argc, argv, envp]) {
Ok(status) => {
// Model glibc startup minimally: after main returns, terminate the
// emulated process through the existing exit path.
emu.regs_mut().rdi = status;
api_exit(emu);
}
Err(err) => {
log::warn!("linuxapi libc: __libc_start_main failed to run main: {}", err);
emu.stop();
}
}
}

fn api_printf(emu: &mut Emu) {
let fmt_addr = emu.regs_aarch64().x[0];
let abi = ApiAbi::from_emu(emu);
let fmt_addr = abi.arg(emu, 0);
let fmt = emu.maps.read_string(fmt_addr);
log::info!(
"{}** {} Linux API printf(\"{}\") {}",
emu.colors.light_red, emu.pos, fmt, emu.colors.nc
emu.colors.light_red,
emu.pos,
fmt,
emu.colors.nc
);
emu.regs_aarch64_mut().x[0] = fmt.len() as u64;
abi.set_ret(emu, fmt.len() as u64);
}

fn api_fprintf(emu: &mut Emu) {
let _stream = emu.regs_aarch64().x[0];
let fmt_addr = emu.regs_aarch64().x[1];
let abi = ApiAbi::from_emu(emu);
let _stream = abi.arg(emu, 0);
let fmt_addr = abi.arg(emu, 1);
let fmt = emu.maps.read_string(fmt_addr);
log::info!(
"{}** {} Linux API fprintf(\"{}\") {}",
emu.colors.light_red, emu.pos, fmt, emu.colors.nc
emu.colors.light_red,
emu.pos,
fmt,
emu.colors.nc
);
emu.regs_aarch64_mut().x[0] = fmt.len() as u64;
abi.set_ret(emu, fmt.len() as u64);
}

fn api_puts(emu: &mut Emu) {
let s_addr = emu.regs_aarch64().x[0];
let abi = ApiAbi::from_emu(emu);
let s_addr = abi.arg(emu, 0);
let s = emu.maps.read_string(s_addr);
log::info!(
"{}** {} Linux API puts(\"{}\") {}",
emu.colors.light_red, emu.pos, s, emu.colors.nc
emu.colors.light_red,
emu.pos,
s,
emu.colors.nc
);
emu.regs_aarch64_mut().x[0] = 0;
abi.set_ret(emu, 0);
}

fn api_putchar(emu: &mut Emu) {
let c = emu.regs_aarch64().x[0] as u8 as char;
let abi = ApiAbi::from_emu(emu);
let c = abi.arg(emu, 0) as u8 as char;
log::info!(
"{}** {} Linux API putchar('{}') {}",
emu.colors.light_red, emu.pos, c, emu.colors.nc
emu.colors.light_red,
emu.pos,
c,
emu.colors.nc
);
emu.regs_aarch64_mut().x[0] = c as u64;
abi.set_ret(emu, c as u64);
}

fn api_exit(emu: &mut Emu) {
let status = emu.regs_aarch64().x[0];
let abi = ApiAbi::from_emu(emu);
let status = abi.arg(emu, 0);
log::info!(
"{}** {} Linux API exit({}) {}",
emu.colors.light_red, emu.pos, status, emu.colors.nc
emu.colors.light_red,
emu.pos,
status,
emu.colors.nc
);
emu.stop();
}

fn api_abort(emu: &mut Emu) {
log::info!(
"{}** {} Linux API abort() {}",
emu.colors.light_red, emu.pos, emu.colors.nc
emu.colors.light_red,
emu.pos,
emu.colors.nc
);
emu.stop();
}

fn api_cxa_finalize(emu: &mut Emu) {
let abi = ApiAbi::from_emu(emu);
let dso_handle = abi.arg(emu, 0);
log::info!(
"{}** {} Linux API __cxa_finalize(0x{:x}) {}",
emu.colors.light_red,
emu.pos,
dso_handle,
emu.colors.nc
);
abi.set_ret(emu, 0);
}

fn api_cxa_atexit(emu: &mut Emu) {
let abi = ApiAbi::from_emu(emu);
let func = abi.arg(emu, 0);
let arg = abi.arg(emu, 1);
let dso_handle = abi.arg(emu, 2);
log::info!(
"{}** {} Linux API __cxa_atexit(func=0x{:x}, arg=0x{:x}, dso=0x{:x}) {}",
emu.colors.light_red,
emu.pos,
func,
arg,
dso_handle,
emu.colors.nc
);
abi.set_ret(emu, 0);
}

fn api_gmon_start(emu: &mut Emu) {
log::info!(
"{}** {} Linux API __gmon_start__() {}",
emu.colors.light_red,
emu.pos,
emu.colors.nc
);
let abi = ApiAbi::from_emu(emu);
abi.set_ret(emu, 0);
}

fn api_malloc(emu: &mut Emu) {
let size = emu.regs_aarch64().x[0];
let abi = ApiAbi::from_emu(emu);
let size = abi.arg(emu, 0);
log::info!(
"{}** {} Linux API malloc({}) {}",
emu.colors.light_red, emu.pos, size, emu.colors.nc
emu.colors.light_red,
emu.pos,
size,
emu.colors.nc
);
todo!("malloc({})", size);
}

fn api_calloc(emu: &mut Emu) { todo!("calloc"); }
fn api_realloc(emu: &mut Emu) { todo!("realloc"); }
fn api_calloc(emu: &mut Emu) {
todo!("calloc");
}
fn api_realloc(emu: &mut Emu) {
todo!("realloc");
}

fn api_free(emu: &mut Emu) {
let ptr = emu.regs_aarch64().x[0];
let abi = ApiAbi::from_emu(emu);
let ptr = abi.arg(emu, 0);
log::info!(
"{}** {} Linux API free(0x{:x}) {}",
emu.colors.light_red, emu.pos, ptr, emu.colors.nc
emu.colors.light_red,
emu.pos,
ptr,
emu.colors.nc
);
// no-op for now
}

fn api_write(emu: &mut Emu) {
let fd = emu.regs_aarch64().x[0];
let buf = emu.regs_aarch64().x[1];
let count = emu.regs_aarch64().x[2];
let abi = ApiAbi::from_emu(emu);
let fd = abi.arg(emu, 0);
let buf = abi.arg(emu, 1);
let count = abi.arg(emu, 2);
let s = emu.maps.read_string(buf);
log::info!(
"{}** {} Linux API write(fd={}, \"{}\", {}) {}",
emu.colors.light_red, emu.pos, fd, s, count, emu.colors.nc
emu.colors.light_red,
emu.pos,
fd,
s,
count,
emu.colors.nc
);
emu.regs_aarch64_mut().x[0] = count;
abi.set_ret(emu, count);
}

fn api_read(emu: &mut Emu) { todo!("read"); }
fn api_open(emu: &mut Emu) { todo!("open"); }
fn api_read(emu: &mut Emu) {
todo!("read");
}
fn api_open(emu: &mut Emu) {
todo!("open");
}

fn api_close(emu: &mut Emu) {
let fd = emu.regs_aarch64().x[0];
let abi = ApiAbi::from_emu(emu);
let fd = abi.arg(emu, 0);
log::info!(
"{}** {} Linux API close(fd={}) {}",
emu.colors.light_red, emu.pos, fd, emu.colors.nc
emu.colors.light_red,
emu.pos,
fd,
emu.colors.nc
);
emu.regs_aarch64_mut().x[0] = 0;
abi.set_ret(emu, 0);
}

fn api_strlen(emu: &mut Emu) {
let s_addr = emu.regs_aarch64().x[0];
let abi = ApiAbi::from_emu(emu);
let s_addr = abi.arg(emu, 0);
let s = emu.maps.read_string(s_addr);
emu.regs_aarch64_mut().x[0] = s.len() as u64;
abi.set_ret(emu, s.len() as u64);
}

fn api_memcpy(emu: &mut Emu) { todo!("memcpy"); }
fn api_memset(emu: &mut Emu) { todo!("memset"); }
fn api_mmap(emu: &mut Emu) { todo!("mmap"); }
fn api_munmap(emu: &mut Emu) { todo!("munmap"); }
fn api_memcpy(emu: &mut Emu) {
todo!("memcpy");
}
fn api_memset(emu: &mut Emu) {
todo!("memset");
}
fn api_mmap(emu: &mut Emu) {
todo!("mmap");
}
fn api_munmap(emu: &mut Emu) {
todo!("munmap");
}
Loading
Loading