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