Path: blob/main/contrib/llvm-project/lldb/source/Utility/Status.cpp
39587 views
//===-- Status.cpp --------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Utility/Status.h"910#include "lldb/Utility/VASPrintf.h"11#include "lldb/lldb-defines.h"12#include "lldb/lldb-enumerations.h"13#include "llvm/ADT/SmallString.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/Support/Errno.h"16#include "llvm/Support/FormatProviders.h"1718#include <cerrno>19#include <cstdarg>20#include <string>21#include <system_error>2223#ifdef __APPLE__24#include <mach/mach.h>25#endif2627#ifdef _WIN3228#include <windows.h>29#endif30#include <cstdint>3132namespace llvm {33class raw_ostream;34}3536using namespace lldb;37using namespace lldb_private;3839Status::Status() : m_string() {}4041Status::Status(ValueType err, ErrorType type)42: m_code(err), m_type(type), m_string() {}4344// This logic is confusing because c++ calls the traditional (posix) errno codes45// "generic errors", while we use the term "generic" to mean completely46// arbitrary (text-based) errors.47Status::Status(std::error_code EC)48: m_code(EC.value()),49m_type(EC.category() == std::generic_category() ? eErrorTypePOSIX50: eErrorTypeGeneric),51m_string(EC.message()) {}5253Status::Status(const char *format, ...) : m_string() {54va_list args;55va_start(args, format);56SetErrorToGenericError();57SetErrorStringWithVarArg(format, args);58va_end(args);59}6061const Status &Status::operator=(llvm::Error error) {62if (!error) {63Clear();64return *this;65}6667// if the error happens to be a errno error, preserve the error code68error = llvm::handleErrors(69std::move(error), [&](std::unique_ptr<llvm::ECError> e) -> llvm::Error {70std::error_code ec = e->convertToErrorCode();71if (ec.category() == std::generic_category()) {72m_code = ec.value();73m_type = ErrorType::eErrorTypePOSIX;74return llvm::Error::success();75}76return llvm::Error(std::move(e));77});7879// Otherwise, just preserve the message80if (error) {81SetErrorToGenericError();82SetErrorString(llvm::toString(std::move(error)));83}8485return *this;86}8788llvm::Error Status::ToError() const {89if (Success())90return llvm::Error::success();91if (m_type == ErrorType::eErrorTypePOSIX)92return llvm::errorCodeToError(93std::error_code(m_code, std::generic_category()));94return llvm::createStringError(AsCString());95}9697Status::~Status() = default;9899#ifdef _WIN32100static std::string RetrieveWin32ErrorString(uint32_t error_code) {101char *buffer = nullptr;102std::string message;103// Retrieve win32 system error.104// First, attempt to load a en-US message105if (::FormatMessageA(106FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |107FORMAT_MESSAGE_MAX_WIDTH_MASK,108NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),109(LPSTR)&buffer, 0, NULL)) {110message.assign(buffer);111::LocalFree(buffer);112}113// If the previous didn't work, use the default OS language114else if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |115FORMAT_MESSAGE_FROM_SYSTEM |116FORMAT_MESSAGE_MAX_WIDTH_MASK,117NULL, error_code, 0, (LPSTR)&buffer, 0, NULL)) {118message.assign(buffer);119::LocalFree(buffer);120}121return message;122}123#endif124125// Get the error value as a NULL C string. The error string will be fetched and126// cached on demand. The cached error string value will remain until the error127// value is changed or cleared.128const char *Status::AsCString(const char *default_error_str) const {129if (Success())130return nullptr;131132if (m_string.empty()) {133switch (m_type) {134case eErrorTypeMachKernel:135#if defined(__APPLE__)136if (const char *s = ::mach_error_string(m_code))137m_string.assign(s);138#endif139break;140141case eErrorTypePOSIX:142m_string = llvm::sys::StrError(m_code);143break;144145case eErrorTypeWin32:146#if defined(_WIN32)147m_string = RetrieveWin32ErrorString(m_code);148#endif149break;150151default:152break;153}154}155if (m_string.empty()) {156if (default_error_str)157m_string.assign(default_error_str);158else159return nullptr; // User wanted a nullptr string back...160}161return m_string.c_str();162}163164// Clear the error and any cached error string that it might contain.165void Status::Clear() {166m_code = 0;167m_type = eErrorTypeInvalid;168m_string.clear();169}170171// Access the error value.172Status::ValueType Status::GetError() const { return m_code; }173174// Access the error type.175ErrorType Status::GetType() const { return m_type; }176177// Returns true if this object contains a value that describes an error or178// otherwise non-success result.179bool Status::Fail() const { return m_code != 0; }180181void Status::SetExpressionError(lldb::ExpressionResults result,182const char *mssg) {183m_code = result;184m_type = eErrorTypeExpression;185m_string = mssg;186}187188int Status::SetExpressionErrorWithFormat(lldb::ExpressionResults result,189const char *format, ...) {190int length = 0;191192if (format != nullptr && format[0]) {193va_list args;194va_start(args, format);195length = SetErrorStringWithVarArg(format, args);196va_end(args);197} else {198m_string.clear();199}200m_code = result;201m_type = eErrorTypeExpression;202return length;203}204205// Set accessor for the error value and type.206void Status::SetError(ValueType err, ErrorType type) {207m_code = err;208m_type = type;209m_string.clear();210}211212// Update the error value to be "errno" and update the type to be "POSIX".213void Status::SetErrorToErrno() {214m_code = errno;215m_type = eErrorTypePOSIX;216m_string.clear();217}218219// Update the error value to be LLDB_GENERIC_ERROR and update the type to be220// "Generic".221void Status::SetErrorToGenericError() {222m_code = LLDB_GENERIC_ERROR;223m_type = eErrorTypeGeneric;224m_string.clear();225}226227// Set accessor for the error string value for a specific error. This allows228// any string to be supplied as an error explanation. The error string value229// will remain until the error value is cleared or a new error value/type is230// assigned.231void Status::SetErrorString(llvm::StringRef err_str) {232if (!err_str.empty()) {233// If we have an error string, we should always at least have an error set234// to a generic value.235if (Success())236SetErrorToGenericError();237}238m_string = std::string(err_str);239}240241/// Set the current error string to a formatted error string.242///243/// \param format244/// A printf style format string245int Status::SetErrorStringWithFormat(const char *format, ...) {246if (format != nullptr && format[0]) {247va_list args;248va_start(args, format);249int length = SetErrorStringWithVarArg(format, args);250va_end(args);251return length;252} else {253m_string.clear();254}255return 0;256}257258int Status::SetErrorStringWithVarArg(const char *format, va_list args) {259if (format != nullptr && format[0]) {260// If we have an error string, we should always at least have an error set261// to a generic value.262if (Success())263SetErrorToGenericError();264265llvm::SmallString<1024> buf;266VASprintf(buf, format, args);267m_string = std::string(buf.str());268return buf.size();269} else {270m_string.clear();271}272return 0;273}274275// Returns true if the error code in this object is considered a successful276// return value.277bool Status::Success() const { return m_code == 0; }278279void llvm::format_provider<lldb_private::Status>::format(280const lldb_private::Status &error, llvm::raw_ostream &OS,281llvm::StringRef Options) {282llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,283Options);284}285286287