summaryrefslogblamecommitdiffstats
path: root/private/os2/ldr/ldrfixup.c
blob: 1e5941eba7b9ad9a6a1c113fdcd09fe3784a69cf (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483


































































































































































































































































































































































































































































































                                                                                               

#include "ldrextrn.h"
#ifdef PMNT
#define INCL_32BIT
#include "pmnt.h"
extern  PID     PMNTPMShellPid;
#endif

/***LP  ldrGetTgtMte - get target mte linear address
 *
 *  Get MTE of module referenced by ordinal number passed.  Use the
 *  ordinal number to index into the import module pointers table.
 *
 *  ENTRY   modord          - ordinal number of module referenced
 *      pmte            - pointer to mte
 *      pptgtmte        - pointer to target mte
 *
 *  EXIT    int         - return code (NO_ERROR if successful)
 *      ptgtmte         - mte linear address
 *                    if mte == 0 reference to DOSCALLS
 *
 *   This procedure performs the following steps:
 *
 *  - Check that module ordinal number is within module pointer table
 *  - Index into module pointer table and return linear address to mte
 */

APIRET  ldrGetTgtMte(modord, pmte, pptgtmte)
ushort_t    modord;
ldrmte_t    *pmte;
ldrmte_t    **pptgtmte;
{
    modord--;               /* normalize ordinal */

    if (modord < (ushort_t) pmte->mte_impmodcnt) {
        *pptgtmte = ((ldrmte_t *) ((ulong_t *) pmte->mte_modptrs)[modord]);
        return(NO_ERROR);
    }

    /*
     * set error = ERROR_BAD_EXE_FORMAT
     */
    return(ERROR_BAD_EXE_FORMAT);
}

/***LP  ldrGetEntAddr - get entry point address
 *
 *  For a given ordinal number, this routine locates the
 *  appropriate entry contained in the module's entry table.
 *  It returns a 48-bit pointer for the specified entry point.
 *
 *  ENTRY   entord -  ordinal number
 *      pmte - pointer to target mte
 *      ptaddr - pointer to return target address (off,sel,flags)
 *      psrcste - pointer to source ste
 *      psrcmte - pointer to source mte
 *
 *  EXIT    entry point address
 *      global variable obj_ptr pointing to target segment
 *      global variable entry_ptr pointing to entry table entry
 *
 *   This procedure performs the following steps:
 *
 *  - Check for zero ordinal number
 *  - Normalize ordinal number
 *  - Checks and handles installable file system mte entry points
 *  - Checks and handles DOSCALLS mte entry points
 *  - Locates the correct bundle for the given ordinal
 *  - Creates the desired entry point address based on source and target
 */

APIRET  ldrGetEntAddr(entord, pmte, ptaddr, psrcste, psrcmte)
ushort_t        entord;
register ldrmte_t   *pmte;
register struct taddr_s *ptaddr;
ldrste_t        *psrcste;
ldrmte_t        *psrcmte;
{
    int         fcallgate;
    ulong_t         objnum;
    ldrsmte_t       *psmte;

    UNREFERENCED_PARAMETER(psrcmte);

    psmte = pmte->mte_swapmte;

    (ulong_t) ldrProcNameBuf = (ulong_t) entord;

    if (entord == 0) {
        return(ERROR_INVALID_ORDINAL);
    }
#if PMNT
    /*
     * This process loads PMWIN.WinCreateMsgQueue()
     */
    if (entord == 58 &&
        5 == (USHORT) *((PCHAR )pmte->mte_modname) &&
        ! strncmp((PCHAR)(pmte->mte_modname+1),"PMWIN",5)) {
        CurrentThread->Process->Flags |= OS2_PROCESS_PMMSGQUE;
    }
    /*
     * This process loads PMNT.PMNTSetPMshellFlag(), thus it is PM Shell.
     */
    else if (entord == 12 &&
        4 == (USHORT) *((PCHAR )pmte->mte_modname) &&
        ! strncmp((PCHAR)(pmte->mte_modname+1),"PMNT",4)) {
        if (!PMNTPMShellPid) {
            PMNTPMShellPid = CurrentThread->Process->ProcessId;
            CurrentThread->Process->Flags |= OS2_PROCESS_IS_PMSHELL;
        }
        else {
            // Do not allow another PMshell
            return(ERROR_2ND_PMSHELL);
        }
    }

#endif

    --entord;           /* Normalize object number */

    ptaddr->fflags = 0;     /* Clear forwarder flags */
    fcallgate = FALSE;      /* assume not a callgate entry */

    if (ldrIsNE(pmte)) {    /* check for 16-bit module */

        register ldrste_t   *pste;
        register ldret_t    *pbndl;
        ldrcte_t            *pcte;
        ldrent_t            *pent;

        /*
         * Find entry point, loop to determine which bundle the
         * ordinal number belongs too.
         */
        pbndl = (ldret_t *) psmte->smte_enttab;

        while (TRUE) {                  /* find bundle ord is in */
            if (pbndl->et_cnt == 0) {   /* check for end of table */
                return(ERROR_INVALID_ORDINAL);
            }

            if (entord < pbndl->et_cnt) /* is ord in this bundle? */
                break;

            entord -= pbndl->et_cnt;
            pbndl = (ldret_t *)((char *) pbndl +
                    ldrSkipEnts(pmte, pbndl->et_type, pbndl->et_cnt));
        }

        if (pbndl->et_type == EMPTY) {/* check for empty bundle */
            return(ERROR_INVALID_ORDINAL);
        }

        pent = (ldrent_t *)((char *) pbndl +
           ldrSkipEnts(pmte, pbndl->et_type, (uchar_t) entord));
        pcte = (ldrcte_t *) pent;

        ptaddr->fflags |= FWD_ALIAS16;      /* indicate tiled object */
        if (pbndl->et_type == B16MOVABLE) { /* check for movable entry */
            objnum = pcte->cte_obj;
            /* get target object */
            if (objnum == B16ABSOLUTE) {    /* if absolute entry */
                ptaddr->toff = (ulong_t) pcte->cte_off;
                ptaddr->tsel = 0;
                ptaddr->tflags = pcte->cte_flags;
                return(NO_ERROR);
            }
            if (objnum > psmte->smte_objcnt) {
                return(ERROR_INVALID_SEGMENT_NUMBER);
            }
            pste = (ldrste_t *) psmte->smte_objtab + objnum - 1;
            ptaddr->toff = (ulong_t) pcte->cte_off;
            //
            // If the target object is a code segment which has IOPL (ring 2)
            // create call gate emulation
            //
            if ((pcte->cte_sel != 0) &&
                (pcte->cte_sel != 0x3fcd) &&
                ((psrcste == NULL) ||  // ldrDosGetProcAddress() calls with NULL
                (((psrcste->ste_flags & STE_SEGDPL) == STE_RING_3) &&
                 ((psrcste->ste_flags & STE_DATA) == 0))) // source is a code segment
               ) {
                ptaddr->fflags |= FWD_IOPL;
                ptaddr->toff = (ulong_t)pcte->cte_sel;
                ptaddr->tsel = FLATTOSEL(R2XFER_BASE);
                return(NO_ERROR);
            }
        }

        /*
         * check for absolute entry
         */
        else if (pbndl->et_type == B16ABSOLUTE) {
            ptaddr->toff = (ulong_t) pent->ent_off;
            ptaddr->tsel = 0;
            ptaddr->tflags = pent->ent_flags;
            return(NO_ERROR);
        }
        else {  /* entry is fixed */
            if((ulong_t) pbndl->et_type > psmte->smte_objcnt) {
                return(ERROR_INVALID_SEGMENT_NUMBER);
            }

            /*
             * get target object
             */
            pste = (ldrste_t *) psmte->smte_objtab + pbndl->et_type - 1;
            ptaddr->toff = (ulong_t) pent->ent_off;
        }

        ptaddr->tsel = pste->ste_selector | 7;
        ptaddr->tflags = pent->ent_flags;
        return(NO_ERROR);
    }

    return(NO_ERROR);
}


/***LP  ldrGetOrdNum - get the ordinal number for procedure name
 *
 *  Given a procedure name and a module table, checks to see if
 *  the procedure is in the resident or nonresident table.  If the
 *  procedure is found in either of the tables, ldrGetOrdNum
 *  returns the corresponding ordinal number.  A 0 ordinal is
 *  returned if the procedure is not found in either of the tables.
 *
 *  ENTRY   pmte - pointer to module table entry
 *      pprocnam - pointer to procedure name
 *      pentord - address to return ordinal number
 *      fstring - flag to tell if null terminated
 *          STRINGNULLTERM
 *          STRINGPREPENDED
 *
 *  EXIT    if found
 *          NO_ERROR
 *      else
 *          ERROR_NOT_ENOUGH_MEMORY
 *          ERROR_PROC_NOT_FOUND
 */

APIRET  ldrGetOrdNum(pmte, pprocnam, pentord, fstring)
ldrmte_t        *pmte;
uchar_t         *pprocnam;
ushort_t        *pentord;
int         fstring;
{
    IO_STATUS_BLOCK     IoStatusBlock;
    PIO_STATUS_BLOCK    pIoStatusBlock = &IoStatusBlock;
    LARGE_INTEGER       ByteOffset;
    PVOID           MemoryAddress;
    ULONG           RegionSize;
    ulong_t         cbread;
    register ldrsmte_t  *psmte;
    ushort_t        proclen;
    char            tname[MAX_PROC_LEN+1];
    char            *ptname;
    int         rc = NO_ERROR;

    ptname = (char *) &tname;
    psmte = pmte->mte_swapmte;

    ldrProcNameBuf = (PUCHAR) (pprocnam + 1);
    ldrProcNameBufL = proclen = (USHORT) (pprocnam[0]);

    /*
     * Check for 32-bit module
     */
    if (ldrIsLE(pmte)) {
        struct ExpHdr   *pexpdir;
        ulong_t     *pexpnameptrs;
        ushort_t        *pexpordinals;

        if (fstring == STRINGNONNULL) {

        /*
             * Since the procedure name strings in a 32-bit module are in
             * the format of a null terminated string we need to convert
             * the 16-bit formated string of a length followed by string
         * to a null terminated string.
             */
        proclen = pprocnam[0];
        memcpy(pprocnam, pprocnam + 1, proclen);
        pprocnam[proclen] = '\0';
        }
        pexpdir = (struct ExpHdr *) psmte->smte_expdir;
        pexpnameptrs = (ulong_t *) pexpdir->exp_name;
        pexpordinals = (ushort_t *) pexpdir->exp_ordinal;
//      rc = ldrBinarySearchOrd(psmte,
//                  pprocnam,
//                  pexpnameptrs,
//                  pexpordinals,
//                  pexpdir->exp_namecnt,
//                  pentord);
        /*
         * Restore procedure name back to length followed by string.
         */
//      if (fstring == STRINGNONNULL) {
//      ldrStrCpyB(pprocnam + 1, pprocnam, proclen);
//      pprocnam[0] = (uchar_t) proclen;
//      }

        return(rc);
    }

    /*
     * Check for null terminated string passed.  If it is we were called
     * by ldrGetProcAddr and we may do this in place copy and not restore
     * it because it is from the stack of ldrGetProcAddr
     */
    if (fstring == STRINGNULLTERM) {
        proclen = (ushort_t) strlen(pprocnam);
        strncpy(&ptname[1], pprocnam, proclen);
        ptname[0] = (uchar_t) proclen;
    }

    else {
        strncpy(ptname, pprocnam, proclen + 1);
    }

    /*
     * 16-bit module, first search the resident name table.
     */
    if ((rc = ldrGetOrdNumSub((uchar_t *) psmte->smte_restab,
                  ptname,
                  pentord)) != ERROR_PROC_NOT_FOUND) {
        return(rc);
    }
#if DBG
    IF_OL2_DEBUG ( FIXUP ) {
    if (fstring == STRINGNONNULL) {
        strncpy(&tname[0], &pprocnam[1], proclen);
        tname[proclen] = '\0';
        DbgPrint(
      "Could not find Procedure %s in module %s in Resident name table\n",
             &tname, (char *) (pmte->mte_modname+1));
    }
    else {
        DbgPrint(
      "Could not find Procedure %s in module %s in Resident name table\n",
             pprocnam, (char *) (pmte->mte_modname+1));
        }

    if (fstring == STRINGNONNULL) {
        strncpy(ptname, pprocnam, proclen + 1);
        }
    }
#endif

    /*
     * The procedure name was not found in the resident name table,
     * need to search the non-resident name table.
     * Do not do this for system dll's other than doscall
     */

    if (pmte->mte_mflags & DOSMOD) {
        return(ERROR_PROC_NOT_FOUND);
    }

    RegionSize = psmte->smte_cbnrestab;
    MemoryAddress = 0;
    if ((rc = NtAllocateVirtualMemory(NtCurrentProcess(),
                      &MemoryAddress,
                      0,
                      &RegionSize,
                      MEM_COMMIT,
                      PAGE_READWRITE)) != NO_ERROR) {
        return(ERROR_PROC_NOT_FOUND);
    }

    /*
     * read the non-resident nametable from the file into non-
     * resident name table object.
     */
    ByteOffset.LowPart = psmte->smte_nrestab;
    ByteOffset.HighPart = 0;
    cbread = psmte->smte_cbnrestab;
    if ((rc = NtReadFile(pmte->mte_sfn,
                 0,
                 0,
                 0,
                 &IoStatusBlock,
                 (void *) MemoryAddress,
                 cbread,
                 &ByteOffset,
                 0)) != 0) {
        return(ERROR_BAD_EXE_FORMAT);
    }

    if (IoStatusBlock.Information != cbread) {
        rc = ERROR_BAD_EXE_FORMAT;
        goto returnstatus;
    }

    /*
     * Now check if the procname is in the nonresident name table.
     */
    rc = ldrGetOrdNumSub((uchar_t *) MemoryAddress,
                 ptname,
                 pentord);
returnstatus:
    NtFreeVirtualMemory(NtCurrentProcess(),
                &MemoryAddress,
                &cbread,
                MEM_RELEASE);
    if (rc == NO_ERROR)
        return(rc);

    if (fstring == STRINGNONNULL) {
        strncpy(&ptname[0], &pprocnam[1], proclen);
        ptname[proclen] = '\0';
    }
#if DBG
    IF_OL2_DEBUG ( FIXUP ) {
    DbgPrint(
       "Could not find Procedure %s in module %s in Non-resident table\n",
        ptname, (char *) (pmte->mte_modname+1));
    }
#endif
    return(ERROR_PROC_NOT_FOUND);
}


/***LP  ldrGetOrdNumSub - get the ordinal number for procedure name
 *
 *  Given a procedure name and a resident or nonresident name table
 *  containing the procedures exported by a module, checks to see
 *  if the procedure is in the table.  If the procedure is found
 *  in the table, ldrGetOrdNumSub gets the corresponding ordinal
 *  number.  A 0 ordinal value is returned if the procedure is not
 *  found in the table.  The ordinal number for the module name string
 *  is set to zero, therefore matching strings with a 0 ordinal number
 *  are skipped.
 *
 *  ENTRY   pnt - pointer to resident or nonresident name table
 *      pprocnam - pointer to procedure name
 *      pentord - place to return ordinal
 *
 *  EXIT    if found
 *          NO_ERROR
 *      else
 *          ERROR_PROC_NOT_FOUND
 *          ERROR_BAD_EXE_FORMAT
 *
 *   This procedure performs the following steps:
 *
 *  - compare procedure name to each entry in table
 *  - if ordinal number is 0 skip to next string
 *  - return ordinal number if found
 */

APIRET          ldrGetOrdNumSub(pnt, pprocnam, pentord)
register uchar_t    *pnt;
register uchar_t    *pprocnam;
ushort_t        *pentord;
{
    register int len;


    /*
     * remove typeinfo from length
     */
    while ((len = (int) (*pnt /*& ~NT_TYPEINFO*/)) != 0) { // YOSEFD: The using of the flag
                                                           // harm the names that are longer
                                                           // then 0x7F. The description string
                                                           // can be longer.
        /*
        * include string size field
        */
        if (memcmp(pnt, pprocnam, ++len) == 0)

        if ((*(ushort_t *) (pnt + len)) != 0) {
            /*
             * return ordinal number
             */
            *pentord = *(ushort_t *)(pnt + len);
            return(NO_ERROR);
        }
        pnt += len + sizeof(ushort_t);  /* skip to next string */
    }

    return(ERROR_PROC_NOT_FOUND);   /* end of table, return not found */
}