source: trunk/src/kernel32/dbglog.cpp@ 22018

Last change on this file since 22018 was 22005, checked in by dmik, 13 years ago

kernel32: Improve logging (showing current FS mode).

File size: 33.1 KB
Line 
1/* $Id: dbglog.cpp,v 1.9 2003-03-26 16:02:33 sandervl Exp $ */
2
3/*
4 * Project Odin Software License can be found in LICENSE.TXT
5 * Debug Logging procedures
6 *
7 * Copyright 1998-2002 Sander van Leeuwen (sandervl@xs4all.nl)
8 * Copyright 1998 Joel Troster
9 * Copyright 1998 Peter FitzSimmons
10 *
11 */
12
13
14/*******************************************************************************
15* Internal Functions *
16*******************************************************************************/
17
18#define INCL_MISC
19#define INCL_BASE
20#define INCL_WIN
21#define INCL_WINERRORS
22#define INCL_DOSFILEMGR
23#include <os2wrap.h> //Odin32 OS/2 api wrappers
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdarg.h>
28#include <process.h>
29#include <win32type.h>
30#include <win32api.h>
31#include <dbglog.h>
32#include "initterm.h"
33#include "logging.h"
34#include "exceptions.h"
35#include "exceptutil.h"
36#include <wprocess.h>
37#include <versionos2.h>
38#include "odinbuild.h"
39#include <cpuhlp.h>
40
41#include "asmutil.h"
42#include "WinImageBase.h"
43#include "WinDllBase.h"
44#include "WinExeBase.h"
45/*****************************************************************************
46 * PMPRINTF Version *
47 *****************************************************************************/
48
49#ifdef PMPRINTF
50
51/* ----- Customization variables ----- */
52#define PRINTFID ""
53#define PRINTFMAXLEN 300
54#define PRINTFLINELEN 100
55#define PRINTFTHREADS 54
56#define PRINTFQNAME "\\QUEUES\\PRINTF32"
57
58/* ----- Includes and externals ----- */
59#include <stddef.h> /* .. */
60#include <time.h> /* .. */
61
62extern ULONG flAllocMem; /*Tue 03.03.1998: knut */
63
64/* ----- Local defines ----- */
65#define PRINTFIDSIZE sizeof(PRINTFID)
66#define PRINTFMAXBUF PRINTFIDSIZE+PRINTFLINELEN
67
68ULONG GetPentiumTSC (QWORD * tsc);
69
70/*****************************************************************************
71 * Structures *
72 *****************************************************************************/
73
74/* ----- Per-thread output buffer and current indices into line ---- */
75struct perthread {
76 LONG lineindex; /* where next char */
77 LONG tidemark; /* rightmost char */
78 int bell; /* TRUE if line has bell */
79 UCHAR line[PRINTFMAXBUF]; /* accumulator */
80 };
81
82/* ----- Local static variables ----- */
83static ULONG ourpid=0; /* our process ID */
84static ULONG servepid=0; /* process IDs of the server */
85static HQUEUE qhandle=0; /* handle for the queue */
86static struct perthread *tps[PRINTFTHREADS+1]; /* -> per-thread data */
87
88/* ----- Local subroutine ----- */
89static int printf_(struct perthread *);
90
91
92/* ----------------------------------------------------------------- */
93/* The "printf" function. Note this has a variable number of */
94/* arguments. */
95/* ----------------------------------------------------------------- */
96int SYSTEM WriteLog(const char *f, ...)
97 {
98 TIB *ptib; /* process/thread id structures */
99 PIB *ppib; /* .. */
100 TID ourtid; /* thread ID */
101 struct perthread *tp; /* pointer to per-thread data */
102 int rc; /* returncode */
103 ULONG urc; /* returncode */
104
105 urc=DosOpenQueue(&servepid, &qhandle, PRINTFQNAME); /* Open the Q */
106 /* Non-0 RC means Q does not exist or cannot be opened */
107 if (urc==343) return 0; /* queue does not exist, so quit */
108 if (urc!=0) return -1; /* report any other error */
109
110 /* First determine our thread ID (and hence get access to the */
111 /* correct per-thread data. If the per-thread data has not been */
112 /* allocated, then allocate it now. It is never freed, once */
113 /* allocated, as PRINTF is not notified of end-of-thread. */
114 DosGetInfoBlocks(&ptib,&ppib); /* get process/thread info */
115 ourtid=ptib->tib_ptib2->tib2_ultid; /* .. and copy TID */
116 if (ourtid>PRINTFTHREADS) /* too many threads .. */
117 return 0; /* .. so quit, quietly */
118 tp=tps[ourtid]; /* copy to local pointer */
119 if (tp==NULL) { /* uninitialized (NULL=0) */
120 /* allocate a per-thread structure */
121 tp=(struct perthread *)malloc(sizeof(struct perthread));
122 if (tp==NULL) return -1; /* out of memory -- return error */
123 tps[ourtid]=tp; /* save for future calls */
124 strcpy(tp->line,PRINTFID); /* initialize: line.. */
125 tp->lineindex=PRINTFIDSIZE-1; /* ..where next char */
126 tp->tidemark =PRINTFIDSIZE-2; /* ..rightmost char */
127 tp->bell=FALSE; /* ..if line has bell */
128 if (ourpid==0) ourpid=ppib->pib_ulpid; /* save PID for all to use */
129 }
130
131 { /* Block for declarations -- only needed if queue exists, etc. */
132 LONG count; /* count of characters formatted */
133 UCHAR buffer[PRINTFMAXLEN+1]; /* formatting area */
134 LONG i, newind; /* work */
135 UCHAR ch; /* .. */
136 va_list argptr; /* -> variable argument list */
137
138 va_start(argptr, f); /* get pointer to argument list */
139 count=vsprintf(buffer, f, argptr);
140 va_end(argptr); /* done with variable arguments */
141
142 if (count<0) return count-1000;/* bad start */
143
144 if (count>PRINTFMAXLEN) {
145 /* Disaster -- we are probably "dead", but just in case we */
146 /* are not, carry on with truncated data. */
147 count=PRINTFMAXLEN;
148 }
149 buffer[count]='\0'; /* ensure terminated */
150 /* OK, ready to go with the data now in BUFFER */
151 /* We copy from the formatted string to the output (line) buffer, */
152 /* taking note of certain control characters and sending a line */
153 /* the queue whenever we see a LF control, or when the line */
154 /* fills (causing a forced break). */
155 for (i=0; ; i++) {
156 ch=buffer[i]; if (!ch) break;
157 switch(ch) {
158 case '\r': /* carriage return */
159 tp->lineindex=PRINTFIDSIZE-1; /* back to start of line */
160 break;
161 case '\n': /* new line */
162 case '\f': /* form feed */
163 rc=printf_(tp); /* print a line */
164 if (rc!=0) return rc; /* error */
165 break;
166 case '\t': /* tab */
167 newind=tp->lineindex-PRINTFIDSIZE+1; /* offset into data */
168 newind=tp->lineindex+5-newind%5; /* new index requested */
169 if (newind>=PRINTFMAXBUF) newind=PRINTFMAXBUF; /* clamp */
170 for (; tp->lineindex<newind; tp->lineindex++) {
171 if (tp->lineindex>tp->tidemark) { /* beyond current end */
172 tp->line[tp->lineindex]=' '; /* add space */
173 tp->tidemark=tp->lineindex;
174 }
175 }
176 break;
177 case '\v': /* vertical tab */
178 /* ignore it */
179 break;
180 case '\b': /* backspace */
181 tp->lineindex=max(tp->lineindex-1,PRINTFIDSIZE);
182 break;
183 case '\a': /* alert (bell) */
184 tp->bell=TRUE;
185 break;
186 default: /* ordinary character */
187 tp->line[tp->lineindex]=ch;
188 if (tp->lineindex>tp->tidemark) /* is rightmost.. */
189 tp->tidemark=tp->lineindex;
190 tp->lineindex++; /* step for next */
191 } /* switch */
192 if (tp->lineindex>=PRINTFMAXBUF) {
193 rc=printf_(tp); /* print a line */
194 if (rc!=0) return rc; /* error */
195 }
196
197 } /* copy loop */
198 return count; /* all formatted data processed */
199 } /* block */
200 } /* printf */
201
202/* ----- printf_(tp) -- Local subroutine to send a line ------------ */
203/* A line has been completed (or overflowed): write it to the queue. */
204int printf_(struct perthread *tp) /* pointer to per-thread data */
205 {
206 ULONG urc; /* unsigned returncode */
207 PSZ pszTo, pszFrom; /* character pointers */
208 PVOID addr; /* address of output data */
209 long size; /* total size of output data */
210 time_t timenow; /* holds current time */
211
212 tp->line[tp->tidemark+1]='\0'; /* add terminator */
213 size=tp->tidemark+2; /* total length of data */
214
215 /* Get some shared memory that can be given away */
216 urc=DosAllocSharedMem(&addr, NULL, (unsigned)size,
217 OBJ_GIVEABLE|PAG_WRITE|PAG_COMMIT|flAllocMem);
218 /*knut: added flAllocMem */
219
220 if (urc!=0) return -2; /* error */
221
222 pszTo=addr; /* copy for clarity */
223 pszFrom=&(tp->line[0]); /* pointer to source */
224 strcpy(pszTo,pszFrom); /* copy the string to shared memory */
225
226 if (ourpid!=servepid) { /* (no giveaway needed if to self) */
227 urc=DosGiveSharedMem(addr, servepid, PAG_READ); /* give access */
228 if (urc!=0) return -3;} /* error */
229
230 /* Write the selector, size, and timestamp to the queue */
231 if (tp->bell) size=-size; /* BELL passed by negation */
232 time(&timenow); /* optional - else use 0 */
233 urc=DosWriteQueue(qhandle, /* handle */
234 (unsigned)timenow, /* 'request' (timestamp) */
235 (unsigned)size, /* 'length' (length/bell) */
236 addr, /* 'address' (address) */
237 0); /* priority (FIFO if enabled) */
238 if (urc!=0) return -4; /* error */
239 if (ourpid!=servepid) { /* if given away.. */
240 urc=DosFreeMem(addr); /* .. *we* are done with it */
241 if (urc!=0) return -5;} /* error */
242 /* Reset the line buffer and indices */
243 tp->lineindex=PRINTFIDSIZE-1; /* where next char */
244 tp->tidemark =PRINTFIDSIZE-2; /* rightmost char */
245 tp->bell =FALSE; /* true if line has bell */
246 return 0; /* success! */
247 } /* printf_ */
248#endif
249
250
251
252/*****************************************************************************
253 * Standard Version *
254 *****************************************************************************/
255
256static FILE *flog = NULL; /*PLF Mon 97-09-08 20:00:15*/
257static BOOL init = FALSE;
258static BOOL firstTime = FALSE;
259static BOOL fLogging = TRUE;
260static int dwEnableLogging = 1;
261#ifdef __IBMC__
262static int oldcrtmsghandle = 0;
263#endif
264
265static BOOL fDisableThread[5] = {0};
266static BOOL fFlushLines = TRUE;
267
268static const char *pszLastLogEntry = NULL;
269
270//#define CHECK_ODINHEAP
271#if defined(DEBUG) && defined(CHECK_ODINHEAP)
272int checkOdinHeap = 1;
273int checkingheap = 0;
274#define ODIN_HEAPCHECK() \
275 if(checkingheap) checkOdinHeap = 0; \
276 checkingheap++; \
277 if(checkOdinHeap) _heap_check(); \
278 checkingheap--;
279#else
280#define ODIN_HEAPCHECK()
281#endif
282
283#define LOG_TIME
284//#define SHOW_FPU_CONTROLREG
285#define WIN32_IP_LOGGING
286#define WIN32_IP_LOG_PORT 5001
287
288#ifdef WIN32_IP_LOGGING
289#include <types.h>
290#include <netinet/in.h>
291#include <sys/socket.h>
292
293static int logSocket = -1;
294static struct sockaddr_in servername;
295#endif
296
297#ifdef LOG_TIME
298static DWORD startTicks = 0;
299static DWORD startTime = 0;
300VOID WINAPI GetLocalTime(LPSYSTEMTIME);
301#endif
302
303static VMutex logMutex;
304
305static void win32modname (ULONG eip, char *szModName, int cbModName)
306{
307 Win32ImageBase *pMod = NULL;
308 if (WinExe && WinExe->insideModule(eip))
309 pMod = WinExe;
310 else
311 pMod = Win32DllBase::findModuleByAddr(eip);
312 if (pMod != NULL)
313 {
314 szModName[0] = '\0';
315 strncat(szModName, pMod->getModuleName(), cbModName);
316 }
317}
318
319static ULONG _System WriteLogExcHandler(PEXCEPTIONREPORTRECORD pReport,
320 PEXCEPTIONREGISTRATIONRECORD pRegRec,
321 PCONTEXTRECORD pContext,
322 PVOID pv)
323{
324 switch (pReport->ExceptionNum)
325 {
326 case XCPT_PROCESS_TERMINATE:
327 case XCPT_ASYNC_PROCESS_TERMINATE:
328 case XCPT_UNWIND:
329 // disable further (possibly, recursive) handler calls
330 DosUnsetExceptionHandler(pRegRec);
331 // free the mutex to avoid deadlocks and make sure other threads can print
332 logMutex.leave();
333 break;
334 }
335
336 return XCPT_CONTINUE_SEARCH;
337}
338
339int SYSTEM WriteLog(const char *tekst, ...)
340{
341 USHORT sel = RestoreOS2FS();
342 va_list argptr;
343 TEB *teb = GetThreadTEB();
344
345 EXCEPTIONREGISTRATIONRECORD RegRec = {0, WriteLogExcHandler};
346 DosSetExceptionHandler(&RegRec);
347
348 logMutex.enter();
349
350 pszLastLogEntry = tekst;
351
352 ODIN_HEAPCHECK();
353
354 if (!init)
355 {
356 init = TRUE;
357 firstTime = TRUE;
358
359#ifdef LOG_TIME
360 // initialize the current time counter
361 startTicks = GetTickCount();
362 SYSTEMTIME t;
363 GetLocalTime(&t);
364 startTime = t.wHour * 3600 + t.wMinute * 60 + t.wSecond;
365 startTime = (startTime * 1000) + t.wMilliseconds;
366#endif
367
368 if(getenv("WIN32LOG_FLUSHLINES"))
369 fFlushLines = TRUE;
370
371#ifdef DEFAULT_LOGGING_OFF
372 if(getenv("WIN32LOG_ENABLED"))
373 {
374#else
375 if(!getenv("NOWIN32LOG"))
376 {
377#endif
378#ifdef WIN32_IP_LOGGING
379 char *logserver = getenv("WIN32LOG_IPSERVER");
380 if(logserver) {
381 sock_init();
382
383 memset(&servername, 0, sizeof(servername));
384 servername.sin_family = AF_INET;
385 servername.sin_addr.s_addr = inet_addr(logserver);
386 servername.sin_port = WIN32_IP_LOG_PORT;
387
388 logSocket = socket(PF_INET, SOCK_DGRAM, 0);
389 }
390#endif
391 char szLogFile[CCHMAXPATH];
392 const char *pszLogBase = getenv("WIN32LOG_FILEBASE");
393 if (!pszLogBase)
394 pszLogBase = "odin32_";
395
396 sprintf(szLogFile, "%s%d.log", pszLogBase, getpid());
397 flog = fopen(szLogFile, "w");
398 if(flog == NULL)
399 {//probably running exe on readonly device
400 sprintf(szLogFile, "%sodin32_%d.log", kernel32Path, getpid());
401 flog = fopen(szLogFile, "w");
402 }
403#ifdef __IBMC__
404 oldcrtmsghandle = _set_crt_msg_handle(fileno(flog));
405#endif
406 }
407 else
408 fLogging = FALSE;
409
410 fDisableThread[0] = getenv("DISABLE_THREAD1") != NULL;
411 fDisableThread[1] = getenv("DISABLE_THREAD2") != NULL;
412 fDisableThread[2] = getenv("DISABLE_THREAD3") != NULL;
413 fDisableThread[3] = getenv("DISABLE_THREAD4") != NULL;
414 fDisableThread[4] = getenv("DISABLE_THREAD5") != NULL;
415 }
416
417 if (teb)
418 {
419 if(teb->o.odin.threadId < 5 && fDisableThread[teb->o.odin.threadId-1] == 1)
420 {
421 logMutex.leave();
422 DosUnsetExceptionHandler(&RegRec);
423 SetFS(sel);
424 return 1;
425 }
426 }
427
428 if (!tekst)
429 {
430 if (flog)
431 fflush(flog);
432
433 logMutex.leave();
434 DosUnsetExceptionHandler(&RegRec);
435 SetFS(sel);
436 return 1;
437 }
438
439#ifdef LOG_TIME
440 // get human readable time values
441 DWORD time = startTime + (GetTickCount() - startTicks);
442 DWORD h = (time / 3600000) % 24;
443 DWORD m = (time %= 3600000) / 60000;
444 DWORD s = (time %= 60000) / 1000;
445 DWORD ms = time % 1000;
446#endif
447
448 if (fLogging && flog && (dwEnableLogging > 0))
449 {
450 if (firstTime)
451 {
452 firstTime = FALSE;
453
454 // print the header with the legend
455#ifdef LOG_TIME
456 fprintf(flog,
457 " /--------------------- Thread ID\n"
458 " | /----------------- Call Depth\n"
459 " | | /-------------- Flags (O: OS/2 FS (150B), W: Win32 FS, o/w: no switch)\n"
460 " | | | /------- Current Time\n"
461 "--- --- - ------------\n");
462#else
463#ifdef SHOW_FPU_CONTROLREG
464 fprintf(flog,
465 " /------------ Thread ID\n"
466 " | /-------- Call Depth\n"
467 " | | /----- Flags (O: OS/2 FS (150B), W: Win32 FS, o/w: no switch)\n"
468 " | | | /-- FPU Control Register\n"
469 "--- --- - ---\n");
470#else
471 fprintf(flog,
472 " /-------- Thread ID\n"
473 " | /---- Call Depth\n"
474 " | | /- Flags (O: OS/2 FS (150B), W: Win32 FS, o/w: no switch)\n"
475 "--- --- -\n");
476#endif
477#endif
478 }
479
480 va_start(argptr, tekst);
481
482#ifdef WIN32_IP_LOGGING
483 if (logSocket == -1)
484 {
485#endif
486 if (teb)
487 {
488 ULONG ulCallDepth;
489#ifdef DEBUG
490 ulCallDepth = teb->o.odin.dbgCallDepth;
491#else
492 ulCallDepth = 0;
493#endif
494
495 teb->o.odin.logfile = (DWORD)flog;
496
497#ifdef LOG_TIME
498 fprintf(flog,
499 "t%02d %03d %c %02d:%02d:%02d.%03d: ",
500 LOWORD(teb->o.odin.threadId),
501 ulCallDepth,
502 fSwitchTIBSel ? (sel == 0x150b ? 'O' : 'W') :
503 (sel == 0x150b ? 'o' : 'w'),
504 h, m, s, ms);
505#else
506#ifdef SHOW_FPU_CONTROLREG
507 fprintf(flog,
508 "t%02d %03d %c %03X: ",
509 LOWORD(teb->o.odin.threadId),
510 ulCallDepth,
511 fSwitchTIBSel ? (sel == 0x150b ? 'O' : 'W') :
512 (sel == 0x150b ? 'o' : 'w'),
513 CONTROL87(0,0));
514#else
515 fprintf(flog,
516 "t%02d %03d %c: ",
517 LOWORD(teb->o.odin.threadId),
518 ulCallDepth,
519 fSwitchTIBSel ? (sel == 0x150b ? 'O' : 'W') :
520 (sel == 0x150b ? 'o' : 'w'));
521#endif
522#endif
523 }
524 else
525 {
526#ifdef LOG_TIME
527 fprintf(flog,
528 "t-- --- - %02d:%02d:%02d.%03d: ",
529 h, m, s, ms);
530#else
531#ifdef SHOW_FPU_CONTROLREG
532 fprintf(flog,
533 "t-- --- - ---: ");
534#else
535 fprintf(flog,
536 "t-- --- -: ");
537#endif
538#endif
539 }
540#ifdef WIN32_IP_LOGGING
541 }
542#endif
543
544#ifdef WIN32_IP_LOGGING
545 if(logSocket != -1)
546 {
547 char logbuffer[1024];
548 int prefixlen = 0;
549
550 if (teb)
551 {
552 ULONG ulCallDepth;
553#ifdef DEBUG
554 ulCallDepth = teb->o.odin.dbgCallDepth;
555#else
556 ulCallDepth = 0;
557#endif
558#ifdef LOG_TIME
559 sprintf(logbuffer,
560 "t%02d %03d %02d:%02d:%02d.%03d [%c]: ",
561 LOWORD(teb->o.odin.threadId),
562 ulCallDepth,
563 h, m, s, ms,
564 fSwitchTIBSel ? (sel == 0x150b ? 'O' : 'W') :
565 (sel == 0x150b ? 'o' : 'w'));
566#else
567 sprintf(logbuffer,
568 "t%02d %03d [%c]: ",
569 LOWORD(teb->o.odin.threadId),
570 ulCallDepth,
571 fSwitchTIBSel ? (sel == 0x150b ? 'O' : 'W') :
572 (sel == 0x150b ? 'o' : 'w'));
573#endif
574 prefixlen = strlen(logbuffer);
575 }
576
577 vsprintf(&logbuffer[prefixlen], tekst, argptr);
578
579 int rc;
580
581 servername.sin_family = AF_INET;
582 servername.sin_port = WIN32_IP_LOG_PORT;
583
584 rc = sendto(logSocket, logbuffer, strlen(logbuffer)+1, 0, (struct sockaddr *)&servername, sizeof(servername));
585 if (rc == -1)
586 rc = sock_errno();
587 if (teb)
588 teb->o.odin.logfile = 0;
589 va_end(argptr);
590 }
591 else
592 {
593 vfprintf(flog, tekst, argptr);
594 if (teb)
595 teb->o.odin.logfile = 0;
596 va_end(argptr);
597
598 if (tekst[strlen(tekst)-1] != '\n')
599 fprintf(flog, "\n");
600#if 0
601 if (teb && LOWORD(teb->o.odin.threadId) > 1)
602 {
603 TEB *winteb = GetThreadTEB();
604 PWINEXCEPTION_FRAME pframe = (PWINEXCEPTION_FRAME)winteb->except;
605
606 fprintf(flog, "debug Win32 exception chain %08X (%08X) (teb = %08X, esp = %08X)\n", pframe, QueryExceptionChain(), teb, getESP());
607 fprintf(flog, "Top record at %08X, Prev at %08X, handler at %08X\n", (PWINEXCEPTION_FRAME)QueryExceptionChain(), ((PWINEXCEPTION_FRAME)QueryExceptionChain())->Prev, ((PWINEXCEPTION_FRAME)QueryExceptionChain())->Handler);
608 fprintf(flog, "*teb %08X %08X %08X %08X %08X %08X %08X %08X\n",
609 ((ULONG *)teb)[0],((ULONG *)teb)[1],((ULONG *)teb)[2],((ULONG *)teb)[3],
610 ((ULONG *)teb)[4],((ULONG *)teb)[5],((ULONG *)teb)[6],((ULONG *)teb)[7]);
611 while ((pframe != NULL) && ((ULONG)pframe != 0xFFFFFFFF)) {
612 if ((void *)pframe > winteb->stack_top || (void *)pframe < winteb->stack_low)
613 {
614 fprintf(flog, "Chain corrupted! Record at %08X is outside stack boundaries!\n", pframe);
615 break;
616 }
617
618 if ((ULONG)pframe < getESP())
619 {
620 fprintf(flog, "Chain corrupted! Record at %08X is below stack pointer!\n", pframe);
621 break;
622 }
623
624 char szModName[32] = "";
625 char szModName2[32] = "";
626 win32modname ((ULONG)pframe->Handler, szModName, sizeof (szModName));
627 win32modname ((ULONG)pframe->Prev, szModName2, sizeof (szModName2));
628 fprintf(flog, "Record at %08X, Prev at %08X [%s], handler at %08X [%s]\n", pframe, pframe->Prev, szModName2, pframe->Handler, szModName);
629 if (pframe == pframe->Prev) {
630 fprintf(flog, "Chain corrupted! Record at %08X pointing to itself!\n", pframe);
631 break;
632 }
633 pframe = pframe->Prev;
634 }
635 }
636#endif
637 if (fFlushLines)
638 fflush(flog);
639 }
640#else
641 vfprintf(flog, tekst, argptr);
642 if(teb) teb->o.odin.logfile = 0;
643 va_end(argptr);
644
645 if(tekst[strlen(tekst)-1] != '\n')
646 fprintf(flog, "\n");
647
648 if(fFlushLines)
649 fflush(flog);
650#endif
651 }
652
653 logMutex.leave();
654 DosUnsetExceptionHandler(&RegRec);
655 SetFS(sel);
656 return 1;
657}
658//******************************************************************************
659//******************************************************************************
660int SYSTEM WriteLogNoEOL(const char *tekst, ...)
661{
662 USHORT sel = RestoreOS2FS();
663 va_list argptr;
664
665 EXCEPTIONREGISTRATIONRECORD RegRec = {0, WriteLogExcHandler};
666 DosSetExceptionHandler(&RegRec);
667
668 logMutex.enter();
669
670 ODIN_HEAPCHECK();
671
672 if (!init)
673 {
674 init = TRUE;
675
676#ifdef DEFAULT_LOGGING_OFF
677 if(getenv("WIN32LOG_ENABLED"))
678 {
679#else
680 if (!getenv("NOWIN32LOG"))
681 {
682#endif
683 char logname[CCHMAXPATH];
684
685 sprintf(logname, "odin32_%d.log", getpid());
686 flog = fopen(logname, "w");
687 if(flog == NULL) {//probably running exe on readonly device
688 sprintf(logname, "%sodin32_%d.log", kernel32Path, getpid());
689 flog = fopen(logname, "w");
690 }
691 }
692 else
693 fLogging = FALSE;
694 }
695
696 if (fLogging && flog && (dwEnableLogging > 0))
697 {
698 TEB *teb = GetThreadTEB();
699
700 va_start(argptr, tekst);
701 if (teb)
702 teb->o.odin.logfile = (DWORD)flog;
703 vfprintf(flog, tekst, argptr);
704 if (teb)
705 teb->o.odin.logfile = 0;
706 va_end(argptr);
707 }
708
709 logMutex.leave();
710 DosUnsetExceptionHandler(&RegRec);
711 SetFS(sel);
712 return 1;
713}
714//******************************************************************************
715//******************************************************************************
716void SYSTEM DecreaseLogCount()
717{
718 dwEnableLogging--;
719}
720//******************************************************************************
721//******************************************************************************
722void SYSTEM IncreaseLogCount()
723{
724 dwEnableLogging++;
725}
726//******************************************************************************
727//******************************************************************************
728int SYSTEM WritePrivateLog(void *logfile, const char *tekst, ...)
729{
730 USHORT sel = RestoreOS2FS();
731 va_list argptr;
732
733 if (fLogging && logfile)
734 {
735 TEB *teb = GetThreadTEB();
736
737 va_start(argptr, tekst);
738 if (teb)
739 teb->o.odin.logfile = (DWORD)flog;
740 vfprintf((FILE *)logfile, tekst, argptr);
741 if (teb)
742 teb->o.odin.logfile = 0;
743 va_end(argptr);
744
745 if (tekst[strlen(tekst)-1] != '\n')
746 fprintf((FILE *)logfile, "\n");
747 }
748
749 SetFS(sel);
750 return 1;
751}
752//******************************************************************************
753//WriteLog has to take special care to handle dprintfs inside our os/2 exception
754//handler; if an exception occurs inside a dprintf, using dprintf in the exception
755//handler will hang the process
756//******************************************************************************
757int LogException(int state, int prevlock)
758{
759 TEB *teb = GetThreadTEB();
760 int ret = 0;
761
762 if (!teb) return 0;
763
764#if !defined(__EMX__)
765 if (teb->o.odin.logfile)
766 {
767#if (__IBMCPP__ == 300) || (__IBMC__ == 300)
768 PUSHORT lock = (USHORT *)(teb->o.odin.logfile+0x1C);
769#else
770#if __IBMC__ >= 360 || __IBMCPP__ >= 360
771//TODO: test this!!!!!!!
772 PUSHORT lock = (USHORT *)(teb->o.odin.logfile+0x1C);
773#else
774#error Check the offset of the lock count word in the file stream structure for this compiler revision!!!!!
775#endif
776#endif
777 ret = (*lock);
778 if (state == ENTER_EXCEPTION)
779 {
780 if((*lock) > 0) (*lock)--;
781 }
782 else
783 { //LEAVE_EXCEPTION
784 if(prevlock) (*lock)++;
785 }
786 }
787#else
788//kso 2001-01-29: EMX/GCC
789// we maybe should do something with the _more->rsem (_rmutex) structure but
790// I wanna have this compile, so we'll address problems later.
791#endif
792 return ret;
793}
794//******************************************************************************
795//Check if the exception occurred inside a fprintf (logging THDB member set)
796//If true, decrease the lock count for that file stream
797//NOTE: HACK: DEPENDS ON COMPILER VERSION!!!!
798//******************************************************************************
799void CheckLogException()
800{
801 TEB *teb = GetThreadTEB();
802 PUSHORT lock;
803
804 if(!teb) return;
805
806#if !defined(__EMX__)
807 if(teb->o.odin.logfile) {
808 //oops, exception in vfprintf; let's clear the lock count
809#if (__IBMCPP__ == 300) || (__IBMC__ == 300)
810 lock = (PUSHORT)(teb->o.odin.logfile+0x1C);
811#else
812#if __IBMC__ >= 360 || __IBMCPP__ >= 360
813//TODO: test this!!!!!!!
814 PUSHORT lock = (USHORT *)(teb->o.odin.logfile+0x1C);
815#else
816#error Check the offset of the lock count word in the file stream structure for this compiler revision!!!!!
817#endif
818#endif
819 (*lock)--;
820 }
821#else
822//kso 2001-01-29: EMX/GCC
823// we maybe should do something with the _more->rsem (_rmutex) structure but
824// I wanna have this compile, so we'll address problems later.
825#endif
826}
827//******************************************************************************
828//NOTE: No need to save/restore FS, as our FS selectors have already been
829// destroyed and FS == 0x150B.
830//******************************************************************************
831void CloseLogFile()
832{
833#ifdef __IBMC__
834 if(oldcrtmsghandle)
835 _set_crt_msg_handle(oldcrtmsghandle);
836#endif
837
838#ifdef WIN32_IP_LOGGING
839 if(logSocket != -1) {
840 soclose(logSocket);
841 }
842#endif
843
844 if(flog) fclose(flog);
845 flog = 0;
846}
847//******************************************************************************
848//Used to open any private logfiles used in kernel32 (for now only in winimagepeldr.cpp)
849//******************************************************************************
850void OpenPrivateLogFiles()
851{
852#ifdef DEFAULT_LOGGING_OFF
853 if(getenv("WIN32LOG_ENABLED")) {
854#else
855 if(!getenv("NOWIN32LOG")) {
856#endif
857 OpenPrivateLogFilePE();
858 }
859}
860//******************************************************************************
861//Used to close all private logfiles used in kernel32 (for now only in winimagepeldr.cpp)
862//******************************************************************************
863void ClosePrivateLogFiles()
864{
865#ifdef DEFAULT_LOGGING_OFF
866 if(getenv("WIN32LOG_ENABLED")) {
867#else
868 if(!getenv("NOWIN32LOG")) {
869#endif
870 ClosePrivateLogFilePE();
871 }
872}
873//******************************************************************************
874//******************************************************************************
875void SYSTEM CheckVersion(ULONG version, char *modname)
876{
877 dprintf(("CheckVersion of %s, %d\n", modname, version));
878 if(version != PE2LX_VERSION){
879 static char msg[300];
880 int r;
881 dprintf(("Version mismatch! %d, %d: %s\n", version, PE2LX_VERSION, modname));
882 sprintf(msg, "%s is intended for use with a different release of Odin.\n", modname);
883 do{
884 r = WinMessageBox(HWND_DESKTOP, NULLHANDLE, msg, "Version Mismatch!", 0, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_MOVEABLE);
885 }while(r == MBID_RETRY); // giggle
886 if( r != MBID_IGNORE )
887 exit(987);
888 }
889}
890//******************************************************************************
891//******************************************************************************
892void SYSTEM CheckVersionFromHMOD(ULONG version, HMODULE hModule)
893{
894 char name[_MAX_PATH];
895
896 // query name of dll.
897 if(!DosQueryModuleName(hModule, sizeof(name), name))
898 CheckVersion(version, name);
899}
900//******************************************************************************
901//******************************************************************************
902#ifdef __WATCOMC__ /*PLF Sat 97-06-21 17:12:36*/
903 extern void interrupt3( void );
904 #pragma aux interrupt3= \
905 "int 3"
906#endif
907extern "C"
908void WIN32API DebugBreak()
909{
910 dprintf(("DebugBreak\n"));
911
912 LPSTR lpstrEnv = getenv("WIN32.DEBUGBREAK"); /* query environment */
913 if (lpstrEnv == NULL) /* if environment is not set, don't call debugger ! */
914 return;
915
916#ifdef __WATCOMC__
917 interrupt3();
918#else
919 _interrupt(3);
920#endif
921}
922//******************************************************************************
923//******************************************************************************
924
925
926/*****************************************************************************
927 * Name : DebugErrorBox
928 * Purpose : display an apprioriate error box with detailed information
929 * about the error cause
930 * Parameters: APIRET iErrorCode - OS/2 error code
931 * PSZ pszFormat - printf-format string
932 * ...
933 * Variables :
934 * Result : return code of the message box
935 * Remark :
936 * Status :
937 *
938 * Author : Patrick Haller [Tue, 1999/09/13 19:55]
939 *****************************************************************************/
940
941int SYSTEM DebugErrorBox(ULONG iErrorCode,
942 char* pszFormat,
943 ...)
944{
945 char szMessageBuffer[1024]; /* buffer for the text message */
946 char szErrorBuffer[1024]; /* buffer for the operating system text */
947 ULONG bc; /* dummy */
948 APIRET rc2; /* API returncode */
949 int iRC; /* message box return code */
950
951 USHORT sel = RestoreOS2FS();
952 va_list argptr;
953
954 // clear memory
955 memset (szMessageBuffer, 0, sizeof(szMessageBuffer));
956 memset (szErrorBuffer, 0, sizeof(szErrorBuffer));
957
958 // build message string
959 va_start(argptr, pszFormat);
960 vsprintf(szMessageBuffer, pszFormat, argptr);
961 va_end(argptr);
962
963 // query error string
964 rc2 = DosGetMessage(NULL,
965 0,
966 szErrorBuffer,
967 sizeof(szErrorBuffer),
968 iErrorCode,
969 "OSO001.MSG",
970 &bc);
971
972 // display message box
973 iRC = WinMessageBox(HWND_DESKTOP,
974 NULLHANDLE,
975 szMessageBuffer,
976 szErrorBuffer,
977 0,
978 MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
979 SetFS(sel);
980 return iRC;
981}
982
983
984/**
985 * Query Odin32 build number.
986 * @returns Build number.
987 * @status Completely implemented.
988 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
989 */
990int WIN32API Odin32GetBuildNumber(void)
991{
992 dprintf(("Odin32GetBuildNumber returned %d\n", ODIN32_BUILD_NR));
993 return ODIN32_BUILD_NR;
994}
995
Note: See TracBrowser for help on using the repository browser.