brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 4acc064 Raw
167 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DWARFCFIChecker/DWARFCFIState.h"10#include "llvm/BinaryFormat/Dwarf.h"11#include "llvm/DebugInfo/DWARF/LowLevel/DWARFUnwindTable.h"12#include "llvm/MC/MCDwarf.h"13#include "llvm/Support/Error.h"14#include "llvm/Support/ErrorHandling.h"15#include "llvm/Support/FormatVariadic.h"16#include <cassert>17#include <optional>18 19using namespace llvm;20 21std::optional<dwarf::UnwindRow> DWARFCFIState::getCurrentUnwindRow() const {22  if (!IsInitiated)23    return std::nullopt;24  return Row;25}26 27void DWARFCFIState::update(const MCCFIInstruction &Directive) {28  auto CFIP = convert(Directive);29 30  // This is a copy of the current row, its value will be updated by31  // `parseRows`.32  dwarf::UnwindRow NewRow = Row;33 34  // `parseRows` updates the current row by applying the `CFIProgram` to it.35  // During this process, it may create multiple rows preceding the newly36  // updated row and following the previous rows. These middle rows are stored37  // in `PrecedingRows`. For now, there is no need to store these rows in the38  // state, so they are ignored in the end.39  dwarf::UnwindTable::RowContainer PrecedingRows;40 41  // TODO: `.cfi_remember_state` and `.cfi_restore_state` directives are not42  // supported yet. The reason is that `parseRows` expects the stack of states43  // to be produced and used in a single `CFIProgram`. However, in this use44  // case, each instruction creates its own `CFIProgram`, which means the stack45  // of states is forgotten between instructions. To fix it, `parseRows` should46  // be refactored to read the current stack of states from the argument and47  // update it based on the `CFIProgram.`48  if (Error Err = parseRows(CFIP, NewRow, nullptr).takeError()) {49    Context->reportError(50        Directive.getLoc(),51        formatv("could not parse this CFI directive due to: {0}",52                toString(std::move(Err))));53 54    // Proceed the analysis by ignoring this CFI directive.55    return;56  }57 58  Row = NewRow;59  IsInitiated = true;60}61 62dwarf::CFIProgram DWARFCFIState::convert(MCCFIInstruction Directive) {63  auto CFIP = dwarf::CFIProgram(64      /* CodeAlignmentFactor */ 1, /* DataAlignmentFactor */ 1,65      Context->getTargetTriple().getArch());66 67  switch (Directive.getOperation()) {68  case MCCFIInstruction::OpSameValue:69    CFIP.addInstruction(dwarf::DW_CFA_same_value, Directive.getRegister());70    break;71  case 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.77    Context->reportWarning(Directive.getLoc(),78                           "this directive is not supported, ignoring it");79    break;80  case 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.86    Context->reportWarning(Directive.getLoc(),87                           "this directive is not supported, ignoring it");88    break;89  case MCCFIInstruction::OpOffset:90    CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),91                        Directive.getOffset());92    break;93  case MCCFIInstruction::OpLLVMDefAspaceCfa:94    CFIP.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,95                        Directive.getRegister());96    break;97  case MCCFIInstruction::OpDefCfaRegister:98    CFIP.addInstruction(dwarf::DW_CFA_def_cfa_register,99                        Directive.getRegister());100    break;101  case MCCFIInstruction::OpDefCfaOffset:102    CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset, Directive.getOffset());103    break;104  case MCCFIInstruction::OpDefCfa:105    CFIP.addInstruction(dwarf::DW_CFA_def_cfa, Directive.getRegister(),106                        Directive.getOffset());107    break;108  case MCCFIInstruction::OpRelOffset:109    assert(110        IsInitiated &&111        "cannot define relative offset to a non-existing CFA unwinding rule");112 113    CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),114                        Directive.getOffset() - Row.getCFAValue().getOffset());115    break;116  case MCCFIInstruction::OpAdjustCfaOffset:117    assert(IsInitiated &&118           "cannot adjust CFA offset of a non-existing CFA unwinding rule");119 120    CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset,121                        Directive.getOffset() + Row.getCFAValue().getOffset());122    break;123  case MCCFIInstruction::OpEscape:124    // TODO: DWARFExpressions are not supported yet, ignoring expression here.125    Context->reportWarning(Directive.getLoc(),126                           "this directive is not supported, ignoring it");127    break;128  case 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.133    Context->reportWarning(134        Directive.getLoc(),135        "this directive behavior depends on the assembler, ignoring it");136    break;137  case MCCFIInstruction::OpUndefined:138    CFIP.addInstruction(dwarf::DW_CFA_undefined, Directive.getRegister());139    break;140  case MCCFIInstruction::OpRegister:141    CFIP.addInstruction(dwarf::DW_CFA_register, Directive.getRegister(),142                        Directive.getRegister2());143    break;144  case MCCFIInstruction::OpWindowSave:145    CFIP.addInstruction(dwarf::DW_CFA_GNU_window_save);146    break;147  case MCCFIInstruction::OpNegateRAState:148    CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);149    break;150  case MCCFIInstruction::OpNegateRAStateWithPC:151    CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);152    break;153  case MCCFIInstruction::OpGnuArgsSize:154    CFIP.addInstruction(dwarf::DW_CFA_GNU_args_size);155    break;156  case MCCFIInstruction::OpLabel:157    // `.cfi_label` does not have any functional effect on unwinding process.158    break;159  case MCCFIInstruction::OpValOffset:160    CFIP.addInstruction(dwarf::DW_CFA_val_offset, Directive.getRegister(),161                        Directive.getOffset());162    break;163  }164 165  return CFIP;166}167