blob: f7b291b3af5fbdc60e226ccad2bd106f165ecec5 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/shared/status.h"
#include <lib/syslog/cpp/macros.h>
#include <string.h>
namespace debug {
#if defined(__Fuchsia__)
// Map some Fuchsia errors to their cross-platform equivalents. Resets the status to 0 if a
// non-platform error was generated.
Status::Type MapFuchsiaError(zx_status_t* status) {
switch (*status) {
case ZX_ERR_NOT_SUPPORTED:
*status = 0;
return Status::kNotSupported;
case ZX_ERR_NOT_FOUND:
*status = 0;
return Status::kNotFound;
case ZX_ERR_ALREADY_EXISTS:
*status = 0;
return Status::kAlreadyExists;
case ZX_ERR_NO_RESOURCES:
*status = 0;
return Status::kNoResources;
default:
return Status::kPlatformError;
}
}
Status ZxStatus(zx_status_t s) {
if (s == ZX_OK)
return Status();
// For cross-platform errors, this use the string provided by the system but only set the
// cross-platform error type. It might be nice to have both a cross-platform type and a
// platform-specific error code set, but that may require using std::optional for the
// platform_error.
const char* msg = zx_status_get_string(s);
Status::Type type = MapFuchsiaError(&s);
return Status(Status::InternalValues(), type, static_cast<int64_t>(s), msg);
}
Status ZxStatus(zx_status_t s, std::string msg) {
if (s == ZX_OK)
return Status();
Status::Type type = MapFuchsiaError(&s);
return Status(Status::InternalValues(), type, static_cast<int64_t>(s), std::move(msg));
}
#else
// Map some errno values to their cross-platform equivalents. Resets the status to 0 if a
// non-platform error was generated.
Status::Type MapErrnoError(int* en) {
switch (*en) {
case ENOENT:
*en = 0;
return Status::kNotFound;
case EEXIST:
*en = 0;
return Status::kAlreadyExists;
case ENOTSUP:
*en = 0;
return Status::kNotSupported;
default:
return Status::kPlatformError;
}
}
Status ErrnoStatus(int en) {
if (en == 0)
return Status();
Status::Type type = MapErrnoError(&en);
return Status(Status::InternalValues(), type, static_cast<int64_t>(en), strerror(en));
}
Status ErrnoStatus(int en, std::string msg) {
if (en == 0)
return Status();
Status::Type type = MapErrnoError(&en);
return Status(Status::InternalValues(), type, static_cast<int64_t>(en), std::move(msg));
}
#endif
Status::Status(std::string msg) : type_(kGenericError), message_(std::move(msg)) {}
Status::Status(Type t, std::string msg) : type_(t), message_(std::move(msg)) {
FX_DCHECK(t != kPlatformError && t != kSuccess && t != kLast);
}
Status::Status(InternalValues tag, Type t, uint64_t pe, std::string msg)
: type_(t), platform_error_(pe), message_(std::move(msg)) {
FX_DCHECK(t != kLast);
FX_DCHECK(t == kPlatformError || pe == 0); // |pe| should be 0 for anything but platform errors.
}
} // namespace debug
std::ostream& operator<<(std::ostream& out, const debug::Status& status) {
if (status.ok()) {
return out << "Status(OK)";
}
if (status.type() == debug::Status::kPlatformError) {
return out << "Status(platform error = " << status.platform_error() << ", \""
<< status.message() << "\")";
}
// TODO: it might be nice to have a stringified version of Status::Type. For now just use an
// integer.
return out << "Status(" << static_cast<uint32_t>(status.type()) << ", \"" << status.message()
<< "\")";
}