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 | |