Watt-32 tcp/ip  2.2 dev-rel.10
misc.c
Go to the documentation of this file.
1 
14 #include <signal.h>
15 #include <math.h>
16 
17 #if defined(__HIGHC__)
18 #include <init.h> /* _mwlsl(), _msgetcs() */
19 #endif
20 
21 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(__CYGWIN__)
22  #include <io.h>
23  #include <fcntl.h>
24 
25  #if !defined(__CYGWIN__)
26  #include <share.h>
27  #endif
28 
29  #include <sys/stat.h>
30 #endif
31 
32 #include "wattcp.h"
33 #include "wdpmi.h"
34 #include "x32vm.h"
35 #include "powerpak.h"
36 #include "strings.h"
37 #include "cpumodel.h"
38 #include "sock_ini.h"
39 #include "pcsed.h"
40 #include "pcpkt.h"
41 #include "pcconfig.h"
42 #include "pcdbug.h"
43 #include "bsddbug.h"
44 #include "ioport.h"
45 #include "timer.h"
46 #include "run.h"
47 #include "misc.h"
48 
49 #if defined(USE_STACKWALKER)
50  /* Ref: http://blog.kalmbachnet.de/files/04-10-01__leakfinder.htm */
51  #include "stkwalk.h"
52 #endif
53 
54 /* These arrays are used in several places (save some space)
55  */
56 const char hex_chars_lower[] = "0123456789abcdef";
57 const char hex_chars_upper[] = "0123456789ABCDEF";
58 
59 BOOL win32_dos_box = FALSE;
60 BOOL _watt_fatal_error = FALSE;
61 WORD _watt_os_ver = 0x622;
62 char _watt_assert_buf[256];
64 /*
65  * Set through macro SOCK_ERRNO() in <sys/werrno.h>.
66  */
67 int _w32_errno = 0;
68 
69 #if (DOSX & (PHARLAP|X32VM)) && defined(HAVE_FARPTR48)
70  FARPTR _watt_dosFp; /* we have 48-bit far-pointers */
71 
72 #endif
73 
74 #if defined(__LCC__)
75  static _CPUID lcc_cpuid;
76  char cdecl x86_type = 5; /* !! */
77  char cdecl x86_vendor_id[13];
78  DWORD cdecl x86_capability;
79 #endif
80 
81 #if (DOSX)
82  static void setup_dos_xfer_buf (void);
83  static void is_in_stack_init (void) ATTR_NOINLINE();
84 #endif
85 
86 #define STATIC /* ease disassembly */
87 
88 #if defined(__BORLANDC__)
89  #pragma inline
90  #if defined(USE_DEBUG) && (defined(__SMALL__) || defined(__LARGE__))
91  STATIC int setup_stk_check (void);
92  #endif
93 
94 #elif defined(WATCOM386) && defined(__MSDOS__)
95  extern char cdecl __begtext; /* label at TEXT start */
96  extern UINT cdecl _x386_stacklow;
97 
98  #if defined(__SW_3S) /* wcc386 -3s */
99  void cdecl _fatal_runtime_error (UINT stk);
100  #define FATAL_HANDLER _fatal_runtime_error
101  #else
102  void cdecl _fatal_runtime_error_ (UINT stk);
103  #define FATAL_HANDLER _fatal_runtime_error_
104  #endif
105 
106 
107  /* Prevent linker (with 'option eliminate') to strip our
108  * '_fatal_runtime_error()' function from .exe-image.
109  */
110  char *dummy_fatal_rte = (char*)&FATAL_HANDLER;
111 
112 #elif defined(_MSC_VER) && defined(__LARGE__) && defined(USE_DEBUG)
113  extern void (__cdecl *_aaltstkovr) (void);
114  static void stk_overflow (void _far *where);
115 #endif
116 
117 #if (DOSX & (PHARLAP|X32VM)) || (DOSX == 0)
118 #define CS_WRITEABLE
119 #endif
120 
121 #define MAKE_CS_WRITEABLE() ((void)0)
122 #define UNDO_CS_ACCESS() ((void)0)
125 #if defined(USE_DEBUG) && defined(__BORLANDC__) && (defined(__SMALL__) || defined(__LARGE__))
126 STATIC void test_stk_check (void)
127 {
128  char buf[1000];
129  sprintf (buf, "In test_stk_check(): CS:IP %04X:%04X\n",
130  _CS, FP_OFF(test_stk_check));
131  puts (buf);
132 }
133 #endif
134 
135 /*
136  * Turn off stack-checking to avoid destroying assumptions
137  * made in bswap patch code below. And also to make this run
138  * a bit faster.
139  */
140 #include "nochkstk.h"
141 
142 #if !defined(USE_BIGENDIAN)
143 
147 unsigned long cdecl _w32_intel (unsigned long val)
148 {
149  return ((val & 0x000000FFU) << 24) |
150  ((val & 0x0000FF00U) << 8) |
151  ((val & 0x00FF0000U) >> 8) |
152  ((val & 0xFF000000U) >> 24);
153 }
154 
159 unsigned short cdecl _w32_intel16 (unsigned short val)
160 {
161  return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8);
162 }
163 
164 #if (DOSX) && defined(CS_WRITEABLE)
165 static const BYTE bswap32[] = {
166  0x8B,0x44,0x24,0x04, /* mov eax,[esp+4] */
167  0x0F,0xC8, /* bswap eax */
168  0xC3 /* ret */
169  };
170 
171 static const BYTE bswap16[] = {
172  0x8B,0x44,0x24,0x04, /* mov eax,[esp+4] */
173  0x0F,0xC8, /* bswap eax */
174  0xC1,0xE8,0x10, /* shr eax,16 */
175  0xC3 /* ret */
176  };
177 
178 /*
179  * Modify functions intel/intel16 (htonl/htons) to use the
180  * BSWAP instruction on 80486+ CPUs. We don't bother with real-mode
181  * targets on a 80486+ CPU. Hope that size of overwritten functions
182  * are big enough.
183  */
184 static void patch_with_bswap (void)
185 {
186  MAKE_CS_WRITEABLE(); /* save descriptor access, make RW */
187  memcpy ((void*)_w32_intel, (const void*)&bswap32, sizeof(bswap32));
188  memcpy ((void*)_w32_intel16,(const void*)&bswap16, sizeof(bswap16));
189  UNDO_CS_ACCESS(); /* set old descriptor access */
190 }
191 #endif /* (DOSX) && defined(CS_WRITEABLE) */
192 #endif /* !USE_BIGENDIAN */
193 
194 
200 DWORD get_day_num (void)
201 {
202 #if defined(WIN32)
203  time_t now;
204 
205  time (&now);
206  return ((DWORD)now / (24*3600));
207 #else
208  struct dosdate_t d;
209 
210  memset (&d, 0, sizeof(d));
211  _dos_getdate (&d);
212  --d.month;
213  --d.day;
214  return ((d.year-1970) * 365 + d.month * 31 + d.day);
215 #endif
216 }
217 
218 
219 #if (DOSX) && defined(__MSDOS__)
220 /*
221  * Safe check for an enabled RDTSC instruction.
222  * Requires an "GenuineIntel" Pentium CPU to call Get_CR4()
223  * (crashes on AMD K6-2 etc.).
224  */
225 static BOOL RDTSC_enabled (void)
226 {
227  const char *env = getenv ("USE_RDTSC");
228 
229  use_rdtsc = (env && ATOI(env) > 0);
230 
231  if (!use_rdtsc || /* Usage not enabled */
232  x86_type < 5) /* Not a Pentium class CPU */
233  return (FALSE);
234 
235  if (!strncmp(x86_vendor_id,"AuthenticAMD",12) &&
236  (x86_capability & X86_CAPA_TSC)) /* AMD with TSC, okay? */
237  return (TRUE);
238 
239  if (!strncmp(x86_vendor_id,"CentaurHauls",12)) /* Centaur/VIA is okay */
240  {
241 #if 0
242  /* The following code was originally written by
243  * Michal Ludvig <michal@logix.cz> for VIA PadLock code
244  * in OpenSSL. http://www.logix.cz/michal
245  */
246  DWORD eax, ebx, ecx, edx;
247 
248  get_cpuid (0xC0000000, &eax, &ebx, &ecx, &edx);
249  centaur_eflag = (eax >= 0xC0000001);
250  if (centaur_eflag)
251  {
252  get_cpuid (0xC0000001, &eax, &ebx, &ecx, &edx);
253  use_ace = ((edx & (0x3 << 6)) == (0x3 << 6)); /* Advanced Cryptography Engine */
254  use_rng = ((edx & (0x3 <<2 )) == (0x3 << 2)); /* Random Number Generator */
255  }
256 #endif
257  return (TRUE);
258  }
259 
260  if (strncmp(x86_vendor_id,"GenuineIntel",12) || /* Not Genuine Intel or */
261  (x86_capability & X86_CAPA_TSC) == 0) /* RDTSC not supported */
262  return (FALSE);
263 
264 #if (DOSX) && !defined(__LCC__) && !defined(BORLAND_WIN32)
265  return ((Get_CR4() & CR4_TS_DISABLE) == 0); /* True if not disabled */
266 #else
267  return (TRUE); /* RDTSC never disabled in real-mode */
268 #endif
269 }
270 #endif /* DOSX && __MSDOS__ */
271 
272 
273 #if (DOSX == 0) && defined(USE_DEBUG)
274 
281 #define OffsetOf(x) (unsigned)&(x)
282 
283 static BOOL check_reg_struct (void)
284 {
285 #if defined(__WATCOMC__)
286  struct IREGS *r1 = NULL;
287  union REGPACK *r2 = NULL;
288 
289  if ((OffsetOf(r2->w.ax) != OffsetOf(r1->r_ax)) ||
290  (OffsetOf(r2->w.bx) != OffsetOf(r1->r_bx)) ||
291  (OffsetOf(r2->w.cx) != OffsetOf(r1->r_cx)) ||
292  (OffsetOf(r2->w.dx) != OffsetOf(r1->r_dx)) ||
293  (OffsetOf(r2->w.bp) != OffsetOf(r1->r_bp)) ||
294  (OffsetOf(r2->w.si) != OffsetOf(r1->r_si)) ||
295  (OffsetOf(r2->w.di) != OffsetOf(r1->r_di)) ||
296  (OffsetOf(r2->w.ds) != OffsetOf(r1->r_ds)) ||
297  (OffsetOf(r2->w.es) != OffsetOf(r1->r_es)) ||
298  (OffsetOf(r2->x.flags) != OffsetOf(r1->r_flags)))
299  return (FALSE);
300 
301 #elif defined(__BORLANDC__)
302  struct IREGS *r1 = NULL;
303  struct REGPACK *r2 = NULL;
304 
305  if ((OffsetOf(r2->r_ax) != OffsetOf(r1->r_ax)) ||
306  (OffsetOf(r2->r_bx) != OffsetOf(r1->r_bx)) ||
307  (OffsetOf(r2->r_cx) != OffsetOf(r1->r_cx)) ||
308  (OffsetOf(r2->r_dx) != OffsetOf(r1->r_dx)) ||
309  (OffsetOf(r2->r_bp) != OffsetOf(r1->r_bp)) ||
310  (OffsetOf(r2->r_si) != OffsetOf(r1->r_si)) ||
311  (OffsetOf(r2->r_di) != OffsetOf(r1->r_di)) ||
312  (OffsetOf(r2->r_ds) != OffsetOf(r1->r_ds)) ||
313  (OffsetOf(r2->r_es) != OffsetOf(r1->r_es)) ||
314  (OffsetOf(r2->r_flags) != OffsetOf(r1->r_flags)))
315  return (FALSE);
316 #endif
317  return (TRUE);
318 }
319 #endif /* (DOSX == 0) && USE_DEBUG */
320 
324 void W32_CALL init_misc (void)
325 {
326  static BOOL init = FALSE;
327 
328  if (init)
329  return;
330 
331  _watt_assert_buf[0] = '\0';
332 
333 #if (DOSX)
335 #endif
336 
337 #if defined(WIN32)
338  init_win_misc();
339 
340 #elif defined(__DJGPP__)
341  _watt_os_ver = _get_dos_version (1);
342 
343 #elif defined(MSC386)
344  _watt_os_ver = 0x500; /* Fake it for 32-bit MSVC */
345 
346 #else
347  _watt_os_ver = (_osmajor << 8) + _osminor;
348 #endif
349 
350 #if defined(WIN32)
351  win32_dos_box = FALSE;
352 #else
353  win32_dos_box = (_watt_os_ver >= 0x700 || /* DOS 7.x/8.x; Win-9x/ME */
354  _watt_os_ver == 0x501 || /* Borland PowerPak under Win32 */
355  _watt_os_ver == 0x532); /* DOS 5.50; Win-NT+ */
356 #endif
357 
358 #if (DOSX & PHARLAP) && defined(HAVE_FARPTR48)
359  /*
360  * For 32-bit compilers with 48-bit far-pointers.
361  * `init_misc' MUST be called before `PEEKx()' functions are used.
362  */
363  FP_SET (_watt_dosFp, 0, SS_DOSMEM);
364 
365 #elif (DOSX & X32VM)
366  _watt_dosFp = MK_FP (_x386_zero_base_selector, 0);
367 
368 #elif defined(HAVE_FARPTR48) /* MSVC */
369  UNFINISHED();
370 #endif
371 
372 #if defined(__DJGPP__) || defined(__HIGHC__)
373 /* backtrace_init(); */
374 #endif
375 
376 #if (DOSX)
377  setup_dos_xfer_buf(); /* A no-op on djgpp and Win32 */
378 
379 #elif defined(USE_DEBUG) /* real-mode */
380  if (!check_reg_struct())
381  {
382  outsnl (__FILE__ ": IREGS/REGPACK size mismatch!");
383  exit (-1);
384  }
385 
386  #if defined(_MSC_VER) && defined(__LARGE__)
387  (DWORD)_aaltstkovr = (DWORD)stk_overflow;
388  #endif
389 
390  #if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__LARGE__))
391  setup_stk_check();
392  #endif
393 #endif
394 
395  /* Check CPU type. Use RDTSC instruction if not forced off and
396  * it's not disabled. No CPU detection on big-endian machines yet.
397  */
398 #if (DOSX) && defined(__MSDOS__)
399 #if defined(__LCC__)
400  if (_cpuidPresent())
401  {
402  _cpuid (&lcc_cpuid);
403  memcpy (&x86_vendor_id, &lcc_cpuid.Vendor, sizeof(x86_vendor_id));
404  x86_capability = X86_CAPA_TSC; /* !! this doesn't work: *(DWORD*) &lcc_cpuid.FpuPresent; */
405  }
406 #elif !defined(BORLAND_WIN32)
407  CheckCpuType();
408 #endif
409 
410  if (RDTSC_enabled()) /* Check if use of RDTSC is safe */
411  has_rdtsc = TRUE;
412 
413 #if defined(CS_WRITEABLE) /* FALSE on most targets */
414  if (x86_type >= 4)
415  patch_with_bswap();
416 #endif
417 #endif /* DOSX && __MSDOS__ */
418 
419 #if defined(WIN32)
420  srand (GetTickCount()); /* should be redundant */
421 #else
422  srand (PEEKW(0,0x46C)); /* initialize rand() using BIOS clock */
423 #endif
424 
425  /* init_misc() is called from gettimeofday2(). So don't do all this
426  * again when init_timers() calls gettimeofday2().
427  */
428  init = TRUE;
429  init_timers();
430 }
431 
439 FILE *fopen_excl (const char *file, const char *mode)
440 {
441 #if defined(WIN32) && !defined(__WATCOMC__) && !defined(__CYGWIN__)
442  int fd, flags = _O_CREAT | _O_TRUNC | _O_WRONLY;
443 
444 #ifdef _O_SEQUENTIAL
445  flags |= _O_SEQUENTIAL;
446 #endif
447  if (mode[strlen(mode)-1] == 'b')
448  flags |= O_BINARY;
449 
450  fd = _sopen (file, flags, SH_DENYWR, S_IREAD | S_IWRITE);
451  if (fd <= -1)
452  return (NULL);
453  return fdopen (fd, mode);
454 
455 #else
456  return fopen (file, mode);
457 #endif
458 }
459 
460 
461 /*
462  * Consolidated memory debug for Fortify and MSVC CrtDbg.
463  */
464 #if defined(USE_CRTDBG) /* For _MSC_VER (Win) only */
465  #if !defined(_MSC_VER)
466  #error "Something wrong; USE_CRTDBG is for Visual-C only"
467  #endif
468 
469 /*
470  * If using MSVCRTD debug version, there's little point using Fortify too.
471  * USE_CRTDBG is set only when building with cl -MDd or MTd etc (_DEBUG set).
472  */
473 #if !defined(_CRT_RPTHOOK_INSTALL) && (_MSC_VER < 1300) /* VC headers too old */
474  #define _CRT_RPTHOOK_INSTALL 0
475  #define _CRT_RPTHOOK_REMOVE 1
476 
477  _CRTIMP _CRT_REPORT_HOOK __cdecl
478  _CrtSetReportHook2 (int, _CRT_REPORT_HOOK);
479 #endif
480 
481 static _CrtMemState last_state;
482 static void __cdecl crtdbg_exit (void);
483 
484 static const char *report_name (int type)
485 {
486  return (type == _CRT_WARN ? "Warn" :
487  type == _CRT_ERROR ? "Error" :
488  type == _CRT_ASSERT ? "Assert" :
489  type == _CRT_ERRCNT ? "ErrCnt" : "??");
490 }
491 
492 /*
493  * This doesn't seem to be called (?)
494  */
495 static void __cdecl crtdbg_dump (const void *buf, size_t len)
496 {
497  const BYTE *p = (const BYTE*) buf;
498  size_t i;
499  int c;
500 
501  fprintf (stderr, "dump: buf %p, %u bytes\n", buf, len);
502  len = min (len, 30);
503  for (i = 0; i < len; i++)
504  {
505  c = *p++;
506  fprintf (stderr, "%c", isprint(c) ? c : '.');
507  }
508 }
509 
510 static BOOL got_crt_assert;
511 
512 static int __cdecl crtdbg_report (int type, char *message, int *ret_val)
513 {
514  fprintf (stderr, "%s: %s\n", report_name(type), message);
515  got_crt_assert = (type == _CRT_ASSERT);
516 
517  if (message && !strnicmp(message,"Run-Time Check",14)) /* 'cl -EHsc -RTCc' causes these */
518  got_crt_assert = 1;
519 
520  if (got_crt_assert)
521  crtdbg_exit();
522 
523  if (ret_val)
524  *ret_val = got_crt_assert; /* stopping forces a breakpoint (int 3) */
525  return (type == _CRT_ASSERT);
526 }
527 
528 static void __cdecl crtdbg_exit (void)
529 {
530 #if defined(USE_STACKWALKER)
531  CONTEXT ctx;
532 
533  memset (&ctx, 0, sizeof(ctx));
534  if (got_crt_assert)
535  {
536  ctx.ContextFlags = CONTEXT_FULL;
537  got_crt_assert = FALSE; /* prevent reentry */
538  RtlCaptureContext (&ctx);
539 
544  CONSOLE_MSG (0, ("\nGot _CRT_ASSERT. Backtrace:\n"));
545  ShowStack (GetCurrentThread(), &ctx, NULL);
546  }
547 
548  if (DeInitAllocCheck() > 0)
549  (*_printf) ("Mem-leaks detected; look at '%s' for details.\n", StackWalkLogFile());
550 #endif /* USE_STACKWALKER */
551 
552 #if 0
553  _CrtMemDumpAllObjectsSince (&last_state);
554  _CrtMemDumpStatistics (&last_state);
555  _CrtCheckMemory();
556  _CrtDumpMemoryLeaks();
557 #endif
558 
559  _CrtSetReportHook (NULL);
560 }
561 
562 void memdbg_init (void)
563 {
564 #if defined(USE_STACKWALKER)
565  InitAllocCheck (ACOutput_Simple, TRUE, 0);
566 
567 #elif (_MSC_VER < 1500) || 1 /* !! */
568  _HFILE file = _CRTDBG_FILE_STDERR;
569  int mode = _CRTDBG_MODE_FILE;
570  int flags = _CRTDBG_LEAK_CHECK_DF |
571  _CRTDBG_DELAY_FREE_MEM_DF |
572  /* _CRTDBG_CHECK_CRT_DF | */ /* Don't report allocs in CRT */
573  _CRTDBG_CHECK_ALWAYS_DF |
574  _CRTDBG_ALLOC_MEM_DF;
575 
576  _CrtSetReportFile (_CRT_ASSERT, file);
577  _CrtSetReportMode (_CRT_ASSERT, mode);
578  _CrtSetReportFile (_CRT_ERROR, file);
579  _CrtSetReportMode (_CRT_ERROR, mode);
580  _CrtSetReportFile (_CRT_WARN, file);
581  _CrtSetReportMode (_CRT_WARN, mode);
582 
583  _CrtSetDbgFlag (flags | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG));
584 
585  _CrtSetReportHook (crtdbg_report);
586  _CrtMemCheckpoint (&last_state);
587  _CrtSetDumpClient (crtdbg_dump);
588 #endif /* USE_STACKWALKER */
589 
590  RUNDOWN_ADD (crtdbg_exit, 305);
591 }
592 
593 void memdbg_post_init (void)
594 {
595 #if defined(USE_STACKWALKER)
596  if (stkwalk_details == 1)
597  SetCallStackOutputType (ACOutput_Simple);
598  else if (stkwalk_details == 2)
599  SetCallStackOutputType (ACOutput_Advanced);
600 #endif
601 }
602 
603 #elif defined(USE_FORTIFY)
604 
609 static void fortify_report (void)
610 {
611  if (debug_on >= 2)
612  {
613  Fortify_SetOutputFunc ((Fortify_OutputFuncPtr)printf);
614  Fortify_OutputStatistics();
615  }
616  else
617  Fortify_SetOutputFunc (NULL);
618  Fortify_LeaveScope();
619 }
620 
621 void memdbg_init (void)
622 {
623  static int done = 0;
624 
625 #if defined(USE_DEBUG) && defined(USE_BSD_API)
626  Fortify_SetOutputFunc (bsd_fortify_print);
627 #endif
628 
629  if (done)
630  return;
631  done = 1;
632  Fortify_EnterScope();
633 
634  RUNDOWN_ADD (fortify_report, 305);
635 }
636 
637 void memdbg_post_init (void)
638 {
639  if (fortify_fail_rate)
640  Fortify_SetAllocateFailRate (fortify_fail_rate);
641 }
642 #endif /* USE_FORTIFY */
643 
644 #if !defined(USE_CRTDBG) && !defined(USE_FORTIFY)
645  void memdbg_init (void) {}
646  void memdbg_post_init (void) {}
647 #endif
648 
652 void assert_fail (const char *file, unsigned line, const char *what)
653 {
654  int (MS_CDECL *save_printf) (const char*, ...) = _printf;
655  int len;
656 
657 #if defined(WIN32)
658  DWORD err = GetLastError();
659 
660 #if defined(USE_STACKWALKER)
661  /*
662  * When calling ShowStack() we must do minimal work
663  * in sock_exit(). Fix this bug!!
664  */
665  _watt_fatal_error = 1;
666 #endif
667 
668  if (_watt_is_gui_app)
669  _printf = gui_printf;
670 #endif /* WIN32 */
671 
672 #if defined(SNPRINTF)
673  len = SNPRINTF (_watt_assert_buf, sizeof(_watt_assert_buf)-1,
674 #else
675  len = sprintf (_watt_assert_buf,
676 #endif
677  "%s (%u): Assertion `%s' failed.\n", file, line, what);
678 
679 #if defined(WIN32)
680  if (err && len > 0)
681  SNPRINTF (len + _watt_assert_buf, sizeof(_watt_assert_buf) - len, \
682  " GetLastError() %s", win_strerror(err));
683 #endif
684 
685  (*_printf) ("%s\n", _watt_assert_buf);
686  _printf = save_printf;
687 
688  /*
689  * On djgpp abort() doesn't call atexit() functions but
690  * makes a handy traceback. We need to force a rundown_run()
691  * to release te packet-driver.
692  */
693  rundown_run();
694  abort(); /* doesn't return */
695  ARGSUSED (len);
696 }
697 
698 /*
699  * Some tests for assert(), abort(), exception and mem-leak code.
700  */
701 void W32_CALL assert_fail_test (void)
702 {
703  int printer_ready = FALSE;
704 
705 #if defined(WIN32)
706  SetLastError (ERROR_PRINTER_DELETED); /* :-) */
707 #endif
708 
709  WATT_ASSERT (printer_ready);
710  ARGSUSED (printer_ready);
711 }
712 
713 void W32_CALL abort_test (void)
714 {
715  abort();
716  exit (-1);
717 }
718 
719 void W32_CALL except_test (void)
720 {
721  char **p = NULL;
722  *p = '\0';
723  exit (-1);
724 }
725 
726 void W32_CALL leak_test (void)
727 {
728  char *s = strdup ("foo-bar");
729 
730  ARGSUSED (s);
731 
732 #ifdef USE_STACKWALKER
733  if (DeInitAllocCheck() > 0) /* Test leak reporting */
734  (*_printf) ("Mem-leaks detected; look at '%s' for details.\n", StackWalkLogFile());
735 #endif
736  exit (-1);
737 }
738 
742 unsigned W32_CALL Random (unsigned a, unsigned b)
743 {
744  if (a == b)
745  return (a);
746 
747  if (a > b)
748  {
749  unsigned tmp = b;
750  b = a;
751  a = tmp;
752  }
753  return (a + (unsigned)(rand() % (b-a+1)));
754 }
755 
759 void W32_CALL RandomWait (unsigned a, unsigned b)
760 {
761  DWORD t = set_timeout (Random(a, b));
762 
763  while (!chk_timeout(t))
764  {
765 #if defined(WIN32)
766  Sleep (1);
767 #else
768  ENABLE();
769 #endif
770  }
771 }
772 
776 void Wait (unsigned msec)
777 {
778  DWORD t = set_timeout (msec);
779 
780  while (!chk_timeout(t))
781  {
782 #if defined(WIN32)
783  Sleep (1);
784 #else
785  ENABLE();
786 #endif
787  }
788 }
789 
790 /*
791  * Return a sensible name for running DOS-extender or subsystem.
792  */
793 const char *dos_extender_name (void)
794 {
795 #if (DOSX & DOS4GW)
796  return dos4gw_extender_name();
797 #elif (DOSX & DJGPP)
798  return ("djgpp");
799 #elif (DOSX & PHARLAP)
800  return ("PharLap");
801 #elif (DOSX & POWERPAK)
802  return ("PowerPak");
803 #elif (DOSX & X32VM)
804  return ("X32VM");
805 #elif defined(_WIN64)
806  return ("Win64");
807 #elif (DOSX & WINWATT)
808  return ("Win32");
809 #else
810  return (NULL);
811 #endif
812 }
813 
814 #if defined(WIN32)
815 void os_yield (void)
816 {
817  /* Since on Windows we cannot longjmp()
818  * out of our SIGINT-handler watt_sig_handler_watt(),
819  * we check the flag here.
820  */
821  if (!_watt_is_gui_app && _watt_cbroke)
822  {
823  BEEP();
824  sock_sig_exit ("\nTerminating.", SIGINT);
825  }
826  Sleep (10);
827 }
828 
829 #else /* !WIN32 */
830 
831 void os_yield (void)
832 {
833  static BOOL do_yield = TRUE;
834 
835 #if defined(__DJGPP__)
836  if (do_yield)
837  {
838  __dpmi_yield();
839  do_yield = (errno != ENOSYS);
840  }
841 #else
842  if (!watt_kbhit() && do_yield) /* watt_kbhit() to enable ^C generation */
843  {
844  IREGS reg;
845  memset (&reg, 0, sizeof(reg));
846  reg.r_ax = 0x1680;
847  GEN_INTERRUPT (0x2F, &reg);
848  do_yield = (loBYTE(reg.r_ax) != 0x80);
849  }
850 #endif
851 }
852 #endif /* WIN32 */
853 
854 
855 #if defined(NOT_USED)
856 BOOL watt_check_break (void)
857 {
858  WORD head = 0x400 + PEEKW (0, 0x41A);
859  WORD tail = 0x400 + PEEKW (0, 0x41C);
860  int ofs, num;
861 
862  printf ("\nwatt_check_break(): head %04X, tail %04X, keys:\n",
863  head, tail);
864  for (num = 0, ofs = head; ofs != tail && num < 32; num++)
865  {
866  printf (" ofs %04X: %02X\n", ofs, PEEKB(0,ofs));
867  if (++ofs > 32+0x41E)
868  ofs = 0x41E;
869  }
870  puts ("");
871  return (FALSE);
872 }
873 #endif
874 
878 char *ctime_r (const time_t *t, char *res)
879 {
880  return strcpy (res, ctime(t));
881 }
882 
886 struct tm *localtime_r (const time_t *t, struct tm *res)
887 {
888  struct tm *r;
889 
890  WATT_ASSERT (res);
891  r = localtime (t);
892  if (r)
893  memcpy (res, r, sizeof(*res));
894  return (r);
895 }
896 
900 int W32_CALL watt_kbhit (void)
901 {
902 #if defined(WIN32)
903  os_yield();
904  return kbhit(); /* for CygWin, kbhit() is in winmisc.c */
905 
906 #else
907  if (_watt_cbroke)
908  return (1);
909 
910  /* If head and tail index of the keyboard buffer are the same,
911  * no key is waiting.
912  */
913  if (PEEKW(0,0x41A) == PEEKW(0,0x41C))
914  return (0);
915 
916  /* RTL's kbhit() calls INT16/11 or INT21/0B which triggers INT 23
917  * which in turn should raise SIGINT in RTL. Except for djgpp under
918  * Windows where normal/extended BREAK checking is turned off (since
919  * SIGINT delivery by pressing ^C is so unreliable under Windows).
920  */
921  return kbhit();
922 #endif
923 }
924 
925 #if defined(USE_DEBUG)
926 
929 const char *list_lookup (DWORD type, const struct search_list *list, int num)
930 {
931  static char buf[15];
932 
933  while (num > 0 && list->name)
934  {
935  if (list->type == type)
936  return (list->name);
937  num--;
938  list++;
939  }
940  sprintf (buf, "?%lu", type);
941  return (buf);
942 }
943 
944 const char *list_lookupX (DWORD type, const struct search_list *list, int num)
945 {
946  static char buf[15];
947 
948  while (num > 0 && list->name)
949  {
950  if (list->type == type)
951  return (list->name);
952  num--;
953  list++;
954  }
955  sprintf (buf, "?0x%lX", type);
956  return (buf);
957 }
958 
963 const char *MAC_address (const void *addr)
964 {
965  static char buf[2][25];
966  static int idx = 0;
967  char *rc = buf [idx];
968  char *p = rc;
969  const char *a = (const char*)addr;
970 
971  p += sprintf (p, "%02X:%02X:%02X:%02X:%02X:%02X",
972  a[0] & 255, a[1] & 255, a[2] & 255,
973  a[3] & 255, a[4] & 255, a[5] & 255);
974 
975  /* assume '*addr' is an 7-byte AX25 address
976  */
977  if (_pktdevclass == PDCLASS_AX25)
978  sprintf (p, ":%02X", a[6] & 255);
979 
980  idx ^= 1;
981  return (rc);
982 }
983 
984 void unfinished (const char *func, const char *file, unsigned line)
985 {
986  if (func)
987  fprintf (stderr, "In `%s' ", func);
988  fprintf (stderr, "%s (%u):\7 Help! Unfinished code.\n", file, line);
989  exit (-1);
990 }
991 
992 void unimplemented (const char *func, const char *file, unsigned line)
993 {
994  fprintf (stderr, "%s (%u): Function \"%s()\" not implemented for this target.\n",
995  file, line, func);
996 }
997 
1002 const char *dword_str (DWORD val)
1003 {
1004  static char buf[20];
1005  char tmp[20];
1006 
1007  if (val < 1000UL)
1008  {
1009  sprintf (buf, "%lu", val);
1010  return (buf);
1011  }
1012  if (val < 1000000UL) /* 1E6 */
1013  {
1014  sprintf (buf, "%lu,%03lu", val/1000UL, val % 1000UL);
1015  return (buf);
1016  }
1017  if (val < 1000000000UL) /* 1E9 */
1018  {
1019  sprintf (tmp, "%9lu", val);
1020  sprintf (buf, "%.3s,%.3s,%.3s", tmp, tmp+3, tmp+6);
1021  return strltrim (buf);
1022  }
1023  sprintf (tmp, "%12lu", val);
1024  sprintf (buf, "%.3s,%.3s,%.3s,%.3s", tmp, tmp+3, tmp+6, tmp+9);
1025  return strltrim (buf);
1026 }
1027 #endif /* USE_DEBUG */
1028 
1029 
1030 #if (DOSX)
1031 #if defined(BORLAND386) || defined(DMC386) || defined(MSC386)
1032 DWORD get_ds_limit (void)
1033 {
1034  DWORD res;
1035  asm mov ax, ds
1036  asm and eax, 0FFFFh
1037  asm lsl eax, eax
1038  asm mov res, eax
1039  return (res);
1040 }
1041 
1042 DWORD get_cs_limit (void)
1043 {
1044  DWORD res;
1045  asm mov ax, cs
1046  asm and eax, 0FFFFh
1047  asm lsl eax, eax
1048  asm mov res, eax
1049  return (res);
1050 }
1051 
1052 DWORD get_ss_limit (void)
1053 {
1054  DWORD res;
1055  asm mov ax, ss
1056  asm and eax, 0FFFFh
1057  asm lsl eax, eax
1058  asm mov res, eax
1059  return (res);
1060 }
1061 
1062 #elif defined(__CCDL__)
1063 DWORD get_ds_limit (void)
1064 {
1065  asm {
1066  mov ax, ds
1067  and eax, 0xFFFF
1068  lsl eax, eax
1069  }
1070  return (_EAX);
1071 }
1072 
1073 DWORD get_cs_limit (void)
1074 {
1075  asm {
1076  mov ax, cs
1077  and eax, 0xFFFF
1078  lsl eax, eax
1079  }
1080  return (_EAX);
1081 }
1082 
1083 DWORD get_ss_limit (void)
1084 {
1085  asm {
1086  mov ax, ss
1087  and eax, 0xFFFF
1088  lsl eax, eax
1089  }
1090  return (_EAX);
1091 }
1092 #endif
1093 
1094 #if defined(__DJGPP__) && 0 /* not needed */
1095  extern unsigned dj_end asm ("end");
1096  extern unsigned _stklen, __djgpp_stack_limit;
1097  #define STK_START() (DWORD)&dj_end
1098 #endif
1099 
1100 /*
1101  * The is_in_stack() function is by
1102  * Jani Kajala (jani.kajala@helsinki.fi)
1103  * Feb 7, 2002.
1104  *
1105  * Swig (when creating _watt32.pyd) has a mysterious issue with
1106  * thread-storage data and MSVC. That's why 'THREAD_LOCAL' is
1107  * undefined when 'SWIG' is defined.
1108  *
1109  * The dis-assembly of get_frame_size() and is_in_stack_init().
1110  * (they are inlined):
1111  *
1112  * mov edx,dword ptr _watt32!__tls_index
1113  * lea eax,0x3[esp]
1114  * lea ecx,0x3[esp]
1115  * add ecx,ecx
1116  * lea eax,[eax+eax*2]
1117  * sub eax,ecx
1118  * mov ecx,dword ptr fs:__tls_array << FS points to Thread Info Block (TIB)
1119  * mov edx,dword ptr [ecx+edx*4] << Crash here (ECX=EDX=0)
1120  */
1121 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
1122  #define THREAD_LOCAL __declspec(thread)
1123 
1124 #elif defined(__DMC__) && defined(WIN32)
1125  #define THREAD_LOCAL __declspec(thread)
1126 
1127 #elif defined(__BORLANDC__) && defined(WIN32)
1128  #define THREAD_LOCAL __thread
1129 
1130 #else
1131  #define THREAD_LOCAL
1132 #endif
1133 
1134 #if defined(SWIG)
1135  #undef THREAD_LOCAL
1136  #define THREAD_LOCAL
1137 #endif
1138 
1139 #if !defined(WIN32)
1140 #define UINT_PTR unsigned
1141 #endif
1142 
1143 THREAD_LOCAL static UINT_PTR stack_bottom = 0;
1144 THREAD_LOCAL static UINT_PTR stack_limit = 0;
1145 
1146 static unsigned get_frame_size (const char *x)
1147 {
1148  char y = 0;
1149  return (unsigned)(x - &y);
1150 }
1151 
1152 /*
1153  * \todo: must call this once for each thread that calls is_in_stack().
1154  * At the moment, there are no callers.
1155  */
1156 static void is_in_stack_init (void)
1157 {
1158 #if !(defined(__WATCOMC__) && defined(WIN32))
1159 
1160 #ifdef WIN32
1161  MEMORY_BASIC_INFORMATION minfo;
1162  NT_TIB *tib = GetCurrentFiber();
1163  NT_TIB *orig_tib = tib;
1164 
1165 #if 1
1166  tib = NULL;
1167 #endif
1168 
1169  if (!tib)
1170  {
1171  VirtualQuery ((void*)&minfo, &minfo, sizeof(minfo));
1172  stack_bottom = (UINT_PTR) minfo.AllocationBase;
1173  stack_limit = 2*1024UL*1204UL; /* 2 MB is just a guess */
1174  }
1175  else
1176  {
1177  stack_bottom = (UINT_PTR) tib->StackBase;
1178  stack_limit = (UINT_PTR) tib->StackLimit;
1179  }
1180 
1181  if (_watt_is_win9x)
1182  stack_bottom += 64 * 1000UL;
1183 
1184  CONSOLE_MSG (2, ("tib: 0x%" ADDR_FMT ", stack_bottom: 0x%" ADDR_FMT ", stack_limit:"
1185  " %" ABUS_VAL_FMT "\n",
1186  ADDR_CAST(orig_tib),
1187  ADDR_CAST(stack_bottom), /* Not an address, but cast anyway to shut-up gcc */
1188  stack_limit));
1189 
1190  CONSOLE_MSG (2, ("is_in_stack(&minfo): %s \n",
1191  is_in_stack(&minfo) ? "TRUE" : "FALSE!!??"));
1192 
1193 #else
1194  char x = 0;
1195  stack_bottom = (unsigned) (&x + get_frame_size(&x) * 2);
1196 #endif
1197 #endif /* !(__WATCOMC__ && WIN32) */
1198 }
1199 
1200 BOOL is_in_stack (const void *ptr)
1201 {
1202  char x;
1203  UINT_PTR stack_top = (UINT_PTR) &x;
1204  UINT_PTR p = (UINT_PTR) ptr;
1205 
1206  if (stack_top > stack_bottom)
1207  return (p > stack_bottom && p < stack_top); /* stack grows up */
1208  return (p > stack_top && p < stack_bottom); /* stack grows down */
1209 }
1210 
1211 unsigned used_stack (void)
1212 {
1213  char x;
1214  UINT_PTR stack_top = (UINT_PTR) &x;
1215 
1216  if (stack_top > stack_bottom)
1217  return (unsigned) (stack_top - stack_bottom);
1218  return (unsigned) (stack_bottom - stack_top);
1219 }
1220 
1221 /*
1222  * Test for valid read/write data address.
1223  * We assume linear address 'addr' is both readable and writeable.
1224  *
1225  * \note MingW (and other Win32 compilers?) puts 'const' data in
1226  * read-only sections (.rdata). Detectable with IsBadWritePtr().
1227  */
1228 BOOL valid_addr (const void *addr, unsigned len)
1229 {
1230 #if defined(WIN32)
1231  /*
1232  * It seems it's a bad idea to use the IsBadXxxPtr() functions.
1233  * See the comment section here:
1234  * http://msdn.microsoft.com/en-us/library/windows/desktop/aa366716(v=vs.85).aspx
1235  */
1236  BOOL bad;
1237 
1238  if (_watt_crit_sect.SpinCount == -1) /* DeleteCriticalSection() was called!? */
1239  return (FALSE);
1240 
1241  ENTER_CRIT();
1242  bad = IsBadWritePtr ((void*)addr,len) || IsBadReadPtr (addr,len);
1243  LEAVE_CRIT();
1244  if (bad)
1245  return (FALSE);
1246 
1247 #else
1248 
1249  DWORD limit, addr_ = (DWORD)addr;
1250 
1251  if (addr_ < 4096) /* Valid in DOS4GW, but we never use such address */
1252  return (FALSE);
1253 
1254  /* In X32VM: DS != SS. addr may be in data or stack.
1255  */
1256 #if defined(DMC386) && (DOSX & X32VM) && 0 /* Doesn't work :-( */
1257  if (selector == MY_SS())
1258  {
1259  limit = get_ss_limit();
1260  if (addr_ < _x386_stacklow || addr_ + len >= limit)
1261  return (FALSE);
1262  if (limit > len && addr_ >= limit - len) /* Segment wrap */
1263  return (FALSE);
1264  }
1265  else if (selector != MY_DS())
1266  return (FALSE);
1267 #endif
1268 
1269 #if defined(__DJGPP__)
1270  limit = __dpmi_get_segment_limit (_my_ds());
1271 #elif defined(__HIGHC__)
1272  limit = _mwlsl (_mwgetcs()); /* DS & CS are aliases */
1273 #else
1274  limit = get_ds_limit();
1275 #endif
1276 
1277  if (addr_ + len >= limit)
1278  return (FALSE);
1279  if (limit > len && addr_ >= limit - len) /* Segment wrap */
1280  return (FALSE);
1281 #endif /* WIN32 */
1282 
1283  return (TRUE);
1284 }
1285 #endif /* DOSX */
1286 
1287 
1288 /*
1289  * Pharlap/X32VM targets: Get location of (or allocate a) transfer buffer.
1290  * DOS4GW/PowerPak targets: Allocate a small (1kB) transfer buffer.
1291  * djgpp/Win32/Win64: Nothing special to do.
1292  */
1293 #if (DOSX & (PHARLAP|X32VM))
1294  REALPTR _watt_dosTbr;
1295  DWORD _watt_dosTbSize = 0;
1296  static WORD rm_seg = 0;
1297 
1298  static void free_selector (void)
1299  {
1300  if (rm_seg)
1301  _dx_real_free (rm_seg);
1302  rm_seg = 0;
1303  _watt_dosTbr = 0;
1304  _watt_dosTbSize = 0;
1305  }
1306 
1307  static void setup_dos_xfer_buf (void)
1308  {
1309  FARPTR dos_tbp; /* pmode transfer-buffer address */
1310  REALPTR r2p_addr; /* rmode to pmode call address */
1311  WORD temp;
1312  int len = 1024; /* min size we need */
1313 
1314  _dx_rmlink_get (&r2p_addr, &_watt_dosTbr,
1315  &_watt_dosTbSize, &dos_tbp);
1316 
1317  if (_watt_dosTbSize < len &&
1318  _dx_real_above(len, &rm_seg, &temp) == 0)
1319  {
1320  RP_SET (_watt_dosTbr, 0, rm_seg);
1321  _watt_dosTbSize = len;
1322  RUNDOWN_ADD (free_selector, 15);
1323  }
1324  }
1325 
1326 #elif (DOSX & DOS4GW)
1327  WORD _watt_dosTbSeg = 0; /* paragraph address of xfer buffer */
1328  WORD _watt_dosTbSel = 0; /* selector for transfer buffer */
1329  DWORD _watt_dosTbSize = 0; /* size of transfer buffer */
1330 
1331  static void free_selector (void)
1332  {
1333  if (_watt_dosTbSel)
1334  #ifdef __CCDL__
1335  dpmi_free_selector (_watt_dosTbSel);
1336  #else
1337  dpmi_real_free (_watt_dosTbSel);
1338  #endif
1339  _watt_dosTbSel = 0;
1340  }
1341 
1342  static void setup_dos_xfer_buf (void)
1343  {
1344  _watt_dosTbSize = 1024;
1345  #ifdef __CCDL__
1346  if (dpmi_alloc_real_memory (&_watt_dosTbSel, &_watt_dosTbSeg, _watt_dosTbSize) >= 0)
1347  _watt_dosTbSeg = 0;
1348  #else
1349  _watt_dosTbSeg = dpmi_real_malloc (_watt_dosTbSize, &_watt_dosTbSel);
1350  #endif
1351 
1352  if (!_watt_dosTbSeg)
1353  _watt_dosTbSize = 0;
1354  else RUNDOWN_ADD (free_selector, 15);
1355  }
1356 
1357 #elif (DOSX & POWERPAK)
1358  WORD _watt_dos_ds;
1359  WORD _watt_dosTbSeg = 0;
1360  WORD _watt_dosTbSel = 0;
1361  DWORD _watt_dosTbr = 0;
1362  DWORD _watt_dosTbSize = 0;
1363 
1364  static void free_selector (void)
1365  {
1366  if (_watt_dosTbSel)
1367  dpmi_real_free (_watt_dosTbSel);
1368  _watt_dosTbSel = 0;
1369  if (_watt_dos_ds)
1370  dpmi_free_dos_selector (_watt_dos_ds);
1371  _watt_dos_ds = 0;
1372  _watt_dosTbr = 0;
1373  }
1374 
1375  static void setup_dos_xfer_buf (void)
1376  {
1377  _watt_dos_ds = dpmi_create_dos_selector();
1378  if (!_watt_dos_ds)
1379  {
1380  fprintf (stderr, "Fatal: Failed to create DOS selector. "
1381  "DPMI error 0x%04X.\n", __dpmi_errno);
1382  exit (-1);
1383  }
1384  _watt_dosTbSize = 1024;
1385  _watt_dosTbSeg = dpmi_real_malloc (_watt_dosTbSize, &_watt_dosTbSel);
1386  if (!_watt_dosTbSeg)
1387  _watt_dosTbSize = 0;
1388  else
1389  {
1390  RUNDOWN_ADD (free_selector, 15);
1391  _watt_dosTbr = (_watt_dosTbSeg << 16);
1392  }
1393  }
1394 
1395 #elif (DOSX)
1396  static void setup_dos_xfer_buf (void)
1397  {
1398  /* no-op */
1399  }
1400 #endif
1401 
1402 
1403 #if defined(USE_BSD_API)
1404 /*
1405  * ffs() isn't needed yet, but could be used in select_s()
1406  *
1407  * Copyright (C) 1991, 1992 Free Software Foundation, Inc.
1408  * Contributed by Torbjorn Granlund (tege@sics.se).
1409  *
1410  * The GNU C Library is free software; you can redistribute it and/or
1411  * modify it under the terms of the GNU Library General Public License as
1412  * published by the Free Software Foundation; either version 2 of the
1413  * License, or (at your option) any later version.
1414  *
1415  * The GNU C Library is distributed in the hope that it will be useful,
1416  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1417  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1418  * Library General Public License for more details.
1419  *
1420  * You should have received a copy of the GNU Library General Public
1421  * License along with the GNU C Library; see the file COPYING.LIB. If
1422  * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
1423  * Cambridge, MA 02139, USA.
1424  */
1425 
1426 /*
1427  * Returns the index of first bit set in 'i'. Counting from 1 at
1428  * "right side". Returns 0 if 'i' is 0.
1429  */
1430 int W32_CALL _w32_ffs (int i)
1431 {
1432  static const BYTE table[] = {
1433  0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1434  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1435  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1436  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1437  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
1438  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
1439  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
1440  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
1441  };
1442  DWORD a, x;
1443 
1444 #if (DOSX) && !defined(__LCC__) && !defined(BORLAND_WIN32) && !defined(__MINGW64__)
1445  if (x86_type >= 3)
1446  return asm_ffs (i); /* BSF requires 386+ */
1447 #endif
1448 
1449  x = i & -i;
1450  a = x <= 0xFFFFUL ? (x <= 0xFF ? 0 : 8) : (x <= 0xFFFFFF ? 16 : 24);
1451  return (table[x >> a] + a);
1452 }
1453 #endif /* USE_BSD_API */
1454 
1455 
1456 /*
1457  * Checks for bugs when compiling in large model C compiler
1458  *
1459  * Borland C uses a 4K stack by default. In all memory models the
1460  * stack grows down toward the heap.
1461  *
1462  * If you accidentally place _tcp_Socket onto the stack, then you
1463  * will have already used up that whole 4K and then some!
1464  *
1465  * In large model, this will mess up the data space in a major way
1466  * because the stack starts at SS:_stklen, or SS:1000, so you will
1467  * wrap the SP pointer back around to FFFE and start writing over
1468  * the far heap. Yuck.
1469  *
1470  * In small model it usually doesn't kill your application because
1471  * you would have to be down to your last 4K of memory and this is
1472  * not as common.
1473  *
1474  * The solutions: declare your sockets as static, or put them on the
1475  * heap, or bump up your stack size by using the global special variable:
1476  *
1477  * unsigned _stklen = 16536;
1478  */
1479 
1480 #if defined(__LARGE__)
1481 void watt_large_check (const void *sock, int size,
1482  const char *file, unsigned line)
1483 {
1484  if ((unsigned)(FP_OFF(sock)) > (unsigned)(-size))
1485  {
1486 #if defined(USE_DEBUG)
1487  fprintf (stderr, "%s (%d): user stack size error", file, line);
1488 #else
1489  outsnl ("user stack size error");
1490  ARGSUSED (file);
1491  ARGSUSED (line);
1492 #endif
1493  exit (3);
1494  }
1495 }
1496 #endif /* __LARGE__ */
1497 
1498 
1499 #if defined(USE_DEBUG)
1500 #if defined(NOT_USED)
1501 BOOL is_big_endian (void)
1502 {
1503  /* From Harbison & Steele.
1504  */
1505  union {
1506  long l;
1507  char c[sizeof(long)];
1508  } u;
1509 
1510  u.l = 1;
1511  return (u.c[sizeof(long)-1] == 1);
1512 }
1513 
1517 #include <sys/pack_on.h>
1518 
1519 struct cmd_block {
1520  BYTE len;
1521  char buf[256];
1522  };
1523 
1524 #include <sys/pack_off.h>
1525 
1526 BOOL shell_exec (const char *cmd)
1527 {
1528  struct cmd_block blk;
1529  size_t i = sizeof(blk.buf)-1;
1530  IREGS regs;
1531 
1532  _strlcpy (blk.buf, cmd, i);
1533  i = min (i, strlen(blk.buf));
1534  blk.len = i;
1535  blk.buf[i] = '\r';
1536 
1537 #if (DOSX & DJGPP)
1538  regs.r_ds = __tb / 16;
1539  regs.r_si = __tb & 15;
1540  dosmemput (&blk, sizeof(blk), __tb);
1541 
1542 #elif (DOSX == 0)
1543  regs.r_ds = FP_SEG (&blk);
1544  regs.r_si = FP_OFF (&blk);
1545 #endif
1546 
1547  GEN_INTERRUPT (0x2E, &regs);
1548  return (regs.r_ax != 0xFFFF);
1549 }
1550 #endif /* NOT_USED */
1551 
1552 
1556 #if (defined(_MSC_VER) || defined(__DMC__)) && (DOSX == 0)
1557 #undef intr
1558 void _w32_intr (int int_no, IREGS *reg)
1559 {
1560  union REGS r;
1561  struct SREGS s;
1562 
1563  r.x.ax = reg->r_ax;
1564  r.x.bx = reg->r_bx;
1565  r.x.cx = reg->r_cx;
1566  r.x.dx = reg->r_dx;
1567  r.x.si = reg->r_si;
1568  r.x.di = reg->r_di;
1569  s.ds = reg->r_ds;
1570  s.es = reg->r_es;
1571  int86x (int_no, &r, &r, &s);
1572  reg->r_flags = r.x.cflag;
1573  reg->r_ax = r.x.ax;
1574  reg->r_bx = r.x.bx;
1575  reg->r_cx = r.x.cx;
1576  reg->r_dx = r.x.dx;
1577  reg->r_si = r.x.si;
1578  reg->r_di = r.x.di;
1579  reg->r_ds = s.ds;
1580  reg->r_es = s.es;
1581 }
1582 #endif
1583 
1584 
1585 #if defined(__BORLANDC__) && defined(__LARGE__)
1586 /*
1587  * Large model with option '-N' generates code like:
1588  * < .. standard prologue ...>
1589  * 39 26 00 00 cmp DGROUP:__stklen,sp
1590  * 77 05 ja Lxx
1591  * 9A 00 00 00 00 call F_OVERFLOW@
1592  * Lxx:
1593  *
1594  * We need to find the address of F_OVERFLOW@ (it cannot be addressed
1595  * from C).
1596  */
1597 STATIC void stk_overflow (WORD ret_addr)
1598 {
1599  static WORD cs, ip;
1600  static WORD stk[128];
1601 
1602  cs = *(WORD*) (&ret_addr-1);
1603  ip = *(WORD*) (&ret_addr-2);
1604 
1605  _SS = FP_SEG (stk);
1606  _SP = (WORD) &stk [DIM(stk)-1];
1607  _stklen = 0x7FFF;
1608  _watt_fatal_error = TRUE;
1609  fprintf (stderr, "\nStack overflow at %04X:%04X!\n", cs, ip);
1610  _eth_release();
1611  _exit (-1);
1612 }
1613 
1614 STATIC int setup_stk_check (void)
1615 {
1616  BYTE sign[] = { 0x39, 0x26, 0,0, 0x77, 5, 0x9A };
1617  BYTE *p = (BYTE*) _eth_arrived;
1618  int i;
1619 
1620  *(WORD*)&sign[2] = FP_OFF (&_stklen);
1621  for (i = 0; i < 10; i++, p++)
1622  if (!memcmp(p, sign, sizeof(sign)))
1623  {
1624  DWORD addr = *(DWORD*) (p + sizeof(sign));
1625  BYTE *patch;
1626 
1627  /* printf ("F_OVERFLOW@ at %04X:%04X\n", (WORD)(addr >> 16), (WORD)addr); */
1628  patch = (BYTE*) addr;
1629  *patch++ = 0x2E;
1630  *patch++ = 0xFF;
1631  *patch++ = 0x2E;
1632  *(WORD*)patch = 6 - 1 + (WORD)addr; /* relocation of [where] */
1633  patch += 2;
1634  *(WORD*)patch = FP_OFF (stk_overflow);
1635  patch += 2;
1636  *(WORD*)patch = FP_SEG (stk_overflow);
1637 
1638  /*
1639  * 0001 F_OVERFLOW@:
1640  * 0001 2E: FF 2E 0006r jmp dword ptr cs:[where]
1641  * 0006 ???????? where dd ?
1642  */
1643 #if 0
1644  printf ("test_stk_check() at CS:IP %04X:%04X\n",
1645  _CS, FP_OFF(test_stk_check));
1646  _stklen = 10;
1647  test_stk_check();
1648 #endif
1649  return (1);
1650  }
1651  return (0);
1652 }
1653 
1654 #elif defined(__BORLANDC__) && defined(__SMALL__)
1655 /*
1656  * Small model with option '-N' generates code like:
1657  * < .. standard prologue ...>
1658  * 39 26 00 00 cmp ___brklvl,sp
1659  * 72 03 jb L$1
1660  * E8 00 00 call N_OVERFLOW@
1661  * L$1:
1662  *
1663  * We need to find the address of N_OVERFLOW@ (it cannot be addressed
1664  * from C). It should be the same code as in large model.
1665  */
1666 extern int __brklvl;
1667 
1668 static void stk_overflow (UINT ret_addr)
1669 {
1670  static WORD cs, ip;
1671  static WORD stk[128];
1672 
1673  cs = _CS;
1674  ip = *(WORD*) (&ret_addr-1);
1675 
1676  _SS = FP_SEG (stk);
1677  _SP = (WORD) &stk [DIM(stk)-1];
1678 
1679  _stklen = 0x7FFF;
1680  _watt_fatal_error = TRUE;
1681  fprintf (stderr, "\nStack overflow at %04X:%04X!\n", cs, ip);
1682  _eth_release();
1683  _exit (1); /* do minimal work, no rundown_run() */
1684 }
1685 
1686 static int stk_check_setup (void)
1687 {
1688  BYTE sign[] = { 0x39, 0x26, 0,0, 0x72, 3, 0xE8 };
1689  BYTE *p = (BYTE*) _eth_arrived;
1690  int i;
1691 
1692  *(WORD*)&sign[2] = FP_OFF (&__brklvl);
1693  for (i = 0; i < 10; i++, p++)
1694  if (!memcmp(p, sign, sizeof(sign)))
1695  {
1696  BYTE *addr = *(BYTE*)(++p);
1697  *addr = (BYTE*) stk_overflow;
1698  return (1);
1699  }
1700  return (0);
1701 }
1702 
1703 #elif defined(WATCOM386) && !defined(WIN32)
1704 /*
1705  * For tracking down stack overflow bugs.
1706  * Stack checker __CHK is pascal-style with stack-size at [esp+4].
1707  * __CHK calls __STK which in turn may call _fatal_runtime_error()
1708  *
1709  * Compiling with stack-checking on, this prologue is in every function:
1710  * (*) push <stack size needed> <- 68h, dword size at EIP-9
1711  * call __CHK <- 5 bytes
1712  * ... <- extracted EIP of return
1713  */
1714 static void stk_overflow (WORD cs, UINT eip)
1715 {
1716  UINT size = *(UINT*)(eip-9);
1717 
1718  eip -= (UINT)&__begtext - 9; /* print .map-file address of (*) */
1719 
1720  _watt_fatal_error = TRUE;
1721  fprintf (stderr, "Stack overflow (%u bytes needed) detected at %X:%08lXh\n",
1722  size, cs, (DWORD)eip);
1723  _eth_release();
1724  _exit (1); /* do minimal work, no rundown_run() */
1725 }
1726 
1727 void FATAL_HANDLER (UINT stk)
1728 {
1729 #if defined(__SMALL__)
1730  _x386_stacklow = stk + 2;
1731  stk_overflow (MY_CS(), *(DWORD*)(&stk+1));
1732 
1733 #elif defined(__LARGE__)
1734  _x386_stacklow = stk + 4;
1735  stk_overflow (*(WORD*)(&stk+1), *(WORD*)(&stk+2)); /* far-call */
1736 
1737 #else /* wcc386/DOS */
1738  _x386_stacklow = stk + 4;
1739  stk_overflow (MY_CS(), *(WORD*)(&stk+1));
1740 #endif
1741 }
1742 
1743 #elif defined(_MSC_VER) && defined(__LARGE__)
1744 static void stk_overflow (void _far *where)
1745 {
1746  fprintf (stderr, "Stack overflow detected at %04X:%04Xh\n",
1747  FP_SEG(where), FP_OFF(where));
1748  _eth_release();
1749  _exit (1);
1750 }
1751 #endif
1752 #endif /* USE_DEBUG */
1753 
1754 /*
1755  * Functions needed for "gcc -O0". These are inlined on -O1 or above.
1756  */
1757 #if defined(__GNUC__)
1758 #undef __SYS_SWAP_BYTES_H
1759 #undef _w32_SYS_SWAP_BYTES_H
1760 #undef _w32_CPUMODEL_H
1761 #undef _w32_MISC_H
1762 #undef _w32_IOPORT_H
1763 #undef BEEP
1764 
1765 #define extern
1766 #define __inline__
1767 #define __inline
1768 
1769 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__)
1770  #undef intel
1771  #undef intel16
1772  #define __NO_INLINE__ /* emulate -O0 */
1773 #endif
1774 
1775 #include <sys/swap.h>
1776 #include "misc.h"
1777 #include "cpumodel.h"
1778 
1779 #if defined(__EMX__)
1780 #include "ioport.h"
1781 #endif
1782 
1783 #endif /* __GNUC__ */
1784 
1785 
1786 #if defined(TEST_PROG)
1787 #if defined(__MSDOS__)
1788 /*
1789  * Get/set DOS' memory allocation strategy.
1790  */
1791 static BOOL get_mem_strat (BYTE *strat)
1792 {
1793  IREGS reg;
1794 
1795  memset (&reg, 0, sizeof(reg));
1796  reg.r_ax = 0x5800;
1797  GEN_INTERRUPT (0x21, &reg);
1798  if (reg.r_flags & CARRY_BIT)
1799  return (FALSE);
1800  *strat = loBYTE (reg.r_ax);
1801  return (TRUE);
1802 }
1803 
1804 static BOOL set_mem_strat (BYTE strat)
1805 {
1806  IREGS reg;
1807 
1808  memset (&reg, 0, sizeof(reg));
1809  reg.r_ax = 0x5801;
1810  reg.r_bx = strat;
1811  GEN_INTERRUPT (0x21, &reg);
1812  if (reg.r_flags & CARRY_BIT)
1813  return (FALSE);
1814  return (TRUE);
1815 }
1816 #endif
1817 
1818 void foo_10 (void) { puts ("I'm foo_10()"); }
1819 void foo_20 (void) { puts ("I'm foo_20()"); }
1820 void foo_30 (void) { puts ("I'm foo_30()"); }
1821 void foo_40 (void) { puts ("I'm foo_40()"); }
1822 void foo_50 (void) { puts ("I'm foo_50()"); }
1823 void foo_60 (void) { puts ("I'm foo_60()"); }
1824 void foo_70 (void) { puts ("I'm foo_70()"); }
1825 
1826 int main (void)
1827 {
1828 #if defined(__MSDOS__)
1829  BYTE strat;
1830 
1831  printf ("DOS memory allocation strategy: ");
1832  if (!get_mem_strat(&strat))
1833  puts ("failed");
1834  else printf ("0x%02X\n", strat);
1835 
1836  printf ("Setting \"low memory best fit\" ");
1837  if (!set_mem_strat(1))
1838  puts ("failed");
1839  else puts ("okay");
1840 
1841  set_mem_strat (strat);
1842 #endif /* __MSDOS__ */
1843 
1844  RUNDOWN_ADD (foo_40, 40);
1845  RUNDOWN_ADD (foo_10, 10);
1846  RUNDOWN_ADD (foo_60, 60);
1847  RUNDOWN_ADD (foo_30, 30);
1848  RUNDOWN_ADD (foo_20, 20);
1849  RUNDOWN_ADD (foo_50, 50);
1850  RUNDOWN_ADD (foo_70, 70);
1851  debug_on = 2;
1852  rundown_run();
1853  return (0);
1854 }
1855 #endif
1856 
char _watt_assert_buf[256]
Definition: misc.c:62
unsigned W32_CALL Random(unsigned a, unsigned b)
Returns a random integer in range [a..b].
Definition: misc.c:742
unsigned long cdecl _w32_intel(unsigned long val)
Convert 32-bit big-endian (network order) to intel (host order) format.
Definition: misc.c:147
void _w32_intr(int int_no, IREGS *reg)
Microsoft/Digital Mars doesn't have intr() so we make our own.
Definition: misc.c:1558
void assert_fail(const char *file, unsigned line, const char *what)
Store the "assert fail" text for later before printing it.
Definition: misc.c:652
struct tm * localtime_r(const time_t *t, struct tm *res)
A reentrant localtime().
Definition: misc.c:886
char * strltrim(const char *s)
Return pointer to first non-blank (space/tab) in a string.
Definition: strings.c:243
WORD _watt_os_ver
Definition: misc.c:61
void Wait(unsigned msec)
Not all vendors have delay().
Definition: misc.c:776
unsigned short cdecl _w32_intel16(unsigned short val)
Convert 16-bit big-endian (network order) to intel (host order) format.
Definition: misc.c:159
BOOL has_rdtsc
Never set in Watt-32.
Definition: timer.c:52
void init_timers(void)
Setup timer stuff and measure CPU speed.
Definition: timer.c:111
volatile int _watt_cbroke
Definition: pc_cbrk.c:47
DWORD get_day_num(void)
Simplified method of getting days since 1970-01-01.
Definition: misc.c:200
Core definitions.
const char * list_lookup(DWORD type, const struct search_list *list, int num)
Search 'list' for 'type' and return it's name.
Definition: misc.c:929
BOOL use_rdtsc
Ditto.
Definition: timer.c:53
char * _strlcpy(char *dst, const char *src, size_t len)
Similar to strncpy(), but always returns 'dst' with 0-termination.
Definition: strings.c:226
const char * MAC_address(const void *addr)
Return hexa-decimal string for an 6/7 byte MAC-address.
Definition: misc.c:963
FILE * fopen_excl(const char *file, const char *mode)
WIN32: Open an existing file (or create) in share-mode but deny other processes to write to the file...
Definition: misc.c:439
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
Definition: ip.h:67
const char * dword_str(DWORD val)
Return nicely formatted string "xx,xxx,xxx" with thousand separators (left adjusted).
Definition: misc.c:1002
WORD _pktdevclass
Ethernet, Token, FDDI etc.
Definition: pcpkt.c:51
void W32_CALL sock_sig_exit(const char *msg, int sig)
Exit handler for unhandled signals.
Definition: sock_ini.c:1057
static void __cdecl crtdbg_exit(void)
Definition: misc.c:528
int W32_CALL watt_kbhit(void)
A less CPU hogging kbhit().
Definition: misc.c:900
void W32_CALL RandomWait(unsigned a, unsigned b)
Wait for a random period in range [a..b] millisec.
Definition: misc.c:759
static void fortify_report(void)
Report routine for Fortify.
Definition: misc.c:609
BOOL _watt_fatal_error
Definition: misc.c:60
static void is_in_stack_init(void)
Definition: misc.c:83
BOOL win32_dos_box
Definition: misc.c:59
Definition: misc.h:511
char * ctime_r(const time_t *t, char *res)
A reentrant ctime().
Definition: misc.c:878
void W32_CALL _eth_release(void)
Release the hardware driver.
Definition: pcsed.c:1397
void W32_CALL init_misc(void)
Initialise various stuff.
Definition: misc.c:324
Run a COMMAND.COM/4DOS external/internal command.
Definition: misc.c:1519
BOOL W32_CALL chk_timeout(DWORD value)
Check if milli-sec value has expired:
Definition: timer.c:547
void *W32_CALL _eth_arrived(WORD *type_ptr, BOOL *broadcast)
Poll for arrival of new packets (IP/ARP/RARP/PPPoE protocol).
Definition: pcsed.c:1026
int main(int argc, char **argv)
Definition: echo.c:223