Path: blob/main/contrib/llvm-project/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp
213766 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DWARFCFIChecker/DWARFCFIState.h"9#include "llvm/BinaryFormat/Dwarf.h"10#include "llvm/DebugInfo/DWARF/LowLevel/DWARFUnwindTable.h"11#include "llvm/MC/MCDwarf.h"12#include "llvm/Support/Error.h"13#include "llvm/Support/ErrorHandling.h"14#include "llvm/Support/FormatVariadic.h"15#include <cassert>16#include <optional>1718using namespace llvm;1920std::optional<dwarf::UnwindRow> DWARFCFIState::getCurrentUnwindRow() const {21if (!IsInitiated)22return std::nullopt;23return Row;24}2526void DWARFCFIState::update(const MCCFIInstruction &Directive) {27auto CFIP = convert(Directive);2829// This is a copy of the current row, its value will be updated by30// `parseRows`.31dwarf::UnwindRow NewRow = Row;3233// `parseRows` updates the current row by applying the `CFIProgram` to it.34// During this process, it may create multiple rows preceding the newly35// updated row and following the previous rows. These middle rows are stored36// in `PrecedingRows`. For now, there is no need to store these rows in the37// state, so they are ignored in the end.38dwarf::UnwindTable::RowContainer PrecedingRows;3940// TODO: `.cfi_remember_state` and `.cfi_restore_state` directives are not41// supported yet. The reason is that `parseRows` expects the stack of states42// to be produced and used in a single `CFIProgram`. However, in this use43// case, each instruction creates its own `CFIProgram`, which means the stack44// of states is forgotten between instructions. To fix it, `parseRows` should45// be refactored to read the current stack of states from the argument and46// update it based on the `CFIProgram.`47if (Error Err = parseRows(CFIP, NewRow, nullptr).takeError()) {48Context->reportError(49Directive.getLoc(),50formatv("could not parse this CFI directive due to: {0}",51toString(std::move(Err))));5253// Proceed the analysis by ignoring this CFI directive.54return;55}5657Row = NewRow;58IsInitiated = true;59}6061dwarf::CFIProgram DWARFCFIState::convert(MCCFIInstruction Directive) {62auto CFIP = dwarf::CFIProgram(63/* CodeAlignmentFactor */ 1, /* DataAlignmentFactor */ 1,64Context->getTargetTriple().getArch());6566auto MaybeCurrentRow = getCurrentUnwindRow();67switch (Directive.getOperation()) {68case MCCFIInstruction::OpSameValue:69CFIP.addInstruction(dwarf::DW_CFA_same_value, Directive.getRegister());70break;71case MCCFIInstruction::OpRememberState:72// TODO: remember state is not supported yet, the following line does not73// work:74// CFIP.addInstruction(dwarf::DW_CFA_remember_state);75// The reason is explained in the `DWARFCFIState::update` method where76// `dwarf::parseRows` is used.77Context->reportWarning(Directive.getLoc(),78"this directive is not supported, ignoring it");79break;80case MCCFIInstruction::OpRestoreState:81// TODO: restore state is not supported yet, the following line does not82// work:83// CFIP.addInstruction(dwarf::DW_CFA_restore_state);84// The reason is explained in the `DWARFCFIState::update` method where85// `dwarf::parseRows` is used.86Context->reportWarning(Directive.getLoc(),87"this directive is not supported, ignoring it");88break;89case MCCFIInstruction::OpOffset:90CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),91Directive.getOffset());92break;93case MCCFIInstruction::OpLLVMDefAspaceCfa:94CFIP.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,95Directive.getRegister());96break;97case MCCFIInstruction::OpDefCfaRegister:98CFIP.addInstruction(dwarf::DW_CFA_def_cfa_register,99Directive.getRegister());100break;101case MCCFIInstruction::OpDefCfaOffset:102CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset, Directive.getOffset());103break;104case MCCFIInstruction::OpDefCfa:105CFIP.addInstruction(dwarf::DW_CFA_def_cfa, Directive.getRegister(),106Directive.getOffset());107break;108case MCCFIInstruction::OpRelOffset:109assert(110IsInitiated &&111"cannot define relative offset to a non-existing CFA unwinding rule");112113CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),114Directive.getOffset() - Row.getCFAValue().getOffset());115break;116case MCCFIInstruction::OpAdjustCfaOffset:117assert(IsInitiated &&118"cannot adjust CFA offset of a non-existing CFA unwinding rule");119120CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset,121Directive.getOffset() + Row.getCFAValue().getOffset());122break;123case MCCFIInstruction::OpEscape:124// TODO: DWARFExpressions are not supported yet, ignoring expression here.125Context->reportWarning(Directive.getLoc(),126"this directive is not supported, ignoring it");127break;128case MCCFIInstruction::OpRestore:129// The `.cfi_restore register` directive restores the register's unwinding130// information to its CIE value. However, assemblers decide where CIE ends131// and the FDE starts, so the functionality of this directive depends on the132// assembler's decision and cannot be validated.133Context->reportWarning(134Directive.getLoc(),135"this directive behavior depends on the assembler, ignoring it");136break;137case MCCFIInstruction::OpUndefined:138CFIP.addInstruction(dwarf::DW_CFA_undefined, Directive.getRegister());139break;140case MCCFIInstruction::OpRegister:141CFIP.addInstruction(dwarf::DW_CFA_register, Directive.getRegister(),142Directive.getRegister2());143break;144case MCCFIInstruction::OpWindowSave:145CFIP.addInstruction(dwarf::DW_CFA_GNU_window_save);146break;147case MCCFIInstruction::OpNegateRAState:148CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);149break;150case MCCFIInstruction::OpNegateRAStateWithPC:151CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);152break;153case MCCFIInstruction::OpGnuArgsSize:154CFIP.addInstruction(dwarf::DW_CFA_GNU_args_size);155break;156case MCCFIInstruction::OpLabel:157// `.cfi_label` does not have any functional effect on unwinding process.158break;159case MCCFIInstruction::OpValOffset:160CFIP.addInstruction(dwarf::DW_CFA_val_offset, Directive.getRegister(),161Directive.getOffset());162break;163}164165return CFIP;166}167168169