DWARFDebugFrame.cpp revision 7bf3d6a0438485df61c438f26cfbaef2f8d8a3c4
160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===//
260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky//
360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky//                     The LLVM Compiler Infrastructure
460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky//
560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky// This file is distributed under the University of Illinois Open Source
660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky// License. See LICENSE.TXT for details.
760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky//
860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky//===----------------------------------------------------------------------===//
960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
1060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky#include "DWARFDebugFrame.h"
1160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky#include "llvm/ADT/SmallString.h"
1260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky#include "llvm/Support/DataTypes.h"
137bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky#include "llvm/Support/ErrorHandling.h"
1460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky#include "llvm/Support/Dwarf.h"
1560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky#include "llvm/Support/Format.h"
167bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky#include "llvm/Support/raw_ostream.h"
177bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky#include <string>
187bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky#include <vector>
1960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
2060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyusing namespace llvm;
2160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyusing namespace dwarf;
2260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
2360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
242e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky/// \brief Abstract frame entry defining the common interface concrete
252e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky/// entries implement.
2660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyclass llvm::FrameEntry {
2760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskypublic:
2860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  enum FrameKind {FK_CIE, FK_FDE};
2960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length)
30ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky    : Kind(K), Data(D), Offset(Offset), Length(Length) {}
3160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
328a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky  virtual ~FrameEntry() {
338a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky  }
348a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky
3560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  FrameKind getKind() const { return Kind; }
367bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  virtual uint64_t getOffset() const { return Offset; }
3760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
387bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// \brief Parse and store a sequence of CFI instructions from our data
397bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// stream, starting at Offset and ending at EndOffset. If everything
407bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// goes well, Offset should be equal to EndOffset when this method
417bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// returns. Otherwise, an error occurred.
427bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// TODO: Improve error reporting...
437bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  virtual void parseInstructions(uint32_t &Offset, uint32_t EndOffset);
447bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
457bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// \brief Dump the entry header to the given output stream.
4660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  virtual void dumpHeader(raw_ostream &OS) const = 0;
47ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky
487bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// \brief Dump the entry's instructions to the given output stream.
497bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  virtual void dumpInstructions(raw_ostream &OS) const;
507bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
5160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyprotected:
5260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  const FrameKind Kind;
53ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky
54ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky  /// \brief The data stream holding the section from which the entry was
55ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky  /// parsed.
5660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  DataExtractor Data;
57ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky
58ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky  /// \brief Offset of this entry in the section.
5960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint64_t Offset;
60ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky
61ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky  /// \brief Entry length as specified in DWARF.
6260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint64_t Length;
637bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
647bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// An entry may contain CFI instructions. An instruction consists of an
657bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// opcode and an optional sequence of operands.
667bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  typedef std::vector<uint64_t> Operands;
677bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  struct Instruction {
687bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Instruction(uint8_t Opcode)
697bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      : Opcode(Opcode)
707bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    {}
717bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
727bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    uint8_t Opcode;
737bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Operands Ops;
747bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  };
757bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
767bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  std::vector<Instruction> Instructions;
777bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
787bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// Convenience methods to add a new instruction with the given opcode and
797bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  /// operands to the Instructions vector.
807bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  void addInstruction(uint8_t Opcode) {
817bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Instructions.push_back(Instruction(Opcode));
827bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  }
837bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
847bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  void addInstruction(uint8_t Opcode, uint64_t Operand1) {
857bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Instructions.push_back(Instruction(Opcode));
867bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Instructions.back().Ops.push_back(Operand1);
877bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  }
887bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
897bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
907bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Instructions.push_back(Instruction(Opcode));
917bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Instructions.back().Ops.push_back(Operand1);
927bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Instructions.back().Ops.push_back(Operand2);
937bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  }
9460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky};
9560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
967bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
977bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky// See DWARF standard v3, section 7.23
987bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Benderskyconst uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
997bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Benderskyconst uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
1007bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
1017bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
1027bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Benderskyvoid FrameEntry::parseInstructions(uint32_t &Offset, uint32_t EndOffset) {
1037bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  while (Offset < EndOffset) {
1047bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    uint8_t Opcode = Data.getU8(&Offset);
1057bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    // Some instructions have a primary opcode encoded in the top bits.
1067bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK;
1077bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
1087bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    if (Primary) {
1097bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      // If it's a primary opcode, the first operand is encoded in the bottom
1107bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      // bits of the opcode itself.
1117bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
1127bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      switch (Primary) {
1137bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        default: llvm_unreachable("Impossible primary CFI opcode");
1147bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_advance_loc:
1157bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_restore:
1167bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Primary, Op1);
1177bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1187bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_offset:
1197bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Primary, Op1, Data.getULEB128(&Offset));
1207bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1217bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      }
1227bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    } else {
1237bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      // Extended opcode - its value is Opcode itself.
1247bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      switch (Opcode) {
1257bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        default: llvm_unreachable("Invalid extended CFI opcode");
1267bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_nop:
1277bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_remember_state:
1287bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_restore_state:
1297bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // No operands
1307bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode);
1317bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1327bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_set_loc:
1337bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: Address
1347bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getAddress(&Offset));
1357bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1367bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_advance_loc1:
1377bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: 1-byte delta
1387bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getU8(&Offset));
1397bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1407bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_advance_loc2:
1417bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: 2-byte delta
1427bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getU16(&Offset));
1437bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1447bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_advance_loc4:
1457bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: 4-byte delta
1467bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getU32(&Offset));
1477bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1487bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_restore_extended:
1497bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_undefined:
1507bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_same_value:
1517bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_def_cfa_register:
1527bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_def_cfa_offset:
1537bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: ULEB128
1547bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getULEB128(&Offset));
1557bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1567bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_def_cfa_offset_sf:
1577bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: SLEB128
1587bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getSLEB128(&Offset));
1597bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1607bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_offset_extended:
1617bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_register:
1627bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_def_cfa:
1637bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_val_offset:
1647bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: ULEB128, ULEB128
1657bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getULEB128(&Offset),
1667bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky                                 Data.getULEB128(&Offset));
1677bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1687bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_offset_extended_sf:
1697bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_def_cfa_sf:
1707bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_val_offset_sf:
1717bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // Operands: ULEB128, SLEB128
1727bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          addInstruction(Opcode, Data.getULEB128(&Offset),
1737bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky                                 Data.getSLEB128(&Offset));
1747bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          break;
1757bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_def_cfa_expression:
1767bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_expression:
1777bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky        case DW_CFA_val_expression:
1787bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          // TODO: implement this
1797bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky          report_fatal_error("Values with expressions not implemented yet!");
1807bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      }
1817bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    }
1827bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  }
1837bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky}
1847bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
1857bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
1867bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Benderskyvoid FrameEntry::dumpInstructions(raw_ostream &OS) const {
1877bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  // TODO: at the moment only instruction names are dumped. Expand this to
1887bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  // dump operands as well.
1897bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  for (std::vector<Instruction>::const_iterator I = Instructions.begin(),
1907bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky                                                E = Instructions.end();
1917bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky       I != E; ++I) {
1927bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    uint8_t Opcode = I->Opcode;
1937bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
1947bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
1957bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    OS << "  " << CallFrameString(Opcode) << ":\n";
1967bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky  }
1977bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky}
1987bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
1997bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
20074b3c8da4800c7e8ba8f019879db29738ecc5f74Benjamin Kramernamespace {
2012e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky/// \brief DWARF Common Information Entry (CIE)
20260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyclass CIE : public FrameEntry {
20360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskypublic:
20460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  // CIEs (and FDEs) are simply container classes, so the only sensible way to
20560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  // create them is by providing the full parsed contents in the constructor.
20660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version,
20760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      SmallString<8> Augmentation, uint64_t CodeAlignmentFactor,
20860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
20960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky   : FrameEntry(FK_CIE, D, Offset, Length), Version(Version),
21060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor),
21160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     DataAlignmentFactor(DataAlignmentFactor),
212ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky     ReturnAddressRegister(ReturnAddressRegister) {}
21360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
2148a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky  ~CIE() {
2158a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky  }
2168a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky
21760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  void dumpHeader(raw_ostream &OS) const {
21890e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi    OS << format("%08x %08x %08x CIE",
21990e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi                 (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID)
22090e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi       << "\n";
22160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    OS << format("  Version:               %d\n", Version);
22260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    OS << "  Augmentation:          \"" << Augmentation << "\"\n";
2237bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    OS << format("  Code alignment factor: %u\n",
2247bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky                 (uint32_t)CodeAlignmentFactor);
2257bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    OS << format("  Data alignment factor: %d\n",
2267bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky                 (int32_t)DataAlignmentFactor);
2277bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    OS << format("  Return address column: %d\n",
2287bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky                 (int32_t)ReturnAddressRegister);
22960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    OS << "\n";
23060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
23160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
23260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  static bool classof(const FrameEntry *FE) {
23360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    return FE->getKind() == FK_CIE;
23460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
235ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky
23660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyprivate:
237ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
23860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint8_t Version;
23960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  SmallString<8> Augmentation;
24060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint64_t CodeAlignmentFactor;
24160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  int64_t DataAlignmentFactor;
24260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint64_t ReturnAddressRegister;
24360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky};
24460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
24560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
2462e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky/// \brief DWARF Frame Description Entry (FDE)
24760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyclass FDE : public FrameEntry {
24860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskypublic:
24960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
25060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
25160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  // is obtained lazily once it's actually required.
252ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky  FDE(DataExtractor D, uint64_t Offset, uint64_t Length,
253ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky      int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange)
25460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky   : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
25560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     InitialLocation(InitialLocation), AddressRange(AddressRange),
256ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky     LinkedCIE(NULL) {}
25760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
2588a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky  ~FDE() {
2598a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky  }
2608a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky
26160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  void dumpHeader(raw_ostream &OS) const {
26290e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi    OS << format("%08x %08x %08x FDE ",
263d9a8d43ed3e7c6c32f52ab5d0f627f7b1cdb6aacNAKAMURA Takumi                 (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset);
26460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    OS << format("cie=%08x pc=%08x...%08x\n",
265d9a8d43ed3e7c6c32f52ab5d0f627f7b1cdb6aacNAKAMURA Takumi                 (int32_t)LinkedCIEOffset,
2668ff0631967c64d51b193b862aa0a6f1e8eb06f78NAKAMURA Takumi                 (uint32_t)InitialLocation,
2678ff0631967c64d51b193b862aa0a6f1e8eb06f78NAKAMURA Takumi                 (uint32_t)InitialLocation + (uint32_t)AddressRange);
268b2ac7c09b17efadea2a9f90f45801d9d2ee687aaEli Bendersky    if (LinkedCIE) {
269b2ac7c09b17efadea2a9f90f45801d9d2ee687aaEli Bendersky      OS << format("%p\n", LinkedCIE);
270b2ac7c09b17efadea2a9f90f45801d9d2ee687aaEli Bendersky    }
27160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
27260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
27360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  static bool classof(const FrameEntry *FE) {
27460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    return FE->getKind() == FK_FDE;
27560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
27660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyprivate:
277ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky
278ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
27960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint64_t LinkedCIEOffset;
28060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint64_t InitialLocation;
28160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint64_t AddressRange;
28260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  CIE *LinkedCIE;
28360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky};
28474b3c8da4800c7e8ba8f019879db29738ecc5f74Benjamin Kramer} // end anonymous namespace
28560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
28660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
287ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli BenderskyDWARFDebugFrame::DWARFDebugFrame() {
28860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
28960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
29060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
291ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli BenderskyDWARFDebugFrame::~DWARFDebugFrame() {
29260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  for (EntryVector::iterator I = Entries.begin(), E = Entries.end();
29360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky       I != E; ++I) {
29460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    delete *I;
29560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
29660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
29760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
29860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
29960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskystatic void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
30060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky                                              uint32_t Offset, int Length) {
30160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  errs() << "DUMP: ";
30260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  for (int i = 0; i < Length; ++i) {
30360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    uint8_t c = Data.getU8(&Offset);
30460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    errs().write_hex(c); errs() << " ";
30560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
30660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  errs() << "\n";
30760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
30860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
30960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
31060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyvoid DWARFDebugFrame::parse(DataExtractor Data) {
31160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  uint32_t Offset = 0;
31260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
31360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  while (Data.isValidOffset(Offset)) {
31460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    uint32_t StartOffset = Offset;
31560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
31660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    bool IsDWARF64 = false;
31760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    uint64_t Length = Data.getU32(&Offset);
31860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    uint64_t Id;
31960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
32060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (Length == UINT32_MAX) {
32160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      // DWARF-64 is distinguished by the first 32 bits of the initial length
32260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      // field being 0xffffffff. Then, the next 64 bits are the actual entry
32360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      // length.
32460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      IsDWARF64 = true;
32560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      Length = Data.getU64(&Offset);
32660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
32760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
32860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    // At this point, Offset points to the next field after Length.
32960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    // Length is the structure size excluding itself. Compute an offset one
33060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    // past the end of the structure (needed to know how many instructions to
33160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    // read).
33260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    // TODO: For honest DWARF64 support, DataExtractor will have to treat
33360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    //       offset_ptr as uint64_t*
33460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);
33560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
33660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    // The Id field's size depends on the DWARF format
33760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
33860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);
33960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
34060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (IsCIE) {
34160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      // Note: this is specifically DWARFv3 CIE header structure. It was
34260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      // changed in DWARFv4.
34360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      uint8_t Version = Data.getU8(&Offset);
34460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      const char *Augmentation = Data.getCStr(&Offset);
34560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
34660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
34760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);
34860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
34960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      CIE *NewCIE = new CIE(Data, StartOffset, Length, Version,
35060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky                            StringRef(Augmentation), CodeAlignmentFactor,
35160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky                            DataAlignmentFactor, ReturnAddressRegister);
35260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      Entries.push_back(NewCIE);
35360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    } else {
35460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      // FDE
35560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      uint64_t CIEPointer = Id;
35660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      uint64_t InitialLocation = Data.getAddress(&Offset);
35760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      uint64_t AddressRange = Data.getAddress(&Offset);
35860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
35960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      FDE *NewFDE = new FDE(Data, StartOffset, Length, CIEPointer,
36060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky                            InitialLocation, AddressRange);
36160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky      Entries.push_back(NewFDE);
36260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
36360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
3647bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Entries.back()->parseInstructions(Offset, EndStructureOffset);
3657bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky
3667bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    if (Offset != EndStructureOffset) {
3677bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      std::string Str;
3687bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      raw_string_ostream OS(Str);
3697bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      OS << format("Parsing entry instructions at %lx failed",
3707bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky                   Entries.back()->getOffset());
3717bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky      report_fatal_error(Str);
3727bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    }
37360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
37460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
37560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
37660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
37760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyvoid DWARFDebugFrame::dump(raw_ostream &OS) const {
37860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  OS << "\n";
37960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end();
38060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky       I != E; ++I) {
3817bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    FrameEntry *Entry = *I;
3827bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Entry->dumpHeader(OS);
3837bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    Entry->dumpInstructions(OS);
3847bf3d6a0438485df61c438f26cfbaef2f8d8a3c4Eli Bendersky    OS << "\n";
38560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky  }
38660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
38760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
388