1 //
2 // part of renode portable
3 //
4 
5 //
6 // reimplement some libc stuff not present in older versions
7 // but possibly used by libmono
8 //
9 
10 #include <syscall.h>
__wrap_getrandom(void * buffer,size_t length,unsigned int flags)11 ssize_t __wrap_getrandom (void *buffer, size_t length, unsigned int flags) {
12     return syscall(__NR_getrandom, buffer, length, flags);
13 }
14 
__wrap_powf()15 void __wrap_powf() {
16     printf("!!!! powf!\n"); // TODO
17 }
18 
__wrap_logf()19 void __wrap_logf() {
20     printf("!!!! logf!\n"); // TODO
21 }
22 
__wrap_expf()23 void __wrap_expf() {
24     printf("!!!! expf!\n"); // TODO
25 }
26 
27 #define LIST_LENGTH 2048
28 #define MAX_FILENAME_LENGTH 4096
29 
30 char binary_path[MAX_FILENAME_LENGTH];
31 
32 void* list_ptrs[LIST_LENGTH];
33 char* list_names[LIST_LENGTH];
34 int list_counter = 0;
35 
get_name(void * ptr)36 static char* get_name(void* ptr) {
37     for (int i = 0; i < list_counter; i++) {
38         if (list_ptrs[i] == ptr) {
39             return list_names[i];
40         }
41     }
42     return "(unknown)";
43 }
44 
45 #include <dlfcn.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <libgen.h>
49 
50 #ifdef DEBUG_PRINT
51   #define debug_print printf
52   #define error_print printf
53 #else
54   #define debug_print(...)
55   #define error_print(...)
56 #endif
57 
58 #define SHM "/dev/shm/"
__wrap___shm_directory(size_t * len)59 const char * __wrap___shm_directory(size_t *len) {
60     *len = sizeof(SHM);
61     return SHM;
62 }
63 
__wrap_mono_dl_lookup_symbol(void ** module_handle,const char * name)64 void *__wrap_mono_dl_lookup_symbol(void **module_handle, const char *name) {
65     debug_print("mono_dl_lookup_symbol(%p, %s)\n", *module_handle, name);
66     debug_print(">>> dlsym: looking for symbol '%s' in %p [%s]\n", name, *module_handle, get_name(*module_handle));
67     return dlsym(*module_handle, name);
68 }
69 
__wrap_mono_dl_open_file(const char * name,int flags)70 void *__wrap_mono_dl_open_file(const char *name, int flags) {
71     debug_print("mono_dl_open_file(%s, %d)\n", name, flags);
72     if (name == NULL) {
73         return NULL;
74     }
75 
76     char filename[MAX_FILENAME_LENGTH];
77     int l = snprintf(filename, MAX_FILENAME_LENGTH, "%s", name);
78     if (l < 0 || l >= MAX_FILENAME_LENGTH) {
79         error_print(">>> dlopen: error while configuring the filename: %s\n", filename);
80         return NULL;
81     }
82 
83     debug_print(">>> dlopen: %s\n", filename);
84 
85     // skip .dll.so calls.
86     if (strstr(filename, ".dll.so") != 0) {
87         debug_print(">>> dlopen: ignoring %s as it is .dll.so\n", filename);
88         return NULL;
89     }
90 
91     // patch current directory
92     if (strlen(filename) >= 2 && filename[0] == '.' && filename[1] == '/') {
93         // +2 to skip the initial './'
94         int l = snprintf(filename, MAX_FILENAME_LENGTH, "%s%s", binary_path, name + 2);
95         if (l < 0 || l >= MAX_FILENAME_LENGTH) {
96             error_print(">>> dlopen: error while patching the filename\n");
97             return NULL;
98         }
99         debug_print(">>> dlopen: filename patched to %s\n", filename);
100     }
101 
102     void* result = dlopen((strcmp(filename, "__Internal") == 0) ? "" : filename, flags);
103     debug_print(">>> dlopen: result is %p; filename was %s, flag was %d\n", result, filename, flags);
104     if (result != NULL) {
105         list_ptrs[list_counter] = result;
106         list_names[list_counter] = strdup(basename(filename));
107         debug_print(">>> dlopen: %s returns %p\n", list_names[list_counter], result);
108         list_counter = (list_counter + 1) % LIST_LENGTH;
109     } else {
110         debug_print(">>> dlopen: result is null: %s\n", dlerror());
111     }
112 
113     return result;
114 }
115 
116 // import MonoPosixHelper functions so that they're exported
117 extern void Mono_Posix_Syscall_get_at_fdcwd();
118 extern void Mono_Posix_Syscall_L_ctermid();
119 extern void Mono_Posix_Syscall_get_utime_now();
120 extern void Mono_Posix_Syscall_readlink();
121 extern void Mono_Posix_Stdlib_SIG_DFL();
122 extern void Mono_Posix_Stdlib_EXIT_FAILURE();
123 extern void CreateZStream();
124 extern void CloseZStream();
125 extern void ReadZStream();
126 extern void WriteZStream();
127 
128 // dummy function so that they're not optimized away
129 #define ATTR __attribute__ ((__visibility__ ("default"))) __attribute__((noinline))
DO_NOT_RUN_dummy_callback(void)130 ATTR void DO_NOT_RUN_dummy_callback(void) {
131     // the section below contains a list of all
132     // symbols that are to be remapped in the dllmap
133     // by the tools/packaging/make_linux_portable.sh script;
134     // they are extracted automatically, so please
135     // add all new items between markers and
136     // *DO NOT* modify markers themselves
137 
138     // --- REMAPPED SYMBOLS SECTION STARTS ---
139     Mono_Posix_Syscall_get_at_fdcwd();
140     Mono_Posix_Syscall_L_ctermid();
141     Mono_Posix_Syscall_get_utime_now();
142     Mono_Posix_Syscall_readlink();
143     Mono_Posix_Stdlib_SIG_DFL();
144     Mono_Posix_Stdlib_EXIT_FAILURE();
145     CreateZStream();
146     CloseZStream();
147     ReadZStream();
148     WriteZStream();
149     // --- REMAPPED SYMBOLS SECTION ENDS ---
150 }
151 
152 //
153 // end of reimplement
154 //
155 
156 //
157 // helper methods
158 //
GetBundlesCount(void)159 ATTR int GetBundlesCount(void) {
160     static int bundle_count = -1;
161     if (bundle_count != -1) return bundle_count;
162     MonoBundledAssembly **ptr = (MonoBundledAssembly **) compressed;
163     int nbundles = 0;
164     while (*ptr++ != NULL) {
165         nbundles++;
166     }
167     bundle_count = nbundles;
168     return bundle_count;
169 }
170 
get_bundle(int id)171 static MonoBundledAssembly *get_bundle(int id) {
172     return (id >= GetBundlesCount()) ? NULL : bundled[id];
173 }
174 
GetBundleName(int id)175 ATTR char* GetBundleName(int id) {
176     MonoBundledAssembly *bundle = get_bundle(id);
177     return bundle ? (char*)(bundle->name) : "";
178 }
179 
GetBundleDataSize(int id)180 ATTR uint32_t GetBundleDataSize(int id) {
181     MonoBundledAssembly *bundle = get_bundle(id);
182     return bundle ? bundle->size : 0;
183 }
184 
GetBundleDataPointer(int id)185 ATTR void* GetBundleDataPointer(int id) {
186     MonoBundledAssembly *bundle = get_bundle(id);
187     return bundle ? (void*)bundle->data : NULL;
188 }
189 
190 //
191 // end of helper methods
192 //
193 
194 #include <mono/jit/jit.h>
main(int argc,char * argv[])195 int main (int argc, char* argv[]) {
196     char **newargs;
197     int i, k = 0;
198 
199     // dirname might modify the content, so let's keep
200     // the link in a separate buffer first
201     char tmp[MAX_FILENAME_LENGTH];
202     ssize_t l = readlink("/proc/self/exe", tmp, MAX_FILENAME_LENGTH);
203     // adding 2 to the size to make room for `/` and the final NULL character
204     // in theory 1 should be enough as we call `dirname`, but let's be safe
205     if (l < 0 || l >= MAX_FILENAME_LENGTH - 2) {
206         printf("ERROR: Could read the link to self and determine the binary path. Exiting");
207         return 1;
208     }
209     sprintf(binary_path, "%s/", dirname(tmp));
210 
211     newargs = (char **) malloc (sizeof (char *) * (argc + 2));
212     newargs [k++] = image_name;
213 
214     for (i = 1; i < argc; i++) {
215         newargs [k++] = argv [i];
216     }
217     newargs [k] = NULL;
218 
219     if (config_dir != NULL && getenv ("MONO_CFG_DIR") == NULL) {
220         mono_set_dirs (getenv ("MONO_PATH"), config_dir);
221     }
222 
223     mono_mkbundle_init();
224 
225     MonoDomain *domain = mono_jit_init ("Renode.exe");
226     MonoAssembly *assembly;
227     assembly = mono_domain_assembly_open (domain, "Renode.exe");
228 
229     mono_jit_exec (domain, assembly, k, newargs);
230     int retval = mono_environment_exitcode_get ();
231     mono_jit_cleanup (domain);
232 
233     return retval;
234 }
235 
236