Removed no longer used structure definition.
[wine] / relay32 / builtin32.c
1 /*
2  * Win32 builtin functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <ctype.h>
13 #ifdef HAVE_DL_API
14 #include <dlfcn.h>
15 #endif
16 #include <sys/types.h>
17 #ifdef HAVE_SYS_MMAN_H
18 #include <sys/mman.h>
19 #endif
20
21 #include "windef.h"
22 #include "wine/winbase16.h"
23 #include "elfdll.h"
24 #include "global.h"
25 #include "neexe.h"
26 #include "heap.h"
27 #include "main.h"
28 #include "winerror.h"
29 #include "server.h"
30 #include "debugtools.h"
31
32 DEFAULT_DEBUG_CHANNEL(module);
33 DECLARE_DEBUG_CHANNEL(relay);
34
35 #define MAX_DLLS 100
36
37 typedef struct
38 {
39     const IMAGE_NT_HEADERS *nt;           /* NT header */
40     const char             *filename;     /* DLL file name */
41 } BUILTIN32_DESCRIPTOR;
42
43 extern void RELAY_SetupDLL( const char *module );
44
45 static BUILTIN32_DESCRIPTOR builtin_dlls[MAX_DLLS];
46 static int nb_dlls;
47
48
49 /***********************************************************************
50  *           BUILTIN32_dlopen
51  */
52 void *BUILTIN32_dlopen( const char *name )
53 {
54 #ifdef HAVE_DL_API
55     void *handle;
56     char buffer[128], *p;
57     if ((p = strrchr( name, '/' ))) name = p + 1;
58     if ((p = strrchr( name, '\\' ))) name = p + 1;
59     sprintf( buffer, "lib%s", name );
60     for (p = buffer; *p; p++) *p = tolower(*p);
61     if ((p = strrchr( buffer, '.' )) && (!strcmp( p, ".dll" ) || !strcmp( p, ".exe" ))) *p = 0;
62     strcat( buffer, ".so" );
63
64     if (!(handle = ELFDLL_dlopen( buffer, RTLD_NOW )))
65     {
66         LPSTR pErr, p;
67         pErr = dlerror();
68         p = strchr(pErr, ':');
69         if ((p) && 
70            (!strncmp(p, ": undefined symbol", 18))) /* undef symbol -> ERR() */
71             ERR("failed to load %s: %s\n", buffer, pErr);
72         else /* WARN() for libraries that are supposed to be native */
73             WARN("failed to load %s: %s\n", buffer, pErr );
74     }
75     return handle;
76 #else
77     return NULL;
78 #endif
79 }
80
81 /***********************************************************************
82  *           BUILTIN32_dlclose
83  */
84 int BUILTIN32_dlclose( void *handle )
85 {
86 #ifdef HAVE_DL_API
87     /* FIXME: should unregister descriptors first */
88     /* return dlclose( handle ); */
89 #endif
90     return 0;
91 }
92
93
94 /***********************************************************************
95  *           fixup_rva_ptrs
96  *
97  * Adjust an array of pointers to make them into RVAs.
98  */
99 static inline void fixup_rva_ptrs( void *array, void *base, int count )
100 {
101     void **ptr = (void **)array;
102     while (count--)
103     {
104         if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
105         ptr++;
106     }
107 }
108
109
110 /***********************************************************************
111  *           fixup_resources
112  */
113 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
114 {
115     IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
116     int i;
117
118     entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
119     for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
120     {
121         void *ptr = root + entry->u2.s.OffsetToDirectory;
122         if (entry->u2.s.DataIsDirectory) fixup_resources( ptr, root, base );
123         else
124         {
125             IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
126             fixup_rva_ptrs( &data->OffsetToData, base, 1 );
127         }
128     }
129 }
130
131
132 /***********************************************************************
133  *           BUILTIN32_DoLoadImage
134  *
135  * Load a built-in Win32 module. Helper function for BUILTIN32_LoadImage.
136  */
137 static HMODULE BUILTIN32_DoLoadImage( const BUILTIN32_DESCRIPTOR *descr )
138 {
139     IMAGE_DATA_DIRECTORY *dir;
140     IMAGE_DOS_HEADER *dos;
141     IMAGE_NT_HEADERS *nt;
142     IMAGE_SECTION_HEADER *sec;
143     INT size, nb_sections;
144     BYTE *addr, *code_start, *data_start;
145     int page_size = VIRTUAL_GetPageSize();
146
147     /* Allocate the module */
148
149     nb_sections = 2;  /* code + data */
150
151     size = (sizeof(IMAGE_DOS_HEADER)
152             + sizeof(IMAGE_NT_HEADERS)
153             + nb_sections * sizeof(IMAGE_SECTION_HEADER));
154
155     assert( size <= page_size );
156
157     if (descr->nt->OptionalHeader.ImageBase)
158     {
159         void *base = (void *)descr->nt->OptionalHeader.ImageBase;
160         if ((addr = VIRTUAL_mmap( -1, base, page_size, 0,
161                                   PROT_READ|PROT_WRITE, MAP_FIXED )) != base)
162         {
163             ERR("failed to map over PE header for %s at %p\n", descr->filename, base );
164             return 0;
165         }
166     }
167     else
168     {
169         if (!(addr = VirtualAlloc( NULL, page_size, MEM_COMMIT, PAGE_READWRITE ))) return 0;
170     }
171
172     dos    = (IMAGE_DOS_HEADER *)addr;
173     nt     = (IMAGE_NT_HEADERS *)(dos + 1);
174     sec    = (IMAGE_SECTION_HEADER *)(nt + 1);
175     code_start = addr + page_size;
176
177     /* HACK! */
178     data_start = code_start + page_size;
179
180     /* Build the DOS and NT headers */
181
182     dos->e_magic  = IMAGE_DOS_SIGNATURE;
183     dos->e_lfanew = sizeof(*dos);
184
185     *nt = *descr->nt;
186
187     nt->FileHeader.NumberOfSections                = nb_sections;
188     nt->OptionalHeader.SizeOfCode                  = data_start - code_start;
189     nt->OptionalHeader.SizeOfInitializedData       = 0;
190     nt->OptionalHeader.SizeOfUninitializedData     = 0;
191     nt->OptionalHeader.ImageBase                   = (DWORD)addr;
192
193     fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
194
195     /* Build the code section */
196
197     strcpy( sec->Name, ".text" );
198     sec->SizeOfRawData = data_start - code_start;
199     sec->Misc.VirtualSize = sec->SizeOfRawData;
200     sec->VirtualAddress   = code_start - addr;
201     sec->PointerToRawData = code_start - addr;
202     sec->Characteristics  = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
203     sec++;
204
205     /* Build the data section */
206
207     strcpy( sec->Name, ".data" );
208     sec->SizeOfRawData = 0;
209     sec->Misc.VirtualSize = sec->SizeOfRawData;
210     sec->VirtualAddress   = data_start - addr;
211     sec->PointerToRawData = data_start - addr;
212     sec->Characteristics  = (IMAGE_SCN_CNT_INITIALIZED_DATA |
213                              IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
214     sec++;
215
216     /* Build the import directory */
217
218     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
219     if (dir->Size)
220     {
221         IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
222         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
223         /* we can fixup everything at once since we only have pointers and 0 values */
224         fixup_rva_ptrs( imports, addr, dir->Size / sizeof(void*) );
225     }
226
227     /* Build the resource directory */
228
229     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
230     if (dir->Size)
231     {
232         void *ptr = (void *)dir->VirtualAddress;
233         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
234         fixup_resources( ptr, ptr, addr );
235     }
236
237     /* Build the export directory */
238
239     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
240     if (dir->Size)
241     {
242         IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
243         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
244         fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
245         fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
246         fixup_rva_ptrs( &exports->Name, addr, 1 );
247         fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
248         fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
249         fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
250
251         /* Setup relay debugging entry points */
252         if (WARN_ON(relay) || TRACE_ON(relay)) RELAY_SetupDLL( addr );
253     }
254
255     return (HMODULE)addr;
256 }
257
258 /***********************************************************************
259  *           BUILTIN32_LoadLibraryExA
260  *
261  * Partly copied from the original PE_ version.
262  *
263  */
264 WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags)
265 {
266     HMODULE module;
267     WINE_MODREF   *wm;
268     char dllname[20], *p;
269     LPCSTR name;
270     void *handle;
271     int i;
272
273     /* Fix the name in case we have a full path and extension */
274     name = path;
275     if ((p = strrchr( name, '\\' ))) name = p + 1;
276     if ((p = strrchr( name, '/' ))) name = p + 1;
277
278     if (strlen(name) >= sizeof(dllname)-4) goto error;
279
280     strcpy( dllname, name );
281     p = strrchr( dllname, '.' );
282     if (!p) strcat( dllname, ".dll" );
283
284     /* Search built-in descriptor */
285     for (i = 0; i < nb_dlls; i++)
286         if (!strcasecmp( builtin_dlls[i].filename, dllname )) goto found;
287
288     if ((handle = BUILTIN32_dlopen( dllname )))
289     {
290         for (i = 0; i < nb_dlls; i++)
291             if (!strcasecmp( builtin_dlls[i].filename, dllname )) goto found;
292         ERR( "loaded .so but dll %s still not found\n", dllname );
293         BUILTIN32_dlclose( handle );
294     }
295
296  error:
297     SetLastError( ERROR_FILE_NOT_FOUND );
298     return NULL;
299
300  found:
301     /* Load built-in module */
302     if (!(module = BUILTIN32_DoLoadImage( &builtin_dlls[i] ))) return NULL;
303
304     /* Create 32-bit MODREF */
305     if ( !(wm = PE_CreateModule( module, path, flags, -1, TRUE )) )
306     {
307         ERR( "can't load %s\n", path );
308         SetLastError( ERROR_OUTOFMEMORY );
309         return NULL;
310     }
311
312     wm->refCount++;  /* we don't support freeing builtin dlls (FIXME)*/
313     return wm;
314 }
315
316 /***********************************************************************
317  *           BUILTIN32_LoadExeModule
318  */
319 HMODULE BUILTIN32_LoadExeModule(void)
320 {
321     int i, exe = -1;
322
323     /* Search built-in EXE descriptor */
324     for ( i = 0; i < nb_dlls; i++ )
325         if ( !(builtin_dlls[i].nt->FileHeader.Characteristics & IMAGE_FILE_DLL) )
326         {
327             if ( exe != -1 )
328             {
329                 MESSAGE( "More than one built-in EXE module loaded!\n" );
330                 break;
331             }
332
333             exe = i;
334         }
335
336     if ( exe == -1 ) 
337     {
338         MESSAGE( "No built-in EXE module loaded!  Did you create a .spec file?\n" );
339         return 0;
340     }
341
342     /* Load built-in module */
343     return BUILTIN32_DoLoadImage( &builtin_dlls[exe] );
344 }
345
346
347 /***********************************************************************
348  *           BUILTIN32_RegisterDLL
349  *
350  * Register a built-in DLL descriptor.
351  */
352 void BUILTIN32_RegisterDLL( const IMAGE_NT_HEADERS *header, const char *filename )
353 {
354     assert( nb_dlls < MAX_DLLS );
355     builtin_dlls[nb_dlls].nt = header;
356     builtin_dlls[nb_dlls].filename = filename;
357     nb_dlls++;
358 }
359
360 /***********************************************************************
361  *           BUILTIN32_Unimplemented
362  *
363  * This function is called for unimplemented 32-bit entry points (declared
364  * as 'stub' in the spec file).
365  */
366 void BUILTIN32_Unimplemented( const char *dllname, const char *funcname )
367 {
368     __RESTORE_ES;  /* Just in case */
369
370     MESSAGE( "FATAL: No handler for Win32 routine %s.%s", dllname, funcname );
371 #ifdef __GNUC__
372     MESSAGE( " (called from %p)", __builtin_return_address(1) );
373 #endif
374     MESSAGE( "\n" );
375     ExitProcess(1);
376 }