blob: 14534d9f82330580a4760dad1d0b4c5a2da5156d [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SRC_PROFILING_PERF_FRAME_POINTER_UNWINDER_H_
#define SRC_PROFILING_PERF_FRAME_POINTER_UNWINDER_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include <unwindstack/Error.h>
#include <unwindstack/MachineArm64.h>
#include <unwindstack/MachineRiscv64.h>
#include <unwindstack/MachineX86_64.h>
#include <unwindstack/Unwinder.h>
namespace perfetto {
namespace profiling {
class FramePointerUnwinder {
public:
FramePointerUnwinder(size_t max_frames,
unwindstack::Maps* maps,
unwindstack::Regs* regs,
std::shared_ptr<unwindstack::Memory> process_memory,
size_t stack_size)
: max_frames_(max_frames),
maps_(maps),
regs_(regs),
process_memory_(process_memory),
stack_size_(stack_size),
arch_(regs->Arch()) {
stack_end_ = regs->sp() + stack_size;
}
FramePointerUnwinder(const FramePointerUnwinder&) = delete;
FramePointerUnwinder& operator=(const FramePointerUnwinder&) = delete;
void Unwind();
// Disabling the resolving of names results in the function name being
// set to an empty string and the function offset being set to zero.
void SetResolveNames(bool resolve) { resolve_names_ = resolve; }
unwindstack::ErrorCode LastErrorCode() const { return last_error_.code; }
uint64_t warnings() const { return warnings_; }
std::vector<unwindstack::FrameData> ConsumeFrames() {
std::vector<unwindstack::FrameData> frames = std::move(frames_);
frames_.clear();
return frames;
}
bool IsArchSupported() const {
return arch_ == unwindstack::ARCH_ARM64 ||
arch_ == unwindstack::ARCH_X86_64;
}
void ClearErrors() {
warnings_ = unwindstack::WARNING_NONE;
last_error_.code = unwindstack::ERROR_NONE;
last_error_.address = 0;
}
protected:
const size_t max_frames_;
unwindstack::Maps* maps_;
unwindstack::Regs* regs_;
std::vector<unwindstack::FrameData> frames_;
std::shared_ptr<unwindstack::Memory> process_memory_;
const size_t stack_size_;
unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN;
bool resolve_names_ = false;
size_t stack_end_;
unwindstack::ErrorData last_error_;
uint64_t warnings_ = 0;
private:
void TryUnwind();
// Given a frame pointer, returns the frame pointer of the calling stack
// frame, places the return address of the calling stack frame into
// `ret_addr` and stack pointer into `sp`.
uint64_t DecodeFrame(uint64_t fp, uint64_t* ret_addr, uint64_t* sp);
bool IsFrameValid(uint64_t fp, uint64_t sp);
};
} // namespace profiling
} // namespace perfetto
#endif // SRC_PROFILING_PERF_FRAME_POINTER_UNWINDER_H_