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::make_error<llvm::StringError>(e.message(),
129 e.convertToErrorCode(), true);
130 };
131 llvm::visitErrors(error, [&](const llvm::ErrorInfoBase &e) {
132 result = joinErrors(std::move(result), clone(e));
133 });
134 return result;
135}
136
137Status Status::FromError(llvm::Error error) { return Status(std::move(error)); }
138
139llvm::Error Status::ToError() const { return CloneError(m_error); }
140
141Status::~Status() { llvm::consumeError(std::move(m_error)); }
142
143#ifdef _WIN32
144static std::string RetrieveWin32ErrorString(uint32_t error_code) {
145 char *buffer = nullptr;
146 std::string message;
147 // Retrieve win32 system error.
148 // First, attempt to load a en-US message
149 if (::FormatMessageA(
150 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
151 FORMAT_MESSAGE_MAX_WIDTH_MASK,
152 NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
153 (LPSTR)&buffer, 0, NULL)) {
154 message.assign(buffer);
155 ::LocalFree(buffer);
156 }
157 // If the previous didn't work, use the default OS language
158 else if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
159 FORMAT_MESSAGE_FROM_SYSTEM |
160 FORMAT_MESSAGE_MAX_WIDTH_MASK,
161 NULL, error_code, 0, (LPSTR)&buffer, 0, NULL)) {
162 message.assign(buffer);
163 ::LocalFree(buffer);
164 }
165 return message;
166}
167#endif
168
169std::string MachKernelError::message() const {
170#if defined(__APPLE__)
171 if (const char *s = ::mach_error_string(convertToErrorCode().value()))
172 return s;
173#endif
174 return "MachKernelError";
175}
176
177std::string Win32Error::message() const {
178#if defined(_WIN32)
179 return RetrieveWin32ErrorString(convertToErrorCode().value());
180#endif
181 return "Win32Error";
182}
183
184std::unique_ptr<CloneableError> MachKernelError::Clone() const {
185 return std::make_unique<MachKernelError>(convertToErrorCode());
186}
187
188std::unique_ptr<CloneableError> Win32Error::Clone() const {
189 return std::make_unique<Win32Error>(convertToErrorCode());
190}
191
192// Get the error value as a NULL C string. The error string will be fetched and
193// cached on demand. The cached error string value will remain until the error
194// value is changed or cleared.
195const char *Status::AsCString(const char *default_error_str) const {
196 if (Success())
197 return nullptr;
198
199 m_string = llvm::toStringWithoutConsuming(m_error);
200 // Backwards compatibility with older implementations of Status.
201 if (m_error.isA<llvm::ECError>())
202 if (!m_string.empty() && m_string[m_string.size() - 1] == '\n')
203 m_string.pop_back();
204
205 if (m_string.empty()) {
206 if (default_error_str)
207 m_string.assign(default_error_str);
208 else
209 return nullptr; // User wanted a nullptr string back...
210 }
211 return m_string.c_str();
212}
213
214// Clear the error and any cached error string that it might contain.
216 if (m_error)
218 "dropping error {0}");
219 m_error = llvm::Error::success();
220}
221
223 Status::ValueType result = 0;
224 llvm::visitErrors(m_error, [&](const llvm::ErrorInfoBase &error) {
225 // Return the first only.
226 if (result)
227 return;
228 std::error_code ec = error.convertToErrorCode();
229 result = ec.value();
230 });
231 return result;
232}
233
234static ErrorType ErrorCodeToErrorType(std::error_code ec) {
235 if (ec.category() == std::generic_category())
236 return eErrorTypePOSIX;
237 if (ec.category() == lldb_generic_category() ||
238 ec == llvm::inconvertibleErrorCode())
239 return eErrorTypeGeneric;
240 return eErrorTypeInvalid;
241}
242
244 return ErrorCodeToErrorType(EC);
245}
246
249}
250
253}
254
256 auto dict_up = std::make_unique<StructuredData::Dictionary>();
257 auto array_up = std::make_unique<StructuredData::Array>();
258 llvm::visitErrors(m_error, [&](const llvm::ErrorInfoBase &error) {
259 if (error.isA<CloneableError>())
260 array_up->AddItem(
261 static_cast<const CloneableError &>(error).GetAsStructuredData());
262 else
263 array_up->AddStringItem(error.message());
264 });
265 dict_up->AddIntegerItem("version", 1u);
266 dict_up->AddIntegerItem("type", (unsigned)GetType());
267 dict_up->AddItem("errors", std::move(array_up));
268 return dict_up;
269}
270
272 auto dict_up = std::make_unique<StructuredData::Dictionary>();
273 dict_up->AddIntegerItem("version", 1u);
274 dict_up->AddIntegerItem("error_code", EC.value());
275 dict_up->AddStringItem("message", message());
276 return dict_up;
277}
278
281 llvm::visitErrors(m_error, [&](const llvm::ErrorInfoBase &error) {
282 // Return the first only.
283 if (result != eErrorTypeInvalid)
284 return;
285 if (error.isA<CloneableError>())
286 result = static_cast<const CloneableError &>(error).GetErrorType();
287 else
288 result = ErrorCodeToErrorType(error.convertToErrorCode());
289
290 });
291 return result;
292}
293
294bool Status::Fail() const {
295 // Note that this does not clear the checked flag in
296 // m_error. Otherwise we'd need to make this thread-safe.
297 return m_error.isA<llvm::ErrorInfoBase>();
298}
299
300Status Status::FromErrno() { return Status(llvm::errnoAsErrorCode()); }
301
302// Returns true if the error code in this object is considered a successful
303// return value.
304bool Status::Success() const { return !Fail(); }
305
306void llvm::format_provider<lldb_private::Status>::format(
307 const lldb_private::Status &error, llvm::raw_ostream &OS,
308 llvm::StringRef Options) {
309 llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
310 Options);
311}
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:234
llvm::Error Error
std::error_code EC
Definition: Status.h:60
lldb::ErrorType GetErrorType() const override
Definition: Status.cpp:243
virtual StructuredData::ObjectSP GetAsStructuredData() const override
Definition: Status.cpp:271
Going a bit against the spirit of llvm::Error, lldb_private::Status need to store errors long-term an...
Definition: Status.h:36
virtual std::unique_ptr< CloneableError > Clone() const =0
virtual StructuredData::ObjectSP GetAsStructuredData() const =0
virtual lldb::ErrorType GetErrorType() const =0
std::string message() const override
Definition: Status.cpp:169
std::unique_ptr< CloneableError > Clone() const override
Definition: Status.cpp:184
lldb::ErrorType GetErrorType() const override
Definition: Status.cpp:247
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:215
static Status FromErrno()
Set the current error to errno.
Definition: Status.cpp:300
lldb::ErrorType GetType() const
Access the error type.
Definition: Status.cpp:279
ValueType GetError() const
Access the error value.
Definition: Status.cpp:222
llvm::Error ToError() const
FIXME: Replace all uses with takeError() instead.
Definition: Status.cpp:139
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition: Status.cpp:106
bool Fail() const
Test for error condition.
Definition: Status.cpp:294
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:195
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:137
llvm::Error m_error
Definition: Status.h:237
bool Success() const
Test for success condition.
Definition: Status.cpp:304
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:255
std::shared_ptr< Object > ObjectSP
static char ID
Definition: Status.h:81
std::string message() const override
Definition: Status.cpp:177
lldb::ErrorType GetErrorType() const override
Definition: Status.cpp:251
std::unique_ptr< CloneableError > Clone() const override
Definition: Status.cpp:188
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
Definition: SBAddress.h:15
@ eErrorTypeInvalid
@ eErrorTypeGeneric
Generic errors that can be any value.
@ eErrorTypeWin32
Standard Win32 error codes.
@ eErrorTypeMachKernel
Mach kernel error codes.
@ eErrorTypePOSIX
POSIX error codes.
Definition: Debugger.h:54