Added a .xcnlnk section to builtin KERNEL32 PE header.
[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     int i;
187
188     /* Fix the name in case we have a full path and extension */
189
190     if ((p = strrchr( name, '\\' ))) name = p + 1;
191     lstrcpynA( dllname, name, sizeof(dllname) );
192     p = strrchr( dllname, '.' );
193          
194     if (!p) strcat( dllname, ".dll" );
195
196     for (i = 0; i < nb_dlls; i++)
197     {
198         const BUILTIN16_DESCRIPTOR *descr = builtin_dlls[i];
199         NE_MODULE *pModule = (NE_MODULE *)descr->module_start;
200         OFSTRUCT *pOfs = (OFSTRUCT *)((LPBYTE)pModule + pModule->fileinfo);
201         if (!lstrcmpiA( pOfs->szPathName, dllname ))
202             return BUILTIN_DoLoadModule16( descr );
203     }
204     return (HMODULE16)2;
205 }
206
207
208 /***********************************************************************
209  *           BUILTIN_GetEntryPoint16
210  *
211  * Return the ordinal, name, and type info corresponding to a CS:IP address.
212  * This is used only by relay debugging.
213  */
214 LPCSTR BUILTIN_GetEntryPoint16( STACK16FRAME *frame, LPSTR name, WORD *pOrd )
215 {
216     WORD i, max_offset;
217     register BYTE *p;
218     NE_MODULE *pModule;
219     ET_BUNDLE *bundle;
220     ET_ENTRY *entry;
221
222     if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) ))))
223         return NULL;
224
225     max_offset = 0;
226     *pOrd = 0;
227     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
228     do 
229     {
230         entry = (ET_ENTRY *)((BYTE *)bundle+6);
231         for (i = bundle->first + 1; i <= bundle->last; i++)
232         {
233             if ((entry->offs < frame->entry_ip)
234             && (entry->segnum == 1) /* code segment ? */
235             && (entry->offs >= max_offset))
236             {
237                 max_offset = entry->offs;
238                 *pOrd = i;
239             }
240             entry++;
241         }
242     } while ( (bundle->next)
243            && (bundle = (ET_BUNDLE *)((BYTE *)pModule+bundle->next)));
244
245     /* Search for the name in the resident names table */
246     /* (built-in modules have no non-resident table)   */
247     
248     p = (BYTE *)pModule + pModule->name_table;
249     while (*p)
250     {
251         p += *p + 1 + sizeof(WORD);
252         if (*(WORD *)(p + *p + 1) == *pOrd) break;
253     }
254
255     sprintf( name, "%.*s.%d: %.*s",
256              *((BYTE *)pModule + pModule->name_table),
257              (char *)pModule + pModule->name_table + 1,
258              *pOrd, *p, (char *)(p + 1) );
259
260     /* Retrieve type info string */
261     return *(LPCSTR *)((LPBYTE)PTR_SEG_OFF_TO_LIN( frame->module_cs, frame->callfrom_ip ) + 4);
262 }
263
264
265 /***********************************************************************
266  *           BUILTIN_RegisterDLL
267  *
268  * Register a built-in DLL descriptor.
269  */
270 void BUILTIN_RegisterDLL( const BUILTIN16_DESCRIPTOR *descr )
271 {
272     assert( nb_dlls < MAX_DLLS );
273     builtin_dlls[nb_dlls++] = descr;
274 }
275
276
277 /**********************************************************************
278  *          BUILTIN_DefaultIntHandler
279  *
280  * Default interrupt handler.
281  */
282 void WINAPI BUILTIN_DefaultIntHandler( CONTEXT86 *context )
283 {
284     WORD ordinal;
285     char name[80];
286     BUILTIN_GetEntryPoint16( CURRENT_STACK16, name, &ordinal );
287     INT_BARF( context, ordinal - FIRST_INTERRUPT_ORDINAL );
288 }