LLDB mainline
Status.cpp
Go to the documentation of this file.
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
10
12#include "lldb/Utility/Log.h"
14#include "lldb/lldb-defines.h"
16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/Support/Errno.h"
19#include "llvm/Support/FormatProviders.h"
20
21#include <cerrno>
22#include <cstdarg>
23#include <string>
24#include <system_error>
25
26#ifdef __APPLE__
27#include <mach/mach.h>
28#endif
29
30#ifdef _WIN32
31#include <windows.h>
32#endif
33#include <cstdint>
34
35namespace llvm {
36class raw_ostream;
37}
38
39using namespace lldb;
40using namespace lldb_private;
41
46
47namespace {
48/// A std::error_code category for eErrorTypeGeneric.
49class LLDBGenericCategory : public std::error_category {
50 const char *name() const noexcept override { return "LLDBGenericCategory"; }
51 std::string message(int __ev) const override { return "generic LLDB error"; };
52};
53LLDBGenericCategory &lldb_generic_category() {
54 static LLDBGenericCategory g_generic_category;
55 return g_generic_category;
56}
57} // namespace
58
59Status::Status() : m_error(llvm::Error::success()) {}
60
61static llvm::Error ErrorFromEnums(Status::ValueType err, ErrorType type,
62 std::string msg) {
63 switch (type) {
65 return llvm::make_error<MachKernelError>(
66 std::error_code(err, std::system_category()));
67 case eErrorTypeWin32:
68#ifdef _WIN32
69 if (err == NO_ERROR)
70 return llvm::Error::success();
71#endif
72 return llvm::make_error<Win32Error>(
73 std::error_code(err, std::system_category()));
74 case eErrorTypePOSIX:
75 if (msg.empty())
76 return llvm::errorCodeToError(
77 std::error_code(err, std::generic_category()));
78 return llvm::createStringError(
79 std::move(msg), std::error_code(err, std::generic_category()));
80 default:
81 return llvm::createStringError(
82 std::move(msg), std::error_code(err, lldb_generic_category()));
83 }
84}
85
86Status::Status(ValueType err, ErrorType type, std::string msg)
87 : m_error(ErrorFromEnums(err, type, msg)) {}
88
89// This logic is confusing because C++ calls the traditional (posix) errno codes
90// "generic errors", while we use the term "generic" to mean completely
91// arbitrary (text-based) errors.
92Status::Status(std::error_code EC)
93 : m_error(!EC ? llvm::Error::success() : llvm::errorCodeToError(EC)) {}
94
95Status::Status(std::string err_str)
96 : m_error(
97 llvm::createStringError(llvm::inconvertibleErrorCode(), err_str)) {}
98
100 Clear();
101 llvm::consumeError(std::move(m_error));
102 m_error = std::move(other.m_error);
103 return *this;
104}
105
107 std::string string;
108 va_list args;
109 va_start(args, format);
110 if (format != nullptr && format[0]) {
111 llvm::SmallString<1024> buf;
112 VASprintf(buf, format, args);
113 string = std::string(buf.str());
114 }
115 va_end(args);
116 return Status(string);
117}
118
119/// Creates a deep copy of all known errors and converts all other
120/// errors to a new llvm::StringError.
121static llvm::Error CloneError(const llvm::Error &error) {
122 llvm::Error result = llvm::Error::success();
123 auto clone = [](const llvm::ErrorInfoBase &e) {
124 if (e.isA<CloneableError>())
125 return llvm::Error(static_cast<const CloneableError &>(e).Clone());
126 if (e.isA<llvm::ECError>())
127 return llvm::errorCodeToError(e.convertToErrorCode());
128 return llvm::createStringError(e.message(), e.convertToErrorCode());
129 };
130 llvm::visitErrors(error, [&](const llvm::ErrorInfoBase &e) {
131 result = joinErrors(std::move(result), clone(e));
132 });
133 return result;
134}
135
136Status Status::FromError(llvm::Error error) { return Status(std::move(error)); }
137
138llvm::Error Status::ToError() const { return CloneError(m_error); }
139
140Status::~Status() { llvm::consumeError(std::move(m_error)); }
141
142#ifdef _WIN32
143static std::string RetrieveWin32ErrorString(uint32_t error_code) {
144 char *buffer = nullptr;
145 std::string message;
146 // Retrieve win32 system error.
147 // First, attempt to load a en-US message
148 if (::FormatMessageA(
149 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
150 FORMAT_MESSAGE_MAX_WIDTH_MASK,
151 NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
152 (LPSTR)&buffer, 0, NULL)) {
153 message.assign(buffer);
154 ::LocalFree(buffer);
155 }
156 // If the previous didn't work, use the default OS language
157 else if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
158 FORMAT_MESSAGE_FROM_SYSTEM |
159 FORMAT_MESSAGE_MAX_WIDTH_MASK,
160 NULL, error_code, 0, (LPSTR)&buffer, 0, NULL)) {
161 message.assign(buffer);
162 ::LocalFree(buffer);
163 }
164 return message;
165}
166#endif
167
168std::string MachKernelError::message() const {
169#if defined(__APPLE__)
170 if (const char *s = ::mach_error_string(convertToErrorCode().value()))
171 return s;
172#endif
173 return "MachKernelError";
174}
175
176std::string Win32Error::message() const {
177#if defined(_WIN32)
178 return RetrieveWin32ErrorString(convertToErrorCode().value());
179#endif
180 return "Win32Error";
181}
182
183std::unique_ptr<CloneableError> MachKernelError::Clone() const {
184 return std::make_unique<MachKernelError>(convertToErrorCode());
185}
186
187std::unique_ptr<CloneableError> Win32Error::Clone() const {
188 return std::make_unique<Win32Error>(convertToErrorCode());
189}
190
191// Get the error value as a NULL C string. The error string will be fetched and
192// cached on demand. The cached error string value will remain until the error
193// value is changed or cleared.
194const char *Status::AsCString(const char *default_error_str) const {
195 if (Success())
196 return nullptr;
197
198 m_string = llvm::toStringWithoutConsuming(m_error);
199 // Backwards compatibility with older implementations of Status.
200 if (m_error.isA<llvm::ECError>())
201 if (!m_string.empty() && m_string[m_string.size() - 1] == '\n')
202 m_string.pop_back();
203
204 if (m_string.empty()) {
205 if (default_error_str)
206 m_string.assign(default_error_str);
207 else
208 return nullptr; // User wanted a nullptr string back...
209 }
210 return m_string.c_str();
211}
212
213// Clear the error and any cached error string that it might contain.
215 if (m_error)
217 "dropping error {0}");
218 m_error = llvm::Error::success();
219}
220
222 Status::ValueType result = 0;
223 llvm::visitErrors(m_error, [&](const llvm::ErrorInfoBase &error) {
224 // Return the first only.
225 if (result)
226 return;
227 std::error_code ec = error.convertToErrorCode();
228 result = ec.value();
229 });
230 return result;
231}
232
233static ErrorType ErrorCodeToErrorType(std::error_code ec) {
234 if (ec.category() == std::generic_category())
235 return eErrorTypePOSIX;
236 if (ec.category() == lldb_generic_category() ||
237 ec == llvm::inconvertibleErrorCode())
238 return eErrorTypeGeneric;
239 return eErrorTypeInvalid;
240}
241
245
249
253
255 auto dict_up = std::make_unique<StructuredData::Dictionary>();
256 auto array_up = std::make_unique<StructuredData::Array>();
257 llvm::visitErrors(m_error, [&](const llvm::ErrorInfoBase &error) {
258 if (error.isA<CloneableError>())
259 array_up->AddItem(
260 static_cast<const CloneableError &>(error).GetAsStructuredData());
261 else
262 array_up->AddStringItem(error.message());
263 });
264 dict_up->AddIntegerItem("version", 1u);
265 dict_up->AddIntegerItem("type", (unsigned)GetType());
266 dict_up->AddItem("errors", std::move(array_up));
267 return dict_up;
268}
269
271 auto dict_up = std::make_unique<StructuredData::Dictionary>();
272 dict_up->AddIntegerItem("version", 1u);
273 dict_up->AddIntegerItem("error_code", EC.value());
274 dict_up->AddStringItem("message", message());
275 return dict_up;
276}
277
280 llvm::visitErrors(m_error, [&](const llvm::ErrorInfoBase &error) {
281 // Return the first only.
282 if (result != eErrorTypeInvalid)
283 return;
284 if (error.isA<CloneableError>())
285 result = static_cast<const CloneableError &>(error).GetErrorType();
286 else
287 result = ErrorCodeToErrorType(error.convertToErrorCode());
288
289 });
290 return result;
291}
292
293bool Status::Fail() const {
294 // Note that this does not clear the checked flag in
295 // m_error. Otherwise we'd need to make this thread-safe.
296 return m_error.isA<llvm::ErrorInfoBase>();
297}
298
299Status Status::FromErrno() { return Status(llvm::errnoAsErrorCode()); }
300
301// Returns true if the error code in this object is considered a successful
302// return value.
303bool Status::Success() const { return !Fail(); }
304
306 const lldb_private::Status &error, llvm::raw_ostream &OS,
307 llvm::StringRef Options) {
308 llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
309 Options);
310}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERRORV(log, error,...)
Definition Log.h:408
static llvm::Error CloneError(const llvm::Error &error)
Creates a deep copy of all known errors and converts all other errors to a new llvm::StringError.
Definition Status.cpp:121
static llvm::Error ErrorFromEnums(Status::ValueType err, ErrorType type, std::string msg)
Definition Status.cpp:61
static ErrorType ErrorCodeToErrorType(std::error_code ec)
Definition Status.cpp:233
lldb::ErrorType GetErrorType() const override
Definition Status.cpp:242
virtual StructuredData::ObjectSP GetAsStructuredData() const override
Definition Status.cpp:270
Going a bit against the spirit of llvm::Error, lldb_private::Status need to store errors long-term an...
Definition Status.h:36
std::string message() const override
Definition Status.cpp:168
std::unique_ptr< CloneableError > Clone() const override
Definition Status.cpp:183
lldb::ErrorType GetErrorType() const override
Definition Status.cpp:246
A command line option parsing protocol class.
Definition Options.h:58
An error handling class.
Definition Status.h:118
uint32_t ValueType
into ValueType.
Definition Status.h:121
void Clear()
Clear the object state.
Definition Status.cpp:214
static Status FromErrno()
Set the current error to errno.
Definition Status.cpp:299
lldb::ErrorType GetType() const
Access the error type.
Definition Status.cpp:278
ValueType GetError() const
Access the error value.
Definition Status.cpp:221
llvm::Error ToError() const
FIXME: Replace all uses with takeError() instead.
Definition Status.cpp:138
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
bool Fail() const
Test for error condition.
Definition Status.cpp:293
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition Status.cpp:194
const Status & operator=(Status &&)
Definition Status.cpp:99
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
llvm::Error m_error
Definition Status.h:237
bool Success() const
Test for success condition.
Definition Status.cpp:303
std::string m_string
TODO: Replace this with just calling toString(m_error).
Definition Status.h:239
StructuredData::ObjectSP GetAsStructuredData() const
Get the error in machine-readable form.
Definition Status.cpp:254
std::shared_ptr< Object > ObjectSP
std::string message() const override
Definition Status.cpp:176
lldb::ErrorType GetErrorType() const override
Definition Status.cpp:250
std::unique_ptr< CloneableError > Clone() const override
Definition Status.cpp:187
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
bool VASprintf(llvm::SmallVectorImpl< char > &buf, const char *fmt, va_list args)
Definition VASprintf.cpp:19
std::unique_ptr< T > clone(const std::unique_ptr< T > &src)
Definition Utils.h:17
@ eErrorTypeGeneric
Generic errors that can be any value.
@ eErrorTypeWin32
Standard Win32 error codes.
@ eErrorTypeMachKernel
Mach kernel error codes.
@ eErrorTypePOSIX
POSIX error codes.
static void format(const lldb_private::Status &error, llvm::raw_ostream &OS, llvm::StringRef Options)
Definition Status.cpp:305