186 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/DebugInfo/DWARF/DWARFUnwindTablePrinter.h"10#include "llvm/DebugInfo/DIContext.h"11#include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"12#include "llvm/Support/ErrorHandling.h"13#include "llvm/Support/Format.h"14#include "llvm/Support/raw_ostream.h"15#include <cassert>16#include <cinttypes>17#include <cstdint>18 19using namespace llvm;20using namespace dwarf;21 22static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts,23 unsigned RegNum) {24 if (DumpOpts.GetNameForDWARFReg) {25 auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH);26 if (!RegName.empty()) {27 OS << RegName;28 return;29 }30 }31 OS << "reg" << RegNum;32}33 34/// Print an unwind location expression as text and use the register information35/// if some is provided.36///37/// \param R the unwind location to print.38///39/// \param OS the stream to use for output.40///41/// \param MRI register information that helps emit register names insteead42/// of raw register numbers.43///44/// \param IsEH true if the DWARF Call Frame Information is from .eh_frame45/// instead of from .debug_frame. This is needed for register number46/// conversion because some register numbers differ between the two sections47/// for certain architectures like x86.48static void printUnwindLocation(const UnwindLocation &UL, raw_ostream &OS,49 DIDumpOptions DumpOpts) {50 if (UL.getDereference())51 OS << '[';52 switch (UL.getLocation()) {53 case UnwindLocation::Unspecified:54 OS << "unspecified";55 break;56 case UnwindLocation::Undefined:57 OS << "undefined";58 break;59 case UnwindLocation::Same:60 OS << "same";61 break;62 case UnwindLocation::CFAPlusOffset:63 OS << "CFA";64 if (UL.getOffset() == 0)65 break;66 if (UL.getOffset() > 0)67 OS << "+";68 OS << UL.getOffset();69 break;70 case UnwindLocation::RegPlusOffset:71 printRegister(OS, DumpOpts, UL.getRegister());72 if (UL.getOffset() == 0 && !UL.hasAddressSpace())73 break;74 if (UL.getOffset() >= 0)75 OS << "+";76 OS << UL.getOffset();77 if (UL.hasAddressSpace())78 OS << " in addrspace" << UL.getAddressSpace();79 break;80 case UnwindLocation::DWARFExpr: {81 if (UL.getDWARFExpressionBytes()) {82 auto Expr = *UL.getDWARFExpressionBytes();83 printDwarfExpression(&Expr, OS, DumpOpts, nullptr);84 }85 break;86 }87 case UnwindLocation::Constant:88 OS << UL.getOffset();89 break;90 }91 if (UL.getDereference())92 OS << ']';93}94 95raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,96 const UnwindLocation &UL) {97 auto DumpOpts = DIDumpOptions();98 printUnwindLocation(UL, OS, DumpOpts);99 return OS;100}101 102/// Print all registers + locations that are currently defined in a register103/// locations.104///105/// \param RL the register locations to print.106///107/// \param OS the stream to use for output.108///109/// \param MRI register information that helps emit register names insteead110/// of raw register numbers.111///112/// \param IsEH true if the DWARF Call Frame Information is from .eh_frame113/// instead of from .debug_frame. This is needed for register number114/// conversion because some register numbers differ between the two sections115/// for certain architectures like x86.116static void printRegisterLocations(const RegisterLocations &RL, raw_ostream &OS,117 DIDumpOptions DumpOpts) {118 bool First = true;119 for (uint32_t Reg : RL.getRegisters()) {120 auto Loc = *RL.getRegisterLocation(Reg);121 if (First)122 First = false;123 else124 OS << ", ";125 printRegister(OS, DumpOpts, Reg);126 OS << '=';127 printUnwindLocation(Loc, OS, DumpOpts);128 }129}130 131raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,132 const RegisterLocations &RL) {133 auto DumpOpts = DIDumpOptions();134 printRegisterLocations(RL, OS, DumpOpts);135 return OS;136}137 138/// Print an UnwindRow to the stream.139///140/// \param Row the UnwindRow to print.141///142/// \param OS the stream to use for output.143///144/// \param MRI register information that helps emit register names insteead145/// of raw register numbers.146///147/// \param IsEH true if the DWARF Call Frame Information is from .eh_frame148/// instead of from .debug_frame. This is needed for register number149/// conversion because some register numbers differ between the two sections150/// for certain architectures like x86.151///152/// \param IndentLevel specify the indent level as an integer. The UnwindRow153/// will be output to the stream preceded by 2 * IndentLevel number of spaces.154static void printUnwindRow(const UnwindRow &Row, raw_ostream &OS,155 DIDumpOptions DumpOpts, unsigned IndentLevel) {156 OS.indent(2 * IndentLevel);157 if (Row.hasAddress())158 OS << format("0x%" PRIx64 ": ", Row.getAddress());159 OS << "CFA=";160 printUnwindLocation(Row.getCFAValue(), OS, DumpOpts);161 if (Row.getRegisterLocations().hasLocations()) {162 OS << ": ";163 printRegisterLocations(Row.getRegisterLocations(), OS, DumpOpts);164 }165 OS << "\n";166}167 168raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) {169 auto DumpOpts = DIDumpOptions();170 printUnwindRow(Row, OS, DumpOpts, 0);171 return OS;172}173 174void llvm::dwarf::printUnwindTable(const UnwindTable &Rows, raw_ostream &OS,175 DIDumpOptions DumpOpts,176 unsigned IndentLevel) {177 for (const UnwindRow &Row : Rows)178 printUnwindRow(Row, OS, DumpOpts, IndentLevel);179}180 181raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) {182 auto DumpOpts = DIDumpOptions();183 printUnwindTable(Rows, OS, DumpOpts, 0);184 return OS;185}186