Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Utility/Status.cpp
39587 views
1
//===-- Status.cpp --------------------------------------------------------===//
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
#include "lldb/Utility/Status.h"
10
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"
18
19
#include <cerrno>
20
#include <cstdarg>
21
#include <string>
22
#include <system_error>
23
24
#ifdef __APPLE__
25
#include <mach/mach.h>
26
#endif
27
28
#ifdef _WIN32
29
#include <windows.h>
30
#endif
31
#include <cstdint>
32
33
namespace llvm {
34
class raw_ostream;
35
}
36
37
using namespace lldb;
38
using namespace lldb_private;
39
40
Status::Status() : m_string() {}
41
42
Status::Status(ValueType err, ErrorType type)
43
: m_code(err), m_type(type), m_string() {}
44
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)
49
: m_code(EC.value()),
50
m_type(EC.category() == std::generic_category() ? eErrorTypePOSIX
51
: eErrorTypeGeneric),
52
m_string(EC.message()) {}
53
54
Status::Status(const char *format, ...) : m_string() {
55
va_list args;
56
va_start(args, format);
57
SetErrorToGenericError();
58
SetErrorStringWithVarArg(format, args);
59
va_end(args);
60
}
61
62
const Status &Status::operator=(llvm::Error error) {
63
if (!error) {
64
Clear();
65
return *this;
66
}
67
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()) {
73
m_code = ec.value();
74
m_type = ErrorType::eErrorTypePOSIX;
75
return llvm::Error::success();
76
}
77
return llvm::Error(std::move(e));
78
});
79
80
// Otherwise, just preserve the message
81
if (error) {
82
SetErrorToGenericError();
83
SetErrorString(llvm::toString(std::move(error)));
84
}
85
86
return *this;
87
}
88
89
llvm::Error Status::ToError() const {
90
if (Success())
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::createStringError(AsCString());
96
}
97
98
Status::~Status() = default;
99
100
#ifdef _WIN32
101
static std::string RetrieveWin32ErrorString(uint32_t error_code) {
102
char *buffer = nullptr;
103
std::string message;
104
// Retrieve win32 system error.
105
// First, attempt to load a en-US message
106
if (::FormatMessageA(
107
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
108
FORMAT_MESSAGE_MAX_WIDTH_MASK,
109
NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
110
(LPSTR)&buffer, 0, NULL)) {
111
message.assign(buffer);
112
::LocalFree(buffer);
113
}
114
// If the previous didn't work, use the default OS language
115
else if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
116
FORMAT_MESSAGE_FROM_SYSTEM |
117
FORMAT_MESSAGE_MAX_WIDTH_MASK,
118
NULL, error_code, 0, (LPSTR)&buffer, 0, NULL)) {
119
message.assign(buffer);
120
::LocalFree(buffer);
121
}
122
return message;
123
}
124
#endif
125
126
// Get the error value as a NULL C string. The error string will be fetched and
127
// cached on demand. The cached error string value will remain until the error
128
// value is changed or cleared.
129
const char *Status::AsCString(const char *default_error_str) const {
130
if (Success())
131
return nullptr;
132
133
if (m_string.empty()) {
134
switch (m_type) {
135
case eErrorTypeMachKernel:
136
#if defined(__APPLE__)
137
if (const char *s = ::mach_error_string(m_code))
138
m_string.assign(s);
139
#endif
140
break;
141
142
case eErrorTypePOSIX:
143
m_string = llvm::sys::StrError(m_code);
144
break;
145
146
case eErrorTypeWin32:
147
#if defined(_WIN32)
148
m_string = RetrieveWin32ErrorString(m_code);
149
#endif
150
break;
151
152
default:
153
break;
154
}
155
}
156
if (m_string.empty()) {
157
if (default_error_str)
158
m_string.assign(default_error_str);
159
else
160
return nullptr; // User wanted a nullptr string back...
161
}
162
return m_string.c_str();
163
}
164
165
// Clear the error and any cached error string that it might contain.
166
void Status::Clear() {
167
m_code = 0;
168
m_type = eErrorTypeInvalid;
169
m_string.clear();
170
}
171
172
// Access the error value.
173
Status::ValueType Status::GetError() const { return m_code; }
174
175
// Access the error type.
176
ErrorType Status::GetType() const { return m_type; }
177
178
// Returns true if this object contains a value that describes an error or
179
// otherwise non-success result.
180
bool Status::Fail() const { return m_code != 0; }
181
182
void Status::SetExpressionError(lldb::ExpressionResults result,
183
const char *mssg) {
184
m_code = result;
185
m_type = eErrorTypeExpression;
186
m_string = mssg;
187
}
188
189
int Status::SetExpressionErrorWithFormat(lldb::ExpressionResults result,
190
const char *format, ...) {
191
int length = 0;
192
193
if (format != nullptr && format[0]) {
194
va_list args;
195
va_start(args, format);
196
length = SetErrorStringWithVarArg(format, args);
197
va_end(args);
198
} else {
199
m_string.clear();
200
}
201
m_code = result;
202
m_type = eErrorTypeExpression;
203
return length;
204
}
205
206
// Set accessor for the error value and type.
207
void Status::SetError(ValueType err, ErrorType type) {
208
m_code = err;
209
m_type = type;
210
m_string.clear();
211
}
212
213
// Update the error value to be "errno" and update the type to be "POSIX".
214
void Status::SetErrorToErrno() {
215
m_code = errno;
216
m_type = eErrorTypePOSIX;
217
m_string.clear();
218
}
219
220
// Update the error value to be LLDB_GENERIC_ERROR and update the type to be
221
// "Generic".
222
void Status::SetErrorToGenericError() {
223
m_code = LLDB_GENERIC_ERROR;
224
m_type = eErrorTypeGeneric;
225
m_string.clear();
226
}
227
228
// Set accessor for the error string value for a specific error. This allows
229
// any string to be supplied as an error explanation. The error string value
230
// will remain until the error value is cleared or a new error value/type is
231
// assigned.
232
void Status::SetErrorString(llvm::StringRef err_str) {
233
if (!err_str.empty()) {
234
// If we have an error string, we should always at least have an error set
235
// to a generic value.
236
if (Success())
237
SetErrorToGenericError();
238
}
239
m_string = std::string(err_str);
240
}
241
242
/// Set the current error string to a formatted error string.
243
///
244
/// \param format
245
/// A printf style format string
246
int Status::SetErrorStringWithFormat(const char *format, ...) {
247
if (format != nullptr && format[0]) {
248
va_list args;
249
va_start(args, format);
250
int length = SetErrorStringWithVarArg(format, args);
251
va_end(args);
252
return length;
253
} else {
254
m_string.clear();
255
}
256
return 0;
257
}
258
259
int Status::SetErrorStringWithVarArg(const char *format, va_list args) {
260
if (format != nullptr && format[0]) {
261
// If we have an error string, we should always at least have an error set
262
// to a generic value.
263
if (Success())
264
SetErrorToGenericError();
265
266
llvm::SmallString<1024> buf;
267
VASprintf(buf, format, args);
268
m_string = std::string(buf.str());
269
return buf.size();
270
} else {
271
m_string.clear();
272
}
273
return 0;
274
}
275
276
// Returns true if the error code in this object is considered a successful
277
// return value.
278
bool Status::Success() const { return m_code == 0; }
279
280
void llvm::format_provider<lldb_private::Status>::format(
281
const lldb_private::Status &error, llvm::raw_ostream &OS,
282
llvm::StringRef Options) {
283
llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
284
Options);
285
}
286
287