181ad6265SDimitry Andric //===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric
981ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
1081ad6265SDimitry Andric
1181ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
1281ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
1381ad6265SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
1481ad6265SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1581ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
1681ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InputFile.h"
1781ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
1881ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
1981ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/UDTLayout.h"
2081ad6265SDimitry Andric #include "llvm/Object/COFF.h"
2181ad6265SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
2281ad6265SDimitry Andric #include "llvm/Support/Format.h"
2381ad6265SDimitry Andric #include "llvm/Support/FormatAdapters.h"
2481ad6265SDimitry Andric #include "llvm/Support/FormatVariadic.h"
2581ad6265SDimitry Andric #include "llvm/Support/Regex.h"
2681ad6265SDimitry Andric
2781ad6265SDimitry Andric #include <algorithm>
2881ad6265SDimitry Andric
2981ad6265SDimitry Andric using namespace llvm;
3081ad6265SDimitry Andric using namespace llvm::msf;
3181ad6265SDimitry Andric using namespace llvm::pdb;
3281ad6265SDimitry Andric
3381ad6265SDimitry Andric namespace {
IsItemExcluded(llvm::StringRef Item,std::list<llvm::Regex> & IncludeFilters,std::list<llvm::Regex> & ExcludeFilters)3481ad6265SDimitry Andric bool IsItemExcluded(llvm::StringRef Item,
3581ad6265SDimitry Andric std::list<llvm::Regex> &IncludeFilters,
3681ad6265SDimitry Andric std::list<llvm::Regex> &ExcludeFilters) {
3781ad6265SDimitry Andric if (Item.empty())
3881ad6265SDimitry Andric return false;
3981ad6265SDimitry Andric
4081ad6265SDimitry Andric auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };
4181ad6265SDimitry Andric
4281ad6265SDimitry Andric // Include takes priority over exclude. If the user specified include
4381ad6265SDimitry Andric // filters, and none of them include this item, them item is gone.
4481ad6265SDimitry Andric if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
4581ad6265SDimitry Andric return true;
4681ad6265SDimitry Andric
4781ad6265SDimitry Andric if (any_of(ExcludeFilters, match_pred))
4881ad6265SDimitry Andric return true;
4981ad6265SDimitry Andric
5081ad6265SDimitry Andric return false;
5181ad6265SDimitry Andric }
5281ad6265SDimitry Andric } // namespace
5381ad6265SDimitry Andric
5481ad6265SDimitry Andric using namespace llvm;
5581ad6265SDimitry Andric
LinePrinter(int Indent,bool UseColor,llvm::raw_ostream & Stream,const FilterOptions & Filters)5681ad6265SDimitry Andric LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream,
5781ad6265SDimitry Andric const FilterOptions &Filters)
5881ad6265SDimitry Andric : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor),
5981ad6265SDimitry Andric Filters(Filters) {
6081ad6265SDimitry Andric SetFilters(ExcludeTypeFilters, Filters.ExcludeTypes.begin(),
6181ad6265SDimitry Andric Filters.ExcludeTypes.end());
6281ad6265SDimitry Andric SetFilters(ExcludeSymbolFilters, Filters.ExcludeSymbols.begin(),
6381ad6265SDimitry Andric Filters.ExcludeSymbols.end());
6481ad6265SDimitry Andric SetFilters(ExcludeCompilandFilters, Filters.ExcludeCompilands.begin(),
6581ad6265SDimitry Andric Filters.ExcludeCompilands.end());
6681ad6265SDimitry Andric
6781ad6265SDimitry Andric SetFilters(IncludeTypeFilters, Filters.IncludeTypes.begin(),
6881ad6265SDimitry Andric Filters.IncludeTypes.end());
6981ad6265SDimitry Andric SetFilters(IncludeSymbolFilters, Filters.IncludeSymbols.begin(),
7081ad6265SDimitry Andric Filters.IncludeSymbols.end());
7181ad6265SDimitry Andric SetFilters(IncludeCompilandFilters, Filters.IncludeCompilands.begin(),
7281ad6265SDimitry Andric Filters.IncludeCompilands.end());
7381ad6265SDimitry Andric }
7481ad6265SDimitry Andric
Indent(uint32_t Amount)7581ad6265SDimitry Andric void LinePrinter::Indent(uint32_t Amount) {
7681ad6265SDimitry Andric if (Amount == 0)
7781ad6265SDimitry Andric Amount = IndentSpaces;
7881ad6265SDimitry Andric CurrentIndent += Amount;
7981ad6265SDimitry Andric }
8081ad6265SDimitry Andric
Unindent(uint32_t Amount)8181ad6265SDimitry Andric void LinePrinter::Unindent(uint32_t Amount) {
8281ad6265SDimitry Andric if (Amount == 0)
8381ad6265SDimitry Andric Amount = IndentSpaces;
8481ad6265SDimitry Andric CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
8581ad6265SDimitry Andric }
8681ad6265SDimitry Andric
NewLine()8781ad6265SDimitry Andric void LinePrinter::NewLine() {
8881ad6265SDimitry Andric OS << "\n";
8981ad6265SDimitry Andric OS.indent(CurrentIndent);
9081ad6265SDimitry Andric }
9181ad6265SDimitry Andric
print(const Twine & T)9281ad6265SDimitry Andric void LinePrinter::print(const Twine &T) { OS << T; }
9381ad6265SDimitry Andric
printLine(const Twine & T)9481ad6265SDimitry Andric void LinePrinter::printLine(const Twine &T) {
9581ad6265SDimitry Andric NewLine();
9681ad6265SDimitry Andric OS << T;
9781ad6265SDimitry Andric }
9881ad6265SDimitry Andric
IsClassExcluded(const ClassLayout & Class)9981ad6265SDimitry Andric bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
10081ad6265SDimitry Andric if (IsTypeExcluded(Class.getName(), Class.getSize()))
10181ad6265SDimitry Andric return true;
10281ad6265SDimitry Andric if (Class.deepPaddingSize() < Filters.PaddingThreshold)
10381ad6265SDimitry Andric return true;
10481ad6265SDimitry Andric return false;
10581ad6265SDimitry Andric }
10681ad6265SDimitry Andric
formatBinary(StringRef Label,ArrayRef<uint8_t> Data,uint64_t StartOffset)10781ad6265SDimitry Andric void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
10881ad6265SDimitry Andric uint64_t StartOffset) {
10981ad6265SDimitry Andric NewLine();
11081ad6265SDimitry Andric OS << Label << " (";
11181ad6265SDimitry Andric if (!Data.empty()) {
11281ad6265SDimitry Andric OS << "\n";
11381ad6265SDimitry Andric OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
11481ad6265SDimitry Andric CurrentIndent + IndentSpaces, true);
11581ad6265SDimitry Andric NewLine();
11681ad6265SDimitry Andric }
11781ad6265SDimitry Andric OS << ")";
11881ad6265SDimitry Andric }
11981ad6265SDimitry Andric
formatBinary(StringRef Label,ArrayRef<uint8_t> Data,uint64_t Base,uint64_t StartOffset)12081ad6265SDimitry Andric void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
12181ad6265SDimitry Andric uint64_t Base, uint64_t StartOffset) {
12281ad6265SDimitry Andric NewLine();
12381ad6265SDimitry Andric OS << Label << " (";
12481ad6265SDimitry Andric if (!Data.empty()) {
12581ad6265SDimitry Andric OS << "\n";
12681ad6265SDimitry Andric Base += StartOffset;
12781ad6265SDimitry Andric OS << format_bytes_with_ascii(Data, Base, 32, 4,
12881ad6265SDimitry Andric CurrentIndent + IndentSpaces, true);
12981ad6265SDimitry Andric NewLine();
13081ad6265SDimitry Andric }
13181ad6265SDimitry Andric OS << ")";
13281ad6265SDimitry Andric }
13381ad6265SDimitry Andric
13481ad6265SDimitry Andric namespace {
13581ad6265SDimitry Andric struct Run {
13681ad6265SDimitry Andric Run() = default;
Run__anonac747d6b0311::Run13781ad6265SDimitry Andric explicit Run(uint32_t Block) : Block(Block) {}
13881ad6265SDimitry Andric uint32_t Block = 0;
13981ad6265SDimitry Andric uint64_t ByteLen = 0;
14081ad6265SDimitry Andric };
14181ad6265SDimitry Andric } // namespace
14281ad6265SDimitry Andric
computeBlockRuns(uint32_t BlockSize,const msf::MSFStreamLayout & Layout)14381ad6265SDimitry Andric static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
14481ad6265SDimitry Andric const msf::MSFStreamLayout &Layout) {
14581ad6265SDimitry Andric std::vector<Run> Runs;
14681ad6265SDimitry Andric if (Layout.Length == 0)
14781ad6265SDimitry Andric return Runs;
14881ad6265SDimitry Andric
14981ad6265SDimitry Andric ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
15081ad6265SDimitry Andric assert(!Blocks.empty());
15181ad6265SDimitry Andric uint64_t StreamBytesRemaining = Layout.Length;
15281ad6265SDimitry Andric uint32_t CurrentBlock = Blocks[0];
15381ad6265SDimitry Andric Runs.emplace_back(CurrentBlock);
15481ad6265SDimitry Andric while (!Blocks.empty()) {
15581ad6265SDimitry Andric Run *CurrentRun = &Runs.back();
15681ad6265SDimitry Andric uint32_t NextBlock = Blocks.front();
15781ad6265SDimitry Andric if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
15881ad6265SDimitry Andric Runs.emplace_back(NextBlock);
15981ad6265SDimitry Andric CurrentRun = &Runs.back();
16081ad6265SDimitry Andric }
16181ad6265SDimitry Andric uint64_t Used =
16281ad6265SDimitry Andric std::min(static_cast<uint64_t>(BlockSize), StreamBytesRemaining);
16381ad6265SDimitry Andric CurrentRun->ByteLen += Used;
16481ad6265SDimitry Andric StreamBytesRemaining -= Used;
16581ad6265SDimitry Andric CurrentBlock = NextBlock;
16681ad6265SDimitry Andric Blocks = Blocks.drop_front();
16781ad6265SDimitry Andric }
16881ad6265SDimitry Andric return Runs;
16981ad6265SDimitry Andric }
17081ad6265SDimitry Andric
findRun(uint64_t Offset,ArrayRef<Run> Runs)17181ad6265SDimitry Andric static std::pair<Run, uint64_t> findRun(uint64_t Offset, ArrayRef<Run> Runs) {
17281ad6265SDimitry Andric for (const auto &R : Runs) {
17381ad6265SDimitry Andric if (Offset < R.ByteLen)
17481ad6265SDimitry Andric return std::make_pair(R, Offset);
17581ad6265SDimitry Andric Offset -= R.ByteLen;
17681ad6265SDimitry Andric }
17781ad6265SDimitry Andric llvm_unreachable("Invalid offset!");
17881ad6265SDimitry Andric }
17981ad6265SDimitry Andric
formatMsfStreamData(StringRef Label,PDBFile & File,uint32_t StreamIdx,StringRef StreamPurpose,uint64_t Offset,uint64_t Size)18081ad6265SDimitry Andric void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
18181ad6265SDimitry Andric uint32_t StreamIdx,
18281ad6265SDimitry Andric StringRef StreamPurpose, uint64_t Offset,
18381ad6265SDimitry Andric uint64_t Size) {
18481ad6265SDimitry Andric if (StreamIdx >= File.getNumStreams()) {
18581ad6265SDimitry Andric formatLine("Stream {0}: Not present", StreamIdx);
18681ad6265SDimitry Andric return;
18781ad6265SDimitry Andric }
18881ad6265SDimitry Andric if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
18981ad6265SDimitry Andric formatLine(
19081ad6265SDimitry Andric "Stream {0}: Invalid offset and size, range out of stream bounds",
19181ad6265SDimitry Andric StreamIdx);
19281ad6265SDimitry Andric return;
19381ad6265SDimitry Andric }
19481ad6265SDimitry Andric
19581ad6265SDimitry Andric auto S = File.createIndexedStream(StreamIdx);
19681ad6265SDimitry Andric if (!S) {
19781ad6265SDimitry Andric NewLine();
19881ad6265SDimitry Andric formatLine("Stream {0}: Not present", StreamIdx);
19981ad6265SDimitry Andric return;
20081ad6265SDimitry Andric }
20181ad6265SDimitry Andric
20281ad6265SDimitry Andric uint64_t End =
20381ad6265SDimitry Andric (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
20481ad6265SDimitry Andric Size = End - Offset;
20581ad6265SDimitry Andric
20681ad6265SDimitry Andric formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
20781ad6265SDimitry Andric StreamPurpose, Size, S->getLength());
20881ad6265SDimitry Andric AutoIndent Indent(*this);
20981ad6265SDimitry Andric BinaryStreamRef Slice(*S);
21081ad6265SDimitry Andric BinarySubstreamRef Substream;
21181ad6265SDimitry Andric Substream.Offset = Offset;
21281ad6265SDimitry Andric Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
21381ad6265SDimitry Andric
21481ad6265SDimitry Andric auto Layout = File.getStreamLayout(StreamIdx);
21581ad6265SDimitry Andric formatMsfStreamData(Label, File, Layout, Substream);
21681ad6265SDimitry Andric }
21781ad6265SDimitry Andric
formatMsfStreamData(StringRef Label,PDBFile & File,const msf::MSFStreamLayout & Stream,BinarySubstreamRef Substream)21881ad6265SDimitry Andric void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
21981ad6265SDimitry Andric const msf::MSFStreamLayout &Stream,
22081ad6265SDimitry Andric BinarySubstreamRef Substream) {
22181ad6265SDimitry Andric BinaryStreamReader Reader(Substream.StreamData);
22281ad6265SDimitry Andric
22381ad6265SDimitry Andric auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
22481ad6265SDimitry Andric
22581ad6265SDimitry Andric NewLine();
22681ad6265SDimitry Andric OS << Label << " (";
22781ad6265SDimitry Andric while (Reader.bytesRemaining() > 0) {
22881ad6265SDimitry Andric OS << "\n";
22981ad6265SDimitry Andric
23081ad6265SDimitry Andric Run FoundRun;
23181ad6265SDimitry Andric uint64_t RunOffset;
23281ad6265SDimitry Andric std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
23381ad6265SDimitry Andric assert(FoundRun.ByteLen >= RunOffset);
23481ad6265SDimitry Andric uint64_t Len = FoundRun.ByteLen - RunOffset;
23581ad6265SDimitry Andric Len = std::min(Len, Reader.bytesRemaining());
23681ad6265SDimitry Andric uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
23781ad6265SDimitry Andric ArrayRef<uint8_t> Data;
23881ad6265SDimitry Andric consumeError(Reader.readBytes(Data, Len));
23981ad6265SDimitry Andric OS << format_bytes_with_ascii(Data, Base, 32, 4,
24081ad6265SDimitry Andric CurrentIndent + IndentSpaces, true);
24181ad6265SDimitry Andric if (Reader.bytesRemaining() > 0) {
24281ad6265SDimitry Andric NewLine();
24381ad6265SDimitry Andric OS << formatv(" {0}",
24481ad6265SDimitry Andric fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
24581ad6265SDimitry Andric }
24681ad6265SDimitry Andric Substream.Offset += Len;
24781ad6265SDimitry Andric }
24881ad6265SDimitry Andric NewLine();
24981ad6265SDimitry Andric OS << ")";
25081ad6265SDimitry Andric }
25181ad6265SDimitry Andric
formatMsfStreamBlocks(PDBFile & File,const msf::MSFStreamLayout & StreamLayout)25281ad6265SDimitry Andric void LinePrinter::formatMsfStreamBlocks(
25381ad6265SDimitry Andric PDBFile &File, const msf::MSFStreamLayout &StreamLayout) {
254*bdd1243dSDimitry Andric auto Blocks = ArrayRef(StreamLayout.Blocks);
25581ad6265SDimitry Andric uint64_t L = StreamLayout.Length;
25681ad6265SDimitry Andric
25781ad6265SDimitry Andric while (L > 0) {
25881ad6265SDimitry Andric NewLine();
25981ad6265SDimitry Andric assert(!Blocks.empty());
26081ad6265SDimitry Andric OS << formatv("Block {0} (\n", uint32_t(Blocks.front()));
26181ad6265SDimitry Andric uint64_t UsedBytes =
26281ad6265SDimitry Andric std::min(L, static_cast<uint64_t>(File.getBlockSize()));
26381ad6265SDimitry Andric ArrayRef<uint8_t> BlockData =
26481ad6265SDimitry Andric cantFail(File.getBlockData(Blocks.front(), File.getBlockSize()));
26581ad6265SDimitry Andric uint64_t BaseOffset = Blocks.front();
26681ad6265SDimitry Andric BaseOffset *= File.getBlockSize();
26781ad6265SDimitry Andric OS << format_bytes_with_ascii(BlockData, BaseOffset, 32, 4,
26881ad6265SDimitry Andric CurrentIndent + IndentSpaces, true);
26981ad6265SDimitry Andric NewLine();
27081ad6265SDimitry Andric OS << ")";
27181ad6265SDimitry Andric NewLine();
27281ad6265SDimitry Andric L -= UsedBytes;
27381ad6265SDimitry Andric Blocks = Blocks.drop_front();
27481ad6265SDimitry Andric }
27581ad6265SDimitry Andric }
27681ad6265SDimitry Andric
IsTypeExcluded(llvm::StringRef TypeName,uint64_t Size)27781ad6265SDimitry Andric bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint64_t Size) {
27881ad6265SDimitry Andric if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
27981ad6265SDimitry Andric return true;
28081ad6265SDimitry Andric if (Size < Filters.SizeThreshold)
28181ad6265SDimitry Andric return true;
28281ad6265SDimitry Andric return false;
28381ad6265SDimitry Andric }
28481ad6265SDimitry Andric
IsSymbolExcluded(llvm::StringRef SymbolName)28581ad6265SDimitry Andric bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
28681ad6265SDimitry Andric return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
28781ad6265SDimitry Andric }
28881ad6265SDimitry Andric
IsCompilandExcluded(llvm::StringRef CompilandName)28981ad6265SDimitry Andric bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
29081ad6265SDimitry Andric return IsItemExcluded(CompilandName, IncludeCompilandFilters,
29181ad6265SDimitry Andric ExcludeCompilandFilters);
29281ad6265SDimitry Andric }
29381ad6265SDimitry Andric
WithColor(LinePrinter & P,PDB_ColorItem C)29481ad6265SDimitry Andric WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
29581ad6265SDimitry Andric : OS(P.OS), UseColor(P.hasColor()) {
29681ad6265SDimitry Andric if (UseColor)
29781ad6265SDimitry Andric applyColor(C);
29881ad6265SDimitry Andric }
29981ad6265SDimitry Andric
~WithColor()30081ad6265SDimitry Andric WithColor::~WithColor() {
30181ad6265SDimitry Andric if (UseColor)
30281ad6265SDimitry Andric OS.resetColor();
30381ad6265SDimitry Andric }
30481ad6265SDimitry Andric
applyColor(PDB_ColorItem C)30581ad6265SDimitry Andric void WithColor::applyColor(PDB_ColorItem C) {
30681ad6265SDimitry Andric switch (C) {
30781ad6265SDimitry Andric case PDB_ColorItem::None:
30881ad6265SDimitry Andric OS.resetColor();
30981ad6265SDimitry Andric return;
31081ad6265SDimitry Andric case PDB_ColorItem::Comment:
31181ad6265SDimitry Andric OS.changeColor(raw_ostream::GREEN, false);
31281ad6265SDimitry Andric return;
31381ad6265SDimitry Andric case PDB_ColorItem::Address:
31481ad6265SDimitry Andric OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
31581ad6265SDimitry Andric return;
31681ad6265SDimitry Andric case PDB_ColorItem::Keyword:
31781ad6265SDimitry Andric OS.changeColor(raw_ostream::MAGENTA, true);
31881ad6265SDimitry Andric return;
31981ad6265SDimitry Andric case PDB_ColorItem::Register:
32081ad6265SDimitry Andric case PDB_ColorItem::Offset:
32181ad6265SDimitry Andric OS.changeColor(raw_ostream::YELLOW, false);
32281ad6265SDimitry Andric return;
32381ad6265SDimitry Andric case PDB_ColorItem::Type:
32481ad6265SDimitry Andric OS.changeColor(raw_ostream::CYAN, true);
32581ad6265SDimitry Andric return;
32681ad6265SDimitry Andric case PDB_ColorItem::Identifier:
32781ad6265SDimitry Andric OS.changeColor(raw_ostream::CYAN, false);
32881ad6265SDimitry Andric return;
32981ad6265SDimitry Andric case PDB_ColorItem::Path:
33081ad6265SDimitry Andric OS.changeColor(raw_ostream::CYAN, false);
33181ad6265SDimitry Andric return;
33281ad6265SDimitry Andric case PDB_ColorItem::Padding:
33381ad6265SDimitry Andric case PDB_ColorItem::SectionHeader:
33481ad6265SDimitry Andric OS.changeColor(raw_ostream::RED, true);
33581ad6265SDimitry Andric return;
33681ad6265SDimitry Andric case PDB_ColorItem::LiteralValue:
33781ad6265SDimitry Andric OS.changeColor(raw_ostream::GREEN, true);
33881ad6265SDimitry Andric return;
33981ad6265SDimitry Andric }
34081ad6265SDimitry Andric }
341