AcessNative - Fixing crashes
[tpg/acess2.git] / AcessNative / ld-acess_src / binary.c
1 /*
2  * AcessNative
3  */
4 #define DEBUG   1
5 #include "common.h"
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 #define LIBRARY_PATH    "$$$$../Usermode/Output/x86_64/Libs"
11
12 // === TYPES ===
13 typedef struct sBinary {
14         struct sBinary  *Next;
15         void    *Base;
16          int    Ready;
17         tBinFmt *Format;
18         char    Path[];
19 }       tBinary;
20
21 // === IMPORTS ===
22 extern void     *Elf_Load(int fd);
23 extern uintptr_t        ElfRelocate(void *Base);
24 extern int      ElfGetSymbol(void *Base, char *Name, uintptr_t *ret, size_t *size);
25 extern int      ciNumBuiltinSymbols;
26 extern tSym     caBuiltinSymbols[];
27 extern char     **gEnvP;
28
29 // === PROTOTYPES ===
30 void    Binary_AddToList(const char *Filename, void *Base, tBinFmt *Format);
31
32 // === GLOBALS ===
33 tBinFmt gElf_FormatDef = {
34 //      .Mask = 0xFFFFFFFF,
35 //      .Magic = "\x7F""ELF",
36         .Name = "ELF32",
37         .Load = Elf_Load,
38         .Relocate = ElfRelocate,
39         .GetSymbol = ElfGetSymbol
40         };
41 tBinary *gLoadedBinaries;
42
43 // === CODE ===
44 char *Binary_LocateLibrary(const char *Name)
45 {
46         char    *envPath = getenv("ACESS_LIBRARY_PATH");
47          int    nameLen = strlen(Name);
48          int    fd;
49         
50         if( strcmp(Name, "libld-acess.so") == 0 ) {
51                 return strdup("libld-acess.so");
52         }
53         
54         // Try the environment ACESS_LIBRARY_PATH
55         if( envPath && envPath[0] != '\0' )
56         {
57                  int    len = strlen(envPath)+1+nameLen+1;
58                 char    tmp[len];
59
60                 strcpy(tmp, envPath);
61                 strcat(tmp, "/");
62                 strcat(tmp, Name);
63                 
64                 fd = acess_open(tmp, 4);        // OPENFLAG_EXEC
65                 if(fd != -1) {
66                         acess_close(fd);
67                         return strdup(tmp);
68                 }
69         }               
70
71         {
72                  int    len = strlen(LIBRARY_PATH)+1+nameLen+1;
73                 char    tmp[len];
74
75                 strcpy(tmp, LIBRARY_PATH);
76                 strcat(tmp, "/");
77                 strcat(tmp, Name);
78                 
79                 #if DEBUG
80                 printf("Binary_LocateLibrary: tmp = '%s'\n", tmp);
81                 #endif
82
83                 fd = acess_open(tmp, 4);        // OPENFLAG_EXEC
84                 if(fd != -1) {
85                         acess_close(fd);
86                         return strdup(tmp);
87                 }
88         }               
89
90         #if DEBUG
91         fprintf(stderr, "Unable to locate library '%s'\n", Name);
92         #endif
93
94         return NULL;
95 }
96
97 void *Binary_LoadLibrary(const char *Name)
98 {
99         char    *path;
100         void    *ret;
101          int    (*entry)(void *,int,char*[],char**) = NULL;
102
103         // Find File
104         path = Binary_LocateLibrary(Name);
105         #if DEBUG
106         printf("Binary_LoadLibrary: path = '%s'\n", path);
107         #endif
108         if( !path ) {
109                 return NULL;
110         }
111
112         ret = Binary_Load(path, (uintptr_t*)&entry);
113         printf("LOADED '%s' to %p (Entry=%p)\n", path, ret, entry);
114         free(path);
115         
116         #if DEBUG
117         printf("Binary_LoadLibrary: ret = %p, entry = %p\n", ret, entry);
118         #endif
119         if( entry ) {
120                 char    *argv[] = {NULL};
121                 #if DEBUG
122                 printf("Calling '%s' entry point %p\n", Name, entry);
123                 #endif
124                 entry(ret, 0, argv, gEnvP);
125         }
126
127         return ret;
128 }
129
130 void *Binary_Load(const char *Filename, uintptr_t *EntryPoint)
131 {
132          int    fd;
133         uint32_t        dword = 0xFA17FA17;
134         void    *ret;
135         uintptr_t       entry = 0;
136         tBinFmt *fmt;
137
138         // Ignore loading ld-acess
139         if( strcmp(Filename, "libld-acess.so") == 0 ) {
140                 *EntryPoint = 0;
141                 return (void*)-1;
142         }
143
144         {
145                 tBinary *bin;
146                 for(bin = gLoadedBinaries; bin; bin = bin->Next)
147                 {
148                         if( strcmp(Filename, bin->Path) == 0 ) {
149                                 return bin->Base;
150                         }
151                 }
152         }
153
154         fd = acess_open(Filename, 2|1); // Execute and Read
155         if( fd == -1 ) {
156                 // TODO: Handle libary directories
157                 perror("Opening binary");
158                 return NULL;
159         }
160
161         acess_read(fd, &dword, 4);
162         acess_seek(fd, 0, ACESS_SEEK_SET);
163         
164         if( memcmp(&dword, "\x7F""ELF", 4) == 0 ) {
165                 fmt = &gElf_FormatDef;
166         }
167         else {
168                 fprintf(stderr, "Unknown executable format (0x%08x)\n", dword);
169                 acess_close(fd);
170                 return NULL;
171         }
172         
173         #if DEBUG
174         printf("fmt->Load(0x%x)...\n", fd);
175         #endif
176         ret = fmt->Load(fd);
177         acess_close(fd);
178         #if DEBUG
179         printf("fmt->Load(0x%x): %p\n", fd, ret);
180         #endif
181         if( !ret ) {
182                 return NULL;
183         }
184         
185         Binary_AddToList(Filename, ret, fmt);
186
187         entry = fmt->Relocate(ret);
188         #if DEBUG
189         printf("fmt->Relocate(%p): %p\n", ret, (void*)entry);
190         #endif
191         if( !entry ) {
192                 // TODO: Clean up
193                 return NULL;
194         }
195         
196         if( EntryPoint )
197                 *EntryPoint = entry;
198
199         Binary_SetReadyToUse(ret);
200
201         return ret;
202 }
203
204 void Binary_AddToList(const char *Filename, void *Base, tBinFmt *Format)
205 {
206         tBinary *bin = malloc(sizeof(tBinary) + strlen(Filename) + 1);
207         bin->Base = Base;
208         bin->Format = Format;
209         strcpy(bin->Path, Filename);
210         bin->Ready = 0;
211         
212         bin->Next = gLoadedBinaries;
213         gLoadedBinaries = bin;
214 }
215
216 void Binary_SetReadyToUse(void *Base)
217 {
218         tBinary *bin;
219         for(bin = gLoadedBinaries; bin; bin = bin->Next)
220         {
221                 if( bin->Base != Base ) continue ;
222                 bin->Ready = 1;
223         }
224 }
225
226 int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value, size_t *Size)
227 {
228          int    i;
229         tBinary *bin;
230         
231         //printf("Binary_GetSymbol: (SymbolName='%s', Value=%p)\n",
232         //      SymbolName, Value);
233
234         // Search builtins
235         // - Placed first to override smartarses that define their own versions
236         //   of system calls
237         for( i = 0; i < ciNumBuiltinSymbols; i ++ )
238         {
239                 if( strcmp(caBuiltinSymbols[i].Name, SymbolName) == 0 ) {
240                         *Value = (uintptr_t)caBuiltinSymbols[i].Value;
241                         if(Size)        *Size = 0;
242                         return 1;
243                 }
244         }
245         
246         // Search list of loaded binaries
247         for(bin = gLoadedBinaries; bin; bin = bin->Next)
248         {
249                 if( !bin->Ready )       continue;
250                 //printf(" Binary_GetSymbol: bin = %p{%p, %s}\n", bin, bin->Base, bin->Path);
251                 if( bin->Format->GetSymbol(bin->Base, (char*)SymbolName, Value, Size) )
252                         return 1;
253         }
254
255         //printf("Binary_GetSymbol: RETURN 0, not found\n");
256         printf("--- ERROR: Unable to find symbol '%s'\n", SymbolName);
257
258         exit( -1 );
259         return 0;
260 }

UCC git Repository :: git.ucc.asn.au