mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 19:11:08 +00:00
Preload the FEX fault report only where x86 loaders look droiddeck-fex put the x86 libfaultreport.so in LD_PRELOAD, which FEX's own arm64 loader reads too - and FEXServer's, and every child FEX's - so each x86 start printed "ERROR: ld.so: object '.../libfaultreport.so' from LD_PRELOAD cannot be preloaded", and an i386 child added "wrong ELF class". It is now listed in the x86 runtime's own /etc/ld.so.preload, which only the loaders inside FEX read, as /usr/$LIB/droiddeck/libfaultreport.so. faultreport.c builds for i386 too, so 32-bit programs get the report as well instead of an error.
164 lines
4.5 KiB
C
164 lines
4.5 KiB
C
#if defined(__x86_64__)
|
|
#define SYS_read 0
|
|
#define SYS_write 1
|
|
#define SYS_close 3
|
|
#define SYS_rt_sigaction 13
|
|
#define SYS_rt_sigreturn "15"
|
|
#define SYS_getpid 39
|
|
#define SYS_gettid 186
|
|
#define SYS_tgkill 234
|
|
#define SYS_openat 257
|
|
#define SI_ADDR 16
|
|
#define TRAP "syscall"
|
|
#elif defined(__i386__)
|
|
#define SYS_read 3
|
|
#define SYS_write 4
|
|
#define SYS_close 6
|
|
#define SYS_rt_sigaction 174
|
|
#define SYS_rt_sigreturn "173"
|
|
#define SYS_getpid 20
|
|
#define SYS_gettid 224
|
|
#define SYS_tgkill 270
|
|
#define SYS_openat 295
|
|
#define SI_ADDR 12
|
|
#define TRAP "int $0x80"
|
|
#else
|
|
#error faultreport is built for x86 guests only
|
|
#endif
|
|
#define AT_FDCWD (-100)
|
|
#define SIGILL 4
|
|
#define SA_SIGINFO 0x4UL
|
|
#define SA_RESTORER 0x04000000UL
|
|
#define SA_NODEFER 0x40000000UL
|
|
#define SA_RESETHAND 0x80000000UL
|
|
|
|
struct kernel_sigaction {
|
|
void (*handler)(int, void *, void *);
|
|
unsigned long flags;
|
|
void (*restorer)(void);
|
|
unsigned long long mask;
|
|
};
|
|
|
|
static long sys(long n, long a, long b, long c, long d)
|
|
{
|
|
long r;
|
|
#if defined(__x86_64__)
|
|
register long r10 __asm__("r10") = d;
|
|
__asm__ volatile("syscall" : "=a"(r) : "a"(n), "D"(a), "S"(b), "d"(c), "r"(r10) : "rcx", "r11", "memory");
|
|
#else
|
|
__asm__ volatile("int $0x80" : "=a"(r) : "a"(n), "b"(a), "c"(b), "d"(c), "S"(d) : "memory");
|
|
#endif
|
|
return r;
|
|
}
|
|
|
|
static char out[1024];
|
|
static unsigned long used;
|
|
static char maps[65536];
|
|
|
|
static void put(const char *s)
|
|
{
|
|
while (*s && used < sizeof(out) - 1)
|
|
out[used++] = *s++;
|
|
}
|
|
|
|
static void put_hex(unsigned long v, int digits)
|
|
{
|
|
char buf[17];
|
|
for (int i = digits - 1; i >= 0; i--) {
|
|
buf[i] = "0123456789abcdef"[v & 15];
|
|
v >>= 4;
|
|
}
|
|
buf[digits] = 0;
|
|
put(buf);
|
|
}
|
|
|
|
static unsigned long parse_hex(const char **p)
|
|
{
|
|
unsigned long v = 0;
|
|
for (;;) {
|
|
char c = **p;
|
|
if (c >= '0' && c <= '9') v = v * 16 + (c - '0');
|
|
else if (c >= 'a' && c <= 'f') v = v * 16 + (c - 'a' + 10);
|
|
else return v;
|
|
(*p)++;
|
|
}
|
|
}
|
|
|
|
static int find_mapping(unsigned long addr, const char **line, unsigned long *length, unsigned long *start, int *readable)
|
|
{
|
|
long fd = sys(SYS_openat, AT_FDCWD, (long)"/proc/self/maps", 0, 0);
|
|
if (fd < 0) return 0;
|
|
unsigned long have = 0;
|
|
long n;
|
|
while (have < sizeof(maps) - 1 && (n = sys(SYS_read, fd, (long)(maps + have), sizeof(maps) - 1 - have, 0)) > 0)
|
|
have += n;
|
|
sys(SYS_close, fd, 0, 0, 0);
|
|
maps[have] = 0;
|
|
const char *p = maps;
|
|
while (*p) {
|
|
const char *begin = p;
|
|
unsigned long lo = parse_hex(&p);
|
|
if (*p == '-') p++;
|
|
unsigned long hi = parse_hex(&p);
|
|
while (*p == ' ') p++;
|
|
int r = *p == 'r';
|
|
const char *end = begin;
|
|
while (*end && *end != '\n') end++;
|
|
if (addr >= lo && addr < hi) {
|
|
*line = begin;
|
|
*length = end - begin;
|
|
*start = lo;
|
|
*readable = r && addr + 16 <= hi;
|
|
return 1;
|
|
}
|
|
p = *end ? end + 1 : end;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void report(int sig, void *info, void *context)
|
|
{
|
|
(void)context;
|
|
unsigned long addr = *(unsigned long *)((char *)info + SI_ADDR);
|
|
int code = *(int *)((char *)info + 8);
|
|
used = 0;
|
|
put("droiddeck-fex: SIGILL at 0x");
|
|
put_hex(addr, 12);
|
|
put(" (si_code ");
|
|
put_hex((unsigned long)code, 2);
|
|
put(")");
|
|
const char *line;
|
|
unsigned long length, start;
|
|
int readable;
|
|
if (find_mapping(addr, &line, &length, &start, &readable)) {
|
|
put(", offset 0x");
|
|
put_hex(addr - start, 8);
|
|
if (readable) {
|
|
put(", bytes");
|
|
for (int i = 0; i < 16; i++) {
|
|
put(" ");
|
|
put_hex(((unsigned char *)addr)[i], 2);
|
|
}
|
|
}
|
|
put("\n in ");
|
|
for (unsigned long i = 0; i < length && used < sizeof(out) - 2; i++)
|
|
out[used++] = line[i];
|
|
} else {
|
|
put(", outside any mapping");
|
|
}
|
|
put("\n");
|
|
sys(SYS_write, 2, (long)out, used, 0);
|
|
struct kernel_sigaction fallback = {0, 0, 0, 0};
|
|
sys(SYS_rt_sigaction, sig, (long)&fallback, 0, sizeof(fallback.mask));
|
|
sys(SYS_tgkill, sys(SYS_getpid, 0, 0, 0, 0), sys(SYS_gettid, 0, 0, 0, 0), sig, 0);
|
|
}
|
|
|
|
void faultreport_restore(void);
|
|
__asm__(".text\n.type faultreport_restore,@function\nfaultreport_restore:\nmov $" SYS_rt_sigreturn ", %eax\n" TRAP "\nhlt\n");
|
|
|
|
__attribute__((constructor)) static void install(void)
|
|
{
|
|
struct kernel_sigaction action = {report, SA_SIGINFO | SA_NODEFER | SA_RESETHAND | SA_RESTORER, faultreport_restore, 0};
|
|
sys(SYS_rt_sigaction, SIGILL, (long)&action, 0, sizeof(action.mask));
|
|
}
|