| // 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() |
| << "\")"; |
| } |