[Renderscript] Add commands for scriptgroup interaction.
authorAidan Dodds <aidan@codeplay.com>
Thu, 3 Nov 2016 13:20:37 +0000 (13:20 +0000)
committerAidan Dodds <aidan@codeplay.com>
Thu, 3 Nov 2016 13:20:37 +0000 (13:20 +0000)
This commit hooks the nofity function that signals script group
compilation.  By tracking scriptgroups compiled at runtine, users
are able to place breakpoints by script group name.  Breakpoints
will be placed on the kernels forming the group.

llvm-svn: 285902

lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt
lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp [new file with mode: 0644]
lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h [new file with mode: 0644]

index fb06604..0b19dba 100644 (file)
@@ -2,6 +2,7 @@ add_lldb_library(lldbPluginRenderScriptRuntime
   RenderScriptRuntime.cpp
   RenderScriptExpressionOpts.cpp
   RenderScriptx86ABIFixups.cpp
+  RenderScriptScriptGroup.cpp
   )
 
 if(NOT LLDB_BUILT_STANDALONE)
index 0ee6b4c..d92f100 100644 (file)
@@ -14,6 +14,7 @@
 
 // Project includes
 #include "RenderScriptRuntime.h"
+#include "RenderScriptScriptGroup.h"
 
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
 #include "lldb/Core/ConstString.h"
 #include "lldb/Interpreter/CommandObjectMultiword.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/Options.h"
+#include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/Symbol.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 
@@ -475,6 +478,26 @@ bool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) {
   return get_index(0, coord.x) && get_index(1, coord.y) &&
          get_index(2, coord.z);
 }
+
+bool SkipPrologue(lldb::ModuleSP &module, Address &addr) {
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+  SymbolContext sc;
+  uint32_t resolved_flags =
+      module->ResolveSymbolContextForAddress(addr, eSymbolContextFunction, sc);
+  if (resolved_flags & eSymbolContextFunction) {
+    if (sc.function) {
+      const uint32_t offset = sc.function->GetPrologueByteSize();
+      ConstString name = sc.GetFunctionName();
+      if (offset)
+        addr.Slide(offset);
+      if (log)
+        log->Printf("%s: Prologue offset for %s is %" PRIu32, __FUNCTION__,
+                    name.AsCString(), offset);
+    }
+    return true;
+  } else
+    return false;
+}
 } // anonymous namespace
 
 // The ScriptDetails class collects data associated with a single script
@@ -872,6 +895,80 @@ RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter,
   return eCallbackReturnContinue;
 }
 
+Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback(
+    SearchFilter &filter, SymbolContext &context, Address *addr,
+    bool containing) {
+
+  if (!m_breakpoint)
+    return eCallbackReturnContinue;
+
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+  ModuleSP &module = context.module_sp;
+
+  if (!module || !IsRenderScriptScriptModule(module))
+    return Searcher::eCallbackReturnContinue;
+
+  std::vector<std::string> names;
+  m_breakpoint->GetNames(names);
+  if (names.empty())
+    return eCallbackReturnContinue;
+
+  for (auto &name : names) {
+    const RSScriptGroupDescriptorSP sg = FindScriptGroup(ConstString(name));
+    if (!sg) {
+      if (log)
+        log->Printf("%s: could not find script group for %s", __FUNCTION__,
+                    name.c_str());
+      continue;
+    }
+
+    if (log)
+      log->Printf("%s: Found ScriptGroup for %s", __FUNCTION__, name.c_str());
+
+    for (const RSScriptGroupDescriptor::Kernel &k : sg->m_kernels) {
+      if (log) {
+        log->Printf("%s: Adding breakpoint for %s", __FUNCTION__,
+                    k.m_name.AsCString());
+        log->Printf("%s: Kernel address 0x%" PRIx64, __FUNCTION__, k.m_addr);
+      }
+
+      const lldb_private::Symbol *sym =
+          module->FindFirstSymbolWithNameAndType(k.m_name, eSymbolTypeCode);
+      if (!sym) {
+        if (log)
+          log->Printf("%s: Unable to find symbol for %s", __FUNCTION__,
+                      k.m_name.AsCString());
+        continue;
+      }
+
+      if (log) {
+        log->Printf("%s: Found symbol name is %s", __FUNCTION__,
+                    sym->GetName().AsCString());
+      }
+
+      auto address = sym->GetAddress();
+      if (!SkipPrologue(module, address)) {
+        if (log)
+          log->Printf("%s: Error trying to skip prologue", __FUNCTION__);
+      }
+
+      bool new_bp;
+      m_breakpoint->AddLocation(address, &new_bp);
+
+      if (log)
+        log->Printf("%s: Placed %sbreakpoint on %s", __FUNCTION__,
+                    new_bp ? "new " : "", k.m_name.AsCString());
+
+      // exit after placing the first breakpoint if we do not intend to stop
+      // on all kernels making up this script group
+      if (!m_stop_on_all)
+        break;
+    }
+  }
+
+  return eCallbackReturnContinue;
+}
+
 void RenderScriptRuntime::Initialize() {
   PluginManager::RegisterPlugin(GetPluginNameStatic(),
                                 "RenderScript language support", CreateInstance,
@@ -1006,7 +1103,15 @@ const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
          "10AllocationE",
          0, RenderScriptRuntime::eModuleKindDriver,
          &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy},
-};
+
+        // renderscript script groups
+        {"rsdDebugHintScriptGroup2", "_ZN7android12renderscript21debugHintScrip"
+                                     "tGroup2EPKcjPKPFvPK24RsExpandKernelDriver"
+                                     "InfojjjEj",
+         "_ZN7android12renderscript21debugHintScriptGroup2EPKcjPKPFvPK24RsExpan"
+         "dKernelDriverInfojjjEj",
+         0, RenderScriptRuntime::eModuleKindImpl,
+         &lldb_private::RenderScriptRuntime::CaptureDebugHintScriptGroup2}};
 
 const size_t RenderScriptRuntime::s_runtimeHookCount =
     sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]);
@@ -1039,6 +1144,154 @@ void RenderScriptRuntime::HookCallback(RuntimeHook *hook,
   }
 }
 
+void RenderScriptRuntime::CaptureDebugHintScriptGroup2(
+    RuntimeHook *hook_info, ExecutionContext &context) {
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
+
+  enum {
+    eGroupName = 0,
+    eGroupNameSize,
+    eKernel,
+    eKernelCount,
+  };
+
+  std::array<ArgItem, 4> args{{
+      {ArgItem::ePointer, 0}, // const char         *groupName
+      {ArgItem::eInt32, 0},   // const uint32_t      groupNameSize
+      {ArgItem::ePointer, 0}, // const ExpandFuncTy *kernel
+      {ArgItem::eInt32, 0},   // const uint32_t      kernelCount
+  }};
+
+  if (!GetArgs(context, args.data(), args.size())) {
+    if (log)
+      log->Printf("%s - Error while reading the function parameters",
+                  __FUNCTION__);
+    return;
+  } else if (log) {
+    log->Printf("%s - groupName    : 0x%" PRIx64, __FUNCTION__,
+                addr_t(args[eGroupName]));
+    log->Printf("%s - groupNameSize: %" PRIu64, __FUNCTION__,
+                uint64_t(args[eGroupNameSize]));
+    log->Printf("%s - kernel       : 0x%" PRIx64, __FUNCTION__,
+                addr_t(args[eKernel]));
+    log->Printf("%s - kernelCount  : %" PRIu64, __FUNCTION__,
+                uint64_t(args[eKernelCount]));
+  }
+
+  // parse script group name
+  ConstString group_name;
+  {
+    Error err;
+    const uint64_t len = uint64_t(args[eGroupNameSize]);
+    std::unique_ptr<char[]> buffer(new char[uint32_t(len + 1)]);
+    m_process->ReadMemory(addr_t(args[eGroupName]), buffer.get(), len, err);
+    buffer.get()[len] = '\0';
+    if (!err.Success()) {
+      if (log)
+        log->Printf("Error reading scriptgroup name from target");
+      return;
+    } else {
+      if (log)
+        log->Printf("Extracted scriptgroup name %s", buffer.get());
+    }
+    // write back the script group name
+    group_name.SetCString(buffer.get());
+  }
+
+  // create or access existing script group
+  RSScriptGroupDescriptorSP group;
+  {
+    // search for existing script group
+    for (auto sg : m_scriptGroups) {
+      if (sg->m_name == group_name) {
+        group = sg;
+        break;
+      }
+    }
+    if (!group) {
+      group.reset(new RSScriptGroupDescriptor);
+      group->m_name = group_name;
+      m_scriptGroups.push_back(group);
+    } else {
+      // already have this script group
+      if (log)
+        log->Printf("Attempt to add duplicate script group %s",
+                    group_name.AsCString());
+      return;
+    }
+  }
+  assert(group);
+
+  const uint32_t target_ptr_size = m_process->GetAddressByteSize();
+  std::vector<addr_t> kernels;
+  // parse kernel addresses in script group
+  for (uint64_t i = 0; i < uint64_t(args[eKernelCount]); ++i) {
+    RSScriptGroupDescriptor::Kernel kernel;
+    // extract script group kernel addresses from the target
+    const addr_t ptr_addr = addr_t(args[eKernel]) + i * target_ptr_size;
+    uint64_t kernel_addr = 0;
+    Error err;
+    size_t read =
+        m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err);
+    if (!err.Success() || read != target_ptr_size) {
+      if (log)
+        log->Printf("Error parsing kernel address %" PRIu64 " in script group",
+                    i);
+      return;
+    }
+    if (log)
+      log->Printf("Extracted scriptgroup kernel address - 0x%" PRIx64,
+                  kernel_addr);
+    kernel.m_addr = kernel_addr;
+
+    // try to resolve the associated kernel name
+    if (!ResolveKernelName(kernel.m_addr, kernel.m_name)) {
+      if (log)
+        log->Printf("Parsed scriptgroup kernel %" PRIu64 " - 0x%" PRIx64, i,
+                    kernel_addr);
+      return;
+    }
+
+    // try to find the non '.expand' function
+    {
+      const llvm::StringRef expand(".expand");
+      const llvm::StringRef name_ref = kernel.m_name.GetStringRef();
+      if (name_ref.endswith(expand)) {
+        const ConstString base_kernel(name_ref.drop_back(expand.size()));
+        // verify this function is a valid kernel
+        if (IsKnownKernel(base_kernel)) {
+          kernel.m_name = base_kernel;
+          if (log)
+            log->Printf("%s - found non expand version '%s'", __FUNCTION__,
+                        base_kernel.GetCString());
+        }
+      }
+    }
+    // add to a list of script group kernels we know about
+    group->m_kernels.push_back(kernel);
+  }
+
+  // Resolve any pending scriptgroup breakpoints
+  {
+    Target &target = m_process->GetTarget();
+    const BreakpointList &list = target.GetBreakpointList();
+    const size_t num_breakpoints = list.GetSize();
+    if (log)
+      log->Printf("Resolving %zu breakpoints", num_breakpoints);
+    for (size_t i = 0; i < num_breakpoints; ++i) {
+      const BreakpointSP bp = list.GetBreakpointAtIndex(i);
+      if (bp) {
+        if (bp->MatchesName(group_name.AsCString())) {
+          if (log)
+            log->Printf("Found breakpoint with name %s",
+                        group_name.AsCString());
+          bp->ResolveBreakpoint();
+        }
+      }
+    }
+  }
+}
+
 void RenderScriptRuntime::CaptureScriptInvokeForEachMulti(
     RuntimeHook *hook, ExecutionContext &exe_ctx) {
   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
@@ -1332,7 +1585,7 @@ void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
   }
 
   Target &target = GetProcess()->GetTarget();
-  llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
+  const llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
 
   if (machine != llvm::Triple::ArchType::x86 &&
       machine != llvm::Triple::ArchType::arm &&
@@ -1345,7 +1598,11 @@ void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
     return;
   }
 
-  uint32_t target_ptr_size = target.GetArchitecture().GetAddressByteSize();
+  const uint32_t target_ptr_size =
+      target.GetArchitecture().GetAddressByteSize();
+
+  std::array<bool, s_runtimeHookCount> hook_placed;
+  hook_placed.fill(false);
 
   for (size_t idx = 0; idx < s_runtimeHookCount; idx++) {
     const HookDefn *hook_defn = &s_runtimeHookDefns[idx];
@@ -1393,6 +1650,20 @@ void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
                   module->GetFileSpec().GetFilename().AsCString(),
                   (uint64_t)hook_defn->version, (uint64_t)addr);
     }
+    hook_placed[idx] = true;
+  }
+
+  // log any unhooked function
+  if (log) {
+    for (size_t i = 0; i < hook_placed.size(); ++i) {
+      if (hook_placed[i])
+        continue;
+      const HookDefn &hook_defn = s_runtimeHookDefns[i];
+      if (hook_defn.kind != kind)
+        continue;
+      log->Printf("%s - function %s was not hooked", __FUNCTION__,
+                  hook_defn.name);
+    }
   }
 }
 
@@ -2594,7 +2865,10 @@ bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
       break;
     }
     case eModuleKindImpl: {
-      m_libRSCpuRef = module_sp;
+      if (!m_libRSCpuRef) {
+        m_libRSCpuRef = module_sp;
+        LoadRuntimeHooks(m_libRSCpuRef, RenderScriptRuntime::eModuleKindImpl);
+      }
       break;
     }
     case eModuleKindLibRS: {
@@ -3535,6 +3809,45 @@ bool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target,
   return true;
 }
 
+BreakpointSP
+RenderScriptRuntime::CreateScriptGroupBreakpoint(const ConstString &name,
+                                                 bool stop_on_all) {
+  Log *log(
+      GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
+
+  if (!m_filtersp) {
+    if (log)
+      log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__);
+    return nullptr;
+  }
+
+  BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver(
+      nullptr, name, m_scriptGroups, stop_on_all));
+  BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(
+      m_filtersp, resolver_sp, false, false, false);
+  // Give RS breakpoints a specific name, so the user can manipulate them as a
+  // group.
+  Error err;
+  if (!bp->AddName(name.AsCString(), err))
+    if (log)
+      log->Printf("%s - error setting break name, '%s'.", __FUNCTION__,
+                  err.AsCString());
+  // ask the breakpoint to resolve itself
+  bp->ResolveBreakpoint();
+  return bp;
+}
+
+bool RenderScriptRuntime::PlaceBreakpointOnScriptGroup(TargetSP target,
+                                                       Stream &strm,
+                                                       const ConstString &name,
+                                                       bool multi) {
+  InitSearchFilter(target);
+  BreakpointSP bp = CreateScriptGroupBreakpoint(name, multi);
+  if (bp)
+    bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
+  return bool(bp);
+}
+
 bool RenderScriptRuntime::PlaceBreakpointOnReduction(TargetSP target,
                                                      Stream &messages,
                                                      const char *reduce_name,
@@ -3617,6 +3930,32 @@ RenderScriptRuntime::CreateAllocation(addr_t address) {
   return m_allocations.back().get();
 }
 
+bool RenderScriptRuntime::ResolveKernelName(lldb::addr_t kernel_addr,
+                                            ConstString &name) {
+  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
+
+  Target &target = GetProcess()->GetTarget();
+  Address resolved;
+  // RenderScript module
+  if (!target.GetSectionLoadList().ResolveLoadAddress(kernel_addr, resolved)) {
+    if (log)
+      log->Printf("%s: unable to resolve 0x%" PRIx64 " to a loaded symbol",
+                  __FUNCTION__, kernel_addr);
+    return false;
+  }
+
+  Symbol *sym = resolved.CalculateSymbolContextSymbol();
+  if (!sym)
+    return false;
+
+  name = sym->GetName();
+  assert(IsRenderScriptModule(resolved.CalculateSymbolContextModule()));
+  if (log)
+    log->Printf("%s: 0x%" PRIx64 " resolved to the symbol '%s'", __FUNCTION__,
+                kernel_addr, name.GetCString());
+  return true;
+}
+
 void RSModuleDescriptor::Dump(Stream &strm) const {
   int indent = strm.GetIndentLevel();
 
@@ -4636,6 +4975,8 @@ public:
         "allocation",
         CommandObjectSP(
             new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
+    LoadSubCommand("scriptgroup",
+                   NewCommandObjectRenderScriptScriptGroup(interpreter));
     LoadSubCommand(
         "reduction",
         CommandObjectSP(
index 41b9d9a..a1211a2 100644 (file)
@@ -36,10 +36,13 @@ class RSModuleDescriptor;
 struct RSGlobalDescriptor;
 struct RSKernelDescriptor;
 struct RSReductionDescriptor;
+struct RSScriptGroupDescriptor;
 
 typedef std::shared_ptr<RSModuleDescriptor> RSModuleDescriptorSP;
 typedef std::shared_ptr<RSGlobalDescriptor> RSGlobalDescriptorSP;
 typedef std::shared_ptr<RSKernelDescriptor> RSKernelDescriptorSP;
+typedef std::shared_ptr<RSScriptGroupDescriptor> RSScriptGroupDescriptorSP;
+
 struct RSCoordinate {
   uint32_t x, y, z;
 
@@ -227,6 +230,61 @@ public:
   std::string m_resname;
 };
 
+struct RSScriptGroupDescriptor {
+  struct Kernel {
+    ConstString m_name;
+    lldb::addr_t m_addr;
+  };
+  ConstString m_name;
+  std::vector<Kernel> m_kernels;
+};
+
+typedef std::vector<RSScriptGroupDescriptorSP> RSScriptGroupList;
+
+class RSScriptGroupBreakpointResolver : public BreakpointResolver {
+public:
+  RSScriptGroupBreakpointResolver(Breakpoint *bp, const ConstString &name,
+                                  const RSScriptGroupList &groups,
+                                  bool stop_on_all)
+      : BreakpointResolver(bp, BreakpointResolver::NameResolver),
+        m_group_name(name), m_script_groups(groups),
+        m_stop_on_all(stop_on_all) {}
+
+  void GetDescription(Stream *strm) override {
+    if (strm)
+      strm->Printf("RenderScript ScriptGroup breakpoint for '%s'",
+                   m_group_name.AsCString());
+  }
+
+  void Dump(Stream *s) const override {}
+
+  Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
+                                          SymbolContext &context, Address *addr,
+                                          bool containing) override;
+
+  Searcher::Depth GetDepth() override { return Searcher::eDepthModule; }
+
+  lldb::BreakpointResolverSP
+  CopyForBreakpoint(Breakpoint &breakpoint) override {
+    lldb::BreakpointResolverSP ret_sp(new RSScriptGroupBreakpointResolver(
+        &breakpoint, m_group_name, m_script_groups, m_stop_on_all));
+    return ret_sp;
+  }
+
+protected:
+  const RSScriptGroupDescriptorSP
+  FindScriptGroup(const ConstString &name) const {
+    for (auto sg : m_script_groups) {
+      if (ConstString::Compare(sg->m_name, name) == 0)
+        return sg;
+    }
+    return RSScriptGroupDescriptorSP();
+  }
+
+  ConstString m_group_name;
+  const RSScriptGroupList &m_script_groups;
+  bool m_stop_on_all;
+};
 } // namespace lldb_renderscript
 
 class RenderScriptRuntime : public lldb_private::CPPLanguageRuntime {
@@ -304,6 +362,9 @@ public:
       const lldb_renderscript::RSCoordinate *coords = nullptr,
       int kernel_types = ~(0));
 
+  bool PlaceBreakpointOnScriptGroup(lldb::TargetSP target, Stream &strm,
+                                    const ConstString &name, bool stop_on_all);
+
   void SetBreakAllKernels(bool do_break, lldb::TargetSP target);
 
   void Status(Stream &strm) const;
@@ -320,6 +381,18 @@ public:
 
   void Initiate();
 
+  const lldb_renderscript::RSScriptGroupList &GetScriptGroups() const {
+    return m_scriptGroups;
+  };
+
+  bool IsKnownKernel(const ConstString &name) {
+    for (const auto &module : m_rsmodules)
+      for (const auto &kernel : module->m_kernels)
+        if (kernel.m_name == name)
+          return true;
+    return false;
+  }
+
   //------------------------------------------------------------------
   // PluginInterface protocol
   //------------------------------------------------------------------
@@ -330,11 +403,15 @@ public:
   static bool GetKernelCoordinate(lldb_renderscript::RSCoordinate &coord,
                                   Thread *thread_ptr);
 
+  bool ResolveKernelName(lldb::addr_t kernel_address, ConstString &name);
+
 protected:
   struct ScriptDetails;
   struct AllocationDetails;
   struct Element;
 
+  lldb_renderscript::RSScriptGroupList m_scriptGroups;
+
   void InitSearchFilter(lldb::TargetSP target) {
     if (!m_filtersp)
       m_filtersp.reset(new SearchFilterForUnconstrainedSearches(target));
@@ -349,6 +426,9 @@ protected:
   bool EvalRSExpression(const char *expression, StackFrame *frame_ptr,
                         uint64_t *result);
 
+  lldb::BreakpointSP CreateScriptGroupBreakpoint(const ConstString &name,
+                                                 bool multi);
+
   lldb::BreakpointSP CreateKernelBreakpoint(const ConstString &name);
 
   lldb::BreakpointSP CreateReductionBreakpoint(const ConstString &name,
@@ -416,6 +496,10 @@ private:
 
   void HookCallback(RuntimeHook *hook_info, ExecutionContext &context);
 
+  // Callback function when 'debugHintScriptGroup2' executes on the target.
+  void CaptureDebugHintScriptGroup2(RuntimeHook *hook_info,
+                                    ExecutionContext &context);
+
   void CaptureScriptInit(RuntimeHook *hook_info, ExecutionContext &context);
 
   void CaptureAllocationInit(RuntimeHook *hook_info, ExecutionContext &context);
diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
new file mode 100644 (file)
index 0000000..a8202dd
--- /dev/null
@@ -0,0 +1,162 @@
+//===-- RenderScriptScriptGroup.cpp -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "RenderScriptRuntime.h"
+#include "RenderScriptScriptGroup.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_renderscript;
+
+class CommandObjectRenderScriptScriptGroupBreakpointSet
+    : public CommandObjectParsed {
+public:
+  CommandObjectRenderScriptScriptGroupBreakpointSet(
+      CommandInterpreter &interpreter)
+      : CommandObjectParsed(
+            interpreter, "renderscript scriptgroup breakpoint set",
+            "Place a breakpoint on all kernels forming a script group.",
+            "renderscript scriptgroup breakpoint set <group_name>",
+            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
+
+  ~CommandObjectRenderScriptScriptGroupBreakpointSet() override = default;
+
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    Stream &stream = result.GetOutputStream();
+    RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
+        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
+            eLanguageTypeExtRenderScript));
+    assert(runtime);
+    auto &target = m_exe_ctx.GetTargetSP();
+    bool stop_on_all = false;
+    const llvm::StringRef long_stop_all("--stop-on-all"), short_stop_all("-a");
+    std::vector<ConstString> sites;
+    sites.reserve(command.GetArgumentCount());
+    for (size_t i = 0; i < command.GetArgumentCount(); ++i) {
+      const auto arg = command.GetArgumentAtIndex(i);
+      if (long_stop_all == arg || short_stop_all == arg)
+        stop_on_all = true;
+      else
+        sites.push_back(ConstString(arg));
+    }
+    for (const auto &name : sites) {
+      runtime->PlaceBreakpointOnScriptGroup(target, stream, name, stop_on_all);
+    }
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return true;
+  }
+};
+
+class CommandObjectRenderScriptScriptGroupBreakpoint
+    : public CommandObjectMultiword {
+public:
+  CommandObjectRenderScriptScriptGroupBreakpoint(
+      CommandInterpreter &interpreter)
+      : CommandObjectMultiword(
+            interpreter, "renderscript scriptgroup breakpoint",
+            "Renderscript scriptgroup breakpoint interaction.",
+            "renderscript scriptgroup breakpoint set [--stop-on-all/-a]"
+            "<scriptgroup name> ...",
+            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
+    LoadSubCommand(
+        "set",
+        CommandObjectSP(new CommandObjectRenderScriptScriptGroupBreakpointSet(
+            interpreter)));
+  }
+
+  ~CommandObjectRenderScriptScriptGroupBreakpoint() override = default;
+};
+
+class CommandObjectRenderScriptScriptGroupList : public CommandObjectParsed {
+public:
+  CommandObjectRenderScriptScriptGroupList(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "renderscript scriptgroup list",
+                            "List all currently discovered script groups.",
+                            "renderscript scriptgroup list",
+                            eCommandRequiresProcess |
+                                eCommandProcessMustBeLaunched) {}
+
+  ~CommandObjectRenderScriptScriptGroupList() override = default;
+
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    Stream &stream = result.GetOutputStream();
+    RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
+        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
+            eLanguageTypeExtRenderScript));
+    assert(runtime);
+    const RSScriptGroupList &groups = runtime->GetScriptGroups();
+    // print script group count
+    stream.Printf("%" PRIu64 " script %s", uint64_t(groups.size()),
+                  (groups.size() == 1) ? "group" : "groups");
+    stream.EOL();
+    // print script group details
+    stream.IndentMore();
+    for (const RSScriptGroupDescriptorSP &g : groups) {
+      if (g) {
+        stream.Indent();
+        // script group name
+        stream.Printf("%s", g->m_name.AsCString());
+        stream.EOL();
+        // print out the kernels
+        stream.IndentMore();
+        for (const auto &k : g->m_kernels) {
+          stream.Indent();
+          stream.Printf(". %s", k.m_name.AsCString());
+          stream.EOL();
+        }
+        stream.IndentLess();
+      }
+    }
+    stream.IndentLess();
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return true;
+  }
+};
+
+class CommandObjectRenderScriptScriptGroup : public CommandObjectMultiword {
+public:
+  CommandObjectRenderScriptScriptGroup(CommandInterpreter &interpreter)
+      : CommandObjectMultiword(interpreter, "renderscript scriptgroup",
+                               "Command set for interacting with scriptgroups.",
+                               nullptr, eCommandRequiresProcess |
+                                            eCommandProcessMustBeLaunched) {
+    LoadSubCommand(
+        "breakpoint",
+        CommandObjectSP(
+            new CommandObjectRenderScriptScriptGroupBreakpoint(interpreter)));
+    LoadSubCommand(
+        "list", CommandObjectSP(
+                    new CommandObjectRenderScriptScriptGroupList(interpreter)));
+  }
+
+  ~CommandObjectRenderScriptScriptGroup() override = default;
+};
+
+lldb::CommandObjectSP NewCommandObjectRenderScriptScriptGroup(
+    lldb_private::CommandInterpreter &interpreter) {
+  return CommandObjectSP(new CommandObjectRenderScriptScriptGroup(interpreter));
+}
diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h
new file mode 100644 (file)
index 0000000..5c5608c
--- /dev/null
@@ -0,0 +1,18 @@
+//===-- RenderScriptScriptGroup.h -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RenderScriptScriptGroup_h_
+#define liblldb_RenderScriptScriptGroup_h_
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+lldb::CommandObjectSP NewCommandObjectRenderScriptScriptGroup(
+    lldb_private::CommandInterpreter &interpreter);
+
+#endif // liblldb_RenderScriptScriptGroup_h_