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

Last change on this file since 21990 was 21979, checked in by dmik, 13 years ago

kernel32: Release log file lock on unexpected thread termination.

This fixes hard deadlocks in debug builds when the application is killed
or terminated with Ctrl-C.

File size: 32.7 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 mode (FS=150B))\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 mode (FS=150B))\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 mode (FS=150B))\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 (sel == 0x150b && fSwitchTIBSel) ? 'O' : '-',
503 h, m, s, ms);
504#else
505#ifdef SHOW_FPU_CONTROLREG
506 fprintf(flog,
507 "t%02d %03d %c %03X: ",
508 LOWORD(teb->o.odin.threadId),
509 ulCallDepth,
510 (sel == 0x150b && fSwitchTIBSel) ? 'O' : '-',
511 CONTROL87(0,0));
512#else
513 fprintf(flog,
514 "t%02d %03d %c: ",
515 LOWORD(teb->o.odin.threadId),
516 ulCallDepth,
517 (sel == 0x150b && fSwitchTIBSel) ? 'O' : '-');
518#endif
519#endif
520 }
521 else
522 {
523#ifdef LOG_TIME
524 fprintf(flog,
525 "t-- --- O %02d:%02d:%02d.%03d: ",
526 h, m, s, ms);
527#else
528#ifdef SHOW_FPU_CONTROLREG
529 fprintf(flog,
530 "t-- --- O ---: ");
531#else
532 fprintf(flog,
533 "t-- --- O: ");
534#endif
535#endif
536 }
537#ifdef WIN32_IP_LOGGING
538 }
539#endif
540
541#ifdef WIN32_IP_LOGGING
542 if(logSocket != -1)
543 {
544 char logbuffer[1024];
545 int prefixlen = 0;
546
547 if (teb)
548 {
549 ULONG ulCallDepth;
550#ifdef DEBUG
551 ulCallDepth = teb->o.odin.dbgCallDepth;
552#else
553 ulCallDepth = 0;
554#endif
555#ifdef LOG_TIME
556 sprintf(logbuffer,
557 "t%02d %03d %02d:%02d:%02d.%03d [%c]: ",
558 LOWORD(teb->o.odin.threadId),
559 ulCallDepth,
560 h, m, s, ms,
561 (sel == 0x150b && fSwitchTIBSel) ? 'O' : '.');
562#else
563 sprintf(logbuffer,
564 "t%02d %03d [%c]: ",
565 LOWORD(teb->o.odin.threadId),
566 ulCallDepth,
567 (sel == 0x150b && fSwitchTIBSel) ? 'O' : '.');
568#endif
569 prefixlen = strlen(logbuffer);
570 }
571
572 vsprintf(&logbuffer[prefixlen], tekst, argptr);
573
574 int rc;
575
576 servername.sin_family = AF_INET;
577 servername.sin_port = WIN32_IP_LOG_PORT;
578
579 rc = sendto(logSocket, logbuffer, strlen(logbuffer)+1, 0, (struct sockaddr *)&servername, sizeof(servername));
580 if (rc == -1)
581 rc = sock_errno();
582 if (teb)
583 teb->o.odin.logfile = 0;
584 va_end(argptr);
585 }
586 else
587 {
588 vfprintf(flog, tekst, argptr);
589 if (teb)
590 teb->o.odin.logfile = 0;
591 va_end(argptr);
592
593 if (tekst[strlen(tekst)-1] != '\n')
594 fprintf(flog, "\n");
595#if 0
596 if (teb && LOWORD(teb->o.odin.threadId) > 1)
597 {
598 TEB *winteb = GetThreadTEB();
599 PWINEXCEPTION_FRAME pframe = (PWINEXCEPTION_FRAME)winteb->except;
600
601 fprintf(flog, "debug Win32 exception chain %08X (%08X) (teb = %08X, esp = %08X)\n", pframe, QueryExceptionChain(), teb, getESP());
602 fprintf(flog, "Top record at %08X, Prev at %08X, handler at %08X\n", (PWINEXCEPTION_FRAME)QueryExceptionChain(), ((PWINEXCEPTION_FRAME)QueryExceptionChain())->Prev, ((PWINEXCEPTION_FRAME)QueryExceptionChain())->Handler);
603 fprintf(flog, "*teb %08X %08X %08X %08X %08X %08X %08X %08X\n",
604 ((ULONG *)teb)[0],((ULONG *)teb)[1],((ULONG *)teb)[2],((ULONG *)teb)[3],
605 ((ULONG *)teb)[4],((ULONG *)teb)[5],((ULONG *)teb)[6],((ULONG *)teb)[7]);
606 while ((pframe != NULL) && ((ULONG)pframe != 0xFFFFFFFF)) {
607 if ((void *)pframe > winteb->stack_top || (void *)pframe < winteb->stack_low)
608 {
609 fprintf(flog, "Chain corrupted! Record at %08X is outside stack boundaries!\n", pframe);
610 break;
611 }
612
613 if ((ULONG)pframe < getESP())
614 {
615 fprintf(flog, "Chain corrupted! Record at %08X is below stack pointer!\n", pframe);
616 break;
617 }
618
619 char szModName[32] = "";
620 char szModName2[32] = "";
621 win32modname ((ULONG)pframe->Handler, szModName, sizeof (szModName));
622 win32modname ((ULONG)pframe->Prev, szModName2, sizeof (szModName2));
623 fprintf(flog, "Record at %08X, Prev at %08X [%s], handler at %08X [%s]\n", pframe, pframe->Prev, szModName2, pframe->Handler, szModName);
624 if (pframe == pframe->Prev) {
625 fprintf(flog, "Chain corrupted! Record at %08X pointing to itself!\n", pframe);
626 break;
627 }
628 pframe = pframe->Prev;
629 }
630 }
631#endif
632 if (fFlushLines)
633 fflush(flog);
634 }
635#else
636 vfprintf(flog, tekst, argptr);
637 if(teb) teb->o.odin.logfile = 0;
638 va_end(argptr);
639
640 if(tekst[strlen(tekst)-1] != '\n')
641 fprintf(flog, "\n");
642
643 if(fFlushLines)
644 fflush(flog);
645#endif
646 }
647
648 logMutex.leave();
649 DosUnsetExceptionHandler(&RegRec);
650 SetFS(sel);
651 return 1;
652}
653//******************************************************************************
654//******************************************************************************
655int SYSTEM WriteLogNoEOL(const char *tekst, ...)
656{
657 USHORT sel = RestoreOS2FS();
658 va_list argptr;
659
660 EXCEPTIONREGISTRATIONRECORD RegRec = {0, WriteLogExcHandler};
661 DosSetExceptionHandler(&RegRec);
662
663 logMutex.enter();
664
665 ODIN_HEAPCHECK();
666
667 if (!init)
668 {
669 init = TRUE;
670
671#ifdef DEFAULT_LOGGING_OFF
672 if(getenv("WIN32LOG_ENABLED"))
673 {
674#else
675 if (!getenv("NOWIN32LOG"))
676 {
677#endif
678 char logname[CCHMAXPATH];
679
680 sprintf(logname, "odin32_%d.log", getpid());
681 flog = fopen(logname, "w");
682 if(flog == NULL) {//probably running exe on readonly device
683 sprintf(logname, "%sodin32_%d.log", kernel32Path, getpid());
684 flog = fopen(logname, "w");
685 }
686 }
687 else
688 fLogging = FALSE;
689 }
690
691 if (fLogging && flog && (dwEnableLogging > 0))
692 {
693 TEB *teb = GetThreadTEB();
694
695 va_start(argptr, tekst);
696 if (teb)
697 teb->o.odin.logfile = (DWORD)flog;
698 vfprintf(flog, tekst, argptr);
699 if (teb)
700 teb->o.odin.logfile = 0;
701 va_end(argptr);
702 }
703
704 logMutex.leave();
705 DosUnsetExceptionHandler(&RegRec);
706 SetFS(sel);
707 return 1;
708}
709//******************************************************************************
710//******************************************************************************
711void SYSTEM DecreaseLogCount()
712{
713 dwEnableLogging--;
714}
715//******************************************************************************
716//******************************************************************************
717void SYSTEM IncreaseLogCount()
718{
719 dwEnableLogging++;
720}
721//******************************************************************************
722//******************************************************************************
723int SYSTEM WritePrivateLog(void *logfile, const char *tekst, ...)
724{
725 USHORT sel = RestoreOS2FS();
726 va_list argptr;
727
728 if (fLogging && logfile)
729 {
730 TEB *teb = GetThreadTEB();
731
732 va_start(argptr, tekst);
733 if (teb)
734 teb->o.odin.logfile = (DWORD)flog;
735 vfprintf((FILE *)logfile, tekst, argptr);
736 if (teb)
737 teb->o.odin.logfile = 0;
738 va_end(argptr);
739
740 if (tekst[strlen(tekst)-1] != '\n')
741 fprintf((FILE *)logfile, "\n");
742 }
743
744 SetFS(sel);
745 return 1;
746}
747//******************************************************************************
748//WriteLog has to take special care to handle dprintfs inside our os/2 exception
749//handler; if an exception occurs inside a dprintf, using dprintf in the exception
750//handler will hang the process
751//******************************************************************************
752int LogException(int state, int prevlock)
753{
754 TEB *teb = GetThreadTEB();
755 int ret = 0;
756
757 if (!teb) return 0;
758
759#if !defined(__EMX__)
760 if (teb->o.odin.logfile)
761 {
762#if (__IBMCPP__ == 300) || (__IBMC__ == 300)
763 PUSHORT lock = (USHORT *)(teb->o.odin.logfile+0x1C);
764#else
765#if __IBMC__ >= 360 || __IBMCPP__ >= 360
766//TODO: test this!!!!!!!
767 PUSHORT lock = (USHORT *)(teb->o.odin.logfile+0x1C);
768#else
769#error Check the offset of the lock count word in the file stream structure for this compiler revision!!!!!
770#endif
771#endif
772 ret = (*lock);
773 if (state == ENTER_EXCEPTION)
774 {
775 if((*lock) > 0) (*lock)--;
776 }
777 else
778 { //LEAVE_EXCEPTION
779 if(prevlock) (*lock)++;
780 }
781 }
782#else
783//kso 2001-01-29: EMX/GCC
784// we maybe should do something with the _more->rsem (_rmutex) structure but
785// I wanna have this compile, so we'll address problems later.
786#endif
787 return ret;
788}
789//******************************************************************************
790//Check if the exception occurred inside a fprintf (logging THDB member set)
791//If true, decrease the lock count for that file stream
792//NOTE: HACK: DEPENDS ON COMPILER VERSION!!!!
793//******************************************************************************
794void CheckLogException()
795{
796 TEB *teb = GetThreadTEB();
797 PUSHORT lock;
798
799 if(!teb) return;
800
801#if !defined(__EMX__)
802 if(teb->o.odin.logfile) {
803 //oops, exception in vfprintf; let's clear the lock count
804#if (__IBMCPP__ == 300) || (__IBMC__ == 300)
805 lock = (PUSHORT)(teb->o.odin.logfile+0x1C);
806#else
807#if __IBMC__ >= 360 || __IBMCPP__ >= 360
808//TODO: test this!!!!!!!
809 PUSHORT lock = (USHORT *)(teb->o.odin.logfile+0x1C);
810#else
811#error Check the offset of the lock count word in the file stream structure for this compiler revision!!!!!
812#endif
813#endif
814 (*lock)--;
815 }
816#else
817//kso 2001-01-29: EMX/GCC
818// we maybe should do something with the _more->rsem (_rmutex) structure but
819// I wanna have this compile, so we'll address problems later.
820#endif
821}
822//******************************************************************************
823//NOTE: No need to save/restore FS, as our FS selectors have already been
824// destroyed and FS == 0x150B.
825//******************************************************************************
826void CloseLogFile()
827{
828#ifdef __IBMC__
829 if(oldcrtmsghandle)
830 _set_crt_msg_handle(oldcrtmsghandle);
831#endif
832
833#ifdef WIN32_IP_LOGGING
834 if(logSocket != -1) {
835 soclose(logSocket);
836 }
837#endif
838
839 if(flog) fclose(flog);
840 flog = 0;
841}
842//******************************************************************************
843//Used to open any private logfiles used in kernel32 (for now only in winimagepeldr.cpp)
844//******************************************************************************
845void OpenPrivateLogFiles()
846{
847#ifdef DEFAULT_LOGGING_OFF
848 if(getenv("WIN32LOG_ENABLED")) {
849#else
850 if(!getenv("NOWIN32LOG")) {
851#endif
852 OpenPrivateLogFilePE();
853 }
854}
855//******************************************************************************
856//Used to close all private logfiles used in kernel32 (for now only in winimagepeldr.cpp)
857//******************************************************************************
858void ClosePrivateLogFiles()
859{
860#ifdef DEFAULT_LOGGING_OFF
861 if(getenv("WIN32LOG_ENABLED")) {
862#else
863 if(!getenv("NOWIN32LOG")) {
864#endif
865 ClosePrivateLogFilePE();
866 }
867}
868//******************************************************************************
869//******************************************************************************
870void SYSTEM CheckVersion(ULONG version, char *modname)
871{
872 dprintf(("CheckVersion of %s, %d\n", modname, version));
873 if(version != PE2LX_VERSION){
874 static char msg[300];
875 int r;
876 dprintf(("Version mismatch! %d, %d: %s\n", version, PE2LX_VERSION, modname));
877 sprintf(msg, "%s is intended for use with a different release of Odin.\n", modname);
878 do{
879 r = WinMessageBox(HWND_DESKTOP, NULLHANDLE, msg, "Version Mismatch!", 0, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_MOVEABLE);
880 }while(r == MBID_RETRY); // giggle
881 if( r != MBID_IGNORE )
882 exit(987);
883 }
884}
885//******************************************************************************
886//******************************************************************************
887void SYSTEM CheckVersionFromHMOD(ULONG version, HMODULE hModule)
888{
889 char name[_MAX_PATH];
890
891 // query name of dll.
892 if(!DosQueryModuleName(hModule, sizeof(name), name))
893 CheckVersion(version, name);
894}
895//******************************************************************************
896//******************************************************************************
897#ifdef __WATCOMC__ /*PLF Sat 97-06-21 17:12:36*/
898 extern void interrupt3( void );
899 #pragma aux interrupt3= \
900 "int 3"
901#endif
902extern "C"
903void WIN32API DebugBreak()
904{
905 dprintf(("DebugBreak\n"));
906
907 LPSTR lpstrEnv = getenv("WIN32.DEBUGBREAK"); /* query environment */
908 if (lpstrEnv == NULL) /* if environment is not set, don't call debugger ! */
909 return;
910
911#ifdef __WATCOMC__
912 interrupt3();
913#else
914 _interrupt(3);
915#endif
916}
917//******************************************************************************
918//******************************************************************************
919
920
921/*****************************************************************************
922 * Name : DebugErrorBox
923 * Purpose : display an apprioriate error box with detailed information
924 * about the error cause
925 * Parameters: APIRET iErrorCode - OS/2 error code
926 * PSZ pszFormat - printf-format string
927 * ...
928 * Variables :
929 * Result : return code of the message box
930 * Remark :
931 * Status :
932 *
933 * Author : Patrick Haller [Tue, 1999/09/13 19:55]
934 *****************************************************************************/
935
936int SYSTEM DebugErrorBox(ULONG iErrorCode,
937 char* pszFormat,
938 ...)
939{
940 char szMessageBuffer[1024]; /* buffer for the text message */
941 char szErrorBuffer[1024]; /* buffer for the operating system text */
942 ULONG bc; /* dummy */
943 APIRET rc2; /* API returncode */
944 int iRC; /* message box return code */
945
946 USHORT sel = RestoreOS2FS();
947 va_list argptr;
948
949 // clear memory
950 memset (szMessageBuffer, 0, sizeof(szMessageBuffer));
951 memset (szErrorBuffer, 0, sizeof(szErrorBuffer));
952
953 // build message string
954 va_start(argptr, pszFormat);
955 vsprintf(szMessageBuffer, pszFormat, argptr);
956 va_end(argptr);
957
958 // query error string
959 rc2 = DosGetMessage(NULL,
960 0,
961 szErrorBuffer,
962 sizeof(szErrorBuffer),
963 iErrorCode,
964 "OSO001.MSG",
965 &bc);
966
967 // display message box
968 iRC = WinMessageBox(HWND_DESKTOP,
969 NULLHANDLE,
970 szMessageBuffer,
971 szErrorBuffer,
972 0,
973 MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
974 SetFS(sel);
975 return iRC;
976}
977
978
979/**
980 * Query Odin32 build number.
981 * @returns Build number.
982 * @status Completely implemented.
983 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
984 */
985int WIN32API Odin32GetBuildNumber(void)
986{
987 dprintf(("Odin32GetBuildNumber returned %d\n", ODIN32_BUILD_NR));
988 return ODIN32_BUILD_NR;
989}
990
Note: See TracBrowser for help on using the repository browser.