EwanCrawford created this revision. EwanCrawford added reviewers: clayborg, jingham. EwanCrawford added subscribers: lldb-commits, domipheus, ADodds. EwanCrawford set the repository for this revision to rL LLVM.
Currently the RS breakpoint command can only find a kernel if it's in an already loaded RS module. This patch allows users to set pending breakpoints on RenderScript kernels which will be loaded in the future. To maintain these breakpoints the command 'renderscript kernel breakpoint' is split into 3 separate sub-commands. 'renderscript kernel breakpoint set', 'renderscript kernel breakpoint list', and 'renderscript kernel breakpoint delete'. Repository: rL LLVM http://reviews.llvm.org/D12360 Files: source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
Index: source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h =================================================================== --- source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -147,8 +147,12 @@ void DumpKernels(Stream &strm) const; + void DumpBreakpoints(Stream &strm) const; + void AttemptBreakpointAtKernelName(Stream &strm, const char *name, Error &error); + void DeleteBreakpoint(Stream &strm, const char* name); + void Status(Stream &strm) const; virtual size_t GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) { @@ -206,6 +210,8 @@ std::map<lldb::addr_t, RSModuleDescriptorSP> m_scriptMappings; std::map<lldb::addr_t, RuntimeHookSP> m_runtimeHooks; + std::map<ConstString, lldb::BreakpointSP> m_kernel_breakpoints; // BreakpointSP is null if breakpoint is pending + bool m_initiated; bool m_debuggerPresentFlagged; static const HookDefn s_runtimeHookDefns[]; @@ -225,6 +231,9 @@ void CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context); void CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context); + void CheckModuleForPendingBreakpoints(const RSModuleDescriptorSP& module_desc); + bool ResolveKernelBreakpoint(ConstString kernel_name, const RSModuleDescriptorSP& module, + Error& error, lldb::BreakpointSP& bp, Stream* strm = nullptr); }; } // namespace lldb_private Index: source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp =================================================================== --- source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -28,6 +28,8 @@ #include "lldb/Symbol/VariableList.h" +#include <algorithm> + using namespace lldb; using namespace lldb_private; @@ -496,7 +498,12 @@ for (const auto &rs_module : m_rsmodules) { if (rs_module->m_module == module_sp) + { + // The dynamic loader can update the loaded sections + // after we have already seen the module. + CheckModuleForPendingBreakpoints(rs_module); return false; + } } bool module_loaded = false; switch (GetModuleKind(module_sp)) @@ -507,6 +514,7 @@ module_desc.reset(new RSModuleDescriptor(module_sp)); if (module_desc->ParseRSInfo()) { + CheckModuleForPendingBreakpoints(module_desc); m_rsmodules.push_back(module_desc); module_loaded = true; } @@ -767,72 +775,189 @@ strm.IndentLess(); } -void -RenderScriptRuntime::AttemptBreakpointAtKernelName(Stream &strm, const char* name, Error& error) +void +RenderScriptRuntime::DumpBreakpoints(Stream &strm) const { - if (!name) + strm.Printf("RenderScript Kernel Breakpoints:"); + strm.EOL(); + strm.IndentMore(); + for (const auto &bp_pair : m_kernel_breakpoints) { - error.SetErrorString("invalid kernel name"); - return; + strm.Printf("\t%s - ", bp_pair.first.AsCString()); + if (bp_pair.second == nullptr) + strm.Printf("Pending on RS module load"); + else + bp_pair.second->GetDescription(&strm, lldb::eDescriptionLevelBrief, false); + + strm.EOL(); } + strm.IndentLess(); +} - bool kernels_found = false; +void +RenderScriptRuntime::DeleteBreakpoint(Stream &strm, const char* name) +{ ConstString kernel_name(name); - for (const auto &module : m_rsmodules) + auto match = m_kernel_breakpoints.find(kernel_name); + + if (match != m_kernel_breakpoints.end()) { - for (const auto &kernel : module->m_kernels) + BreakpointSP bp = match->second; + if (bp != nullptr) + GetProcess()->GetTarget().RemoveBreakpointByID(bp->GetID()); + strm.Printf("Breakpoint deleted"); + m_kernel_breakpoints.erase(match); + } + else + strm.Printf("No kernel breakpoint found matching '%s'", name); + + strm.EOL(); +} + +// Given the name of a kernel and a RS module, check to see if there is a matching kernel in the module. +// If so a breakpoint is set on the kernel and true is returned, otherwise return false. +bool +RenderScriptRuntime::ResolveKernelBreakpoint(ConstString kernel_name, + const RSModuleDescriptorSP& module, + Error& error, + BreakpointSP& bp, + Stream* strm) +{ + Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + for (const auto &kernel : module->m_kernels) + { + if (kernel.m_name == kernel_name) { - if (kernel.m_name == kernel_name) + // Attempt to set a breakpoint on this symbol, within the module library + // If it's not found, it's likely debug info is unavailable - set a + // breakpoint on <name>.expand and emit a warning. + + const Symbol* kernel_sym = module->m_module->FindFirstSymbolWithNameAndType(kernel_name, eSymbolTypeCode); + const char* kernel_name_cstr = kernel_name.AsCString(); + + if (!kernel_sym) { - //Attempt to set a breakpoint on this symbol, within the module library - //If it's not found, it's likely debug info is unavailable - set a - //breakpoint on <name>.expand and emit a warning. + std::string kernel_name_expanded(kernel_name_cstr); + kernel_name_expanded.append(".expand"); + kernel_sym = module->m_module->FindFirstSymbolWithNameAndType(ConstString(kernel_name_expanded.c_str()), + eSymbolTypeCode); - const Symbol* kernel_sym = module->m_module->FindFirstSymbolWithNameAndType(kernel_name, eSymbolTypeCode); - - if (!kernel_sym) + if (kernel_sym && strm != nullptr) { - std::string kernel_name_expanded(name); - kernel_name_expanded.append(".expand"); - kernel_sym = module->m_module->FindFirstSymbolWithNameAndType(ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); - - if (kernel_sym) - { - strm.Printf("Kernel '%s' could not be found, but expansion exists. ", name); - strm.Printf("Breakpoint placed on expanded kernel. Have you compiled in debug mode?"); - strm.EOL(); - } - else - { - error.SetErrorStringWithFormat("Could not locate symbols for loaded kernel '%s'.", name); - return; - } + strm->Printf("Kernel '%s' could not be found, but expansion exists. ", kernel_name_cstr); + strm->Printf("Breakpoint placed on expanded kernel. Have you compiled in debug mode?"); + strm->EOL(); } + } + if (kernel_sym) + { addr_t bp_addr = kernel_sym->GetLoadAddress(&GetProcess()->GetTarget()); if (bp_addr == LLDB_INVALID_ADDRESS) { - error.SetErrorStringWithFormat("Could not locate load address for symbols of kernel '%s'.", name); - return; + error.SetErrorStringWithFormat("Could not locate load address for symbols of kernel '%s'.", + kernel_name_cstr); + return false; } - BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(bp_addr, false, false); - strm.Printf("Breakpoint %" PRIu64 ": kernel '%s' within script '%s'", (uint64_t)bp->GetID(), name, module->m_resname.c_str()); - strm.EOL(); + bp = GetProcess()->GetTarget().CreateBreakpoint(bp_addr, false, false); + if (strm != nullptr) + { + strm->Printf("Breakpoint %" PRIu64 ": kernel '%s' within script '%s'", (uint64_t)bp->GetID(), + kernel_name_cstr, + module->m_resname.c_str()); + strm->EOL(); + } + } + else + { + error.SetErrorStringWithFormat("Could not locate symbols for loaded kernel '%s'.", kernel_name_cstr); + return false; + } - kernels_found = true; - } + if (log) + log->Printf ("RenderScriptRuntime::ResolveKernelBreakpoint - '%s' kernel breakpoint resolved.", + kernel_name_cstr); + + return true; } } + return false; +} - if (!kernels_found) +void +RenderScriptRuntime::AttemptBreakpointAtKernelName(Stream &strm, const char* name, Error& error) +{ + if (!name) { - error.SetErrorString("kernel name not found"); + error.SetErrorString("invalid kernel name"); + return; } + + ConstString kernel_name(name); + + // Only create one pending breakpoint per kernel name + auto end_itr = m_kernel_breakpoints.end(); + auto matching_itr = m_kernel_breakpoints.find(kernel_name); + + if (matching_itr == end_itr) + { + // Check if the kernel breakpoint can be set in any of the loaded RS modules + BreakpointSP bp; + bool kernel_found = std::any_of + ( + m_rsmodules.begin(), + m_rsmodules.end(), + [&](const RSModuleDescriptorSP module) + { + return ResolveKernelBreakpoint(kernel_name, module, error, bp, &strm); + } + ); + + if (!kernel_found) + { + m_kernel_breakpoints[kernel_name] = nullptr; // Pending breakpoint + strm.Printf("Kernel could not be found, pending breakpoint created"); + strm.EOL(); + } + else + m_kernel_breakpoints[kernel_name] = bp; + } + else + error.SetErrorStringWithFormat("Breakpoint already exists for kernel '%s'.", name); + return; } +// Iterate over all the kernel breakpoints which haven't yet been resolved to an address. +// If they can be set in the module, then remove them for the list of pending breakpoints. void +RenderScriptRuntime::CheckModuleForPendingBreakpoints(const RSModuleDescriptorSP& module_desc) +{ + Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + // Kernels to remove from list which we have now set a breakpoint at + for (auto iter = m_kernel_breakpoints.begin(); iter != m_kernel_breakpoints.end(); ++iter) + { + Error err; + BreakpointSP bp; + + if (iter->second != nullptr) // Breakpoint already set on kernel + continue; + + bool kernel_bp_set = ResolveKernelBreakpoint(iter->first, module_desc, err, bp); + + if (kernel_bp_set) + iter->second = bp; + + if (log && !err.Success()) + log->Printf ("RenderScriptRuntime::CheckModuleForPendingBreakpoints - Error '%s'", + err.AsCString()); + } +} + +void RenderScriptRuntime::DumpModules(Stream &strm) const { strm.Printf("RenderScript Modules:"); @@ -1031,18 +1156,18 @@ } }; -class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectParsed +class CommandObjectRenderScriptRuntimeKernelBreakpointSet : public CommandObjectParsed { private: public: - CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript kernel breakpoint", - "Sets a breakpoint on a renderscript kernel.", "renderscript kernel breakpoint", + CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript kernel breakpoint set", + "Set a breakpoint on a renderscript kernel.", "renderscript kernel breakpoint set <kernel name>", eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { } - ~CommandObjectRenderScriptRuntimeKernelBreakpoint() {} + ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() {} bool DoExecute(Args &command, CommandReturnObject &result) @@ -1051,7 +1176,7 @@ if (argc == 1) { RenderScriptRuntime *runtime = - (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); + static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); Error error; runtime->AttemptBreakpointAtKernelName(result.GetOutputStream(), command.GetArgumentAtIndex(0), error); @@ -1073,6 +1198,84 @@ } }; +class CommandObjectRenderScriptRuntimeKernelBreakpointList : public CommandObjectParsed +{ + private: + public: + CommandObjectRenderScriptRuntimeKernelBreakpointList(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript kernel breakpoint list", + "List all renderscript kernel breakpoints.", "renderscript kernel breakpoint list", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) + { + } + + ~CommandObjectRenderScriptRuntimeKernelBreakpointList() {} + + bool + DoExecute(Args &command, CommandReturnObject &result) + { + RenderScriptRuntime *runtime = + static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); + + runtime->DumpBreakpoints(result.GetOutputStream()); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } +}; + +class CommandObjectRenderScriptRuntimeKernelBreakpointDelete : public CommandObjectParsed +{ + private: + public: + CommandObjectRenderScriptRuntimeKernelBreakpointDelete(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript kernel breakpoint delete", + "Remove renderscript kernel breakpoint.", "renderscript kernel breakpoint delete <kernel_name>", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) + { + } + + ~CommandObjectRenderScriptRuntimeKernelBreakpointDelete() {} + + bool + DoExecute(Args &command, CommandReturnObject &result) + { + const size_t argc = command.GetArgumentCount(); + if (argc == 1) + { + RenderScriptRuntime *runtime = + static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); + + runtime->DeleteBreakpoint(result.GetOutputStream(), command.GetArgumentAtIndex(0)); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + + result.AppendErrorWithFormat("'%s' takes 1 argument of kernel name", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } +}; + +class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectMultiword +{ + private: + public: + CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "renderscript kernel breakpoint", + "Commands for managing renderscript kernel breakpoints.", + NULL) + { + LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointList(interpreter))); + LoadSubCommand("set", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(interpreter))); + LoadSubCommand("delete", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointDelete(interpreter))); + } + + ~CommandObjectRenderScriptRuntimeKernelBreakpoint() {} +}; + + class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword { private:
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits