blob: 864626e86ed34b684fcd746dbbd5e9747014a9c6 [file] [log] [blame]
// Copyright 2023 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 <lib/elfldltl/zircon.h>
#include <ldmsg/ldmsg.h>
#include "startup-diagnostics.h"
#include "zircon.h"
namespace ld {
namespace {
struct LdsvcOp {
uint64_t ordinal;
std::string_view call;
};
constexpr LdsvcOp kLoadObject = {LDMSG_OP_LOAD_OBJECT, "load"};
zx::vmo LoaderServiceRpc(Diagnostics& diag, zx::unowned_channel ldsvc, LdsvcOp type,
std::string_view name) {
union {
ldmsg_req_t req;
ldmsg_rsp_t rsp;
} ldmsg_req_rsp;
ldmsg_req_t* req = &ldmsg_req_rsp.req;
size_t req_len;
zx_status_t status = ldmsg_req_encode(type.ordinal, req, &req_len,
static_cast<const char*>(name.data()), name.size());
if (status != ZX_OK) {
diag.SystemError("message of ", name.size(), "bytes too large for loader service protocol");
return {};
}
ldmsg_rsp_t* rsp = &ldmsg_req_rsp.rsp;
zx::vmo vmo;
zx_channel_call_args_t call = {
.wr_bytes = req,
.rd_bytes = rsp,
.rd_handles = vmo.reset_and_get_address(),
.wr_num_bytes = static_cast<uint32_t>(req_len),
.rd_num_bytes = sizeof(*rsp),
.rd_num_handles = 1u,
};
uint32_t reply_size;
uint32_t handle_count;
status = ldsvc->call(0, zx::time::infinite(), &call, &reply_size, &handle_count);
if (status != ZX_OK) {
diag.SystemError("zx_channel_call of ", call.wr_num_bytes,
"bytes to loader service: ", elfldltl::ZirconError{status});
return {};
}
size_t expected_reply_size = ldmsg_rsp_get_size(rsp);
if (reply_size != expected_reply_size) [[unlikely]] {
diag.SystemError("loader service reply ", reply_size, " bytes != ", expected_reply_size);
return {};
}
if (rsp->header.ordinal != type.ordinal) [[unlikely]] {
diag.SystemError("loader service reply opcode ", rsp->header.ordinal, "!= ", type.ordinal);
return {};
}
if (rsp->rv != ZX_OK) [[unlikely]] {
if (rsp->rv != ZX_ERR_NOT_FOUND) {
diag.SystemError("fuchsia.ldsvc/", type.call, "(\"", name, "\") ",
elfldltl::ZirconError{rsp->rv});
}
return {};
}
if (!vmo) [[unlikely]] {
diag.SystemError("fuchsia.ldsvc/", type.call, "(\"", name, "\") returned invalid VMO handle.");
return {};
}
return vmo;
}
} // namespace
zx::vmo StartupData::GetLibraryVmo(Diagnostics& diag, std::string_view name) {
return LoaderServiceRpc(diag, ldsvc.borrow(), kLoadObject, name);
}
} // namespace ld