From 0f6c365733c09cc8cc924552abe4c711919db7f2 Mon Sep 17 00:00:00 2001 From: jam1garner Date: Wed, 8 Apr 2020 22:39:10 -0400 Subject: [PATCH] Flesh out skyline::libc --- link.T | 14 +- skyline/skyline_macro/src/lib.rs | 79 ++++----- skyline/src/build.rs | 5 +- skyline/src/hooks.rs | 44 +++-- skyline/src/lib.rs | 3 +- skyline/src/libc.rs | 279 ++++++++++++++++++++++++++++++- src/lib.rs | 6 +- 7 files changed, 357 insertions(+), 73 deletions(-) diff --git a/link.T b/link.T index b67b4ea..2d94f43 100644 --- a/link.T +++ b/link.T @@ -17,7 +17,7 @@ SECTIONS .text : ALIGN(0x1000) { HIDDEN(__text_start = .); - KEEP(*(.nro_header)) + *(.nro_header) KEEP(*(.text.jmp)) . = 0x80; @@ -32,7 +32,17 @@ SECTIONS . = ALIGN(0x1000); .module_name : { KEEP (*(.rodata.module_name)) } :rodata - .rodata : { *(.rodata .rodata.*) } :rodata + + .hooks : { + __hook_array_start = .; + *(.rodata.hooks) + __hook_array_end = .; + } :rodata + + .rodata : { + *(.rodata .rodata.*) + } :rodata + .mod0 : { KEEP(crt0.nso.o(.data.mod0)) KEEP(crt0.nro.o(.data.mod0)) diff --git a/skyline/skyline_macro/src/lib.rs b/skyline/skyline_macro/src/lib.rs index 8365463..50cc9d6 100644 --- a/skyline/skyline_macro/src/lib.rs +++ b/skyline/skyline_macro/src/lib.rs @@ -1,8 +1,7 @@ use quote::{ToTokens, quote}; use proc_macro::TokenStream; -use syn::{parse_macro_input, token, Token, Ident, Path, AttrStyle, punctuated::Punctuated}; +use syn::{parse_macro_input, token, Ident, AttrStyle}; use proc_macro2::{Span, TokenStream as TokenStream2}; -use syn::parse::Parser; fn new_attr(attr_name: &str) -> syn::Attribute { @@ -38,66 +37,50 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn hook(_: TokenStream, input: TokenStream) -> TokenStream { - let mod_fn = parse_macro_input!(input as syn::ItemFn); + let mut mod_fn = parse_macro_input!(input as syn::ItemFn); let mut output = TokenStream2::new(); + // #[no_mangle] + mod_fn.attrs.push( + new_attr("no_mangle") + ); + + // extern "C" + mod_fn.sig.abi = Some(syn::Abi { + extern_token: syn::token::Extern { span: Span::call_site() }, + name: Some(syn::LitStr::new("C", Span::call_site())) + }); + mod_fn.to_tokens(&mut output); - let ident = quote::format_ident!( + let mod_fn = mod_fn.sig.ident; + + let info = quote::format_ident!( "{}_skyline_internal_hook_info", - mod_fn.sig.ident + mod_fn + ); + + let hook = quote::format_ident!( + "{}_skyline_internal_hook", + mod_fn ); quote!( - #[allow(non_upper_case_globals)] - const #ident: ::skyline::hooks::HookInfo = ::skyline::hooks::HookInfo { + /*#[allow(non_upper_case_globals)] + static #info: ::skyline::hooks::HookInfo = ::skyline::hooks::HookInfo { name: None, + fn_name: stringify!(#mod_fn), offset: None, symbol: None, inline: false }; + #[allow(non_upper_case_globals)] + #[link_section = ".rodata.hooks"] + static #hook: ::skyline::hooks::Hook = ::skyline::hooks::Hook{ + ptr: #mod_fn as *const (), + info: &#info + };*/ ).to_tokens(&mut output); output.into() } - -fn parse_hook_fns(input: TokenStream) -> syn::Result> { - Ok( - Punctuated::::parse_terminated - .parse(input)? - .into_iter() - .collect() - ) -} - -fn concat_path(path: &Path) -> Path { - let mut path = path.clone(); - - let last = path.segments.iter_mut().last().unwrap(); - - last.ident = quote::format_ident!("{}_skyline_internal_hook_info", last.ident); - - path -} - -#[proc_macro] -pub fn hooks(tokens: TokenStream) -> TokenStream { - parse_hook_fns(tokens) - .map(|hook_fns|{ - let hook_fn_infos = hook_fns.iter().map(concat_path); - quote!{ - ::skyline::hooks::Hooks(::skyline::alloc::vec![ - #( - ::skyline::new_hook!( - #hook_fns, - #hook_fn_infos - ) - ),* - ]) - } - }) - .unwrap_or_else(|e|{ - e.to_compile_error() - }) - .into() -} diff --git a/skyline/src/build.rs b/skyline/src/build.rs index 6db7217..270b54d 100644 --- a/skyline/src/build.rs +++ b/skyline/src/build.rs @@ -14,7 +14,10 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { global_asm!(include_str!("mod0.s")); -#[no_mangle] pub extern "C" fn __custom_init() {} +#[no_mangle] pub unsafe extern "C" fn __custom_init() { +} + + #[no_mangle] pub extern "C" fn __custom_fini() {} #[repr(packed)] diff --git a/skyline/src/hooks.rs b/skyline/src/hooks.rs index 0756050..4a75beb 100644 --- a/skyline/src/hooks.rs +++ b/skyline/src/hooks.rs @@ -1,7 +1,7 @@ use crate::alloc::string::String; -use crate::alloc::vec::Vec; pub struct HookInfo { + pub fn_name: &'static str, pub name: Option, pub offset: Option, pub symbol: Option, @@ -10,7 +10,11 @@ pub struct HookInfo { pub struct Hook { pub ptr: *const (), - pub info: &'static HookInfo + pub info: &'static HookInfo, +} + +unsafe impl Sync for Hook { + } impl Hook { @@ -19,21 +23,27 @@ impl Hook { } } -pub struct Hooks(pub Vec); - -impl Hooks { - pub fn install_hooks(&self) { - for hook in &self.0 { - hook.install(); - } - } +#[allow(improper_ctypes)] +extern "C" { + static __hook_array_start: Hook; + static __hook_array_end: Hook; } -#[macro_export] macro_rules! new_hook { - ($path:path, $info:path) => { - $crate::hooks::Hook { - ptr: $path as *const (), - info: &$info - } - }; +pub fn iter_hooks() -> impl Iterator { + let hook_start = unsafe {&__hook_array_start as *const Hook}; + let hook_end = unsafe {&__hook_array_end as *const Hook}; + + let hook_count = ((hook_start as usize) - (hook_end as usize)) / core::mem::size_of::(); + + crate::println!("hook_count: {}", hook_count); + crate::println!("hook_start: {:?}", hook_start); + crate::println!("hook_end: {:?}", hook_start); + + unsafe { + core::slice::from_raw_parts( + hook_start, + hook_count + ) + }.iter() } + diff --git a/skyline/src/lib.rs b/skyline/src/lib.rs index f708c08..bda0e9d 100644 --- a/skyline/src/lib.rs +++ b/skyline/src/lib.rs @@ -9,7 +9,8 @@ pub mod hooks; pub mod build; pub mod extern_alloc; pub use extern_alloc::Allocator; -pub use skyline_macro::{main, hook, hooks}; +pub use skyline_macro::{main, hook}; +pub use hooks::iter_hooks; extern "C" { fn skyline_tcp_send_raw(bytes: *const u8, usize: u64); diff --git a/skyline/src/libc.rs b/skyline/src/libc.rs index 1cda0aa..a26f0b5 100644 --- a/skyline/src/libc.rs +++ b/skyline/src/libc.rs @@ -1,8 +1,64 @@ //! Public exports of libc functions +#![allow(non_camel_case_types)] + pub use core::ffi::c_void; -#[allow(non_camel_case_types)] -type size_t = usize; +pub type c_char = u8; +pub type time_t = i32; +pub type wchar_t = u16; +pub type c_long = i64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type pid_t = i32; +pub type uid_t = u32; +pub type gid_t = u32; +pub type in_addr_t = u32; +pub type in_port_t = u16; + +pub type mode_t = c_uint; +pub type off_t = i64; +#[repr(C)] +pub struct sem_t { // Unverified + __size: [c_char; 16], +} +pub type pthread_key_t = c_uint; + +#[repr(C)] +pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, +} + +#[derive(Debug, Clone, Copy)] +pub enum FILE {} + +#[derive(Debug, Clone, Copy)] +pub enum DIR {} extern "C" { pub fn malloc(size: size_t) -> *const c_void; @@ -11,3 +67,222 @@ extern "C" { pub fn realloc(ptr: *const c_void, size: size_t) -> *const c_void; // fn aligned_alloc(align: usize, size: usize) -> *const c_void; } + +extern "C" { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn isblank(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + + pub fn qsort( + base: *mut c_void, + num: size_t, + size: size_t, + compar: Option< + unsafe extern "C" fn(*const c_void, *const c_void) -> c_int, + >, + ); + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn setvbuf( + stream: *mut FILE, + buffer: *mut c_char, + mode: c_int, + size: size_t, + ) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fwrite( + ptr: *const c_void, + size: size_t, + nobj: size_t, + stream: *mut FILE, + ) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + + pub fn perror(s: *const c_char); + pub fn atoi(s: *const c_char) -> c_int; + + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtol( + s: *const c_char, + endp: *mut *mut c_char, + base: c_int, + ) -> c_long; + + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + + pub fn atexit(cb: extern "C" fn()) -> c_int; + + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy( + dst: *mut c_char, + src: *const c_char, + n: size_t, + ) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat( + s: *mut c_char, + ct: *const c_char, + n: size_t, + ) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp( + s1: *const c_char, + s2: *const c_char, + n: size_t, + ) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs( + dest: *mut c_char, + src: *const wchar_t, + n: size_t, + ) -> size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn wmemchr(cx: *const wchar_t, c: wchar_t, n: size_t) -> *mut wchar_t; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy( + dest: *mut c_void, + src: *const c_void, + n: size_t, + ) -> *mut c_void; + + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn fprintf( + stream: *mut FILE, + format: *const c_char, + ... + ) -> c_int; + pub fn printf(format: *const c_char, ...) -> c_int; + pub fn snprintf( + s: *mut c_char, + n: size_t, + format: *const c_char, + ... + ) -> c_int; + pub fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int; + pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; + + pub fn access(path: *const c_char, amode: c_int) -> c_int; + + pub fn chdir(dir: *const c_char) -> c_int; + + pub fn close(fd: c_int) -> c_int; + + pub fn getpid() -> pid_t; + + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; + + pub fn posix_memalign( + memptr: *mut *mut c_void, + align: size_t, + size: size_t, + ) -> c_int; + + pub fn rmdir(path: *const c_char) -> c_int; + pub fn sleep(secs: c_uint) -> c_uint; + pub fn read(fd: c_int, buf: *mut c_void, count: size_t) + -> ssize_t; + + pub fn open(path: *const c_char, oflag: c_int, ...) -> c_int; + + pub fn unlink(c: *const c_char) -> c_int; + + pub fn write( + fd: c_int, + buf: *const c_void, + count: size_t, + ) -> ssize_t; + + pub fn pwrite( + fd: c_int, + buf: *const c_void, + count: size_t, + offset: off_t, + ) -> ssize_t; + + pub fn setenv( + name: *const c_char, + val: *const c_char, + overwrite: c_int, + ) -> c_int; + + pub fn unsetenv(name: *const c_char) -> c_int; + + pub fn ftruncate(fd: c_int, length: off_t) -> c_int; + + pub fn sched_yield() -> c_int; + + pub fn pthread_setspecific( + key: pthread_key_t, + value: *const c_void, + ) -> c_int; + + pub fn mktime(tm: *mut tm) -> time_t; + pub fn time(time: *mut time_t) -> time_t; + pub fn gmtime(time_p: *const time_t) -> *mut tm; + pub fn localtime(time_p: *const time_t) -> *mut tm; + pub fn difftime(time1: time_t, time0: time_t) -> c_double; + + pub fn putenv(string: *mut c_char) -> c_int; + + pub fn setlocale( + category: c_int, + locale: *const c_char, + ) -> *mut c_char; + + pub fn sem_wait(sem: *mut sem_t) -> c_int; + pub fn sem_trywait(sem: *mut sem_t) -> c_int; + pub fn sem_post(sem: *mut sem_t) -> c_int; + + pub fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn getline( + lineptr: *mut *mut c_char, + n: *mut size_t, + stream: *mut FILE, + ) -> ssize_t; + + pub fn fdopendir(fd: c_int) -> *mut DIR; +} diff --git a/src/lib.rs b/src/lib.rs index 759c251..a2bce54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] #![feature(proc_macro_hygiene)] -use skyline::{hook, hooks}; +use skyline::hook; #[hook(sym = "nn::fs::MountSaveData")] fn test1(path: *const u8, user_id: u64) { @@ -21,5 +21,7 @@ pub fn main() { println!("{}", i); } - hooks![test1, test2].install_hooks(); + for hook in skyline::iter_hooks() { + println!("hook: {}", hook.info.fn_name); + } }