summaryrefslogtreecommitdiffstats
path: root/lldb/tools/lldb-test/lldb-test.cpp
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2018-02-26 18:50:16 +0000
committerPavel Labath <labath@google.com>2018-02-26 18:50:16 +0000
commit7c94582f908abafd7ca18d032d9ea20dabb3a5a3 (patch)
tree5774b3d30f4cc71ee14cfd40ac30d2e65f6f94f8 /lldb/tools/lldb-test/lldb-test.cpp
parent473f3fbaf8069e53b1edea415e7254fad20ec4a2 (diff)
downloadbcm5719-llvm-7c94582f908abafd7ca18d032d9ea20dabb3a5a3.tar.gz
bcm5719-llvm-7c94582f908abafd7ca18d032d9ea20dabb3a5a3.zip
Add "lldb-test breakpoint" command and convert the case-sensitivity test to use it
Summary: The command takes two input arguments: a module to use as a debug target and a file containing a list of commands. The command will execute each of the breakpoint commands in the file and dump the breakpoint state after each one. The commands are expected to be breakpoint set/remove/etc. commands, but I explicitly allow any lldb command here, so you can do things like change setting which impact breakpoint resolution, etc. There is also a "-persistent" flag, which causes lldb-test to *not* automatically clear the breakpoint list after each command. Right now I don't use it, but the idea behind it was that it could be used to test more complex combinations of breakpoint commands (set+modify, set+disable, etc.). Right now the command prints out only the basic breakpoint state, but more information can be easily added there. To enable easy matching of the "at least one breakpoint location found" state, the command explicitly prints out the string "At least one breakpoint location.". To enable testing of breakpoints set with an absolute paths, I add the ability to perform rudimentary substitutions on the commands: right now the string %p is replaced by the directory which contains the command file (so, under normal circumstances, this will perform the same substitution as lit would do for %p). I use this command to rewrite the TestBreakpointCaseSensitivity test -- the test was checking about a dozen breakpoint commands, but it was launching a new process for each one, so it took about 90 seconds to run. The new test takes about 0.3 seconds for me, which is approximately a 300x speedup. Reviewers: davide, zturner, jingham Subscribers: luporl, lldb-commits Differential Revision: https://reviews.llvm.org/D43686 llvm-svn: 326112
Diffstat (limited to 'lldb/tools/lldb-test/lldb-test.cpp')
-rw-r--r--lldb/tools/lldb-test/lldb-test.cpp121
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)
OpenPOWER on IntegriCloud