1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "WinErrorHandling.h"
  27 #include "Log.h"
  28 #include "SysInfo.h"
  29 #include "FileUtils.h"
  30 
  31 
  32 namespace {
  33 
  34 std::string makeMessage(const std::string& msg, const char* label,
  35                                             const void* c, DWORD errorCode) {
  36     std::ostringstream err;
  37     err << (label ? label : "Some error") << " [" << errorCode << "]";
  38 
  39     HMODULE hmodule = NULL;
  40     if (c) {
  41         GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
  42                 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
  43                 reinterpret_cast<LPCTSTR>(c), &hmodule);
  44 
  45         if (!hmodule) {
  46             LOG_WARNING(tstrings::any() << "GetModuleHandleEx() failed for "
  47                     << c << " address.");
  48         }
  49     }
  50     if (hmodule || !c) {
  51         err << "(" << SysError::getSysErrorMessage(errorCode, hmodule) << ")";
  52     }
  53 
  54     return joinErrorMessages(msg, err.str());
  55 }
  56 
  57 
  58 std::wstring getSystemMessageDescription(DWORD messageId, HMODULE moduleHandle) {
  59     LPWSTR pMsg = NULL;
  60     std::wstring descr;
  61 
  62     // we always retrieve UNICODE description from system,
  63     // convert it to utf8 if UNICODE is not defined
  64 
  65     while (true) {
  66         DWORD res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
  67                 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS
  68                 | (moduleHandle != NULL ? FORMAT_MESSAGE_FROM_HMODULE : 0),
  69                 moduleHandle, messageId, 0, (LPWSTR)&pMsg, 0, NULL);
  70         if (res > 0) {
  71             // replace all non-printed chars with space
  72             for (DWORD i=0; i<res; i++) {
  73                 if (pMsg[i] < L' ') {
  74                     pMsg[i] = L' ';
  75                 }
  76             }
  77             // trim right (spaces and dots)
  78             for (DWORD i=res; i>0; i--) {
  79                 if (pMsg[i] > L' ' && pMsg[i] != L'.') {
  80                     break;
  81                 }
  82                 pMsg[i] = 0;
  83             }
  84 
  85             descr = pMsg;
  86 
  87             LocalFree(pMsg);
  88         } else {
  89             // if we fail to get description for specific moduleHandle,
  90             // try to get "common" description.
  91             if (moduleHandle != NULL) {
  92                 moduleHandle = NULL;
  93                 continue;
  94             }
  95             descr = L"No description available";
  96         }
  97         break;
  98     }
  99 
 100     return descr;
 101 }
 102 
 103 } // namespace
 104 
 105 
 106 SysError::SysError(const tstrings::any& msg, const void* caller, DWORD ec,
 107         const char* label):
 108 
 109 std::runtime_error(makeMessage(msg.str(), label, caller, ec)) {
 110 }
 111 
 112 std::wstring SysError::getSysErrorMessage(DWORD errCode, HMODULE moduleHandle) {
 113     tstrings::any msg;
 114     msg << "system error " << errCode
 115         << " (" << getSystemMessageDescription(errCode, moduleHandle) << ")";
 116     return msg.tstr();
 117 }
 118 
 119 std::wstring SysError::getComErrorMessage(HRESULT hr) {
 120     HRESULT hrOrig = hr;
 121     // for FACILITY_WIN32 facility we need to reset hiword
 122     if(HRESULT_FACILITY(hr) == FACILITY_WIN32) {
 123         hr = HRESULT_CODE(hr);
 124     }
 125     return tstrings::format(_T("COM error 0x%08X (%s)"), hrOrig,
 126             getSystemMessageDescription(hr, NULL));
 127 }