summaryrefslogtreecommitdiff
path: root/src/wrapper/wrapper.c
blob: 1c2d684046715af5f1065379e3aefb3c95459cd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "wrapper.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/mman.h>
#include "verbose.h"
#include <pthread.h>

static __thread bool skip_trace;

void
verbose_log(const char *fmt, ...)
{
   if (skip_trace)
      return;

   static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
   pthread_mutex_lock(&mutex);
   va_list ap;
   va_start(ap, fmt);
   static char buf[1024];
   vsnprintf(buf, sizeof(buf), fmt, ap);
   va_end(ap);
   fprintf(stderr"%lu%s\n", pthread_self(), buf);
   pthread_mutex_unlock(&mutex);
}

#ifdef VERBOSE_FUNCTIONS
#  ifdef ANDROID_X86_LINKER
__asm__(
   "wrapper_start: nop\n"
   "wrapper_store: push %edi\npush %esp\npush %ebp\npush %ebx\npush %eax\npush %ecx\npush %edx\n"
   "wrapper_symbol: pushl $0xFAFBFCFD\n" // arg1 for trace
   "wrapper_trace: .byte 0xE8, 0xFA, 0xFB, 0xFC, 0xFD\n" // CALL (trace)
   "wrapper_restore: pop %eax\npop %edx\npop %ecx\npop %eax\npop %ebx\npop %ebp\npop %esp\npop %edi\n"
   "wrapper_jmp: .byte 0xE9, 0xFA, 0xFB, 0xFC, 0xFD\n" // JMP
   "wrapper_ud: .byte 0x0F, 0xFF\n" // UD
   "wrapper_end: nop\n"
);
#     define WRAPPER_TRACE
#  else
#     warning "no wrapper asm for this platform, function tracing is not available"
#  endif
#endif

#ifdef WRAPPER_TRACE
extern unsigned char wrapper_start, wrapper_symbol, wrapper_trace, wrapper_restore, wrapper_jmp, wrapper_ud, wrapper_end;

static union {
   void *ptr;
   char* (*fun)(const char *mangled_name, char *output_buffer, size_t *length, int *status);
} __cxa_demangle;

static void
trace(const char *const symbol)
{
   assert(symbol);

   if (__cxa_demangle.ptr) {
      // >If output_buffer is not long enough, it is expanded using realloc
      // Holy fuck gcc what the fuck? Guess we don't use stack then, thanks
      int status;
      char *demangled;
      static __thread char *data;
      static __thread size_t size;

      // Avoid infinite recursion and tracing calls made by __cxa_demangle.fun
      if (skip_trace)
         return;

      skip_trace = true;
      demangled = __cxa_demangle.fun(symbol, data, &size, &status);
      skip_trace = false;

      if (demangled) {
         data = (data != demangled ? demangled : data);
         verbose("trace: %s", demangled);
         return;
      }
   }

   verbose("trace: %s", symbol);
}
#endif

void
wrapper_set_cpp_demangler(void *function)
{
#ifdef WRAPPER_TRACE
   __cxa_demangle.ptr = function;
   verbose_log("wrapper: set cpp_demangler to %p", function);
#endif
}

void*
wrapper_create(const char *const symbol, void *function)
{
   assert(symbol);

   if (!function) {
      verbose_log("FIXME: unimplemented symbol: %s", symbol);
      return NULL;
   }

#ifdef WRAPPER_TRACE
   static const union {
      void *ptr;
      void (*fun)(const char*);
   } tracefun = { .fun = trace };

   const size_t len = strlen(symbol) + 1;
   char *copy = malloc(len);
   assert(copy && "welp, malloc failed");
   memcpy(copy, symbol, len);
   const size_t sz = &wrapper_end - &wrapper_start;
   unsigned char *fun = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -10);
   assert(fun != MAP_FAILED);
   memcpy(fun, &wrapper_start, sz);
#ifdef ANDROID_X86_LINKER
   memcpy(fun + (&wrapper_symbol - &wrapper_start) + 1, &copy, sizeof(copy));
   {
      const unsigned char *from = fun + (&wrapper_restore - &wrapper_start);
      const intptr_t to = (unsigned char*)tracefun.ptr - from;
      memcpy(fun + (&wrapper_trace - &wrapper_start) + 1, &to, sizeof(to));
   }{
      const unsigned char *from = fun + (&wrapper_ud - &wrapper_start);
      const intptr_t to = (unsigned char*)function - from;
      memcpy(fun + (&wrapper_jmp - &wrapper_start) + 1, &to, sizeof(to));
   }
#else
#   error "you forgot to implement the pointer setups for your asm platform"
#endif
   mprotect(fun, sz, PROT_READ | PROT_EXEC);
   return fun;
#else
   return function;
#endif
}