FS2_Open
Open source remastering of the Freespace 2 engine
windebug.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 // Nothing in this module should be externalized!!!
11 //XSTR:OFF
12 
13 //#define DUMPRAM // This dumps all symbol sizes. See John for more info
14 
15 /* Windows Headers */
16 #include <windows.h>
17 #include <windowsx.h>
18 #include <stdio.h>
19 
20 #ifdef _MSC_VER
21 # include <crtdbg.h>
22  /* Uncomment SHOW_CALL_STACK to show the call stack in Asserts, Warnings, and Errors */
23 # define SHOW_CALL_STACK
24 #endif // _MSC_VER
25 
26 /* STL Headers */
27 #include <string>
28 
29 /* SCP Headers */
30 #include "osapi/osapi.h"
31 #include "globalincs/pstypes.h"
32 #include "globalincs/systemvars.h"
33 #include "cmdline/cmdline.h"
34 #include "parse/lua.h"
35 #include "parse/parselo.h"
36 #include "debugconsole/console.h"
37 
38 #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
40 #endif
41 
42 extern void gr_activate(int active);
43 
44 bool Messagebox_active = false;
45 
48 
49 const int Messagebox_lines = 30;
50 
51 #ifndef _ASSERT
52  #ifndef _DEBUG
53  #define _ASSERT(expr) ((void)0)
54  #else
55  #define _ASSERT(expr) (assert(expr))
56 // #error _ASSERT is not defined yet for debug mode with non-MSVC compilers
57  #endif
58 #endif
59 
60 const char *clean_filename( const char *name)
61 {
62  const char *p = name+strlen(name)-1;
63  // Move p to point to first letter of EXE filename
64  while( (*p!='\\') && (*p!='/') && (*p!=':') && (p>= name) )
65  p--;
66  p++;
67 
68  return p;
69 }
70 
71 #if defined( SHOW_CALL_STACK )
72 static bool Dump_to_log = true;
73 
74 class DumpBuffer
75 {
76 public :
77  enum { BUFFER_SIZE = 32000 } ;
78  DumpBuffer() ;
79  void Clear() ;
80  void Printf( const char* format, ... ) ;
81  void SetWindowText( HWND hWnd ) const ;
82  char buffer[ BUFFER_SIZE ] ;
83 
84  void Append(const char* text);
85  void Truncate(size_t size);
86  void TruncateLines(int num_allowed_lines);
87  size_t Size() const;
88 private :
89  char* current ;
90 } ;
91 
92 
93 
94 DumpBuffer :: DumpBuffer()
95 {
96  Clear() ;
97 }
98 
99 
100 void DumpBuffer :: Clear()
101 {
102  current = buffer ;
103 }
104 
105 
106 void DumpBuffer :: Append(const char* text)
107 {
108  strcat_s(buffer, text);
109 }
110 
111 
112 void DumpBuffer :: Truncate(size_t size)
113 {
114  if (size >= strlen(buffer))
115  return;
116 
117  buffer[size] = 0;
118 }
119 
120 
121 // adapted from parselo
122 void DumpBuffer :: TruncateLines(int num_allowed_lines)
123 {
124  Assert(num_allowed_lines > 0);
125  char *find_from = buffer;
126  char *lastch = find_from + strlen(buffer) - 6;
127 
128  while (find_from < lastch)
129  {
130  if (num_allowed_lines <= 0)
131  {
132  *find_from = 0;
133  strcat_s(buffer, "[...]");
134  break;
135  }
136 
137  char *p = strchr(find_from, '\n');
138  if (p == NULL)
139  break;
140 
141  num_allowed_lines--;
142  find_from = p + 1;
143  }
144 }
145 
146 
147 size_t DumpBuffer :: Size() const
148 {
149  return strlen(buffer);
150 }
151 
152 
153 void DumpBuffer :: Printf( const char* format, ... )
154 {
155  va_list argPtr ;
156  int pos = current - buffer;
157  int max = BUFFER_SIZE - pos;
158 
159  // protect against obvious buffer overflow
160  if (pos >= BUFFER_SIZE)
161  return;
162 
163  va_start( argPtr, format ) ;
164  vsnprintf( current, max-1, format, argPtr ) ;
165  va_end( argPtr ) ;
166 
167  current[max-1] = '\0';
168  current += strlen(current);
169 }
170 
171 
172 void DumpBuffer :: SetWindowText( HWND hWnd ) const
173 {
174  SendMessage( hWnd, WM_SETTEXT, 0, (LPARAM)buffer ) ;
175 }
176 
177 /* Needed by LUA printf */
178 // This ought to be local to VerboseAssert, but it
179 // causes problems in Visual C++ (in the CRTL init phase)
180 static DumpBuffer dumpBuffer;
181 const char* Separator = "------------------------------------------------------------------\n" ;
182 
183 #endif
184 
185 /* MSVC2005+ callstack support
186  */
187 #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
188 
189 class SCP_DebugCallStack : public SCP_IDumpHandler
190 {
191 public:
192  virtual bool ResolveSymbols( )
193  {
194  return true;
195  }
196 
197  virtual void OnBegin( )
198  {
199  }
200 
201  virtual void OnEnd( )
202  {
203  }
204 
205  virtual void OnEntry( void* address, const char* module, const char* symbol )
206  {
207  UNREFERENCED_PARAMETER( address );
208 
209  StackEntry entry;
210  entry.module = clean_filename( module );
211  entry.symbol = symbol;
212  m_stackFrames.push_back( entry );
213  }
214 
215  virtual void OnError( const char* error )
216  {
217  /* No error handling here! */
218  UNREFERENCED_PARAMETER( error );
219  }
220 
221  SCP_string DumpToString( )
222  {
223  SCP_string callstack;
224  for ( size_t i = 0; i < m_stackFrames.size( ); i++ )
225  {
226  callstack += m_stackFrames[ i ].module + "! " + m_stackFrames[ i ].symbol + "\n";
227  }
228 
229  return callstack; /* Inefficient, but we don't need efficient here */
230  }
231 private:
232  struct StackEntry
233  {
234  SCP_string module;
235  SCP_string symbol;
236  };
237 
238  SCP_vector< StackEntry > m_stackFrames;
239 };
240 
241 #elif defined( SHOW_CALL_STACK )
242 
243 class PE_Debug
244  {
245  public :
246  PE_Debug() ;
247  ~PE_Debug() ;
248  void ClearReport() ;
249  int DumpDebugInfo( DumpBuffer& dumpBuffer, const BYTE* caller, HINSTANCE hInstance ) ;
250  void Display() ;
251  private :
252  // Report data
253  enum { MAX_MODULENAME_LEN = 512, VA_MAX_FILENAME_LEN = 256 } ;
254  char latestModule[ MAX_MODULENAME_LEN ] ;
255  char latestFile[ VA_MAX_FILENAME_LEN ] ;
256  // File mapping data
257  HANDLE hFile ;
258  HANDLE hFileMapping ;
259  PIMAGE_DOS_HEADER fileBase ;
260  // Pointers to debug information
261  PIMAGE_NT_HEADERS NT_Header ;
262  PIMAGE_COFF_SYMBOLS_HEADER COFFDebugInfo ;
263  PIMAGE_SYMBOL COFFSymbolTable ;
264  int COFFSymbolCount ;
265  const char* stringTable ;
266 
267  void ClearFileCache() ;
268  void ClearDebugPtrs() ;
269  void MapFileInMemory( const char* module ) ;
270  void FindDebugInfo() ;
271  void DumpSymbolInfo( DumpBuffer& dumpBuffer, DWORD relativeAddress ) ;
272  void DumpLineNumber( DumpBuffer& dumpBuffer, DWORD relativeAddress ) ;
273  PIMAGE_COFF_SYMBOLS_HEADER GetDebugHeader() ;
274  PIMAGE_SECTION_HEADER SectionHeaderFromName( const char* name ) ;
275  const char* GetSymbolName( PIMAGE_SYMBOL sym ) ;
276  } ;
277 
278 
279 // Add an offset to a pointer and cast to a given type; may be
280 // implemented as a template function but Visual C++ has some problems.
281 #define BasedPtr( type, ptr, ofs ) (type)( (DWORD)(ptr) + (DWORD)(ofs) )
282 
283 
284 PE_Debug :: PE_Debug()
285  {
286  // Init file mapping cache
287  hFileMapping = 0 ;
288  hFile = INVALID_HANDLE_VALUE ;
289  fileBase = 0 ;
290  ClearDebugPtrs() ;
291  ClearReport() ;
292  }
293 
294 
295 PE_Debug :: ~PE_Debug()
296  {
297  ClearFileCache() ;
298  }
299 
300 
301 void PE_Debug :: ClearReport()
302  {
303  latestModule[ 0 ] = 0 ;
304  latestFile[ 0 ] = 0 ;
305  }
306 
307 
308 void PE_Debug :: ClearDebugPtrs()
309  {
310  NT_Header = NULL ;
311  COFFDebugInfo = NULL ;
312  COFFSymbolTable = NULL ;
313  COFFSymbolCount = 0 ;
314  stringTable = NULL ;
315  }
316 
317 
318 void PE_Debug :: ClearFileCache()
319  {
320  if( fileBase )
321  {
322  UnmapViewOfFile( fileBase ) ;
323  fileBase = 0 ;
324  }
325  if( hFileMapping != 0 )
326  {
327  CloseHandle( hFileMapping ) ;
328  hFileMapping = 0 ;
329  }
330  if( hFile != INVALID_HANDLE_VALUE )
331  {
332  CloseHandle( hFile ) ;
333  hFile = INVALID_HANDLE_VALUE ;
334  }
335  }
336 
337 
338 void PE_Debug :: DumpLineNumber( DumpBuffer& dumpBuffer, DWORD relativeAddress )
339  {
340  PIMAGE_LINENUMBER line = BasedPtr( PIMAGE_LINENUMBER, COFFDebugInfo,
341  COFFDebugInfo->LvaToFirstLinenumber ) ;
342  DWORD lineCount = COFFDebugInfo->NumberOfLinenumbers ;
343  const DWORD none = (DWORD)-1 ;
344  DWORD maxAddr = 0 ;
345  DWORD lineNum = none ;
346  for( DWORD i=0; i < lineCount; i++ )
347  {
348  if( line->Linenumber != 0 ) // A regular line number
349  {
350  // look for line with bigger address <= relativeAddress
351  if( line->Type.VirtualAddress <= relativeAddress &&
352  line->Type.VirtualAddress > maxAddr )
353  {
354  maxAddr = line->Type.VirtualAddress ;
355  lineNum = line->Linenumber ;
356  }
357  }
358  line++ ;
359  }
360  if( lineNum != none ) {
361  dumpBuffer.Printf( " line %d\r\n", lineNum ) ;
362  if (Dump_to_log) {
363  mprintf(( " line %d\r\n", lineNum )) ;
364  }
365  }
366 // else
367 // dumpBuffer.Printf( " line <unknown>\r\n" ) ;
368  }
369 
370 
371 const char* PE_Debug :: GetSymbolName( PIMAGE_SYMBOL sym )
372  {
373  const int NAME_MAX_LEN = 64 ;
374  static char buf[ NAME_MAX_LEN ] ;
375  if( sym->N.Name.Short != 0 )
376  {
377  strncpy( buf, (const char*)sym->N.ShortName, 8 ) ;
378  buf[ 8 ] = 0 ;
379  }
380  else
381  {
382  strncpy( buf, stringTable + sym->N.Name.Long, NAME_MAX_LEN ) ;
383  buf[ NAME_MAX_LEN - 1 ] = 0 ;
384  }
385  return( buf ) ;
386  }
387 
388 void unmangle(char *dst, const char *src)
389 {
390  //strcpy_s( dst, src );
391  //return;
392 
393  src++;
394  while( (*src) && (*src!=' ') && (*src!='@') ) {
395  *dst++ = *src++;
396  }
397  *dst++ = 0;
398 }
399 
400 #ifdef DUMPRAM
401 
402 typedef struct MemSymbol {
403  int section;
404  int offset;
405  int size;
406  char name[132];
407 } MemSymbol;
408 
409 int Num_symbols = 0;
410 int Max_symbols = 0;
411 MemSymbol *Symbols;
412 
413 void InitSymbols()
414 {
415  Num_symbols = 0;
416  Max_symbols = 5000;
417  Symbols = (MemSymbol *)vm_malloc(Max_symbols*sizeof(MemSymbol));
418  if ( !Symbols ) {
419  Max_symbols = 0;
420  }
421 }
422 
423 void Add_Symbol( int section, int offset, const char *name, char *module )
424 {
425  if ( Num_symbols >= Max_symbols ) {
426  return;
427  }
428 
429  MemSymbol * sym = &Symbols[Num_symbols++];
430 
431  sym->section = section;
432  sym->offset = offset;
433  sym->size = -1;
434 
435  strcpy_s( sym->name, name );
436  strcat_s( sym->name, "(" );
437  strcat_s( sym->name, module );
438  strcat_s( sym->name, ")" );
439 
440 }
441 
442 int Sym_compare( const void *arg1, const void *arg2 )
443 {
444  MemSymbol * sym1 = (MemSymbol *)arg1;
445  MemSymbol * sym2 = (MemSymbol *)arg2;
446 
447  if ( sym1->section < sym2->section ) {
448  return -1;
449  } else if ( sym1->section > sym2->section ) {
450  return 1;
451  } else {
452  if ( sym1->offset > sym2->offset ) {
453  return 1;
454  } else {
455  return -1;
456  }
457  }
458 }
459 
460 int Sym_compare1( const void *arg1, const void *arg2 )
461 {
462  MemSymbol * sym1 = (MemSymbol *)arg1;
463  MemSymbol * sym2 = (MemSymbol *)arg2;
464 
465  if ( sym1->size < sym2->size ) {
466  return 1;
467  } else if ( sym1->size > sym2->size ) {
468  return -1;
469  } else {
470  return 0;
471  }
472 }
473 
474 void DumpSymbols()
475 {
476  int i;
477 
478  insertion_sort( Symbols, Num_symbols, sizeof(MemSymbol), Sym_compare );
479 
480  for (i=0;i<Num_symbols; i++ ) {
481  MemSymbol * sym1 = &Symbols[i];
482  MemSymbol * sym2 = &Symbols[i+1];
483  if ( (i<Num_symbols-1) && (sym1->section == sym2->section) ) {
484  sym1->size = sym2->offset-sym1->offset;
485  } else {
486  sym1->size = -1;
487  }
488  }
489 
490  insertion_sort( Symbols, Num_symbols, sizeof(MemSymbol), Sym_compare1 );
491 
492 
493  FILE *fp = fopen( "dump", "wt" );
494 
495  fprintf( fp, "%-100s %10s %10s\n", "Name", "Size", "Total" );
496 
497  int total_size = 0;
498  for (i=0;i<Num_symbols; i++ ) {
499  MemSymbol * sym = &Symbols[i];
500  if ( sym->size > 0 )
501  total_size += sym->size;
502  fprintf( fp, "%-100s %10d %10d\n", sym->name, sym->size, total_size );
503  }
504 
505  fclose(fp);
506 
507  vm_free( Symbols );
508  Symbols = NULL;
509  _asm int 3
510 }
511 #endif
512 
513 void PE_Debug::DumpSymbolInfo( DumpBuffer& dumpBuffer, DWORD relativeAddress )
514 {
515  // Variables to keep track of function symbols
516  PIMAGE_SYMBOL currentSym = COFFSymbolTable ;
517  PIMAGE_SYMBOL fnSymbol = NULL ;
518  DWORD maxFnAddress = 0 ;
519 
520  #ifdef DUMPRAM
521  InitSymbols();
522  #endif
523 
524  // Variables to keep track of file symbols
525  PIMAGE_SYMBOL fileSymbol = NULL ;
526  PIMAGE_SYMBOL latestFileSymbol = NULL ;
527  for ( int i = 0; i < COFFSymbolCount; i++ ) {
528 
529  // Look for .text section where relativeAddress belongs to.
530  // Keep track of the filename the .text section belongs to.
531  if ( currentSym->StorageClass == IMAGE_SYM_CLASS_FILE ) {
532  latestFileSymbol = currentSym;
533  }
534 
535  // Borland uses "CODE" instead of the standard ".text" entry
536  // Microsoft uses sections that only _begin_ with .text
537  const char* symName = GetSymbolName( currentSym ) ;
538 
539  if ( strnicmp( symName, ".text", 5 ) == 0 || strcmpi( symName, "CODE" ) == 0 ) {
540  if ( currentSym->Value <= relativeAddress ) {
541  PIMAGE_AUX_SYMBOL auxSym = (PIMAGE_AUX_SYMBOL)(currentSym + 1) ;
542  if ( currentSym->Value + auxSym->Section.Length >= relativeAddress ) {
543  fileSymbol = latestFileSymbol ;
544  }
545  }
546  }
547 
548 
549  // Look for the function with biggest address <= relativeAddress
550  BOOL isFunction = ISFCN( currentSym->Type ); // Type == 0x20, See WINNT.H
551  if ( isFunction && ( currentSym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL || currentSym->StorageClass == IMAGE_SYM_CLASS_STATIC ) ) {
552 
553  if ( currentSym->Value <= relativeAddress && currentSym->Value > maxFnAddress ) {
554  maxFnAddress = currentSym->Value ;
555  fnSymbol = currentSym ;
556  }
557  }
558 
559  #ifdef DUMPRAM
560  if ( !isFunction && (currentSym->SectionNumber >= 0) ) {
561  if ( (symName[0]=='_' && symName[1]!='$') || (symName[0]=='?') ) {
562 
563  char pretty_module[1024];
564 
565  if ( fileSymbol ) {
566  const char* auxSym = (const char*)(latestFileSymbol + 1) ;
567  char tmpFile[ VA_MAX_FILENAME_LEN ] ;
568  strcpy_s( tmpFile, auxSym ) ;
569  strcpy_s( pretty_module, tmpFile );
570  char *p = pretty_module+strlen(pretty_module)-1;
571  // Move p to point to first letter of EXE filename
572  while( (*p!='\\') && (*p!='/') && (*p!=':') )
573  p--;
574  p++;
575  if ( strlen(p) < 1 ) {
576  strcpy_s( pretty_module, "<unknown>" );
577  } else {
578  memmove( pretty_module, p, strlen(p)+1 );
579  }
580  } else {
581  strcpy_s( pretty_module, "" );
582  }
583 
584  Add_Symbol( currentSym->SectionNumber, currentSym->Value, symName, pretty_module );
585  }
586  }
587  #endif
588 
589  // Advance counters, skip aux symbols
590  i += currentSym->NumberOfAuxSymbols ;
591  currentSym += currentSym->NumberOfAuxSymbols ;
592  currentSym++ ;
593  }
594 
595  #ifdef DUMPRAM
596  DumpSymbols();
597  #endif
598 
599  // dump symbolic info if found
600  if ( fileSymbol ) {
601  const char* auxSym = (const char*)(fileSymbol + 1) ;
602 
603  if( strcmpi( latestFile, auxSym ) ) {
604  strcpy_s( latestFile, auxSym ) ;
605  //JAS dumpBuffer.Printf( " file: %s\r\n", auxSym ) ;
606  }
607  } else {
608  latestFile[ 0 ] = 0 ;
609  //JAS dumpBuffer.Printf( " file: unknown\r\n" ) ;
610  }
611 
612  if ( fnSymbol ) {
613  char tmp_name[1024];
614  unmangle(tmp_name, GetSymbolName( fnSymbol ) );
615  dumpBuffer.Printf( " %s()", tmp_name ) ;
616  if (Dump_to_log) {
617  mprintf((" %s()", tmp_name )) ;
618  }
619  } else {
620  dumpBuffer.Printf( " <unknown>" ) ;
621  if (Dump_to_log) {
622  mprintf((" <unknown>" )) ;
623  }
624  }
625 }
626 
627 
628 PIMAGE_SECTION_HEADER PE_Debug :: SectionHeaderFromName( const char* name )
629  {
630  PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( NT_Header ) ;
631  for( unsigned i = 0; i < NT_Header->FileHeader.NumberOfSections; i++ )
632  {
633  if( strnicmp( (const char*)section->Name, name, IMAGE_SIZEOF_SHORT_NAME ) == 0 )
634  return( section ) ;
635  else
636  section++ ;
637  }
638  return 0;
639  }
640 
641 
642 PIMAGE_COFF_SYMBOLS_HEADER PE_Debug :: GetDebugHeader()
643  {
644  // Some files have a wrong entry in the COFF header, so
645  // first check if the debug info exists at all
646  if( NT_Header->FileHeader.PointerToSymbolTable == 0 )
647  return( 0 ) ;
648  DWORD debugDirRVA = NT_Header->OptionalHeader.
649  DataDirectory[ IMAGE_DIRECTORY_ENTRY_DEBUG ].
650  VirtualAddress;
651  if( debugDirRVA == 0 )
652  return( 0 ) ;
653 
654  // The following values must be calculated differently for MS/Borland files
655  PIMAGE_DEBUG_DIRECTORY debugDir ;
656  DWORD size ;
657 
658  // Borland files have the debug directory at the beginning of a .debug section
659  PIMAGE_SECTION_HEADER debugHeader = SectionHeaderFromName( ".debug" ) ;
660  if( debugHeader && debugHeader->VirtualAddress == debugDirRVA )
661  {
662  debugDir = (PIMAGE_DEBUG_DIRECTORY)(debugHeader->PointerToRawData + (DWORD)fileBase) ;
663  size = NT_Header->OptionalHeader.
664  DataDirectory[ IMAGE_DIRECTORY_ENTRY_DEBUG ].Size *
665  sizeof( IMAGE_DEBUG_DIRECTORY ) ;
666  }
667  else
668  // Microsoft debug directory is in the .rdata section
669  {
670  debugHeader = SectionHeaderFromName( ".rdata" ) ;
671  if( debugHeader == 0 )
672  return( 0 ) ;
673  size = NT_Header->OptionalHeader.
674  DataDirectory[ IMAGE_DIRECTORY_ENTRY_DEBUG ].Size ;
675  DWORD offsetInto_rdata = debugDirRVA - debugHeader->VirtualAddress ;
676  debugDir = BasedPtr( PIMAGE_DEBUG_DIRECTORY, fileBase,
677  debugHeader->PointerToRawData + offsetInto_rdata ) ;
678  }
679 
680  // look for COFF debug info
681  DWORD debugFormats = size / sizeof( IMAGE_DEBUG_DIRECTORY ) ;
682  for( DWORD i = 0; i < debugFormats; i++ )
683  {
684  if( debugDir->Type == IMAGE_DEBUG_TYPE_COFF )
685  return( (PIMAGE_COFF_SYMBOLS_HEADER)((DWORD)fileBase + debugDir->PointerToRawData) ) ;
686  else
687  debugDir++ ;
688  }
689  return( NULL ) ;
690  }
691 
692 
693 void PE_Debug :: FindDebugInfo()
694  {
695  ClearDebugPtrs() ;
696  // Put everything into a try/catch in case the file has wrong fields
697  try
698  {
699  // Verify that fileBase is a valid pointer to a DOS header
700  if( fileBase->e_magic == IMAGE_DOS_SIGNATURE )
701  {
702  // Get a pointer to the PE header
703  NT_Header = BasedPtr( PIMAGE_NT_HEADERS, fileBase, fileBase->e_lfanew ) ;
704  // Verify that NT_Header is a valid pointer to a NT header
705  if( NT_Header->Signature == IMAGE_NT_SIGNATURE )
706  {
707  // Get a pointer to the debug header if any
708  COFFDebugInfo = GetDebugHeader() ;
709  // Get a pointer to the symbol table and retrieve the number of symbols
710  if( NT_Header->FileHeader.PointerToSymbolTable )
711  COFFSymbolTable =
712  BasedPtr( PIMAGE_SYMBOL, fileBase, NT_Header->FileHeader.PointerToSymbolTable ) ;
713  COFFSymbolCount = NT_Header->FileHeader.NumberOfSymbols ;
714  // The string table starts right after the symbol table
715  stringTable = (const char*)(COFFSymbolTable + COFFSymbolCount) ;
716  }
717  }
718  }
719  catch( ... )
720  {
721  // Header wrong, do nothing
722  }
723  }
724 
725 
726 void PE_Debug :: MapFileInMemory( const char* module )
727  {
728  ClearFileCache() ;
729  hFile = CreateFile( module, GENERIC_READ, FILE_SHARE_READ, NULL,
730  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ) ;
731  if( hFile != INVALID_HANDLE_VALUE )
732  {
733  hFileMapping = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL ) ;
734  if( hFileMapping != 0 )
735  fileBase = (PIMAGE_DOS_HEADER)MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0 ) ;
736  }
737  // NB: open files/mapping are closed later in ClearFileCache
738  }
739 
740 
741 int PE_Debug::DumpDebugInfo( DumpBuffer& dumpBuffer, const BYTE* caller, HINSTANCE hInstance )
742 {
743  // Avoid to open, map and looking for debug header/symbol table
744  // by caching the latest and comparing the actual module with
745  // the latest one.
746  static char module[ MAX_MODULENAME_LEN ] ;
747  GetModuleFileName( hInstance, module, MAX_MODULENAME_LEN ) ;
748 
749  // New module
750  if( strcmpi( latestModule, module ) ) {
751  strcpy_s( latestModule, module );
752  //JAS dumpBuffer.Printf( "Module: %s\r\n", module );
753  MapFileInMemory( module );
754  FindDebugInfo();
755  }
756 
757  char pretty_module[1024];
758 
759  strcpy_s( pretty_module, module );
760  char *p = pretty_module+strlen(pretty_module)-1;
761  // Move p to point to first letter of EXE filename
762  while( (*p!='\\') && (*p!='/') && (*p!=':') )
763  p--;
764  p++;
765  if ( strlen(p) < 1 ) {
766  strcpy_s( pretty_module, "<unknown>" );
767  } else {
768  memmove( pretty_module, p, strlen(p)+1 );
769  }
770 
771  if ( fileBase ) {
772  // Put everything into a try/catch in case the file has wrong fields
773  try {
774  DWORD relativeAddress = caller - (BYTE*)hInstance ;
775  // Dump symbolic information and line number if available
776  if( COFFSymbolCount != 0 && COFFSymbolTable != NULL ) {
777  DumpSymbolInfo( dumpBuffer, relativeAddress ) ;
778  if( COFFDebugInfo )
779  DumpLineNumber( dumpBuffer, relativeAddress ) ;
780  return 1;
781  } else {
782  //dumpBuffer.Printf( "Call stack is unavailable, because there is\r\nno COFF debugging info in this module.\r\n" ) ;
783  //JAS dumpBuffer.Printf( " no debug information\r\n" ) ;
784  dumpBuffer.Printf( " %s %08x()\r\n", pretty_module, caller ) ;
785  if (Dump_to_log) {
786  mprintf((" %s %08x()\r\n", pretty_module, caller )) ;
787  }
788  return 0;
789  }
790  } catch( ... ) {
791  // Header wrong, do nothing
792  return 0;
793  }
794  } else {
795  dumpBuffer.Printf( " %s %08x()\r\n", pretty_module, caller ) ;
796  if (Dump_to_log) {
797  mprintf(( " %s %08x()\r\n", pretty_module, caller )) ;
798  }
799  //JAS dumpBuffer.Printf( " module not accessible\r\n" ) ;
800  //JAS dumpBuffer.Printf( " address: %8X\r\n", caller ) ;
801  return 0;
802  }
803 
804  Int3();
805 
806 }
807 
808 void DumpCallsStack( DumpBuffer& dumpBuffer )
809 {
810  static PE_Debug PE_debug ;
811 
812  dumpBuffer.Printf( "\r\nCall stack:\r\n" ) ;
813  dumpBuffer.Printf( Separator ) ;
814 
815  // The structure of the stack frames is the following:
816  // EBP -> parent stack frame EBP
817  // return address for this call ( = caller )
818  // The chain can be navigated iteratively, after the
819  // initial value of EBP is loaded from the register
820  DWORD parentEBP, retval;
821  MEMORY_BASIC_INFORMATION mbi ;
822  HINSTANCE hInstance;
823 
824  int depth = 0;
825 
826  __asm MOV parentEBP, EBP
827 
828  do {
829  depth++;
830  if ( depth > 16 )
831  break;
832 
833  if ( (parentEBP & 3) || IsBadReadPtr((DWORD*)parentEBP, sizeof(DWORD)) ) {
834  break;
835  }
836  parentEBP = *(DWORD*)parentEBP ;
837 
838  BYTE **NextCaller = ((BYTE**)parentEBP + 1);
839 
840  if (IsBadReadPtr(NextCaller, sizeof(BYTE *))) {
841  break;
842  }
843 
844  BYTE* caller = *NextCaller; // Error sometimes!!!
845 
846  // Skip the first EBP as it points to AssertionFailed, which is
847  // uninteresting for the user
848 
849  if ( depth > 1 ) {
850 
851  // Get the instance handle of the module where caller belongs to
852  retval = VirtualQuery( caller, &mbi, sizeof( mbi ) ) ;
853 
854  // The instance handle is equal to the allocation base in Win32
855  hInstance = (HINSTANCE)mbi.AllocationBase ;
856 
857  if( ( retval == sizeof( mbi ) ) && hInstance ) {
858  if ( !PE_debug.DumpDebugInfo( dumpBuffer, caller, hInstance ) ) {
859  //break;
860  }
861  } else {
862  break ; // End of the call chain
863  }
864  }
865  } while( TRUE ) ;
866 
867 
868  dumpBuffer.Printf( Separator ) ;
869  PE_debug.ClearReport() ; // Prepare for future calls
870 }
871 
872 #endif //SHOW_CALL_STACK
873 
874 
875 char AssertText1[2048];
876 char AssertText2[1024];
877 
879 //uint flags = MB_SYSTEMMODAL;
880 
881 extern void gr_force_windowed();
882 
883 void dump_text_to_clipboard( const char *text )
884 {
885  int len = strlen(text)+1024;
886 
887  HGLOBAL h_text = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len );
888  if ( !h_text ) return;
889  char *ptr = (char *)GlobalLock(h_text);
890  if ( !ptr ) return;
891 
892  // copy then, if you find any \n's without \r's, then add in the \r.
893  char last_char = 0;
894  while( *text ) {
895  if ( (*text == '\n') && (last_char != '\r') ) {
896  *ptr++ = '\r';
897  }
898  last_char = *text;
899  *ptr++ = last_char;
900  text++;
901  }
902  *ptr++ = 0;
903  GlobalUnlock(h_text);
904  OpenClipboard(NULL);
905  EmptyClipboard();
906  SetClipboardData(CF_TEXT, h_text);
907  CloseClipboard();
908 }
909 
910 
911 void _cdecl WinAssert(char * text, char * filename, int linenum )
912 {
913  int val;
914 
915  // this stuff migt be really useful for solving bug reports and user errors. We should output it!
916  mprintf(("ASSERTION: \"%s\" at %s:%d\n", text, strrchr(filename, '\\')+1, linenum ));
917 
918 #ifdef Allow_NoWarn
919  if (Cmdline_nowarn) {
920  return;
921  }
922 #endif
923 
924  Messagebox_active = true;
925 
926  gr_activate(0);
927 
928  filename = strrchr(filename, '\\')+1;
929  sprintf( AssertText1, "Assert: %s\r\nFile: %s\r\nLine: %d\r\n", text, filename, linenum );
930 
931 #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
932  /* Dump the callstack */
933  SCP_DebugCallStack callStack;
934  SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) );
935 
936  /* Format the string */
937  SCP_string assertString( AssertText1 );
938  assertString += "\n";
939  assertString += callStack.DumpToString( );
940 
941  /* Copy to the clipboard */
942  dump_text_to_clipboard( assertString.c_str( ) );
943 
944  // truncate text
946 
947  assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n";
948  assertString += "\n\nUse Ok to break into Debugger, Cancel to exit.\n";
949  val = MessageBox( NULL, assertString.c_str( ), "Assertion Failed!", MB_OKCANCEL | flags );
950 
951 #elif defined( SHOW_CALL_STACK )
952  dumpBuffer.Clear();
953  dumpBuffer.Printf( AssertText1 );
954  dumpBuffer.Printf( "\r\n" );
955  DumpCallsStack( dumpBuffer ) ;
956  dump_text_to_clipboard(dumpBuffer.buffer);
957 
958  // truncate text
959  dumpBuffer.TruncateLines(Messagebox_lines);
960 
961  dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" );
962  dumpBuffer.Printf( "\r\n\r\nUse Ok to break into Debugger, Cancel to exit.\r\n");
963 
964  val = MessageBox(NULL, dumpBuffer.buffer, "Assertion Failed!", MB_OKCANCEL|flags );
965 #else
966  val = MessageBox(NULL, AssertText1, "Assertion Failed!", MB_OKCANCEL|flags );
967 #endif
968 
969  if (val == IDCANCEL)
970  exit(1);
971 
972  Int3();
973 
974  gr_activate(1);
975 
976  Messagebox_active = false;
977 }
978 
979 void _cdecl WinAssert(char * text, char * filename, int linenum, const char * format, ... )
980 {
981  int val;
982  va_list args;
983 
984  memset( AssertText1, 0, sizeof(AssertText1) );
985  memset( AssertText2, 0, sizeof(AssertText2) );
986 
987  va_start(args, format);
988  vsnprintf(AssertText2, sizeof(AssertText2)-1, format, args);
989  va_end(args);
990 
991  // this stuff migt be really useful for solving bug reports and user errors. We should output it!
992  mprintf(("ASSERTION: \"%s\" at %s:%d\n %s\n", text, strrchr(filename, '\\')+1, linenum, AssertText2 ));
993 
994 #ifdef Allow_NoWarn
995  if (Cmdline_nowarn) {
996  return;
997  }
998 #endif
999 
1000  Messagebox_active = true;
1001 
1002  gr_activate(0);
1003 
1004  filename = strrchr(filename, '\\')+1;
1005  snprintf( AssertText1, sizeof(AssertText1)-1, "Assert: %s\r\nFile: %s\r\nLine: %d\r\n%s\r\n", text, filename, linenum, AssertText2 );
1006 
1007 #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
1008  /* Dump the callstack */
1009  SCP_DebugCallStack callStack;
1010  SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) );
1011 
1012  /* Format the string */
1013  SCP_string assertString( AssertText1 );
1014  assertString += "\n";
1015  assertString += callStack.DumpToString( );
1016 
1017  /* Copy to the clipboard */
1018  dump_text_to_clipboard( assertString.c_str( ) );
1019 
1020  // truncate text
1022 
1023  assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n";
1024  assertString += "\n\nUse Ok to break into Debugger, Cancel to exit.\n";
1025  val = MessageBox( NULL, assertString.c_str( ), "Assertion Failed!", MB_OKCANCEL | flags );
1026 
1027 #elif defined ( SHOW_CALL_STACK )
1028  dumpBuffer.Clear();
1029  dumpBuffer.Printf( AssertText1 );
1030  dumpBuffer.Printf( "\r\n" );
1031  DumpCallsStack( dumpBuffer ) ;
1032  dump_text_to_clipboard(dumpBuffer.buffer);
1033 
1034  // truncate text
1035  dumpBuffer.TruncateLines(Messagebox_lines);
1036 
1037  dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" );
1038  dumpBuffer.Printf( "\r\n\r\nUse Ok to break into Debugger, Cancel to exit.\r\n");
1039 
1040  val = MessageBox(NULL, dumpBuffer.buffer, "Assertion Failed!", MB_OKCANCEL|flags );
1041 #else
1042  val = MessageBox(NULL, AssertText1, "Assertion Failed!", MB_OKCANCEL|flags );
1043 #endif
1044 
1045  if (val == IDCANCEL)
1046  exit(1);
1047 
1048  Int3();
1049 
1050  gr_activate(1);
1051 
1052  Messagebox_active = false;
1053 }
1054 
1055 void LuaDebugPrint(lua_Debug &ar)
1056 {
1057  dumpBuffer.Printf( "Name:\t\t%s\r\n", ar.name);
1058  dumpBuffer.Printf( "Name of:\t%s\r\n", ar.namewhat);
1059  dumpBuffer.Printf( "Function type:\t%s\r\n", ar.what);
1060  dumpBuffer.Printf( "Defined on:\t%d\r\n", ar.linedefined);
1061  dumpBuffer.Printf( "Upvalues:\t%d\r\n", ar.nups);
1062  dumpBuffer.Printf( "\r\n" );
1063  dumpBuffer.Printf( "Source:\t\t%s\r\n", ar.source);
1064  dumpBuffer.Printf( "Short source:\t%s\r\n", ar.short_src);
1065  dumpBuffer.Printf( "Current line:\t%d\r\n", ar.currentline);
1066  dumpBuffer.Printf( "- Function line:\t%d\r\n", (ar.linedefined ? (1 + ar.currentline - ar.linedefined) : 0));
1067 }
1068 
1069 extern lua_Debug Ade_debug_info;
1070 extern char debug_stack[4][32];
1071 void LuaError(struct lua_State *L, const char *format, ...)
1072 {
1073  int val;
1074 
1075  Messagebox_active = true;
1076 
1077  gr_activate(0);
1078 
1079  dumpBuffer.Clear();
1080  //WMC - if format is set to NULL, assume this is acting as an
1081  //error handler for Lua.
1082  if(format == NULL)
1083  {
1084  dumpBuffer.Printf("LUA ERROR: %s", lua_tostring(L, -1));
1085  lua_pop(L, -1);
1086  }
1087  else
1088  {
1089  va_list args;
1090 
1091  memset(AssertText1, 0, sizeof(AssertText1));
1092  memset(AssertText2, 0, sizeof(AssertText2));
1093 
1094  va_start(args, format);
1095  vsnprintf(AssertText1, sizeof(AssertText1)-1, format,args);
1096  va_end(args);
1097 
1098  dumpBuffer.Printf(AssertText1);
1099  }
1100 
1101  dumpBuffer.Printf( "\r\n" );
1102  dumpBuffer.Printf( "\r\n" );
1103 
1104  //WMC - This is virtually worthless.
1105 /*
1106  dumpBuffer.Printf(Separator);
1107  dumpBuffer.Printf( "LUA Debug:" );
1108  dumpBuffer.Printf( "\r\n" );
1109  dumpBuffer.Printf(Separator);
1110 
1111  lua_Debug ar;
1112  if(lua_getstack(L, 0, &ar))
1113  {
1114  lua_getinfo(L, "nSlu", &ar);
1115  LuaDebugPrint(ar);
1116  }
1117  else
1118  {
1119  dumpBuffer.Printf("(No stack debug info)\r\n");
1120  }
1121 */
1122 // TEST CODE
1123 
1124  dumpBuffer.Printf(Separator);
1125  dumpBuffer.Printf( "ADE Debug:" );
1126  dumpBuffer.Printf( "\r\n" );
1127  dumpBuffer.Printf(Separator);
1128  LuaDebugPrint(Ade_debug_info);
1129  dumpBuffer.Printf(Separator);
1130 
1131  dumpBuffer.Printf( "\r\n" );
1132  dumpBuffer.Printf( "\r\n" );
1133 
1134  AssertText2[0] = '\0';
1135  dumpBuffer.Printf(Separator);
1136 
1137  // Get the stack via the debug.traceback() function
1138  lua_getglobal(L, LUA_DBLIBNAME);
1139 
1140  if (!lua_isnil(L, -1))
1141  {
1142  dumpBuffer.Printf( "\r\n" );
1143  lua_getfield(L, -1, "traceback");
1144  lua_remove(L, -2);
1145 
1146  if (lua_pcall(L, 0, 1, 0) != 0)
1147  dumpBuffer.Printf("Error while retrieving stack: %s", lua_tostring(L, -1));
1148  else
1149  dumpBuffer.Printf(lua_tostring(L, -1));
1150 
1151  lua_pop(L, 1);
1152  }
1153  else
1154  {
1155  // If the debug library is nil then fall back to the default debug stack
1156  dumpBuffer.Printf("LUA Stack:\r\n");
1157  int i;
1158  for (i = 0; i < 4; i++) {
1159  if (debug_stack[i][0] != '\0')
1160  dumpBuffer.Printf("\t%s\r\n", debug_stack[i]);
1161  }
1162  }
1163  dumpBuffer.Printf( "\r\n" );
1164 
1165  dumpBuffer.Printf(Separator);
1166  ade_stackdump(L, AssertText2);
1167  dumpBuffer.Printf( AssertText2 );
1168  dumpBuffer.Printf( "\r\n" );
1169  dumpBuffer.Printf(Separator);
1170 
1171  dump_text_to_clipboard(dumpBuffer.buffer);
1172 
1173  // truncate text
1174  dumpBuffer.TruncateLines(Messagebox_lines);
1175 
1176  dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" );
1177  dumpBuffer.Printf( "\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit");
1178 
1179  val = MessageBox(NULL, dumpBuffer.buffer, "Error!", flags|MB_YESNOCANCEL );
1180 
1181  if (val == IDCANCEL ) {
1182  exit(1);
1183  } else if(val == IDYES) {
1184  Int3();
1185  }
1186 
1187  gr_activate(1);
1188 
1189  Messagebox_active = false;
1190 }
1191 
1192 void _cdecl Error( const char * filename, int line, const char * format, ... )
1193 {
1195 
1196  int val;
1197  va_list args;
1198 
1199  memset( AssertText1, 0, sizeof(AssertText1) );
1200  memset( AssertText2, 0, sizeof(AssertText2) );
1201 
1202  va_start(args, format);
1203  vsnprintf(AssertText1, sizeof(AssertText1)-1, format, args);
1204  va_end(args);
1205 
1206  filename = strrchr(filename, '\\')+1;
1207  snprintf(AssertText2, sizeof(AssertText2)-1, "Error: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line);
1208  mprintf(("ERROR: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line));
1209 
1210  Messagebox_active = true;
1211 
1212  gr_activate(0);
1213 
1214 #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
1215  /* Dump the callstack */
1216  SCP_DebugCallStack callStack;
1217  SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) );
1218 
1219  /* Format the string */
1220  SCP_string assertString( AssertText1 );
1221  assertString += "\n";
1222  assertString += callStack.DumpToString( );
1223 
1224  /* Copy to the clipboard */
1225  dump_text_to_clipboard( assertString.c_str( ) );
1226 
1227  // truncate text
1229 
1230  assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n";
1231  assertString += "\n\nUse Ok to break into Debugger, Cancel to exit.\n";
1232  val = MessageBox( NULL, assertString.c_str( ), "Error!", flags | MB_DEFBUTTON2 | MB_OKCANCEL );
1233 
1234 #elif defined( SHOW_CALL_STACK )
1235  dumpBuffer.Clear();
1236  dumpBuffer.Printf( AssertText2 );
1237  dumpBuffer.Printf( "\r\n" );
1238  DumpCallsStack( dumpBuffer ) ;
1239  dump_text_to_clipboard(dumpBuffer.buffer);
1240 
1241  // truncate text
1242  dumpBuffer.TruncateLines(Messagebox_lines);
1243 
1244  dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" );
1245  dumpBuffer.Printf( "\r\n\r\nUse Ok to break into Debugger, Cancel exits.\r\n");
1246 
1247  val = MessageBox(NULL, dumpBuffer.buffer, "Error!", flags | MB_DEFBUTTON2 | MB_OKCANCEL );
1248 #else
1249  strcat_s(AssertText2,"\r\n\r\nUse Ok to break into Debugger, Cancel exits.\r\n");
1250 
1251  val = MessageBox(NULL, AssertText2, "Error!", flags | MB_DEFBUTTON2 | MB_OKCANCEL );
1252 #endif
1253 
1254  switch (val)
1255  {
1256  case IDCANCEL:
1257  exit(1);
1258 
1259  default:
1260  Int3();
1261  break;
1262  }
1263 
1264  gr_activate(1);
1265 
1266  Messagebox_active = false;
1267 }
1268 
1269 void _cdecl WarningEx( char *filename, int line, const char *format, ... )
1270 {
1271 #ifndef NDEBUG
1272  if (Cmdline_extra_warn) {
1273  char msg[sizeof(AssertText1)];
1274  va_list args;
1275 
1276  memset(msg, 0, sizeof(msg));
1277 
1278  va_start(args, format);
1279  vsnprintf(msg, sizeof(msg)-1, format, args);
1280  va_end(args);
1281 
1282  Warning(filename, line, msg);
1283  }
1284 #endif
1285 }
1286 
1287 void _cdecl Warning( char *filename, int line, const char *format, ... )
1288 {
1290 
1291 #ifndef NDEBUG
1292  va_list args;
1293  int result;
1294  int i;
1295  int slen = 0;
1296 
1297  // output to the debug log before anything else (so that we have a complete record)
1298 
1299  memset( AssertText1, 0, sizeof(AssertText1) );
1300  memset( AssertText2, 0, sizeof(AssertText2) );
1301 
1302  va_start(args, format);
1303  vsnprintf(AssertText1, sizeof(AssertText1) - 1, format, args);
1304  va_end(args);
1305 
1306  slen = strlen(AssertText1);
1307 
1308  // strip out the newline char so the output looks better
1309  for (i = 0; i < slen; i++){
1310  if (AssertText1[i] == (char)0x0a) {
1311  AssertText2[i] = ' ';
1312  } else {
1313  AssertText2[i] = AssertText1[i];
1314  }
1315  }
1316 
1317  // kill off extra white space at end
1318  if (AssertText2[slen-1] == (char)0x20) {
1319  AssertText2[slen-1] = '\0';
1320  } else {
1321  // just being careful
1322  AssertText2[slen] = '\0';
1323  }
1324 
1325  mprintf(("WARNING: \"%s\" at %s:%d\n", AssertText2, strrchr(filename, '\\')+1, line));
1326 
1327  // now go for the additional popup window, if we want it ...
1328 #ifdef Allow_NoWarn
1329  if (Cmdline_nowarn) {
1330  return;
1331  }
1332 #endif
1333 
1334  filename = strrchr(filename, '\\')+1;
1335  sprintf(AssertText2, "Warning: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line );
1336 
1337  Messagebox_active = true;
1338 
1339  gr_activate(0);
1340 
1341 #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
1342  /* Dump the callstack */
1343  SCP_DebugCallStack callStack;
1344  SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) );
1345 
1346  /* Format the string */
1347  SCP_string assertString( AssertText1 );
1348  assertString += "\n";
1349  assertString += callStack.DumpToString( );
1350 
1351  /* Copy to the clipboard */
1352  dump_text_to_clipboard( assertString.c_str( ) );
1353 
1354  // truncate text
1356 
1357  assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n";
1358  assertString += "\n\nUse Yes to break into Debugger, No to continue.\nand Cancel to Quit\n";
1359  result = MessageBox( NULL, assertString.c_str( ), "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags );
1360 
1361 #elif defined ( SHOW_CALL_STACK )
1362  //we don't want to dump the call stack for every single warning
1363  Dump_to_log = false;
1364 
1365  dumpBuffer.Clear();
1366  dumpBuffer.Printf( AssertText2 );
1367  dumpBuffer.Printf( "\r\n" );
1368  DumpCallsStack( dumpBuffer ) ;
1369  dump_text_to_clipboard(dumpBuffer.buffer);
1370 
1371  // truncate text
1372  dumpBuffer.TruncateLines(Messagebox_lines);
1373 
1374  dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" );
1375  dumpBuffer.Printf("\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit");
1376 
1377  result = MessageBox((HWND)os_get_window(), dumpBuffer.buffer, "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags );
1378 
1379  Dump_to_log = true;
1380 
1381 #else
1382  strcat_s(AssertText2,"\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit");
1383  result = MessageBox((HWND)os_get_window(), AssertText2, "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags );
1384 #endif
1385 
1386  switch (result)
1387  {
1388  case IDYES:
1389  Int3();
1390  break;
1391 
1392  case IDNO:
1393  break;
1394 
1395  case IDCANCEL:
1396  exit(1);
1397  }
1398 
1399  gr_activate(1);
1400 
1401  Messagebox_active = false;
1402 #endif // !NDEBUG
1403 }
1404 
1405 //Display warning even in non-devug builds
1406 void _cdecl ReleaseWarning(char *filename, int line, const char *format, ...)
1407 {
1409 
1410  va_list args;
1411  int result;
1412  int i;
1413  int slen = 0;
1414 
1415  // output to the debug log before anything else (so that we have a complete record)
1416 
1417  memset(AssertText1, 0, sizeof(AssertText1));
1418  memset(AssertText2, 0, sizeof(AssertText2));
1419 
1420  va_start(args, format);
1421  vsnprintf(AssertText1, sizeof(AssertText1) - 1, format, args);
1422  va_end(args);
1423 
1424  slen = strlen(AssertText1);
1425 
1426  // strip out the newline char so the output looks better
1427  for (i = 0; i < slen; i++) {
1428  if (AssertText1[i] == (char)0x0a) {
1429  AssertText2[i] = ' ';
1430  }
1431  else {
1432  AssertText2[i] = AssertText1[i];
1433  }
1434  }
1435 
1436  // kill off extra white space at end
1437  if (AssertText2[slen - 1] == (char)0x20) {
1438  AssertText2[slen - 1] = '\0';
1439  }
1440  else {
1441  // just being careful
1442  AssertText2[slen] = '\0';
1443  }
1444 
1445  mprintf(("WARNING: \"%s\" at %s:%d\n", AssertText2, strrchr(filename, '\\') + 1, line));
1446 
1447  // now go for the additional popup window, if we want it ...
1448 #ifdef Allow_NoWarn
1449  if (Cmdline_nowarn) {
1450  return;
1451  }
1452 #endif
1453 
1454  filename = strrchr(filename, '\\') + 1;
1455  sprintf(AssertText2, "Warning: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line);
1456 
1457  Messagebox_active = true;
1458 
1459  gr_activate(0);
1460 
1461 #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
1462  /* Dump the callstack */
1463  SCP_DebugCallStack callStack;
1464  SCP_DumpStack(dynamic_cast< SCP_IDumpHandler* >(&callStack));
1465 
1466  /* Format the string */
1467  SCP_string assertString(AssertText1);
1468  assertString += "\n";
1469  assertString += callStack.DumpToString();
1470 
1471  /* Copy to the clipboard */
1472  dump_text_to_clipboard(assertString.c_str());
1473 
1474  // truncate text
1476 
1477  assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n";
1478  assertString += "\n\nUse Yes to break into Debugger, No to continue.\nand Cancel to Quit\n";
1479  result = MessageBox(NULL, assertString.c_str(), "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags);
1480 
1481 #elif defined ( SHOW_CALL_STACK )
1482  //we don't want to dump the call stack for every single warning
1483  Dump_to_log = false;
1484 
1485  dumpBuffer.Clear();
1486  dumpBuffer.Printf(AssertText2);
1487  dumpBuffer.Printf("\r\n");
1488  DumpCallsStack(dumpBuffer);
1489  dump_text_to_clipboard(dumpBuffer.buffer);
1490 
1491  // truncate text
1492  dumpBuffer.TruncateLines(Messagebox_lines);
1493 
1494  dumpBuffer.Printf("\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n");
1495  dumpBuffer.Printf("\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit");
1496 
1497  result = MessageBox((HWND)os_get_window(), dumpBuffer.buffer, "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags);
1498 
1499  Dump_to_log = true;
1500 
1501 #else
1502  strcat_s(AssertText2, "\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit");
1503  result = MessageBox((HWND)os_get_window(), AssertText2, "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags);
1504 #endif
1505 
1506  switch (result)
1507  {
1508  case IDYES:
1509  Int3();
1510  break;
1511 
1512  case IDNO:
1513  break;
1514 
1515  case IDCANCEL:
1516  exit(1);
1517  }
1518 
1519  gr_activate(1);
1520 
1521  Messagebox_active = false;
1522 }
1523 
1524 
1525 //================= memory stuff
1526 /*
1527 char *format_mem( DWORD num )
1528 {
1529  if ( num < 1024 ) {
1530  sprintf( tmp_mem, "%d bytes", num );
1531  } else if ( num < 1024*1024 ) {
1532  sprintf( tmp_mem, "%.3f KB", (float)num/1024.0f );
1533  } else {
1534  sprintf( tmp_mem, "%.3f MB", (float)(num/1024)/(1024.0f) );
1535  }
1536  return tmp_mem;
1537 }
1538 */
1539 
1540 /*
1541 void getmem()
1542 {
1543  DWORD retval;
1544  MEMORY_BASIC_INFORMATION mbi ;
1545  HINSTANCE hInstance;
1546 
1547  MEMORYSTATUS ms;
1548 
1549  ms.dwLength = sizeof(MEMORYSTATUS);
1550  GlobalMemoryStatus(&ms);
1551 
1552  printf( "Percent of memory in use: %d%%\n", ms.dwMemoryLoad );
1553  printf( "Bytes of physical memory: %s\n", format_mem(ms.dwTotalPhys) );
1554  printf( "Free physical memory bytes: %s\n", format_mem(ms.dwAvailPhys) ); //
1555  printf( "Bytes of paging file: %s\n", format_mem(ms.dwTotalPageFile) ); // bytes of paging file
1556  printf( "Free bytes of paging file: %s\n", format_mem(ms.dwAvailPageFile) ); // free bytes of paging file
1557  printf( "User bytes of address space: %s\n", format_mem(ms.dwTotalVirtual) ); //
1558  printf( "Free user bytes: %s\n", format_mem(ms.dwAvailVirtual) ); // free user bytes
1559 
1560 
1561  // Get the instance handle of the module where caller belongs to
1562  retval = VirtualQuery( getmem, &mbi, sizeof( mbi ) ) ;
1563 
1564  // The instance handle is equal to the allocation base in Win32
1565  hInstance = (HINSTANCE)mbi.AllocationBase ;
1566 
1567  if( ( retval == sizeof( mbi ) ) && hInstance ) {
1568  printf( "Virtual Query succeeded...\n" );
1569  } else {
1570  printf( "Virtual Query failed...\n" );
1571  }
1572 
1573 }
1574 */
1575 
1576 
1577 
1578 #ifndef NDEBUG
1579 
1580 int TotalRam = 0;
1581 #define nNoMansLandSize 4
1582 
1583 typedef struct _CrtMemBlockHeader
1584 {
1587  char * szFileName;
1588  int nLine;
1589  size_t nDataSize;
1591  long lRequest;
1592  unsigned char gap[nNoMansLandSize];
1593  /* followed by:
1594  * unsigned char data[nDataSize];
1595  * unsigned char anotherGap[nNoMansLandSize];
1596  */
1598 
1599 #define pHdr(pbData) (((_CrtMemBlockHeader *)pbData)-1)
1600 
1601 
1602 // this block of code is never referenced...
1603 #if 0
1604 int __cdecl MyAllocHook(
1605  int nAllocType,
1606  void * pvData,
1607  size_t nSize,
1608  int nBlockUse,
1609  long lRequest,
1610  const char * szFileName,
1611  int nLine
1612  )
1613 {
1614  // char *operation[] = { "", "allocating", "re-allocating", "freeing" };
1615  // char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };
1616 
1617  if ( nBlockUse == _CRT_BLOCK ) // Ignore internal C runtime library allocations
1618  return( TRUE );
1619 
1620  _ASSERT( ( nAllocType > 0 ) && ( nAllocType < 4 ) );
1621  _ASSERT( ( nBlockUse >= 0 ) && ( nBlockUse < 5 ) );
1622 
1623  if ( nAllocType == 3 ) {
1624  _CrtMemBlockHeader *phd = pHdr(pvData);
1625  nSize = phd->nDataSize;
1626  }
1627 
1628 // mprintf(( "Total RAM = %d\n", TotalRam ));
1629 
1630  mprintf(( "Memory operation in %s, line %d: %s a %d-byte '%s' block (# %ld)\n",
1631  szFileName, nLine, operation[nAllocType], nSize,
1632  blockType[nBlockUse], lRequest ));
1633  if ( pvData != NULL )
1634  mprintf(( " at %X", pvData ));
1635 
1636  mprintf(("\n" ));
1637 
1638 
1639  return( TRUE ); // Allow the memory operation to proceed
1640 }
1641 #endif // #if 0
1642 
1643 
1644 
1646 {
1647  //_CrtSetAllocHook(MyAllocHook);
1648  TotalRam = 0;
1649 }
1650 
1651 #endif
1652 
1654 DCF_BOOL(watch_malloc, Watch_malloc );
1655 
1656 // Returns 0 if not enough RAM.
1657 int vm_init(int min_heap_size)
1658 {
1659  #ifndef NDEBUG
1660  TotalRam = 0;
1661  #endif
1662 
1663  return 1;
1664 }
1665 
1666 
1667 #ifdef _DEBUG
1668 
1669 #ifdef _REPORT_MEM_LEAKS
1670 const int MAX_MEM_POINTERS = 50000;
1671 
1672 typedef struct
1673 {
1674  char filename[33];
1675  int size;
1676  int line;
1677  void *ptr;
1678 } MemPtrInfo;
1679 
1680 MemPtrInfo mem_ptr_list[MAX_MEM_POINTERS];
1681 
1682 #endif
1683 
1684 const int MAX_MEM_MODULES = 600;
1685 
1686 typedef struct
1687 {
1688  char filename[33];
1689  int size;
1690  int magic_num1;
1691  int magic_num2;
1692  bool in_use;
1693 
1694 } MemBlockInfo;
1695 
1696 MemBlockInfo mem_block_list[MAX_MEM_MODULES];
1697 
1698 int memblockinfo_sort_compare( const void *arg1, const void *arg2 )
1699 {
1700  MemBlockInfo *mbi1 = (MemBlockInfo *) arg1;
1701  MemBlockInfo *mbi2 = (MemBlockInfo *) arg2;
1702 
1703  if (mbi1->size > mbi2->size)
1704  return -1;
1705 
1706  if (mbi1->size < mbi2->size)
1707  return 1;
1708 
1709  return 0;
1710 }
1711 
1712 void memblockinfo_sort()
1713 {
1714  insertion_sort(mem_block_list, MAX_MEM_MODULES, sizeof(MemBlockInfo), memblockinfo_sort_compare );
1715 }
1716 
1717 void memblockinfo_sort_get_entry(int index, char *filename, int *size)
1718 {
1719  Assert(index < MAX_MEM_MODULES);
1720 
1721  strcpy(filename, mem_block_list[index].filename);
1722  *size = mem_block_list[index].size;
1723 }
1724 
1725 static bool first_time = true;
1726 
1727 void register_malloc( int size, char *filename, int line, void *ptr)
1728 {
1729  if(first_time == true)
1730  {
1731  ZeroMemory(mem_block_list, MAX_MEM_MODULES * sizeof(MemBlockInfo) );
1732  first_time = false;
1733 
1734  // Get current flag
1735  int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
1736 
1737  // Turn on leak-checking bit
1738  tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
1739 
1740  // Set flag to the new value
1741  _CrtSetDbgFlag( tmpFlag );
1742 
1743 #ifdef _REPORT_MEM_LEAKS
1744  ZeroMemory(mem_ptr_list, MAX_MEM_POINTERS * sizeof(MemPtrInfo));
1745 #endif
1746  }
1747 
1748  char *temp = strrchr(filename, '\\');
1749  if(temp)
1750  filename = temp + 1;
1751 
1752  // calculate magic numbers
1753  int magic1, magic2, len = strlen(filename);
1754 
1755  magic1 = magic2 = 0;
1756 
1757  for(int c = 0; c < len; c++)
1758  {
1759  magic1 += filename[c];
1760 
1761  if(c % 2)
1762  magic2 += filename[c];
1763  else
1764  magic2 -= filename[c];
1765  }
1766 
1767  for(int i = 0; i < MAX_MEM_MODULES; i++)
1768  {
1769  // Found the first empty entry, fill it
1770  if(mem_block_list[i].in_use == false)
1771  {
1772  strcpy_s(mem_block_list[i].filename, filename);
1773  mem_block_list[i].size = size;
1774  mem_block_list[i].magic_num1 = magic1;
1775  mem_block_list[i].magic_num2 = magic2;
1776  mem_block_list[i].in_use = true;
1777  break;
1778  }
1779 
1780  // Found a matching entry, update it
1781  if( mem_block_list[i].magic_num1 == magic1 &&
1782  mem_block_list[i].magic_num2 == magic2 &&
1783  stricmp(mem_block_list[i].filename, filename) == 0)
1784  {
1785  mem_block_list[i].size += size;
1786  break;
1787  }
1788  }
1789 
1790  // Now if system is compiled register it with the fuller system
1791  #ifdef _REPORT_MEM_LEAKS
1792 
1793  // Find empty slot
1794  int count = 0;
1795  while(mem_ptr_list[count].ptr != NULL)
1796  {
1797  count++;
1798  // If you hit this just increase MAX_MEM_POINTERS
1799  Assert(count < MAX_MEM_POINTERS);
1800  }
1801  mem_ptr_list[count].ptr = ptr;
1802  mem_ptr_list[count].line = line;
1803  mem_ptr_list[count].size = size;
1804  strcpy_s(mem_ptr_list[count].filename, filename);
1805 
1806  #endif
1807 }
1808 
1809 void memblockinfo_output_memleak()
1810 {
1811  if(!Cmdline_show_mem_usage) return;
1812 
1813  if(TotalRam == 0)
1814  return;
1815 
1816  if(TotalRam < 0) {
1817  _RPT1(_CRT_WARN, "TotalRam bad value!",TotalRam);
1818  return;
1819  }
1820 
1821  _RPT1(_CRT_WARN, "malloc memory leak of %d\n",TotalRam);
1822 
1823 // Now if system is compiled register it with the fuller system
1824 #ifdef _REPORT_MEM_LEAKS
1825 
1826  int total = 0;
1827  // Find empty slot
1828  for(int f = 0; f < MAX_MEM_POINTERS; f++)
1829  {
1830  if(mem_ptr_list[f].ptr)
1831  {
1832  _RPT3(_CRT_WARN, "Memory leaks: (%s line %d) of %d bytes\n", mem_ptr_list[f].filename, mem_ptr_list[f].line, mem_ptr_list[f].size);
1833  total += mem_ptr_list[f].size;
1834  }
1835  }
1836 
1837  Assert(TotalRam == total);
1838 
1839 #else
1840 
1841  for(int i = 0; i < MAX_MEM_MODULES; i++)
1842  {
1843  // Found the first empty entry, fill it
1844  if(mem_block_list[i].size > 0)
1845  {
1846  // Oh... bad code... making assumsions...
1847  _RPT2(_CRT_WARN, "Possible memory leaks: %s %d\n", mem_block_list[i].filename, mem_block_list[i].size);
1848  }
1849  }
1850 #endif
1851 }
1852 
1853 void unregister_malloc(char *filename, int size, void *ptr)
1854 {
1855  // calculate magic numbers
1856  int magic1, magic2, len;
1857 
1858  char *temp = strrchr(filename, '\\');
1859  if(temp)
1860  filename = temp + 1;
1861 
1862  len = strlen(filename);
1863 
1864  magic1 = magic2 = 0;
1865 
1866  for(int c = 0; c < len; c++)
1867  {
1868  magic1 += filename[c];
1869 
1870  if(c % 2)
1871  magic2 += filename[c];
1872  else
1873  magic2 -= filename[c];
1874  }
1875 
1876 // Now if system is compiled register it with the fuller system
1877 #ifdef _REPORT_MEM_LEAKS
1878 
1879  // Find empty slot
1880  for(int f = 0; f < MAX_MEM_POINTERS; f++)
1881  {
1882  if(mem_ptr_list[f].ptr == ptr) {
1883  mem_ptr_list[f].ptr = NULL;
1884  break;
1885  }
1886  }
1887 
1888 #endif
1889 
1890  for(int i = 0; i < MAX_MEM_MODULES; i++)
1891  {
1892  // Found a matching entry, update it
1893  if( mem_block_list[i].magic_num1 == magic1 &&
1894  mem_block_list[i].magic_num2 == magic2 &&
1895  stricmp(mem_block_list[i].filename, filename) == 0)
1896  {
1897  mem_block_list[i].size -= size;
1898  return;
1899  }
1900  }
1901 }
1902 
1903 #endif
1904 
1905 #ifndef NDEBUG
1906 void *_vm_malloc( int size, char *filename, int line, int quiet )
1907 #else
1908 void *_vm_malloc( int size, int quiet )
1909 #endif
1910 {
1911  void *ptr = NULL;
1912 
1913  ptr = _malloc_dbg(size, _NORMAL_BLOCK, __FILE__, __LINE__ );
1914 
1915  if (ptr == NULL)
1916  {
1917  mprintf(( "Malloc failed!!!!!!!!!!!!!!!!!!!\n" ));
1918 
1919  if (quiet) {
1920  return NULL;
1921  }
1922 
1923  Error(LOCATION, "Malloc Failed!\n");
1924  }
1925 #ifndef NDEBUG
1926  TotalRam += size;
1927 
1929  register_malloc(size, filename, line, ptr);
1930 #endif
1931  return ptr;
1932 }
1933 
1934 #ifndef NDEBUG
1935 char *_vm_strdup( const char *ptr, char *filename, int line )
1936 #else
1937 char *_vm_strdup( const char *ptr )
1938 #endif
1939 {
1940  char *dst;
1941  int len = strlen(ptr);
1942 
1943  dst = (char *)vm_malloc( len+1 );
1944 
1945  if (!dst)
1946  return NULL;
1947 
1948  strcpy_s( dst, len + 1, ptr );
1949  return dst;
1950 }
1951 
1952 #ifndef NDEBUG
1953 char *_vm_strndup( const char *ptr, int size, char *filename, int line )
1954 #else
1955 char *_vm_strndup( const char *ptr, int size )
1956 #endif
1957 {
1958  char *dst;
1959 
1960  dst = (char *)vm_malloc( size+1 );
1961 
1962  if (!dst)
1963  return NULL;
1964 
1965  strncpy( dst, ptr, size );
1966  // make sure it has a NULL terminiator
1967  dst[size] = '\0';
1968 
1969  return dst;
1970 }
1971 
1972 #ifndef NDEBUG
1973 void _vm_free( void *ptr, char *filename, int line )
1974 #else
1975 void _vm_free( void *ptr )
1976 #endif
1977 {
1978  if ( !ptr ) {
1979  return;
1980  }
1981 
1982 
1983 
1984 #ifndef NDEBUG
1985  _CrtMemBlockHeader *phd = pHdr(ptr);
1986  int nSize = phd->nDataSize;
1987 
1988  TotalRam -= nSize;
1990  unregister_malloc(filename, nSize, ptr);
1991 #endif
1992 
1993  _free_dbg(ptr,_NORMAL_BLOCK);
1994 }
1995 
1997 {
1998 }
1999 
2000 #ifndef NDEBUG
2001 void *_vm_realloc( void *ptr, int size, char *filename, int line, int quiet )
2002 #else
2003 void *_vm_realloc( void *ptr, int size, int quiet )
2004 #endif
2005 {
2006  // if this is the first time it's used then we need to malloc it first
2007  if ( ptr == NULL )
2008  return vm_malloc(size);
2009 
2010  void *ret_ptr = NULL;
2011 
2012 #ifndef NDEBUG
2013  // Unregistered the previous allocation
2014  _CrtMemBlockHeader *phd = pHdr(ptr);
2015  int nSize = phd->nDataSize;
2016 
2017  TotalRam -= nSize;
2019  unregister_malloc(filename, nSize, ptr);
2020 #endif
2021 
2022  ret_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, __FILE__, __LINE__ );
2023 
2024  if (ret_ptr == NULL) {
2025  mprintf(( "realloc failed!!!!!!!!!!!!!!!!!!!\n" ));
2026 
2027  if (quiet && (size > 0) && (ptr != NULL)) {
2028  // realloc doesn't touch the original ptr in the case of failure so we could still use it
2029  return NULL;
2030  }
2031 
2032  Error(LOCATION, "Out of memory. Try closing down other applications, increasing your\n"
2033  "virtual memory size, or installing more physical RAM.\n");
2034  }
2035 #ifndef NDEBUG
2036  TotalRam += size;
2037 
2038  // register this allocation
2040  register_malloc(size, filename, line, ret_ptr);
2041 #endif
2042  return ret_ptr;
2043 }
GLenum GLsizei GLenum format
Definition: Gl.h:1509
GLuint64EXT * result
Definition: Glext.h:10775
#define MB_OKCANCEL
Definition: config.h:180
const char * clean_filename(const char *name)
Definition: windebug.cpp:60
GLuint GLuint GLuint GLuint arg1
Definition: Glext.h:8984
void * HWND
Definition: config.h:104
void * _vm_malloc(int size, char *filename, int line, int quiet)
Definition: windebug.cpp:1906
int i
Definition: multi_pxo.cpp:466
#define vm_free(ptr)
Definition: pstypes.h:548
struct _CrtMemBlockHeader _CrtMemBlockHeader
char * _vm_strndup(const char *ptr, int size, char *filename, int line)
Definition: windebug.cpp:1953
char * _vm_strdup(const char *ptr, char *filename, int line)
Definition: windebug.cpp:1935
void gr_force_windowed()
Definition: 2d.cpp:1101
GLuint index
Definition: Glext.h:5608
#define __cdecl
Definition: config.h:72
int Global_error_count
Definition: windebug.cpp:47
void * _vm_realloc(void *ptr, int size, char *filename, int line, int quiet)
Definition: windebug.cpp:2001
Assert(pm!=NULL)
void * HINSTANCE
Definition: config.h:105
GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg2
Definition: Glext.h:8985
void _vm_free(void *ptr, char *filename, int line)
Definition: windebug.cpp:1973
#define mprintf(args)
Definition: pstypes.h:238
GLint GLint GLsizei GLsizei GLsizei depth
Definition: Glext.h:5180
DCF_BOOL(watch_malloc, Watch_malloc)
GLclampf f
Definition: Glext.h:7097
#define TRUE
Definition: pstypes.h:399
#define MB_YESNOCANCEL
Definition: config.h:183
struct _CrtMemBlockHeader * pBlockHeaderNext
Definition: windebug.cpp:1585
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
GLsizeiptr size
Definition: Glext.h:5496
#define Int3()
Definition: pstypes.h:292
void vm_free_all()
Definition: windebug.cpp:1996
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
long LPARAM
Definition: config.h:101
int Cmdline_show_mem_usage
Definition: cmdline.cpp:497
struct _CrtMemBlockHeader * pBlockHeaderPrev
Definition: windebug.cpp:1586
uint os_get_window()
Definition: osapi.cpp:208
void _cdecl Error(const char *filename, int line, const char *format,...)
Definition: windebug.cpp:1192
GLintptr offset
Definition: Glext.h:5497
const int Messagebox_lines
Definition: windebug.cpp:49
unsigned int uint
Definition: pstypes.h:64
GLenum GLenum dst
Definition: Glext.h:5917
void gr_activate(int active)
Definition: 2d.cpp:1122
#define MB_DEFBUTTON2
Definition: config.h:193
char debug_stack[4][32]
Definition: lua.cpp:15808
char * filename
#define strnicmp(s1, s2, n)
Definition: config.h:272
#define nNoMansLandSize
Definition: windebug.cpp:1581
#define pHdr(pbData)
Definition: windebug.cpp:1599
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
GLuint buffer
Definition: Glext.h:5492
#define MB_SYSTEMMODAL
Definition: config.h:197
void insertion_sort(void *array_base, size_t array_size, size_t element_size, int(*fncompare)(const void *, const void *))
Definition: systemvars.cpp:599
bool Messagebox_active
Definition: windebug.cpp:44
unsigned long DWORD
Definition: config.h:90
cfbp fp
Definition: cfile.cpp:1065
#define MB_ICONWARNING
Definition: config.h:185
void truncate_message_lines(SCP_string &text, int num_allowed_lines)
Definition: parselo.cpp:4154
void LuaDebugPrint(lua_Debug &ar)
Definition: windebug.cpp:1055
GLbitfield flags
Definition: Glext.h:6722
#define vm_malloc(size)
Definition: pstypes.h:547
GLuint const GLchar * name
Definition: Glext.h:5608
int TotalRam
Definition: windebug.cpp:1580
GLuint GLfloat * val
Definition: Glext.h:6741
int BOOL
Definition: config.h:80
HWND hWnd
Definition: vddraw.h:425
void ade_stackdump(lua_State *L, char *stackdump)
Definition: lua.cpp:15953
void _cdecl WarningEx(char *filename, int line, const char *format,...)
Definition: windebug.cpp:1269
void dump_text_to_clipboard(const char *text)
Definition: windebug.cpp:883
#define strcat_s(...)
Definition: safe_strings.h:68
void _cdecl Warning(char *filename, int line, const char *format,...)
Definition: windebug.cpp:1287
int vm_init(int min_heap_size)
Definition: windebug.cpp:1657
void windebug_memwatch_init()
Definition: windebug.cpp:1645
#define MB_SETFOREGROUND
Definition: config.h:202
GLfloat GLfloat p
Definition: Glext.h:8373
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
GLenum src
Definition: Glext.h:5917
#define LOCATION
Definition: pstypes.h:245
void _cdecl WinAssert(char *text, char *filename, int linenum)
Definition: windebug.cpp:911
int MessageBox(HWND h, const char *s1, const char *s2, int i)
uint flags
Definition: windebug.cpp:878
int Watch_malloc
Definition: windebug.cpp:1653
hull_check pos
Definition: lua.cpp:5050
void LuaError(struct lua_State *L, const char *format,...)
Definition: windebug.cpp:1071
GLint GLsizei count
Definition: Gl.h:1491
GLenum GLsizei len
Definition: Glext.h:6283
int temp
Definition: lua.cpp:4996
#define _ASSERT(expr)
Definition: windebug.cpp:53
void * HANDLE
Definition: config.h:106
char AssertText2[1024]
Definition: windebug.cpp:876
int Global_warning_count
Definition: windebug.cpp:46
void _cdecl ReleaseWarning(char *filename, int line, const char *format,...)
Definition: windebug.cpp:1406
unsigned char gap[nNoMansLandSize]
Definition: windebug.cpp:1592
#define _cdecl
Definition: config.h:71
#define stricmp(s1, s2)
Definition: config.h:271
int Cmdline_extra_warn
Definition: cmdline.cpp:496
GLuint address
Definition: Glext.h:8864
const GLubyte * c
Definition: Glext.h:8376
lua_Debug Ade_debug_info
Definition: lua.cpp:15807
char AssertText1[2048]
Definition: windebug.cpp:875
#define strcpy_s(...)
Definition: safe_strings.h:67