vsk updated this revision to Diff 149159.
vsk edited the summary of this revision.
vsk added a comment.

- Use %zu, and improve detection of overlapping allocations.


https://reviews.llvm.org/D47508

Files:
  lit/Expr/TestIRMemoryMap.test
  source/Target/Process.cpp
  tools/lldb-test/lldb-test.cpp

Index: tools/lldb-test/lldb-test.cpp
===================================================================
--- tools/lldb-test/lldb-test.cpp
+++ tools/lldb-test/lldb-test.cpp
@@ -15,37 +15,53 @@
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Expression/IRMemoryMap.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/Symbol/SymbolVendor.h"
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
 #include "lldb/Utility/CleanUp.h"
 #include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/StreamString.h"
 
+#include "llvm/ADT/IntervalMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/WithColor.h"
+#include <cstdio>
 #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");
+cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap");
+cl::opt<std::string> Log("log", cl::desc("Path to a log file"), cl::init(""),
+                         cl::sub(IRMemoryMapSubcommand));
+
+/// Create a target using the file pointed to by \p Filename, or abort.
+TargetSP createTarget(Debugger &Dbg, const std::string &Filename);
+
+/// Read \p Filename into a null-terminated buffer, or abort.
+std::unique_ptr<MemoryBuffer> openFile(const std::string &Filename);
 
 namespace breakpoint {
 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
@@ -135,8 +151,47 @@
 
 static int dumpSymbols(Debugger &Dbg);
 }
+
+namespace irmemorymap {
+static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
+                                   cl::Required,
+                                   cl::sub(IRMemoryMapSubcommand));
+static cl::opt<std::string> CommandFile(cl::Positional,
+                                        cl::desc("<command-file>"),
+                                        cl::init("-"),
+                                        cl::sub(IRMemoryMapSubcommand));
+using AddrIntervalMap =
+      IntervalMap<addr_t, bool, 8, IntervalMapHalfOpenInfo<addr_t>>;
+bool evalMalloc(IRMemoryMap &IRMemMap, StringRef Line,
+                AddrIntervalMap &AllocatedIntervals);
+int evaluateMemoryMapCommands(Debugger &Dbg);
+} // namespace irmemorymap
+
 } // namespace opts
 
+TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) {
+  TargetSP Target;
+  Status ST =
+      Dbg.GetTargetList().CreateTarget(Dbg, Filename, /*triple*/ "",
+                                       /*get_dependent_modules*/ false,
+                                       /*platform_options*/ nullptr, Target);
+  if (ST.Fail()) {
+    errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST);
+    exit(1);
+  }
+  return Target;
+}
+
+std::unique_ptr<MemoryBuffer> opts::openFile(const std::string &Filename) {
+  auto MB = MemoryBuffer::getFileOrSTDIN(Filename);
+  if (!MB) {
+    errs() << formatv("Could not open file '{0}: {1}\n", Filename,
+                      MB.getError().message());
+    exit(1);
+  }
+  return std::move(*MB);
+}
+
 void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) {
   P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize()));
   if (List.GetSize() > 0)
@@ -177,7 +232,7 @@
     switch (Cmd[0]) {
     case '%':
       if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) {
-        OS << sys::path::parent_path(CommandFile);
+        OS << sys::path::parent_path(breakpoint::CommandFile);
         break;
       }
       // fall through
@@ -192,26 +247,11 @@
 }
 
 int 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);
-  }
+  TargetSP Target = opts::createTarget(Dbg, breakpoint::Target);
+  std::unique_ptr<MemoryBuffer> MB = opts::openFile(breakpoint::CommandFile);
 
   LinePrinter P(4, outs());
-  StringRef Rest = (*MB)->getBuffer();
+  StringRef Rest = MB->getBuffer();
   int HadErrors = 0;
   while (!Rest.empty()) {
     StringRef Line;
@@ -459,6 +499,116 @@
   return HadErrors;
 }
 
+bool opts::irmemorymap::evalMalloc(IRMemoryMap &IRMemMap, StringRef Line,
+                                   AddrIntervalMap &AllocatedIntervals) {
+  // ::= malloc <size> <alignment>
+  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);
+  if (!isPowerOf2_32(Alignment)) {
+    outs() << "Malloc error: alignment is not a power of 2\n";
+    exit(1);
+  }
+
+  // Issue the malloc in the target process with "-rw" permissions.
+  const uint32_t Permissions = 0x3;
+  const bool ZeroMemory = false;
+  IRMemoryMap::AllocationPolicy Policy =
+      IRMemoryMap::eAllocationPolicyProcessOnly;
+  Status ST;
+  addr_t Addr =
+      IRMemMap.Malloc(Size, Alignment, Permissions, Policy, ZeroMemory, ST);
+  if (ST.Fail()) {
+    outs() << formatv("Malloc error: {0}\n", ST);
+    return true;
+  }
+
+  // Print the result of the allocation before checking its validity.
+  outs() << format("Malloc: address = 0x%x\n", Addr);
+
+  // Check that the allocation is aligned.
+  if (!Addr || Addr % Alignment != 0) {
+    outs() << "Malloc error: zero or unaligned allocation detected\n";
+    exit(1);
+  }
+
+  // Check that the allocation does not overlap another allocation. Do this
+  // by scanning for allocated intervals in the range [Addr, Addr + Size). 
+  auto Probe = AllocatedIntervals.begin();
+  Probe.advanceTo(Addr);
+  auto End = AllocatedIntervals.begin();
+  End.advanceTo(Addr + Size);
+  while (Probe != End) {
+    bool Overlaps = Addr >= Probe.start() && Addr < Probe.stop();
+    if (Overlaps) {
+      outs() << "Malloc error: overlapping allocation detected"
+             << format(", previous allocation at [0x%x, 0x%x)\n", Probe.start(),
+                       Probe.stop());
+      exit(1);
+    }
+    ++Probe;
+  }
+
+  // Insert the new allocation into the interval map.
+  if (Size)
+    AllocatedIntervals.insert(Addr, Addr + Size, true);
+
+  return true;
+}
+
+int opts::irmemorymap::evaluateMemoryMapCommands(Debugger &Dbg) {
+  // Set up a Target.
+  TargetSP Target = opts::createTarget(Dbg, irmemorymap::Target);
+
+  // Set up a Process. In order to allocate memory within a target, this
+  // process must be alive and must support JIT'ing.
+  CommandReturnObject Result;
+  Dbg.SetAsyncExecution(false);
+  CommandInterpreter &CI = Dbg.GetCommandInterpreter();
+  auto IssueCmd = [&](const char *Cmd) -> bool {
+    return CI.HandleCommand(Cmd, eLazyBoolNo, Result);
+  };
+  if (!IssueCmd("b main") || !IssueCmd("run")) {
+    outs() << formatv("Failed: {0}\n", Result.GetErrorData());
+    exit(1);
+  }
+
+  ProcessSP Process = Target->GetProcessSP();
+  if (!Process || !Process->IsAlive() || !Process->CanJIT()) {
+    outs() << "Cannot use process to test IRMemoryMap\n";
+    exit(1);
+  }
+
+  // Set up an IRMemoryMap and associated testing state.
+  IRMemoryMap IRMemMap(Target);
+  AddrIntervalMap::Allocator AIMapAllocator;
+  AddrIntervalMap AllocatedIntervals(AIMapAllocator);
+
+  // Parse and apply commands from the command file.
+  std::unique_ptr<MemoryBuffer> MB = opts::openFile(irmemorymap::CommandFile);
+  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 (evalMalloc(IRMemMap, Line, AllocatedIntervals))
+      continue;
+
+    errs() << "Could not parse line: " << Line << "\n";
+    exit(1);
+  }
+  return 0;
+}
+
 int main(int argc, const char *argv[]) {
   StringRef ToolName = argv[0];
   sys::PrintStackTraceOnErrorSignal(ToolName);
@@ -474,12 +624,17 @@
 
   auto Dbg = lldb_private::Debugger::CreateInstance();
 
+  if (!opts::Log.empty())
+    Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs());
+
   if (opts::BreakpointSubcommand)
     return opts::breakpoint::evaluateBreakpoints(*Dbg);
   if (opts::ModuleSubcommand)
     return dumpModules(*Dbg);
   if (opts::SymbolsSubcommand)
     return opts::symbols::dumpSymbols(*Dbg);
+  if (opts::IRMemoryMapSubcommand)
+    return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg);
 
   WithColor::error() << "No command specified.\n";
   return 1;
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -2539,8 +2539,10 @@
 #define USE_ALLOCATE_MEMORY_CACHE 1
 addr_t Process::AllocateMemory(size_t size, uint32_t permissions,
                                Status &error) {
-  if (GetPrivateState() != eStateStopped)
+  if (GetPrivateState() != eStateStopped) {
+    error.SetErrorToGenericError();
     return LLDB_INVALID_ADDRESS;
+  }
 
 #if defined(USE_ALLOCATE_MEMORY_CACHE)
   return m_allocated_memory_cache.AllocateMemory(size, permissions, error);
Index: lit/Expr/TestIRMemoryMap.test
===================================================================
--- /dev/null
+++ lit/Expr/TestIRMemoryMap.test
@@ -0,0 +1,28 @@
+# RUN: %cxx %p/Inputs/call-function.cpp -g -o %t
+# RUN: lldb-test ir-memory-map %t %s
+
+malloc 0 1
+malloc 1 1
+
+malloc 2 1
+malloc 2 2
+malloc 2 4
+
+malloc 3 1
+malloc 3 2
+malloc 3 4
+
+malloc 128 1
+malloc 128 2
+malloc 128 4
+malloc 128 128
+
+malloc 2048 1
+malloc 2048 2
+malloc 2048 4
+
+malloc 3968 1
+malloc 3968 2
+malloc 3968 4
+
+malloc 0 1
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to