* Copyright (C) 2016 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 _LIBUNWINDSTACK_DWARF_CFA_H
#define _LIBUNWINDSTACK_DWARF_CFA_H
#include <stdint.h>
#include <stack>
#include <string>
#include <type_traits>
#include <vector>
#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>
namespace unwindstack {
enum ArchEnum : uint8_t;
class DwarfCfaInfo {
public:
enum DisplayType : uint8_t {
DWARF_DISPLAY_NONE = 0,
DWARF_DISPLAY_REGISTER,
DWARF_DISPLAY_NUMBER,
DWARF_DISPLAY_SIGNED_NUMBER,
DWARF_DISPLAY_EVAL_BLOCK,
DWARF_DISPLAY_ADDRESS,
DWARF_DISPLAY_SET_LOC,
DWARF_DISPLAY_ADVANCE_LOC,
};
struct Info {
const char name[36];
uint8_t supported_version;
uint8_t num_operands;
uint8_t operands[2];
uint8_t display_operands[2];
};
const static Info kTable[64];
};
template <typename AddressType>
class DwarfCfa {
typedef typename std::make_signed<AddressType>::type SignedType;
public:
DwarfCfa(DwarfMemory* memory, const DwarfFde* fde, ArchEnum arch)
: memory_(memory), fde_(fde), arch_(arch) {}
virtual ~DwarfCfa() = default;
bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
dwarf_loc_regs_t* loc_regs);
bool Log(uint32_t indent, uint64_t pc, uint64_t start_offset, uint64_t end_offset);
const DwarfErrorData& last_error() { return last_error_; }
DwarfErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
AddressType cur_pc() { return cur_pc_; }
void set_cie_loc_regs(const dwarf_loc_regs_t* cie_loc_regs) { cie_loc_regs_ = cie_loc_regs; }
protected:
std::string GetOperandString(uint8_t operand, uint64_t value, uint64_t* cur_pc);
bool LogOffsetRegisterString(uint32_t indent, uint64_t cfa_offset, uint8_t reg);
bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc);
private:
DwarfErrorData last_error_;
DwarfMemory* memory_;
const DwarfFde* fde_;
ArchEnum arch_;
AddressType cur_pc_;
const dwarf_loc_regs_t* cie_loc_regs_ = nullptr;
std::vector<AddressType> operands_;
std::stack<dwarf_loc_regs_t> loc_reg_state_;
bool cfa_nop(dwarf_loc_regs_t*);
bool cfa_set_loc(dwarf_loc_regs_t*);
bool cfa_advance_loc(dwarf_loc_regs_t*);
bool cfa_offset(dwarf_loc_regs_t*);
bool cfa_restore(dwarf_loc_regs_t*);
bool cfa_undefined(dwarf_loc_regs_t*);
bool cfa_same_value(dwarf_loc_regs_t*);
bool cfa_register(dwarf_loc_regs_t*);
bool cfa_remember_state(dwarf_loc_regs_t*);
bool cfa_restore_state(dwarf_loc_regs_t*);
bool cfa_def_cfa(dwarf_loc_regs_t*);
bool cfa_def_cfa_register(dwarf_loc_regs_t*);
bool cfa_def_cfa_offset(dwarf_loc_regs_t*);
bool cfa_def_cfa_expression(dwarf_loc_regs_t*);
bool cfa_expression(dwarf_loc_regs_t*);
bool cfa_offset_extended_sf(dwarf_loc_regs_t*);
bool cfa_def_cfa_sf(dwarf_loc_regs_t*);
bool cfa_def_cfa_offset_sf(dwarf_loc_regs_t*);
bool cfa_val_offset(dwarf_loc_regs_t*);
bool cfa_val_offset_sf(dwarf_loc_regs_t*);
bool cfa_val_expression(dwarf_loc_regs_t*);
bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*);
bool cfa_aarch64_negate_ra_state(dwarf_loc_regs_t*);
using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*);
constexpr static process_func kCallbackTable[64] = {
&DwarfCfa::cfa_nop,
&DwarfCfa::cfa_set_loc,
&DwarfCfa::cfa_advance_loc,
&DwarfCfa::cfa_advance_loc,
&DwarfCfa::cfa_advance_loc,
&DwarfCfa::cfa_offset,
&DwarfCfa::cfa_restore,
&DwarfCfa::cfa_undefined,
&DwarfCfa::cfa_same_value,
&DwarfCfa::cfa_register,
&DwarfCfa::cfa_remember_state,
&DwarfCfa::cfa_restore_state,
&DwarfCfa::cfa_def_cfa,
&DwarfCfa::cfa_def_cfa_register,
&DwarfCfa::cfa_def_cfa_offset,
&DwarfCfa::cfa_def_cfa_expression,
&DwarfCfa::cfa_expression,
&DwarfCfa::cfa_offset_extended_sf,
&DwarfCfa::cfa_def_cfa_sf,
&DwarfCfa::cfa_def_cfa_offset_sf,
&DwarfCfa::cfa_val_offset,
&DwarfCfa::cfa_val_offset_sf,
&DwarfCfa::cfa_val_expression,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
&DwarfCfa::cfa_aarch64_negate_ra_state,
&DwarfCfa::cfa_nop,
&DwarfCfa::cfa_gnu_negative_offset_extended,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
};
};
}
#endif