Status.cpp revision 320041
1318378Sdim//===-- Status.cpp -----------------------------------------------*- C++ 2318378Sdim//-*-===// 3318378Sdim// 4318378Sdim// The LLVM Compiler Infrastructure 5318378Sdim// 6318378Sdim// This file is distributed under the University of Illinois Open Source 7318378Sdim// License. See LICENSE.TXT for details. 8318378Sdim// 9318378Sdim//===----------------------------------------------------------------------===// 10318378Sdim 11318378Sdim#include "lldb/Utility/Status.h" 12318378Sdim 13318378Sdim#include "lldb/Utility/VASPrintf.h" 14319799Sdim#include "lldb/lldb-defines.h" // for LLDB_GENERIC_ERROR 15319799Sdim#include "lldb/lldb-enumerations.h" // for ErrorType, ErrorType::eErr... 16319799Sdim#include "llvm/ADT/SmallString.h" // for SmallString 17319799Sdim#include "llvm/ADT/StringRef.h" // for StringRef 18319799Sdim#include "llvm/Support/Errno.h" 19318378Sdim#include "llvm/Support/FormatProviders.h" // for format_provider 20318378Sdim 21318378Sdim#include <cerrno> 22318378Sdim#include <cstdarg> 23318378Sdim#include <string> // for string 24318378Sdim#include <system_error> 25318378Sdim 26318378Sdim#ifdef __APPLE__ 27318378Sdim#include <mach/mach.h> 28318378Sdim#endif 29318378Sdim 30318378Sdim#include <stdint.h> // for uint32_t 31318378Sdim 32318378Sdimnamespace llvm { 33318378Sdimclass raw_ostream; 34318378Sdim} 35318378Sdim 36318378Sdimusing namespace lldb; 37318378Sdimusing namespace lldb_private; 38318378Sdim 39318378SdimStatus::Status() : m_code(0), m_type(eErrorTypeInvalid), m_string() {} 40318378Sdim 41318378SdimStatus::Status(ValueType err, ErrorType type) 42318378Sdim : m_code(err), m_type(type), m_string() {} 43318378Sdim 44318378SdimStatus::Status(std::error_code EC) 45318378Sdim : m_code(EC.value()), m_type(ErrorType::eErrorTypeGeneric), 46318378Sdim m_string(EC.message()) {} 47318378Sdim 48318378SdimStatus::Status(const Status &rhs) = default; 49318378Sdim 50318378SdimStatus::Status(const char *format, ...) 51318378Sdim : m_code(0), m_type(eErrorTypeInvalid), m_string() { 52318378Sdim va_list args; 53318378Sdim va_start(args, format); 54318378Sdim SetErrorToGenericError(); 55318378Sdim SetErrorStringWithVarArg(format, args); 56318378Sdim va_end(args); 57318378Sdim} 58318378Sdim 59320041Sdimconst Status &Status::operator=(llvm::Error error) { 60320041Sdim if (!error) { 61320041Sdim Clear(); 62320041Sdim return *this; 63320041Sdim } 64318681Sdim 65318681Sdim // if the error happens to be a errno error, preserve the error code 66318681Sdim error = llvm::handleErrors( 67318681Sdim std::move(error), [&](std::unique_ptr<llvm::ECError> e) -> llvm::Error { 68318681Sdim std::error_code ec = e->convertToErrorCode(); 69318681Sdim if (ec.category() == std::generic_category()) { 70318681Sdim m_code = ec.value(); 71318681Sdim m_type = ErrorType::eErrorTypePOSIX; 72318681Sdim return llvm::Error::success(); 73318681Sdim } 74318681Sdim return llvm::Error(std::move(e)); 75318681Sdim }); 76318681Sdim 77318681Sdim // Otherwise, just preserve the message 78320041Sdim if (error) { 79320041Sdim SetErrorToGenericError(); 80318681Sdim SetErrorString(llvm::toString(std::move(error))); 81320041Sdim } 82320041Sdim 83320041Sdim return *this; 84318681Sdim} 85318681Sdim 86318681Sdimllvm::Error Status::ToError() const { 87318681Sdim if (Success()) 88318681Sdim return llvm::Error::success(); 89318681Sdim if (m_type == ErrorType::eErrorTypePOSIX) 90318681Sdim return llvm::errorCodeToError(std::error_code(m_code, std::generic_category())); 91318681Sdim return llvm::make_error<llvm::StringError>(AsCString(), 92318681Sdim llvm::inconvertibleErrorCode()); 93318681Sdim} 94318681Sdim 95318378Sdim//---------------------------------------------------------------------- 96318378Sdim// Assignment operator 97318378Sdim//---------------------------------------------------------------------- 98318378Sdimconst Status &Status::operator=(const Status &rhs) { 99318378Sdim if (this != &rhs) { 100318378Sdim m_code = rhs.m_code; 101318378Sdim m_type = rhs.m_type; 102318378Sdim m_string = rhs.m_string; 103318378Sdim } 104318378Sdim return *this; 105318378Sdim} 106318378Sdim 107318378Sdim//---------------------------------------------------------------------- 108318378Sdim// Assignment operator 109318378Sdim//---------------------------------------------------------------------- 110318378Sdimconst Status &Status::operator=(uint32_t err) { 111318378Sdim m_code = err; 112318378Sdim m_type = eErrorTypeMachKernel; 113318378Sdim m_string.clear(); 114318378Sdim return *this; 115318378Sdim} 116318378Sdim 117318378SdimStatus::~Status() = default; 118318378Sdim 119318378Sdim//---------------------------------------------------------------------- 120318378Sdim// Get the error value as a NULL C string. The error string will be 121318378Sdim// fetched and cached on demand. The cached error string value will 122318378Sdim// remain until the error value is changed or cleared. 123318378Sdim//---------------------------------------------------------------------- 124318378Sdimconst char *Status::AsCString(const char *default_error_str) const { 125318378Sdim if (Success()) 126318378Sdim return nullptr; 127318378Sdim 128318378Sdim if (m_string.empty()) { 129318378Sdim switch (m_type) { 130318378Sdim case eErrorTypeMachKernel: 131318378Sdim#if defined(__APPLE__) 132319799Sdim if (const char *s = ::mach_error_string(m_code)) 133319799Sdim m_string.assign(s); 134318378Sdim#endif 135318378Sdim break; 136318378Sdim 137318378Sdim case eErrorTypePOSIX: 138319799Sdim m_string = llvm::sys::StrError(m_code); 139318378Sdim break; 140318378Sdim 141318378Sdim default: 142318378Sdim break; 143318378Sdim } 144318378Sdim } 145318378Sdim if (m_string.empty()) { 146318378Sdim if (default_error_str) 147318378Sdim m_string.assign(default_error_str); 148318378Sdim else 149318378Sdim return nullptr; // User wanted a nullptr string back... 150318378Sdim } 151318378Sdim return m_string.c_str(); 152318378Sdim} 153318378Sdim 154318378Sdim//---------------------------------------------------------------------- 155318378Sdim// Clear the error and any cached error string that it might contain. 156318378Sdim//---------------------------------------------------------------------- 157318378Sdimvoid Status::Clear() { 158318378Sdim m_code = 0; 159318378Sdim m_type = eErrorTypeInvalid; 160318378Sdim m_string.clear(); 161318378Sdim} 162318378Sdim 163318378Sdim//---------------------------------------------------------------------- 164318378Sdim// Access the error value. 165318378Sdim//---------------------------------------------------------------------- 166318378SdimStatus::ValueType Status::GetError() const { return m_code; } 167318378Sdim 168318378Sdim//---------------------------------------------------------------------- 169318378Sdim// Access the error type. 170318378Sdim//---------------------------------------------------------------------- 171318378SdimErrorType Status::GetType() const { return m_type; } 172318378Sdim 173318378Sdim//---------------------------------------------------------------------- 174318378Sdim// Returns true if this object contains a value that describes an 175318378Sdim// error or otherwise non-success result. 176318378Sdim//---------------------------------------------------------------------- 177318378Sdimbool Status::Fail() const { return m_code != 0; } 178318378Sdim 179318378Sdim//---------------------------------------------------------------------- 180318378Sdim// Set accesssor for the error value to "err" and the type to 181318378Sdim// "eErrorTypeMachKernel" 182318378Sdim//---------------------------------------------------------------------- 183318378Sdimvoid Status::SetMachError(uint32_t err) { 184318378Sdim m_code = err; 185318378Sdim m_type = eErrorTypeMachKernel; 186318378Sdim m_string.clear(); 187318378Sdim} 188318378Sdim 189318378Sdimvoid Status::SetExpressionError(lldb::ExpressionResults result, 190318378Sdim const char *mssg) { 191318378Sdim m_code = result; 192318378Sdim m_type = eErrorTypeExpression; 193318378Sdim m_string = mssg; 194318378Sdim} 195318378Sdim 196318378Sdimint Status::SetExpressionErrorWithFormat(lldb::ExpressionResults result, 197318378Sdim const char *format, ...) { 198318378Sdim int length = 0; 199318378Sdim 200318378Sdim if (format != nullptr && format[0]) { 201318378Sdim va_list args; 202318378Sdim va_start(args, format); 203318378Sdim length = SetErrorStringWithVarArg(format, args); 204318378Sdim va_end(args); 205318378Sdim } else { 206318378Sdim m_string.clear(); 207318378Sdim } 208318378Sdim m_code = result; 209318378Sdim m_type = eErrorTypeExpression; 210318378Sdim return length; 211318378Sdim} 212318378Sdim 213318378Sdim//---------------------------------------------------------------------- 214318378Sdim// Set accesssor for the error value and type. 215318378Sdim//---------------------------------------------------------------------- 216318378Sdimvoid Status::SetError(ValueType err, ErrorType type) { 217318378Sdim m_code = err; 218318378Sdim m_type = type; 219318378Sdim m_string.clear(); 220318378Sdim} 221318378Sdim 222318378Sdim//---------------------------------------------------------------------- 223318378Sdim// Update the error value to be "errno" and update the type to 224318378Sdim// be "POSIX". 225318378Sdim//---------------------------------------------------------------------- 226318378Sdimvoid Status::SetErrorToErrno() { 227318378Sdim m_code = errno; 228318378Sdim m_type = eErrorTypePOSIX; 229318378Sdim m_string.clear(); 230318378Sdim} 231318378Sdim 232318378Sdim//---------------------------------------------------------------------- 233318378Sdim// Update the error value to be LLDB_GENERIC_ERROR and update the type 234318378Sdim// to be "Generic". 235318378Sdim//---------------------------------------------------------------------- 236318378Sdimvoid Status::SetErrorToGenericError() { 237318378Sdim m_code = LLDB_GENERIC_ERROR; 238318378Sdim m_type = eErrorTypeGeneric; 239318378Sdim m_string.clear(); 240318378Sdim} 241318378Sdim 242318378Sdim//---------------------------------------------------------------------- 243318378Sdim// Set accessor for the error string value for a specific error. 244318378Sdim// This allows any string to be supplied as an error explanation. 245318378Sdim// The error string value will remain until the error value is 246318378Sdim// cleared or a new error value/type is assigned. 247318378Sdim//---------------------------------------------------------------------- 248318378Sdimvoid Status::SetErrorString(llvm::StringRef err_str) { 249318378Sdim if (!err_str.empty()) { 250318378Sdim // If we have an error string, we should always at least have an error 251318378Sdim // set to a generic value. 252318378Sdim if (Success()) 253318378Sdim SetErrorToGenericError(); 254318378Sdim } 255318378Sdim m_string = err_str; 256318378Sdim} 257318378Sdim 258318378Sdim//------------------------------------------------------------------ 259318378Sdim/// Set the current error string to a formatted error string. 260318378Sdim/// 261318378Sdim/// @param format 262318378Sdim/// A printf style format string 263318378Sdim//------------------------------------------------------------------ 264318378Sdimint Status::SetErrorStringWithFormat(const char *format, ...) { 265318378Sdim if (format != nullptr && format[0]) { 266318378Sdim va_list args; 267318378Sdim va_start(args, format); 268318378Sdim int length = SetErrorStringWithVarArg(format, args); 269318378Sdim va_end(args); 270318378Sdim return length; 271318378Sdim } else { 272318378Sdim m_string.clear(); 273318378Sdim } 274318378Sdim return 0; 275318378Sdim} 276318378Sdim 277318378Sdimint Status::SetErrorStringWithVarArg(const char *format, va_list args) { 278318378Sdim if (format != nullptr && format[0]) { 279318378Sdim // If we have an error string, we should always at least have 280318378Sdim // an error set to a generic value. 281318378Sdim if (Success()) 282318378Sdim SetErrorToGenericError(); 283318378Sdim 284318378Sdim llvm::SmallString<1024> buf; 285318378Sdim VASprintf(buf, format, args); 286318378Sdim m_string = buf.str(); 287318378Sdim return buf.size(); 288318378Sdim } else { 289318378Sdim m_string.clear(); 290318378Sdim } 291318378Sdim return 0; 292318378Sdim} 293318378Sdim 294318378Sdim//---------------------------------------------------------------------- 295318378Sdim// Returns true if the error code in this object is considered a 296318378Sdim// successful return value. 297318378Sdim//---------------------------------------------------------------------- 298318378Sdimbool Status::Success() const { return m_code == 0; } 299318378Sdim 300318378Sdimbool Status::WasInterrupted() const { 301318378Sdim return (m_type == eErrorTypePOSIX && m_code == EINTR); 302318378Sdim} 303318378Sdim 304318378Sdimvoid llvm::format_provider<lldb_private::Status>::format( 305318378Sdim const lldb_private::Status &error, llvm::raw_ostream &OS, 306318378Sdim llvm::StringRef Options) { 307318378Sdim llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS, 308318378Sdim Options); 309318378Sdim} 310