blob: 502e555dd7cd09e33b8d9a549b65fb100a2b5fed [file] [log] [blame]
Zachary Turner888a4282017-12-01 00:52:51 +00001//===- lldb-test.cpp ------------------------------------------ *- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "FormatUtil.h"
11#include "SystemInitializerTest.h"
12
Zachary Turnera6d54642017-12-02 00:15:29 +000013#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
Pavel Labath7c945822018-02-26 18:50:16 +000014#include "lldb/Breakpoint/BreakpointLocation.h"
Zachary Turner888a4282017-12-01 00:52:51 +000015#include "lldb/Core/Debugger.h"
16#include "lldb/Core/Module.h"
17#include "lldb/Core/Section.h"
18#include "lldb/Initialization/SystemLifetimeManager.h"
Pavel Labath7c945822018-02-26 18:50:16 +000019#include "lldb/Interpreter/CommandInterpreter.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
Zachary Turnera6d54642017-12-02 00:15:29 +000021#include "lldb/Symbol/ClangASTContext.h"
22#include "lldb/Symbol/ClangASTImporter.h"
Zachary Turner888a4282017-12-01 00:52:51 +000023#include "lldb/Utility/DataExtractor.h"
Zachary Turnera6d54642017-12-02 00:15:29 +000024#include "lldb/Utility/StreamString.h"
Zachary Turner888a4282017-12-01 00:52:51 +000025
26#include "llvm/ADT/StringRef.h"
27#include "llvm/Support/CommandLine.h"
28#include "llvm/Support/ManagedStatic.h"
Pavel Labath7c945822018-02-26 18:50:16 +000029#include "llvm/Support/Path.h"
Zachary Turner888a4282017-12-01 00:52:51 +000030#include "llvm/Support/PrettyStackTrace.h"
31#include "llvm/Support/Signals.h"
32#include <thread>
33
34using namespace lldb;
35using namespace lldb_private;
36using namespace llvm;
37
38namespace opts {
Pavel Labath7c945822018-02-26 18:50:16 +000039static cl::SubCommand BreakpointSubcommand("breakpoints",
40 "Test breakpoint resolution");
Zachary Turner888a4282017-12-01 00:52:51 +000041cl::SubCommand ModuleSubcommand("module-sections",
42 "Display LLDB Module Information");
Zachary Turnera6d54642017-12-02 00:15:29 +000043cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file");
Zachary Turner888a4282017-12-01 00:52:51 +000044
Pavel Labath7c945822018-02-26 18:50:16 +000045namespace breakpoint {
46static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
47 cl::Required, cl::sub(BreakpointSubcommand));
48static cl::opt<std::string> CommandFile(cl::Positional,
49 cl::desc("<command-file>"),
50 cl::init("-"),
51 cl::sub(BreakpointSubcommand));
52static cl::opt<bool> Persistent(
53 "persistent",
54 cl::desc("Don't automatically remove all breakpoints before each command"),
55 cl::sub(BreakpointSubcommand));
56
57static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; }
58static void dumpState(const BreakpointList &List, LinePrinter &P);
59static std::string substitute(StringRef Cmd);
60static void evaluateBreakpoints(Debugger &Dbg);
61} // namespace breakpoint
62
Zachary Turner888a4282017-12-01 00:52:51 +000063namespace module {
64cl::opt<bool> SectionContents("contents",
65 cl::desc("Dump each section's contents"),
66 cl::sub(ModuleSubcommand));
67cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
68 cl::OneOrMore, cl::sub(ModuleSubcommand));
69} // namespace module
Zachary Turnera6d54642017-12-02 00:15:29 +000070
71namespace symbols {
72cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
73 cl::OneOrMore, cl::sub(SymbolsSubcommand));
74}
Zachary Turner888a4282017-12-01 00:52:51 +000075} // namespace opts
76
77static llvm::ManagedStatic<SystemLifetimeManager> DebuggerLifetime;
78
Pavel Labath7c945822018-02-26 18:50:16 +000079void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) {
80 P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize()));
81 if (List.GetSize() > 0)
82 P.formatLine("At least one breakpoint.");
83 for (size_t i = 0, e = List.GetSize(); i < e; ++i) {
84 BreakpointSP BP = List.GetBreakpointAtIndex(i);
85 P.formatLine("Breakpoint ID {0}:", BP->GetID());
86 AutoIndent Indent(P, 2);
87 P.formatLine("{0} location{1}.", BP->GetNumLocations(),
88 plural(BP->GetNumLocations()));
89 if (BP->GetNumLocations() > 0)
90 P.formatLine("At least one location.");
91 P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(),
92 plural(BP->GetNumResolvedLocations()));
93 if (BP->GetNumResolvedLocations() > 0)
94 P.formatLine("At least one resolved location.");
95 for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) {
96 BreakpointLocationSP Loc = BP->GetLocationAtIndex(l);
97 P.formatLine("Location ID {0}:", Loc->GetID());
98 AutoIndent Indent(P, 2);
99 P.formatLine("Enabled: {0}", Loc->IsEnabled());
100 P.formatLine("Resolved: {0}", Loc->IsResolved());
101 P.formatLine("Address: {0}+{1:x}",
102 Loc->GetAddress().GetSection()->GetName(),
103 Loc->GetAddress().GetOffset());
104 }
105 }
106 P.NewLine();
107}
108
109std::string opts::breakpoint::substitute(StringRef Cmd) {
110 std::string Result;
111 raw_string_ostream OS(Result);
112 while (!Cmd.empty()) {
113 switch (Cmd[0]) {
114 case '%':
115 if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) {
116 OS << sys::path::parent_path(CommandFile);
117 break;
118 }
119 // fall through
120 default:
121 size_t pos = Cmd.find('%');
122 OS << Cmd.substr(0, pos);
123 Cmd = Cmd.substr(pos);
124 break;
125 }
126 }
127 return std::move(OS.str());
128}
129
130void opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) {
131 TargetSP Target;
132 Status ST =
133 Dbg.GetTargetList().CreateTarget(Dbg, breakpoint::Target, /*triple*/ "",
134 /*get_dependent_modules*/ false,
135 /*platform_options*/ nullptr, Target);
136 if (ST.Fail()) {
137 errs() << formatv("Failed to create target '{0}: {1}\n", breakpoint::Target,
138 ST);
139 exit(1);
140 }
141
142 auto MB = MemoryBuffer::getFileOrSTDIN(CommandFile);
143 if (!MB) {
144 errs() << formatv("Could not open file '{0}: {1}\n", CommandFile,
145 MB.getError().message());
146 exit(1);
147 }
148
149 LinePrinter P(4, outs());
150 StringRef Rest = (*MB)->getBuffer();
151 while (!Rest.empty()) {
152 StringRef Line;
153 std::tie(Line, Rest) = Rest.split('\n');
154 Line = Line.ltrim();
155 if (Line.empty() || Line[0] == '#')
156 continue;
157
158 if (!Persistent)
159 Target->RemoveAllBreakpoints(/*internal_also*/ true);
160
161 std::string Command = substitute(Line);
162 P.formatLine("Command: {0}", Command);
163 CommandReturnObject Result;
164 if (!Dbg.GetCommandInterpreter().HandleCommand(
165 Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) {
166 P.formatLine("Failed: {0}", Result.GetErrorData());
167 continue;
168 }
169
170 dumpState(Target->GetBreakpointList(/*internal*/ false), P);
171 }
172}
173
Zachary Turnera6d54642017-12-02 00:15:29 +0000174static void dumpSymbols(Debugger &Dbg) {
175 for (const auto &File : opts::symbols::InputFilenames) {
176 ModuleSpec Spec{FileSpec(File, false)};
177 Spec.GetSymbolFileSpec().SetFile(File, false);
178
179 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
180
181 StreamString Stream;
182 ModulePtr->ParseAllDebugSymbols();
183 ModulePtr->Dump(&Stream);
184 llvm::outs() << Stream.GetData() << "\n";
185 llvm::outs().flush();
186 }
187}
188
Zachary Turner888a4282017-12-01 00:52:51 +0000189static void dumpModules(Debugger &Dbg) {
190 LinePrinter Printer(4, llvm::outs());
191
192 for (const auto &File : opts::module::InputFilenames) {
193 ModuleSpec Spec{FileSpec(File, false)};
194 Spec.GetSymbolFileSpec().SetFile(File, false);
195
Zachary Turnera6d54642017-12-02 00:15:29 +0000196 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
Zachary Turner888a4282017-12-01 00:52:51 +0000197 SectionList *Sections = ModulePtr->GetSectionList();
198 if (!Sections) {
199 llvm::errs() << "Could not load sections for module " << File << "\n";
200 continue;
201 }
202
203 size_t Count = Sections->GetNumSections(0);
204 Printer.formatLine("Showing {0} sections", Count);
205 for (size_t I = 0; I < Count; ++I) {
206 AutoIndent Indent(Printer, 2);
207 auto S = Sections->GetSectionAtIndex(I);
208 assert(S);
209 Printer.formatLine("Index: {0}", I);
210 Printer.formatLine("Name: {0}", S->GetName().GetStringRef());
Pavel Labathe2867bc2017-12-15 14:23:58 +0000211 Printer.formatLine("VM size: {0}", S->GetByteSize());
212 Printer.formatLine("File size: {0}", S->GetFileSize());
Zachary Turner888a4282017-12-01 00:52:51 +0000213
214 if (opts::module::SectionContents) {
215 DataExtractor Data;
216 S->GetSectionData(Data);
217 ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()};
218 Printer.formatBinary("Data: ", Bytes, 0);
219 }
220 Printer.NewLine();
221 }
222 }
223}
224
225int main(int argc, const char *argv[]) {
226 StringRef ToolName = argv[0];
227 sys::PrintStackTraceOnErrorSignal(ToolName);
228 PrettyStackTraceProgram X(argc, argv);
229 llvm_shutdown_obj Y;
230
231 cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
232
233 DebuggerLifetime->Initialize(llvm::make_unique<SystemInitializerTest>(),
234 nullptr);
235
236 auto Dbg = lldb_private::Debugger::CreateInstance();
237
Pavel Labath7c945822018-02-26 18:50:16 +0000238 if (opts::BreakpointSubcommand)
239 opts::breakpoint::evaluateBreakpoints(*Dbg);
Zachary Turner888a4282017-12-01 00:52:51 +0000240 if (opts::ModuleSubcommand)
241 dumpModules(*Dbg);
Zachary Turnera6d54642017-12-02 00:15:29 +0000242 else if (opts::SymbolsSubcommand)
243 dumpSymbols(*Dbg);
Zachary Turner888a4282017-12-01 00:52:51 +0000244
245 DebuggerLifetime->Terminate();
246 return 0;
247}