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