diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt --- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -39,7 +39,6 @@ lldbPluginCPlusPlusLanguage lldbPluginCPPRuntime lldbPluginObjCRuntime - lldbPluginRenderScriptRuntime lldbPluginTypeSystemClang CLANG_LIBS clangAST diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -91,7 +91,6 @@ #include "lldb/Utility/StringList.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" -#include "Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h" #include #include @@ -396,7 +395,6 @@ lldb::LanguageType frame_lang = expr.Language(); // defaults to lldb::eLanguageTypeUnknown - bool overridden_target_opts = false; lldb_private::LanguageRuntime *lang_rt = nullptr; std::string abi; @@ -464,34 +462,7 @@ if (!abi.empty()) m_compiler->getTargetOpts().ABI = abi; - // 3. Now allow the runtime to provide custom configuration options for the - // target. In this case, a specialized language runtime is available and we - // can query it for extra options. For 99% of use cases, this will not be - // needed and should be provided when basic platform detection is not enough. - // FIXME: Generalize this. Only RenderScriptRuntime currently supports this - // currently. Hardcoding this isn't ideal but it's better than LanguageRuntime - // having knowledge of clang::TargetOpts. - if (auto *renderscript_rt = - llvm::dyn_cast_or_null(lang_rt)) - overridden_target_opts = - renderscript_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); - - if (overridden_target_opts) - if (log && log->GetVerbose()) { - LLDB_LOGV( - log, "Using overridden target options for the expression evaluation"); - - auto opts = m_compiler->getTargetOpts(); - LLDB_LOGV(log, "Triple: '{0}'", opts.Triple); - LLDB_LOGV(log, "CPU: '{0}'", opts.CPU); - LLDB_LOGV(log, "FPMath: '{0}'", opts.FPMath); - LLDB_LOGV(log, "ABI: '{0}'", opts.ABI); - LLDB_LOGV(log, "LinkerVersion: '{0}'", opts.LinkerVersion); - StringList::LogDump(log, opts.FeaturesAsWritten, "FeaturesAsWritten"); - StringList::LogDump(log, opts.Features, "Features"); - } - - // 4. Create and install the target on the compiler. + // 3. Create and install the target on the compiler. m_compiler->createDiagnostics(); // Limit the number of error diagnostics we emit. // A value of 0 means no limit for both LLDB and Clang. @@ -510,7 +481,7 @@ assert(m_compiler->hasTarget()); - // 5. Set language options. + // 4. Set language options. lldb::LanguageType language = expr.Language(); LangOptions &lang_opts = m_compiler->getLangOpts(); @@ -648,13 +619,13 @@ m_compiler->getTarget().adjust(m_compiler->getDiagnostics(), m_compiler->getLangOpts()); - // 6. Set up the diagnostic buffer for reporting errors + // 5. Set up the diagnostic buffer for reporting errors auto diag_mgr = new ClangDiagnosticManagerAdapter( m_compiler->getDiagnostics().getDiagnosticOptions()); m_compiler->getDiagnostics().setClient(diag_mgr); - // 7. Set up the source management objects inside the compiler + // 6. Set up the source management objects inside the compiler m_compiler->createFileManager(); if (!m_compiler->hasSourceManager()) m_compiler->createSourceManager(m_compiler->getFileManager()); @@ -689,7 +660,7 @@ } } - // 8. Most of this we get from the CompilerInstance, but we also want to give + // 7. Most of this we get from the CompilerInstance, but we also want to give // the context an ExternalASTSource. auto &PP = m_compiler->getPreprocessor(); diff --git a/lldb/source/Plugins/LanguageRuntime/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CMakeLists.txt --- a/lldb/source/Plugins/LanguageRuntime/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/CMakeLists.txt @@ -1,3 +1,2 @@ add_subdirectory(CPlusPlus) add_subdirectory(ObjC) -add_subdirectory(RenderScript) diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(RenderScriptRuntime) diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -add_lldb_library(lldbPluginRenderScriptRuntime PLUGIN - RenderScriptRuntime.cpp - RenderScriptExpressionOpts.cpp - RenderScriptx86ABIFixups.cpp - RenderScriptScriptGroup.cpp - - DEPENDS - intrinsics_gen - - LINK_LIBS - lldbBreakpoint - lldbCore - lldbDataFormatters - lldbExpression - lldbHost - lldbInterpreter - lldbSymbol - lldbTarget - CLANG_LIBS - clangBasic - LINK_COMPONENTS - Core - IRReader - Support - Target - ) diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h +++ /dev/null @@ -1,53 +0,0 @@ -//===-- RenderScriptExpressionOpts.h ----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTEXPRESSIONOPTS_H -#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTEXPRESSIONOPTS_H - -#include "llvm/IR/Module.h" -#include "llvm/MC/TargetRegistry.h" -#include "llvm/Pass.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" - -#include "lldb/Target/LanguageRuntime.h" -#include "lldb/Target/Process.h" -#include "lldb/lldb-private.h" - -#include "RenderScriptRuntime.h" -#include "RenderScriptx86ABIFixups.h" - -// RenderScriptRuntimeModulePass is a simple llvm::ModulesPass that is used -// during expression evaluation to apply RenderScript-specific fixes for -// expression evaluation. In particular this is used to make expression IR -// conformant with the ABI generated by the slang frontend. This ModulePass is -// executed in ClangExpressionParser::PrepareForExecution whenever an -// expression's DWARF language is eLanguageTypeExtRenderscript - -class RenderScriptRuntimeModulePass : public llvm::ModulePass { -public: - static char ID; - RenderScriptRuntimeModulePass(const lldb_private::Process *process) - : ModulePass(ID), m_process_ptr(process) {} - - bool runOnModule(llvm::Module &module) override; - -private: - const lldb_private::Process *m_process_ptr; -}; - -namespace lldb_private { -namespace lldb_renderscript { -struct RSIRPasses : public lldb_private::LLVMUserExpression::IRPasses { - RSIRPasses(lldb_private::Process *process); - - ~RSIRPasses(); -}; -} // namespace lldb_renderscript -} // namespace lldb_private -#endif diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp +++ /dev/null @@ -1,187 +0,0 @@ -//===-- RenderScriptExpressionOpts.cpp ------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include - -#include "llvm/ADT/StringRef.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/TargetRegistry.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" - -#include "clang/Basic/TargetOptions.h" - -#include "lldb/Target/Process.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" - -#include "RenderScriptExpressionOpts.h" -#include "RenderScriptRuntime.h" -#include "RenderScriptx86ABIFixups.h" - -using namespace lldb_private; -using namespace lldb_renderscript; - -// [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang), -// the compiler frontend for RenderScript embeds an ARM specific triple in IR -// that is shipped in the app, after generating IR that has some assumptions -// that an ARM device is the target. As the IR is then compiled on a device of -// unknown (at time the IR was generated at least) architecture, when calling -// RenderScript API function as part of debugger expressions, we have to -// perform a fixup pass that removes those assumptions right before the module -// is sent to be generated by the llvm backend. - -static bool registerRSDefaultTargetOpts(clang::TargetOptions &proto, - const llvm::Triple::ArchType &arch) { - switch (arch) { - case llvm::Triple::ArchType::x86: - proto.Triple = "i686--linux-android"; - proto.CPU = "atom"; - proto.Features.push_back("+long64"); - // Fallthrough for common x86 family features - [[fallthrough]]; - case llvm::Triple::ArchType::x86_64: - proto.Features.push_back("+mmx"); - proto.Features.push_back("+sse"); - proto.Features.push_back("+sse2"); - proto.Features.push_back("+sse3"); - proto.Features.push_back("+ssse3"); - proto.Features.push_back("+sse4.1"); - proto.Features.push_back("+sse4.2"); - break; - case llvm::Triple::ArchType::mipsel: - // pretend this is `arm' for the front-end - proto.Triple = "armv7-none-linux-android"; - proto.CPU = ""; - proto.Features.push_back("+long64"); - break; - case llvm::Triple::ArchType::mips64el: - // pretend this is `aarch64' for the front-end - proto.Triple = "aarch64-none-linux-android"; - proto.CPU = ""; - break; - default: - return false; - } - return true; -} - -bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { - bool changed_module = false; - Log *log = GetLog(LLDBLog::Language | LLDBLog::Expressions); - - std::string err; - llvm::StringRef real_triple = - m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); - const llvm::Target *target_info = - llvm::TargetRegistry::lookupTarget(std::string(real_triple), err); - if (!target_info) { - if (log) - log->Warning("couldn't determine real target architecture: '%s'", - err.c_str()); - return false; - } - - std::optional reloc_model; - assert(m_process_ptr && "no available lldb process"); - switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) { - case llvm::Triple::ArchType::x86: - changed_module |= fixupX86FunctionCalls(module); - // For some reason this triple gets totally missed by the backend, and must - // be set manually. There a reference in bcc/Main.cpp about auto feature- - // detection being removed from LLVM3.5, but I can't see that discussion - // anywhere public. - real_triple = "i686--linux-android"; - break; - case llvm::Triple::ArchType::x86_64: - changed_module |= fixupX86_64FunctionCalls(module); - break; - case llvm::Triple::ArchType::mipsel: - case llvm::Triple::ArchType::mips64el: - // No actual IR fixup pass is needed on MIPS, but the datalayout and - // targetmachine do need to be explicitly set. - - // bcc explicitly compiles MIPS code to use the static relocation model due - // to an issue with relocations in mclinker. see - // libbcc/support/CompilerConfig.cpp for details - reloc_model = llvm::Reloc::Static; - changed_module = true; - break; - case llvm::Triple::ArchType::arm: - case llvm::Triple::ArchType::aarch64: - // ARM subtargets need no fixup passes as they are the initial target as - // generated by the - // slang compiler frontend. - break; - default: - if (log) - log->Warning("Ignoring unknown renderscript target"); - return false; - } - - if (changed_module) { - llvm::TargetOptions options; - llvm::TargetMachine *target_machine = target_info->createTargetMachine( - real_triple, "", "", options, reloc_model); - assert(target_machine && - "failed to identify RenderScriptRuntime target machine"); - // We've been using a triple and datalayout of some ARM variant all along, - // so we need to let the backend know that this is no longer the case. - if (log) { - LLDB_LOGF(log, "%s - Changing RS target triple to '%s'", __FUNCTION__, - real_triple.str().c_str()); - LLDB_LOGF( - log, "%s - Changing RS datalayout to '%s'", __FUNCTION__, - target_machine->createDataLayout().getStringRepresentation().c_str()); - } - module.setTargetTriple(real_triple); - module.setDataLayout(target_machine->createDataLayout()); - } - return changed_module; -} - -char RenderScriptRuntimeModulePass::ID = 0; - -namespace lldb_private { - -bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) { - auto *process = GetProcess(); - assert(process); - return registerRSDefaultTargetOpts( - proto, process->GetTarget().GetArchitecture().GetMachine()); -} - -bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) { - if (!m_ir_passes) - m_ir_passes = new RSIRPasses(GetProcess()); - assert(m_ir_passes); - - passes.EarlyPasses = m_ir_passes->EarlyPasses; - passes.LatePasses = m_ir_passes->LatePasses; - - return true; -} - -namespace lldb_renderscript { - -RSIRPasses::RSIRPasses(Process *process) { - assert(process); - - EarlyPasses = std::make_shared(); - assert(EarlyPasses); - EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); -} - -RSIRPasses::~RSIRPasses() = default; - -} // namespace lldb_renderscript -} // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ /dev/null @@ -1,592 +0,0 @@ -//===-- RenderScriptRuntime.h -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTRUNTIME_H -#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTRUNTIME_H - -#include -#include -#include -#include -#include - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "lldb/Core/Module.h" -#include "lldb/Expression/LLVMUserExpression.h" -#include "lldb/Target/LanguageRuntime.h" -#include "lldb/lldb-private.h" - -#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" - -namespace clang { -class TargetOptions; -} - -namespace lldb_private { -namespace lldb_renderscript { - -typedef uint32_t RSSlot; -class RSModuleDescriptor; -struct RSGlobalDescriptor; -struct RSKernelDescriptor; -struct RSReductionDescriptor; -struct RSScriptGroupDescriptor; - -typedef std::shared_ptr RSModuleDescriptorSP; -typedef std::shared_ptr RSGlobalDescriptorSP; -typedef std::shared_ptr RSKernelDescriptorSP; -typedef std::shared_ptr RSScriptGroupDescriptorSP; - -struct RSCoordinate { - uint32_t x = 0, y = 0, z = 0; - - RSCoordinate() = default; - - bool operator==(const lldb_renderscript::RSCoordinate &rhs) { - return x == rhs.x && y == rhs.y && z == rhs.z; - } -}; - -// Breakpoint Resolvers decide where a breakpoint is placed, so having our own -// allows us to limit the search scope to RS kernel modules. As well as check -// for .expand kernels as a fallback. -class RSBreakpointResolver : public BreakpointResolver { -public: - RSBreakpointResolver(const lldb::BreakpointSP &bp, ConstString name) - : BreakpointResolver(bp, BreakpointResolver::NameResolver), - m_kernel_name(name) {} - - void GetDescription(Stream *strm) override { - if (strm) - strm->Printf("RenderScript kernel breakpoint for '%s'", - m_kernel_name.AsCString()); - } - - void Dump(Stream *s) const override {} - - Searcher::CallbackReturn SearchCallback(SearchFilter &filter, - SymbolContext &context, - Address *addr) override; - - lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } - - lldb::BreakpointResolverSP - CopyForBreakpoint(lldb::BreakpointSP &breakpoint) override { - lldb::BreakpointResolverSP ret_sp( - new RSBreakpointResolver(breakpoint, m_kernel_name)); - return ret_sp; - } - -protected: - ConstString m_kernel_name; -}; - -class RSReduceBreakpointResolver : public BreakpointResolver { -public: - enum ReduceKernelTypeFlags { - eKernelTypeAll = ~(0), - eKernelTypeNone = 0, - eKernelTypeAccum = (1 << 0), - eKernelTypeInit = (1 << 1), - eKernelTypeComb = (1 << 2), - eKernelTypeOutC = (1 << 3), - eKernelTypeHalter = (1 << 4) - }; - - RSReduceBreakpointResolver( - const lldb::BreakpointSP &breakpoint, ConstString reduce_name, - std::vector *rs_modules, - int kernel_types = eKernelTypeAll) - : BreakpointResolver(breakpoint, BreakpointResolver::NameResolver), - m_reduce_name(reduce_name), m_rsmodules(rs_modules), - m_kernel_types(kernel_types) { - // The reduce breakpoint resolver handles adding breakpoints for named - // reductions. - // Breakpoints will be resolved for all constituent kernels in the named - // reduction - } - - void GetDescription(Stream *strm) override { - if (strm) - strm->Printf("RenderScript reduce breakpoint for '%s'", - m_reduce_name.AsCString()); - } - - void Dump(Stream *s) const override {} - - Searcher::CallbackReturn SearchCallback(SearchFilter &filter, - SymbolContext &context, - Address *addr) override; - - lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } - - lldb::BreakpointResolverSP - CopyForBreakpoint(lldb::BreakpointSP &breakpoint) override { - lldb::BreakpointResolverSP ret_sp(new RSReduceBreakpointResolver( - breakpoint, m_reduce_name, m_rsmodules, m_kernel_types)); - return ret_sp; - } - -private: - ConstString m_reduce_name; // The name of the reduction - std::vector *m_rsmodules; - int m_kernel_types; -}; - -struct RSKernelDescriptor { -public: - RSKernelDescriptor(const RSModuleDescriptor *module, llvm::StringRef name, - uint32_t slot) - : m_module(module), m_name(name), m_slot(slot) {} - - void Dump(Stream &strm) const; - - const RSModuleDescriptor *m_module; - ConstString m_name; - RSSlot m_slot; -}; - -struct RSGlobalDescriptor { -public: - RSGlobalDescriptor(const RSModuleDescriptor *module, llvm::StringRef name) - : m_module(module), m_name(name) {} - - void Dump(Stream &strm) const; - - const RSModuleDescriptor *m_module; - ConstString m_name; -}; - -struct RSReductionDescriptor { - RSReductionDescriptor(const RSModuleDescriptor *module, uint32_t sig, - uint32_t accum_data_size, llvm::StringRef name, - llvm::StringRef init_name, llvm::StringRef accum_name, - llvm::StringRef comb_name, llvm::StringRef outc_name, - llvm::StringRef halter_name = ".") - : m_module(module), m_reduce_name(name), m_init_name(init_name), - m_accum_name(accum_name), m_comb_name(comb_name), - m_outc_name(outc_name), m_halter_name(halter_name), m_accum_sig(0), - m_accum_data_size(0), m_comb_name_generated(false) { - // TODO Check whether the combiner is an autogenerated name, and track - // this - } - - void Dump(Stream &strm) const; - - const RSModuleDescriptor *m_module; - ConstString m_reduce_name; // This is the name given to the general reduction - // as a group as passed to pragma - // reduce(m_reduce_name). There is no kernel function with this name - ConstString m_init_name; // The name of the initializer name. "." if no - // initializer given - ConstString m_accum_name; // The accumulator function name. "." if not given - ConstString m_comb_name; // The name of the combiner function. If this was not - // given, a name is generated by the - // compiler. TODO - ConstString m_outc_name; // The name of the outconverter - - ConstString m_halter_name; // The name of the halter function. XXX This is not - // yet specified by the RenderScript - // compiler or runtime, and its semantics and existence is still under - // discussion by the - // RenderScript Contributors - RSSlot m_accum_sig; // metatdata signature for this reduction (bitwise mask of - // type information (see - // libbcc/include/bcinfo/MetadataExtractor.h - uint32_t m_accum_data_size; // Data size of the accumulator function input - bool m_comb_name_generated; // Was the combiner name generated by the compiler -}; - -class RSModuleDescriptor { - std::string m_slang_version; - std::string m_bcc_version; - - bool ParseVersionInfo(llvm::StringRef *, size_t n_lines); - - bool ParseExportForeachCount(llvm::StringRef *, size_t n_lines); - - bool ParseExportVarCount(llvm::StringRef *, size_t n_lines); - - bool ParseExportReduceCount(llvm::StringRef *, size_t n_lines); - - bool ParseBuildChecksum(llvm::StringRef *, size_t n_lines); - - bool ParsePragmaCount(llvm::StringRef *, size_t n_lines); - -public: - RSModuleDescriptor(const lldb::ModuleSP &module) : m_module(module) {} - - ~RSModuleDescriptor() = default; - - bool ParseRSInfo(); - - void Dump(Stream &strm) const; - - void WarnIfVersionMismatch(Stream *s) const; - - const lldb::ModuleSP m_module; - std::vector m_kernels; - std::vector m_globals; - std::vector m_reductions; - std::map m_pragmas; - std::string m_resname; -}; - -struct RSScriptGroupDescriptor { - struct Kernel { - ConstString m_name; - lldb::addr_t m_addr; - }; - ConstString m_name; - std::vector m_kernels; -}; - -typedef std::vector RSScriptGroupList; - -class RSScriptGroupBreakpointResolver : public BreakpointResolver { -public: - RSScriptGroupBreakpointResolver(const lldb::BreakpointSP &bp, - 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) override; - - lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } - - lldb::BreakpointResolverSP - CopyForBreakpoint(lldb::BreakpointSP &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(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 { -public: - enum ModuleKind { - eModuleKindIgnored, - eModuleKindLibRS, - eModuleKindDriver, - eModuleKindImpl, - eModuleKindKernelObj - }; - - ~RenderScriptRuntime() override; - - // Static Functions - static void Initialize(); - - static void Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); - - static lldb::CommandObjectSP - GetCommandObject(CommandInterpreter &interpreter); - - static llvm::StringRef GetPluginNameStatic() { return "renderscript"; } - - static char ID; - - bool isA(const void *ClassID) const override { - return ClassID == &ID || CPPLanguageRuntime::isA(ClassID); - } - - static bool classof(const LanguageRuntime *runtime) { - return runtime->isA(&ID); - } - - static bool IsRenderScriptModule(const lldb::ModuleSP &module_sp); - - static ModuleKind GetModuleKind(const lldb::ModuleSP &module_sp); - - static void ModulesDidLoad(const lldb::ProcessSP &process_sp, - const ModuleList &module_list); - - bool GetDynamicTypeAndAddress(ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) override; - - TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, - ValueObject &static_value) override; - - bool CouldHaveDynamicValue(ValueObject &in_value) override; - - lldb::BreakpointResolverSP - CreateExceptionResolver(const lldb::BreakpointSP &bp, - bool catch_bp, bool throw_bp) override; - - bool LoadModule(const lldb::ModuleSP &module_sp); - - void DumpModules(Stream &strm) const; - - void DumpContexts(Stream &strm) const; - - void DumpKernels(Stream &strm) const; - - bool DumpAllocation(Stream &strm, StackFrame *frame_ptr, const uint32_t id); - - void ListAllocations(Stream &strm, StackFrame *frame_ptr, - const uint32_t index); - - bool RecomputeAllAllocations(Stream &strm, StackFrame *frame_ptr); - - bool PlaceBreakpointOnKernel( - lldb::TargetSP target, Stream &messages, const char *name, - const lldb_renderscript::RSCoordinate *coords = nullptr); - - bool PlaceBreakpointOnReduction( - lldb::TargetSP target, Stream &messages, const char *reduce_name, - const lldb_renderscript::RSCoordinate *coords = nullptr, - int kernel_types = ~(0)); - - bool PlaceBreakpointOnScriptGroup(lldb::TargetSP target, Stream &strm, - ConstString name, bool stop_on_all); - - void SetBreakAllKernels(bool do_break, lldb::TargetSP target); - - void DumpStatus(Stream &strm) const; - - void ModulesDidLoad(const ModuleList &module_list) override; - - bool LoadAllocation(Stream &strm, const uint32_t alloc_id, - const char *filename, StackFrame *frame_ptr); - - bool SaveAllocation(Stream &strm, const uint32_t alloc_id, - const char *filename, StackFrame *frame_ptr); - - void Update(); - - void Initiate(); - - const lldb_renderscript::RSScriptGroupList &GetScriptGroups() const { - return m_scriptGroups; - }; - - bool IsKnownKernel(ConstString name) { - for (const auto &module : m_rsmodules) - for (const auto &kernel : module->m_kernels) - if (kernel.m_name == name) - return true; - return false; - } - - bool GetOverrideExprOptions(clang::TargetOptions &prototype); - - // PluginInterface protocol - llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } - - 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 = - std::make_shared(target); - } - - void FixupScriptDetails(lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); - - void LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind); - - bool RefreshAllocation(AllocationDetails *alloc, StackFrame *frame_ptr); - - bool EvalRSExpression(const char *expression, StackFrame *frame_ptr, - uint64_t *result); - - lldb::BreakpointSP CreateScriptGroupBreakpoint(ConstString name, - bool multi); - - lldb::BreakpointSP CreateKernelBreakpoint(ConstString name); - - lldb::BreakpointSP CreateReductionBreakpoint(ConstString name, - int kernel_types); - - void BreakOnModuleKernels( - const lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); - - struct RuntimeHook; - typedef void (RenderScriptRuntime::*CaptureStateFn)( - RuntimeHook *hook_info, - ExecutionContext &context); // Please do this! - - struct HookDefn { - const char *name; - const char *symbol_name_m32; // mangled name for the 32 bit architectures - const char *symbol_name_m64; // mangled name for the 64 bit archs - uint32_t version; - ModuleKind kind; - CaptureStateFn grabber; - }; - - struct RuntimeHook { - lldb::addr_t address; - const HookDefn *defn; - lldb::BreakpointSP bp_sp; - }; - - typedef std::shared_ptr RuntimeHookSP; - - lldb::ModuleSP m_libRS; - lldb::ModuleSP m_libRSDriver; - lldb::ModuleSP m_libRSCpuRef; - std::vector m_rsmodules; - - std::vector> m_scripts; - std::vector> m_allocations; - - std::map - m_scriptMappings; - std::map m_runtimeHooks; - std::map> - m_conditional_breaks; - - lldb::SearchFilterSP - m_filtersp; // Needed to create breakpoints through Target API - - bool m_initiated; - bool m_debuggerPresentFlagged; - bool m_breakAllKernels; - static const HookDefn s_runtimeHookDefns[]; - static const size_t s_runtimeHookCount; - LLVMUserExpression::IRPasses *m_ir_passes; - -private: - RenderScriptRuntime(Process *process); // Call CreateInstance instead. - - static bool HookCallback(void *baton, StoppointCallbackContext *ctx, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - static bool KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - 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); - - void CaptureAllocationDestroy(RuntimeHook *hook_info, - ExecutionContext &context); - - void CaptureSetGlobalVar(RuntimeHook *hook_info, ExecutionContext &context); - - void CaptureScriptInvokeForEachMulti(RuntimeHook *hook_info, - ExecutionContext &context); - - AllocationDetails *FindAllocByID(Stream &strm, const uint32_t alloc_id); - - std::shared_ptr GetAllocationData(AllocationDetails *alloc, - StackFrame *frame_ptr); - - void SetElementSize(Element &elem); - - static bool GetFrameVarAsUnsigned(const lldb::StackFrameSP, - const char *var_name, uint64_t &val); - - void FindStructTypeName(Element &elem, StackFrame *frame_ptr); - - size_t PopulateElementHeaders(const std::shared_ptr header_buffer, - size_t offset, const Element &elem); - - size_t CalculateElementHeaderSize(const Element &elem); - - void SetConditional(lldb::BreakpointSP bp, lldb_private::Stream &messages, - const lldb_renderscript::RSCoordinate &coord); - // - // Helper functions for jitting the runtime - // - - bool JITDataPointer(AllocationDetails *alloc, StackFrame *frame_ptr, - uint32_t x = 0, uint32_t y = 0, uint32_t z = 0); - - bool JITTypePointer(AllocationDetails *alloc, StackFrame *frame_ptr); - - bool JITTypePacked(AllocationDetails *alloc, StackFrame *frame_ptr); - - bool JITElementPacked(Element &elem, const lldb::addr_t context, - StackFrame *frame_ptr); - - bool JITAllocationSize(AllocationDetails *alloc, StackFrame *frame_ptr); - - bool JITSubelements(Element &elem, const lldb::addr_t context, - StackFrame *frame_ptr); - - bool JITAllocationStride(AllocationDetails *alloc, StackFrame *frame_ptr); - - // Search for a script detail object using a target address. - // If a script does not currently exist this function will return nullptr. - // If 'create' is true and there is no previous script with this address, - // then a new Script detail object will be created for this address and - // returned. - ScriptDetails *LookUpScript(lldb::addr_t address, bool create); - - // Search for a previously saved allocation detail object using a target - // address. - // If an allocation does not exist for this address then nullptr will be - // returned. - AllocationDetails *LookUpAllocation(lldb::addr_t address); - - // Creates a new allocation with the specified address assigning a new ID and - // removes - // any previous stored allocation which has the same address. - AllocationDetails *CreateAllocation(lldb::addr_t address); - - bool GetIRPasses(LLVMUserExpression::IRPasses &passes) override; -}; - -} // namespace lldb_private - -#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTRUNTIME_H diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ /dev/null @@ -1,4937 +0,0 @@ -//===-- RenderScriptRuntime.cpp -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "RenderScriptRuntime.h" -#include "RenderScriptScriptGroup.h" - -#include "lldb/Breakpoint/StoppointCallbackContext.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Core/DumpDataExtractor.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/ValueObjectVariable.h" -#include "lldb/DataFormatters/DumpValueObjectOptions.h" -#include "lldb/Expression/UserExpression.h" -#include "lldb/Host/OptionParser.h" -#include "lldb/Interpreter/CommandInterpreter.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" -#include "lldb/Utility/Args.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/RegularExpression.h" -#include "lldb/Utility/Status.h" - -#include "llvm/ADT/StringSwitch.h" - -#include - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_renderscript; - -LLDB_PLUGIN_DEFINE(RenderScriptRuntime) - -#define FMT_COORD "(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")" - -char RenderScriptRuntime::ID = 0; - -namespace { - -// The empirical_type adds a basic level of validation to arbitrary data -// allowing us to track if data has been discovered and stored or not. An -// empirical_type will be marked as valid only if it has been explicitly -// assigned to. -template class empirical_type { -public: - // Ctor. Contents is invalid when constructed. - empirical_type() = default; - - // Return true and copy contents to out if valid, else return false. - bool get(type_t &out) const { - if (valid) - out = data; - return valid; - } - - // Return a pointer to the contents or nullptr if it was not valid. - const type_t *get() const { return valid ? &data : nullptr; } - - // Assign data explicitly. - void set(const type_t in) { - data = in; - valid = true; - } - - // Mark contents as invalid. - void invalidate() { valid = false; } - - // Returns true if this type contains valid data. - bool isValid() const { return valid; } - - // Assignment operator. - empirical_type &operator=(const type_t in) { - set(in); - return *this; - } - - // Dereference operator returns contents. - // Warning: Will assert if not valid so use only when you know data is valid. - const type_t &operator*() const { - assert(valid); - return data; - } - -protected: - bool valid = false; - type_t data; -}; - -// ArgItem is used by the GetArgs() function when reading function arguments -// from the target. -struct ArgItem { - enum { ePointer, eInt32, eInt64, eLong, eBool } type; - - uint64_t value; - - explicit operator uint64_t() const { return value; } -}; - -// Context structure to be passed into GetArgsXXX(), argument reading functions -// below. -struct GetArgsCtx { - RegisterContext *reg_ctx; - Process *process; -}; - -bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { - Log *log = GetLog(LLDBLog::Language); - - Status err; - - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); - - for (size_t i = 0; i < num_args; ++i) { - ArgItem &arg = arg_list[i]; - // advance up the stack by one argument - sp += sizeof(uint32_t); - // get the argument type size - size_t arg_size = sizeof(uint32_t); - // read the argument from memory - arg.value = 0; - Status err; - size_t read = - ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), err); - if (read != arg_size || !err.Success()) { - LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 " '%s'", - __FUNCTION__, uint64_t(i), err.AsCString()); - return false; - } - } - return true; -} - -bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { - Log *log = GetLog(LLDBLog::Language); - - // number of arguments passed in registers - static const uint32_t args_in_reg = 6; - // register passing order - static const std::array reg_names{ - {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}}; - // argument type to size mapping - static const std::array arg_size{{ - 8, // ePointer, - 4, // eInt32, - 8, // eInt64, - 8, // eLong, - 4, // eBool, - }}; - - Status err; - - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); - // step over the return address - sp += sizeof(uint64_t); - - // check the stack alignment was correct (16 byte aligned) - if ((sp & 0xf) != 0x0) { - LLDB_LOGF(log, "%s - stack misaligned", __FUNCTION__); - return false; - } - - // find the start of arguments on the stack - uint64_t sp_offset = 0; - for (uint32_t i = args_in_reg; i < num_args; ++i) { - sp_offset += arg_size[arg_list[i].type]; - } - // round up to multiple of 16 - sp_offset = (sp_offset + 0xf) & 0xf; - sp += sp_offset; - - for (size_t i = 0; i < num_args; ++i) { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < args_in_reg) { - const RegisterInfo *reg = - ctx.reg_ctx->GetRegisterInfoByName(reg_names[i]); - RegisterValue reg_val; - if (ctx.reg_ctx->ReadRegister(reg, reg_val)) - arg.value = reg_val.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else { - // get the argument type size - const size_t size = arg_size[arg_list[i].type]; - // read the argument from memory - arg.value = 0; - // note: due to little endian layout reading 4 or 8 bytes will give the - // correct value. - size_t read = ctx.process->ReadMemory(sp, &arg.value, size, err); - success = (err.Success() && read == size); - // advance past this argument - sp -= size; - } - // fail if we couldn't read this argument - if (!success) { - LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", - __FUNCTION__, uint64_t(i), err.AsCString("n/a")); - return false; - } - } - return true; -} - -bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { - // number of arguments passed in registers - static const uint32_t args_in_reg = 4; - - Log *log = GetLog(LLDBLog::Language); - - Status err; - - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); - - for (size_t i = 0; i < num_args; ++i) { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < args_in_reg) { - const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); - RegisterValue reg_val; - if (ctx.reg_ctx->ReadRegister(reg, reg_val)) - arg.value = reg_val.GetAsUInt32(0, &success); - } - // arguments passed on the stack - else { - // get the argument type size - const size_t arg_size = sizeof(uint32_t); - // clear all 64bits - arg.value = 0; - // read this argument from memory - size_t bytes_read = - ctx.process->ReadMemory(sp, &arg.value, arg_size, err); - success = (err.Success() && bytes_read == arg_size); - // advance the stack pointer - sp += sizeof(uint32_t); - } - // fail if we couldn't read this argument - if (!success) { - LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", - __FUNCTION__, uint64_t(i), err.AsCString("n/a")); - return false; - } - } - return true; -} - -bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { - // number of arguments passed in registers - static const uint32_t args_in_reg = 8; - - Log *log = GetLog(LLDBLog::Language); - - for (size_t i = 0; i < num_args; ++i) { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < args_in_reg) { - const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); - RegisterValue reg_val; - if (ctx.reg_ctx->ReadRegister(reg, reg_val)) - arg.value = reg_val.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else { - LLDB_LOGF(log, "%s - reading arguments spilled to stack not implemented", - __FUNCTION__); - } - // fail if we couldn't read this argument - if (!success) { - LLDB_LOGF(log, "%s - error reading argument: %" PRIu64, __FUNCTION__, - uint64_t(i)); - return false; - } - } - return true; -} - -bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { - // number of arguments passed in registers - static const uint32_t args_in_reg = 4; - // register file offset to first argument - static const uint32_t reg_offset = 4; - - Log *log = GetLog(LLDBLog::Language); - - Status err; - - // find offset to arguments on the stack (+16 to skip over a0-a3 shadow - // space) - uint64_t sp = ctx.reg_ctx->GetSP() + 16; - - for (size_t i = 0; i < num_args; ++i) { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < args_in_reg) { - const RegisterInfo *reg = - ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset); - RegisterValue reg_val; - if (ctx.reg_ctx->ReadRegister(reg, reg_val)) - arg.value = reg_val.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else { - const size_t arg_size = sizeof(uint32_t); - arg.value = 0; - size_t bytes_read = - ctx.process->ReadMemory(sp, &arg.value, arg_size, err); - success = (err.Success() && bytes_read == arg_size); - // advance the stack pointer - sp += arg_size; - } - // fail if we couldn't read this argument - if (!success) { - LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", - __FUNCTION__, uint64_t(i), err.AsCString("n/a")); - return false; - } - } - return true; -} - -bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { - // number of arguments passed in registers - static const uint32_t args_in_reg = 8; - // register file offset to first argument - static const uint32_t reg_offset = 4; - - Log *log = GetLog(LLDBLog::Language); - - Status err; - - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); - - for (size_t i = 0; i < num_args; ++i) { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < args_in_reg) { - const RegisterInfo *reg = - ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset); - RegisterValue reg_val; - if (ctx.reg_ctx->ReadRegister(reg, reg_val)) - arg.value = reg_val.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else { - // get the argument type size - const size_t arg_size = sizeof(uint64_t); - // clear all 64bits - arg.value = 0; - // read this argument from memory - size_t bytes_read = - ctx.process->ReadMemory(sp, &arg.value, arg_size, err); - success = (err.Success() && bytes_read == arg_size); - // advance the stack pointer - sp += arg_size; - } - // fail if we couldn't read this argument - if (!success) { - LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", - __FUNCTION__, uint64_t(i), err.AsCString("n/a")); - return false; - } - } - return true; -} - -bool GetArgs(ExecutionContext &exe_ctx, ArgItem *arg_list, size_t num_args) { - Log *log = GetLog(LLDBLog::Language); - - // verify that we have a target - if (!exe_ctx.GetTargetPtr()) { - LLDB_LOGF(log, "%s - invalid target", __FUNCTION__); - return false; - } - - GetArgsCtx ctx = {exe_ctx.GetRegisterContext(), exe_ctx.GetProcessPtr()}; - assert(ctx.reg_ctx && ctx.process); - - // dispatch based on architecture - switch (exe_ctx.GetTargetPtr()->GetArchitecture().GetMachine()) { - case llvm::Triple::ArchType::x86: - return GetArgsX86(ctx, arg_list, num_args); - - case llvm::Triple::ArchType::x86_64: - return GetArgsX86_64(ctx, arg_list, num_args); - - case llvm::Triple::ArchType::arm: - return GetArgsArm(ctx, arg_list, num_args); - - case llvm::Triple::ArchType::aarch64: - return GetArgsAarch64(ctx, arg_list, num_args); - - case llvm::Triple::ArchType::mipsel: - return GetArgsMipsel(ctx, arg_list, num_args); - - case llvm::Triple::ArchType::mips64el: - return GetArgsMips64el(ctx, arg_list, num_args); - - default: - // unsupported architecture - if (log) { - LLDB_LOGF(log, "%s - architecture not supported: '%s'", __FUNCTION__, - exe_ctx.GetTargetRef().GetArchitecture().GetArchitectureName()); - } - return false; - } -} - -bool IsRenderScriptScriptModule(ModuleSP module) { - if (!module) - return false; - return module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), - eSymbolTypeData) != nullptr; -} - -bool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) { - // takes an argument of the form 'num[,num][,num]'. Where 'coord_s' is a - // comma separated 1,2 or 3-dimensional coordinate with the whitespace - // trimmed. Missing coordinates are defaulted to zero. If parsing of any - // elements fails the contents of &coord are undefined and `false` is - // returned, `true` otherwise - - llvm::SmallVector matches; - - if (!RegularExpression("^([0-9]+),([0-9]+),([0-9]+)$") - .Execute(coord_s, &matches) && - !RegularExpression("^([0-9]+),([0-9]+)$").Execute(coord_s, &matches) && - !RegularExpression("^([0-9]+)$").Execute(coord_s, &matches)) - return false; - - auto get_index = [&](size_t idx, uint32_t &i) -> bool { - std::string group; - errno = 0; - if (idx + 1 < matches.size()) { - return !llvm::StringRef(matches[idx + 1]).getAsInteger(10, i); - } - return true; - }; - - 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 = GetLog(LLDBLog::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); - LLDB_LOGF(log, "%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 -// instance. -struct RenderScriptRuntime::ScriptDetails { - ~ScriptDetails() = default; - - enum ScriptType { eScript, eScriptC }; - - // The derived type of the script. - empirical_type type; - // The name of the original source file. - empirical_type res_name; - // Path to script .so file on the device. - empirical_type shared_lib; - // Directory where kernel objects are cached on device. - empirical_type cache_dir; - // Pointer to the context which owns this script. - empirical_type context; - // Pointer to the script object itself. - empirical_type script; -}; - -// This Element class represents the Element object in RS, defining the type -// associated with an Allocation. -struct RenderScriptRuntime::Element { - // Taken from rsDefines.h - enum DataKind { - RS_KIND_USER, - RS_KIND_PIXEL_L = 7, - RS_KIND_PIXEL_A, - RS_KIND_PIXEL_LA, - RS_KIND_PIXEL_RGB, - RS_KIND_PIXEL_RGBA, - RS_KIND_PIXEL_DEPTH, - RS_KIND_PIXEL_YUV, - RS_KIND_INVALID = 100 - }; - - // Taken from rsDefines.h - enum DataType { - RS_TYPE_NONE = 0, - RS_TYPE_FLOAT_16, - RS_TYPE_FLOAT_32, - RS_TYPE_FLOAT_64, - RS_TYPE_SIGNED_8, - RS_TYPE_SIGNED_16, - RS_TYPE_SIGNED_32, - RS_TYPE_SIGNED_64, - RS_TYPE_UNSIGNED_8, - RS_TYPE_UNSIGNED_16, - RS_TYPE_UNSIGNED_32, - RS_TYPE_UNSIGNED_64, - RS_TYPE_BOOLEAN, - - RS_TYPE_UNSIGNED_5_6_5, - RS_TYPE_UNSIGNED_5_5_5_1, - RS_TYPE_UNSIGNED_4_4_4_4, - - RS_TYPE_MATRIX_4X4, - RS_TYPE_MATRIX_3X3, - RS_TYPE_MATRIX_2X2, - - RS_TYPE_ELEMENT = 1000, - RS_TYPE_TYPE, - RS_TYPE_ALLOCATION, - RS_TYPE_SAMPLER, - RS_TYPE_SCRIPT, - RS_TYPE_MESH, - RS_TYPE_PROGRAM_FRAGMENT, - RS_TYPE_PROGRAM_VERTEX, - RS_TYPE_PROGRAM_RASTER, - RS_TYPE_PROGRAM_STORE, - RS_TYPE_FONT, - - RS_TYPE_INVALID = 10000 - }; - - std::vector children; // Child Element fields for structs - empirical_type - element_ptr; // Pointer to the RS Element of the Type - empirical_type - type; // Type of each data pointer stored by the allocation - empirical_type - type_kind; // Defines pixel type if Allocation is created from an image - empirical_type - type_vec_size; // Vector size of each data point, e.g '4' for uchar4 - empirical_type field_count; // Number of Subelements - empirical_type datum_size; // Size of a single Element with padding - empirical_type padding; // Number of padding bytes - empirical_type - array_size; // Number of items in array, only needed for structs - ConstString type_name; // Name of type, only needed for structs - - static ConstString - GetFallbackStructName(); // Print this as the type name of a struct Element - // If we can't resolve the actual struct name - - bool ShouldRefresh() const { - const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0; - const bool valid_type = - type.isValid() && type_vec_size.isValid() && type_kind.isValid(); - return !valid_ptr || !valid_type || !datum_size.isValid(); - } -}; - -// This AllocationDetails class collects data associated with a single -// allocation instance. -struct RenderScriptRuntime::AllocationDetails { - struct Dimension { - uint32_t dim_1; - uint32_t dim_2; - uint32_t dim_3; - uint32_t cube_map; - - Dimension() { - dim_1 = 0; - dim_2 = 0; - dim_3 = 0; - cube_map = 0; - } - }; - - // The FileHeader struct specifies the header we use for writing allocations - // to a binary file. Our format begins with the ASCII characters "RSAD", - // identifying the file as an allocation dump. Member variables dims and - // hdr_size are then written consecutively, immediately followed by an - // instance of the ElementHeader struct. Because Elements can contain - // subelements, there may be more than one instance of the ElementHeader - // struct. With this first instance being the root element, and the other - // instances being the root's descendants. To identify which instances are an - // ElementHeader's children, each struct is immediately followed by a - // sequence of consecutive offsets to the start of its child structs. These - // offsets are - // 4 bytes in size, and the 0 offset signifies no more children. - struct FileHeader { - uint8_t ident[4]; // ASCII 'RSAD' identifying the file - uint32_t dims[3]; // Dimensions - uint16_t hdr_size; // Header size in bytes, including all element headers - }; - - struct ElementHeader { - uint16_t type; // DataType enum - uint32_t kind; // DataKind enum - uint32_t element_size; // Size of a single element, including padding - uint16_t vector_size; // Vector width - uint32_t array_size; // Number of elements in array - }; - - // Monotonically increasing from 1 - static uint32_t ID; - - // Maps Allocation DataType enum and vector size to printable strings using - // mapping from RenderScript numerical types summary documentation - static const char *RsDataTypeToString[][4]; - - // Maps Allocation DataKind enum to printable strings - static const char *RsDataKindToString[]; - - // Maps allocation types to format sizes for printing. - static const uint32_t RSTypeToFormat[][3]; - - // Give each allocation an ID as a way - // for commands to reference it. - const uint32_t id; - - // Allocation Element type - RenderScriptRuntime::Element element; - // Dimensions of the Allocation - empirical_type dimension; - // Pointer to address of the RS Allocation - empirical_type address; - // Pointer to the data held by the Allocation - empirical_type data_ptr; - // Pointer to the RS Type of the Allocation - empirical_type type_ptr; - // Pointer to the RS Context of the Allocation - empirical_type context; - // Size of the allocation - empirical_type size; - // Stride between rows of the allocation - empirical_type stride; - - // Give each allocation an id, so we can reference it in user commands. - AllocationDetails() : id(ID++) {} - - bool ShouldRefresh() const { - bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0; - valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0; - return !valid_ptrs || !dimension.isValid() || !size.isValid() || - element.ShouldRefresh(); - } -}; - -ConstString RenderScriptRuntime::Element::GetFallbackStructName() { - static const ConstString FallbackStructName("struct"); - return FallbackStructName; -} - -uint32_t RenderScriptRuntime::AllocationDetails::ID = 1; - -const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = { - "User", "Undefined", "Undefined", "Undefined", - "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7 - "L Pixel", "A Pixel", "LA Pixel", "RGB Pixel", - "RGBA Pixel", "Pixel Depth", "YUV Pixel"}; - -const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = { - {"None", "None", "None", "None"}, - {"half", "half2", "half3", "half4"}, - {"float", "float2", "float3", "float4"}, - {"double", "double2", "double3", "double4"}, - {"char", "char2", "char3", "char4"}, - {"short", "short2", "short3", "short4"}, - {"int", "int2", "int3", "int4"}, - {"long", "long2", "long3", "long4"}, - {"uchar", "uchar2", "uchar3", "uchar4"}, - {"ushort", "ushort2", "ushort3", "ushort4"}, - {"uint", "uint2", "uint3", "uint4"}, - {"ulong", "ulong2", "ulong3", "ulong4"}, - {"bool", "bool2", "bool3", "bool4"}, - {"packed_565", "packed_565", "packed_565", "packed_565"}, - {"packed_5551", "packed_5551", "packed_5551", "packed_5551"}, - {"packed_4444", "packed_4444", "packed_4444", "packed_4444"}, - {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"}, - {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"}, - {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"}, - - // Handlers - {"RS Element", "RS Element", "RS Element", "RS Element"}, - {"RS Type", "RS Type", "RS Type", "RS Type"}, - {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"}, - {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"}, - {"RS Script", "RS Script", "RS Script", "RS Script"}, - - // Deprecated - {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"}, - {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", - "RS Program Fragment"}, - {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", - "RS Program Vertex"}, - {"RS Program Raster", "RS Program Raster", "RS Program Raster", - "RS Program Raster"}, - {"RS Program Store", "RS Program Store", "RS Program Store", - "RS Program Store"}, - {"RS Font", "RS Font", "RS Font", "RS Font"}}; - -// Used as an index into the RSTypeToFormat array elements -enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize }; - -// { format enum of single element, format enum of element vector, size of -// element} -const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = { - // RS_TYPE_NONE - {eFormatHex, eFormatHex, 1}, - // RS_TYPE_FLOAT_16 - {eFormatFloat, eFormatVectorOfFloat16, 2}, - // RS_TYPE_FLOAT_32 - {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, - // RS_TYPE_FLOAT_64 - {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, - // RS_TYPE_SIGNED_8 - {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, - // RS_TYPE_SIGNED_16 - {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)}, - // RS_TYPE_SIGNED_32 - {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)}, - // RS_TYPE_SIGNED_64 - {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)}, - // RS_TYPE_UNSIGNED_8 - {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)}, - // RS_TYPE_UNSIGNED_16 - {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)}, - // RS_TYPE_UNSIGNED_32 - {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)}, - // RS_TYPE_UNSIGNED_64 - {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)}, - // RS_TYPE_BOOL - {eFormatBoolean, eFormatBoolean, 1}, - // RS_TYPE_UNSIGNED_5_6_5 - {eFormatHex, eFormatHex, sizeof(uint16_t)}, - // RS_TYPE_UNSIGNED_5_5_5_1 - {eFormatHex, eFormatHex, sizeof(uint16_t)}, - // RS_TYPE_UNSIGNED_4_4_4_4 - {eFormatHex, eFormatHex, sizeof(uint16_t)}, - // RS_TYPE_MATRIX_4X4 - {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16}, - // RS_TYPE_MATRIX_3X3 - {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9}, - // RS_TYPE_MATRIX_2X2 - {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4}}; - -// Static Functions -LanguageRuntime * -RenderScriptRuntime::CreateInstance(Process *process, - lldb::LanguageType language) { - - if (language == eLanguageTypeExtRenderScript) - return new RenderScriptRuntime(process); - else - return nullptr; -} - -// Callback with a module to search for matching symbols. We first check that -// the module contains RS kernels. Then look for a symbol which matches our -// kernel name. The breakpoint address is finally set using the address of this -// symbol. -Searcher::CallbackReturn -RSBreakpointResolver::SearchCallback(SearchFilter &filter, - SymbolContext &context, Address *) { - BreakpointSP breakpoint_sp = GetBreakpoint(); - assert(breakpoint_sp); - - ModuleSP module = context.module_sp; - - if (!module || !IsRenderScriptScriptModule(module)) - return Searcher::eCallbackReturnContinue; - - // Attempt to set a breakpoint on the kernel name symbol within the module - // library. If it's not found, it's likely debug info is unavailable - try to - // set a breakpoint on .expand. - const Symbol *kernel_sym = - module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode); - if (!kernel_sym) { - std::string kernel_name_expanded(m_kernel_name.AsCString()); - kernel_name_expanded.append(".expand"); - kernel_sym = module->FindFirstSymbolWithNameAndType( - ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); - } - - if (kernel_sym) { - Address bp_addr = kernel_sym->GetAddress(); - if (filter.AddressPasses(bp_addr)) - breakpoint_sp->AddLocation(bp_addr); - } - - return Searcher::eCallbackReturnContinue; -} - -Searcher::CallbackReturn -RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, - lldb_private::SymbolContext &context, - Address *) { - BreakpointSP breakpoint_sp = GetBreakpoint(); - assert(breakpoint_sp); - - // We need to have access to the list of reductions currently parsed, as - // reduce names don't actually exist as symbols in a module. They are only - // identifiable by parsing the .rs.info packet, or finding the expand symbol. - // We therefore need access to the list of parsed rs modules to properly - // resolve reduction names. - Log *log = GetLog(LLDBLog::Breakpoints); - ModuleSP module = context.module_sp; - - if (!module || !IsRenderScriptScriptModule(module)) - return Searcher::eCallbackReturnContinue; - - if (!m_rsmodules) - return Searcher::eCallbackReturnContinue; - - for (const auto &module_desc : *m_rsmodules) { - if (module_desc->m_module != module) - continue; - - for (const auto &reduction : module_desc->m_reductions) { - if (reduction.m_reduce_name != m_reduce_name) - continue; - - std::array, 5> funcs{ - {{reduction.m_init_name, eKernelTypeInit}, - {reduction.m_accum_name, eKernelTypeAccum}, - {reduction.m_comb_name, eKernelTypeComb}, - {reduction.m_outc_name, eKernelTypeOutC}, - {reduction.m_halter_name, eKernelTypeHalter}}}; - - for (const auto &kernel : funcs) { - // Skip constituent functions that don't match our spec - if (!(m_kernel_types & kernel.second)) - continue; - - const auto kernel_name = kernel.first; - const auto symbol = module->FindFirstSymbolWithNameAndType( - kernel_name, eSymbolTypeCode); - if (!symbol) - continue; - - auto address = symbol->GetAddress(); - if (filter.AddressPasses(address)) { - bool new_bp; - if (!SkipPrologue(module, address)) { - LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__); - } - breakpoint_sp->AddLocation(address, &new_bp); - LLDB_LOGF(log, "%s: %s reduction breakpoint on %s in %s", - __FUNCTION__, new_bp ? "new" : "existing", - kernel_name.GetCString(), - address.GetModule()->GetFileSpec().GetPath().c_str()); - } - } - } - } - return eCallbackReturnContinue; -} - -Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback( - SearchFilter &filter, SymbolContext &context, Address *addr) { - - BreakpointSP breakpoint_sp = GetBreakpoint(); - if (!breakpoint_sp) - return eCallbackReturnContinue; - - Log *log = GetLog(LLDBLog::Breakpoints); - ModuleSP &module = context.module_sp; - - if (!module || !IsRenderScriptScriptModule(module)) - return Searcher::eCallbackReturnContinue; - - std::vector names; - Breakpoint& breakpoint = *breakpoint_sp; - breakpoint.GetNames(names); - if (names.empty()) - return eCallbackReturnContinue; - - for (auto &name : names) { - const RSScriptGroupDescriptorSP sg = FindScriptGroup(ConstString(name)); - if (!sg) { - LLDB_LOGF(log, "%s: could not find script group for %s", __FUNCTION__, - name.c_str()); - continue; - } - - LLDB_LOGF(log, "%s: Found ScriptGroup for %s", __FUNCTION__, name.c_str()); - - for (const RSScriptGroupDescriptor::Kernel &k : sg->m_kernels) { - if (log) { - LLDB_LOGF(log, "%s: Adding breakpoint for %s", __FUNCTION__, - k.m_name.AsCString()); - LLDB_LOGF(log, "%s: Kernel address 0x%" PRIx64, __FUNCTION__, k.m_addr); - } - - const lldb_private::Symbol *sym = - module->FindFirstSymbolWithNameAndType(k.m_name, eSymbolTypeCode); - if (!sym) { - LLDB_LOGF(log, "%s: Unable to find symbol for %s", __FUNCTION__, - k.m_name.AsCString()); - continue; - } - - if (log) { - LLDB_LOGF(log, "%s: Found symbol name is %s", __FUNCTION__, - sym->GetName().AsCString()); - } - - auto address = sym->GetAddress(); - if (!SkipPrologue(module, address)) { - LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__); - } - - bool new_bp; - breakpoint.AddLocation(address, &new_bp); - - LLDB_LOGF(log, "%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, - GetCommandObject); -} - -void RenderScriptRuntime::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -RenderScriptRuntime::ModuleKind -RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) { - if (module_sp) { - if (IsRenderScriptScriptModule(module_sp)) - return eModuleKindKernelObj; - - // Is this the main RS runtime library - const ConstString rs_lib("libRS.so"); - if (module_sp->GetFileSpec().GetFilename() == rs_lib) { - return eModuleKindLibRS; - } - - const ConstString rs_driverlib("libRSDriver.so"); - if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) { - return eModuleKindDriver; - } - - const ConstString rs_cpureflib("libRSCpuRef.so"); - if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) { - return eModuleKindImpl; - } - } - return eModuleKindIgnored; -} - -bool RenderScriptRuntime::IsRenderScriptModule( - const lldb::ModuleSP &module_sp) { - return GetModuleKind(module_sp) != eModuleKindIgnored; -} - -void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) { - std::lock_guard guard(module_list.GetMutex()); - - size_t num_modules = module_list.GetSize(); - for (size_t i = 0; i < num_modules; i++) { - auto mod = module_list.GetModuleAtIndex(i); - if (IsRenderScriptModule(mod)) { - LoadModule(mod); - } - } -} - -bool RenderScriptRuntime::GetDynamicTypeAndAddress( - ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &address, - Value::ValueType &value_type) { - return false; -} - -TypeAndOrName -RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, - ValueObject &static_value) { - return type_and_or_name; -} - -bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) { - return false; -} - -lldb::BreakpointResolverSP -RenderScriptRuntime::CreateExceptionResolver(const lldb::BreakpointSP &bp, - bool catch_bp, bool throw_bp) { - BreakpointResolverSP resolver_sp; - return resolver_sp; -} - -const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = - { - // rsdScript - {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP" - "NS0_7ScriptCEPKcS7_PKhjj", - "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_" - "7ScriptCEPKcS7_PKhmj", - 0, RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureScriptInit}, - {"rsdScriptInvokeForEachMulti", - "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" - "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", - "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" - "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", - 0, RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti}, - {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render" - "script7ContextEPKNS0_6ScriptEjPvj", - "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_" - "6ScriptEjPvm", - 0, RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar}, - - // rsdAllocation - {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C" - "ontextEPNS0_10AllocationEb", - "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_" - "10AllocationEb", - 0, RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureAllocationInit}, - {"rsdAllocationRead2D", - "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" - "10AllocationEjjj23RsAllocationCubemapFacejjPvjj", - "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" - "10AllocationEjjj23RsAllocationCubemapFacejjPvmm", - 0, RenderScriptRuntime::eModuleKindDriver, nullptr}, - {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc" - "ript7ContextEPNS0_10AllocationE", - "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_" - "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]); - -bool RenderScriptRuntime::HookCallback(void *baton, - StoppointCallbackContext *ctx, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) { - RuntimeHook *hook = (RuntimeHook *)baton; - ExecutionContext exe_ctx(ctx->exe_ctx_ref); - - RenderScriptRuntime *lang_rt = llvm::cast( - exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - lang_rt->HookCallback(hook, exe_ctx); - - return false; -} - -void RenderScriptRuntime::HookCallback(RuntimeHook *hook, - ExecutionContext &exe_ctx) { - Log *log = GetLog(LLDBLog::Language); - - LLDB_LOGF(log, "%s - '%s'", __FUNCTION__, hook->defn->name); - - if (hook->defn->grabber) { - (this->*(hook->defn->grabber))(hook, exe_ctx); - } -} - -void RenderScriptRuntime::CaptureDebugHintScriptGroup2( - RuntimeHook *hook_info, ExecutionContext &context) { - Log *log = GetLog(LLDBLog::Language); - - enum { - eGroupName = 0, - eGroupNameSize, - eKernel, - eKernelCount, - }; - - std::array 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())) { - LLDB_LOGF(log, "%s - Error while reading the function parameters", - __FUNCTION__); - return; - } else if (log) { - LLDB_LOGF(log, "%s - groupName : 0x%" PRIx64, __FUNCTION__, - addr_t(args[eGroupName])); - LLDB_LOGF(log, "%s - groupNameSize: %" PRIu64, __FUNCTION__, - uint64_t(args[eGroupNameSize])); - LLDB_LOGF(log, "%s - kernel : 0x%" PRIx64, __FUNCTION__, - addr_t(args[eKernel])); - LLDB_LOGF(log, "%s - kernelCount : %" PRIu64, __FUNCTION__, - uint64_t(args[eKernelCount])); - } - - // parse script group name - ConstString group_name; - { - Status err; - const uint64_t len = uint64_t(args[eGroupNameSize]); - std::unique_ptr 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()) { - LLDB_LOGF(log, "Error reading scriptgroup name from target"); - return; - } else { - LLDB_LOGF(log, "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 = std::make_shared(); - group->m_name = group_name; - m_scriptGroups.push_back(group); - } else { - // already have this script group - LLDB_LOGF(log, "Attempt to add duplicate script group %s", - group_name.AsCString()); - return; - } - } - assert(group); - - const uint32_t target_ptr_size = m_process->GetAddressByteSize(); - std::vector 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; - Status err; - size_t read = - m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err); - if (!err.Success() || read != target_ptr_size) { - LLDB_LOGF(log, "Error parsing kernel address %" PRIu64 " in script group", - i); - return; - } - LLDB_LOGF(log, "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)) { - LLDB_LOGF(log, "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; - LLDB_LOGF(log, "%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(); - LLDB_LOGF(log, "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())) { - LLDB_LOGF(log, "Found breakpoint with name %s", - group_name.AsCString()); - bp->ResolveBreakpoint(); - } - } - } - } -} - -void RenderScriptRuntime::CaptureScriptInvokeForEachMulti( - RuntimeHook *hook, ExecutionContext &exe_ctx) { - Log *log = GetLog(LLDBLog::Language); - - enum { - eRsContext = 0, - eRsScript, - eRsSlot, - eRsAIns, - eRsInLen, - eRsAOut, - eRsUsr, - eRsUsrLen, - eRsSc, - }; - - std::array args{{ - ArgItem{ArgItem::ePointer, 0}, // const Context *rsc - ArgItem{ArgItem::ePointer, 0}, // Script *s - ArgItem{ArgItem::eInt32, 0}, // uint32_t slot - ArgItem{ArgItem::ePointer, 0}, // const Allocation **aIns - ArgItem{ArgItem::eInt32, 0}, // size_t inLen - ArgItem{ArgItem::ePointer, 0}, // Allocation *aout - ArgItem{ArgItem::ePointer, 0}, // const void *usr - ArgItem{ArgItem::eInt32, 0}, // size_t usrLen - ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall *sc - }}; - - bool success = GetArgs(exe_ctx, &args[0], args.size()); - if (!success) { - LLDB_LOGF(log, "%s - Error while reading the function parameters", - __FUNCTION__); - return; - } - - const uint32_t target_ptr_size = m_process->GetAddressByteSize(); - Status err; - std::vector allocs; - - // traverse allocation list - for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) { - // calculate offest to allocation pointer - const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size; - - // Note: due to little endian layout, reading 32bits or 64bits into res - // will give the correct results. - uint64_t result = 0; - size_t read = m_process->ReadMemory(addr, &result, target_ptr_size, err); - if (read != target_ptr_size || !err.Success()) { - LLDB_LOGF(log, - "%s - Error while reading allocation list argument %" PRIu64, - __FUNCTION__, i); - } else { - allocs.push_back(result); - } - } - - // if there is an output allocation track it - if (uint64_t alloc_out = uint64_t(args[eRsAOut])) { - allocs.push_back(alloc_out); - } - - // for all allocations we have found - for (const uint64_t alloc_addr : allocs) { - AllocationDetails *alloc = LookUpAllocation(alloc_addr); - if (!alloc) - alloc = CreateAllocation(alloc_addr); - - if (alloc) { - // save the allocation address - if (alloc->address.isValid()) { - // check the allocation address we already have matches - assert(*alloc->address.get() == alloc_addr); - } else { - alloc->address = alloc_addr; - } - - // save the context - if (log) { - if (alloc->context.isValid() && - *alloc->context.get() != addr_t(args[eRsContext])) - LLDB_LOGF(log, "%s - Allocation used by multiple contexts", - __FUNCTION__); - } - alloc->context = addr_t(args[eRsContext]); - } - } - - // make sure we track this script object - if (lldb_private::RenderScriptRuntime::ScriptDetails *script = - LookUpScript(addr_t(args[eRsScript]), true)) { - if (log) { - if (script->context.isValid() && - *script->context.get() != addr_t(args[eRsContext])) - LLDB_LOGF(log, "%s - Script used by multiple contexts", __FUNCTION__); - } - script->context = addr_t(args[eRsContext]); - } -} - -void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook, - ExecutionContext &context) { - Log *log = GetLog(LLDBLog::Language); - - enum { - eRsContext, - eRsScript, - eRsId, - eRsData, - eRsLength, - }; - - std::array args{{ - ArgItem{ArgItem::ePointer, 0}, // eRsContext - ArgItem{ArgItem::ePointer, 0}, // eRsScript - ArgItem{ArgItem::eInt32, 0}, // eRsId - ArgItem{ArgItem::ePointer, 0}, // eRsData - ArgItem{ArgItem::eInt32, 0}, // eRsLength - }}; - - bool success = GetArgs(context, &args[0], args.size()); - if (!success) { - LLDB_LOGF(log, "%s - error reading the function parameters.", __FUNCTION__); - return; - } - - if (log) { - LLDB_LOGF(log, - "%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 - ":%" PRIu64 "bytes.", - __FUNCTION__, uint64_t(args[eRsContext]), - uint64_t(args[eRsScript]), uint64_t(args[eRsId]), - uint64_t(args[eRsData]), uint64_t(args[eRsLength])); - - addr_t script_addr = addr_t(args[eRsScript]); - if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) { - auto rsm = m_scriptMappings[script_addr]; - if (uint64_t(args[eRsId]) < rsm->m_globals.size()) { - auto rsg = rsm->m_globals[uint64_t(args[eRsId])]; - LLDB_LOGF(log, "%s - Setting of '%s' within '%s' inferred", - __FUNCTION__, rsg.m_name.AsCString(), - rsm->m_module->GetFileSpec().GetFilename().AsCString()); - } - } - } -} - -void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook, - ExecutionContext &exe_ctx) { - Log *log = GetLog(LLDBLog::Language); - - enum { eRsContext, eRsAlloc, eRsForceZero }; - - std::array args{{ - ArgItem{ArgItem::ePointer, 0}, // eRsContext - ArgItem{ArgItem::ePointer, 0}, // eRsAlloc - ArgItem{ArgItem::eBool, 0}, // eRsForceZero - }}; - - bool success = GetArgs(exe_ctx, &args[0], args.size()); - if (!success) { - LLDB_LOGF(log, "%s - error while reading the function parameters", - __FUNCTION__); - return; - } - - LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", - __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]), - uint64_t(args[eRsForceZero])); - - AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc])); - if (alloc) - alloc->context = uint64_t(args[eRsContext]); -} - -void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook, - ExecutionContext &exe_ctx) { - Log *log = GetLog(LLDBLog::Language); - - enum { - eRsContext, - eRsAlloc, - }; - - std::array args{{ - ArgItem{ArgItem::ePointer, 0}, // eRsContext - ArgItem{ArgItem::ePointer, 0}, // eRsAlloc - }}; - - bool success = GetArgs(exe_ctx, &args[0], args.size()); - if (!success) { - LLDB_LOGF(log, "%s - error while reading the function parameters.", - __FUNCTION__); - return; - } - - LLDB_LOGF(log, "%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__, - uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc])); - - for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) { - auto &allocation_up = *iter; // get the unique pointer - if (allocation_up->address.isValid() && - *allocation_up->address.get() == addr_t(args[eRsAlloc])) { - m_allocations.erase(iter); - LLDB_LOGF(log, "%s - deleted allocation entry.", __FUNCTION__); - return; - } - } - - LLDB_LOGF(log, "%s - couldn't find destroyed allocation.", __FUNCTION__); -} - -void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook, - ExecutionContext &exe_ctx) { - Log *log = GetLog(LLDBLog::Language); - - Status err; - Process *process = exe_ctx.GetProcessPtr(); - - enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr }; - - std::array args{ - {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}, - ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}}; - bool success = GetArgs(exe_ctx, &args[0], args.size()); - if (!success) { - LLDB_LOGF(log, "%s - error while reading the function parameters.", - __FUNCTION__); - return; - } - - std::string res_name; - process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), res_name, err); - if (err.Fail()) { - LLDB_LOGF(log, "%s - error reading res_name: %s.", __FUNCTION__, - err.AsCString()); - } - - std::string cache_dir; - process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cache_dir, err); - if (err.Fail()) { - LLDB_LOGF(log, "%s - error reading cache_dir: %s.", __FUNCTION__, - err.AsCString()); - } - - LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .", - __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsScript]), - res_name.c_str(), cache_dir.c_str()); - - if (res_name.size() > 0) { - StreamString strm; - strm.Printf("librs.%s.so", res_name.c_str()); - - ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true); - if (script) { - script->type = ScriptDetails::eScriptC; - script->cache_dir = cache_dir; - script->res_name = res_name; - script->shared_lib = std::string(strm.GetString()); - script->context = addr_t(args[eRsContext]); - } - - LLDB_LOGF(log, - "%s - '%s' tagged with context 0x%" PRIx64 - " and script 0x%" PRIx64 ".", - __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]), - uint64_t(args[eRsScript])); - } else if (log) { - LLDB_LOGF(log, "%s - resource name invalid, Script not tagged.", - __FUNCTION__); - } -} - -void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, - ModuleKind kind) { - Log *log = GetLog(LLDBLog::Language); - - if (!module) { - return; - } - - Target &target = GetProcess()->GetTarget(); - const llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine(); - - if (machine != llvm::Triple::ArchType::x86 && - machine != llvm::Triple::ArchType::arm && - machine != llvm::Triple::ArchType::aarch64 && - machine != llvm::Triple::ArchType::mipsel && - machine != llvm::Triple::ArchType::mips64el && - machine != llvm::Triple::ArchType::x86_64) { - LLDB_LOGF(log, "%s - unable to hook runtime functions.", __FUNCTION__); - return; - } - - const uint32_t target_ptr_size = - target.GetArchitecture().GetAddressByteSize(); - - std::array hook_placed; - hook_placed.fill(false); - - for (size_t idx = 0; idx < s_runtimeHookCount; idx++) { - const HookDefn *hook_defn = &s_runtimeHookDefns[idx]; - if (hook_defn->kind != kind) { - continue; - } - - const char *symbol_name = (target_ptr_size == 4) - ? hook_defn->symbol_name_m32 - : hook_defn->symbol_name_m64; - - const Symbol *sym = module->FindFirstSymbolWithNameAndType( - ConstString(symbol_name), eSymbolTypeCode); - if (!sym) { - if (log) { - LLDB_LOGF(log, "%s - symbol '%s' related to the function %s not found", - __FUNCTION__, symbol_name, hook_defn->name); - } - continue; - } - - addr_t addr = sym->GetLoadAddress(&target); - if (addr == LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "%s - unable to resolve the address of hook function '%s' " - "with symbol '%s'.", - __FUNCTION__, hook_defn->name, symbol_name); - continue; - } else { - LLDB_LOGF(log, "%s - function %s, address resolved at 0x%" PRIx64, - __FUNCTION__, hook_defn->name, addr); - } - - RuntimeHookSP hook(new RuntimeHook()); - hook->address = addr; - hook->defn = hook_defn; - hook->bp_sp = target.CreateBreakpoint(addr, true, false); - hook->bp_sp->SetCallback(HookCallback, hook.get(), true); - m_runtimeHooks[addr] = hook; - if (log) { - LLDB_LOGF(log, - "%s - successfully hooked '%s' in '%s' version %" PRIu64 - " at 0x%" PRIx64 ".", - __FUNCTION__, hook_defn->name, - 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; - LLDB_LOGF(log, "%s - function %s was not hooked", __FUNCTION__, - hook_defn.name); - } - } -} - -void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) { - if (!rsmodule_sp) - return; - - Log *log = GetLog(LLDBLog::Language); - - const ModuleSP module = rsmodule_sp->m_module; - const FileSpec &file = module->GetPlatformFileSpec(); - - // Iterate over all of the scripts that we currently know of. Note: We cant - // push or pop to m_scripts here or it may invalidate rs_script. - for (const auto &rs_script : m_scripts) { - // Extract the expected .so file path for this script. - std::string shared_lib; - if (!rs_script->shared_lib.get(shared_lib)) - continue; - - // Only proceed if the module that has loaded corresponds to this script. - if (file.GetFilename() != ConstString(shared_lib.c_str())) - continue; - - // Obtain the script address which we use as a key. - lldb::addr_t script; - if (!rs_script->script.get(script)) - continue; - - // If we have a script mapping for the current script. - if (m_scriptMappings.find(script) != m_scriptMappings.end()) { - // if the module we have stored is different to the one we just received. - if (m_scriptMappings[script] != rsmodule_sp) { - LLDB_LOGF( - log, - "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.", - __FUNCTION__, (uint64_t)script, - rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); - } - } - // We don't have a script mapping for the current script. - else { - // Obtain the script resource name. - std::string res_name; - if (rs_script->res_name.get(res_name)) - // Set the modules resource name. - rsmodule_sp->m_resname = res_name; - // Add Script/Module pair to map. - m_scriptMappings[script] = rsmodule_sp; - LLDB_LOGF(log, "%s - script %" PRIx64 " associated with rsmodule '%s'.", - __FUNCTION__, (uint64_t)script, - rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); - } - } -} - -// Uses the Target API to evaluate the expression passed as a parameter to the -// function The result of that expression is returned an unsigned 64 bit int, -// via the result* parameter. Function returns true on success, and false on -// failure -bool RenderScriptRuntime::EvalRSExpression(const char *expr, - StackFrame *frame_ptr, - uint64_t *result) { - Log *log = GetLog(LLDBLog::Language); - LLDB_LOGF(log, "%s(%s)", __FUNCTION__, expr); - - ValueObjectSP expr_result; - EvaluateExpressionOptions options; - options.SetLanguage(lldb::eLanguageTypeC_plus_plus); - // Perform the actual expression evaluation - auto &target = GetProcess()->GetTarget(); - target.EvaluateExpression(expr, frame_ptr, expr_result, options); - - if (!expr_result) { - LLDB_LOGF(log, "%s: couldn't evaluate expression.", __FUNCTION__); - return false; - } - - // The result of the expression is invalid - if (!expr_result->GetError().Success()) { - Status err = expr_result->GetError(); - // Expression returned is void, so this is actually a success - if (err.GetError() == UserExpression::kNoResult) { - LLDB_LOGF(log, "%s - expression returned void.", __FUNCTION__); - - result = nullptr; - return true; - } - - LLDB_LOGF(log, "%s - error evaluating expression result: %s", __FUNCTION__, - err.AsCString()); - return false; - } - - bool success = false; - // We only read the result as an uint32_t. - *result = expr_result->GetValueAsUnsigned(0, &success); - - if (!success) { - LLDB_LOGF(log, "%s - couldn't convert expression result to uint32_t", - __FUNCTION__); - return false; - } - - return true; -} - -namespace { -// Used to index expression format strings -enum ExpressionStrings { - eExprGetOffsetPtr = 0, - eExprAllocGetType, - eExprTypeDimX, - eExprTypeDimY, - eExprTypeDimZ, - eExprTypeElemPtr, - eExprElementType, - eExprElementKind, - eExprElementVec, - eExprElementFieldCount, - eExprSubelementsId, - eExprSubelementsName, - eExprSubelementsArrSize, - - _eExprLast // keep at the end, implicit size of the array runtime_expressions -}; - -// max length of an expanded expression -const int jit_max_expr_size = 512; - -// Retrieve the string to JIT for the given expression -#define JIT_TEMPLATE_CONTEXT "void* ctxt = (void*)rsDebugGetContextWrapper(0x%" PRIx64 "); " -const char *JITTemplate(ExpressionStrings e) { - // Format strings containing the expressions we may need to evaluate. - static std::array runtime_expressions = { - {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) - "(int*)_" - "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation" - "CubemapFace" - "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", // eExprGetOffsetPtr - - // Type* rsaAllocationGetType(Context*, Allocation*) - JIT_TEMPLATE_CONTEXT "(void*)rsaAllocationGetType(ctxt, 0x%" PRIx64 ")", // eExprAllocGetType - - // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) Pack the - // data in the following way mHal.state.dimX; mHal.state.dimY; - // mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement; - // into typeData Need to specify 32 or 64 bit for uint_t since this - // differs between devices - JIT_TEMPLATE_CONTEXT - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 6); data[0]", // eExprTypeDimX - JIT_TEMPLATE_CONTEXT - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 6); data[1]", // eExprTypeDimY - JIT_TEMPLATE_CONTEXT - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 6); data[2]", // eExprTypeDimZ - JIT_TEMPLATE_CONTEXT - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 6); data[5]", // eExprTypeElemPtr - - // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) - // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into - // elemData - JIT_TEMPLATE_CONTEXT - "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 5); data[0]", // eExprElementType - JIT_TEMPLATE_CONTEXT - "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 5); data[1]", // eExprElementKind - JIT_TEMPLATE_CONTEXT - "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 5); data[3]", // eExprElementVec - JIT_TEMPLATE_CONTEXT - "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" - ", 0x%" PRIx64 ", data, 5); data[4]", // eExprElementFieldCount - - // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t - // *ids, const char **names, size_t *arraySizes, uint32_t dataSize) - // Needed for Allocations of structs to gather details about - // fields/Subelements Element* of field - JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 - "]; size_t arr_size[%" PRIu32 "];" - "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64 - ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", // eExprSubelementsId - - // Name of field - JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 - "]; size_t arr_size[%" PRIu32 "];" - "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64 - ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", // eExprSubelementsName - - // Array size of field - JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 - "]; size_t arr_size[%" PRIu32 "];" - "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64 - ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; // eExprSubelementsArrSize - - return runtime_expressions[e]; -} -} // end of the anonymous namespace - -// JITs the RS runtime for the internal data pointer of an allocation. Is -// passed x,y,z coordinates for the pointer to a specific element. Then sets -// the data_ptr member in Allocation with the result. Returns true on success, -// false otherwise -bool RenderScriptRuntime::JITDataPointer(AllocationDetails *alloc, - StackFrame *frame_ptr, uint32_t x, - uint32_t y, uint32_t z) { - Log *log = GetLog(LLDBLog::Language); - - if (!alloc->address.isValid()) { - LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - const char *fmt_str = JITTemplate(eExprGetOffsetPtr); - char expr_buf[jit_max_expr_size]; - - int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, - *alloc->address.get(), x, y, z); - if (written < 0) { - LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); - return false; - } else if (written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); - return false; - } - - uint64_t result = 0; - if (!EvalRSExpression(expr_buf, frame_ptr, &result)) - return false; - - addr_t data_ptr = static_cast(result); - alloc->data_ptr = data_ptr; - - return true; -} - -// JITs the RS runtime for the internal pointer to the RS Type of an allocation -// Then sets the type_ptr member in Allocation with the result. Returns true on -// success, false otherwise -bool RenderScriptRuntime::JITTypePointer(AllocationDetails *alloc, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - if (!alloc->address.isValid() || !alloc->context.isValid()) { - LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - const char *fmt_str = JITTemplate(eExprAllocGetType); - char expr_buf[jit_max_expr_size]; - - int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, - *alloc->context.get(), *alloc->address.get()); - if (written < 0) { - LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); - return false; - } else if (written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); - return false; - } - - uint64_t result = 0; - if (!EvalRSExpression(expr_buf, frame_ptr, &result)) - return false; - - addr_t type_ptr = static_cast(result); - alloc->type_ptr = type_ptr; - - return true; -} - -// JITs the RS runtime for information about the dimensions and type of an -// allocation Then sets dimension and element_ptr members in Allocation with -// the result. Returns true on success, false otherwise -bool RenderScriptRuntime::JITTypePacked(AllocationDetails *alloc, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - if (!alloc->type_ptr.isValid() || !alloc->context.isValid()) { - LLDB_LOGF(log, "%s - Failed to find allocation details.", __FUNCTION__); - return false; - } - - // Expression is different depending on if device is 32 or 64 bit - uint32_t target_ptr_size = - GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); - const uint32_t bits = target_ptr_size == 4 ? 32 : 64; - - // We want 4 elements from packed data - const uint32_t num_exprs = 4; - static_assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1), - "Invalid number of expressions"); - - char expr_bufs[num_exprs][jit_max_expr_size]; - uint64_t results[num_exprs]; - - for (uint32_t i = 0; i < num_exprs; ++i) { - const char *fmt_str = JITTemplate(ExpressionStrings(eExprTypeDimX + i)); - int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, - *alloc->context.get(), bits, *alloc->type_ptr.get()); - if (written < 0) { - LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); - return false; - } else if (written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); - return false; - } - - // Perform expression evaluation - if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i])) - return false; - } - - // Assign results to allocation members - AllocationDetails::Dimension dims; - dims.dim_1 = static_cast(results[0]); - dims.dim_2 = static_cast(results[1]); - dims.dim_3 = static_cast(results[2]); - alloc->dimension = dims; - - addr_t element_ptr = static_cast(results[3]); - alloc->element.element_ptr = element_ptr; - - LLDB_LOGF(log, - "%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32 - ") Element*: 0x%" PRIx64 ".", - __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, element_ptr); - - return true; -} - -// JITs the RS runtime for information about the Element of an allocation Then -// sets type, type_vec_size, field_count and type_kind members in Element with -// the result. Returns true on success, false otherwise -bool RenderScriptRuntime::JITElementPacked(Element &elem, - const lldb::addr_t context, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - if (!elem.element_ptr.isValid()) { - LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - // We want 4 elements from packed data - const uint32_t num_exprs = 4; - static_assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1), - "Invalid number of expressions"); - - char expr_bufs[num_exprs][jit_max_expr_size]; - uint64_t results[num_exprs]; - - for (uint32_t i = 0; i < num_exprs; i++) { - const char *fmt_str = JITTemplate(ExpressionStrings(eExprElementType + i)); - int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, context, - *elem.element_ptr.get()); - if (written < 0) { - LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); - return false; - } else if (written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); - return false; - } - - // Perform expression evaluation - if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i])) - return false; - } - - // Assign results to allocation members - elem.type = static_cast(results[0]); - elem.type_kind = - static_cast(results[1]); - elem.type_vec_size = static_cast(results[2]); - elem.field_count = static_cast(results[3]); - - LLDB_LOGF(log, - "%s - data type %" PRIu32 ", pixel type %" PRIu32 - ", vector size %" PRIu32 ", field count %" PRIu32, - __FUNCTION__, *elem.type.get(), *elem.type_kind.get(), - *elem.type_vec_size.get(), *elem.field_count.get()); - - // If this Element has subelements then JIT rsaElementGetSubElements() for - // details about its fields - return !(*elem.field_count.get() > 0 && - !JITSubelements(elem, context, frame_ptr)); -} - -// JITs the RS runtime for information about the subelements/fields of a struct -// allocation This is necessary for infering the struct type so we can pretty -// print the allocation's contents. Returns true on success, false otherwise -bool RenderScriptRuntime::JITSubelements(Element &elem, - const lldb::addr_t context, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) { - LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - const short num_exprs = 3; - static_assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1), - "Invalid number of expressions"); - - char expr_buffer[jit_max_expr_size]; - uint64_t results; - - // Iterate over struct fields. - const uint32_t field_count = *elem.field_count.get(); - for (uint32_t field_index = 0; field_index < field_count; ++field_index) { - Element child; - for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) { - const char *fmt_str = - JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index)); - int written = snprintf(expr_buffer, jit_max_expr_size, fmt_str, - context, field_count, field_count, field_count, - *elem.element_ptr.get(), field_count, field_index); - if (written < 0) { - LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); - return false; - } else if (written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); - return false; - } - - // Perform expression evaluation - if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) - return false; - - LLDB_LOGF(log, "%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results); - - switch (expr_index) { - case 0: // Element* of child - child.element_ptr = static_cast(results); - break; - case 1: // Name of child - { - lldb::addr_t address = static_cast(results); - Status err; - std::string name; - GetProcess()->ReadCStringFromMemory(address, name, err); - if (!err.Fail()) - child.type_name = ConstString(name); - else { - LLDB_LOGF(log, "%s - warning: Couldn't read field name.", - __FUNCTION__); - } - break; - } - case 2: // Array size of child - child.array_size = static_cast(results); - break; - } - } - - // We need to recursively JIT each Element field of the struct since - // structs can be nested inside structs. - if (!JITElementPacked(child, context, frame_ptr)) - return false; - elem.children.push_back(child); - } - - // Try to infer the name of the struct type so we can pretty print the - // allocation contents. - FindStructTypeName(elem, frame_ptr); - - return true; -} - -// JITs the RS runtime for the address of the last element in the allocation. -// The `elem_size` parameter represents the size of a single element, including -// padding. Which is needed as an offset from the last element pointer. Using -// this offset minus the starting address we can calculate the size of the -// allocation. Returns true on success, false otherwise -bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *alloc, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - if (!alloc->address.isValid() || !alloc->dimension.isValid() || - !alloc->data_ptr.isValid() || !alloc->element.datum_size.isValid()) { - LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - // Find dimensions - uint32_t dim_x = alloc->dimension.get()->dim_1; - uint32_t dim_y = alloc->dimension.get()->dim_2; - uint32_t dim_z = alloc->dimension.get()->dim_3; - - // Our plan of jitting the last element address doesn't seem to work for - // struct Allocations` Instead try to infer the size ourselves without any - // inter element padding. - if (alloc->element.children.size() > 0) { - if (dim_x == 0) - dim_x = 1; - if (dim_y == 0) - dim_y = 1; - if (dim_z == 0) - dim_z = 1; - - alloc->size = dim_x * dim_y * dim_z * *alloc->element.datum_size.get(); - - LLDB_LOGF(log, "%s - inferred size of struct allocation %" PRIu32 ".", - __FUNCTION__, *alloc->size.get()); - return true; - } - - const char *fmt_str = JITTemplate(eExprGetOffsetPtr); - char expr_buf[jit_max_expr_size]; - - // Calculate last element - dim_x = dim_x == 0 ? 0 : dim_x - 1; - dim_y = dim_y == 0 ? 0 : dim_y - 1; - dim_z = dim_z == 0 ? 0 : dim_z - 1; - - int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, - *alloc->address.get(), dim_x, dim_y, dim_z); - if (written < 0) { - LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); - return false; - } else if (written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); - return false; - } - - uint64_t result = 0; - if (!EvalRSExpression(expr_buf, frame_ptr, &result)) - return false; - - addr_t mem_ptr = static_cast(result); - // Find pointer to last element and add on size of an element - alloc->size = static_cast(mem_ptr - *alloc->data_ptr.get()) + - *alloc->element.datum_size.get(); - - return true; -} - -// JITs the RS runtime for information about the stride between rows in the -// allocation. This is done to detect padding, since allocated memory is -// 16-byte aligned. Returns true on success, false otherwise -bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *alloc, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - if (!alloc->address.isValid() || !alloc->data_ptr.isValid()) { - LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - const char *fmt_str = JITTemplate(eExprGetOffsetPtr); - char expr_buf[jit_max_expr_size]; - - int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, - *alloc->address.get(), 0, 1, 0); - if (written < 0) { - LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); - return false; - } else if (written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); - return false; - } - - uint64_t result = 0; - if (!EvalRSExpression(expr_buf, frame_ptr, &result)) - return false; - - addr_t mem_ptr = static_cast(result); - alloc->stride = static_cast(mem_ptr - *alloc->data_ptr.get()); - - return true; -} - -// JIT all the current runtime info regarding an allocation -bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc, - StackFrame *frame_ptr) { - // GetOffsetPointer() - if (!JITDataPointer(alloc, frame_ptr)) - return false; - - // rsaAllocationGetType() - if (!JITTypePointer(alloc, frame_ptr)) - return false; - - // rsaTypeGetNativeData() - if (!JITTypePacked(alloc, frame_ptr)) - return false; - - // rsaElementGetNativeData() - if (!JITElementPacked(alloc->element, *alloc->context.get(), frame_ptr)) - return false; - - // Sets the datum_size member in Element - SetElementSize(alloc->element); - - // Use GetOffsetPointer() to infer size of the allocation - return JITAllocationSize(alloc, frame_ptr); -} - -// Function attempts to set the type_name member of the parameterised Element -// object. This string should be the name of the struct type the Element -// represents. We need this string for pretty printing the Element to users. -void RenderScriptRuntime::FindStructTypeName(Element &elem, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - if (!elem.type_name.IsEmpty()) // Name already set - return; - else - elem.type_name = Element::GetFallbackStructName(); // Default type name if - // we don't succeed - - // Find all the global variables from the script rs modules - VariableList var_list; - for (auto module_sp : m_rsmodules) - module_sp->m_module->FindGlobalVariables( - RegularExpression(llvm::StringRef(".")), UINT32_MAX, var_list); - - // Iterate over all the global variables looking for one with a matching type - // to the Element. We make the assumption a match exists since there needs to - // be a global variable to reflect the struct type back into java host code. - for (const VariableSP &var_sp : var_list) { - if (!var_sp) - continue; - - ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); - if (!valobj_sp) - continue; - - // Find the number of variable fields. - // If it has no fields, or more fields than our Element, then it can't be - // the struct we're looking for. Don't check for equality since RS can add - // extra struct members for padding. - size_t num_children = valobj_sp->GetNumChildren(); - if (num_children > elem.children.size() || num_children == 0) - continue; - - // Iterate over children looking for members with matching field names. If - // all the field names match, this is likely the struct we want. - // TODO: This could be made more robust by also checking children data - // sizes, or array size - bool found = true; - for (size_t i = 0; i < num_children; ++i) { - ValueObjectSP child = valobj_sp->GetChildAtIndex(i, true); - if (!child || (child->GetName() != elem.children[i].type_name)) { - found = false; - break; - } - } - - // RS can add extra struct members for padding in the format - // '#rs_padding_[0-9]+' - if (found && num_children < elem.children.size()) { - const uint32_t size_diff = elem.children.size() - num_children; - LLDB_LOGF(log, "%s - %" PRIu32 " padding struct entries", __FUNCTION__, - size_diff); - - for (uint32_t i = 0; i < size_diff; ++i) { - ConstString name = elem.children[num_children + i].type_name; - if (strcmp(name.AsCString(), "#rs_padding") < 0) - found = false; - } - } - - // We've found a global variable with matching type - if (found) { - // Dereference since our Element type isn't a pointer. - if (valobj_sp->IsPointerType()) { - Status err; - ValueObjectSP deref_valobj = valobj_sp->Dereference(err); - if (!err.Fail()) - valobj_sp = deref_valobj; - } - - // Save name of variable in Element. - elem.type_name = valobj_sp->GetTypeName(); - LLDB_LOGF(log, "%s - element name set to %s", __FUNCTION__, - elem.type_name.AsCString()); - - return; - } - } -} - -// Function sets the datum_size member of Element. Representing the size of a -// single instance including padding. Assumes the relevant allocation -// information has already been jitted. -void RenderScriptRuntime::SetElementSize(Element &elem) { - Log *log = GetLog(LLDBLog::Language); - const Element::DataType type = *elem.type.get(); - assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && - "Invalid allocation type"); - - const uint32_t vec_size = *elem.type_vec_size.get(); - uint32_t data_size = 0; - uint32_t padding = 0; - - // Element is of a struct type, calculate size recursively. - if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) { - for (Element &child : elem.children) { - SetElementSize(child); - const uint32_t array_size = - child.array_size.isValid() ? *child.array_size.get() : 1; - data_size += *child.datum_size.get() * array_size; - } - } - // These have been packed already - else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || - type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || - type == Element::RS_TYPE_UNSIGNED_4_4_4_4) { - data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; - } else if (type < Element::RS_TYPE_ELEMENT) { - data_size = - vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; - if (vec_size == 3) - padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; - } else - data_size = - GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); - - elem.padding = padding; - elem.datum_size = data_size + padding; - LLDB_LOGF(log, "%s - element size set to %" PRIu32, __FUNCTION__, - data_size + padding); -} - -// Given an allocation, this function copies the allocation contents from -// device into a buffer on the heap. Returning a shared pointer to the buffer -// containing the data. -std::shared_ptr -RenderScriptRuntime::GetAllocationData(AllocationDetails *alloc, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - // JIT all the allocation details - if (alloc->ShouldRefresh()) { - LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info", - __FUNCTION__); - - if (!RefreshAllocation(alloc, frame_ptr)) { - LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__); - return nullptr; - } - } - - assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && - alloc->element.type_vec_size.isValid() && alloc->size.isValid() && - "Allocation information not available"); - - // Allocate a buffer to copy data into - const uint32_t size = *alloc->size.get(); - std::shared_ptr buffer(new uint8_t[size]); - if (!buffer) { - LLDB_LOGF(log, "%s - couldn't allocate a %" PRIu32 " byte buffer", - __FUNCTION__, size); - return nullptr; - } - - // Read the inferior memory - Status err; - lldb::addr_t data_ptr = *alloc->data_ptr.get(); - GetProcess()->ReadMemory(data_ptr, buffer.get(), size, err); - if (err.Fail()) { - LLDB_LOGF(log, - "%s - '%s' Couldn't read %" PRIu32 - " bytes of allocation data from 0x%" PRIx64, - __FUNCTION__, err.AsCString(), size, data_ptr); - return nullptr; - } - - return buffer; -} - -// Function copies data from a binary file into an allocation. There is a -// header at the start of the file, FileHeader, before the data content itself. -// Information from this header is used to display warnings to the user about -// incompatibilities -bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, - const char *path, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - // Find allocation with the given id - AllocationDetails *alloc = FindAllocByID(strm, alloc_id); - if (!alloc) - return false; - - LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__, - *alloc->address.get()); - - // JIT all the allocation details - if (alloc->ShouldRefresh()) { - LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.", - __FUNCTION__); - - if (!RefreshAllocation(alloc, frame_ptr)) { - LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__); - return false; - } - } - - assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && - alloc->element.type_vec_size.isValid() && alloc->size.isValid() && - alloc->element.datum_size.isValid() && - "Allocation information not available"); - - // Check we can read from file - FileSpec file(path); - FileSystem::Instance().Resolve(file); - if (!FileSystem::Instance().Exists(file)) { - strm.Printf("Error: File %s does not exist", path); - strm.EOL(); - return false; - } - - if (!FileSystem::Instance().Readable(file)) { - strm.Printf("Error: File %s does not have readable permissions", path); - strm.EOL(); - return false; - } - - // Read file into data buffer - auto data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath()); - - // Cast start of buffer to FileHeader and use pointer to read metadata - const void *file_buf = data_sp->GetBytes(); - if (file_buf == nullptr || - data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) + - sizeof(AllocationDetails::ElementHeader))) { - strm.Printf("Error: File %s does not contain enough data for header", path); - strm.EOL(); - return false; - } - const AllocationDetails::FileHeader *file_header = - static_cast(file_buf); - - // Check file starts with ascii characters "RSAD" - if (memcmp(file_header->ident, "RSAD", 4)) { - strm.Printf("Error: File doesn't contain identifier for an RS allocation " - "dump. Are you sure this is the correct file?"); - strm.EOL(); - return false; - } - - // Look at the type of the root element in the header - AllocationDetails::ElementHeader root_el_hdr; - memcpy(&root_el_hdr, - static_cast(file_buf) + - sizeof(AllocationDetails::FileHeader), - sizeof(AllocationDetails::ElementHeader)); - - LLDB_LOGF(log, "%s - header type %" PRIu32 ", element size %" PRIu32, - __FUNCTION__, root_el_hdr.type, root_el_hdr.element_size); - - // Check if the target allocation and file both have the same number of bytes - // for an Element - if (*alloc->element.datum_size.get() != root_el_hdr.element_size) { - strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32 - " bytes, allocation %" PRIu32 " bytes", - root_el_hdr.element_size, *alloc->element.datum_size.get()); - strm.EOL(); - } - - // Check if the target allocation and file both have the same type - const uint32_t alloc_type = static_cast(*alloc->element.type.get()); - const uint32_t file_type = root_el_hdr.type; - - if (file_type > Element::RS_TYPE_FONT) { - strm.Printf("Warning: File has unknown allocation type"); - strm.EOL(); - } else if (alloc_type != file_type) { - // Enum value isn't monotonous, so doesn't always index RsDataTypeToString - // array - uint32_t target_type_name_idx = alloc_type; - uint32_t head_type_name_idx = file_type; - if (alloc_type >= Element::RS_TYPE_ELEMENT && - alloc_type <= Element::RS_TYPE_FONT) - target_type_name_idx = static_cast( - (alloc_type - Element::RS_TYPE_ELEMENT) + - Element::RS_TYPE_MATRIX_2X2 + 1); - - if (file_type >= Element::RS_TYPE_ELEMENT && - file_type <= Element::RS_TYPE_FONT) - head_type_name_idx = static_cast( - (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + - 1); - - const char *head_type_name = - AllocationDetails::RsDataTypeToString[head_type_name_idx][0]; - const char *target_type_name = - AllocationDetails::RsDataTypeToString[target_type_name_idx][0]; - - strm.Printf( - "Warning: Mismatched Types - file '%s' type, allocation '%s' type", - head_type_name, target_type_name); - strm.EOL(); - } - - // Advance buffer past header - file_buf = static_cast(file_buf) + file_header->hdr_size; - - // Calculate size of allocation data in file - size_t size = data_sp->GetByteSize() - file_header->hdr_size; - - // Check if the target allocation and file both have the same total data - // size. - const uint32_t alloc_size = *alloc->size.get(); - if (alloc_size != size) { - strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 - " bytes, allocation 0x%" PRIx32 " bytes", - (uint64_t)size, alloc_size); - strm.EOL(); - // Set length to copy to minimum - size = alloc_size < size ? alloc_size : size; - } - - // Copy file data from our buffer into the target allocation. - lldb::addr_t alloc_data = *alloc->data_ptr.get(); - Status err; - size_t written = GetProcess()->WriteMemory(alloc_data, file_buf, size, err); - if (!err.Success() || written != size) { - strm.Printf("Error: Couldn't write data to allocation %s", err.AsCString()); - strm.EOL(); - return false; - } - - strm.Printf("Contents of file '%s' read into allocation %" PRIu32, path, - alloc->id); - strm.EOL(); - - return true; -} - -// Function takes as parameters a byte buffer, which will eventually be written -// to file as the element header, an offset into that buffer, and an Element -// that will be saved into the buffer at the parametrised offset. Return value -// is the new offset after writing the element into the buffer. Elements are -// saved to the file as the ElementHeader struct followed by offsets to the -// structs of all the element's children. -size_t RenderScriptRuntime::PopulateElementHeaders( - const std::shared_ptr header_buffer, size_t offset, - const Element &elem) { - // File struct for an element header with all the relevant details copied - // from elem. We assume members are valid already. - AllocationDetails::ElementHeader elem_header; - elem_header.type = *elem.type.get(); - elem_header.kind = *elem.type_kind.get(); - elem_header.element_size = *elem.datum_size.get(); - elem_header.vector_size = *elem.type_vec_size.get(); - elem_header.array_size = - elem.array_size.isValid() ? *elem.array_size.get() : 0; - const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); - - // Copy struct into buffer and advance offset We assume that header_buffer - // has been checked for nullptr before this method is called - memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); - offset += elem_header_size; - - // Starting offset of child ElementHeader struct - size_t child_offset = - offset + ((elem.children.size() + 1) * sizeof(uint32_t)); - for (const RenderScriptRuntime::Element &child : elem.children) { - // Recursively populate the buffer with the element header structs of - // children. Then save the offsets where they were set after the parent - // element header. - memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); - offset += sizeof(uint32_t); - - child_offset = PopulateElementHeaders(header_buffer, child_offset, child); - } - - // Zero indicates no more children - memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); - - return child_offset; -} - -// Given an Element object this function returns the total size needed in the -// file header to store the element's details. Taking into account the size of -// the element header struct, plus the offsets to all the element's children. -// Function is recursive so that the size of all ancestors is taken into -// account. -size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) { - // Offsets to children plus zero terminator - size_t size = (elem.children.size() + 1) * sizeof(uint32_t); - // Size of header struct with type details - size += sizeof(AllocationDetails::ElementHeader); - - // Calculate recursively for all descendants - for (const Element &child : elem.children) - size += CalculateElementHeaderSize(child); - - return size; -} - -// Function copies allocation contents into a binary file. This file can then -// be loaded later into a different allocation. There is a header, FileHeader, -// before the allocation data containing meta-data. -bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, - const char *path, - StackFrame *frame_ptr) { - Log *log = GetLog(LLDBLog::Language); - - // Find allocation with the given id - AllocationDetails *alloc = FindAllocByID(strm, alloc_id); - if (!alloc) - return false; - - LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64 ".", __FUNCTION__, - *alloc->address.get()); - - // JIT all the allocation details - if (alloc->ShouldRefresh()) { - LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.", - __FUNCTION__); - - if (!RefreshAllocation(alloc, frame_ptr)) { - LLDB_LOGF(log, "%s - couldn't JIT allocation details.", __FUNCTION__); - return false; - } - } - - assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && - alloc->element.type_vec_size.isValid() && - alloc->element.datum_size.get() && - alloc->element.type_kind.isValid() && alloc->dimension.isValid() && - "Allocation information not available"); - - // Check we can create writable file - FileSpec file_spec(path); - FileSystem::Instance().Resolve(file_spec); - auto file = FileSystem::Instance().Open( - file_spec, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate | - File::eOpenOptionTruncate); - - if (!file) { - std::string error = llvm::toString(file.takeError()); - strm.Printf("Error: Failed to open '%s' for writing: %s", path, - error.c_str()); - strm.EOL(); - return false; - } - - // Read allocation into buffer of heap memory - const std::shared_ptr buffer = GetAllocationData(alloc, frame_ptr); - if (!buffer) { - strm.Printf("Error: Couldn't read allocation data into buffer"); - strm.EOL(); - return false; - } - - // Create the file header - AllocationDetails::FileHeader head; - memcpy(head.ident, "RSAD", 4); - head.dims[0] = static_cast(alloc->dimension.get()->dim_1); - head.dims[1] = static_cast(alloc->dimension.get()->dim_2); - head.dims[2] = static_cast(alloc->dimension.get()->dim_3); - - const size_t element_header_size = CalculateElementHeaderSize(alloc->element); - assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < - UINT16_MAX && - "Element header too large"); - head.hdr_size = static_cast(sizeof(AllocationDetails::FileHeader) + - element_header_size); - - // Write the file header - size_t num_bytes = sizeof(AllocationDetails::FileHeader); - LLDB_LOGF(log, "%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__, - (uint64_t)num_bytes); - - Status err = file.get()->Write(&head, num_bytes); - if (!err.Success()) { - strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path); - strm.EOL(); - return false; - } - - // Create the headers describing the element type of the allocation. - std::shared_ptr element_header_buffer( - new uint8_t[element_header_size]); - if (element_header_buffer == nullptr) { - strm.Printf("Internal Error: Couldn't allocate %" PRIu64 - " bytes on the heap", - (uint64_t)element_header_size); - strm.EOL(); - return false; - } - - PopulateElementHeaders(element_header_buffer, 0, alloc->element); - - // Write headers for allocation element type to file - num_bytes = element_header_size; - LLDB_LOGF(log, "%s - writing element headers, 0x%" PRIx64 " bytes.", - __FUNCTION__, (uint64_t)num_bytes); - - err = file.get()->Write(element_header_buffer.get(), num_bytes); - if (!err.Success()) { - strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path); - strm.EOL(); - return false; - } - - // Write allocation data to file - num_bytes = static_cast(*alloc->size.get()); - LLDB_LOGF(log, "%s - writing 0x%" PRIx64 " bytes", __FUNCTION__, - (uint64_t)num_bytes); - - err = file.get()->Write(buffer.get(), num_bytes); - if (!err.Success()) { - strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path); - strm.EOL(); - return false; - } - - strm.Printf("Allocation written to file '%s'", path); - strm.EOL(); - return true; -} - -bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { - Log *log = GetLog(LLDBLog::Language); - - if (module_sp) { - for (const auto &rs_module : m_rsmodules) { - if (rs_module->m_module == module_sp) { - // Check if the user has enabled automatically breaking on all RS - // kernels. - if (m_breakAllKernels) - BreakOnModuleKernels(rs_module); - - return false; - } - } - bool module_loaded = false; - switch (GetModuleKind(module_sp)) { - case eModuleKindKernelObj: { - RSModuleDescriptorSP module_desc; - module_desc = std::make_shared(module_sp); - if (module_desc->ParseRSInfo()) { - m_rsmodules.push_back(module_desc); - module_desc->WarnIfVersionMismatch(GetProcess() - ->GetTarget() - .GetDebugger() - .GetAsyncOutputStream() - .get()); - module_loaded = true; - } - if (module_loaded) { - FixupScriptDetails(module_desc); - } - break; - } - case eModuleKindDriver: { - if (!m_libRSDriver) { - m_libRSDriver = module_sp; - LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); - } - break; - } - case eModuleKindImpl: { - if (!m_libRSCpuRef) { - m_libRSCpuRef = module_sp; - LoadRuntimeHooks(m_libRSCpuRef, RenderScriptRuntime::eModuleKindImpl); - } - break; - } - case eModuleKindLibRS: { - if (!m_libRS) { - m_libRS = module_sp; - static ConstString gDbgPresentStr("gDebuggerPresent"); - const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType( - gDbgPresentStr, eSymbolTypeData); - if (debug_present) { - Status err; - uint32_t flag = 0x00000001U; - Target &target = GetProcess()->GetTarget(); - addr_t addr = debug_present->GetLoadAddress(&target); - GetProcess()->WriteMemory(addr, &flag, sizeof(flag), err); - if (err.Success()) { - LLDB_LOGF(log, "%s - debugger present flag set on debugee.", - __FUNCTION__); - - m_debuggerPresentFlagged = true; - } else if (log) { - LLDB_LOGF(log, "%s - error writing debugger present flags '%s' ", - __FUNCTION__, err.AsCString()); - } - } else if (log) { - LLDB_LOGF( - log, - "%s - error writing debugger present flags - symbol not found", - __FUNCTION__); - } - } - break; - } - default: - break; - } - if (module_loaded) - Update(); - return module_loaded; - } - return false; -} - -void RenderScriptRuntime::Update() { - if (m_rsmodules.size() > 0) { - if (!m_initiated) { - Initiate(); - } - } -} - -void RSModuleDescriptor::WarnIfVersionMismatch(lldb_private::Stream *s) const { - if (!s) - return; - - if (m_slang_version.empty() || m_bcc_version.empty()) { - s->PutCString("WARNING: Unknown bcc or slang (llvm-rs-cc) version; debug " - "experience may be unreliable"); - s->EOL(); - } else if (m_slang_version != m_bcc_version) { - s->Printf("WARNING: The debug info emitted by the slang frontend " - "(llvm-rs-cc) used to build this module (%s) does not match the " - "version of bcc used to generate the debug information (%s). " - "This is an unsupported configuration and may result in a poor " - "debugging experience; proceed with caution", - m_slang_version.c_str(), m_bcc_version.c_str()); - s->EOL(); - } -} - -bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines, - size_t n_lines) { - // Skip the pragma prototype line - ++lines; - for (; n_lines--; ++lines) { - const auto kv_pair = lines->split(" - "); - m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str(); - } - return true; -} - -bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines, - size_t n_lines) { - // The list of reduction kernels in the `.rs.info` symbol is of the form - // "signature - accumulatordatasize - reduction_name - initializer_name - - // accumulator_name - combiner_name - outconverter_name - halter_name" Where - // a function is not explicitly named by the user, or is not generated by the - // compiler, it is named "." so the dash separated list should always be 8 - // items long - Log *log = GetLog(LLDBLog::Language); - // Skip the exportReduceCount line - ++lines; - for (; n_lines--; ++lines) { - llvm::SmallVector spec; - lines->split(spec, " - "); - if (spec.size() != 8) { - if (spec.size() < 8) { - if (log) - log->Error("Error parsing RenderScript reduction spec. wrong number " - "of fields"); - return false; - } else if (log) - log->Warning("Extraneous members in reduction spec: '%s'", - lines->str().c_str()); - } - - const auto sig_s = spec[0]; - uint32_t sig; - if (sig_s.getAsInteger(10, sig)) { - if (log) - log->Error("Error parsing Renderscript reduction spec: invalid kernel " - "signature: '%s'", - sig_s.str().c_str()); - return false; - } - - const auto accum_data_size_s = spec[1]; - uint32_t accum_data_size; - if (accum_data_size_s.getAsInteger(10, accum_data_size)) { - if (log) - log->Error("Error parsing Renderscript reduction spec: invalid " - "accumulator data size %s", - accum_data_size_s.str().c_str()); - return false; - } - - LLDB_LOGF(log, "Found RenderScript reduction '%s'", spec[2].str().c_str()); - - m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size, - spec[2], spec[3], spec[4], - spec[5], spec[6], spec[7])); - } - return true; -} - -bool RSModuleDescriptor::ParseVersionInfo(llvm::StringRef *lines, - size_t n_lines) { - // Skip the versionInfo line - ++lines; - for (; n_lines--; ++lines) { - // We're only interested in bcc and slang versions, and ignore all other - // versionInfo lines - const auto kv_pair = lines->split(" - "); - if (kv_pair.first == "slang") - m_slang_version = kv_pair.second.str(); - else if (kv_pair.first == "bcc") - m_bcc_version = kv_pair.second.str(); - } - return true; -} - -bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines, - size_t n_lines) { - // Skip the exportForeachCount line - ++lines; - for (; n_lines--; ++lines) { - uint32_t slot; - // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name" - // pair per line - const auto kv_pair = lines->split(" - "); - if (kv_pair.first.getAsInteger(10, slot)) - return false; - m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot)); - } - return true; -} - -bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines, - size_t n_lines) { - // Skip the ExportVarCount line - ++lines; - for (; n_lines--; ++lines) - m_globals.push_back(RSGlobalDescriptor(this, *lines)); - return true; -} - -// The .rs.info symbol in renderscript modules contains a string which needs to -// be parsed. The string is basic and is parsed on a line by line basis. -bool RSModuleDescriptor::ParseRSInfo() { - assert(m_module); - Log *log = GetLog(LLDBLog::Language); - const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType( - ConstString(".rs.info"), eSymbolTypeData); - if (!info_sym) - return false; - - const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); - if (addr == LLDB_INVALID_ADDRESS) - return false; - - const addr_t size = info_sym->GetByteSize(); - const FileSpec fs = m_module->GetFileSpec(); - - auto buffer = - FileSystem::Instance().CreateDataBuffer(fs.GetPath(), size, addr); - if (!buffer) - return false; - - // split rs.info. contents into lines - llvm::SmallVector info_lines; - { - const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes()); - raw_rs_info.split(info_lines, '\n'); - LLDB_LOGF(log, "'.rs.info symbol for '%s':\n%s", - m_module->GetFileSpec().GetPath().c_str(), - raw_rs_info.str().c_str()); - } - - enum { - eExportVar, - eExportForEach, - eExportReduce, - ePragma, - eBuildChecksum, - eObjectSlot, - eVersionInfo, - }; - - const auto rs_info_handler = [](llvm::StringRef name) -> int { - return llvm::StringSwitch(name) - // The number of visible global variables in the script - .Case("exportVarCount", eExportVar) - // The number of RenderScrip `forEach` kernels __attribute__((kernel)) - .Case("exportForEachCount", eExportForEach) - // The number of generalreductions: This marked in the script by - // `#pragma reduce()` - .Case("exportReduceCount", eExportReduce) - // Total count of all RenderScript specific `#pragmas` used in the - // script - .Case("pragmaCount", ePragma) - .Case("objectSlotCount", eObjectSlot) - .Case("versionInfo", eVersionInfo) - .Default(-1); - }; - - // parse all text lines of .rs.info - for (auto line = info_lines.begin(); line != info_lines.end(); ++line) { - const auto kv_pair = line->split(": "); - const auto key = kv_pair.first; - const auto val = kv_pair.second.trim(); - - const auto handler = rs_info_handler(key); - if (handler == -1) - continue; - // getAsInteger returns `true` on an error condition - we're only - // interested in numeric fields at the moment - uint64_t n_lines; - if (val.getAsInteger(10, n_lines)) { - LLDB_LOGV(log, "Failed to parse non-numeric '.rs.info' section {0}", - line->str()); - continue; - } - if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines) - return false; - - bool success = false; - switch (handler) { - case eExportVar: - success = ParseExportVarCount(line, n_lines); - break; - case eExportForEach: - success = ParseExportForeachCount(line, n_lines); - break; - case eExportReduce: - success = ParseExportReduceCount(line, n_lines); - break; - case ePragma: - success = ParsePragmaCount(line, n_lines); - break; - case eVersionInfo: - success = ParseVersionInfo(line, n_lines); - break; - default: { - LLDB_LOGF(log, "%s - skipping .rs.info field '%s'", __FUNCTION__, - line->str().c_str()); - continue; - } - } - if (!success) - return false; - line += n_lines; - } - return info_lines.size() > 0; -} - -void RenderScriptRuntime::DumpStatus(Stream &strm) const { - if (m_libRS) { - strm.Printf("Runtime Library discovered."); - strm.EOL(); - } - if (m_libRSDriver) { - strm.Printf("Runtime Driver discovered."); - strm.EOL(); - } - if (m_libRSCpuRef) { - strm.Printf("CPU Reference Implementation discovered."); - strm.EOL(); - } - - if (m_runtimeHooks.size()) { - strm.Printf("Runtime functions hooked:"); - strm.EOL(); - for (auto b : m_runtimeHooks) { - strm.Indent(b.second->defn->name); - strm.EOL(); - } - } else { - strm.Printf("Runtime is not hooked."); - strm.EOL(); - } -} - -void RenderScriptRuntime::DumpContexts(Stream &strm) const { - strm.Printf("Inferred RenderScript Contexts:"); - strm.EOL(); - strm.IndentMore(); - - std::map contextReferences; - - // Iterate over all of the currently discovered scripts. Note: We cant push - // or pop from m_scripts inside this loop or it may invalidate script. - for (const auto &script : m_scripts) { - if (!script->context.isValid()) - continue; - lldb::addr_t context = *script->context; - - if (contextReferences.find(context) != contextReferences.end()) { - contextReferences[context]++; - } else { - contextReferences[context] = 1; - } - } - - for (const auto &cRef : contextReferences) { - strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", - cRef.first, cRef.second); - strm.EOL(); - } - strm.IndentLess(); -} - -void RenderScriptRuntime::DumpKernels(Stream &strm) const { - strm.Printf("RenderScript Kernels:"); - strm.EOL(); - strm.IndentMore(); - for (const auto &module : m_rsmodules) { - strm.Printf("Resource '%s':", module->m_resname.c_str()); - strm.EOL(); - for (const auto &kernel : module->m_kernels) { - strm.Indent(kernel.m_name.GetStringRef()); - strm.EOL(); - } - } - strm.IndentLess(); -} - -RenderScriptRuntime::AllocationDetails * -RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) { - AllocationDetails *alloc = nullptr; - - // See if we can find allocation using id as an index; - if (alloc_id <= m_allocations.size() && alloc_id != 0 && - m_allocations[alloc_id - 1]->id == alloc_id) { - alloc = m_allocations[alloc_id - 1].get(); - return alloc; - } - - // Fallback to searching - for (const auto &a : m_allocations) { - if (a->id == alloc_id) { - alloc = a.get(); - break; - } - } - - if (alloc == nullptr) { - strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, - alloc_id); - strm.EOL(); - } - - return alloc; -} - -// Prints the contents of an allocation to the output stream, which may be a -// file -bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, - const uint32_t id) { - Log *log = GetLog(LLDBLog::Language); - - // Check we can find the desired allocation - AllocationDetails *alloc = FindAllocByID(strm, id); - if (!alloc) - return false; // FindAllocByID() will print error message for us here - - LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__, - *alloc->address.get()); - - // Check we have information about the allocation, if not calculate it - if (alloc->ShouldRefresh()) { - LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.", - __FUNCTION__); - - // JIT all the allocation information - if (!RefreshAllocation(alloc, frame_ptr)) { - strm.Printf("Error: Couldn't JIT allocation details"); - strm.EOL(); - return false; - } - } - - // Establish format and size of each data element - const uint32_t vec_size = *alloc->element.type_vec_size.get(); - const Element::DataType type = *alloc->element.type.get(); - - assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && - "Invalid allocation type"); - - lldb::Format format; - if (type >= Element::RS_TYPE_ELEMENT) - format = eFormatHex; - else - format = vec_size == 1 - ? static_cast( - AllocationDetails::RSTypeToFormat[type][eFormatSingle]) - : static_cast( - AllocationDetails::RSTypeToFormat[type][eFormatVector]); - - const uint32_t data_size = *alloc->element.datum_size.get(); - - LLDB_LOGF(log, "%s - element size %" PRIu32 " bytes, including padding", - __FUNCTION__, data_size); - - // Allocate a buffer to copy data into - std::shared_ptr buffer = GetAllocationData(alloc, frame_ptr); - if (!buffer) { - strm.Printf("Error: Couldn't read allocation data"); - strm.EOL(); - return false; - } - - // Calculate stride between rows as there may be padding at end of rows since - // allocated memory is 16-byte aligned - if (!alloc->stride.isValid()) { - if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension - alloc->stride = 0; - else if (!JITAllocationStride(alloc, frame_ptr)) { - strm.Printf("Error: Couldn't calculate allocation row stride"); - strm.EOL(); - return false; - } - } - const uint32_t stride = *alloc->stride.get(); - const uint32_t size = *alloc->size.get(); // Size of whole allocation - const uint32_t padding = - alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; - LLDB_LOGF(log, - "%s - stride %" PRIu32 " bytes, size %" PRIu32 - " bytes, padding %" PRIu32, - __FUNCTION__, stride, size, padding); - - // Find dimensions used to index loops, so need to be non-zero - uint32_t dim_x = alloc->dimension.get()->dim_1; - dim_x = dim_x == 0 ? 1 : dim_x; - - uint32_t dim_y = alloc->dimension.get()->dim_2; - dim_y = dim_y == 0 ? 1 : dim_y; - - uint32_t dim_z = alloc->dimension.get()->dim_3; - dim_z = dim_z == 0 ? 1 : dim_z; - - // Use data extractor to format output - const uint32_t target_ptr_size = - GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); - DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), - target_ptr_size); - - uint32_t offset = 0; // Offset in buffer to next element to be printed - uint32_t prev_row = 0; // Offset to the start of the previous row - - // Iterate over allocation dimensions, printing results to user - strm.Printf("Data (X, Y, Z):"); - for (uint32_t z = 0; z < dim_z; ++z) { - for (uint32_t y = 0; y < dim_y; ++y) { - // Use stride to index start of next row. - if (!(y == 0 && z == 0)) - offset = prev_row + stride; - prev_row = offset; - - // Print each element in the row individually - for (uint32_t x = 0; x < dim_x; ++x) { - strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); - if ((type == Element::RS_TYPE_NONE) && - (alloc->element.children.size() > 0) && - (alloc->element.type_name != Element::GetFallbackStructName())) { - // Here we are dumping an Element of struct type. This is done using - // expression evaluation with the name of the struct type and pointer - // to element. Don't print the name of the resulting expression, - // since this will be '$[0-9]+' - DumpValueObjectOptions expr_options; - expr_options.SetHideName(true); - - // Setup expression as dereferencing a pointer cast to element - // address. - char expr_char_buffer[jit_max_expr_size]; - int written = - snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, - alloc->element.type_name.AsCString(), - *alloc->data_ptr.get() + offset); - - if (written < 0 || written >= jit_max_expr_size) { - LLDB_LOGF(log, "%s - error in snprintf().", __FUNCTION__); - continue; - } - - // Evaluate expression - ValueObjectSP expr_result; - GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, - frame_ptr, expr_result); - - // Print the results to our stream. - expr_result->Dump(strm, expr_options); - } else { - DumpDataExtractor(alloc_data, &strm, offset, format, - data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, - 0); - } - offset += data_size; - } - } - } - strm.EOL(); - - return true; -} - -// Function recalculates all our cached information about allocations by -// jitting the RS runtime regarding each allocation we know about. Returns true -// if all allocations could be recomputed, false otherwise. -bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, - StackFrame *frame_ptr) { - bool success = true; - for (auto &alloc : m_allocations) { - // JIT current allocation information - if (!RefreshAllocation(alloc.get(), frame_ptr)) { - strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 - "\n", - alloc->id); - success = false; - } - } - - if (success) - strm.Printf("All allocations successfully recomputed"); - strm.EOL(); - - return success; -} - -// Prints information regarding currently loaded allocations. These details are -// gathered by jitting the runtime, which has as latency. Index parameter -// specifies a single allocation ID to print, or a zero value to print them all -void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, - const uint32_t index) { - strm.Printf("RenderScript Allocations:"); - strm.EOL(); - strm.IndentMore(); - - for (auto &alloc : m_allocations) { - // index will only be zero if we want to print all allocations - if (index != 0 && index != alloc->id) - continue; - - // JIT current allocation information - if (alloc->ShouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) { - strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, - alloc->id); - strm.EOL(); - continue; - } - - strm.Printf("%" PRIu32 ":", alloc->id); - strm.EOL(); - strm.IndentMore(); - - strm.Indent("Context: "); - if (!alloc->context.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); - - strm.Indent("Address: "); - if (!alloc->address.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); - - strm.Indent("Data pointer: "); - if (!alloc->data_ptr.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); - - strm.Indent("Dimensions: "); - if (!alloc->dimension.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", - alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, - alloc->dimension.get()->dim_3); - - strm.Indent("Data Type: "); - if (!alloc->element.type.isValid() || - !alloc->element.type_vec_size.isValid()) - strm.Printf("unknown\n"); - else { - const int vector_size = *alloc->element.type_vec_size.get(); - Element::DataType type = *alloc->element.type.get(); - - if (!alloc->element.type_name.IsEmpty()) - strm.Printf("%s\n", alloc->element.type_name.AsCString()); - else { - // Enum value isn't monotonous, so doesn't always index - // RsDataTypeToString array - if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) - type = - static_cast((type - Element::RS_TYPE_ELEMENT) + - Element::RS_TYPE_MATRIX_2X2 + 1); - - if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / - sizeof(AllocationDetails::RsDataTypeToString[0])) || - vector_size > 4 || vector_size < 1) - strm.Printf("invalid type\n"); - else - strm.Printf( - "%s\n", - AllocationDetails::RsDataTypeToString[static_cast(type)] - [vector_size - 1]); - } - } - - strm.Indent("Data Kind: "); - if (!alloc->element.type_kind.isValid()) - strm.Printf("unknown\n"); - else { - const Element::DataKind kind = *alloc->element.type_kind.get(); - if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) - strm.Printf("invalid kind\n"); - else - strm.Printf( - "%s\n", - AllocationDetails::RsDataKindToString[static_cast(kind)]); - } - - strm.EOL(); - strm.IndentLess(); - } - strm.IndentLess(); -} - -// Set breakpoints on every kernel found in RS module -void RenderScriptRuntime::BreakOnModuleKernels( - const RSModuleDescriptorSP rsmodule_sp) { - for (const auto &kernel : rsmodule_sp->m_kernels) { - // Don't set breakpoint on 'root' kernel - if (strcmp(kernel.m_name.AsCString(), "root") == 0) - continue; - - CreateKernelBreakpoint(kernel.m_name); - } -} - -// Method is internally called by the 'kernel breakpoint all' command to enable -// or disable breaking on all kernels. When do_break is true we want to enable -// this functionality. When do_break is false we want to disable it. -void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) { - Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints); - - InitSearchFilter(target); - - // Set breakpoints on all the kernels - if (do_break && !m_breakAllKernels) { - m_breakAllKernels = true; - - for (const auto &module : m_rsmodules) - BreakOnModuleKernels(module); - - LLDB_LOGF(log, - "%s(True) - breakpoints set on all currently loaded kernels.", - __FUNCTION__); - } else if (!do_break && - m_breakAllKernels) // Breakpoints won't be set on any new kernels. - { - m_breakAllKernels = false; - - LLDB_LOGF(log, "%s(False) - breakpoints no longer automatically set.", - __FUNCTION__); - } -} - -// Given the name of a kernel this function creates a breakpoint using our own -// breakpoint resolver, and returns the Breakpoint shared pointer. -BreakpointSP -RenderScriptRuntime::CreateKernelBreakpoint(ConstString name) { - Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints); - - if (!m_filtersp) { - LLDB_LOGF(log, "%s - error, no breakpoint search filter set.", - __FUNCTION__); - return nullptr; - } - - BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); - Target &target = GetProcess()->GetTarget(); - BreakpointSP bp = target.CreateBreakpoint( - m_filtersp, resolver_sp, false, false, false); - - // Give RS breakpoints a specific name, so the user can manipulate them as a - // group. - Status err; - target.AddNameToBreakpoint(bp, "RenderScriptKernel", err); - if (err.Fail() && log) - LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__, - err.AsCString()); - - return bp; -} - -BreakpointSP -RenderScriptRuntime::CreateReductionBreakpoint(ConstString name, - int kernel_types) { - Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints); - - if (!m_filtersp) { - LLDB_LOGF(log, "%s - error, no breakpoint search filter set.", - __FUNCTION__); - return nullptr; - } - - BreakpointResolverSP resolver_sp(new RSReduceBreakpointResolver( - nullptr, name, &m_rsmodules, kernel_types)); - Target &target = GetProcess()->GetTarget(); - BreakpointSP bp = target.CreateBreakpoint( - m_filtersp, resolver_sp, false, false, false); - - // Give RS breakpoints a specific name, so the user can manipulate them as a - // group. - Status err; - target.AddNameToBreakpoint(bp, "RenderScriptReduction", err); - if (err.Fail() && log) - LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__, - err.AsCString()); - - return bp; -} - -// Given an expression for a variable this function tries to calculate the -// variable's value. If this is possible it returns true and sets the uint64_t -// parameter to the variables unsigned value. Otherwise function returns false. -bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, - const char *var_name, - uint64_t &val) { - Log *log = GetLog(LLDBLog::Language); - Status err; - VariableSP var_sp; - - // Find variable in stack frame - ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( - var_name, eNoDynamicValues, - StackFrame::eExpressionPathOptionCheckPtrVsMember | - StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, - var_sp, err)); - if (!err.Success()) { - LLDB_LOGF(log, "%s - error, couldn't find '%s' in frame", __FUNCTION__, - var_name); - return false; - } - - // Find the uint32_t value for the variable - bool success = false; - val = value_sp->GetValueAsUnsigned(0, &success); - if (!success) { - LLDB_LOGF(log, "%s - error, couldn't parse '%s' as an uint32_t.", - __FUNCTION__, var_name); - return false; - } - - return true; -} - -// Function attempts to find the current coordinate of a kernel invocation by -// investigating the values of frame variables in the .expand function. These -// coordinates are returned via the coord array reference parameter. Returns -// true if the coordinates could be found, and false otherwise. -bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, - Thread *thread_ptr) { - static const char *const x_expr = "rsIndex"; - static const char *const y_expr = "p->current.y"; - static const char *const z_expr = "p->current.z"; - - Log *log = GetLog(LLDBLog::Language); - - if (!thread_ptr) { - LLDB_LOGF(log, "%s - Error, No thread pointer", __FUNCTION__); - - return false; - } - - // Walk the call stack looking for a function whose name has the suffix - // '.expand' and contains the variables we're looking for. - for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) { - if (!thread_ptr->SetSelectedFrameByIndex(i)) - continue; - - StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); - if (!frame_sp) - continue; - - // Find the function name - const SymbolContext sym_ctx = - frame_sp->GetSymbolContext(eSymbolContextFunction); - const ConstString func_name = sym_ctx.GetFunctionName(); - if (!func_name) - continue; - - LLDB_LOGF(log, "%s - Inspecting function '%s'", __FUNCTION__, - func_name.GetCString()); - - // Check if function name has .expand suffix - if (!func_name.GetStringRef().endswith(".expand")) - continue; - - LLDB_LOGF(log, "%s - Found .expand function '%s'", __FUNCTION__, - func_name.GetCString()); - - // Get values for variables in .expand frame that tell us the current - // kernel invocation - uint64_t x, y, z; - bool found = GetFrameVarAsUnsigned(frame_sp, x_expr, x) && - GetFrameVarAsUnsigned(frame_sp, y_expr, y) && - GetFrameVarAsUnsigned(frame_sp, z_expr, z); - - if (found) { - // The RenderScript runtime uses uint32_t for these vars. If they're not - // within bounds, our frame parsing is garbage - assert(x <= UINT32_MAX && y <= UINT32_MAX && z <= UINT32_MAX); - coord.x = (uint32_t)x; - coord.y = (uint32_t)y; - coord.z = (uint32_t)z; - return true; - } - } - return false; -} - -// Callback when a kernel breakpoint hits and we're looking for a specific -// coordinate. Baton parameter contains a pointer to the target coordinate we -// want to break on. Function then checks the .expand frame for the current -// coordinate and breaks to user if it matches. Parameter 'break_id' is the id -// of the Breakpoint which made the callback. Parameter 'break_loc_id' is the -// id for the BreakpointLocation which was hit, a single logical breakpoint can -// have multiple addresses. -bool RenderScriptRuntime::KernelBreakpointHit(void *baton, - StoppointCallbackContext *ctx, - user_id_t break_id, - user_id_t break_loc_id) { - Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints); - - assert(baton && - "Error: null baton in conditional kernel breakpoint callback"); - - // Coordinate we want to stop on - RSCoordinate target_coord = *static_cast(baton); - - LLDB_LOGF(log, "%s - Break ID %" PRIu64 ", " FMT_COORD, __FUNCTION__, - break_id, target_coord.x, target_coord.y, target_coord.z); - - // Select current thread - ExecutionContext context(ctx->exe_ctx_ref); - Thread *thread_ptr = context.GetThreadPtr(); - assert(thread_ptr && "Null thread pointer"); - - // Find current kernel invocation from .expand frame variables - RSCoordinate current_coord{}; - if (!GetKernelCoordinate(current_coord, thread_ptr)) { - LLDB_LOGF(log, "%s - Error, couldn't select .expand stack frame", - __FUNCTION__); - return false; - } - - LLDB_LOGF(log, "%s - " FMT_COORD, __FUNCTION__, current_coord.x, - current_coord.y, current_coord.z); - - // Check if the current kernel invocation coordinate matches our target - // coordinate - if (target_coord == current_coord) { - LLDB_LOGF(log, "%s, BREAKING " FMT_COORD, __FUNCTION__, current_coord.x, - current_coord.y, current_coord.z); - - BreakpointSP breakpoint_sp = - context.GetTargetPtr()->GetBreakpointByID(break_id); - assert(breakpoint_sp != nullptr && - "Error: Couldn't find breakpoint matching break id for callback"); - breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint - // should only be hit once. - return true; - } - - // No match on coordinate - return false; -} - -void RenderScriptRuntime::SetConditional(BreakpointSP bp, Stream &messages, - const RSCoordinate &coord) { - messages.Printf("Conditional kernel breakpoint on coordinate " FMT_COORD, - coord.x, coord.y, coord.z); - messages.EOL(); - - // Allocate memory for the baton, and copy over coordinate - RSCoordinate *baton = new RSCoordinate(coord); - - // Create a callback that will be invoked every time the breakpoint is hit. - // The baton object passed to the handler is the target coordinate we want to - // break on. - bp->SetCallback(KernelBreakpointHit, baton, true); - - // Store a shared pointer to the baton, so the memory will eventually be - // cleaned up after destruction - m_conditional_breaks[bp->GetID()] = std::unique_ptr(baton); -} - -// Tries to set a breakpoint on the start of a kernel, resolved using the -// kernel name. Argument 'coords', represents a three dimensional coordinate -// which can be used to specify a single kernel instance to break on. If this -// is set then we add a callback to the breakpoint. -bool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target, - Stream &messages, - const char *name, - const RSCoordinate *coord) { - if (!name) - return false; - - InitSearchFilter(target); - - ConstString kernel_name(name); - BreakpointSP bp = CreateKernelBreakpoint(kernel_name); - if (!bp) - return false; - - // We have a conditional breakpoint on a specific coordinate - if (coord) - SetConditional(bp, messages, *coord); - - bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false); - - return true; -} - -BreakpointSP -RenderScriptRuntime::CreateScriptGroupBreakpoint(ConstString name, - bool stop_on_all) { - Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints); - - if (!m_filtersp) { - LLDB_LOGF(log, "%s - error, no breakpoint search filter set.", - __FUNCTION__); - return nullptr; - } - - BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver( - nullptr, name, m_scriptGroups, stop_on_all)); - Target &target = GetProcess()->GetTarget(); - BreakpointSP bp = target.CreateBreakpoint( - m_filtersp, resolver_sp, false, false, false); - // Give RS breakpoints a specific name, so the user can manipulate them as a - // group. - Status err; - target.AddNameToBreakpoint(bp, name.GetCString(), err); - if (err.Fail() && log) - LLDB_LOGF(log, "%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, - 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, - const RSCoordinate *coord, - int kernel_types) { - if (!reduce_name) - return false; - - InitSearchFilter(target); - BreakpointSP bp = - CreateReductionBreakpoint(ConstString(reduce_name), kernel_types); - if (!bp) - return false; - - if (coord) - SetConditional(bp, messages, *coord); - - bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false); - - return true; -} - -void RenderScriptRuntime::DumpModules(Stream &strm) const { - strm.Printf("RenderScript Modules:"); - strm.EOL(); - strm.IndentMore(); - for (const auto &module : m_rsmodules) { - module->Dump(strm); - } - strm.IndentLess(); -} - -RenderScriptRuntime::ScriptDetails * -RenderScriptRuntime::LookUpScript(addr_t address, bool create) { - for (const auto &s : m_scripts) { - if (s->script.isValid()) - if (*s->script == address) - return s.get(); - } - if (create) { - std::unique_ptr s(new ScriptDetails); - s->script = address; - m_scripts.push_back(std::move(s)); - return m_scripts.back().get(); - } - return nullptr; -} - -RenderScriptRuntime::AllocationDetails * -RenderScriptRuntime::LookUpAllocation(addr_t address) { - for (const auto &a : m_allocations) { - if (a->address.isValid()) - if (*a->address == address) - return a.get(); - } - return nullptr; -} - -RenderScriptRuntime::AllocationDetails * -RenderScriptRuntime::CreateAllocation(addr_t address) { - Log *log = GetLog(LLDBLog::Language); - - // Remove any previous allocation which contains the same address - auto it = m_allocations.begin(); - while (it != m_allocations.end()) { - if (*((*it)->address) == address) { - LLDB_LOGF(log, "%s - Removing allocation id: %d, address: 0x%" PRIx64, - __FUNCTION__, (*it)->id, address); - - it = m_allocations.erase(it); - } else { - it++; - } - } - - std::unique_ptr a(new AllocationDetails); - a->address = address; - m_allocations.push_back(std::move(a)); - return m_allocations.back().get(); -} - -bool RenderScriptRuntime::ResolveKernelName(lldb::addr_t kernel_addr, - ConstString &name) { - Log *log = GetLog(LLDBLog::Symbols); - - Target &target = GetProcess()->GetTarget(); - Address resolved; - // RenderScript module - if (!target.GetSectionLoadList().ResolveLoadAddress(kernel_addr, resolved)) { - LLDB_LOGF(log, "%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())); - LLDB_LOGF(log, "%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(); - - strm.Indent(); - m_module->GetFileSpec().Dump(strm.AsRawOstream()); - strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded." - : "Debug info does not exist."); - strm.EOL(); - strm.IndentMore(); - - strm.Indent(); - strm.Printf("Globals: %" PRIu64, static_cast(m_globals.size())); - strm.EOL(); - strm.IndentMore(); - for (const auto &global : m_globals) { - global.Dump(strm); - } - strm.IndentLess(); - - strm.Indent(); - strm.Printf("Kernels: %" PRIu64, static_cast(m_kernels.size())); - strm.EOL(); - strm.IndentMore(); - for (const auto &kernel : m_kernels) { - kernel.Dump(strm); - } - strm.IndentLess(); - - strm.Indent(); - strm.Printf("Pragmas: %" PRIu64, static_cast(m_pragmas.size())); - strm.EOL(); - strm.IndentMore(); - for (const auto &key_val : m_pragmas) { - strm.Indent(); - strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); - strm.EOL(); - } - strm.IndentLess(); - - strm.Indent(); - strm.Printf("Reductions: %" PRIu64, - static_cast(m_reductions.size())); - strm.EOL(); - strm.IndentMore(); - for (const auto &reduction : m_reductions) { - reduction.Dump(strm); - } - - strm.SetIndentLevel(indent); -} - -void RSGlobalDescriptor::Dump(Stream &strm) const { - strm.Indent(m_name.GetStringRef()); - VariableList var_list; - m_module->m_module->FindGlobalVariables(m_name, CompilerDeclContext(), 1U, - var_list); - if (var_list.GetSize() == 1) { - auto var = var_list.GetVariableAtIndex(0); - auto type = var->GetType(); - if (type) { - strm.Printf(" - "); - type->DumpTypeName(&strm); - } else { - strm.Printf(" - Unknown Type"); - } - } else { - strm.Printf(" - variable identified, but not found in binary"); - const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType( - m_name, eSymbolTypeData); - if (s) { - strm.Printf(" (symbol exists) "); - } - } - - strm.EOL(); -} - -void RSKernelDescriptor::Dump(Stream &strm) const { - strm.Indent(m_name.GetStringRef()); - strm.EOL(); -} - -void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const { - stream.Indent(m_reduce_name.GetStringRef()); - stream.IndentMore(); - stream.EOL(); - stream.Indent(); - stream.Printf("accumulator: %s", m_accum_name.AsCString()); - stream.EOL(); - stream.Indent(); - stream.Printf("initializer: %s", m_init_name.AsCString()); - stream.EOL(); - stream.Indent(); - stream.Printf("combiner: %s", m_comb_name.AsCString()); - stream.EOL(); - stream.Indent(); - stream.Printf("outconverter: %s", m_outc_name.AsCString()); - stream.EOL(); - // XXX This is currently unspecified by RenderScript, and unused - // stream.Indent(); - // stream.Printf("halter: '%s'", m_init_name.AsCString()); - // stream.EOL(); - stream.IndentLess(); -} - -class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript module dump", - "Dumps renderscript specific information for all modules.", - "renderscript module dump", - eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} - - ~CommandObjectRenderScriptRuntimeModuleDump() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - RenderScriptRuntime *runtime = llvm::cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - runtime->DumpModules(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } -}; - -class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript module", - "Commands that deal with RenderScript modules.", - nullptr) { - LoadSubCommand( - "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump( - interpreter))); - } - - ~CommandObjectRenderScriptRuntimeModule() override = default; -}; - -class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript kernel list", - "Lists renderscript kernel names and associated script resources.", - "renderscript kernel list", - eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} - - ~CommandObjectRenderScriptRuntimeKernelList() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - RenderScriptRuntime *runtime = llvm::cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - runtime->DumpKernels(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } -}; - -static constexpr OptionDefinition g_renderscript_reduction_bp_set_options[] = { - {LLDB_OPT_SET_1, false, "function-role", 't', - OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOneLiner, - "Break on a comma separated set of reduction kernel types " - "(accumulator,outcoverter,combiner,initializer"}, - {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeValue, - "Set a breakpoint on a single invocation of the kernel with specified " - "coordinate.\n" - "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " - "integers representing kernel dimensions. " - "Any unset dimensions will be defaulted to zero."}}; - -class CommandObjectRenderScriptRuntimeReductionBreakpointSet - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeReductionBreakpointSet( - CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript reduction breakpoint set", - "Set a breakpoint on named RenderScript general reductions", - "renderscript reduction breakpoint set [-t " - "]", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | - eCommandProcessMustBePaused), - m_options() { - CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlain}; - m_arguments.push_back({name_arg}); - }; - - class CommandOptions : public Options { - public: - CommandOptions() : Options() {} - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *exe_ctx) override { - Status err; - StreamString err_str; - const int short_option = m_getopt_table[option_idx].val; - switch (short_option) { - case 't': - if (!ParseReductionTypes(option_arg, err_str)) - err.SetErrorStringWithFormat( - "Unable to deduce reduction types for %s: %s", - option_arg.str().c_str(), err_str.GetData()); - break; - case 'c': { - auto coord = RSCoordinate{}; - if (!ParseCoordinate(option_arg, coord)) - err.SetErrorStringWithFormat("unable to parse coordinate for %s", - option_arg.str().c_str()); - else { - m_have_coord = true; - m_coord = coord; - } - break; - } - default: - err.SetErrorStringWithFormat("Invalid option '-%c'", short_option); - } - return err; - } - - void OptionParsingStarting(ExecutionContext *exe_ctx) override { - m_have_coord = false; - } - - llvm::ArrayRef GetDefinitions() override { - return llvm::ArrayRef(g_renderscript_reduction_bp_set_options); - } - - bool ParseReductionTypes(llvm::StringRef option_val, - StreamString &err_str) { - m_kernel_types = RSReduceBreakpointResolver::eKernelTypeNone; - const auto reduce_name_to_type = [](llvm::StringRef name) -> int { - return llvm::StringSwitch(name) - .Case("accumulator", RSReduceBreakpointResolver::eKernelTypeAccum) - .Case("initializer", RSReduceBreakpointResolver::eKernelTypeInit) - .Case("outconverter", RSReduceBreakpointResolver::eKernelTypeOutC) - .Case("combiner", RSReduceBreakpointResolver::eKernelTypeComb) - .Case("all", RSReduceBreakpointResolver::eKernelTypeAll) - // Currently not exposed by the runtime - // .Case("halter", RSReduceBreakpointResolver::eKernelTypeHalter) - .Default(0); - }; - - // Matching a comma separated list of known words is fairly - // straightforward with PCRE, but we're using ERE, so we end up with a - // little ugliness... - RegularExpression match_type_list( - llvm::StringRef("^([[:alpha:]]+)(,[[:alpha:]]+){0,4}$")); - - assert(match_type_list.IsValid()); - - if (!match_type_list.Execute(option_val)) { - err_str.PutCString( - "a comma-separated list of kernel types is required"); - return false; - } - - // splitting on commas is much easier with llvm::StringRef than regex - llvm::SmallVector type_names; - llvm::StringRef(option_val).split(type_names, ','); - - for (const auto &name : type_names) { - const int type = reduce_name_to_type(name); - if (!type) { - err_str.Printf("unknown kernel type name %s", name.str().c_str()); - return false; - } - m_kernel_types |= type; - } - - return true; - } - - int m_kernel_types = RSReduceBreakpointResolver::eKernelTypeAll; - llvm::StringRef m_reduce_name; - RSCoordinate m_coord; - bool m_have_coord = false; - }; - - Options *GetOptions() override { return &m_options; } - - bool DoExecute(Args &command, CommandReturnObject &result) override { - const size_t argc = command.GetArgumentCount(); - if (argc < 1) { - result.AppendErrorWithFormat("'%s' takes 1 argument of reduction name, " - "and an optional kernel type list", - m_cmd_name.c_str()); - return false; - } - - RenderScriptRuntime *runtime = static_cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - auto &outstream = result.GetOutputStream(); - auto name = command.GetArgumentAtIndex(0); - auto &target = m_exe_ctx.GetTargetSP(); - auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr; - if (!runtime->PlaceBreakpointOnReduction(target, outstream, name, coord, - m_options.m_kernel_types)) { - result.AppendError("Error: unable to place breakpoint on reduction"); - return false; - } - result.AppendMessage("Breakpoint(s) created"); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } - -private: - CommandOptions m_options; -}; - -static constexpr OptionDefinition g_renderscript_kernel_bp_set_options[] = { - {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeValue, - "Set a breakpoint on a single invocation of the kernel with specified " - "coordinate.\n" - "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " - "integers representing kernel dimensions. " - "Any unset dimensions will be defaulted to zero."}}; - -class CommandObjectRenderScriptRuntimeKernelBreakpointSet - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeKernelBreakpointSet( - CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript kernel breakpoint set", - "Sets a breakpoint on a renderscript kernel.", - "renderscript kernel breakpoint set [-c x,y,z]", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | - eCommandProcessMustBePaused), - m_options() { - CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlain}; - m_arguments.push_back({name_arg}); - } - - ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; - - Options *GetOptions() override { return &m_options; } - - class CommandOptions : public Options { - public: - CommandOptions() : Options() {} - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *exe_ctx) override { - Status err; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) { - case 'c': { - auto coord = RSCoordinate{}; - if (!ParseCoordinate(option_arg, coord)) - err.SetErrorStringWithFormat( - "Couldn't parse coordinate '%s', should be in format 'x,y,z'.", - option_arg.str().c_str()); - else { - m_have_coord = true; - m_coord = coord; - } - break; - } - default: - err.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; - } - return err; - } - - void OptionParsingStarting(ExecutionContext *exe_ctx) override { - m_have_coord = false; - } - - llvm::ArrayRef GetDefinitions() override { - return llvm::ArrayRef(g_renderscript_kernel_bp_set_options); - } - - RSCoordinate m_coord; - bool m_have_coord = false; - }; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - const size_t argc = command.GetArgumentCount(); - if (argc < 1) { - result.AppendErrorWithFormat( - "'%s' takes 1 argument of kernel name, and an optional coordinate.", - m_cmd_name.c_str()); - return false; - } - - RenderScriptRuntime *runtime = llvm::cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - auto &outstream = result.GetOutputStream(); - auto &target = m_exe_ctx.GetTargetSP(); - auto name = command.GetArgumentAtIndex(0); - auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr; - if (!runtime->PlaceBreakpointOnKernel(target, outstream, name, coord)) { - result.AppendErrorWithFormat( - "Error: unable to set breakpoint on kernel '%s'", name); - return false; - } - - result.AppendMessage("Breakpoint(s) created"); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } - -private: - CommandOptions m_options; -}; - -class CommandObjectRenderScriptRuntimeKernelBreakpointAll - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeKernelBreakpointAll( - CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript kernel breakpoint all", - "Automatically sets a breakpoint on all renderscript kernels that " - "are or will be loaded.\n" - "Disabling option means breakpoints will no longer be set on any " - "kernels loaded in the future, " - "but does not remove currently set breakpoints.", - "renderscript kernel breakpoint all ", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | - eCommandProcessMustBePaused) { - CommandArgumentData enable_arg{eArgTypeNone, eArgRepeatPlain}; - m_arguments.push_back({enable_arg}); - } - - ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - const size_t argc = command.GetArgumentCount(); - if (argc != 1) { - result.AppendErrorWithFormat( - "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); - return false; - } - - RenderScriptRuntime *runtime = static_cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - bool do_break = false; - const char *argument = command.GetArgumentAtIndex(0); - if (strcmp(argument, "enable") == 0) { - do_break = true; - result.AppendMessage("Breakpoints will be set on all kernels."); - } else if (strcmp(argument, "disable") == 0) { - do_break = false; - result.AppendMessage("Breakpoints will not be set on any new kernels."); - } else { - result.AppendErrorWithFormat( - "Argument must be either 'enable' or 'disable'"); - return false; - } - - runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); - - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } -}; - -class CommandObjectRenderScriptRuntimeReductionBreakpoint - : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntimeReductionBreakpoint( - CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript reduction breakpoint", - "Commands that manipulate breakpoints on " - "renderscript general reductions.", - nullptr) { - LoadSubCommand( - "set", CommandObjectSP( - new CommandObjectRenderScriptRuntimeReductionBreakpointSet( - interpreter))); - } - - ~CommandObjectRenderScriptRuntimeReductionBreakpoint() override = default; -}; - -class CommandObjectRenderScriptRuntimeKernelCoordinate - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeKernelCoordinate( - CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript kernel coordinate", - "Shows the (x,y,z) coordinate of the current kernel invocation.", - "renderscript kernel coordinate", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | - eCommandProcessMustBePaused) {} - - ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - RSCoordinate coord{}; - bool success = RenderScriptRuntime::GetKernelCoordinate( - coord, m_exe_ctx.GetThreadPtr()); - Stream &stream = result.GetOutputStream(); - - if (success) { - stream.Printf("Coordinate: " FMT_COORD, coord.x, coord.y, coord.z); - stream.EOL(); - result.SetStatus(eReturnStatusSuccessFinishResult); - } else { - stream.Printf("Error: Coordinate could not be found."); - stream.EOL(); - result.SetStatus(eReturnStatusFailed); - } - return true; - } -}; - -class CommandObjectRenderScriptRuntimeKernelBreakpoint - : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntimeKernelBreakpoint( - CommandInterpreter &interpreter) - : CommandObjectMultiword( - interpreter, "renderscript kernel", - "Commands that generate breakpoints on renderscript kernels.", - nullptr) { - LoadSubCommand( - "set", - CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet( - interpreter))); - LoadSubCommand( - "all", - CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll( - interpreter))); - } - - ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; -}; - -class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript kernel", - "Commands that deal with RenderScript kernels.", - nullptr) { - LoadSubCommand( - "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList( - interpreter))); - LoadSubCommand( - "coordinate", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); - LoadSubCommand( - "breakpoint", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); - } - - ~CommandObjectRenderScriptRuntimeKernel() override = default; -}; - -class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript context dump", - "Dumps renderscript context information.", - "renderscript context dump", - eCommandRequiresProcess | - eCommandProcessMustBeLaunched) {} - - ~CommandObjectRenderScriptRuntimeContextDump() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - RenderScriptRuntime *runtime = llvm::cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - runtime->DumpContexts(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } -}; - -static constexpr OptionDefinition g_renderscript_runtime_alloc_dump_options[] = { - {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeFilename, - "Print results to specified file instead of command line."}}; - -class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript context", - "Commands that deal with RenderScript contexts.", - nullptr) { - LoadSubCommand( - "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump( - interpreter))); - } - - ~CommandObjectRenderScriptRuntimeContext() override = default; -}; - -class CommandObjectRenderScriptRuntimeAllocationDump - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeAllocationDump( - CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript allocation dump", - "Displays the contents of a particular allocation", - "renderscript allocation dump ", - eCommandRequiresProcess | - eCommandProcessMustBeLaunched), - m_options() { - CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - m_arguments.push_back({id_arg}); - } - - ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; - - Options *GetOptions() override { return &m_options; } - - class CommandOptions : public Options { - public: - CommandOptions() : Options() {} - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *exe_ctx) override { - Status err; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) { - case 'f': - m_outfile.SetFile(option_arg, FileSpec::Style::native); - FileSystem::Instance().Resolve(m_outfile); - if (FileSystem::Instance().Exists(m_outfile)) { - m_outfile.Clear(); - err.SetErrorStringWithFormat("file already exists: '%s'", - option_arg.str().c_str()); - } - break; - default: - err.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; - } - return err; - } - - void OptionParsingStarting(ExecutionContext *exe_ctx) override { - m_outfile.Clear(); - } - - llvm::ArrayRef GetDefinitions() override { - return llvm::ArrayRef(g_renderscript_runtime_alloc_dump_options); - } - - FileSpec m_outfile; - }; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - const size_t argc = command.GetArgumentCount(); - if (argc < 1) { - result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. " - "As well as an optional -f argument", - m_cmd_name.c_str()); - return false; - } - - RenderScriptRuntime *runtime = static_cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - const char *id_cstr = command.GetArgumentAtIndex(0); - uint32_t id; - if (!llvm::to_integer(id_cstr, id)) { - result.AppendErrorWithFormat("invalid allocation id argument '%s'", - id_cstr); - return false; - } - - Stream *output_stream_p = nullptr; - std::unique_ptr output_stream_storage; - - const FileSpec &outfile_spec = - m_options.m_outfile; // Dump allocation to file instead - if (outfile_spec) { - // Open output file - std::string path = outfile_spec.GetPath(); - auto file = FileSystem::Instance().Open(outfile_spec, - File::eOpenOptionWriteOnly | - File::eOpenOptionCanCreate); - if (file) { - output_stream_storage = - std::make_unique(std::move(file.get())); - output_stream_p = output_stream_storage.get(); - result.GetOutputStream().Printf("Results written to '%s'", - path.c_str()); - result.GetOutputStream().EOL(); - } else { - std::string error = llvm::toString(file.takeError()); - result.AppendErrorWithFormat("Couldn't open file '%s': %s", - path.c_str(), error.c_str()); - return false; - } - } else - output_stream_p = &result.GetOutputStream(); - - assert(output_stream_p != nullptr); - bool dumped = - runtime->DumpAllocation(*output_stream_p, m_exe_ctx.GetFramePtr(), id); - - if (dumped) - result.SetStatus(eReturnStatusSuccessFinishResult); - else - result.SetStatus(eReturnStatusFailed); - - return true; - } - -private: - CommandOptions m_options; -}; - -static constexpr OptionDefinition g_renderscript_runtime_alloc_list_options[] = { - {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr, - {}, 0, eArgTypeIndex, - "Only show details of a single allocation with specified id."}}; - -class CommandObjectRenderScriptRuntimeAllocationList - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeAllocationList( - CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript allocation list", - "List renderscript allocations and their information.", - "renderscript allocation list", - eCommandRequiresProcess | eCommandProcessMustBeLaunched), - m_options() {} - - ~CommandObjectRenderScriptRuntimeAllocationList() override = default; - - Options *GetOptions() override { return &m_options; } - - class CommandOptions : public Options { - public: - CommandOptions() : Options() {} - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *exe_ctx) override { - Status err; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) { - case 'i': - if (option_arg.getAsInteger(0, m_id)) - err.SetErrorStringWithFormat("invalid integer value for option '%c'", - short_option); - break; - default: - err.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; - } - return err; - } - - void OptionParsingStarting(ExecutionContext *exe_ctx) override { m_id = 0; } - - llvm::ArrayRef GetDefinitions() override { - return llvm::ArrayRef(g_renderscript_runtime_alloc_list_options); - } - - uint32_t m_id = 0; - }; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - RenderScriptRuntime *runtime = static_cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), - m_options.m_id); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } - -private: - CommandOptions m_options; -}; - -class CommandObjectRenderScriptRuntimeAllocationLoad - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeAllocationLoad( - CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript allocation load", - "Loads renderscript allocation contents from a file.", - "renderscript allocation load ", - eCommandRequiresProcess | eCommandProcessMustBeLaunched) { - CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - CommandArgumentData name_arg{eArgTypeFilename, eArgRepeatPlain}; - m_arguments.push_back({id_arg}); - m_arguments.push_back({name_arg}); - } - - ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - const size_t argc = command.GetArgumentCount(); - if (argc != 2) { - result.AppendErrorWithFormat( - "'%s' takes 2 arguments, an allocation ID and filename to read from.", - m_cmd_name.c_str()); - return false; - } - - RenderScriptRuntime *runtime = static_cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - const char *id_cstr = command.GetArgumentAtIndex(0); - uint32_t id; - if (!llvm::to_integer(id_cstr, id)) { - result.AppendErrorWithFormat("invalid allocation id argument '%s'", - id_cstr); - return false; - } - - const char *path = command.GetArgumentAtIndex(1); - bool loaded = runtime->LoadAllocation(result.GetOutputStream(), id, path, - m_exe_ctx.GetFramePtr()); - - if (loaded) - result.SetStatus(eReturnStatusSuccessFinishResult); - else - result.SetStatus(eReturnStatusFailed); - - return true; - } -}; - -class CommandObjectRenderScriptRuntimeAllocationSave - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeAllocationSave( - CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript allocation save", - "Write renderscript allocation contents to a file.", - "renderscript allocation save ", - eCommandRequiresProcess | - eCommandProcessMustBeLaunched) { - CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - CommandArgumentData name_arg{eArgTypeFilename, eArgRepeatPlain}; - m_arguments.push_back({id_arg}); - m_arguments.push_back({name_arg}); - } - - ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - const size_t argc = command.GetArgumentCount(); - if (argc != 2) { - result.AppendErrorWithFormat( - "'%s' takes 2 arguments, an allocation ID and filename to read from.", - m_cmd_name.c_str()); - return false; - } - - RenderScriptRuntime *runtime = static_cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - const char *id_cstr = command.GetArgumentAtIndex(0); - uint32_t id; - if (!llvm::to_integer(id_cstr, id)) { - result.AppendErrorWithFormat("invalid allocation id argument '%s'", - id_cstr); - return false; - } - - const char *path = command.GetArgumentAtIndex(1); - bool saved = runtime->SaveAllocation(result.GetOutputStream(), id, path, - m_exe_ctx.GetFramePtr()); - - if (saved) - result.SetStatus(eReturnStatusSuccessFinishResult); - else - result.SetStatus(eReturnStatusFailed); - - return true; - } -}; - -class CommandObjectRenderScriptRuntimeAllocationRefresh - : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeAllocationRefresh( - CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript allocation refresh", - "Recomputes the details of all allocations.", - "renderscript allocation refresh", - eCommandRequiresProcess | - eCommandProcessMustBeLaunched) {} - - ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - RenderScriptRuntime *runtime = static_cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - - bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), - m_exe_ctx.GetFramePtr()); - - if (success) { - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } else { - result.SetStatus(eReturnStatusFailed); - return false; - } - } -}; - -class CommandObjectRenderScriptRuntimeAllocation - : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) - : CommandObjectMultiword( - interpreter, "renderscript allocation", - "Commands that deal with RenderScript allocations.", nullptr) { - LoadSubCommand( - "list", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); - LoadSubCommand( - "dump", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); - LoadSubCommand( - "save", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); - LoadSubCommand( - "load", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); - LoadSubCommand( - "refresh", - CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh( - interpreter))); - } - - ~CommandObjectRenderScriptRuntimeAllocation() override = default; -}; - -class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed { -public: - CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript status", - "Displays current RenderScript runtime status.", - "renderscript status", - eCommandRequiresProcess | - eCommandProcessMustBeLaunched) {} - - ~CommandObjectRenderScriptRuntimeStatus() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - RenderScriptRuntime *runtime = llvm::cast( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( - eLanguageTypeExtRenderScript)); - runtime->DumpStatus(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } -}; - -class CommandObjectRenderScriptRuntimeReduction - : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntimeReduction(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript reduction", - "Commands that handle general reduction kernels", - nullptr) { - LoadSubCommand( - "breakpoint", - CommandObjectSP(new CommandObjectRenderScriptRuntimeReductionBreakpoint( - interpreter))); - } - ~CommandObjectRenderScriptRuntimeReduction() override = default; -}; - -class CommandObjectRenderScriptRuntime : public CommandObjectMultiword { -public: - CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) - : CommandObjectMultiword( - interpreter, "renderscript", - "Commands for operating on the RenderScript runtime.", - "renderscript []") { - LoadSubCommand( - "module", CommandObjectSP( - new CommandObjectRenderScriptRuntimeModule(interpreter))); - LoadSubCommand( - "status", CommandObjectSP( - new CommandObjectRenderScriptRuntimeStatus(interpreter))); - LoadSubCommand( - "kernel", CommandObjectSP( - new CommandObjectRenderScriptRuntimeKernel(interpreter))); - LoadSubCommand("context", - CommandObjectSP(new CommandObjectRenderScriptRuntimeContext( - interpreter))); - LoadSubCommand( - "allocation", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeAllocation(interpreter))); - LoadSubCommand("scriptgroup", - NewCommandObjectRenderScriptScriptGroup(interpreter)); - LoadSubCommand( - "reduction", - CommandObjectSP( - new CommandObjectRenderScriptRuntimeReduction(interpreter))); - } - - ~CommandObjectRenderScriptRuntime() override = default; -}; - -void RenderScriptRuntime::Initiate() { assert(!m_initiated); } - -RenderScriptRuntime::RenderScriptRuntime(Process *process) - : lldb_private::CPPLanguageRuntime(process), m_initiated(false), - m_debuggerPresentFlagged(false), m_breakAllKernels(false), - m_ir_passes(nullptr) { - ModulesDidLoad(process->GetTarget().GetImages()); -} - -lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject( - lldb_private::CommandInterpreter &interpreter) { - return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); -} - -RenderScriptRuntime::~RenderScriptRuntime() = default; diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h +++ /dev/null @@ -1,17 +0,0 @@ -//===-- RenderScriptScriptGroup.h -------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTSCRIPTGROUP_H -#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTSCRIPTGROUP_H - -#include "lldb/Interpreter/CommandInterpreter.h" - -lldb::CommandObjectSP NewCommandObjectRenderScriptScriptGroup( - lldb_private::CommandInterpreter &interpreter); - -#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTSCRIPTGROUP_H diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===-- RenderScriptScriptGroup.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Breakpoint/StoppointCallbackContext.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Core/PluginManager.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 "lldb/Utility/Args.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.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 ", - eCommandRequiresProcess | eCommandProcessMustBeLaunched) { - CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlus}; - m_arguments.push_back({name_arg}); - } - - ~CommandObjectRenderScriptScriptGroupBreakpointSet() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - Stream &stream = result.GetOutputStream(); - RenderScriptRuntime *runtime = static_cast( - 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 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]" - " ...", - 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( - 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/RenderScriptx86ABIFixups.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h +++ /dev/null @@ -1,22 +0,0 @@ -//===-- RenderScriptx86ABIFixups.h ------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTX86ABIFIXUPS_H -#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_RENDERSCRIPT_RENDERSCRIPTRUNTIME_RENDERSCRIPTX86ABIFIXUPS_H - -#include "llvm/IR/Module.h" - -namespace lldb_private { -namespace lldb_renderscript { - -bool fixupX86FunctionCalls(llvm::Module &module); - -bool fixupX86_64FunctionCalls(llvm::Module &module); -} -} -#endif diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp deleted file mode 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp +++ /dev/null @@ -1,271 +0,0 @@ -//===-- RenderScriptx86ABIFixups.cpp --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include - -#include "llvm/ADT/StringRef.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/IRReader/IRReader.h" -#include "llvm/Pass.h" - -#include "lldb/Target/Process.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" - -using namespace lldb_private; - -static bool isRSAPICall(llvm::CallInst *call_inst) { - // TODO get the list of renderscript modules from lldb and check if - // this llvm::Module calls into any of them. - const auto func_name = call_inst->getCalledFunction()->getName(); - if (func_name.startswith("llvm") || func_name.startswith("lldb")) - return false; - - if (call_inst->getCalledFunction()->isIntrinsic()) - return false; - - return true; -} - -static bool isRSLargeReturnCall(llvm::CallInst *call_inst) { - // i686 and x86_64 returns for large vectors in the RenderScript API are not - // handled as normal register pairs, but as a hidden sret type. This is not - // reflected in the debug info or mangled symbol name, and the android ABI - // for x86 and x86_64, (as well as the emulators) specifies there is no AVX, - // so bcc generates an sret function because we cannot natively return - // 256 bit vectors. - // This function simply checks whether a function has a > 128bit return type. - // It is perhaps an unreliable heuristic, and relies on bcc not generating - // AVX code, so if the android ABI one day provides for AVX, this function - // may go out of fashion. - if (!call_inst || !call_inst->getCalledFunction()) - return false; - - return call_inst->getCalledFunction() - ->getReturnType() - ->getPrimitiveSizeInBits() > 128; -} - -static bool isRSAllocationTy(const llvm::Type *type) { - return type->isStructTy() && - type->getStructName().startswith("struct.rs_allocation"); -} - -static bool isRSAllocationTyCallSite(llvm::CallInst *call_inst) { - if (!call_inst->hasByValArgument()) - return false; - for (unsigned i = 0; i < call_inst->arg_size(); ++i) { - if (llvm::Type *ByValTy = call_inst->getParamByValType(i)) - if (isRSAllocationTy(ByValTy)) - return true; - } - return false; -} - -static llvm::FunctionType *cloneToStructRetFnTy(llvm::CallInst *call_inst) { - // on x86 StructReturn functions return a pointer to the return value, rather - // than the return value itself - // [ref](http://www.agner.org/optimize/calling_conventions.pdf section 6). We - // create a return type by getting the pointer type of the old return type, - // and inserting a new initial argument of pointer type of the original - // return type. - Log *log = GetLog(LLDBLog::Language | LLDBLog::Expressions); - - assert(call_inst && "no CallInst"); - llvm::Function *orig = call_inst->getCalledFunction(); - assert(orig && "CallInst has no called function"); - llvm::FunctionType *orig_type = orig->getFunctionType(); - auto name = orig->getName(); - LLDB_LOGF(log, "%s - cloning to StructRet function for '%s'", __FUNCTION__, - name.str().c_str()); - - unsigned num_params = orig_type->getNumParams(); - std::vector new_params{num_params + 1, nullptr}; - std::vector params{orig_type->param_begin(), - orig_type->param_end()}; - - // This may not work if the function is somehow declared void as llvm is - // strongly typed and represents void* with i8* - assert(!orig_type->getReturnType()->isVoidTy() && - "Cannot add StructRet attribute to void function"); - llvm::PointerType *return_type_ptr_type = - llvm::PointerType::getUnqual(orig->getReturnType()); - assert(return_type_ptr_type && - "failed to get function return type PointerType"); - if (!return_type_ptr_type) - return nullptr; - - LLDB_LOGF(log, - "%s - return type pointer type for StructRet clone @ '0x%p':\n", - __FUNCTION__, (void *)return_type_ptr_type); - // put the sret pointer argument in place at the beginning of the - // argument list. - params.emplace(params.begin(), return_type_ptr_type); - assert(params.size() == num_params + 1); - return llvm::FunctionType::get(return_type_ptr_type, params, - orig->isVarArg()); -} - -static bool -findRSCallSites(llvm::Module &module, std::set &rs_callsites, - bool (*predicate)(llvm::CallInst *)) { - bool found = false; - - for (auto &func : module.getFunctionList()) - for (auto &block : func) - for (auto &inst : block) { - llvm::CallInst *call_inst = - llvm::dyn_cast_or_null(&inst); - if (!call_inst || !call_inst->getCalledFunction()) - // This is not the call-site you are looking for... - continue; - if (isRSAPICall(call_inst) && predicate(call_inst)) { - rs_callsites.insert(call_inst); - found = true; - } - } - return found; -} - -static bool fixupX86StructRetCalls(llvm::Module &module) { - bool changed = false; - // changing a basic block while iterating over it seems to have some - // undefined behaviour going on so we find all RS callsites first, then fix - // them up after consuming the iterator. - std::set rs_callsites; - if (!findRSCallSites(module, rs_callsites, isRSLargeReturnCall)) - return false; - - for (auto call_inst : rs_callsites) { - llvm::FunctionType *new_func_type = cloneToStructRetFnTy(call_inst); - assert(new_func_type && - "failed to clone functionType for Renderscript ABI fixup"); - - llvm::Function *func = call_inst->getCalledFunction(); - assert(func && "cannot resolve function in RenderScriptRuntime"); - // Copy the original call arguments - std::vector new_call_args(call_inst->arg_begin(), - call_inst->arg_end()); - - // Allocate enough space to store the return value of the original function - // we pass a pointer to this allocation as the StructRet param, and then - // copy its value into the lldb return value - const llvm::DataLayout &DL = module.getDataLayout(); - llvm::AllocaInst *return_value_alloc = new llvm::AllocaInst( - func->getReturnType(), DL.getAllocaAddrSpace(), "var_vector_return_alloc", - call_inst); - // use the new allocation as the new first argument - new_call_args.emplace(new_call_args.begin(), - llvm::cast(return_value_alloc)); - llvm::PointerType *new_func_ptr_type = - llvm::PointerType::get(new_func_type, 0); - // Create the type cast from the old function type to the new one - llvm::Constant *new_func_cast = llvm::ConstantExpr::getCast( - llvm::Instruction::BitCast, func, new_func_ptr_type); - // create an allocation for a new function pointer - llvm::AllocaInst *new_func_ptr = - new llvm::AllocaInst(new_func_ptr_type, DL.getAllocaAddrSpace(), - "new_func_ptr", call_inst); - // store the new_func_cast to the newly allocated space - (new llvm::StoreInst(new_func_cast, new_func_ptr, call_inst)) - ->setName("new_func_ptr_load_cast"); - // load the new function address ready for a jump - llvm::LoadInst *new_func_addr_load = new llvm::LoadInst( - new_func_ptr_type, new_func_ptr, "load_func_pointer", call_inst); - // and create a callinstruction from it - llvm::CallInst *new_call_inst = - llvm::CallInst::Create(new_func_type, new_func_addr_load, new_call_args, - "new_func_call", call_inst); - new_call_inst->setCallingConv(call_inst->getCallingConv()); - new_call_inst->setTailCall(call_inst->isTailCall()); - llvm::LoadInst *lldb_save_result_address = - new llvm::LoadInst(func->getReturnType(), return_value_alloc, - "save_return_val", call_inst); - - // Now remove the old broken call - call_inst->replaceAllUsesWith(lldb_save_result_address); - call_inst->eraseFromParent(); - changed = true; - } - return changed; -} - -static bool fixupRSAllocationStructByValCalls(llvm::Module &module) { - // On x86_64, calls to functions in the RS runtime that take an - // `rs_allocation` type argument are actually handled as by-ref params by - // bcc, but appear to be passed by value by lldb (the callsite all use - // `struct byval`). On x86_64 Linux, struct arguments are transferred in - // registers if the struct size is no bigger than 128bits - // [ref](http://www.agner.org/optimize/calling_conventions.pdf) section 7.1 - // "Passing and returning objects" otherwise passed on the stack. an object - // of type `rs_allocation` is actually 256bits, so should be passed on the - // stack. However, code generated by bcc actually treats formal params of - // type `rs_allocation` as `rs_allocation *` so we need to convert the - // calling convention to pass by reference, and remove any hint of byval from - // formal parameters. - bool changed = false; - std::set rs_callsites; - if (!findRSCallSites(module, rs_callsites, isRSAllocationTyCallSite)) - return false; - - std::set rs_functions; - - // for all call instructions - for (auto call_inst : rs_callsites) { - // add the called function to a set so that we can strip its byval - // attributes in another pass - rs_functions.insert(call_inst->getCalledFunction()); - - // get the function attributes - llvm::AttributeList call_attribs = call_inst->getAttributes(); - - // iterate over the argument attributes - for (unsigned I : call_attribs.indexes()) { - // if this argument is passed by val - if (call_attribs.hasAttributeAtIndex(I, llvm::Attribute::ByVal)) { - // strip away the byval attribute - call_inst->removeAttributeAtIndex(I, llvm::Attribute::ByVal); - changed = true; - } - } - } - - // for all called function decls - for (auto func : rs_functions) { - // inspect all of the arguments in the call - for (auto &arg : func->args()) { - if (arg.hasByValAttr()) { - arg.removeAttr(llvm::Attribute::ByVal); - changed = true; - } - } - } - return changed; -} - -namespace lldb_private { -namespace lldb_renderscript { - -bool fixupX86FunctionCalls(llvm::Module &module) { - return fixupX86StructRetCalls(module); -} - -bool fixupX86_64FunctionCalls(llvm::Module &module) { - bool changed = false; - changed |= fixupX86StructRetCalls(module); - changed |= fixupRSAllocationStructByValCalls(module); - return changed; -} - -} // end namespace lldb_renderscript -} // end namespace lldb_private diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4223,8 +4223,6 @@ switch (val) { case DW_LANG_Mips_Assembler: return eLanguageTypeMipsAssembler; - case DW_LANG_GOOGLE_RenderScript: - return eLanguageTypeExtRenderScript; default: return static_cast(val); } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -108,7 +108,6 @@ lldb_private::Language::LanguageIsPascal(language) || // Use Clang for Rust until there is a proper language plugin for it language == eLanguageTypeRust || - language == eLanguageTypeExtRenderScript || // Use Clang for D until there is a proper language plugin for it language == eLanguageTypeD || // Open Dylan compiler debug info is designed to be Clang-compatible @@ -475,7 +474,6 @@ switch (IK.getLanguage()) { case clang::Language::Unknown: case clang::Language::LLVM_IR: - case clang::Language::RenderScript: llvm_unreachable("Invalid input kind!"); case clang::Language::OpenCL: LangStd = LangStandard::lang_opencl10; diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -196,7 +196,6 @@ {"fortran08", eLanguageTypeFortran08}, // Vendor Extensions {"assembler", eLanguageTypeMipsAssembler}, - {"renderscript", eLanguageTypeExtRenderScript}, // Now synonyms, in arbitrary order {"objc", eLanguageTypeObjC}, {"objc++", eLanguageTypeObjC_plus_plus}, @@ -350,7 +349,6 @@ case eLanguageTypeJulia: case eLanguageTypeDylan: case eLanguageTypeMipsAssembler: - case eLanguageTypeExtRenderScript: case eLanguageTypeUnknown: default: return language;