1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
//===-- llvm-debuginfo-analyzer.cpp - LLVM Debug info analysis utility ---===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that displays the logical view for the debug
// information.
//
//===----------------------------------------------------------------------===//
#include "Options.h"
#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
#include "llvm/Support/COM.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
using namespace llvm;
using namespace logicalview;
using namespace cmdline;
/// Create formatted StringError object.
static StringRef ToolName = "llvm-debuginfo-analyzer";
template <typename... Ts>
static void error(std::error_code EC, char const *Fmt, const Ts &...Vals) {
if (!EC)
return;
std::string Buffer;
raw_string_ostream Stream(Buffer);
Stream << format(Fmt, Vals...);
WithColor::error(errs(), ToolName) << Buffer << "\n";
exit(1);
}
static void error(Error EC) {
if (!EC)
return;
handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
errs() << "\n";
WithColor::error(errs(), ToolName) << EI.message() << ".\n";
exit(1);
});
}
/// If the input path is a .dSYM bundle (as created by the dsymutil tool),
/// replace it with individual entries for each of the object files inside the
/// bundle otherwise return the input path.
static std::vector<std::string> expandBundle(const std::string &InputPath) {
std::vector<std::string> BundlePaths;
SmallString<256> BundlePath(InputPath);
// Normalize input path. This is necessary to accept `bundle.dSYM/`.
sys::path::remove_dots(BundlePath);
// Manually open up the bundle to avoid introducing additional dependencies.
if (sys::fs::is_directory(BundlePath) &&
sys::path::extension(BundlePath) == ".dSYM") {
std::error_code EC;
sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
const std::string &Path = Dir->path();
sys::fs::file_status Status;
EC = sys::fs::status(Path, Status);
error(EC, "%s", Path.c_str());
switch (Status.type()) {
case sys::fs::file_type::regular_file:
case sys::fs::file_type::symlink_file:
case sys::fs::file_type::type_unknown:
BundlePaths.push_back(Path);
break;
default: /*ignore*/;
}
}
}
if (BundlePaths.empty())
BundlePaths.push_back(InputPath);
return BundlePaths;
}
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
// Initialize targets and assembly printers/parsers.
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
InitializeAllDisassemblers();
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
cl::extrahelp HelpResponse(
"\nPass @FILE as argument to read options from FILE.\n");
cl::HideUnrelatedOptions(
{&AttributeCategory, &CompareCategory, &InternalCategory, &OutputCategory,
&PrintCategory, &ReportCategory, &SelectCategory, &WarningCategory});
cl::ParseCommandLineOptions(argc, argv,
"Printing a logical representation of low-level "
"debug information.\n");
cl::PrintOptionValues();
std::error_code EC;
ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None);
error(EC, "Unable to open output file %s", OutputFilename.c_str());
// Don't remove output file if we exit with an error.
OutputFile.keep();
// Defaults to a.out if no filenames specified.
if (InputFilenames.empty())
InputFilenames.push_back("a.out");
// Expand any .dSYM bundles to the individual object files contained therein.
std::vector<std::string> Objects;
for (const std::string &Filename : InputFilenames) {
std::vector<std::string> Objs = expandBundle(Filename);
llvm::append_range(Objects, Objs);
}
propagateOptions();
ScopedPrinter W(OutputFile.os());
LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
// Print the command line.
if (options().getInternalCmdline()) {
raw_ostream &Stream = W.getOStream();
Stream << "\nCommand line:\n";
for (int Index = 0; Index < argc; ++Index)
Stream << " " << argv[Index] << "\n";
Stream << "\n";
}
// Create readers and perform requested tasks on them.
if (Error Err = ReaderHandler.process())
error(std::move(Err));
return EXIT_SUCCESS;
}
|