blob: c86b6c0f102fa8a74e79f94dada86bb617f5b068 [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.
#ifndef SRC_LIB_UNWINDER_CFI_UNWINDER_H_
#define SRC_LIB_UNWINDER_CFI_UNWINDER_H_
#include <cstdint>
#include <map>
#include <memory>
#include <vector>
#include "sdk/lib/fit/include/lib/fit/function.h"
#include "src/lib/unwinder/cfi_module.h"
#include "src/lib/unwinder/memory.h"
#include "src/lib/unwinder/module.h"
#include "src/lib/unwinder/registers.h"
#include "src/lib/unwinder/unwinder_base.h"
namespace unwinder {
// Contains the information relevant for the given Module. The CfiModules are lazily loaded when
// this module is needed.
struct CfiModuleInfo {
bool IsValidPC(uint64_t pc) const;
Module module;
// The loaded binary file corresponding to this module.. This is the (possibly stripped) binary
// file. It may contain an .eh_frame section, and optionally a .debug_frame section (in the case
// it is unstripped).
std::unique_ptr<CfiModule> binary;
// The loaded debug info file, if present. This is an optional addition to the binary file
// above. When non-null, this file will be inspected for a .debug_frame section before the
// binary file. This is only loaded and used if the |debug_info_memory| is non-null in |module|.
std::unique_ptr<CfiModule> debug_info;
};
class CfiUnwinder : public UnwinderBase {
public:
explicit CfiUnwinder(const std::vector<Module>& modules);
Error Step(Memory* stack, const Frame& current, Frame& next) override;
void AsyncStep(AsyncMemory* stack, const Frame& current,
fit::callback<void(Error, Registers)> cb) override;
// For other unwinders that want to check whether a value looks like a valid PC.
bool IsValidPC(uint64_t pc);
// Fetch the corresponding CfiModuleInfo for the given PC value. The CfiModuleInfo will always
// attempt to load CFI directives for the given module, which can return errors if the CFI is
// missing or invalid. If this function returns Success, then the CFI was successfully loaded.
Error GetCfiModuleInfoForPc(uint64_t pc, CfiModuleInfo** out);
// Returns the Module object for the binary without attempting to load either .eh_frame or
// .debug_frame. This may be used by fallback unwinders to probe memory when debug info is
// unavailable or incomplete. Errors are only returned if the given |pc| is not within any known
// modules. Callers must ensure that the binary or debug_info memory is valid before using them.
Error GetModuleForPc(uint64_t pc, Module** out);
private:
// If the returned value is fit::ok, then the contained boolean indicates whether the next frame
// is a signal frame or not. Otherwise the encased Error type will have more information.
fit::result<Error, bool> Step(Memory* stack, const Registers& current, Registers& next,
bool is_return_address);
void AsyncStep(AsyncMemory* stack, Registers current, bool is_return_address,
fit::callback<void(Error, Registers)> cb);
// Mapping from module load addresses to a pair of (module description, lazily-initialized CFI
// modules for the binary and optional debugging info).
std::map<uint64_t, CfiModuleInfo> module_map_;
};
} // namespace unwinder
#endif // SRC_LIB_UNWINDER_CFI_UNWINDER_H_