source: trunk/src/win32k/dev16/probkrnl.c@ 2836

Last change on this file since 2836 was 2836, checked in by bird, 26 years ago

ProbKrnl and code for importing krnl symbols has been enhanched.
Now we'll lock 32-bit segments into memory too.
And some other fixes...

File size: 36.4 KB
Line 
1/* $Id: probkrnl.c,v 1.13 2000-02-21 04:45:45 bird Exp $
2 *
3 * Description: Autoprobes the os2krnl file and os2krnl[*].sym files.
4 * Another Hack!
5 *
6 * 16-bit inittime code.
7 *
8 * All data has to be initiated because this is 16-bit C code
9 * and is to be linked with 32-bit C/C++ code. Uninitiazlied
10 * data ends up in the BSS segment, and that segment can't
11 * both be 32-bit and 16-bit. I have not found any other way
12 * around this problem that initiating all data.
13 *
14 * How this works:
15 * 1. parses the device-line parameters and collects some "SysInfo".
16 * 2. gets the kernel object table. (elf$)
17 * 3. finds the kernel image and scans it for a build number.
18 * 4. locates and scans the symbol-file(s) for the entrypoints which are wanted.
19 * 5. the entry points are verified. (elf$)
20 * 6. finished.
21 *
22 * Copyright (c) 1998-2000 knut st. osmundsen
23 *
24 * Project Odin Software License can be found in LICENSE.TXT
25 *
26 */
27
28
29/*******************************************************************************
30* Defined Constants And Macros *
31*******************************************************************************/
32#ifdef DEBUGR3
33 #if 1
34 int printf(const char *, ...);
35 #define dprintf(a) printf a
36 #else
37 #define dprintf(a)
38 #endif
39#else
40 #define dprintf(a)
41 #define static
42#endif
43
44#define fclose(a) DosClose(a)
45#define SEEK_SET FILE_BEGIN
46#define SEEK_END FILE_END
47
48#define WORD unsigned short int
49#define DWORD unsigned long int
50
51/* "@#IBM:14.039#@ os2krnl... "*/
52/* "@#IBM:8.264#@ os2krnl... "*/
53#define KERNEL_ID_STRING_LENGTH 42
54#define KERNEL_READ_SIZE 512
55
56#define INCL_BASE
57#define INCL_DOS
58
59
60/*******************************************************************************
61* Header Files *
62*******************************************************************************/
63#include <os2.h>
64
65#include <exe386.h>
66#include <strat2.h>
67#include <reqpkt.h>
68
69#include "os2krnl.h" /* must be included before dev1632.h! */
70#include "sym.h"
71#include "probkrnl.h"
72#include "dev16.h"
73#include "dev1632.h"
74
75
76/*******************************************************************************
77* Global Variables *
78* Note: must be inited or else we'll get BSS segment *
79*******************************************************************************/
80/*
81 * kernel data - !only valid during init!
82 */
83
84/*
85 * aImportTab defines the imported and overloaded OS/2 kernel functions.
86 * IMPORTANT: aImportTab has a sibling array in d32init.c, aulProc, which must
87 * match entry by entry. Adding/removing/shuffling aImportTab, aulProc
88 * has to be updated immediately!
89 */
90IMPORTKRNLSYM aImportTab[NBR_OF_KRNLIMPORTS] =
91{/* iFound cchName offObject usSel fType */
92 /* iObject achName ulAddress cProlog */
93 {FALSE, -1, 8, "_ldrRead", -1, -1, -1, -1, EPT_PROC32}, /* 0 */
94 {FALSE, -1, 8, "_ldrOpen", -1, -1, -1, -1, EPT_PROC32}, /* 1 */
95 {FALSE, -1, 9, "_ldrClose", -1, -1, -1, -1, EPT_PROC32}, /* 2 */
96 {FALSE, -1, 12, "_LDRQAppType", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 3 */ /* to be removed? */
97 {FALSE, -1, 20, "_ldrEnum32bitRelRecs", -1, -1, -1, -1, EPT_PROC32}, /* 4 */
98 {FALSE, -1, 10, "_IOSftOpen", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 5 */
99 {FALSE, -1, 11, "_IOSftClose", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 6 */
100 {FALSE, -1, 15, "_IOSftTransPath", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 7 */
101 {FALSE, -1, 12, "_IOSftReadAt", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 8 */
102 {FALSE, -1, 13, "_IOSftWriteAt", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 9 */
103 {FALSE, -1, 12, "_SftFileSize", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 10 */
104 {FALSE, -1, 11, "_VMAllocMem", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 11 */
105 {FALSE, -1, 11, "_VMGetOwner", -1, -1, -1, -1, EPT_PROCIMPORT32}, /* 12 */
106 {FALSE, -1, 11, "g_tkExecPgm", -1, -1, -1, -1, EPT_PROC32}, /* 13 */
107 {FALSE, -1, 11, "f_FuStrLenZ", -1, -1, -1, -1, EPT_PROCIMPORT16}, /* 14 */
108 {FALSE, -1, 8, "f_FuBuff", -1, -1, -1, -1, EPT_PROCIMPORT16} /* 15 */
109/* {FALSE, -1, 11, "", -1, -1, -1, EPT_PROCIMPORT16} */ /* 16 */
110};
111
112unsigned long int ulBuild = 0;
113unsigned short usVerMajor = 0;
114unsigned short usVerMinor = 0;
115
116
117/*
118 * privat data
119 */
120static int fQuiet = 0;
121static char szUsrOS2Krnl[50] = {0};
122static char szOS2Krnl[] = {"c:\\os2krnl"};
123
124static char szUsrSym[50] = {0};
125static char * apszSym[] =
126{
127 {"c:\\os2krnl.sym"}, /* usual for debugkernel */
128 {"c:\\os2\\pdpsi\\pmdf\\warp4\\os2krnlr.sym"}, /* warp 4 */
129 {"c:\\os2\\pdpsi\\pmdf\\warp4\\os2krnld.sym"}, /* warp 4 */
130 {"c:\\os2\\pdpsi\\pmdf\\warp4\\os2krnlb.sym"}, /* warp 4 */
131 {"c:\\os2\\pdpsi\\pmdf\\warp45_u\\os2krnlr.sym"}, /* warp 45 */
132 {"c:\\os2\\pdpsi\\pmdf\\warp45_u\\os2krnld.sym"}, /* warp 45 */
133 {"c:\\os2\\pdpsi\\pmdf\\warp45_u\\os2krnlb.sym"}, /* warp 45 */
134 {"c:\\os2\\pdpsi\\pmdf\\warp45_s\\os2krnlr.sym"}, /* warp 45 */
135 {"c:\\os2\\pdpsi\\pmdf\\warp45_s\\os2krnld.sym"}, /* warp 45 */
136 {"c:\\os2\\pdpsi\\pmdf\\warp45_s\\os2krnlb.sym"}, /* warp 45 */
137 {"c:\\os2\\system\\trace\\os2krnl.sym"}, /* warp 3 ?*/
138 {"c:\\os2\\system\\pmdf\\os2krnlr.sym"}, /* warp 3 ?*/
139 {"c:\\os2krnlr.sym"}, /* custom */
140 {"c:\\os2krnlh.sym"}, /* custom */
141 {"c:\\os2krnld.sym"}, /* custom */
142 NULL
143};
144
145static KRNLOBJTABLE KrnlOTEs = {0};
146
147/* messages */
148static char szBanner[] = "Win32k - Odin32 support driver.";
149static char szMsg1[] = "\n\r Found kernel: ";
150static char szMsg1a[] = "\n\r Build: ";
151static char szMsg2[] = "\n\r Found symbolfile: ";
152static char szMsg4[] = "\n\r Failed to find symbolfile!\n\r";
153static char szMsgfailed[]= "failed! ";
154
155
156/*******************************************************************************
157* Internal Functions *
158*******************************************************************************/
159/* File an output replacements */
160static HFILE fopen(const char * pszFilename, const char * pszIgnored);
161static int fread(void * pvBuffer, USHORT cbBlock, USHORT cBlock, HFILE hFile);
162static int fseek(HFILE hfile, signed long off, int iOrg);
163static unsigned long fsize(HFILE hFile);
164static void puts(char *psz);
165
166/* C-library replacements. */
167static void kmemcpy(char *psz1, const char *psz2, int cch);
168static char * kstrstr(const char *psz1, const char *psz2);
169static int kstrcmp(const char *psz1, const char *psz2);
170static int kstrncmp(const char *psz1, const char *psz2, int cch);
171static int kstrnicmp(const char *psz1, const char *psz2, int cch);
172static int kstrlen(const char *psz);
173static int kargncpy(char *pszTarget, const char *pszArg, unsigned cchMaxlen);
174
175/* Workers */
176static int VerifyPrologs(void);
177static int ProbeSymFile(char *pszFilename);
178static int VerifyKernelVer(void);
179static int ReadOS2Krnl(char *pszFilename);
180static int ReadOS2Krnl2(HFILE hKrnl, unsigned long cbKrnl);
181static int GetKernelOTEs(void);
182
183/* Ouput */
184static void ShowDecNumber(unsigned long ul);
185static void ShowHexNumber(unsigned long ul);
186static void ShowResult(int rc, int iSym);
187
188
189
190
191/*******************************************************************************
192* Implementation of Internal Helper Functions *
193*******************************************************************************/
194
195/**
196 * Quick implementation of fopen.
197 * @param pszFilename name of file to open (sz)
198 * @param pszIgnored whatever - it is ignored
199 * @return Handle to file. (not pointer to a FILE stream as in C-library)
200 * @remark binary and readonly is assumed!
201 */
202static HFILE fopen(const char * pszFilename, const char * pszIgnored)
203{
204 HFILE hFile = 0;
205 USHORT rc;
206 unsigned short Action = 0;
207
208 rc = DosOpen(
209 (char*)pszFilename,
210 &hFile,
211 &Action,
212 0,
213 FILE_NORMAL,
214 OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
215 OPEN_SHARE_DENYNONE + OPEN_ACCESS_READONLY,
216 NULL);
217
218 pszIgnored = pszIgnored;
219 return hFile;
220}
221
222
223/**
224 * fread emulation
225 * @returns Number of blocks read.
226 * @param pvBuffer Buffer to read into
227 * @param cbBlock Blocksize
228 * @param cBlock Block count
229 * @param hFile Handle to file (HFILE)
230 */
231static int fread(void * pvBuffer, USHORT cbBlock, USHORT cBlock, HFILE hFile)
232{
233 USHORT ulRead;
234 USHORT rc;
235
236 rc = DosRead(hFile, pvBuffer, (USHORT)(cbBlock*cBlock), &ulRead);
237 if (rc == 0)
238 rc = (USHORT)cBlock;
239 else
240 rc = 0;
241
242 return rc;
243}
244
245
246/**
247 * fseek emultation
248 * @returns Same as DosChgFilePtr
249 * @param hFile Filehandle
250 * @param off offset into file from origin
251 * @param org origin
252 */
253static int fseek(HFILE hFile, signed long off, int iOrg)
254{
255 ULONG ul;
256 return (int)DosChgFilePtr(hFile, off, iOrg, &ul);
257}
258
259
260/**
261 * Get filesize in bytes.
262 * @returns Filesize.
263 * @param hFile Filehandle
264 * @remark This function sets the file position to end of file.
265 */
266static unsigned long fsize(HFILE hFile)
267{
268 USHORT rc;
269 unsigned long cb;
270
271 rc = DosChgFilePtr(hFile, 0, FILE_END, &cb);
272
273 return cb;
274}
275
276
277/**
278 * puts lookalike
279 */
280static void puts(char * psz)
281{
282 DosPutMessage(0, kstrlen(psz), psz);
283}
284
285
286/**
287 * kmemcpy - memory copy - slow!
288 * @param psz1 target
289 * @param psz2 source
290 * @param cch length
291 */
292static void kmemcpy(char *psz1, const char *psz2, int cch)
293{
294 while (cch-- != 0)
295 *psz1++ = *psz2++;
296}
297
298
299/**
300 * Finds psz2 in psz2.
301 * @returns Pointer to occurence of psz2 in psz1.
302 * @param psz1 String to be search.
303 * @param psz2 Substring to search for.
304 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
305 */
306static char *kstrstr(const char *psz1, const char *psz2)
307{
308 while (*psz1 != '\0')
309 {
310 register int i = 0;
311 while (psz2[i] != '\0' && psz1[i] == psz2[i])
312 i++;
313
314 /* found it? */
315 if (psz2[i] == '\0')
316 return (char*)psz1;
317 if (psz1[i] == '\0' )
318 break;
319 psz1++;
320 }
321
322 return NULL;
323}
324
325
326#if 0 /* not in use */
327/**
328 * kstrcmp - String compare
329 * @returns 0 - equal else !0
330 * @param psz1 String 1
331 * @param psz2 String 2
332 */
333static int kstrcmp(const char *psz1, const char *psz2);
334{
335 while (*psz1 == *psz2 && *psz1 != '\0' && *psz2 != '\0')
336 {
337 psz1++;
338 psz2++;
339 }
340 return *psz1 - *psz2;
341}
342#endif
343
344
345/**
346 * kstrncmp - String 'n' compare.
347 * @returns 0 - equal else !0
348 * @param p1 String 1
349 * @param p2 String 2
350 * @param len length
351 */
352static int kstrncmp(register const char *psz1, register const char *psz2, int cch)
353{
354 int i = 0;
355 while (i < cch && *psz1 == *psz2 && *psz1 != '\0' && *psz2 != '\0')
356 {
357 psz1++;
358 psz2++;
359 i++;
360 }
361
362 return i - cch;
363}
364
365
366#if 0 /* not in use */
367/**
368 * kstrnicmp - String 'n' compare, case-insensitive.
369 * @returns 0 - equal else !0
370 * @param p1 String 1
371 * @param p2 String 2
372 * @param len length
373 */
374static int kstrnicmp(const char *psz1, const char *psz2, int cch)
375{
376 register char ch1, ch2;
377
378 do
379 {
380 ch1 = *psz1++;
381 if (ch1 >= 'A' && ch1 <= 'Z')
382 ch1 += 'a' - 'A'; /* to lower case */
383 ch2 = *psz2++;
384 if (ch2 >= 'A' && ch2 <= 'Z')
385 ch2 += 'a' - 'A'; /* to lower case */
386 } while (--cch > 0 && ch1 == ch2 && ch1 != '\0' && ch2 != '\0');
387
388 return ch1 - ch2;
389}
390#endif
391
392
393/**
394 * kstrlen - String length.
395 * @returns Length of the string.
396 * @param psz Pointer to string.
397 * @status completely implemented and tested.
398 * @author knut st. osmundsen
399 */
400static int kstrlen(register const char * psz)
401{
402 register int cch = 0;
403 while (*psz++ != '\0')
404 cch++;
405 return cch;
406}
407
408
409/**
410 * Copy an argument to a buffer. Ie. "-K[=|:]c:\os2krnl ....". Supports quotes
411 * @returns Number of chars of pszArg that has been processed.
412 * @param pszTarget - pointer to target buffer.
413 * @param pszArg - pointer to source argument string.
414 * @param cchMaxlen - maximum chars to copy.
415 */
416static int kargncpy(char * pszTarget, const char * pszArg, unsigned cchMaxlen)
417{
418 int i = 0;
419 int fQuote = FALSE;
420
421 /* skip option word/letter */
422 while (*pszArg != '\0' && *pszArg != ' ' && *pszArg != ':' &&
423 *pszArg != '=' && *pszArg != '-' && *pszArg != '/')
424 {
425 pszArg++;
426 i++;
427 }
428
429 if (*pszArg == ' ' || *pszArg == '-' || *pszArg == '/' || *pszArg == '\0')
430 return 0;
431
432
433 do
434 {
435 pszArg++;
436 i++;
437 } while (*pszArg != '\0' && *pszArg == ' ');
438
439 /* copy maxlen or less */
440 /* check for quotes */
441 if (*pszArg == '"')
442 {
443 fQuote = TRUE;
444 pszArg++;
445 i++;
446 }
447 /* copy loop */
448 while (cchMaxlen > 1 && (fQuote ? *pszArg != '"' : *pszArg != ' ') && *pszArg != '\0')
449 {
450 *pszTarget++ = *pszArg++;
451 i++;
452 cchMaxlen--;
453 }
454
455 /* terminate pszTarget */
456 pszTarget = '\0';
457
458 return i;
459}
460
461
462
463/*******************************************************************************
464* Implementation Of The Important Functions *
465*******************************************************************************/
466
467/**
468 * Verifies the that the addresses in aImportTab are valid.
469 * This is done at Ring-0 of course.
470 * @returns 0 if ok, not 0 if not ok.
471 */
472static int VerifyPrologs(void)
473{
474#ifndef DEBUGR3
475 APIRET rc;
476 HFILE hDev0 = 0;
477 USHORT usAction = 0;
478
479 rc = DosOpen("\\dev\\elf$", &hDev0, &usAction, 0UL, FILE_NORMAL,
480 OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
481 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY,
482 0UL);
483 if (rc == NO_ERROR)
484 {
485 rc = DosDevIOCtl("", "", D16_IOCTL_VERIFYPROCTAB, D16_IOCTL_CAT, hDev0);
486 DosClose(hDev0);
487 }
488
489 return rc;
490#else
491 return 0;
492#endif
493}
494
495
496/**
497 * Check a symbol file. Searches for the wanted entry-point addresses.
498 * @returns 0 on success - something else on failiure.
499 * @param pszFilename Name of file to probe.
500 * @precond Must be called after kernel-file is found and processed.
501 * @remark Error codes starts at -50.
502 */
503static int ProbeSymFile(char * pszFilename)
504{
505 HFILE hSym; /* Filehandle */
506 int cLeftToFind; /* Symbols left to find */
507 unsigned long iSeg; /* Outer search loop: Segment number */
508 unsigned iSym; /* Middle search loop: Symbol number */
509 unsigned i; /* Inner search loop: ProcTab index */
510 int rc;
511
512 MAPDEF MapDef; /* Mapfile header */
513 SEGDEF SegDef; /* Segment header */
514 SYMDEF32 SymDef32; /* Symbol definition 32-bit */
515 SYMDEF16 SymDef16; /* Symbol definition 16-bit */
516 char achBuffer[256]; /* Name buffer */
517 unsigned long offSegment; /* Segment definition offset */
518 unsigned long offSymPtr; /* Symbol pointer(offset) offset */
519 unsigned short offSym; /* Symbol definition offset */
520
521
522 /*
523 * Open the symbol file
524 */
525 hSym = fopen(pszFilename, "rb");
526 if (hSym==0)
527 {
528 dprintf(("Error opening file %s\n", pszFilename));
529 return -50;
530 }
531 dprintf(("\nSuccessfully opened symbolfile: %s\n", pszFilename));
532
533
534 /*
535 * (Open were successfully.)
536 * Now read header and display it.
537 */
538 rc = fread(&MapDef, sizeof(MAPDEF), 1, hSym);
539 if (!rc)
540 { /* oops! read failed, close file and fail. */
541 fclose(hSym);
542 return -51;
543 }
544 achBuffer[0] = MapDef.achModName[0];
545 fread(&achBuffer[1], 1, MapDef.cbModName, hSym);
546 achBuffer[MapDef.cbModName] = '\0';
547 dprintf(("*Module name: %s\n", achBuffer));
548 dprintf(("*Segments: %d\n*MaxSymbolLength: %d\n", MapDef.cSegs, MapDef.cbMaxSym));
549 dprintf(("*ppNextMap: 0x%x\n", MapDef.ppNextMap ));
550
551
552 /*
553 * Verify that the modulename of the symbol file is OS2KRNL.
554 */
555 if (MapDef.cbModName == 7 && kstrncmp(achBuffer, "OS2KRNL", 7) != 0)
556 { /* modulename was not OS2KRNL, fail. */
557 dprintf(("Modulename verify failed\n"));
558 fclose(hSym);
559 return -51;
560 }
561
562
563 /*
564 * Verify that the number of segments is equal to the number objects in OS2KRNL.
565 */
566 if (MapDef.cSegs != KrnlOTEs.cObjects)
567 { /* incorrect count of segments. */
568 dprintf(("Segment No. verify failed\n"));
569 fclose(hSym);
570 return -52;
571 }
572
573
574 /*
575 * Reset ProcTab
576 */
577 for (i = 0; i < NBR_OF_KRNLIMPORTS; i++)
578 aImportTab[i].fFound = 0;
579
580
581 /*
582 * Fileoffset of the first segment.
583 * And set cLeftToFind.
584 */
585 offSegment = SEGDEFOFFSET(MapDef);
586 cLeftToFind = NBR_OF_KRNLIMPORTS;
587
588 /*
589 * Search thru the entire file, segment by segment.
590 *
591 * ASSUME: last segment is the only 32-bit code segment.
592 *
593 */
594 for (iSeg = 0; iSeg < MapDef.cSegs; iSeg++, offSegment = NEXTSEGDEFOFFSET(SegDef))
595 {
596 int fSegEPTBitType; /* Type of segment, 16 or 32 bit, expressed in EPT_XXBIT flags */
597 int fCode; /* Set if this is a code segment, else clear. */
598
599 /*
600 * Read the segment definition.
601 */
602 if (fseek(hSym, offSegment, SEEK_SET))
603 { /* Failed to seek to the segment definition, fail! */
604 fclose(hSym);
605 return -53;
606 }
607 rc = fread(&SegDef, sizeof(SEGDEF), 1, hSym);
608 if (!rc)
609 { /* Failed to read the segment definition, fail! */
610 fclose(hSym);
611 return -53;
612 }
613
614 /*
615 * Some debugging info.
616 */
617 achBuffer[0] = SegDef.achSegName[0];
618 fread(&achBuffer[1], 1, SegDef.cbSegName, hSym);
619 achBuffer[SegDef.cbSegName] = '\0';
620 dprintf(("Segment %.2li Flags=0x%02x cSymbols=0x%04x Name=%s\n",
621 iSeg, SegDef.bFlags, SegDef.cSymbols, &achBuffer[0]));
622
623 /*
624 * Determin segment bit type.
625 */
626 fSegEPTBitType = SEG32BitSegment(SegDef) ? EPT_32BIT : EPT_16BIT;
627 fCode = kstrstr(achBuffer, "CODE") != NULL;
628
629 /*
630 * Search thru all the symbols in this segment
631 * while we look for the requested symbols in aImportTab.
632 */
633 for (iSym = 0; iSym < SegDef.cSymbols && cLeftToFind; iSym++)
634 {
635 unsigned cchName;
636 /*
637 * Fileoffset of the current symbol.
638 * Set filepointer to that position.
639 * Read word (which is the offset of the symbol).
640 */
641 offSymPtr = SYMDEFOFFSET(offSegment, SegDef, iSym);
642 rc = fseek(hSym, offSymPtr, SEEK_SET);
643 if (rc)
644 { /* Symboloffset seek failed, try read next symbol. */
645 dprintf(("Warning: Seek failed (offSymPtr=%d, rc=%d)\n", offSymPtr, rc));
646 continue;
647 }
648 rc = fread(&offSym, sizeof(unsigned short int), 1, hSym);
649 if (!rc)
650 { /* Symboloffset read failed, try read next symbol. */
651 dprintf(("Warning: read failed (offSymPtr=%d, rc=%d)\n", offSymPtr, rc));
652 continue;
653 }
654 rc = fseek(hSym, offSym + offSegment, SEEK_SET);
655 if (rc)
656 { /* Symbol Seek failed, try read next symbol. */
657 dprintf(("Warning: Seek failed (offSym=%d, rc=%d)\n", offSym, rc));
658 continue;
659 }
660
661
662 /*
663 * Read symbol and symbolname.
664 */
665 if (SegDef.bFlags & 0x01)
666 rc = fread(&SymDef32, sizeof(SYMDEF32), 1, hSym);
667 else
668 rc = fread(&SymDef16, sizeof(SYMDEF16), 1, hSym);
669 if (!rc)
670 { /* Symbol read failed, try read next symbol */
671 dprintf(("Warning: Read(1) failed (offSym=%d, rc=%d)\n", offSym, rc));
672 continue;
673 }
674 achBuffer[0] = (SegDef.bFlags & 0x01) ? SymDef32.achSymName[0] : SymDef16.achSymName[0];
675 cchName = (SegDef.bFlags & 0x01) ? SymDef32.cbSymName : SymDef16.cbSymName;
676 rc = fread(&achBuffer[1], 1, cchName, hSym);
677 if (!rc)
678 { /* Symbol read failed, try read next symbol */
679 dprintf(("Warning: Read(2) failed (offSym=%d, rc=%d)\n", offSym, rc));
680 continue;
681 }
682 achBuffer[cchName] = '\0';
683
684
685 /*
686 * Search proctable.
687 */
688 for (i = 0; i < NBR_OF_KRNLIMPORTS; i++)
689 {
690 if (!aImportTab[i].fFound /* Not allready found */
691 && (aImportTab[i].fType & EPT_BIT_MASK) == fSegEPTBitType /* Equal bittype */
692 && (fCode || (aImportTab[i].fType & EPT_VARIMPORT)) /* Don't look for code in a data segment and vice versa */
693 && aImportTab[i].cchName == cchName /* Equal name length */
694 && kstrncmp(aImportTab[i].achName, achBuffer, cchName) == 0 /* Equal name */
695 )
696 { /* Symbol was found */
697 aImportTab[i].offObject = (SegDef.bFlags & 0x01 ? SymDef32.wSymVal : SymDef16.wSymVal);
698 aImportTab[i].ulAddress = aImportTab[i].offObject + KrnlOTEs.aObjects[iSeg].ote_base;
699 aImportTab[i].usSel = KrnlOTEs.aObjects[iSeg].ote_sel;
700
701 /* Paranoia test! */
702 if (aImportTab[i].offObject < KrnlOTEs.aObjects[iSeg].ote_size)
703 {
704 aImportTab[i].fFound = TRUE;
705 cLeftToFind--;
706 dprintf(("Found: %s at off 0x%lx addr 0x%lx, sel=0x%x\n",
707 aImportTab[i].achName, aImportTab[i].offObject,
708 aImportTab[i].ulAddress, aImportTab[i].usSel));
709 }
710 else/* test failed, continue on next symbol*/
711 dprintf(("Error: Paranoia test failed for %s\n", aImportTab[i].achName));;
712 break;
713 }
714
715 } /* aImportTab for-loop */
716
717 } /* Symbol for-loop */
718
719 } /* Segment for-loop */
720
721 /*
722 * Close symbol file.
723 */
724 fclose(hSym);
725
726 /*
727 * If not all procedures were found fail.
728 */
729 if (cLeftToFind != 0)
730 return -57;
731
732 /*
733 * Verify function prologs and return.
734 */
735 return VerifyPrologs();
736}
737
738
739/**
740 * Verifies that build no, matches kernel number.
741 * @returns 0 on equal, !0 on error.
742 */
743static int VerifyKernelVer(void)
744{
745 int VerMinor, VerMajor;
746
747 VerMajor = ulBuild < 20000 ? 20 : 30/*?*/;
748 VerMinor = ulBuild < 6600 ? 10 : ulBuild < 8000 ? 11 : ulBuild < 9000 ? 30 :
749 ulBuild < 10000 ? 40 : ulBuild < 15000 ? 45 : 50;
750
751 return VerMajor - (int)usVerMajor | VerMinor - (int)usVerMinor;
752}
753
754
755/**
756 * Reads and verifies OS/2 kernel.
757 * @returns 0 on success, not 0 on failure.
758 * @param filename Filename of the OS/2 kernel.
759 * @result ulBuild is set.
760 * @remark This step will be eliminated by searching thru the DOSGROUP datasegment
761 * in the kernel memory. This segment have a string "Internal revision 9.034[smp|uni]"
762 * This would be much faster than reading the kernel file. It will also give us a more precise
763 * answer to the question! This is currently a TODO issue. !FIXME!
764 */
765static int ReadOS2Krnl(char * pszFilename)
766{
767 HFILE hKrnl;
768 unsigned long cbKrnl;
769 int rc;
770
771 hKrnl = fopen(pszFilename, "rb");
772 if (hKrnl != 0)
773 {
774 cbKrnl = fsize(hKrnl);
775 if (!fseek(hKrnl, 0, SEEK_SET))
776 rc = ReadOS2Krnl2(hKrnl, cbKrnl);
777 else
778 rc = -2;
779 fclose(hKrnl);
780 }
781 else
782 {
783 dprintf(("Could not open file\n"));
784 rc = -1;
785 }
786 return rc;
787}
788
789/**
790 * Worker function for ReadOS2Krnl
791 * @returns 0 on success.
792 * errorcodes on failure. (-1 >= rc >= -14)
793 * @param hKrnl Handle to the kernel file.
794 * @param cbKrnl Size of the kernel file.
795 * @author knut st. osmundsen
796 */
797static int ReadOS2Krnl2(HFILE hKrnl, unsigned long cbKrnl)
798{
799 int i, j;
800 int rc = 0;
801 char achBuffer[KERNEL_ID_STRING_LENGTH + KERNEL_READ_SIZE];
802 unsigned long offLXHdr;
803 struct e32_exe *pLXHdr;
804
805
806 /* find bldlevel string - "@#IBM:14.020#@ IBM OS/2 Kernel - 14.020F" */
807 if (fseek(hKrnl, 0, SEEK_SET))
808 return -2;
809
810 if (!fread(&achBuffer[KERNEL_ID_STRING_LENGTH], 1, KERNEL_READ_SIZE, hKrnl))
811 return -3;
812
813 i = KERNEL_ID_STRING_LENGTH;
814 while (cbKrnl > 0)
815 {
816 if (i == KERNEL_READ_SIZE)
817 {
818
819 kmemcpy(achBuffer, &achBuffer[KERNEL_READ_SIZE], KERNEL_ID_STRING_LENGTH);
820 if (!fread(&achBuffer[KERNEL_ID_STRING_LENGTH], 1, cbKrnl > KERNEL_READ_SIZE ? KERNEL_READ_SIZE : (int)cbKrnl, hKrnl))
821 return -3;
822
823 i = 0;
824 }
825
826 if (kstrncmp("@#IBM:", &achBuffer[i], 6) == 0)
827 break;
828
829 /* next */
830 i++;
831 cbKrnl--;
832 }
833
834 if (cbKrnl == 0)
835 {
836 fclose(hKrnl);
837 return -4;
838 }
839
840 /* displacement */
841 j = 0;
842 while (j < 6 && achBuffer[i+10+j] != '#')
843 j++;
844
845 /* verify signature */
846 if (kstrncmp(&achBuffer[i+10+j], "#@ IBM OS/2 Kernel", 19) != 0)
847 return -5;
848
849 /* read ulBuild */
850 ulBuild = (char)(achBuffer[i+6] - '0') * 1000;
851 if (achBuffer[i+7] != '.')
852 {
853 /* this code is for Warp5 */
854 ulBuild *= 10;
855 ulBuild += (char)(achBuffer[i+7] - '0') * 1000;
856 i++;
857 j--;
858 if (achBuffer[i+7] != '.')
859 {
860 ulBuild = ulBuild * 10;
861 ulBuild = ulBuild + (unsigned long)(achBuffer[i+7] - '0') * 1000;
862 i++;
863 j--;
864 }
865 }
866
867 if (j == 0)
868 {
869 ulBuild += (achBuffer[i+ 8] - '0') * 10;
870 ulBuild += (achBuffer[i+ 9] - '0') * 1;
871 } else
872 {
873 if (j == 3)
874 return -9;
875 ulBuild += (achBuffer[i+ 8] - '0') * 100;
876 ulBuild += (achBuffer[i+ 9] - '0') * 10;
877 ulBuild += (achBuffer[i+10] - '0');
878 }
879
880 if (VerifyKernelVer())
881 return -9;
882 dprintf(("ulBuild: %d\n",ulBuild));
883
884 /* get segment number */
885 /* read-MZheader */
886 if (fseek(hKrnl,0,SEEK_SET))
887 return -2;
888
889 if (!fread(achBuffer, 1, 0x40, hKrnl))
890 return -3;
891
892 offLXHdr = *(unsigned long int *)&achBuffer[0x3c];
893
894 if (offLXHdr > 0x2000 && offLXHdr < 0x80) /* just to detect garbage */
895 return -6;
896
897 if (fseek(hKrnl, offLXHdr, SEEK_SET))
898 return -2;
899
900 if (!fread(achBuffer, 1, sizeof(struct e32_exe), hKrnl))
901 return -3;
902
903 /* check LX-magic */
904 if (achBuffer[0] != 'L' || achBuffer[1] != 'X')
905 return -7;
906
907#ifndef DEBUGR3
908 /* check object count - match it with what we got from the kernel. */
909 pLXHdr = (struct e32_exe *)achBuffer;
910 if ((UCHAR)pLXHdr->e32_objcnt != KrnlOTEs.cObjects)
911 return -8;
912
913 if (pLXHdr->e32_objcnt < 10)
914 return -9;
915
916 /* check objects (sizes and flags(?)) */
917 if (!fseek(hKrnl, (LONG)offLXHdr + (LONG)pLXHdr->e32_objtab, SEEK_SET))
918 {
919 struct o32_obj *pObj = (struct o32_obj *)achBuffer;
920 for (i = 0; i < (int)KrnlOTEs.cObjects; i++)
921 {
922 if (!fread(achBuffer, 1, sizeof(OTE), hKrnl))
923 return -11;
924 if (pObj->o32_size < KrnlOTEs.aObjects[i].ote_size)
925 return -12;
926
927 #if 0 /* don't work! */
928 if ((pObj->o32_flags & 0xffffUL) != (KrnlOTEs.aObjects[i].ote_flags & 0xffffUL))
929 return -14;
930 #endif
931 }
932 }
933 else
934 return -10;
935#else
936 /* Since we can't get the OTEs from the kernel when debugging in RING-3,
937 * we'll use what we find in the kernel.
938 */
939
940 /* object count */
941 pLXHdr = (struct e32_exe *)achBuffer;
942 KrnlOTEs.cObjects = (UCHAR)pLXHdr->e32_objcnt;
943
944 /* get OTEs */
945 if (!fseek(hKrnl, (LONG)offLXHdr + (LONG)pLXHdr->e32_objtab, SEEK_SET))
946 {
947 struct o32_obj *pObj = (struct o32_obj *)achBuffer;
948 for (i = 0; i < (int)KrnlOTEs.cObjects; i++)
949 if (!fread(&KrnlOTEs.aObjects[i], 1, sizeof(struct o32_obj), hKrnl))
950 return -11;
951 }
952 else
953 return -10;
954#endif
955
956 return 0;
957}
958
959
960/**
961 * Gets the os/2 kernel OTE's (object table entries).
962 * @returns 0 on success. Not 0 on error.
963 */
964static int GetKernelOTEs(void)
965{
966#ifndef DEBUGR3
967 APIRET rc;
968 HFILE hDev0 = 0;
969 USHORT usAction = 0;
970
971 rc = DosOpen("\\dev\\elf$", &hDev0, &usAction, 0UL, FILE_NORMAL,
972 OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
973 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY,
974 0UL);
975 if (rc == NO_ERROR)
976 {
977 rc = DosDevIOCtl(&KrnlOTEs, "", D16_IOCTL_GETKRNLOTES, D16_IOCTL_CAT, hDev0);
978 DosClose(hDev0);
979 }
980
981 if (rc != NO_ERROR)
982 puts("Failed to get kernel OTEs\r\n");
983
984 return rc;
985#else
986 KrnlOTEs.cObjects = 23;
987 return 0;
988#endif
989}
990
991
992/**
993 * Displays an ULONG in decimal notation using DosPutMessage
994 * @param n ULONG to show.
995 */
996static void ShowDecNumber(unsigned long n)
997{
998 int f = 0;
999 unsigned long div;
1000 char sif;
1001
1002 for (div = 1000000; div > 0; div /= 10)
1003 {
1004 sif = (char)(n/div);
1005 n %= div;
1006 if (sif != 0 || f)
1007 {
1008 f = 1;
1009 sif += '0';
1010 DosPutMessage(0, 1, &sif);
1011 }
1012 }
1013}
1014
1015
1016/**
1017 * Displays an ULONG in hexadecimal notation using DosPutMessage
1018 * @param n ULONG to show.
1019 */
1020static void ShowHexNumber(unsigned long int n)
1021{
1022 signed int div;
1023 char sif;
1024 DosPutMessage(0, 2, "0x");
1025 for (div = 28; div >= 0; div -= 4)
1026 {
1027 sif = (char)(n >> div) & (char)0xF;
1028 sif += (sif < 10 ? '0' : 'a' - 10);
1029 DosPutMessage(0, 1, &sif);
1030 }
1031}
1032
1033
1034
1035/**
1036 * Shows result of kernelprobing if not quiet or on error.
1037 * @param rc Return code.
1038 * @param iSym index of .sym-file into static struct.
1039 */
1040static void ShowResult(int rc, int iSym)
1041{
1042 int i, j;
1043
1044 /* complain even if quiet on error */
1045 if (!fQuiet || rc != 0)
1046 {
1047 puts(szBanner);
1048
1049 /* kernel stuff */
1050 puts(szMsg1);
1051 if (rc <= -50 || rc == 0)
1052 {
1053 puts(szOS2Krnl);
1054 puts(szMsg1a);
1055 ShowDecNumber(ulBuild);
1056 puts(" - v");
1057 ShowDecNumber(usVerMajor);
1058 puts(".");
1059 ShowDecNumber(usVerMinor);
1060 }
1061 else
1062 puts(szMsgfailed);
1063
1064 /* functions */
1065 if (rc == 0)
1066 {
1067 puts(szMsg2);
1068 if (szUsrSym[0] == '\0')
1069 puts(apszSym[iSym]);
1070 else
1071 puts(szUsrSym);
1072
1073 for (i = 0; i < NBR_OF_KRNLIMPORTS; i++)
1074 {
1075 if ((i % 2) == 0)
1076 puts("\n\r ");
1077 else
1078 puts(" ");
1079 puts(aImportTab[i].achName);
1080 for (j = aImportTab[i].cchName; j < 20; j++)
1081 puts(" ");
1082
1083 puts(" at ");
1084 if (aImportTab[i].fFound)
1085 ShowHexNumber(aImportTab[i].ulAddress);
1086 else
1087 puts(szMsgfailed);
1088 }
1089 }
1090 else
1091 puts(szMsg4);
1092 puts("\n\r");
1093 }
1094
1095 /* if error: write rc */
1096 if (rc != 0)
1097 {
1098 puts("rc = ");
1099 ShowHexNumber((unsigned long)rc);
1100 puts("\n\r");
1101 }
1102}
1103
1104
1105
1106/**
1107 * "main" function.
1108 * Note that the option -Noloader causes nothing to be done.
1109 * @returns 0 on success, something else on error.
1110 * @param pReqPack Pointer to init request packet
1111 * @remark
1112 */
1113int ProbeKernel(PRPINITIN pReqPack)
1114{
1115 int rc;
1116 int i;
1117 int n;
1118 SEL GDT;
1119 SEL LDT;
1120 PGINFOSEG pInfoSeg;
1121 USHORT usBootDrive;
1122
1123 /*----------------*/
1124 /* parse InitArgs */
1125 /*----------------*/
1126 if (pReqPack != NULL && pReqPack->InitArgs != NULL)
1127 {
1128 n = kstrlen(pReqPack->InitArgs);
1129 for (i = 0; i < n; i++)
1130 {
1131 if ((pReqPack->InitArgs[i] == '/' || pReqPack->InitArgs[i] == '-') && (i+1) < n)
1132 {
1133 i++;
1134 switch (pReqPack->InitArgs[i])
1135 {
1136 case 'k':
1137 case 'K': /* Kernel file */
1138 i++;
1139 i += kargncpy(szUsrOS2Krnl, &pReqPack->InitArgs[i], sizeof(szUsrOS2Krnl));
1140 break;
1141
1142 case 'n':
1143 case 'N': /* NoLoader */
1144 return 0;
1145
1146 case 'q':
1147 case 'Q': /* Quiet */
1148 fQuiet = 1;
1149 break;
1150
1151 case 's':
1152 case 'S': /* Symbol file */
1153 i++;
1154 if (pReqPack->InitArgs[i] == 'Y' || pReqPack->InitArgs[i] == 'y')
1155 i += kargncpy(szUsrSym, &pReqPack->InitArgs[i], sizeof(szUsrSym));
1156 break;
1157
1158 case 'v':
1159 case 'V': /* Verbose */
1160 fQuiet = 0;
1161 break;
1162 }
1163 }
1164 }
1165 }
1166
1167 /*---------------------*/
1168 /* determin boot drive */
1169 /*---------------------*/
1170 rc = DosGetInfoSeg(&GDT, &LDT);
1171 if (rc != NO_ERROR)
1172 return rc;
1173
1174 pInfoSeg = MAKEPGINFOSEG(GDT);
1175 usBootDrive = pInfoSeg->bootdrive;
1176 usVerMajor = pInfoSeg->uchMajorVersion;
1177 usVerMinor = pInfoSeg->uchMinorVersion;
1178 dprintf(("BootDrive: %d\n", usBootDrive));
1179
1180 /* set driveletter in constants strings */
1181 usBootDrive = (char)usBootDrive + (char)'a' - 1;
1182 szOS2Krnl[0] = (char)usBootDrive;
1183 for (i = 0; apszSym[i] != NULL; i++)
1184 apszSym[i][0] = (char)usBootDrive;
1185
1186 /*-----------------*/
1187 /* get kernel OTEs */
1188 /*-----------------*/
1189 rc = GetKernelOTEs();
1190 if (rc != NO_ERROR)
1191 return rc;
1192
1193 /*--------------*/
1194 /* read kernel */
1195 /*--------------*/
1196 if (szUsrOS2Krnl[0] != '\0')
1197 {
1198 rc = ReadOS2Krnl(szUsrOS2Krnl);
1199 if (rc != 0)
1200 {
1201 puts("Warning: Invalid kernel file specified. Tries defaults.\n\r");
1202 szUsrOS2Krnl[0] = '\0';
1203 rc = ReadOS2Krnl(szOS2Krnl);
1204 }
1205 }
1206 else
1207 rc = ReadOS2Krnl(szOS2Krnl);
1208
1209 /*--------------*/
1210 /* read symfile */
1211 /*--------------*/
1212 if (!rc)
1213 {
1214 rc = 1;
1215 if (szUsrSym[0] != '\0')
1216 {
1217 rc = ProbeSymFile(szUsrSym);
1218 if (rc)
1219 {
1220 puts("Warning: Invalid symbol file specified. Tries defaults.\n\r");
1221 szUsrSym[0] = '\0';
1222 }
1223 }
1224 if (rc != 0) /* if user sym failed or don't exists */
1225 {
1226 i = 0;
1227 while (apszSym[i] != NULL && (rc = ProbeSymFile(apszSym[i])) != 0)
1228 i++;
1229 }
1230 }
1231
1232 /* show the result and set return-value */
1233 dprintf(("rc=%d; i=%d\n", rc, i));
1234 ShowResult(rc, i);
1235
1236 return rc;
1237}
1238
1239
1240
1241#ifdef DEBUGR3
1242/**
1243 * Debug - Main procedure for standalone testing.
1244 */
1245void main(int argc, char **argv)
1246{
1247 char szParm[512];
1248 RPINITIN ReqPack;
1249 int j;
1250 int i = 0;
1251 int argi = 0;
1252
1253 while (argi < argc)
1254 {
1255 j = 0;
1256 while (argv[argi][j] != '\0')
1257 szParm[i++] = argv[argi][j++];
1258 szParm[i++] = ' ';
1259
1260 /* next */
1261 argi++;
1262 }
1263 szParm[i++] = '\0';
1264
1265 ReqPack.InitArgs = szParm;
1266
1267 ProbeKernel(&ReqPack);
1268}
1269
1270#endif
1271
Note: See TracBrowser for help on using the repository browser.