diff options
Diffstat (limited to 'lldb/tools/lldb-test/lldb-test.cpp')
-rw-r--r-- | lldb/tools/lldb-test/lldb-test.cpp | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp index 1fe2f5b6385..502e555dd7c 100644 --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -11,10 +11,13 @@ #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" @@ -23,6 +26,7 @@ #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> @@ -32,10 +36,30 @@ 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"), @@ -52,6 +76,101 @@ cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"), 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()); + P.formatLine("Address: {0}+{1:x}", + Loc->GetAddress().GetSection()->GetName(), + Loc->GetAddress().GetOffset()); + } + } + 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)}; @@ -116,6 +235,8 @@ int main(int argc, const char *argv[]) { auto Dbg = lldb_private::Debugger::CreateInstance(); + if (opts::BreakpointSubcommand) + opts::breakpoint::evaluateBreakpoints(*Dbg); if (opts::ModuleSubcommand) dumpModules(*Dbg); else if (opts::SymbolsSubcommand) |