forked from OSchip/llvm-project
253 lines
8.7 KiB
C++
253 lines
8.7 KiB
C++
//===- lldb-test.cpp ------------------------------------------ *- C++ --*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FormatUtil.h"
|
|
#include "SystemInitializerTest.h"
|
|
|
|
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
|
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Initialization/SystemLifetimeManager.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
|
#include "lldb/Symbol/ClangASTContext.h"
|
|
#include "lldb/Symbol/ClangASTImporter.h"
|
|
#include "lldb/Utility/DataExtractor.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
#include "llvm/Support/Signals.h"
|
|
#include <thread>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace llvm;
|
|
|
|
namespace opts {
|
|
static cl::SubCommand BreakpointSubcommand("breakpoints",
|
|
"Test breakpoint resolution");
|
|
cl::SubCommand ModuleSubcommand("module-sections",
|
|
"Display LLDB Module Information");
|
|
cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file");
|
|
|
|
namespace breakpoint {
|
|
static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
|
|
cl::Required, cl::sub(BreakpointSubcommand));
|
|
static cl::opt<std::string> CommandFile(cl::Positional,
|
|
cl::desc("<command-file>"),
|
|
cl::init("-"),
|
|
cl::sub(BreakpointSubcommand));
|
|
static cl::opt<bool> Persistent(
|
|
"persistent",
|
|
cl::desc("Don't automatically remove all breakpoints before each command"),
|
|
cl::sub(BreakpointSubcommand));
|
|
|
|
static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; }
|
|
static void dumpState(const BreakpointList &List, LinePrinter &P);
|
|
static std::string substitute(StringRef Cmd);
|
|
static void evaluateBreakpoints(Debugger &Dbg);
|
|
} // namespace breakpoint
|
|
|
|
namespace module {
|
|
cl::opt<bool> SectionContents("contents",
|
|
cl::desc("Dump each section's contents"),
|
|
cl::sub(ModuleSubcommand));
|
|
cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
|
|
cl::OneOrMore, cl::sub(ModuleSubcommand));
|
|
} // namespace module
|
|
|
|
namespace symbols {
|
|
cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
|
|
cl::OneOrMore, cl::sub(SymbolsSubcommand));
|
|
}
|
|
} // namespace opts
|
|
|
|
static llvm::ManagedStatic<SystemLifetimeManager> DebuggerLifetime;
|
|
|
|
void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) {
|
|
P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize()));
|
|
if (List.GetSize() > 0)
|
|
P.formatLine("At least one breakpoint.");
|
|
for (size_t i = 0, e = List.GetSize(); i < e; ++i) {
|
|
BreakpointSP BP = List.GetBreakpointAtIndex(i);
|
|
P.formatLine("Breakpoint ID {0}:", BP->GetID());
|
|
AutoIndent Indent(P, 2);
|
|
P.formatLine("{0} location{1}.", BP->GetNumLocations(),
|
|
plural(BP->GetNumLocations()));
|
|
if (BP->GetNumLocations() > 0)
|
|
P.formatLine("At least one location.");
|
|
P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(),
|
|
plural(BP->GetNumResolvedLocations()));
|
|
if (BP->GetNumResolvedLocations() > 0)
|
|
P.formatLine("At least one resolved location.");
|
|
for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) {
|
|
BreakpointLocationSP Loc = BP->GetLocationAtIndex(l);
|
|
P.formatLine("Location ID {0}:", Loc->GetID());
|
|
AutoIndent Indent(P, 2);
|
|
P.formatLine("Enabled: {0}", Loc->IsEnabled());
|
|
P.formatLine("Resolved: {0}", Loc->IsResolved());
|
|
SymbolContext sc;
|
|
Loc->GetAddress().CalculateSymbolContext(&sc);
|
|
lldb_private::StreamString S;
|
|
sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(),
|
|
Loc->GetAddress(), false, true, false, true, true);
|
|
P.formatLine("Address: {0}", S.GetString());
|
|
}
|
|
}
|
|
P.NewLine();
|
|
}
|
|
|
|
std::string opts::breakpoint::substitute(StringRef Cmd) {
|
|
std::string Result;
|
|
raw_string_ostream OS(Result);
|
|
while (!Cmd.empty()) {
|
|
switch (Cmd[0]) {
|
|
case '%':
|
|
if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) {
|
|
OS << sys::path::parent_path(CommandFile);
|
|
break;
|
|
}
|
|
// fall through
|
|
default:
|
|
size_t pos = Cmd.find('%');
|
|
OS << Cmd.substr(0, pos);
|
|
Cmd = Cmd.substr(pos);
|
|
break;
|
|
}
|
|
}
|
|
return std::move(OS.str());
|
|
}
|
|
|
|
void opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) {
|
|
TargetSP Target;
|
|
Status ST =
|
|
Dbg.GetTargetList().CreateTarget(Dbg, breakpoint::Target, /*triple*/ "",
|
|
/*get_dependent_modules*/ false,
|
|
/*platform_options*/ nullptr, Target);
|
|
if (ST.Fail()) {
|
|
errs() << formatv("Failed to create target '{0}: {1}\n", breakpoint::Target,
|
|
ST);
|
|
exit(1);
|
|
}
|
|
|
|
auto MB = MemoryBuffer::getFileOrSTDIN(CommandFile);
|
|
if (!MB) {
|
|
errs() << formatv("Could not open file '{0}: {1}\n", CommandFile,
|
|
MB.getError().message());
|
|
exit(1);
|
|
}
|
|
|
|
LinePrinter P(4, outs());
|
|
StringRef Rest = (*MB)->getBuffer();
|
|
while (!Rest.empty()) {
|
|
StringRef Line;
|
|
std::tie(Line, Rest) = Rest.split('\n');
|
|
Line = Line.ltrim();
|
|
if (Line.empty() || Line[0] == '#')
|
|
continue;
|
|
|
|
if (!Persistent)
|
|
Target->RemoveAllBreakpoints(/*internal_also*/ true);
|
|
|
|
std::string Command = substitute(Line);
|
|
P.formatLine("Command: {0}", Command);
|
|
CommandReturnObject Result;
|
|
if (!Dbg.GetCommandInterpreter().HandleCommand(
|
|
Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) {
|
|
P.formatLine("Failed: {0}", Result.GetErrorData());
|
|
continue;
|
|
}
|
|
|
|
dumpState(Target->GetBreakpointList(/*internal*/ false), P);
|
|
}
|
|
}
|
|
|
|
static void dumpSymbols(Debugger &Dbg) {
|
|
for (const auto &File : opts::symbols::InputFilenames) {
|
|
ModuleSpec Spec{FileSpec(File, false)};
|
|
Spec.GetSymbolFileSpec().SetFile(File, false);
|
|
|
|
auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
|
|
|
|
StreamString Stream;
|
|
ModulePtr->ParseAllDebugSymbols();
|
|
ModulePtr->Dump(&Stream);
|
|
llvm::outs() << Stream.GetData() << "\n";
|
|
llvm::outs().flush();
|
|
}
|
|
}
|
|
|
|
static void dumpModules(Debugger &Dbg) {
|
|
LinePrinter Printer(4, llvm::outs());
|
|
|
|
for (const auto &File : opts::module::InputFilenames) {
|
|
ModuleSpec Spec{FileSpec(File, false)};
|
|
|
|
auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
|
|
// Fetch symbol vendor before we get the section list to give the symbol
|
|
// vendor a chance to populate it.
|
|
ModulePtr->GetSymbolVendor();
|
|
SectionList *Sections = ModulePtr->GetSectionList();
|
|
if (!Sections) {
|
|
llvm::errs() << "Could not load sections for module " << File << "\n";
|
|
continue;
|
|
}
|
|
|
|
size_t Count = Sections->GetNumSections(0);
|
|
Printer.formatLine("Showing {0} sections", Count);
|
|
for (size_t I = 0; I < Count; ++I) {
|
|
AutoIndent Indent(Printer, 2);
|
|
auto S = Sections->GetSectionAtIndex(I);
|
|
assert(S);
|
|
Printer.formatLine("Index: {0}", I);
|
|
Printer.formatLine("Name: {0}", S->GetName().GetStringRef());
|
|
Printer.formatLine("VM size: {0}", S->GetByteSize());
|
|
Printer.formatLine("File size: {0}", S->GetFileSize());
|
|
|
|
if (opts::module::SectionContents) {
|
|
DataExtractor Data;
|
|
S->GetSectionData(Data);
|
|
ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()};
|
|
Printer.formatBinary("Data: ", Bytes, 0);
|
|
}
|
|
Printer.NewLine();
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, const char *argv[]) {
|
|
StringRef ToolName = argv[0];
|
|
sys::PrintStackTraceOnErrorSignal(ToolName);
|
|
PrettyStackTraceProgram X(argc, argv);
|
|
llvm_shutdown_obj Y;
|
|
|
|
cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
|
|
|
|
DebuggerLifetime->Initialize(llvm::make_unique<SystemInitializerTest>(),
|
|
nullptr);
|
|
|
|
auto Dbg = lldb_private::Debugger::CreateInstance();
|
|
|
|
if (opts::BreakpointSubcommand)
|
|
opts::breakpoint::evaluateBreakpoints(*Dbg);
|
|
if (opts::ModuleSubcommand)
|
|
dumpModules(*Dbg);
|
|
else if (opts::SymbolsSubcommand)
|
|
dumpSymbols(*Dbg);
|
|
|
|
DebuggerLifetime->Terminate();
|
|
return 0;
|
|
}
|