1 //===-- Status.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/Status.h"
11 #include "lldb/Utility/VASPrintf.h"
12 #include "lldb/lldb-defines.h"
13 #include "lldb/lldb-enumerations.h"
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Errno.h"
17 #include "llvm/Support/FormatProviders.h"
22 #include <system_error>
25 #include <mach/mach.h>
38 using namespace lldb_private
;
40 Status::Status() : m_string() {}
42 Status::Status(ValueType err
, ErrorType type
)
43 : m_code(err
), m_type(type
), m_string() {}
45 // This logic is confusing because c++ calls the traditional (posix) errno codes
46 // "generic errors", while we use the term "generic" to mean completely
47 // arbitrary (text-based) errors.
48 Status::Status(std::error_code EC
)
50 m_type(EC
.category() == std::generic_category() ? eErrorTypePOSIX
52 m_string(EC
.message()) {}
54 Status::Status(const char *format
, ...) : m_string() {
56 va_start(args
, format
);
57 SetErrorToGenericError();
58 SetErrorStringWithVarArg(format
, args
);
62 const Status
&Status::operator=(llvm::Error error
) {
68 // if the error happens to be a errno error, preserve the error code
69 error
= llvm::handleErrors(
70 std::move(error
), [&](std::unique_ptr
<llvm::ECError
> e
) -> llvm::Error
{
71 std::error_code ec
= e
->convertToErrorCode();
72 if (ec
.category() == std::generic_category()) {
74 m_type
= ErrorType::eErrorTypePOSIX
;
75 return llvm::Error::success();
77 return llvm::Error(std::move(e
));
80 // Otherwise, just preserve the message
82 SetErrorToGenericError();
83 SetErrorString(llvm::toString(std::move(error
)));
89 llvm::Error
Status::ToError() const {
91 return llvm::Error::success();
92 if (m_type
== ErrorType::eErrorTypePOSIX
)
93 return llvm::errorCodeToError(
94 std::error_code(m_code
, std::generic_category()));
95 return llvm::make_error
<llvm::StringError
>(AsCString(),
96 llvm::inconvertibleErrorCode());
99 Status::~Status() = default;
102 static std::string
RetrieveWin32ErrorString(uint32_t error_code
) {
103 char *buffer
= nullptr;
105 // Retrieve win32 system error.
106 // First, attempt to load a en-US message
107 if (::FormatMessageA(
108 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
109 FORMAT_MESSAGE_MAX_WIDTH_MASK
,
110 NULL
, error_code
, MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
),
111 (LPSTR
)&buffer
, 0, NULL
)) {
112 message
.assign(buffer
);
115 // If the previous didn't work, use the default OS language
116 else if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
117 FORMAT_MESSAGE_FROM_SYSTEM
|
118 FORMAT_MESSAGE_MAX_WIDTH_MASK
,
119 NULL
, error_code
, 0, (LPSTR
)&buffer
, 0, NULL
)) {
120 message
.assign(buffer
);
127 // Get the error value as a NULL C string. The error string will be fetched and
128 // cached on demand. The cached error string value will remain until the error
129 // value is changed or cleared.
130 const char *Status::AsCString(const char *default_error_str
) const {
134 if (m_string
.empty()) {
136 case eErrorTypeMachKernel
:
137 #if defined(__APPLE__)
138 if (const char *s
= ::mach_error_string(m_code
))
143 case eErrorTypePOSIX
:
144 m_string
= llvm::sys::StrError(m_code
);
147 case eErrorTypeWin32
:
149 m_string
= RetrieveWin32ErrorString(m_code
);
157 if (m_string
.empty()) {
158 if (default_error_str
)
159 m_string
.assign(default_error_str
);
161 return nullptr; // User wanted a nullptr string back...
163 return m_string
.c_str();
166 // Clear the error and any cached error string that it might contain.
167 void Status::Clear() {
169 m_type
= eErrorTypeInvalid
;
173 // Access the error value.
174 Status::ValueType
Status::GetError() const { return m_code
; }
176 // Access the error type.
177 ErrorType
Status::GetType() const { return m_type
; }
179 // Returns true if this object contains a value that describes an error or
180 // otherwise non-success result.
181 bool Status::Fail() const { return m_code
!= 0; }
183 // Set accessor for the error value to "err" and the type to
184 // "eErrorTypeMachKernel"
185 void Status::SetMachError(uint32_t err
) {
187 m_type
= eErrorTypeMachKernel
;
191 void Status::SetExpressionError(lldb::ExpressionResults result
,
194 m_type
= eErrorTypeExpression
;
198 int Status::SetExpressionErrorWithFormat(lldb::ExpressionResults result
,
199 const char *format
, ...) {
202 if (format
!= nullptr && format
[0]) {
204 va_start(args
, format
);
205 length
= SetErrorStringWithVarArg(format
, args
);
211 m_type
= eErrorTypeExpression
;
215 // Set accessor for the error value and type.
216 void Status::SetError(ValueType err
, ErrorType type
) {
222 // Update the error value to be "errno" and update the type to be "POSIX".
223 void Status::SetErrorToErrno() {
225 m_type
= eErrorTypePOSIX
;
229 // Update the error value to be LLDB_GENERIC_ERROR and update the type to be
231 void Status::SetErrorToGenericError() {
232 m_code
= LLDB_GENERIC_ERROR
;
233 m_type
= eErrorTypeGeneric
;
237 // Set accessor for the error string value for a specific error. This allows
238 // any string to be supplied as an error explanation. The error string value
239 // will remain until the error value is cleared or a new error value/type is
241 void Status::SetErrorString(llvm::StringRef err_str
) {
242 if (!err_str
.empty()) {
243 // If we have an error string, we should always at least have an error set
244 // to a generic value.
246 SetErrorToGenericError();
248 m_string
= std::string(err_str
);
251 /// Set the current error string to a formatted error string.
254 /// A printf style format string
255 int Status::SetErrorStringWithFormat(const char *format
, ...) {
256 if (format
!= nullptr && format
[0]) {
258 va_start(args
, format
);
259 int length
= SetErrorStringWithVarArg(format
, args
);
268 int Status::SetErrorStringWithVarArg(const char *format
, va_list args
) {
269 if (format
!= nullptr && format
[0]) {
270 // If we have an error string, we should always at least have an error set
271 // to a generic value.
273 SetErrorToGenericError();
275 llvm::SmallString
<1024> buf
;
276 VASprintf(buf
, format
, args
);
277 m_string
= std::string(buf
.str());
285 // Returns true if the error code in this object is considered a successful
287 bool Status::Success() const { return m_code
== 0; }
289 void llvm::format_provider
<lldb_private::Status
>::format(
290 const lldb_private::Status
&error
, llvm::raw_ostream
&OS
,
291 llvm::StringRef Options
) {
292 llvm::format_provider
<llvm::StringRef
>::format(error
.AsCString(), OS
,