180814287SRaphael Isemann //===-- Status.cpp --------------------------------------------------------===//
297206d57SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
697206d57SZachary Turner //
797206d57SZachary Turner //===----------------------------------------------------------------------===//
897206d57SZachary Turner 
997206d57SZachary Turner #include "lldb/Utility/Status.h"
1097206d57SZachary Turner 
1197206d57SZachary Turner #include "lldb/Utility/VASPrintf.h"
12672d2c12SJonas Devlieghere #include "lldb/lldb-defines.h"
13672d2c12SJonas Devlieghere #include "lldb/lldb-enumerations.h"
14672d2c12SJonas Devlieghere #include "llvm/ADT/SmallString.h"
15672d2c12SJonas Devlieghere #include "llvm/ADT/StringRef.h"
1610c41f37SPavel Labath #include "llvm/Support/Errno.h"
17672d2c12SJonas Devlieghere #include "llvm/Support/FormatProviders.h"
1897206d57SZachary Turner 
1997206d57SZachary Turner #include <cerrno>
2097206d57SZachary Turner #include <cstdarg>
21672d2c12SJonas Devlieghere #include <string>
2297206d57SZachary Turner #include <system_error>
2397206d57SZachary Turner 
2497206d57SZachary Turner #ifdef __APPLE__
2597206d57SZachary Turner #include <mach/mach.h>
2697206d57SZachary Turner #endif
2797206d57SZachary Turner 
28c3d447feSAaron Smith #ifdef _WIN32
29c3d447feSAaron Smith #include <windows.h>
30c3d447feSAaron Smith #endif
3176e47d48SRaphael Isemann #include <cstdint>
3297206d57SZachary Turner 
3397206d57SZachary Turner namespace llvm {
3497206d57SZachary Turner class raw_ostream;
3597206d57SZachary Turner }
3697206d57SZachary Turner 
3797206d57SZachary Turner using namespace lldb;
3897206d57SZachary Turner using namespace lldb_private;
3997206d57SZachary Turner 
Status()409494c510SJonas Devlieghere Status::Status() : m_string() {}
4197206d57SZachary Turner 
Status(ValueType err,ErrorType type)4297206d57SZachary Turner Status::Status(ValueType err, ErrorType type)
4397206d57SZachary Turner     : m_code(err), m_type(type), m_string() {}
4497206d57SZachary Turner 
45f512b978SPavel Labath // This logic is confusing because c++ calls the traditional (posix) errno codes
46f512b978SPavel Labath // "generic errors", while we use the term "generic" to mean completely
47f512b978SPavel Labath // arbitrary (text-based) errors.
Status(std::error_code EC)4897206d57SZachary Turner Status::Status(std::error_code EC)
49f512b978SPavel Labath     : m_code(EC.value()),
50f512b978SPavel Labath       m_type(EC.category() == std::generic_category() ? eErrorTypePOSIX
51f512b978SPavel Labath                                                       : eErrorTypeGeneric),
5297206d57SZachary Turner       m_string(EC.message()) {}
5397206d57SZachary Turner 
Status(const char * format,...)54*28c878aeSShafik Yaghmour Status::Status(const char *format, ...) : m_string() {
5597206d57SZachary Turner   va_list args;
5697206d57SZachary Turner   va_start(args, format);
5797206d57SZachary Turner   SetErrorToGenericError();
5897206d57SZachary Turner   SetErrorStringWithVarArg(format, args);
5997206d57SZachary Turner   va_end(args);
6097206d57SZachary Turner }
6197206d57SZachary Turner 
operator =(llvm::Error error)623adc4087SPavel Labath const Status &Status::operator=(llvm::Error error) {
633adc4087SPavel Labath   if (!error) {
643adc4087SPavel Labath     Clear();
653adc4087SPavel Labath     return *this;
663adc4087SPavel Labath   }
67a24a3a30SPavel Labath 
68a24a3a30SPavel Labath   // if the error happens to be a errno error, preserve the error code
69a24a3a30SPavel Labath   error = llvm::handleErrors(
70a24a3a30SPavel Labath       std::move(error), [&](std::unique_ptr<llvm::ECError> e) -> llvm::Error {
71a24a3a30SPavel Labath         std::error_code ec = e->convertToErrorCode();
72a24a3a30SPavel Labath         if (ec.category() == std::generic_category()) {
73a24a3a30SPavel Labath           m_code = ec.value();
74a24a3a30SPavel Labath           m_type = ErrorType::eErrorTypePOSIX;
75a24a3a30SPavel Labath           return llvm::Error::success();
76a24a3a30SPavel Labath         }
77a24a3a30SPavel Labath         return llvm::Error(std::move(e));
78a24a3a30SPavel Labath       });
79a24a3a30SPavel Labath 
80a24a3a30SPavel Labath   // Otherwise, just preserve the message
813adc4087SPavel Labath   if (error) {
823adc4087SPavel Labath     SetErrorToGenericError();
83a24a3a30SPavel Labath     SetErrorString(llvm::toString(std::move(error)));
84a24a3a30SPavel Labath   }
85a24a3a30SPavel Labath 
863adc4087SPavel Labath   return *this;
873adc4087SPavel Labath }
883adc4087SPavel Labath 
ToError() const89a24a3a30SPavel Labath llvm::Error Status::ToError() const {
90a24a3a30SPavel Labath   if (Success())
91a24a3a30SPavel Labath     return llvm::Error::success();
92a24a3a30SPavel Labath   if (m_type == ErrorType::eErrorTypePOSIX)
93c3d447feSAaron Smith     return llvm::errorCodeToError(
94c3d447feSAaron Smith         std::error_code(m_code, std::generic_category()));
95a24a3a30SPavel Labath   return llvm::make_error<llvm::StringError>(AsCString(),
96a24a3a30SPavel Labath                                              llvm::inconvertibleErrorCode());
97a24a3a30SPavel Labath }
98a24a3a30SPavel Labath 
9997206d57SZachary Turner Status::~Status() = default;
10097206d57SZachary Turner 
101c3d447feSAaron Smith #ifdef _WIN32
RetrieveWin32ErrorString(uint32_t error_code)102c3d447feSAaron Smith static std::string RetrieveWin32ErrorString(uint32_t error_code) {
103c3d447feSAaron Smith   char *buffer = nullptr;
104c3d447feSAaron Smith   std::string message;
105c3d447feSAaron Smith   // Retrieve win32 system error.
106bdad3ec7SAlexandre Ganea   // First, attempt to load a en-US message
107c3d447feSAaron Smith   if (::FormatMessageA(
108c3d447feSAaron Smith           FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
109c3d447feSAaron Smith               FORMAT_MESSAGE_MAX_WIDTH_MASK,
110bdad3ec7SAlexandre Ganea           NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
111c3d447feSAaron Smith           (LPSTR)&buffer, 0, NULL)) {
112c3d447feSAaron Smith     message.assign(buffer);
113c3d447feSAaron Smith     ::LocalFree(buffer);
114c3d447feSAaron Smith   }
115bdad3ec7SAlexandre Ganea   // If the previous didn't work, use the default OS language
116bdad3ec7SAlexandre Ganea   else if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
117bdad3ec7SAlexandre Ganea                                 FORMAT_MESSAGE_FROM_SYSTEM |
118bdad3ec7SAlexandre Ganea                                 FORMAT_MESSAGE_MAX_WIDTH_MASK,
119bdad3ec7SAlexandre Ganea                             NULL, error_code, 0, (LPSTR)&buffer, 0, NULL)) {
120bdad3ec7SAlexandre Ganea     message.assign(buffer);
121bdad3ec7SAlexandre Ganea     ::LocalFree(buffer);
122bdad3ec7SAlexandre Ganea   }
123c3d447feSAaron Smith   return message;
124c3d447feSAaron Smith }
125c3d447feSAaron Smith #endif
126c3d447feSAaron Smith 
12705097246SAdrian Prantl // Get the error value as a NULL C string. The error string will be fetched and
12805097246SAdrian Prantl // cached on demand. The cached error string value will remain until the error
12905097246SAdrian Prantl // value is changed or cleared.
AsCString(const char * default_error_str) const13097206d57SZachary Turner const char *Status::AsCString(const char *default_error_str) const {
13197206d57SZachary Turner   if (Success())
13297206d57SZachary Turner     return nullptr;
13397206d57SZachary Turner 
13497206d57SZachary Turner   if (m_string.empty()) {
13597206d57SZachary Turner     switch (m_type) {
13697206d57SZachary Turner     case eErrorTypeMachKernel:
13797206d57SZachary Turner #if defined(__APPLE__)
13810c41f37SPavel Labath       if (const char *s = ::mach_error_string(m_code))
13910c41f37SPavel Labath         m_string.assign(s);
14097206d57SZachary Turner #endif
14197206d57SZachary Turner       break;
14297206d57SZachary Turner 
14397206d57SZachary Turner     case eErrorTypePOSIX:
14410c41f37SPavel Labath       m_string = llvm::sys::StrError(m_code);
14597206d57SZachary Turner       break;
14697206d57SZachary Turner 
147c3d447feSAaron Smith     case eErrorTypeWin32:
148c3d447feSAaron Smith #if defined(_WIN32)
149c3d447feSAaron Smith       m_string = RetrieveWin32ErrorString(m_code);
150c3d447feSAaron Smith #endif
151c3d447feSAaron Smith       break;
152c3d447feSAaron Smith 
15397206d57SZachary Turner     default:
15497206d57SZachary Turner       break;
15597206d57SZachary Turner     }
15697206d57SZachary Turner   }
15797206d57SZachary Turner   if (m_string.empty()) {
15897206d57SZachary Turner     if (default_error_str)
15997206d57SZachary Turner       m_string.assign(default_error_str);
16097206d57SZachary Turner     else
16197206d57SZachary Turner       return nullptr; // User wanted a nullptr string back...
16297206d57SZachary Turner   }
16397206d57SZachary Turner   return m_string.c_str();
16497206d57SZachary Turner }
16597206d57SZachary Turner 
16697206d57SZachary Turner // Clear the error and any cached error string that it might contain.
Clear()16797206d57SZachary Turner void Status::Clear() {
16897206d57SZachary Turner   m_code = 0;
16997206d57SZachary Turner   m_type = eErrorTypeInvalid;
17097206d57SZachary Turner   m_string.clear();
17197206d57SZachary Turner }
17297206d57SZachary Turner 
17397206d57SZachary Turner // Access the error value.
GetError() const17497206d57SZachary Turner Status::ValueType Status::GetError() const { return m_code; }
17597206d57SZachary Turner 
17697206d57SZachary Turner // Access the error type.
GetType() const17797206d57SZachary Turner ErrorType Status::GetType() const { return m_type; }
17897206d57SZachary Turner 
17905097246SAdrian Prantl // Returns true if this object contains a value that describes an error or
18005097246SAdrian Prantl // otherwise non-success result.
Fail() const18197206d57SZachary Turner bool Status::Fail() const { return m_code != 0; }
18297206d57SZachary Turner 
1834ebdee0aSBruce Mitchener // Set accessor for the error value to "err" and the type to
18497206d57SZachary Turner // "eErrorTypeMachKernel"
SetMachError(uint32_t err)18597206d57SZachary Turner void Status::SetMachError(uint32_t err) {
18697206d57SZachary Turner   m_code = err;
18797206d57SZachary Turner   m_type = eErrorTypeMachKernel;
18897206d57SZachary Turner   m_string.clear();
18997206d57SZachary Turner }
19097206d57SZachary Turner 
SetExpressionError(lldb::ExpressionResults result,const char * mssg)19197206d57SZachary Turner void Status::SetExpressionError(lldb::ExpressionResults result,
19297206d57SZachary Turner                                 const char *mssg) {
19397206d57SZachary Turner   m_code = result;
19497206d57SZachary Turner   m_type = eErrorTypeExpression;
19597206d57SZachary Turner   m_string = mssg;
19697206d57SZachary Turner }
19797206d57SZachary Turner 
SetExpressionErrorWithFormat(lldb::ExpressionResults result,const char * format,...)19897206d57SZachary Turner int Status::SetExpressionErrorWithFormat(lldb::ExpressionResults result,
19997206d57SZachary Turner                                          const char *format, ...) {
20097206d57SZachary Turner   int length = 0;
20197206d57SZachary Turner 
20297206d57SZachary Turner   if (format != nullptr && format[0]) {
20397206d57SZachary Turner     va_list args;
20497206d57SZachary Turner     va_start(args, format);
20597206d57SZachary Turner     length = SetErrorStringWithVarArg(format, args);
20697206d57SZachary Turner     va_end(args);
20797206d57SZachary Turner   } else {
20897206d57SZachary Turner     m_string.clear();
20997206d57SZachary Turner   }
21097206d57SZachary Turner   m_code = result;
21197206d57SZachary Turner   m_type = eErrorTypeExpression;
21297206d57SZachary Turner   return length;
21397206d57SZachary Turner }
21497206d57SZachary Turner 
2154ebdee0aSBruce Mitchener // Set accessor for the error value and type.
SetError(ValueType err,ErrorType type)21697206d57SZachary Turner void Status::SetError(ValueType err, ErrorType type) {
21797206d57SZachary Turner   m_code = err;
21897206d57SZachary Turner   m_type = type;
21997206d57SZachary Turner   m_string.clear();
22097206d57SZachary Turner }
22197206d57SZachary Turner 
22205097246SAdrian Prantl // Update the error value to be "errno" and update the type to be "POSIX".
SetErrorToErrno()22397206d57SZachary Turner void Status::SetErrorToErrno() {
22497206d57SZachary Turner   m_code = errno;
22597206d57SZachary Turner   m_type = eErrorTypePOSIX;
22697206d57SZachary Turner   m_string.clear();
22797206d57SZachary Turner }
22897206d57SZachary Turner 
22905097246SAdrian Prantl // Update the error value to be LLDB_GENERIC_ERROR and update the type to be
23005097246SAdrian Prantl // "Generic".
SetErrorToGenericError()23197206d57SZachary Turner void Status::SetErrorToGenericError() {
23297206d57SZachary Turner   m_code = LLDB_GENERIC_ERROR;
23397206d57SZachary Turner   m_type = eErrorTypeGeneric;
23497206d57SZachary Turner   m_string.clear();
23597206d57SZachary Turner }
23697206d57SZachary Turner 
23705097246SAdrian Prantl // Set accessor for the error string value for a specific error. This allows
23805097246SAdrian Prantl // any string to be supplied as an error explanation. The error string value
23905097246SAdrian Prantl // will remain until the error value is cleared or a new error value/type is
24005097246SAdrian Prantl // assigned.
SetErrorString(llvm::StringRef err_str)24197206d57SZachary Turner void Status::SetErrorString(llvm::StringRef err_str) {
24297206d57SZachary Turner   if (!err_str.empty()) {
24305097246SAdrian Prantl     // If we have an error string, we should always at least have an error set
24405097246SAdrian Prantl     // to a generic value.
24597206d57SZachary Turner     if (Success())
24697206d57SZachary Turner       SetErrorToGenericError();
24797206d57SZachary Turner   }
248adcd0268SBenjamin Kramer   m_string = std::string(err_str);
24997206d57SZachary Turner }
25097206d57SZachary Turner 
25197206d57SZachary Turner /// Set the current error string to a formatted error string.
25297206d57SZachary Turner ///
253f05b42e9SAdrian Prantl /// \param format
25497206d57SZachary Turner ///     A printf style format string
SetErrorStringWithFormat(const char * format,...)25597206d57SZachary Turner int Status::SetErrorStringWithFormat(const char *format, ...) {
25697206d57SZachary Turner   if (format != nullptr && format[0]) {
25797206d57SZachary Turner     va_list args;
25897206d57SZachary Turner     va_start(args, format);
25997206d57SZachary Turner     int length = SetErrorStringWithVarArg(format, args);
26097206d57SZachary Turner     va_end(args);
26197206d57SZachary Turner     return length;
26297206d57SZachary Turner   } else {
26397206d57SZachary Turner     m_string.clear();
26497206d57SZachary Turner   }
26597206d57SZachary Turner   return 0;
26697206d57SZachary Turner }
26797206d57SZachary Turner 
SetErrorStringWithVarArg(const char * format,va_list args)26897206d57SZachary Turner int Status::SetErrorStringWithVarArg(const char *format, va_list args) {
26997206d57SZachary Turner   if (format != nullptr && format[0]) {
27005097246SAdrian Prantl     // If we have an error string, we should always at least have an error set
27105097246SAdrian Prantl     // to a generic value.
27297206d57SZachary Turner     if (Success())
27397206d57SZachary Turner       SetErrorToGenericError();
27497206d57SZachary Turner 
27597206d57SZachary Turner     llvm::SmallString<1024> buf;
27697206d57SZachary Turner     VASprintf(buf, format, args);
277adcd0268SBenjamin Kramer     m_string = std::string(buf.str());
27897206d57SZachary Turner     return buf.size();
27997206d57SZachary Turner   } else {
28097206d57SZachary Turner     m_string.clear();
28197206d57SZachary Turner   }
28297206d57SZachary Turner   return 0;
28397206d57SZachary Turner }
28497206d57SZachary Turner 
28505097246SAdrian Prantl // Returns true if the error code in this object is considered a successful
28605097246SAdrian Prantl // return value.
Success() const28797206d57SZachary Turner bool Status::Success() const { return m_code == 0; }
28897206d57SZachary Turner 
format(const lldb_private::Status & error,llvm::raw_ostream & OS,llvm::StringRef Options)28997206d57SZachary Turner void llvm::format_provider<lldb_private::Status>::format(
29097206d57SZachary Turner     const lldb_private::Status &error, llvm::raw_ostream &OS,
29197206d57SZachary Turner     llvm::StringRef Options) {
29297206d57SZachary Turner   llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
29397206d57SZachary Turner                                                  Options);
29497206d57SZachary Turner }
295