| 1 | //===-- Status.h ------------------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLDB_UTILITY_STATUS_H |
| 10 | #define LLDB_UTILITY_STATUS_H |
| 11 | |
| 12 | #include "lldb/Utility/FileSpec.h" |
| 13 | #include "lldb/Utility/StructuredData.h" |
| 14 | #include "lldb/lldb-defines.h" |
| 15 | #include "lldb/lldb-enumerations.h" |
| 16 | #include "llvm/ADT/StringRef.h" |
| 17 | #include "llvm/Support/Error.h" |
| 18 | #include "llvm/Support/FormatVariadic.h" |
| 19 | #include <cstdarg> |
| 20 | #include <cstdint> |
| 21 | #include <string> |
| 22 | #include <system_error> |
| 23 | #include <type_traits> |
| 24 | |
| 25 | namespace llvm { |
| 26 | class raw_ostream; |
| 27 | } |
| 28 | |
| 29 | namespace lldb_private { |
| 30 | |
| 31 | /// Going a bit against the spirit of llvm::Error, |
| 32 | /// lldb_private::Status need to store errors long-term and sometimes |
| 33 | /// copy them. This base class defines an interface for this |
| 34 | /// operation. |
| 35 | class CloneableError |
| 36 | : public llvm::ErrorInfo<CloneableError, llvm::ErrorInfoBase> { |
| 37 | public: |
| 38 | using llvm::ErrorInfo<CloneableError, llvm::ErrorInfoBase>::ErrorInfo; |
| 39 | CloneableError() : ErrorInfo() {} |
| 40 | virtual std::unique_ptr<CloneableError> Clone() const = 0; |
| 41 | virtual lldb::ErrorType GetErrorType() const = 0; |
| 42 | virtual StructuredData::ObjectSP GetAsStructuredData() const = 0; |
| 43 | static char ID; |
| 44 | }; |
| 45 | |
| 46 | /// Common base class for all error-code errors. |
| 47 | class CloneableECError |
| 48 | : public llvm::ErrorInfo<CloneableECError, CloneableError> { |
| 49 | public: |
| 50 | using llvm::ErrorInfo<CloneableECError, CloneableError>::ErrorInfo; |
| 51 | std::error_code convertToErrorCode() const override { return EC; } |
| 52 | void log(llvm::raw_ostream &OS) const override { OS << EC.message(); } |
| 53 | lldb::ErrorType GetErrorType() const override; |
| 54 | virtual StructuredData::ObjectSP GetAsStructuredData() const override; |
| 55 | static char ID; |
| 56 | |
| 57 | protected: |
| 58 | CloneableECError() = delete; |
| 59 | CloneableECError(std::error_code ec) : ErrorInfo(), EC(ec) {} |
| 60 | std::error_code EC; |
| 61 | }; |
| 62 | /// FIXME: Move these declarations closer to where they're used. |
| 63 | class MachKernelError |
| 64 | : public llvm::ErrorInfo<MachKernelError, CloneableECError> { |
| 65 | public: |
| 66 | using llvm::ErrorInfo<MachKernelError, CloneableECError>::ErrorInfo; |
| 67 | MachKernelError(std::error_code ec) : ErrorInfo(ec) {} |
| 68 | std::string message() const override; |
| 69 | std::unique_ptr<CloneableError> Clone() const override; |
| 70 | lldb::ErrorType GetErrorType() const override; |
| 71 | static char ID; |
| 72 | }; |
| 73 | |
| 74 | class Win32Error : public llvm::ErrorInfo<Win32Error, CloneableECError> { |
| 75 | public: |
| 76 | using llvm::ErrorInfo<Win32Error, CloneableECError>::ErrorInfo; |
| 77 | Win32Error(std::error_code ec, const llvm::Twine &msg = {}) : ErrorInfo(ec) {} |
| 78 | std::string message() const override; |
| 79 | std::unique_ptr<CloneableError> Clone() const override; |
| 80 | lldb::ErrorType GetErrorType() const override; |
| 81 | static char ID; |
| 82 | }; |
| 83 | |
| 84 | /// \class Status Status.h "lldb/Utility/Status.h" An error handling class. |
| 85 | /// |
| 86 | /// This class is designed to be able to hold any error code that can be |
| 87 | /// encountered on a given platform. The errors are stored as a value of type |
| 88 | /// Status::ValueType. This value should be large enough to hold any and all |
| 89 | /// errors that the class supports. Each error has an associated type that is |
| 90 | /// of type lldb::ErrorType. New types can be added to support new error |
| 91 | /// types, and architecture specific types can be enabled. In the future we |
| 92 | /// may wish to switch to a registration mechanism where new error types can |
| 93 | /// be registered at runtime instead of a hard coded scheme. |
| 94 | /// |
| 95 | /// All errors in this class also know how to generate a string representation |
| 96 | /// of themselves for printing results and error codes. The string value will |
| 97 | /// be fetched on demand and its string value will be cached until the error |
| 98 | /// is cleared of the value of the error changes. |
| 99 | /// |
| 100 | /// API design notes: |
| 101 | /// |
| 102 | /// Most APIs that currently vend a Status would be better served by |
| 103 | /// returning llvm::Expected<> instead. If possibles APIs should be |
| 104 | /// refactored to avoid Status. The only legitimate long-term uses of |
| 105 | /// Status are objects that need to store an error for a long time |
| 106 | /// (which should be questioned as a design decision, too). |
| 107 | /// |
| 108 | /// Implementation notes: |
| 109 | /// |
| 110 | /// Internally, Status stores an llvm::Error. |
| 111 | /// eErrorTypeInvalid |
| 112 | /// eErrorTypeGeneric llvm::StringError |
| 113 | /// eErrorTypePOSIX llvm::ECError |
| 114 | /// eErrorTypeMachKernel MachKernelError |
| 115 | /// eErrorTypeExpression llvm::ErrorList<ExpressionError> |
| 116 | /// eErrorTypeWin32 Win32Error |
| 117 | |
| 118 | class Status { |
| 119 | public: |
| 120 | /// into ValueType. |
| 121 | typedef uint32_t ValueType; |
| 122 | |
| 123 | Status(); |
| 124 | Status(Status &&other) = default; |
| 125 | |
| 126 | /// Initialize the error object with a generic success value. |
| 127 | /// |
| 128 | /// \param[in] err |
| 129 | /// An error code. |
| 130 | /// |
| 131 | /// \param[in] type |
| 132 | /// The type for \a err. |
| 133 | explicit Status(ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric, |
| 134 | std::string msg = {}); |
| 135 | |
| 136 | Status(std::error_code EC); |
| 137 | |
| 138 | /// Create a generic error with the message \c err_str. |
| 139 | explicit Status(std::string err_str); |
| 140 | |
| 141 | static Status FromErrorString(const char *str) { |
| 142 | if (str) |
| 143 | return Status(std::string(str)); |
| 144 | return Status(std::string("null error" )); |
| 145 | } |
| 146 | |
| 147 | static Status FromErrorStringWithFormat(const char *format, ...) |
| 148 | __attribute__((format(printf, 1, 2))); |
| 149 | |
| 150 | template <typename... Args> |
| 151 | static Status FromErrorStringWithFormatv(const char *format, Args &&...args) { |
| 152 | return Status(llvm::formatv(format, std::forward<Args>(args)...)); |
| 153 | } |
| 154 | |
| 155 | /// Set the current error to errno. |
| 156 | /// |
| 157 | /// Update the error value to be \c errno and update the type to be \c |
| 158 | /// Status::POSIX. |
| 159 | static Status FromErrno(); |
| 160 | |
| 161 | ~Status(); |
| 162 | |
| 163 | const Status &operator=(Status &&); |
| 164 | /// Avoid using this in new code. Migrate APIs to llvm::Expected instead. |
| 165 | static Status FromError(llvm::Error error); |
| 166 | |
| 167 | /// FIXME: Replace all uses with takeError() instead. |
| 168 | llvm::Error ToError() const; |
| 169 | |
| 170 | llvm::Error takeError() { return std::move(m_error); } |
| 171 | |
| 172 | /// Don't call this function in new code. Instead, redesign the API |
| 173 | /// to use llvm::Expected instead of Status. |
| 174 | Status Clone() const { return Status(ToError()); } |
| 175 | |
| 176 | /// Get the error string associated with the current error. |
| 177 | // |
| 178 | /// Gets the error value as a NULL terminated C string. The error string |
| 179 | /// will be fetched and cached on demand. The error string will be retrieved |
| 180 | /// from a callback that is appropriate for the type of the error and will |
| 181 | /// be cached until the error value is changed or cleared. |
| 182 | /// |
| 183 | /// \return |
| 184 | /// The error as a NULL terminated C string value if the error |
| 185 | /// is valid and is able to be converted to a string value, |
| 186 | /// NULL otherwise. |
| 187 | const char *AsCString(const char *default_error_str = "unknown error" ) const; |
| 188 | |
| 189 | /// Get the error in machine-readable form. |
| 190 | StructuredData::ObjectSP GetAsStructuredData() const; |
| 191 | |
| 192 | /// Clear the object state. |
| 193 | /// |
| 194 | /// Reverts the state of this object to contain a generic success value and |
| 195 | /// frees any cached error string value. |
| 196 | void Clear(); |
| 197 | |
| 198 | /// Test for error condition. |
| 199 | /// |
| 200 | /// \return |
| 201 | /// \b true if this object contains an error, \b false |
| 202 | /// otherwise. |
| 203 | bool Fail() const; |
| 204 | |
| 205 | /// Access the error value. |
| 206 | /// |
| 207 | /// If the internally stored \ref llvm::Error is an \ref |
| 208 | /// llvm::ErrorList then this returns the error value of the first |
| 209 | /// error. |
| 210 | /// |
| 211 | /// \return |
| 212 | /// The error value. |
| 213 | ValueType GetError() const; |
| 214 | |
| 215 | /// Access the error type. |
| 216 | /// |
| 217 | /// If the internally stored \ref llvm::Error is an \ref |
| 218 | /// llvm::ErrorList then this returns the error value of the first |
| 219 | /// error. |
| 220 | /// |
| 221 | /// \return |
| 222 | /// The error type enumeration value. |
| 223 | lldb::ErrorType GetType() const; |
| 224 | |
| 225 | /// Test for success condition. |
| 226 | /// |
| 227 | /// Returns true if the error code in this object is considered a successful |
| 228 | /// return value. |
| 229 | /// |
| 230 | /// \return |
| 231 | /// \b true if this object contains an value that describes |
| 232 | /// success (non-erro), \b false otherwise. |
| 233 | bool Success() const; |
| 234 | |
| 235 | protected: |
| 236 | Status(llvm::Error error) : m_error(std::move(error)) {} |
| 237 | llvm::Error m_error; |
| 238 | /// TODO: Replace this with just calling toString(m_error). |
| 239 | mutable std::string m_string; |
| 240 | }; |
| 241 | |
| 242 | } // namespace lldb_private |
| 243 | |
| 244 | namespace llvm { |
| 245 | template <> struct format_provider<lldb_private::Status> { |
| 246 | static void format(const lldb_private::Status &error, llvm::raw_ostream &OS, |
| 247 | llvm::StringRef Options); |
| 248 | }; |
| 249 | } // namespace llvm |
| 250 | |
| 251 | #define LLDB_ERRORF(status, fmt, ...) \ |
| 252 | do { \ |
| 253 | if (status) { \ |
| 254 | (status)->SetErrorStringWithFormat((fmt), __VA_ARGS__); \ |
| 255 | } \ |
| 256 | } while (0); |
| 257 | |
| 258 | #endif // LLDB_UTILITY_STATUS_H |
| 259 | |