diff --git a/CMakeLists.txt b/CMakeLists.txt index 1302c64b7b8f555650a519772af710afa21004ec..120b5de3f1b00b5604c20ff6509657d6e6ad09cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -894,6 +894,11 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) IF(KWSYS_USE_SystemInformation) IF(WIN32) TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32) + # link in dbghelp.dll for symbol lookup if MSVC 1800 or later + # Note that the dbghelp runtime is part of MS Windows OS + IF(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800) + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp) + ENDIF() IF(KWSYS_SYS_HAS_PSAPI) TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} Psapi) diff --git a/SystemInformation.cxx b/SystemInformation.cxx index 435475399a938d46098d8677fefb2913483ab941..fb7832b088b6e44a752c41db76876648158ef9aa 100644 --- a/SystemInformation.cxx +++ b/SystemInformation.cxx @@ -2,6 +2,9 @@ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ #if defined(_WIN32) # define NOMINMAX // use our min,max +# if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800 +# define _WIN32_WINNT 0x0600 // vista +# endif # if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300) # define _WIN32_WINNT 0x0501 # endif @@ -3879,6 +3882,20 @@ SystemInformation::LongLong SystemInformationImplementation::GetProcessId() #endif } +/** + * Used in GetProgramStack(...) below + */ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && defined(_MSC_VER) && \ + _MSC_VER >= 1800 +# define KWSYS_SYSTEMINFORMATION_HAS_DBGHELP +# define TRACE_MAX_STACK_FRAMES 1024 +# define TRACE_MAX_FUNCTION_NAME_LENGTH 1024 +# pragma warning(push) +# pragma warning(disable : 4091) /* 'typedef ': ignored on left of '' */ +# include "dbghelp.h" +# pragma warning(pop) +#endif + /** return current program stack in a string demangle cxx symbols if possible. @@ -3886,28 +3903,58 @@ demangle cxx symbols if possible. std::string SystemInformationImplementation::GetProgramStack(int firstFrame, int wholePath) { - std::string programStack = "" -#if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) - "WARNING: The stack could not be examined " - "because backtrace is not supported.\n" -#elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD) - "WARNING: The stack trace will not use advanced " - "capabilities because this is a release build.\n" + std::ostringstream oss; + std::string programStack = ""; + +#ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP + (void)wholePath; + + void* stack[TRACE_MAX_STACK_FRAMES]; + HANDLE process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + WORD numberOfFrames = + CaptureStackBackTrace(firstFrame, TRACE_MAX_STACK_FRAMES, stack, NULL); + SYMBOL_INFO* symbol = static_cast<SYMBOL_INFO*>( + malloc(sizeof(SYMBOL_INFO) + + (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR))); + symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + DWORD displacement; + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + for (int i = 0; i < numberOfFrames; i++) { + DWORD64 address = reinterpret_cast<DWORD64>(stack[i]); + SymFromAddr(process, address, NULL, symbol); + if (SymGetLineFromAddr64(process, address, &displacement, &line)) { + oss << " at " << symbol->Name << " in " << line.FileName << " line " + << line.LineNumber << std::endl; + } else { + oss << " at " << symbol->Name << std::endl; + } + } + free(symbol); + #else -# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) - "WARNING: Function names will not be demangled " - "because " - "dladdr is not available.\n" -# endif -# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) - "WARNING: Function names will not be demangled " - "because cxxabi is not available.\n" + programStack += "" +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + "WARNING: The stack could not be examined " + "because backtrace is not supported.\n" +# elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD) + "WARNING: The stack trace will not use advanced " + "capabilities because this is a release build.\n" +# else +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + "WARNING: Function names will not be demangled " + "because dladdr is not available.\n" +# endif +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) + "WARNING: Function names will not be demangled " + "because cxxabi is not available.\n" +# endif # endif -#endif ; - std::ostringstream oss; -#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) +# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) void* stackSymbols[256]; int nFrames = backtrace(stackSymbols, 256); for (int i = firstFrame; i < nFrames; ++i) { @@ -3916,10 +3963,12 @@ std::string SystemInformationImplementation::GetProgramStack(int firstFrame, symProps.Initialize(stackSymbols[i]); oss << symProps << std::endl; } -#else +# else (void)firstFrame; (void)wholePath; +# endif #endif + programStack += oss.str(); return programStack;