| /* | |
| * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code 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 | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| #include "WinErrorHandling.h" | |
| #include "Log.h" | |
| #include "SysInfo.h" | |
| #include "FileUtils.h" | |
| namespace { | |
| std::string makeMessage(const std::string& msg, const char* label, | |
| const void* c, DWORD errorCode) { | |
| std::ostringstream err; | |
| err << (label ? label : "Some error") << " [" << errorCode << "]"; | |
| HMODULE hmodule = NULL; | |
| if (c) { | |
| GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | |
| | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | |
| reinterpret_cast<LPCTSTR>(c), &hmodule); | |
| if (!hmodule) { | |
| LOG_WARNING(tstrings::any() << "GetModuleHandleEx() failed for " | |
| << c << " address."); | |
| } | |
| } | |
| if (hmodule || !c) { | |
| err << "(" << SysError::getSysErrorMessage(errorCode, hmodule) << ")"; | |
| } | |
| return joinErrorMessages(msg, err.str()); | |
| } | |
| std::wstring getSystemMessageDescription(DWORD messageId, HMODULE moduleHandle) { | |
| LPWSTR pMsg = NULL; | |
| std::wstring descr; | |
| // we always retrieve UNICODE description from system, | |
| // convert it to utf8 if UNICODE is not defined | |
| while (true) { | |
| DWORD res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
| | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | |
| | (moduleHandle != NULL ? FORMAT_MESSAGE_FROM_HMODULE : 0), | |
| moduleHandle, messageId, 0, (LPWSTR)&pMsg, 0, NULL); | |
| if (res > 0) { | |
| // replace all non-printed chars with space | |
| for (DWORD i=0; i<res; i++) { | |
| if (pMsg[i] < L' ') { | |
| pMsg[i] = L' '; | |
| } | |
| } | |
| // trim right (spaces and dots) | |
| for (DWORD i=res; i>0; i--) { | |
| if (pMsg[i] > L' ' && pMsg[i] != L'.') { | |
| break; | |
| } | |
| pMsg[i] = 0; | |
| } | |
| descr = pMsg; | |
| LocalFree(pMsg); | |
| } else { | |
| // if we fail to get description for specific moduleHandle, | |
| // try to get "common" description. | |
| if (moduleHandle != NULL) { | |
| moduleHandle = NULL; | |
| continue; | |
| } | |
| descr = L"No description available"; | |
| } | |
| break; | |
| } | |
| return descr; | |
| } | |
| } // namespace | |
| SysError::SysError(const tstrings::any& msg, const void* caller, DWORD ec, | |
| const char* label): | |
| std::runtime_error(makeMessage(msg.str(), label, caller, ec)) { | |
| } | |
| std::wstring SysError::getSysErrorMessage(DWORD errCode, HMODULE moduleHandle) { | |
| tstrings::any msg; | |
| msg << "system error " << errCode | |
| << " (" << getSystemMessageDescription(errCode, moduleHandle) << ")"; | |
| return msg.tstr(); | |
| } | |
| std::wstring SysError::getComErrorMessage(HRESULT hr) { | |
| HRESULT hrOrig = hr; | |
| // for FACILITY_WIN32 facility we need to reset hiword | |
| if(HRESULT_FACILITY(hr) == FACILITY_WIN32) { | |
| hr = HRESULT_CODE(hr); | |
| } | |
| return tstrings::format(_T("COM error 0x%08X (%s)"), hrOrig, | |
| getSystemMessageDescription(hr, NULL)); | |
| } | |
| void debugBreak(const SourceCodePos& location, const tstring& envVarName, | |
| const tstring& substr) { | |
| if (!SysInfo::isEnvVariableSet(envVarName)) { | |
| return; | |
| } | |
| const tstring v = SysInfo::getEnvVariable(std::nothrow, envVarName); | |
| if (v != _T("*") && v.find(substr) == tstring::npos) { | |
| return; | |
| } | |
| tstring msg = tstrings::fromUtf8(makeMessage( | |
| std::runtime_error((tstrings::any() | |
| << "debug break. Reason: environment variable " | |
| << envVarName << " is set.").str()), | |
| location)); | |
| tstring caption = FileUtils::basename(SysInfo::getCurrentModulePath()); | |
| MessageBoxW(NULL, msg.c_str(), caption.c_str(), MB_OK | MB_TASKMODAL); | |
| } |