diff options
Diffstat (limited to 'lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp')
-rw-r--r-- | lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp | 349 |
1 files changed, 345 insertions, 4 deletions
diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index 0ee6b4c1ef0..d92f10014d1 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -14,6 +14,7 @@ // Project includes #include "RenderScriptRuntime.h" +#include "RenderScriptScriptGroup.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/ConstString.h" @@ -31,11 +32,13 @@ #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -475,6 +478,26 @@ bool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) { return get_index(0, coord.x) && get_index(1, coord.y) && get_index(2, coord.z); } + +bool SkipPrologue(lldb::ModuleSP &module, Address &addr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + SymbolContext sc; + uint32_t resolved_flags = + module->ResolveSymbolContextForAddress(addr, eSymbolContextFunction, sc); + if (resolved_flags & eSymbolContextFunction) { + if (sc.function) { + const uint32_t offset = sc.function->GetPrologueByteSize(); + ConstString name = sc.GetFunctionName(); + if (offset) + addr.Slide(offset); + if (log) + log->Printf("%s: Prologue offset for %s is %" PRIu32, __FUNCTION__, + name.AsCString(), offset); + } + return true; + } else + return false; +} } // anonymous namespace // The ScriptDetails class collects data associated with a single script @@ -872,6 +895,80 @@ RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, return eCallbackReturnContinue; } +Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback( + SearchFilter &filter, SymbolContext &context, Address *addr, + bool containing) { + + if (!m_breakpoint) + return eCallbackReturnContinue; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + ModuleSP &module = context.module_sp; + + if (!module || !IsRenderScriptScriptModule(module)) + return Searcher::eCallbackReturnContinue; + + std::vector<std::string> names; + m_breakpoint->GetNames(names); + if (names.empty()) + return eCallbackReturnContinue; + + for (auto &name : names) { + const RSScriptGroupDescriptorSP sg = FindScriptGroup(ConstString(name)); + if (!sg) { + if (log) + log->Printf("%s: could not find script group for %s", __FUNCTION__, + name.c_str()); + continue; + } + + if (log) + log->Printf("%s: Found ScriptGroup for %s", __FUNCTION__, name.c_str()); + + for (const RSScriptGroupDescriptor::Kernel &k : sg->m_kernels) { + if (log) { + log->Printf("%s: Adding breakpoint for %s", __FUNCTION__, + k.m_name.AsCString()); + log->Printf("%s: Kernel address 0x%" PRIx64, __FUNCTION__, k.m_addr); + } + + const lldb_private::Symbol *sym = + module->FindFirstSymbolWithNameAndType(k.m_name, eSymbolTypeCode); + if (!sym) { + if (log) + log->Printf("%s: Unable to find symbol for %s", __FUNCTION__, + k.m_name.AsCString()); + continue; + } + + if (log) { + log->Printf("%s: Found symbol name is %s", __FUNCTION__, + sym->GetName().AsCString()); + } + + auto address = sym->GetAddress(); + if (!SkipPrologue(module, address)) { + if (log) + log->Printf("%s: Error trying to skip prologue", __FUNCTION__); + } + + bool new_bp; + m_breakpoint->AddLocation(address, &new_bp); + + if (log) + log->Printf("%s: Placed %sbreakpoint on %s", __FUNCTION__, + new_bp ? "new " : "", k.m_name.AsCString()); + + // exit after placing the first breakpoint if we do not intend to stop + // on all kernels making up this script group + if (!m_stop_on_all) + break; + } + } + + return eCallbackReturnContinue; +} + void RenderScriptRuntime::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), "RenderScript language support", CreateInstance, @@ -1006,7 +1103,15 @@ const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = "10AllocationE", 0, RenderScriptRuntime::eModuleKindDriver, &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy}, -}; + + // renderscript script groups + {"rsdDebugHintScriptGroup2", "_ZN7android12renderscript21debugHintScrip" + "tGroup2EPKcjPKPFvPK24RsExpandKernelDriver" + "InfojjjEj", + "_ZN7android12renderscript21debugHintScriptGroup2EPKcjPKPFvPK24RsExpan" + "dKernelDriverInfojjjEj", + 0, RenderScriptRuntime::eModuleKindImpl, + &lldb_private::RenderScriptRuntime::CaptureDebugHintScriptGroup2}}; const size_t RenderScriptRuntime::s_runtimeHookCount = sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]); @@ -1039,6 +1144,154 @@ void RenderScriptRuntime::HookCallback(RuntimeHook *hook, } } +void RenderScriptRuntime::CaptureDebugHintScriptGroup2( + RuntimeHook *hook_info, ExecutionContext &context) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + enum { + eGroupName = 0, + eGroupNameSize, + eKernel, + eKernelCount, + }; + + std::array<ArgItem, 4> args{{ + {ArgItem::ePointer, 0}, // const char *groupName + {ArgItem::eInt32, 0}, // const uint32_t groupNameSize + {ArgItem::ePointer, 0}, // const ExpandFuncTy *kernel + {ArgItem::eInt32, 0}, // const uint32_t kernelCount + }}; + + if (!GetArgs(context, args.data(), args.size())) { + if (log) + log->Printf("%s - Error while reading the function parameters", + __FUNCTION__); + return; + } else if (log) { + log->Printf("%s - groupName : 0x%" PRIx64, __FUNCTION__, + addr_t(args[eGroupName])); + log->Printf("%s - groupNameSize: %" PRIu64, __FUNCTION__, + uint64_t(args[eGroupNameSize])); + log->Printf("%s - kernel : 0x%" PRIx64, __FUNCTION__, + addr_t(args[eKernel])); + log->Printf("%s - kernelCount : %" PRIu64, __FUNCTION__, + uint64_t(args[eKernelCount])); + } + + // parse script group name + ConstString group_name; + { + Error err; + const uint64_t len = uint64_t(args[eGroupNameSize]); + std::unique_ptr<char[]> buffer(new char[uint32_t(len + 1)]); + m_process->ReadMemory(addr_t(args[eGroupName]), buffer.get(), len, err); + buffer.get()[len] = '\0'; + if (!err.Success()) { + if (log) + log->Printf("Error reading scriptgroup name from target"); + return; + } else { + if (log) + log->Printf("Extracted scriptgroup name %s", buffer.get()); + } + // write back the script group name + group_name.SetCString(buffer.get()); + } + + // create or access existing script group + RSScriptGroupDescriptorSP group; + { + // search for existing script group + for (auto sg : m_scriptGroups) { + if (sg->m_name == group_name) { + group = sg; + break; + } + } + if (!group) { + group.reset(new RSScriptGroupDescriptor); + group->m_name = group_name; + m_scriptGroups.push_back(group); + } else { + // already have this script group + if (log) + log->Printf("Attempt to add duplicate script group %s", + group_name.AsCString()); + return; + } + } + assert(group); + + const uint32_t target_ptr_size = m_process->GetAddressByteSize(); + std::vector<addr_t> kernels; + // parse kernel addresses in script group + for (uint64_t i = 0; i < uint64_t(args[eKernelCount]); ++i) { + RSScriptGroupDescriptor::Kernel kernel; + // extract script group kernel addresses from the target + const addr_t ptr_addr = addr_t(args[eKernel]) + i * target_ptr_size; + uint64_t kernel_addr = 0; + Error err; + size_t read = + m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err); + if (!err.Success() || read != target_ptr_size) { + if (log) + log->Printf("Error parsing kernel address %" PRIu64 " in script group", + i); + return; + } + if (log) + log->Printf("Extracted scriptgroup kernel address - 0x%" PRIx64, + kernel_addr); + kernel.m_addr = kernel_addr; + + // try to resolve the associated kernel name + if (!ResolveKernelName(kernel.m_addr, kernel.m_name)) { + if (log) + log->Printf("Parsed scriptgroup kernel %" PRIu64 " - 0x%" PRIx64, i, + kernel_addr); + return; + } + + // try to find the non '.expand' function + { + const llvm::StringRef expand(".expand"); + const llvm::StringRef name_ref = kernel.m_name.GetStringRef(); + if (name_ref.endswith(expand)) { + const ConstString base_kernel(name_ref.drop_back(expand.size())); + // verify this function is a valid kernel + if (IsKnownKernel(base_kernel)) { + kernel.m_name = base_kernel; + if (log) + log->Printf("%s - found non expand version '%s'", __FUNCTION__, + base_kernel.GetCString()); + } + } + } + // add to a list of script group kernels we know about + group->m_kernels.push_back(kernel); + } + + // Resolve any pending scriptgroup breakpoints + { + Target &target = m_process->GetTarget(); + const BreakpointList &list = target.GetBreakpointList(); + const size_t num_breakpoints = list.GetSize(); + if (log) + log->Printf("Resolving %zu breakpoints", num_breakpoints); + for (size_t i = 0; i < num_breakpoints; ++i) { + const BreakpointSP bp = list.GetBreakpointAtIndex(i); + if (bp) { + if (bp->MatchesName(group_name.AsCString())) { + if (log) + log->Printf("Found breakpoint with name %s", + group_name.AsCString()); + bp->ResolveBreakpoint(); + } + } + } + } +} + void RenderScriptRuntime::CaptureScriptInvokeForEachMulti( RuntimeHook *hook, ExecutionContext &exe_ctx) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); @@ -1332,7 +1585,7 @@ void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, } Target &target = GetProcess()->GetTarget(); - llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine(); + const llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine(); if (machine != llvm::Triple::ArchType::x86 && machine != llvm::Triple::ArchType::arm && @@ -1345,7 +1598,11 @@ void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, return; } - uint32_t target_ptr_size = target.GetArchitecture().GetAddressByteSize(); + const uint32_t target_ptr_size = + target.GetArchitecture().GetAddressByteSize(); + + std::array<bool, s_runtimeHookCount> hook_placed; + hook_placed.fill(false); for (size_t idx = 0; idx < s_runtimeHookCount; idx++) { const HookDefn *hook_defn = &s_runtimeHookDefns[idx]; @@ -1393,6 +1650,20 @@ void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, module->GetFileSpec().GetFilename().AsCString(), (uint64_t)hook_defn->version, (uint64_t)addr); } + hook_placed[idx] = true; + } + + // log any unhooked function + if (log) { + for (size_t i = 0; i < hook_placed.size(); ++i) { + if (hook_placed[i]) + continue; + const HookDefn &hook_defn = s_runtimeHookDefns[i]; + if (hook_defn.kind != kind) + continue; + log->Printf("%s - function %s was not hooked", __FUNCTION__, + hook_defn.name); + } } } @@ -2594,7 +2865,10 @@ bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { break; } case eModuleKindImpl: { - m_libRSCpuRef = module_sp; + if (!m_libRSCpuRef) { + m_libRSCpuRef = module_sp; + LoadRuntimeHooks(m_libRSCpuRef, RenderScriptRuntime::eModuleKindImpl); + } break; } case eModuleKindLibRS: { @@ -3535,6 +3809,45 @@ bool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target, return true; } +BreakpointSP +RenderScriptRuntime::CreateScriptGroupBreakpoint(const ConstString &name, + bool stop_on_all) { + Log *log( + GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); + + if (!m_filtersp) { + if (log) + log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__); + return nullptr; + } + + BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver( + nullptr, name, m_scriptGroups, stop_on_all)); + BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( + m_filtersp, resolver_sp, false, false, false); + // Give RS breakpoints a specific name, so the user can manipulate them as a + // group. + Error err; + if (!bp->AddName(name.AsCString(), err)) + if (log) + log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, + err.AsCString()); + // ask the breakpoint to resolve itself + bp->ResolveBreakpoint(); + return bp; +} + +bool RenderScriptRuntime::PlaceBreakpointOnScriptGroup(TargetSP target, + Stream &strm, + const ConstString &name, + bool multi) { + InitSearchFilter(target); + BreakpointSP bp = CreateScriptGroupBreakpoint(name, multi); + if (bp) + bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); + return bool(bp); +} + bool RenderScriptRuntime::PlaceBreakpointOnReduction(TargetSP target, Stream &messages, const char *reduce_name, @@ -3617,6 +3930,32 @@ RenderScriptRuntime::CreateAllocation(addr_t address) { return m_allocations.back().get(); } +bool RenderScriptRuntime::ResolveKernelName(lldb::addr_t kernel_addr, + ConstString &name) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); + + Target &target = GetProcess()->GetTarget(); + Address resolved; + // RenderScript module + if (!target.GetSectionLoadList().ResolveLoadAddress(kernel_addr, resolved)) { + if (log) + log->Printf("%s: unable to resolve 0x%" PRIx64 " to a loaded symbol", + __FUNCTION__, kernel_addr); + return false; + } + + Symbol *sym = resolved.CalculateSymbolContextSymbol(); + if (!sym) + return false; + + name = sym->GetName(); + assert(IsRenderScriptModule(resolved.CalculateSymbolContextModule())); + if (log) + log->Printf("%s: 0x%" PRIx64 " resolved to the symbol '%s'", __FUNCTION__, + kernel_addr, name.GetCString()); + return true; +} + void RSModuleDescriptor::Dump(Stream &strm) const { int indent = strm.GetIndentLevel(); @@ -4636,6 +4975,8 @@ public: "allocation", CommandObjectSP( new CommandObjectRenderScriptRuntimeAllocation(interpreter))); + LoadSubCommand("scriptgroup", + NewCommandObjectRenderScriptScriptGroup(interpreter)); LoadSubCommand( "reduction", CommandObjectSP( |