10b57cec5SDimitry Andric //===-- Status.h ------------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLDB_UTILITY_STATUS_H
100b57cec5SDimitry Andric #define LLDB_UTILITY_STATUS_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "lldb/lldb-defines.h"
130b57cec5SDimitry Andric #include "lldb/lldb-enumerations.h"
140b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
150b57cec5SDimitry Andric #include "llvm/Support/Error.h"
160b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
170b57cec5SDimitry Andric #include <cstdarg>
18fe6060f1SDimitry Andric #include <cstdint>
190b57cec5SDimitry Andric #include <string>
200b57cec5SDimitry Andric #include <system_error>
210b57cec5SDimitry Andric #include <type_traits>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace llvm {
240b57cec5SDimitry Andric class raw_ostream;
250b57cec5SDimitry Andric }
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric namespace lldb_private {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric /// \class Status Status.h "lldb/Utility/Status.h" An error handling class.
300b57cec5SDimitry Andric ///
310b57cec5SDimitry Andric /// This class is designed to be able to hold any error code that can be
320b57cec5SDimitry Andric /// encountered on a given platform. The errors are stored as a value of type
330b57cec5SDimitry Andric /// Status::ValueType. This value should be large enough to hold any and all
340b57cec5SDimitry Andric /// errors that the class supports. Each error has an associated type that is
350b57cec5SDimitry Andric /// of type lldb::ErrorType. New types can be added to support new error
360b57cec5SDimitry Andric /// types, and architecture specific types can be enabled. In the future we
370b57cec5SDimitry Andric /// may wish to switch to a registration mechanism where new error types can
380b57cec5SDimitry Andric /// be registered at runtime instead of a hard coded scheme.
390b57cec5SDimitry Andric ///
400b57cec5SDimitry Andric /// All errors in this class also know how to generate a string representation
410b57cec5SDimitry Andric /// of themselves for printing results and error codes. The string value will
420b57cec5SDimitry Andric /// be fetched on demand and its string value will be cached until the error
430b57cec5SDimitry Andric /// is cleared of the value of the error changes.
440b57cec5SDimitry Andric class Status {
450b57cec5SDimitry Andric public:
460b57cec5SDimitry Andric   /// Every error value that this object can contain needs to be able to fit
470b57cec5SDimitry Andric   /// into ValueType.
480b57cec5SDimitry Andric   typedef uint32_t ValueType;
490b57cec5SDimitry Andric 
509dba64beSDimitry Andric   Status();
519dba64beSDimitry Andric 
520b57cec5SDimitry Andric   /// Initialize the error object with a generic success value.
530b57cec5SDimitry Andric   ///
540b57cec5SDimitry Andric   /// \param[in] err
550b57cec5SDimitry Andric   ///     An error code.
560b57cec5SDimitry Andric   ///
570b57cec5SDimitry Andric   /// \param[in] type
580b57cec5SDimitry Andric   ///     The type for \a err.
590b57cec5SDimitry Andric   explicit Status(ValueType err,
600b57cec5SDimitry Andric                   lldb::ErrorType type = lldb::eErrorTypeGeneric);
610b57cec5SDimitry Andric 
629dba64beSDimitry Andric   Status(std::error_code EC);
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   explicit Status(const char *format, ...)
650b57cec5SDimitry Andric       __attribute__((format(printf, 2, 3)));
660b57cec5SDimitry Andric 
67bdd1243dSDimitry Andric   template <typename... Args>
createWithFormat(const char * format,Args &&...args)68bdd1243dSDimitry Andric   static Status createWithFormat(const char *format, Args &&...args) {
69bdd1243dSDimitry Andric     return Status(llvm::formatv(format, std::forward<Args>(args)...));
70bdd1243dSDimitry Andric   }
71bdd1243dSDimitry Andric 
720b57cec5SDimitry Andric   ~Status();
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   // llvm::Error support
Status(llvm::Error error)750b57cec5SDimitry Andric   explicit Status(llvm::Error error) { *this = std::move(error); }
760b57cec5SDimitry Andric   const Status &operator=(llvm::Error error);
770b57cec5SDimitry Andric   llvm::Error ToError() const;
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   /// Get the error string associated with the current error.
800b57cec5SDimitry Andric   //
810b57cec5SDimitry Andric   /// Gets the error value as a NULL terminated C string. The error string
820b57cec5SDimitry Andric   /// will be fetched and cached on demand. The error string will be retrieved
830b57cec5SDimitry Andric   /// from a callback that is appropriate for the type of the error and will
840b57cec5SDimitry Andric   /// be cached until the error value is changed or cleared.
850b57cec5SDimitry Andric   ///
860b57cec5SDimitry Andric   /// \return
870b57cec5SDimitry Andric   ///     The error as a NULL terminated C string value if the error
880b57cec5SDimitry Andric   ///     is valid and is able to be converted to a string value,
890b57cec5SDimitry Andric   ///     NULL otherwise.
900b57cec5SDimitry Andric   const char *AsCString(const char *default_error_str = "unknown error") const;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   /// Clear the object state.
930b57cec5SDimitry Andric   ///
940b57cec5SDimitry Andric   /// Reverts the state of this object to contain a generic success value and
950b57cec5SDimitry Andric   /// frees any cached error string value.
960b57cec5SDimitry Andric   void Clear();
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   /// Test for error condition.
990b57cec5SDimitry Andric   ///
1000b57cec5SDimitry Andric   /// \return
1010b57cec5SDimitry Andric   ///     \b true if this object contains an error, \b false
1020b57cec5SDimitry Andric   ///     otherwise.
1030b57cec5SDimitry Andric   bool Fail() const;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   /// Access the error value.
1060b57cec5SDimitry Andric   ///
1070b57cec5SDimitry Andric   /// \return
1080b57cec5SDimitry Andric   ///     The error value.
1090b57cec5SDimitry Andric   ValueType GetError() const;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   /// Access the error type.
1120b57cec5SDimitry Andric   ///
1130b57cec5SDimitry Andric   /// \return
1140b57cec5SDimitry Andric   ///     The error type enumeration value.
1150b57cec5SDimitry Andric   lldb::ErrorType GetType() const;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   void SetExpressionError(lldb::ExpressionResults, const char *mssg);
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   int SetExpressionErrorWithFormat(lldb::ExpressionResults, const char *format,
1200b57cec5SDimitry Andric                                    ...) __attribute__((format(printf, 3, 4)));
1210b57cec5SDimitry Andric 
1225ffd83dbSDimitry Andric   /// Set accessor with an error value and type.
1230b57cec5SDimitry Andric   ///
1245ffd83dbSDimitry Andric   /// Set accessor for the error value to \a err and the error type to \a
1250b57cec5SDimitry Andric   /// type.
1260b57cec5SDimitry Andric   ///
1270b57cec5SDimitry Andric   /// \param[in] err
1280b57cec5SDimitry Andric   ///     A mach error code.
1290b57cec5SDimitry Andric   ///
1300b57cec5SDimitry Andric   /// \param[in] type
1310b57cec5SDimitry Andric   ///     The type for \a err.
1320b57cec5SDimitry Andric   void SetError(ValueType err, lldb::ErrorType type);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   /// Set the current error to errno.
1350b57cec5SDimitry Andric   ///
1360b57cec5SDimitry Andric   /// Update the error value to be \c errno and update the type to be \c
1370b57cec5SDimitry Andric   /// Status::POSIX.
1380b57cec5SDimitry Andric   void SetErrorToErrno();
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   /// Set the current error to a generic error.
1410b57cec5SDimitry Andric   ///
1420b57cec5SDimitry Andric   /// Update the error value to be \c LLDB_GENERIC_ERROR and update the type
1430b57cec5SDimitry Andric   /// to be \c Status::Generic.
1440b57cec5SDimitry Andric   void SetErrorToGenericError();
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric   /// Set the current error string to \a err_str.
1470b57cec5SDimitry Andric   ///
1480b57cec5SDimitry Andric   /// Set accessor for the error string value for a generic errors, or to
1490b57cec5SDimitry Andric   /// supply additional details above and beyond the standard error strings
1500b57cec5SDimitry Andric   /// that the standard type callbacks typically provide. This allows custom
1510b57cec5SDimitry Andric   /// strings to be supplied as an error explanation. The error string value
1520b57cec5SDimitry Andric   /// will remain until the error value is cleared or a new error value/type
1530b57cec5SDimitry Andric   /// is assigned.
1540b57cec5SDimitry Andric   ///
1550b57cec5SDimitry Andric   /// \param err_str
1560b57cec5SDimitry Andric   ///     The new custom error string to copy and cache.
1570b57cec5SDimitry Andric   void SetErrorString(llvm::StringRef err_str);
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   /// Set the current error string to a formatted error string.
1600b57cec5SDimitry Andric   ///
1610b57cec5SDimitry Andric   /// \param format
1620b57cec5SDimitry Andric   ///     A printf style format string
1630b57cec5SDimitry Andric   int SetErrorStringWithFormat(const char *format, ...)
1640b57cec5SDimitry Andric       __attribute__((format(printf, 2, 3)));
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   int SetErrorStringWithVarArg(const char *format, va_list args);
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   template <typename... Args>
SetErrorStringWithFormatv(const char * format,Args &&...args)1690b57cec5SDimitry Andric   void SetErrorStringWithFormatv(const char *format, Args &&... args) {
1700b57cec5SDimitry Andric     SetErrorString(llvm::formatv(format, std::forward<Args>(args)...).str());
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   /// Test for success condition.
1740b57cec5SDimitry Andric   ///
1750b57cec5SDimitry Andric   /// Returns true if the error code in this object is considered a successful
1760b57cec5SDimitry Andric   /// return value.
1770b57cec5SDimitry Andric   ///
1780b57cec5SDimitry Andric   /// \return
1790b57cec5SDimitry Andric   ///     \b true if this object contains an value that describes
1800b57cec5SDimitry Andric   ///     success (non-erro), \b false otherwise.
1810b57cec5SDimitry Andric   bool Success() const;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric protected:
1840b57cec5SDimitry Andric   /// Member variables
185fe6060f1SDimitry Andric   ValueType m_code = 0; ///< Status code as an integer value.
186fe6060f1SDimitry Andric   lldb::ErrorType m_type =
187fe6060f1SDimitry Andric       lldb::eErrorTypeInvalid;  ///< The type of the above error code.
1880b57cec5SDimitry Andric   mutable std::string m_string; ///< A string representation of the error code.
189bdd1243dSDimitry Andric private:
Status(const llvm::formatv_object_base & payload)190bdd1243dSDimitry Andric   explicit Status(const llvm::formatv_object_base &payload) {
191bdd1243dSDimitry Andric     SetErrorToGenericError();
192bdd1243dSDimitry Andric     m_string = payload.str();
193bdd1243dSDimitry Andric   }
1940b57cec5SDimitry Andric };
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric } // namespace lldb_private
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric namespace llvm {
1990b57cec5SDimitry Andric template <> struct format_provider<lldb_private::Status> {
2000b57cec5SDimitry Andric   static void format(const lldb_private::Status &error, llvm::raw_ostream &OS,
2010b57cec5SDimitry Andric                      llvm::StringRef Options);
2020b57cec5SDimitry Andric };
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
2059dba64beSDimitry Andric #define LLDB_ERRORF(status, fmt, ...)                                          \
2069dba64beSDimitry Andric   do {                                                                         \
2079dba64beSDimitry Andric     if (status) {                                                              \
2089dba64beSDimitry Andric       (status)->SetErrorStringWithFormat((fmt), __VA_ARGS__);                  \
2099dba64beSDimitry Andric     }                                                                          \
2109dba64beSDimitry Andric   } while (0);
2119dba64beSDimitry Andric 
2125ffd83dbSDimitry Andric #endif // LLDB_UTILITY_STATUS_H
213