blob: 995e42c03190d67d93a6535d2e7693460f547913 [file] [log] [blame]
// Copyright 2022 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.
#ifndef SRC_LIB_ZXDUMP_INCLUDE_LIB_ZXDUMP_FD_WRITER_H_
#define SRC_LIB_ZXDUMP_INCLUDE_LIB_ZXDUMP_FD_WRITER_H_
#include <lib/fit/result.h>
#include <sys/uio.h>
#include <cstring>
#include <string_view>
#include <vector>
#include <fbl/unique_fd.h>
#include "types.h"
// Like all zxdump APIs, the interfaces here are not thread-safe.
namespace zxdump {
// This provides callbacks for using zxdump::ProcessDump to stream output to
// a file descriptor. It supports both seekable and non-seekable descriptors.
//
// Writers work in two models: accumulate and flush for small fragments; and
// direct writing for large chunks. The first model is used for the headers
// and notes, which come in many small pieces that can be collected together in
// a single writev call. The second model is used for the bulk data like
// memory segments, which is streamed through temporary buffers rather than
// held in the dumper's memory throughout, but comes in large chunks big enough
// to merit individual write calls.
class FdWriter {
public:
using error_type = FdError;
FdWriter() = delete;
FdWriter(FdWriter&&) = default;
FdWriter& operator=(FdWriter&&) = default;
// The writer takes ownership of the fd.
explicit FdWriter(fbl::unique_fd fd) : fd_(std::move(fd)) {}
// Pass the result of this to zxdump::ProcessDump::DumpHeaders or
// zxdump::JobDump::DumpHeaders. The callback accumulates small fragments to
// be written out by WriteFragments. The views passed to the callback must
// stay valid pointers until after WriteFragments returns. This callback
// expects to receive a contiguous stream of data with no gaps before each
// offset.
//
// The returned callable object is valid for the lifetime of the FdWriter.
auto AccumulateFragmentsCallback() {
return [this](size_t offset, ByteView data) -> fit::result<error_type> {
Accumulate(offset, data);
return fit::ok();
};
}
// Call this after DumpHeaders makes all its calls to that callback, and
// before calling the WriteCallback callback. It returns the number of bytes
// written out.
fit::result<error_type, size_t> WriteFragments();
// Pass the result of this to zxdump::ProcessDump::DumpMemory or the like.
// The callback makes direct writes. It accepts an offset that advances over
// a gap since the preceding write (either via this callback or via the
// previous WriteFragments call), but offsets can never go backwards.
//
// The returned callable object is valid for the lifetime of the FdWriter.
auto WriteCallback() {
return [this](size_t offset, ByteView data) -> fit::result<error_type> {
return Write(offset, data);
};
}
// Reset the file offset calculations. After this, the next call to one of
// the callbacks is expected to use offset 0.
void ResetOffset() { total_ = 0; }
private:
struct Fragments {
std::vector<iovec> iov_;
size_t size_bytes_ = 0;
};
// Just store the data pointer for WriteFragments to gather later.
void Accumulate(size_t offset, ByteView data);
// Directly write the data out, seeking or zero-padding ahead if there's a
// gap from the last write to this offset.
fit::result<error_type> Write(size_t offset, ByteView data);
Fragments fragments_;
size_t total_ = 0;
fbl::unique_fd fd_;
bool is_pipe_ = false;
};
} // namespace zxdump
#endif // SRC_LIB_ZXDUMP_INCLUDE_LIB_ZXDUMP_FD_WRITER_H_