[IRMemoryMap] Use labels in the "malloc" and "free" lldb-test commands

Change the syntax of the malloc and free commands in lldb-test's
ir-memory-map subcommand to:

  <malloc> ::= <label> = malloc <size> <alignment>

  <free> ::= free <label>

This should make it easier to read and extend tests in the future, e.g
to test IRMemoryMap::WriteMemory or double-free behavior.

Differential Revision: https://reviews.llvm.org/D47646

llvm-svn: 333930
diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp
index 8fc5a34..b27aad9 100644
--- a/lldb/tools/lldb-test/lldb-test.cpp
+++ b/lldb/tools/lldb-test/lldb-test.cpp
@@ -167,13 +167,25 @@
     cl::init(false), cl::sub(IRMemoryMapSubcommand));
 
 using AllocationT = std::pair<addr_t, addr_t>;
-bool areAllocationsOverlapping(const AllocationT &L, const AllocationT &R);
 using AddrIntervalMap =
       IntervalMap<addr_t, unsigned, 8, IntervalMapHalfOpenInfo<addr_t>>;
-bool evalMalloc(IRMemoryMap &IRMemMap, StringRef Line,
-                AddrIntervalMap &AllocatedIntervals);
-bool evalFree(IRMemoryMap &IRMemMap, StringRef Line,
-              AddrIntervalMap &AllocatedIntervals);
+
+struct IRMemoryMapTestState {
+  TargetSP Target;
+  IRMemoryMap Map;
+
+  AddrIntervalMap::Allocator IntervalMapAllocator;
+  AddrIntervalMap Allocations;
+
+  StringMap<addr_t> Label2AddrMap;
+
+  IRMemoryMapTestState(TargetSP Target)
+      : Target(Target), Map(Target), Allocations(IntervalMapAllocator) {}
+};
+
+bool areAllocationsOverlapping(const AllocationT &L, const AllocationT &R);
+bool evalMalloc(StringRef Line, IRMemoryMapTestState &State);
+bool evalFree(StringRef Line, IRMemoryMapTestState &State);
 int evaluateMemoryMapCommands(Debugger &Dbg);
 } // namespace irmemorymap
 
@@ -514,17 +526,23 @@
   return R.first < L.second && L.first < R.second;
 }
 
-bool opts::irmemorymap::evalMalloc(IRMemoryMap &IRMemMap, StringRef Line,
-                                   AddrIntervalMap &AllocatedIntervals) {
-  // ::= malloc <size> <alignment>
+bool opts::irmemorymap::evalMalloc(StringRef Line,
+                                   IRMemoryMapTestState &State) {
+  // ::= <label> = malloc <size> <alignment>
+  StringRef Label;
+  std::tie(Label, Line) = Line.split('=');
+  if (Line.empty())
+    return false;
+  Label = Label.trim();
+  Line = Line.trim();
   size_t Size;
   uint8_t Alignment;
   int Matches = sscanf(Line.data(), "malloc %zu %hhu", &Size, &Alignment);
   if (Matches != 2)
     return false;
 
-  outs() << formatv("Command: malloc(size={0}, alignment={1})\n", Size,
-                    Alignment);
+  outs() << formatv("Command: {0} = malloc(size={1}, alignment={2})\n", Label,
+                    Size, Alignment);
   if (!isPowerOf2_32(Alignment)) {
     outs() << "Malloc error: alignment is not a power of 2\n";
     exit(1);
@@ -539,7 +557,7 @@
   const bool ZeroMemory = false;
   Status ST;
   addr_t Addr =
-      IRMemMap.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST);
+      State.Map.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST);
   if (ST.Fail()) {
     outs() << formatv("Malloc error: {0}\n", ST);
     return true;
@@ -557,10 +575,10 @@
   // Check that the allocation does not overlap another allocation. Do so by
   // testing each allocation which may cover the interval [Addr, EndOfRegion).
   addr_t EndOfRegion = Addr + Size;
-  auto Probe = AllocatedIntervals.begin();
+  auto Probe = State.Allocations.begin();
   Probe.advanceTo(Addr); //< First interval s.t stop >= Addr.
   AllocationT NewAllocation = {Addr, EndOfRegion};
-  while (Probe != AllocatedIntervals.end() && Probe.start() < EndOfRegion) {
+  while (Probe != State.Allocations.end() && Probe.start() < EndOfRegion) {
     AllocationT ProbeAllocation = {Probe.start(), Probe.stop()};
     if (areAllocationsOverlapping(ProbeAllocation, NewAllocation)) {
       outs() << "Malloc error: overlapping allocation detected"
@@ -575,41 +593,42 @@
   // to inhibit interval coalescing.
   static unsigned AllocationID = 0;
   if (Size)
-    AllocatedIntervals.insert(Addr, EndOfRegion, AllocationID++);
+    State.Allocations.insert(Addr, EndOfRegion, AllocationID++);
+
+  // Store the label -> address mapping.
+  State.Label2AddrMap[Label] = Addr;
 
   return true;
 }
 
-bool opts::irmemorymap::evalFree(IRMemoryMap &IRMemMap, StringRef Line,
-                                 AddrIntervalMap &AllocatedIntervals) {
-  // ::= free <allocation-index>
-  size_t AllocIndex;
-  int Matches = sscanf(Line.data(), "free %zu", &AllocIndex);
-  if (Matches != 1)
+bool opts::irmemorymap::evalFree(StringRef Line, IRMemoryMapTestState &State) {
+  // ::= free <label>
+  if (!Line.consume_front("free"))
     return false;
+  StringRef Label = Line.trim();
 
-  outs() << formatv("Command: free(allocation-index={0})\n", AllocIndex);
-
-  // Find and free the AllocIndex-th allocation.
-  auto Probe = AllocatedIntervals.begin();
-  for (size_t I = 0; I < AllocIndex && Probe != AllocatedIntervals.end(); ++I)
-    ++Probe;
-
-  if (Probe == AllocatedIntervals.end()) {
-    outs() << "Free error: Invalid allocation index\n";
+  outs() << formatv("Command: free({0})\n", Label);
+  auto LabelIt = State.Label2AddrMap.find(Label);
+  if (LabelIt == State.Label2AddrMap.end()) {
+    outs() << "Free error: Invalid allocation label\n";
     exit(1);
   }
 
   Status ST;
-  IRMemMap.Free(Probe.start(), ST);
+  addr_t Addr = LabelIt->getValue();
+  State.Map.Free(Addr, ST);
   if (ST.Fail()) {
     outs() << formatv("Free error: {0}\n", ST);
     exit(1);
   }
 
   // Erase the allocation from the live interval map.
-  outs() << formatv("Free: [{0:x}, {1:x})\n", Probe.start(), Probe.stop());
-  Probe.erase();
+  auto Interval = State.Allocations.find(Addr);
+  if (Interval != State.Allocations.end()) {
+    outs() << formatv("Free: [{0:x}, {1:x})\n", Interval.start(),
+                      Interval.stop());
+    Interval.erase();
+  }
 
   return true;
 }
@@ -638,9 +657,7 @@
   }
 
   // Set up an IRMemoryMap and associated testing state.
-  IRMemoryMap IRMemMap(Target);
-  AddrIntervalMap::Allocator AIMapAllocator;
-  AddrIntervalMap AllocatedIntervals(AIMapAllocator);
+  IRMemoryMapTestState State(Target);
 
   // Parse and apply commands from the command file.
   std::unique_ptr<MemoryBuffer> MB = opts::openFile(irmemorymap::CommandFile);
@@ -653,10 +670,10 @@
     if (Line.empty() || Line[0] == '#')
       continue;
 
-    if (evalMalloc(IRMemMap, Line, AllocatedIntervals))
+    if (evalMalloc(Line, State))
       continue;
 
-    if (evalFree(IRMemMap, Line, AllocatedIntervals))
+    if (evalFree(Line, State))
       continue;
 
     errs() << "Could not parse line: " << Line << "\n";