[llvm-branch-commits] [llvm] 8f820dd - [Symbolizer] Implement data symbolizer markup element.
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Sep 6 23:38:25 PDT 2022
Author: Daniel Thornburgh
Date: 2022-09-07T08:37:30+02:00
New Revision: 8f820dd89e9b27523db809ad8e205d4b0ddbf284
URL: https://github.com/llvm/llvm-project/commit/8f820dd89e9b27523db809ad8e205d4b0ddbf284
DIFF: https://github.com/llvm/llvm-project/commit/8f820dd89e9b27523db809ad8e205d4b0ddbf284.diff
LOG: [Symbolizer] Implement data symbolizer markup element.
This connects the Symbolizer to the markup filter and enables the first
working end-to-end flow using the filter.
Reviewed By: peter.smith
Differential Revision: https://reviews.llvm.org/D130187
(cherry picked from commit 22df238d4a642a4553ebf7b91325189be48b139d)
Added:
llvm/test/DebugInfo/symbolize-filter-markup-data.test
Modified:
llvm/docs/CommandGuide/llvm-symbolizer.rst
llvm/docs/SymbolizerMarkupFormat.rst
llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h
llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
llvm/test/DebugInfo/symbolize-filter-markup-context-line-elision.test
llvm/test/DebugInfo/symbolize-filter-markup-error-location.test
llvm/test/DebugInfo/symbolize-filter-markup-mmap.test
llvm/test/DebugInfo/symbolize-filter-markup-module.test
llvm/test/DebugInfo/symbolize-filter-markup-reset.test
llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
Removed:
################################################################################
diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index 33b5fa5b0fe1a..3fff88a7f1651 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -251,13 +251,13 @@ OPTIONS
Reads from standard input, converts contained
:doc:`Symbolizer Markup </SymbolizerMarkupFormat>` into human-readable form,
- and prints the results to standard output. Presently, only the following
- markup elements are supported:
+ and prints the results to standard output. The following markup elements are
+ not yet supported:
- * ``{{symbol}}``
- * ``{{reset}}``
- * ``{{module}}``
- * ``{{mmap}}``
+ * ``{{pc}}``
+ * ``{{bt}}``
+ * ``{{hexdict}}``
+ * ``{{dumpfile}}``
.. _llvm-symbolizer-opt-f:
diff --git a/llvm/docs/SymbolizerMarkupFormat.rst b/llvm/docs/SymbolizerMarkupFormat.rst
index 95ac5d89d84e7..319a330219506 100644
--- a/llvm/docs/SymbolizerMarkupFormat.rst
+++ b/llvm/docs/SymbolizerMarkupFormat.rst
@@ -195,7 +195,7 @@ human-readable symbolic form.
{{{pc:0x12345678}}}
{{{pc:0xffffffff9abcdef0}}}
-``{{{data:%p}}}`` [#not_yet_implemented]_
+``{{{data:%p}}}``
Here ``%p`` is the memory address of a data location. It might be presented as
the name of a global variable at that location.
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h b/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h
index 26686143af95b..3a2c2bf490411 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h
@@ -26,11 +26,14 @@
namespace llvm {
namespace symbolize {
+class LLVMSymbolizer;
+
/// Filter to convert parsed log symbolizer markup elements into human-readable
/// text.
class MarkupFilter {
public:
- MarkupFilter(raw_ostream &OS, Optional<bool> ColorsEnabled = llvm::None);
+ MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer,
+ Optional<bool> ColorsEnabled = llvm::None);
/// Filters a line containing symbolizer markup and writes the human-readable
/// results to the output stream.
@@ -57,6 +60,7 @@ class MarkupFilter {
uint64_t ModuleRelativeAddr;
bool contains(uint64_t Addr) const;
+ uint64_t getModuleRelativeAddr(uint64_t Addr) const;
};
// An informational module line currently being constructed. As many mmap
@@ -83,6 +87,7 @@ class MarkupFilter {
bool tryPresentation(const MarkupNode &Node);
bool trySymbol(const MarkupNode &Node);
+ bool tryData(const MarkupNode &Node);
bool trySGR(const MarkupNode &Node);
@@ -107,11 +112,13 @@ class MarkupFilter {
void reportTypeError(StringRef Str, StringRef TypeName) const;
void reportLocation(StringRef::iterator Loc) const;
- const MMap *overlappingMMap(const MMap &Map) const;
+ const MMap *getOverlappingMMap(const MMap &Map) const;
+ const MMap *getContainingMMap(uint64_t Addr) const;
StringRef lineEnding() const;
raw_ostream &OS;
+ LLVMSymbolizer &Symbolizer;
const bool ColorsEnabled;
MarkupParser Parser;
diff --git a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
index 91a51485026e0..2bf2e17514e1d 100644
--- a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
@@ -21,6 +21,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/DebugInfo/Symbolize/Markup.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Debuginfod/Debuginfod.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/ObjectFile.h"
@@ -32,9 +33,11 @@
using namespace llvm;
using namespace llvm::symbolize;
-MarkupFilter::MarkupFilter(raw_ostream &OS, Optional<bool> ColorsEnabled)
- : OS(OS), ColorsEnabled(ColorsEnabled.value_or(
- WithColor::defaultAutoDetectFunction()(OS))) {}
+MarkupFilter::MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer,
+ Optional<bool> ColorsEnabled)
+ : OS(OS), Symbolizer(Symbolizer),
+ ColorsEnabled(
+ ColorsEnabled.value_or(WithColor::defaultAutoDetectFunction()(OS))) {}
void MarkupFilter::filter(StringRef Line) {
this->Line = Line;
@@ -94,10 +97,10 @@ bool MarkupFilter::tryMMap(const MarkupNode &Node,
if (!ParsedMMap)
return true;
- if (const MMap *M = overlappingMMap(*ParsedMMap)) {
+ if (const MMap *M = getOverlappingMMap(*ParsedMMap)) {
WithColor::error(errs())
- << formatv("overlapping mmap: #{0:x} [{1:x},{2:x})\n", M->Mod->ID,
- M->Addr, M->Addr + M->Size);
+ << formatv("overlapping mmap: #{0:x} [{1:x}-{2:x}]\n", M->Mod->ID,
+ M->Addr, M->Addr + M->Size - 1);
reportLocation(Node.Fields[0].begin());
return true;
}
@@ -182,9 +185,9 @@ void MarkupFilter::endAnyModuleInfoLine() {
return A->Addr < B->Addr;
});
for (const MMap *M : MIL->MMaps) {
- OS << (M == MIL->MMaps.front() ? ' ' : '-');
+ OS << (M == MIL->MMaps.front() ? ' ' : ',');
highlightValue();
- OS << formatv("{0:x}", M->Addr);
+ OS << formatv("[{0:x}-{1:x}]", M->Addr, M->Addr + M->Size - 1);
highlight();
OS << '(';
highlightValue();
@@ -210,7 +213,9 @@ void MarkupFilter::filterNode(const MarkupNode &Node) {
}
bool MarkupFilter::tryPresentation(const MarkupNode &Node) {
- return trySymbol(Node);
+ if (trySymbol(Node))
+ return true;
+ return tryData(Node);
}
bool MarkupFilter::trySymbol(const MarkupNode &Node) {
@@ -225,6 +230,47 @@ bool MarkupFilter::trySymbol(const MarkupNode &Node) {
return true;
}
+bool MarkupFilter::tryData(const MarkupNode &Node) {
+ if (Node.Tag != "data")
+ return false;
+ if (!checkNumFields(Node, 1))
+ return true;
+ Optional<uint64_t> Addr = parseAddr(Node.Fields[0]);
+ if (!Addr)
+ return true;
+
+ const auto PrintRaw = [&]() {
+ highlight();
+ OS << "[[[data:";
+ highlightValue();
+ OS << "0x" << toHex(*Addr, /*LowerCase=*/true);
+ highlight();
+ OS << "]]]\n";
+ restoreColor();
+ };
+
+ const MMap *MMap = getContainingMMap(*Addr);
+ if (!MMap) {
+ WithColor::error() << "no mmap covers address\n";
+ reportLocation(Node.Fields[0].begin());
+ PrintRaw();
+ return true;
+ }
+
+ Expected<DIGlobal> Symbol = Symbolizer.symbolizeData(
+ MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
+ if (!Symbol) {
+ WithColor::defaultErrorHandler(Symbol.takeError());
+ PrintRaw();
+ return true;
+ }
+
+ highlight();
+ OS << Symbol->Name;
+ restoreColor();
+ return true;
+}
+
bool MarkupFilter::trySGR(const MarkupNode &Node) {
if (Node.Text == "\033[0m") {
resetColor();
@@ -442,7 +488,7 @@ bool MarkupFilter::checkTag(const MarkupNode &Node) const {
bool MarkupFilter::checkNumFields(const MarkupNode &Element,
size_t Size) const {
if (Element.Fields.size() != Size) {
- WithColor::error(errs()) << "expected " << Size << " fields; found "
+ WithColor::error(errs()) << "expected " << Size << " field(s); found "
<< Element.Fields.size() << "\n";
reportLocation(Element.Tag.end());
return false;
@@ -454,7 +500,7 @@ bool MarkupFilter::checkNumFieldsAtLeast(const MarkupNode &Element,
size_t Size) const {
if (Element.Fields.size() < Size) {
WithColor::error(errs())
- << "expected at least " << Size << " fields; found "
+ << "expected at least " << Size << " field(s); found "
<< Element.Fields.size() << "\n";
reportLocation(Element.Tag.end());
return false;
@@ -479,7 +525,8 @@ void MarkupFilter::reportLocation(StringRef::iterator Loc) const {
// Checks for an existing mmap that overlaps the given one and returns a
// pointer to one of them.
-const MarkupFilter::MMap *MarkupFilter::overlappingMMap(const MMap &Map) const {
+const MarkupFilter::MMap *
+MarkupFilter::getOverlappingMMap(const MMap &Map) const {
// If the given map contains the start of another mmap, they overlap.
auto I = MMaps.upper_bound(Map.Addr);
if (I != MMaps.end() && Map.contains(I->second.Addr))
@@ -495,6 +542,20 @@ const MarkupFilter::MMap *MarkupFilter::overlappingMMap(const MMap &Map) const {
return nullptr;
}
+// Returns the MMap that contains the given address or nullptr if none.
+const MarkupFilter::MMap *MarkupFilter::getContainingMMap(uint64_t Addr) const {
+ // Find the first mmap starting >= Addr.
+ auto I = MMaps.lower_bound(Addr);
+ if (I != MMaps.end() && I->second.contains(Addr))
+ return &I->second;
+
+ // The previous mmap is the last one starting < Addr.
+ if (I == MMaps.begin())
+ return nullptr;
+ --I;
+ return I->second.contains(Addr) ? &I->second : nullptr;
+}
+
StringRef MarkupFilter::lineEnding() const {
return Line.endswith("\r\n") ? "\r\n" : "\n";
}
@@ -502,3 +563,8 @@ StringRef MarkupFilter::lineEnding() const {
bool MarkupFilter::MMap::contains(uint64_t Addr) const {
return this->Addr <= Addr && Addr < this->Addr + Size;
}
+
+// Returns the module-relative address for a given virtual address.
+uint64_t MarkupFilter::MMap::getModuleRelativeAddr(uint64_t Addr) const {
+ return Addr - this->Addr + ModuleRelativeAddr;
+}
diff --git a/llvm/test/DebugInfo/symbolize-filter-markup-context-line-elision.test b/llvm/test/DebugInfo/symbolize-filter-markup-context-line-elision.test
index af187f8954bd4..acba42e0ced9d 100644
--- a/llvm/test/DebugInfo/symbolize-filter-markup-context-line-elision.test
+++ b/llvm/test/DebugInfo/symbolize-filter-markup-context-line-elision.test
@@ -3,7 +3,7 @@ RUN: llvm-symbolizer --filter-markup < %t/log | \
RUN: FileCheck --match-full-lines --implicit-check-not {{.}} \
RUN: --strict-whitespace %s
-CHECK:keep[[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=ab 0x0(r)[[END:\]{3}]]
+CHECK:keep[[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=ab [0x0-0x0](r)[[END:\]{3}]]
CHECK:keep[[BEGIN]]ELF module #0x1 "b.o"; BuildID=cd[[END]]
;--- log
diff --git a/llvm/test/DebugInfo/symbolize-filter-markup-data.test b/llvm/test/DebugInfo/symbolize-filter-markup-data.test
new file mode 100644
index 0000000000000..3ce1baea4d6cd
--- /dev/null
+++ b/llvm/test/DebugInfo/symbolize-filter-markup-data.test
@@ -0,0 +1,35 @@
+REQUIRES: x86-registered-target
+RUN: split-file %s %t
+RUN: mkdir -p %t/.build-id/ab
+RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t/asm.s \
+RUN: -o %t/.build-id/ab/cdef.debug
+RUN: llvm-symbolizer --debug-file-directory=%t --filter-markup < %t/input \
+RUN: > %t.output 2> %t.err
+RUN: FileCheck %s --input-file=%t.output --match-full-lines \
+RUN: --implicit-check-not {{.}}
+RUN: FileCheck %s --check-prefix=ERR --input-file=%t.err --match-full-lines
+
+CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=abcdef [0x0-0x4](r),[0x10-0x11](r)[[END:\]{3}]]
+CHECK: long long byte
+CHECK: long byte
+CHECK: [[BEGIN]]data:0x05[[END]]
+
+ERR: error: expected 1 field(s); found 0
+ERR: error: no mmap covers address
+
+;--- input
+{{{module:0:a.o:elf:abcdef}}}
+{{{mmap:0:5:load:0:r:0}}}
+{{{mmap:0x10:2:load:0:r:0x3}}}
+{{{data:0x0}}} {{{data:0x1}}} {{{data:0x4}}}
+{{{data:0x10}}} {{{data:0x11}}}
+
+{{{data}}}
+{{{data:0x5}}}
+;--- asm.s
+long:
+ .long 0x11223344
+ .size long, 4
+byte:
+ .byte 0x42
+ .size byte, 1
diff --git a/llvm/test/DebugInfo/symbolize-filter-markup-error-location.test b/llvm/test/DebugInfo/symbolize-filter-markup-error-location.test
index 400131d9e549b..4c7a7e51c2b90 100644
--- a/llvm/test/DebugInfo/symbolize-filter-markup-error-location.test
+++ b/llvm/test/DebugInfo/symbolize-filter-markup-error-location.test
@@ -2,13 +2,13 @@ RUN: split-file %s %t
RUN: llvm-symbolizer --filter-markup < %t/log > /dev/null 2> %t.err
RUN: FileCheck %s -input-file=%t.err --match-full-lines --strict-whitespace
-CHECK:error: expected 1 fields; found 0
+CHECK:error: expected 1 field(s); found 0
CHECK:[[BEGIN:[{]{3}]]symbol[[END:[}]{3}]]
CHECK: ^
-CHECK:error: expected 1 fields; found 0
+CHECK:error: expected 1 field(s); found 0
CHECK:foo[[BEGIN]]symbol[[END]]bar[[BEGIN]]symbol[[END]]baz
CHECK: ^
-CHECK:error: expected 1 fields; found 0
+CHECK:error: expected 1 field(s); found 0
CHECK:foo[[BEGIN]]symbol[[END]]bar[[BEGIN]]symbol[[END]]baz
CHECK: ^
diff --git a/llvm/test/DebugInfo/symbolize-filter-markup-mmap.test b/llvm/test/DebugInfo/symbolize-filter-markup-mmap.test
index 506d7a926baea..37e159e7797f6 100644
--- a/llvm/test/DebugInfo/symbolize-filter-markup-mmap.test
+++ b/llvm/test/DebugInfo/symbolize-filter-markup-mmap.test
@@ -4,19 +4,19 @@ RUN: FileCheck %s --input-file=%t.out --match-full-lines \
RUN: --implicit-check-not {{.}}
RUN: FileCheck %s --check-prefix=ERR -input-file=%t.err --match-full-lines
-CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=abb50d82b6bdc861 0x0(rwx)-0x1(r)-0x2(w)-0x3(x)-0x4(rwx)-0xa(r)[[END:\]{3}]]
+CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=abb50d82b6bdc861 [0x0-0x0](rwx),[0x1-0x1](r),[0x2-0x2](w),[0x3-0x3](x),[0x4-0x4](rwx),[0xa-0xb](r)[[END:\]{3}]]
-ERR: error: expected at least 3 fields; found 0
+ERR: error: expected at least 3 field(s); found 0
ERR: error: unknown mmap type
-ERR: error: expected 6 fields; found 3
+ERR: error: expected 6 field(s); found 3
ERR: error: expected address; found '1'
ERR: error: expected size; found '-1'
ERR: error: expected mode; found ''
ERR: error: expected mode; found 'g'
ERR: error: expected mode; found 'wr'
-ERR: error: overlapping mmap: #0x0 [0xa,0xc)
-ERR: error: overlapping mmap: #0x0 [0xa,0xc)
-ERR: error: overlapping mmap: #0x0 [0xa,0xc)
+ERR: error: overlapping mmap: #0x0 [0xa-0xb]
+ERR: error: overlapping mmap: #0x0 [0xa-0xb]
+ERR: error: overlapping mmap: #0x0 [0xa-0xb]
;--- log
{{{module:0:a.o:elf:abb50d82b6bdc861}}}
diff --git a/llvm/test/DebugInfo/symbolize-filter-markup-module.test b/llvm/test/DebugInfo/symbolize-filter-markup-module.test
index 74d6347941dc0..38ef796b913d4 100644
--- a/llvm/test/DebugInfo/symbolize-filter-markup-module.test
+++ b/llvm/test/DebugInfo/symbolize-filter-markup-module.test
@@ -7,12 +7,12 @@ RUN: FileCheck %s --check-prefix=ERR -input-file=%t.err --match-full-lines
CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=ab[[END:\]{3}]]
CHECK: [[BEGIN]]ELF module #0x1 "b.o"; BuildID=abb50d82b6bdc861[[END]]
CHECK: [[BEGIN]]ELF module #0x2 "c.o"; BuildID=cd[[END]]
-CHECK: [[BEGIN]]ELF module #0x1 "b.o"; adds 0x0(r)[[END]]
+CHECK: [[BEGIN]]ELF module #0x1 "b.o"; adds [0x0-0x98967f](r)[[END]]
-ERR: error: expected at least 3 fields; found 0
+ERR: error: expected at least 3 field(s); found 0
ERR: error: unknown module type
ERR: error: duplicate module ID
-ERR: error: expected 4 fields; found 3
+ERR: error: expected 4 field(s); found 3
;--- log
{{{module:0:a.o:elf:ab}}}
diff --git a/llvm/test/DebugInfo/symbolize-filter-markup-reset.test b/llvm/test/DebugInfo/symbolize-filter-markup-reset.test
index 1abb90582dfea..75ffd5d943505 100644
--- a/llvm/test/DebugInfo/symbolize-filter-markup-reset.test
+++ b/llvm/test/DebugInfo/symbolize-filter-markup-reset.test
@@ -4,11 +4,11 @@ RUN: FileCheck %s --input-file=%t.out --match-full-lines \
RUN: --implicit-check-not {{.}}
RUN: FileCheck %s --check-prefix=ERR -input-file=%t.err --match-full-lines
-CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=ab 0x0(r)[[END:\]{3}]]
+CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "a.o"; BuildID=ab [0x0-0x0](r)[[END:\]{3}]]
CHECK: {{ }}[[BEGIN]]reset[[END]]
-CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "b.o"; BuildID=cd 0x1(r)[[END:\]{3}]]
+CHECK: [[BEGIN:\[{3}]]ELF module #0x0 "b.o"; BuildID=cd [0x1-0x1](r)[[END:\]{3}]]
-ERR: error: expected 0 fields; found 1
+ERR: error: expected 0 field(s); found 1
;--- log
{{{reset}}}
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 7ec70e42f1c1f..34c93be67f80f 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -366,8 +366,8 @@ static SmallVector<uint8_t> parseBuildIDArg(const opt::InputArgList &Args,
}
// Symbolize markup from stdin and write the result to stdout.
-static void filterMarkup(const opt::InputArgList &Args) {
- MarkupFilter Filter(outs(), parseColorArg(Args));
+static void filterMarkup(const opt::InputArgList &Args, LLVMSymbolizer &Symbolizer) {
+ MarkupFilter Filter(outs(), Symbolizer, parseColorArg(Args));
std::string InputString;
while (std::getline(std::cin, InputString)) {
InputString += '\n';
@@ -437,8 +437,19 @@ int main(int argc, char **argv) {
}
}
+ LLVMSymbolizer Symbolizer(Opts);
+
+ // A debuginfod lookup could succeed if a HTTP client is available and at
+ // least one backing URL is configured.
+ bool ShouldUseDebuginfodByDefault =
+ HTTPClient::isAvailable() &&
+ !ExitOnErr(getDefaultDebuginfodUrls()).empty();
+ if (Args.hasFlag(OPT_debuginfod, OPT_no_debuginfod,
+ ShouldUseDebuginfodByDefault))
+ enableDebuginfod(Symbolizer);
+
if (Args.hasArg(OPT_filter_markup)) {
- filterMarkup(Args);
+ filterMarkup(Args, Symbolizer);
return 0;
}
@@ -458,17 +469,6 @@ int main(int argc, char **argv) {
}
SmallVector<uint8_t> BuildID = parseBuildIDArg(Args, OPT_build_id_EQ);
- LLVMSymbolizer Symbolizer(Opts);
-
- // A debuginfod lookup could succeed if a HTTP client is available and at
- // least one backing URL is configured.
- bool ShouldUseDebuginfodByDefault =
- HTTPClient::isAvailable() &&
- !ExitOnErr(getDefaultDebuginfodUrls()).empty();
- if (Args.hasFlag(OPT_debuginfod, OPT_no_debuginfod,
- ShouldUseDebuginfodByDefault))
- enableDebuginfod(Symbolizer);
-
std::unique_ptr<DIPrinter> Printer;
if (Style == OutputStyle::GNU)
Printer = std::make_unique<GNUPrinter>(outs(), errs(), Config);
More information about the llvm-branch-commits
mailing list