mirror of
https://github.com/darlinghq/darling.git
synced 2026-05-24 13:38:37 -05:00
Some initial work on ptrace/SIGEXC support
This commit is contained in:
@@ -15,7 +15,11 @@ add_definitions(-DBSDTHREAD_WRAP_LINUX_PTHREAD
|
||||
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src/startup)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
# include src/startup for rtsig.h
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/src/startup
|
||||
)
|
||||
|
||||
set(emulation_sources
|
||||
elfcalls_wrapper.c
|
||||
@@ -132,6 +136,7 @@ set(emulation_sources
|
||||
signal/sigprocmask.c
|
||||
signal/sig_restorer.S
|
||||
signal/sigsuspend.c
|
||||
signal/sigexc.c
|
||||
misc/ptrace.c
|
||||
misc/getentropy.c
|
||||
misc/syscall.c
|
||||
@@ -291,6 +296,7 @@ set_source_files_properties(misc/sysctl.c PROPERTIES COMPILE_FLAGS
|
||||
add_library(emulation OBJECT ${emulation_sources})
|
||||
add_library(emulation_dyld OBJECT ${emulation_sources})
|
||||
set_target_properties(emulation_dyld PROPERTIES COMPILE_FLAGS "-ffunction-sections -DVARIANT_DYLD")
|
||||
add_dependencies(emulation rtsig_h)
|
||||
|
||||
make_fat(emulation)
|
||||
make_fat(emulation_dyld)
|
||||
|
||||
@@ -518,6 +518,8 @@ kern_return_t syscall_thread_switch_impl(
|
||||
};
|
||||
// Sleep for 1ms
|
||||
__linux_nanosleep(&tv, &tv);
|
||||
|
||||
// TODO: we could implement this with yield_to() in LKM
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "../errno.h"
|
||||
#include "../signal/duct_signals.h"
|
||||
#include "../misc/ptrace.h"
|
||||
#include "../mach/lkm.h"
|
||||
#include "../../../../lkm/api.h"
|
||||
#include <sys/signal.h>
|
||||
#include <stddef.h>
|
||||
#include <linux-syscalls/linux.h>
|
||||
@@ -39,21 +41,18 @@ restart:
|
||||
signal = signum_linux_to_bsd(signal);
|
||||
*status = (*status & 0x7f) | (signal << 8);
|
||||
|
||||
switch (signal)
|
||||
if (lkm_call(NR_get_tracer, (void*)(long) ret) == getpid())
|
||||
{
|
||||
case SIGCONT:
|
||||
case SIGSTOP:
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
// It is standard behavior that these signals stop (resume) the process
|
||||
break;
|
||||
default:
|
||||
// We are probably ptracing the target process.
|
||||
// Allow the execution to continue so that the ptraced process can translate
|
||||
// the signal into a Mach message.
|
||||
sys_ptrace(PT_CONTINUE, ret, NULL, signal);
|
||||
goto restart;
|
||||
// We are ptracing the target process.
|
||||
// Allow the execution to continue so that the ptraced process can translate
|
||||
// the signal into a Mach message.
|
||||
if (signal == SIGSTOP)
|
||||
{
|
||||
// TODO: notify target process it has been SIGSTOP'ed via sigqueue
|
||||
}
|
||||
|
||||
sys_ptrace(PT_CONTINUE, ret, NULL, signal);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#define LINUX_SIGPWR 30
|
||||
#define LINUX_SIGSYS 31
|
||||
#define LINUX_SIGUNUSED 31
|
||||
#define LINUX_SIGRTMIN 32
|
||||
#define LINUX_SA_NOCLDSTOP 0x00000001u
|
||||
#define LINUX_SA_NOCLDWAIT 0x00000002u
|
||||
#define LINUX_SA_SIGINFO 0x00000004u
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#include "../simple.h"
|
||||
#include <linux-syscalls/linux.h>
|
||||
#include <stddef.h>
|
||||
#include "sigexc.h"
|
||||
#include "../../../../../platform-include/sys/errno.h"
|
||||
|
||||
static void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt);
|
||||
static int sigflags_bsd_to_linux(int flags);
|
||||
static int sigflags_linux_to_bsd(int flags);
|
||||
extern void sig_restorer(void);
|
||||
@@ -17,7 +17,9 @@ extern void* memset(void* dest, int v, __SIZE_TYPE__ len);
|
||||
|
||||
// Libc uses only one trampoline
|
||||
void (*sa_tramp)(void*, int, int, struct bsd_siginfo*, void*) = 0;
|
||||
static bsd_sig_handler* sig_handlers[32];
|
||||
bsd_sig_handler* sig_handlers[32];
|
||||
int sig_flags[32];
|
||||
unsigned int sig_masks[32];
|
||||
|
||||
long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sigaction* osa)
|
||||
{
|
||||
@@ -42,7 +44,11 @@ long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sig
|
||||
if (nsa != NULL)
|
||||
{
|
||||
sa_tramp = nsa->sa_tramp;
|
||||
if (nsa->sa_sigaction != SIG_DFL && nsa->sa_sigaction != SIG_IGN
|
||||
if (darling_am_i_ptraced())
|
||||
{
|
||||
sa.sa_sigaction = &sigexc_handler;
|
||||
}
|
||||
else if (nsa->sa_sigaction != SIG_DFL && nsa->sa_sigaction != SIG_IGN
|
||||
&& nsa->sa_sigaction != SIG_ERR)
|
||||
{
|
||||
sa.sa_sigaction = &handler_linux_to_bsd;
|
||||
@@ -71,10 +77,12 @@ long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sig
|
||||
osa->sa_flags = sigflags_linux_to_bsd(olsa.sa_flags);
|
||||
}
|
||||
|
||||
if (nsa != NULL)
|
||||
if (nsa != NULL && ret >= 0)
|
||||
{
|
||||
// __simple_printf("Saving handler for signal %d: %d\n", linux_signum, nsa->sa_sigaction);
|
||||
sig_handlers[linux_signum] = nsa->sa_sigaction;
|
||||
sig_flags[linux_signum] = sa.sa_flags;
|
||||
sig_masks[linux_signum] = sa.sa_mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -120,7 +128,7 @@ static void ucontext_linux_to_bsd(const struct linux_ucontext* lc, struct bsd_uc
|
||||
#undef copyreg
|
||||
}
|
||||
|
||||
static void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt)
|
||||
void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt)
|
||||
{
|
||||
int bsd_signum;
|
||||
struct bsd_siginfo binfo;
|
||||
|
||||
@@ -51,6 +51,7 @@ struct linux_siginfo
|
||||
union
|
||||
{
|
||||
int _pad[__SI_PAD_SIZE];
|
||||
unsigned long si_value;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -194,5 +195,10 @@ struct bsd_ucontext
|
||||
struct bsd_mcontext* uc_mcontext;
|
||||
};
|
||||
|
||||
void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt);
|
||||
extern bsd_sig_handler* sig_handlers[32];
|
||||
extern int sig_flags[32];
|
||||
extern unsigned int sig_masks[32];
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "sigexc.h"
|
||||
#include "../base.h"
|
||||
#include <stddef.h>
|
||||
#include <linux-syscalls/linux.h>
|
||||
|
||||
// Support for Darwin debugging.
|
||||
// Unlike other Unix-like systems, macOS doesn't use wait() to handle events in the debugged process.
|
||||
|
||||
static bool am_i_ptraced = false;
|
||||
static void handle_rt_signal(int signum);
|
||||
extern void sig_restorer(void);
|
||||
void darling_sigexc_uninstall(void);
|
||||
void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt);
|
||||
|
||||
void sigexc_setup(void)
|
||||
{
|
||||
// Setup handler for SIGNAL_SIGEXC_TOGGLE and SIGNAL_SIGEXC_THUPDATE
|
||||
handle_rt_signal(SIGNAL_SIGEXC_TOGGLE);
|
||||
handle_rt_signal(SIGNAL_SIGEXC_THUPDATE);
|
||||
}
|
||||
|
||||
static void handle_rt_signal(int signum)
|
||||
{
|
||||
struct linux_sigaction sa;
|
||||
sa.sa_sigaction = sigrt_handler;
|
||||
sa.sa_mask = 0;
|
||||
sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART;
|
||||
sa.sa_restorer = sig_restorer;
|
||||
|
||||
LINUX_SYSCALL(__NR_rt_sigaction, signum,
|
||||
&sa, NULL,
|
||||
sizeof(sa.sa_mask));
|
||||
}
|
||||
|
||||
bool darling_am_i_ptraced(void)
|
||||
{
|
||||
return am_i_ptraced;
|
||||
}
|
||||
|
||||
void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt)
|
||||
{
|
||||
if (signum == SIGNAL_SIGEXC_TOGGLE)
|
||||
{
|
||||
if (info->si_value == SIGRT_MAGIC_ENABLE_SIGEXC)
|
||||
{
|
||||
am_i_ptraced = true;
|
||||
darling_sigexc_self();
|
||||
}
|
||||
else if (info->si_value == SIGRT_MAGIC_DISABLE_SIGEXC)
|
||||
{
|
||||
am_i_ptraced = false;
|
||||
darling_sigexc_uninstall();
|
||||
}
|
||||
}
|
||||
else if (signum == SIGNAL_SIGEXC_THUPDATE)
|
||||
{
|
||||
// TODO: Change how a pending signal is handled
|
||||
// Use TLS?
|
||||
if (!am_i_ptraced)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void darling_sigexc_self(void)
|
||||
{
|
||||
// Make sigexc_handler the handler for all signals in the process
|
||||
for (int i = 1; i <= 31; i++)
|
||||
{
|
||||
struct linux_sigaction sa;
|
||||
sa.sa_sigaction = sigrt_handler;
|
||||
sa.sa_mask = sig_masks[i];
|
||||
sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART;
|
||||
sa.sa_restorer = sig_restorer;
|
||||
|
||||
LINUX_SYSCALL(__NR_rt_sigaction, i,
|
||||
&sa, NULL,
|
||||
sizeof(sa.sa_mask));
|
||||
}
|
||||
}
|
||||
void darling_sigexc_uninstall(void)
|
||||
{
|
||||
for (int i = 1; i <= 31; i++)
|
||||
{
|
||||
struct linux_sigaction sa;
|
||||
|
||||
if (sig_handlers[i] == SIG_DFL || sig_handlers[i] != SIG_IGN
|
||||
|| sig_handlers[i] != SIG_ERR)
|
||||
{
|
||||
sa.sa_sigaction = (linux_sig_handler*) sig_handlers[i];
|
||||
}
|
||||
else
|
||||
sa.sa_sigaction = &handler_linux_to_bsd;
|
||||
|
||||
sa.sa_mask = sig_masks[i];
|
||||
sa.sa_flags = sig_flags[i];
|
||||
sa.sa_restorer = sig_restorer;
|
||||
|
||||
LINUX_SYSCALL(__NR_rt_sigaction, i,
|
||||
&sa, NULL,
|
||||
sizeof(sa.sa_mask));
|
||||
}
|
||||
}
|
||||
|
||||
void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt)
|
||||
{
|
||||
// SIGSEGV + SIGBUS -> EXC_BAD_ACCESS
|
||||
// SIGTRAP -> EXC_BREAKPOINT
|
||||
// * -> EXC_SOFTWARE with EXC_SOFT_SIGNAL (e.g. SIGSTOP
|
||||
if (darling_am_i_ptraced())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef _SIGEXC_H
|
||||
#define _SIGEXC_H
|
||||
#include <stdbool.h>
|
||||
#include "rtsig.h"
|
||||
#include "sigaction.h"
|
||||
|
||||
#define SIGNAL_SIGEXC_TOGGLE LINUX_SIGRTMIN
|
||||
#define SIGNAL_SIGEXC_THUPDATE (LINUX_SIGRTMIN + 1)
|
||||
|
||||
#define SIGRT_MAGIC_ENABLE_SIGEXC 0xdebdeb01
|
||||
#define SIGRT_MAGIC_DISABLE_SIGEXC 0xdebdeb00
|
||||
#define SIGRT_
|
||||
|
||||
// Initializes this module
|
||||
void sigexc_setup(void);
|
||||
|
||||
// Is this process currently traced by a debugger?
|
||||
bool darling_am_i_ptraced(void);
|
||||
|
||||
// for PT_SIGEXC to handle this operation synchronously
|
||||
void darling_sigexc_self(void);
|
||||
void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
Submodule src/lkm updated: bb88121f91...622b9032ed
@@ -59,3 +59,7 @@ if (DEFINED WITH_PRINT_WRAPPED_ELF)
|
||||
add_executable(print_wrapped_elf wrapgen/print_wrapped_elf.cpp)
|
||||
endif (DEFINED WITH_PRINT_WRAPPED_ELF)
|
||||
|
||||
add_executable(rtsig rtsig.c)
|
||||
add_custom_command(OUTPUT rtsig.h DEPENDS rtsig COMMAND ${CMAKE_CURRENT_BINARY_DIR}/rtsig rtsig.h COMMENT "Determining available RT signals")
|
||||
add_custom_target(rtsig_h DEPENDS rtsig.h)
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Determine RT signal ranges without polluting the build environment with Linux system headers
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
FILE* output = stdout;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
output = fopen(argv[1], "w");
|
||||
if (!output)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(output, "#define LINUX_SIGRTMIN %d\n", SIGRTMIN);
|
||||
fprintf(output, "#define LINUX_SIGRTMAX %d\n", SIGRTMAX);
|
||||
|
||||
fclose(output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user