]> de.git.xonotic.org Git - voretournament/voretournament.git/blobdiff - misc/mediasource/netradiant-src/radiant/stacktrace.cpp
Move the netradiant and fteqcc sources
[voretournament/voretournament.git] / misc / mediasource / netradiant-src / radiant / stacktrace.cpp
diff --git a/misc/mediasource/netradiant-src/radiant/stacktrace.cpp b/misc/mediasource/netradiant-src/radiant/stacktrace.cpp
new file mode 100644 (file)
index 0000000..18a7046
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+Copyright (C) 2001-2006, William Joseph.
+All Rights Reserved.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "stacktrace.h"
+#include "stream/textstream.h"
+
+#include "environment.h"
+
+#ifdef __linux__
+#include <execinfo.h>
+
+void write_stack_trace(TextOutputStream& outputStream)
+{
+  const unsigned int MAX_SYMBOLS = 256;
+  void* symbols[MAX_SYMBOLS];
+    
+  // get return addresses
+  int symbol_count = backtrace(symbols, MAX_SYMBOLS);
+  
+  if(!symbol_count)
+       return;
+  
+  // resolve and print names
+  char** symbol_names = backtrace_symbols(symbols, symbol_count);      
+  if(symbol_names)
+  {
+     for(int i = 0; (i < symbol_count); ++i)
+        outputStream << symbol_names[i] << "\n";
+        
+     // not a memleak, see www.gnu.org/software/libc/manual (Debugging Support, Backtraces)
+     free(symbol_names);
+  }
+}      
+#elif defined (WIN32) && defined (_MSC_VER)
+
+#include "windows.h"
+#include "winnt.h"
+#include "dbghelp.h"
+
+class Address
+{
+public:
+  void* m_value;
+  Address(void* value) : m_value(value)
+  {
+  }
+};
+
+/// \brief Writes an address \p p to \p ostream in hexadecimal form.
+template<typename TextOutputStreamType>
+inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const Address& p)
+{
+  const std::size_t bufferSize = (sizeof(void*) * 2) + 1;
+  char buf[bufferSize];
+  ostream.write(buf, snprintf(buf, bufferSize, "%0p", p.m_value));
+  return ostream;
+}
+
+class Offset
+{
+public:
+  void* m_value;
+  Offset(void* value) : m_value(value)
+  {
+  }
+};
+
+/// \brief Writes an address \p p to \p ostream in hexadecimal form.
+template<typename TextOutputStreamType>
+inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const Offset& p)
+{
+  const std::size_t bufferSize = (sizeof(void*) * 2) + 1;
+  char buf[bufferSize];
+  ostream.write(buf, snprintf(buf, bufferSize, "%X", p.m_value));
+  return ostream;
+}
+
+/// \brief Writes a WCHAR string \p s to \p ostream.
+template<typename TextOutputStreamType>
+inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const WCHAR* s)
+{
+  const std::size_t bufferSize = 1024;
+  char buf[bufferSize];
+  ostream.write(buf, snprintf(buf, bufferSize, "%ls", s));
+  return ostream;
+}
+
+struct EnumerateSymbolsContext
+{
+  STACKFRAME64& sf;
+  TextOutputStream& outputStream;
+  std::size_t count;
+  EnumerateSymbolsContext(STACKFRAME64& sf, TextOutputStream& outputStream) : sf(sf), outputStream(outputStream), count(0)
+  {
+  }
+};
+
+void write_symbol(PSYMBOL_INFO pSym, STACKFRAME64& sf, TextOutputStream& outputStream, std::size_t& count)
+{
+#if 0
+ if ( pSym->Flags & SYMFLAG_PARAMETER )
+ {
+
+    DWORD basicType;
+    if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex,
+                        TI_GET_BASETYPE, &basicType ) )
+    {
+      int bleh = 0;
+    }
+    else
+    {
+      DWORD typeId;
+      if(SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex,
+                      TI_GET_TYPEID, &typeId ))
+      {
+        if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex,
+                            TI_GET_BASETYPE, &basicType ) )
+        {
+          int bleh = 0;
+        }
+        else
+        {
+          const char* FormatGetLastError();
+          const char* error = FormatGetLastError();
+          int bleh = 0;
+
+          WCHAR* name;
+          if(SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, typeId,
+                          TI_GET_SYMNAME, &name ))
+          {
+            outputStream << name << " ";
+            LocalFree(name);
+            int bleh = 0;
+          }
+          else
+          {
+            const char* FormatGetLastError();
+            const char* error = FormatGetLastError();
+            int bleh = 0;
+          }
+        }
+      }
+      else
+      {
+        const char* FormatGetLastError();
+        const char* error = FormatGetLastError();
+        int bleh = 0;
+      }
+    }
+    if(count != 0)
+    {
+      outputStream << ", ";
+    }
+    outputStream << pSym->Name;
+    ++count;
+  }
+#endif
+}
+
+BOOL CALLBACK
+EnumerateSymbolsCallback(
+    PSYMBOL_INFO  pSymInfo,
+    ULONG         SymbolSize,
+    PVOID         UserContext )
+{
+  write_symbol( pSymInfo, ((EnumerateSymbolsContext*)UserContext)->sf, ((EnumerateSymbolsContext*)UserContext)->outputStream, ((EnumerateSymbolsContext*)UserContext)->count);
+
+
+  return TRUE;
+}
+
+void write_stack_trace(PCONTEXT pContext, TextOutputStream& outputStream)
+{
+  HANDLE m_hProcess = GetCurrentProcess();
+  DWORD dwMachineType = 0;
+
+  CONTEXT context = *pContext;
+
+  // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
+  if ( !SymInitialize( m_hProcess, (PSTR)environment_get_app_path(), TRUE ) )
+  {
+    return;
+  }
+
+  STACKFRAME64 sf;
+  memset( &sf, 0, sizeof(sf) );
+  sf.AddrPC.Mode         = AddrModeFlat;
+  sf.AddrStack.Mode      = AddrModeFlat;
+  sf.AddrFrame.Mode      = AddrModeFlat;
+  
+#ifdef _M_IX86
+  // Initialize the STACKFRAME structure for the first call.  This is only
+  // necessary for Intel CPUs, and isn't mentioned in the documentation.
+  sf.AddrPC.Offset       = context.Eip;
+  sf.AddrStack.Offset    = context.Esp;
+  sf.AddrFrame.Offset    = context.Ebp;
+  
+  dwMachineType = IMAGE_FILE_MACHINE_I386;
+#elif _M_X64
+  sf.AddrPC.Offset       = context.Rip;
+  sf.AddrStack.Offset    = context.Rsp;
+  
+  // MSDN: x64:  The frame pointer is RBP or RDI. This value is not always used.
+  // very funny, we'll try Rdi for now
+  sf.AddrFrame.Offset    = context.Rdi;
+  
+  dwMachineType = IMAGE_FILE_MACHINE_AMD64;
+#endif
+
+  const unsigned int max_sym_name = 1024;// should be enough
+
+  while ( 1 )
+  {
+    // Get the next stack frame
+    if ( ! StackWalk64( dwMachineType,
+                        m_hProcess,
+                        GetCurrentThread(),
+                        &sf,
+                        &context,
+                        0,
+                        SymFunctionTableAccess64,
+                        SymGetModuleBase64,
+                        0 ) )
+        break;
+
+    if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure
+      break;                      // the frame is OK.  Bail if not.
+
+    // Get the name of the function for this stack frame entry
+    BYTE symbolBuffer[ sizeof(SYMBOL_INFO) + max_sym_name ];
+    PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
+    pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+    pSymbol->MaxNameLen = max_sym_name;
+                    
+    DWORD64 symDisplacement = 0;    // Displacement of the input address,
+                                    // relative to the start of the symbol
+
+    IMAGEHLP_MODULE64 module = { sizeof(IMAGEHLP_MODULE64) };
+    if(SymGetModuleInfo64(m_hProcess, sf.AddrPC.Offset, &module))
+    {
+      outputStream << module.ModuleName << "!";
+
+      if ( SymFromAddr(m_hProcess, sf.AddrPC.Offset, &symDisplacement, pSymbol))
+      {
+        char undecoratedName[max_sym_name];
+        UnDecorateSymbolName(pSymbol->Name, undecoratedName, max_sym_name, UNDNAME_COMPLETE);
+
+        outputStream << undecoratedName;
+
+        outputStream << "(";
+        // Use SymSetContext to get just the locals/params for this frame
+        IMAGEHLP_STACK_FRAME imagehlpStackFrame;
+        imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
+        SymSetContext( m_hProcess, &imagehlpStackFrame, 0 );
+
+        // Enumerate the locals/parameters
+        EnumerateSymbolsContext context(sf, outputStream);
+        SymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &context );
+        outputStream << ")";
+
+        outputStream << " + " << Offset(reinterpret_cast<void*>(symDisplacement));
+
+        // Get the source line for this stack frame entry
+        IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };
+        DWORD dwLineDisplacement;
+        if ( SymGetLineFromAddr64( m_hProcess, sf.AddrPC.Offset,
+                                &dwLineDisplacement, &lineInfo ) )
+        {
+          outputStream << " " << lineInfo.FileName << " line " << Unsigned(lineInfo.LineNumber); 
+        }
+      }
+      else
+      {
+        outputStream << Address(reinterpret_cast<void*>(sf.AddrPC.Offset));
+      }
+    }
+
+    outputStream << "\n";
+  }
+
+  SymCleanup(m_hProcess);
+
+  return;
+}
+
+void write_stack_trace(TextOutputStream& outputStream)
+{
+  __try{ RaiseException(0,0,0,0); } __except(write_stack_trace((GetExceptionInformation())->ContextRecord, outputStream), EXCEPTION_CONTINUE_EXECUTION) {}
+}
+
+#elif defined (WIN32)
+void write_stack_trace(TextOutputStream& outputStream)
+{
+       outputStream << "\nStacktrace is disabled on this compiler\n";
+}
+#else
+void write_stack_trace(TextOutputStream& outputStream)
+{
+       outputStream << "\nStacktrace is disabled on this platform\n";
+}
+#endif