Implemented on-demand loading of builtin dlls using dlopen().
[wine] / if1632 / builtin.c
1 /*
2  * Built-in modules
3  *
4  * Copyright 1996 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include "winbase.h"
12 #include "wine/winbase16.h"
13 #include "wine/winestring.h"
14 #include "builtin16.h"
15 #include "builtin32.h"
16 #include "global.h"
17 #include "heap.h"
18 #include "module.h"
19 #include "miscemu.h"
20 #include "neexe.h"
21 #include "stackframe.h"
22 #include "user.h"
23 #include "process.h"
24 #include "task.h"
25 #include "debugtools.h"
26 #include "toolhelp.h"
27
28 DEFAULT_DEBUG_CHANNEL(module);
29
30 typedef struct
31 {
32     LPVOID  res_start;          /* address of resource data */
33     DWORD   nr_res;
34     DWORD   res_size;           /* size of resource data */
35 } BUILTIN16_RESOURCE;
36
37
38 /* Table of all built-in DLLs */
39
40 #define MAX_DLLS 50
41
42 static const BUILTIN16_DESCRIPTOR *builtin_dlls[MAX_DLLS];
43 static int nb_dlls;
44
45 /* list of DLLs that should always be loaded at startup */
46 static const char * const always_load[] =
47 {
48     "system", "display", "wprocs", "wineps", NULL
49 };
50
51   /* Ordinal number for interrupt 0 handler in WPROCS.DLL */
52 #define FIRST_INTERRUPT_ORDINAL 100
53
54
55 /***********************************************************************
56  *           BUILTIN_DoLoadModule16
57  *
58  * Load a built-in Win16 module. Helper function for BUILTIN_LoadModule
59  * and BUILTIN_Init.
60  */
61 static HMODULE16 BUILTIN_DoLoadModule16( const BUILTIN16_DESCRIPTOR *descr )
62 {
63     NE_MODULE *pModule;
64     int minsize, res_off;
65     SEGTABLEENTRY *pSegTable;
66     HMODULE16 hModule;
67     const BUILTIN16_RESOURCE *rsrc = descr->rsrc;
68
69     if (!rsrc)
70     {
71         hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, descr->module_start,
72                                       descr->module_size, 0,
73                                             FALSE, FALSE, FALSE, NULL );
74         if (!hModule) return 0;
75         FarSetOwner16( hModule, hModule );
76
77         pModule = (NE_MODULE *)GlobalLock16( hModule );
78     }
79     else
80     {
81         ET_BUNDLE *bundle;
82
83         hModule = GLOBAL_Alloc( GMEM_MOVEABLE, 
84                                 descr->module_size + rsrc->res_size, 
85                                 0, FALSE, FALSE, FALSE );
86         if (!hModule) return 0;
87         FarSetOwner16( hModule, hModule );
88
89         pModule = (NE_MODULE *)GlobalLock16( hModule );
90         res_off = ((NE_MODULE *)descr->module_start)->res_table;
91
92         memcpy( (LPBYTE)pModule, descr->module_start, res_off );
93         memcpy( (LPBYTE)pModule + res_off, rsrc->res_start, rsrc->res_size );
94         memcpy( (LPBYTE)pModule + res_off + rsrc->res_size, 
95                 (LPBYTE)descr->module_start + res_off, descr->module_size - res_off );
96
97         /* Have to fix up various pModule-based near pointers.  Ugh! */
98         pModule->name_table   += rsrc->res_size;
99         pModule->modref_table += rsrc->res_size;
100         pModule->import_table += rsrc->res_size;
101         pModule->entry_table  += rsrc->res_size;
102
103         for ( bundle = (ET_BUNDLE *)((LPBYTE)pModule + pModule->entry_table);
104               bundle->next;
105               bundle = (ET_BUNDLE *)((LPBYTE)pModule + bundle->next) )
106             bundle->next += rsrc->res_size;
107
108         /* NOTE: (Ab)use the hRsrcMap parameter for resource data pointer */
109         pModule->hRsrcMap = rsrc->res_start;
110     }
111     pModule->self = hModule;
112
113     TRACE( "Built-in %s: hmodule=%04x\n", descr->name, hModule );
114
115     /* Allocate the code segment */
116
117     pSegTable = NE_SEG_TABLE( pModule );
118     pSegTable->hSeg = GLOBAL_CreateBlock( GMEM_FIXED, descr->code_start,
119                                               pSegTable->minsize, hModule,
120                                               TRUE, TRUE, FALSE, NULL );
121     if (!pSegTable->hSeg) return 0;
122     pSegTable++;
123
124     /* Allocate the data segment */
125
126     minsize = pSegTable->minsize ? pSegTable->minsize : 0x10000;
127     minsize += pModule->heap_size;
128     if (minsize > 0x10000) minsize = 0x10000;
129     pSegTable->hSeg = GLOBAL_Alloc( GMEM_FIXED, minsize,
130                                         hModule, FALSE, FALSE, FALSE );
131     if (!pSegTable->hSeg) return 0;
132     if (pSegTable->minsize) memcpy( GlobalLock16( pSegTable->hSeg ),
133                                     descr->data_start, pSegTable->minsize);
134     if (pModule->heap_size)
135         LocalInit16( GlobalHandleToSel16(pSegTable->hSeg),
136                 pSegTable->minsize, minsize );
137
138         if (rsrc)
139                 NE_InitResourceHandler(hModule);
140
141     NE_RegisterModule( pModule );
142     return hModule;
143 }
144
145
146 /***********************************************************************
147  *           BUILTIN_Init
148  *
149  * Load all built-in modules marked as 'always used'.
150  */
151 BOOL BUILTIN_Init(void)
152 {
153     WORD vector;
154     HMODULE16 hModule;
155     const char * const *ptr = always_load;
156
157     while (*ptr)
158     {
159         if (!BUILTIN_LoadModule( *ptr )) return FALSE;
160         ptr++;
161     }
162
163     /* Set interrupt vectors from entry points in WPROCS.DLL */
164
165     hModule = GetModuleHandle16( "WPROCS" );
166     for (vector = 0; vector < 256; vector++)
167     {
168         FARPROC16 proc = NE_GetEntryPoint( hModule,
169                                            FIRST_INTERRUPT_ORDINAL + vector );
170         assert(proc);
171         INT_SetPMHandler( vector, proc );
172     }
173
174     return TRUE;
175 }
176
177
178 /***********************************************************************
179  *           BUILTIN_LoadModule
180  *
181  * Load a built-in module.
182  */
183 HMODULE16 BUILTIN_LoadModule( LPCSTR name )
184 {
185     char dllname[16], *p;
186     void *handle;
187     int i;
188
189     /* Fix the name in case we have a full path and extension */
190
191     if ((p = strrchr( name, '\\' ))) name = p + 1;
192     lstrcpynA( dllname, name, sizeof(dllname) );
193     p = strrchr( dllname, '.' );
194          
195     if (!p) strcat( dllname, ".dll" );
196
197     for (i = 0; i < nb_dlls; i++)
198     {
199         const BUILTIN16_DESCRIPTOR *descr = builtin_dlls[i];
200         NE_MODULE *pModule = (NE_MODULE *)descr->module_start;
201         OFSTRUCT *pOfs = (OFSTRUCT *)((LPBYTE)pModule + pModule->fileinfo);
202         if (!strcasecmp( pOfs->szPathName, dllname ))
203             return BUILTIN_DoLoadModule16( descr );
204     }
205
206     if ((handle = BUILTIN32_dlopen( dllname )))
207     {
208         for (i = 0; i < nb_dlls; i++)
209         {
210             const BUILTIN16_DESCRIPTOR *descr = builtin_dlls[i];
211             NE_MODULE *pModule = (NE_MODULE *)descr->module_start;
212             OFSTRUCT *pOfs = (OFSTRUCT *)((LPBYTE)pModule + pModule->fileinfo);
213             if (!strcasecmp( pOfs->szPathName, dllname ))
214                 return BUILTIN_DoLoadModule16( descr );
215         }
216         ERR( "loaded .so but dll %s still not found\n", dllname );
217         BUILTIN32_dlclose( handle );
218     }
219
220     return (HMODULE16)2;
221 }
222
223
224 /***********************************************************************
225  *           BUILTIN_GetEntryPoint16
226  *
227  * Return the ordinal, name, and type info corresponding to a CS:IP address.
228  * This is used only by relay debugging.
229  */
230 LPCSTR BUILTIN_GetEntryPoint16( STACK16FRAME *frame, LPSTR name, WORD *pOrd )
231 {
232     WORD i, max_offset;
233     register BYTE *p;
234     NE_MODULE *pModule;
235     ET_BUNDLE *bundle;
236     ET_ENTRY *entry;
237
238     if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) ))))
239         return NULL;
240
241     max_offset = 0;
242     *pOrd = 0;
243     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
244     do 
245     {
246         entry = (ET_ENTRY *)((BYTE *)bundle+6);
247         for (i = bundle->first + 1; i <= bundle->last; i++)
248         {
249             if ((entry->offs < frame->entry_ip)
250             && (entry->segnum == 1) /* code segment ? */
251             && (entry->offs >= max_offset))
252             {
253                 max_offset = entry->offs;
254                 *pOrd = i;
255             }
256             entry++;
257         }
258     } while ( (bundle->next)
259            && (bundle = (ET_BUNDLE *)((BYTE *)pModule+bundle->next)));
260
261     /* Search for the name in the resident names table */
262     /* (built-in modules have no non-resident table)   */
263     
264     p = (BYTE *)pModule + pModule->name_table;
265     while (*p)
266     {
267         p += *p + 1 + sizeof(WORD);
268         if (*(WORD *)(p + *p + 1) == *pOrd) break;
269     }
270
271     sprintf( name, "%.*s.%d: %.*s",
272              *((BYTE *)pModule + pModule->name_table),
273              (char *)pModule + pModule->name_table + 1,
274              *pOrd, *p, (char *)(p + 1) );
275
276     /* Retrieve type info string */
277     return *(LPCSTR *)((LPBYTE)PTR_SEG_OFF_TO_LIN( frame->module_cs, frame->callfrom_ip ) + 4);
278 }
279
280
281 /***********************************************************************
282  *           BUILTIN_RegisterDLL
283  *
284  * Register a built-in DLL descriptor.
285  */
286 void BUILTIN_RegisterDLL( const BUILTIN16_DESCRIPTOR *descr )
287 {
288     assert( nb_dlls < MAX_DLLS );
289     builtin_dlls[nb_dlls++] = descr;
290 }
291
292
293 /**********************************************************************
294  *          BUILTIN_DefaultIntHandler
295  *
296  * Default interrupt handler.
297  */
298 void WINAPI BUILTIN_DefaultIntHandler( CONTEXT86 *context )
299 {
300     WORD ordinal;
301     char name[80];
302     BUILTIN_GetEntryPoint16( CURRENT_STACK16, name, &ordinal );
303     INT_BARF( context, ordinal - FIRST_INTERRUPT_ORDINAL );
304 }