xref: /llvm-project/lldb/include/lldb/Utility/Status.h (revision d9cc37fea7b02954079ca59e8f7f28cffacc7e9e)
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