Author: ldrumm Date: Wed Oct 5 14:10:47 2016 New Revision: 283362 URL: http://llvm.org/viewvc/llvm-project?rev=283362&view=rev Log: Add the ability to set breakpoints on named RenderScript reductions
- Add new `lldb_private::lldb_renderscript::RSReduceBreakpointResolver` class that can set breakpoints on kernels that are constituent functions of named reduction groups. Also support debugging of subsets of the the reduction group with the `-t, --function-role` flag which takes a comma-separated list of reduction function types outconverter,combiner,initializer,accumulator (defaults to all) - Add 2 new helper methods to `RenderScriptRuntime`, 1. `CreateReductionBreakpoint(name, types)`: instantiates a new RSReduceBreakpointResolver and inserts that resolver into the running process. 2. `PlaceBreakpointOnReduction`: which is a public helper function. - hook up the above functionality to the command-line with new `CommandObject*` classes that handle parsing of function roles and dispatch to the runtime. These are namespaced under the snappy `language renderscript reduction breakpoint ...` subcommand - [incidental] Factor multiple common uses of `FindFirstSymbolWithNameAndType(ConstString(".rs.info")` into static `IsRenderScriptScriptModule(ModuleSP module)` function, and replace original uses. Modified: lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h Modified: lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp?rev=283362&r1=283361&r2=283362&view=diff ============================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp (original) +++ lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp Wed Oct 5 14:10:47 2016 @@ -10,7 +10,7 @@ // C Includes // C++ Includes // Other libraries and framework includes -#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSwitch.h" // Project includes #include "RenderScriptRuntime.h" @@ -432,6 +432,13 @@ bool GetArgs(ExecutionContext &exe_ctx, } } +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 @@ -781,13 +788,7 @@ RSBreakpointResolver::SearchCallback(Sea SymbolContext &context, Address *, bool) { ModuleSP module = context.module_sp; - if (!module) - return Searcher::eCallbackReturnContinue; - - // Is this a module containing renderscript kernels? - if (nullptr == - module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), - eSymbolTypeData)) + if (!module || !IsRenderScriptScriptModule(module)) return Searcher::eCallbackReturnContinue; // Attempt to set a breakpoint on the kernel name symbol within the module @@ -811,6 +812,66 @@ RSBreakpointResolver::SearchCallback(Sea return Searcher::eCallbackReturnContinue; } +Searcher::CallbackReturn +RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, + lldb_private::SymbolContext &context, + Address *, bool) { + // 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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_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<std::pair<ConstString, int>, 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; + m_breakpoint->AddLocation(address, &new_bp); + if (log) + log->Printf("%s: %s reduction breakpoint on %s in %s", __FUNCTION__, + new_bp ? "new" : "existing", kernel_name.GetCString(), + address.GetModule()->GetFileSpec().GetCString()); + } + } + } + } + return eCallbackReturnContinue; +} + void RenderScriptRuntime::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), "RenderScript language support", CreateInstance, @@ -829,12 +890,8 @@ lldb_private::ConstString RenderScriptRu RenderScriptRuntime::ModuleKind RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) { if (module_sp) { - // Is this a module containing renderscript kernels? - const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType( - ConstString(".rs.info"), eSymbolTypeData); - if (info_sym) { + if (IsRenderScriptScriptModule(module_sp)) return eModuleKindKernelObj; - } // Is this the main RS runtime library const ConstString rs_lib("libRS.so"); @@ -2722,17 +2779,21 @@ bool RSModuleDescriptor::ParseRSInfo() { eObjectSlot }; - static const llvm::StringMap<int> rs_info_handlers{ - {// The number of visible global variables in the script - {"exportVarCount", eExportVar}, - // The number of RenderScrip `forEach` kernels __attribute__((kernel)) - {"exportForEachCount", eExportForEach}, - // The number of generalreductions: This marked in the script by `#pragma - // reduce()` - {"exportReduceCount", eExportReduce}, - // Total count of all RenderScript specific `#pragmas` used in the script - {"pragmaCount", ePragma}, - {"objectSlotCount", eObjectSlot}}}; + const auto rs_info_handler = [](llvm::StringRef name) -> int { + return llvm::StringSwitch<int>(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) + .Default(-1); + }; // parse all text lines of .rs.info for (auto line = info_lines.begin(); line != info_lines.end(); ++line) { @@ -2740,12 +2801,11 @@ bool RSModuleDescriptor::ParseRSInfo() { const auto key = kv_pair.first; const auto val = kv_pair.second.trim(); - const auto handler = rs_info_handlers.find(key); - if (handler == rs_info_handlers.end()) + 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 + // in numeric fields at the moment uint64_t n_lines; if (val.getAsInteger(10, n_lines)) { if (log) @@ -2757,7 +2817,7 @@ bool RSModuleDescriptor::ParseRSInfo() { return false; bool success = false; - switch (handler->getValue()) { + switch (handler) { case eExportVar: success = ParseExportVarCount(line, n_lines); break; @@ -3225,9 +3285,38 @@ RenderScriptRuntime::CreateKernelBreakpo // Give RS breakpoints a specific name, so the user can manipulate them as a // group. Error err; - if (!bp->AddName("RenderScriptKernel", err) && log) - log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, - err.AsCString()); + if (!bp->AddName("RenderScriptKernel", err)) + if (log) + log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, + err.AsCString()); + + return bp; +} + +BreakpointSP +RenderScriptRuntime::CreateReductionBreakpoint(const ConstString &name, + int kernel_types) { + 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 RSReduceBreakpointResolver( + nullptr, name, &m_rsmodules, kernel_types)); + 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("RenderScriptReduction", err)) + if (log) + log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, + err.AsCString()); return bp; } @@ -3446,6 +3535,28 @@ bool RenderScriptRuntime::PlaceBreakpoin return true; } +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(); @@ -3666,6 +3777,164 @@ public: } }; +static OptionDefinition g_renderscript_reduction_bp_set_options[] = { + {LLDB_OPT_SET_1, false, "function-role", 't', + OptionParser::eRequiredArgument, nullptr, 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, 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 <kernel_name> [-t " + "<reduction_kernel_type,...>]", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused), + m_options(){}; + + class CommandOptions : public Options { + public: + CommandOptions() + : Options(), + m_kernel_types(RSReduceBreakpointResolver::eKernelTypeAll) {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, const char *option_val, + ExecutionContext *exe_ctx) override { + Error err; + StreamString err_str; + const int short_option = m_getopt_table[option_idx].val; + switch (short_option) { + case 't': + if (!ParseReductionTypes(option_val, err_str)) + err.SetErrorStringWithFormat( + "Unable to deduce reduction types for %s: %s", option_val, + err_str.GetData()); + break; + case 'c': { + auto coord = RSCoordinate{}; + if (!ParseCoordinate(option_val, coord)) + err.SetErrorStringWithFormat("unable to parse coordinate for %s", + option_val); + 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<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_renderscript_reduction_bp_set_options); + } + + bool ParseReductionTypes(const char *option_val, StreamString &err_str) { + m_kernel_types = RSReduceBreakpointResolver::eKernelTypeNone; + const auto reduce_name_to_type = [](llvm::StringRef name) -> int { + return llvm::StringSwitch<int>(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 match(/* max_matches */ 5); + RegularExpression match_type_list( + llvm::StringRef("^([[:alpha:]]+)(,[[:alpha:]]+){0,4}$")); + + assert(match_type_list.IsValid()); + + if (!match_type_list.Execute(llvm::StringRef(option_val), &match)) { + 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<llvm::StringRef, 5> 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; + llvm::StringRef m_reduce_name; + RSCoordinate m_coord; + bool m_have_coord; + }; + + 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()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( + 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.SetStatus(eReturnStatusFailed); + 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 OptionDefinition g_renderscript_kernel_bp_set_options[] = { {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, @@ -3699,7 +3968,7 @@ public: ~CommandOptions() override = default; Error SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) override { + ExecutionContext *exe_ctx) override { Error err; const int short_option = m_getopt_table[option_idx].val; @@ -3723,7 +3992,7 @@ public: return err; } - void OptionParsingStarting(ExecutionContext *execution_context) override { + void OptionParsingStarting(ExecutionContext *exe_ctx) override { m_have_coord = false; } @@ -3822,6 +4091,24 @@ public: } }; +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: @@ -3962,7 +4249,7 @@ public: ~CommandOptions() override = default; Error SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) override { + ExecutionContext *exe_ctx) override { Error err; const int short_option = m_getopt_table[option_idx].val; @@ -3981,7 +4268,7 @@ public: return err; } - void OptionParsingStarting(ExecutionContext *execution_context) override { + void OptionParsingStarting(ExecutionContext *exe_ctx) override { m_outfile.Clear(); } @@ -4083,7 +4370,7 @@ public: ~CommandOptions() override = default; Error SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) override { + ExecutionContext *exe_ctx) override { Error err; const int short_option = m_getopt_table[option_idx].val; @@ -4102,9 +4389,7 @@ public: return err; } - void OptionParsingStarting(ExecutionContext *execution_context) override { - m_id = 0; - } + void OptionParsingStarting(ExecutionContext *exe_ctx) override { m_id = 0; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { return llvm::makeArrayRef(g_renderscript_runtime_alloc_list_options); @@ -4313,6 +4598,21 @@ public: } }; +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) @@ -4336,6 +4636,10 @@ public: "allocation", CommandObjectSP( new CommandObjectRenderScriptRuntimeAllocation(interpreter))); + LoadSubCommand( + "reduction", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeReduction(interpreter))); } ~CommandObjectRenderScriptRuntime() override = default; Modified: lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h?rev=283362&r1=283361&r2=283362&view=diff ============================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h (original) +++ lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h Wed Oct 5 14:10:47 2016 @@ -84,6 +84,58 @@ 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( + Breakpoint *breakpoint, ConstString reduce_name, + std::vector<lldb_renderscript::RSModuleDescriptorSP> *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, + bool containing) override; + + Searcher::Depth GetDepth() override { return Searcher::eDepthModule; } + + lldb::BreakpointResolverSP + CopyForBreakpoint(Breakpoint &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<lldb_renderscript::RSModuleDescriptorSP> *m_rsmodules; + int m_kernel_types; +}; + struct RSKernelDescriptor { public: RSKernelDescriptor(const RSModuleDescriptor *module, llvm::StringRef name, @@ -247,6 +299,11 @@ public: 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)); + void SetBreakAllKernels(bool do_break, lldb::TargetSP target); void Status(Stream &strm) const; @@ -294,6 +351,9 @@ protected: lldb::BreakpointSP CreateKernelBreakpoint(const ConstString &name); + lldb::BreakpointSP CreateReductionBreakpoint(const ConstString &name, + int kernel_types); + void BreakOnModuleKernels( const lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits