Index: lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h =================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -150,8 +150,7 @@ eModuleKindKernelObj }; - - ~RenderScriptRuntime() {} + ~RenderScriptRuntime(); //------------------------------------------------------------------ // Static Functions @@ -253,20 +252,16 @@ typedef std::shared_ptr RuntimeHookSP; - struct ScriptDetails - { - std::string resname; - std::string scriptDyLib; - std::string cachedir; - lldb::addr_t context; - lldb::addr_t script; - }; + struct ScriptDetails; + struct AllocationDetails; lldb::ModuleSP m_libRS; lldb::ModuleSP m_libRSDriver; lldb::ModuleSP m_libRSCpuRef; std::vector m_rsmodules; - std::vector m_scripts; + + std::vector> m_scripts; + std::vector> m_allocations; std::map m_scriptMappings; std::map m_runtimeHooks; @@ -293,6 +288,17 @@ void CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context); void CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context); + // 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. + // If 'create' is true and there is no previous allocation then a new allocation + // detail object will be created for this address and returned. + AllocationDetails* LookUpAllocation(lldb::addr_t address, bool create); }; } // namespace lldb_private Index: lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp =================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -32,6 +32,126 @@ using namespace lldb_private; using namespace lldb_renderscript; +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() + : valid(false) + {} + + // 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; + type_t data; +}; + +} // namespace {} + +// The ScriptDetails class collects data associated with a single script instance. +struct RenderScriptRuntime::ScriptDetails +{ + ~ScriptDetails() {}; + + enum ScriptType + { + eScript, + eScriptC + }; + + // The derived type of the script. + empirical_type type; + // The name of the original source file. + empirical_type resName; + // Path to script .so file on the device. + empirical_type scriptDyLib; + // Directory where kernel objects are cached on device. + empirical_type cacheDir; + // Pointer to the context which owns this script. + empirical_type context; + // Pointer to the script object itself. + empirical_type script; +}; + +// This AllocationDetails class collects data associated with a single +// allocation instance. +struct RenderScriptRuntime::AllocationDetails +{ + ~AllocationDetails () {}; + + enum DataType + { + eInt, + }; + + enum Dimension + { + e1d, + e2d, + e3d, + eCubeMap, + }; + + empirical_type type; + empirical_type dimension; + empirical_type address; + empirical_type dataPtr; + empirical_type context; +}; + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ @@ -484,6 +604,10 @@ if (log) log->Printf ("RenderScriptRuntime::CaptureAllocationInit1 - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", rs_context_u64, rs_alloc_u64, rs_forceZero_u64); + + AllocationDetails* alloc = LookUpAllocation(rs_alloc_u64, true); + if (alloc) + alloc->context = rs_context_u64; } void @@ -541,14 +665,15 @@ StreamString strm; strm.Printf("librs.%s.so", resname.c_str()); - ScriptDetails script; - script.cachedir = cachedir; - script.resname = resname; - script.scriptDyLib.assign(strm.GetData()); - script.script = (addr_t) rs_script_u64; - script.context = (addr_t) rs_context_u64; - - m_scripts.push_back(script); + ScriptDetails* script = LookUpScript(rs_script_u64, true); + if (script) + { + script->type = ScriptDetails::eScriptC; + script->cacheDir = cachedir; + script->resName = resname; + script->scriptDyLib = strm.GetData(); + script->context = addr_t(rs_context_u64); + } if (log) log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - '%s' tagged with context 0x%" PRIx64 " and script 0x%" PRIx64 ".", @@ -561,7 +686,6 @@ } - void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind) { @@ -642,35 +766,51 @@ const ModuleSP module = rsmodule_sp->m_module; const FileSpec& file = module->GetPlatformFileSpec(); - - for (const auto &rs_script : m_scripts) - { - if (file.GetFilename() == ConstString(rs_script.scriptDyLib.c_str())) + + // 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 dylib; + if (!rs_script->scriptDyLib.get(dylib)) + continue; + + // Only proceed if the module that has loaded corresponds to this script. + if (file.GetFilename() != ConstString(dylib.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 (m_scriptMappings.find( rs_script.script ) != m_scriptMappings.end()) - { - if (m_scriptMappings[rs_script.script] != rsmodule_sp) - { - if (log) - { - log->Printf ("RenderScriptRuntime::FixupScriptDetails - Error: script %" PRIx64 " wants reassigned to new rsmodule '%s'.", - (uint64_t)rs_script.script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); - } - } - } - else + // if the module we have stored is different to the one we just received. + if (m_scriptMappings[script] != rsmodule_sp) { - m_scriptMappings[rs_script.script] = rsmodule_sp; - rsmodule_sp->m_resname = rs_script.resname; if (log) - { - log->Printf ("RenderScriptRuntime::FixupScriptDetails - script %" PRIx64 " associated with rsmodule '%s'.", - (uint64_t)rs_script.script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); - } + log->Printf ("RenderScriptRuntime::FixupScriptDetails - Error: script %" PRIx64 " wants reassigned to new rsmodule '%s'.", + (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 resName; + if (rs_script->resName.get(resName)) + // Set the modules resource name. + rsmodule_sp->m_resname = resName; + // Add Script/Module pair to map. + m_scriptMappings[script] = rsmodule_sp; + if (log) + log->Printf ("RenderScriptRuntime::FixupScriptDetails - script %" PRIx64 " associated with rsmodule '%s'.", + (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); + } } - } bool @@ -922,15 +1062,21 @@ std::map contextReferences; - for (const auto &script : m_scripts) + // 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 (contextReferences.find(script.context) != contextReferences.end()) + if (!script->context.isValid()) + continue; + lldb::addr_t context = *script->context; + + if (contextReferences.find(context) != contextReferences.end()) { - contextReferences[script.context]++; + contextReferences[context]++; } else { - contextReferences[script.context] = 1; + contextReferences[context] = 1; } } @@ -1065,6 +1211,44 @@ 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 s.get(); + } + return nullptr; +} + +RenderScriptRuntime::AllocationDetails* +RenderScriptRuntime::LookUpAllocation(addr_t address, bool create) +{ + for (const auto & a : m_allocations) + { + if (a->address.isValid()) + if (*a->address == address) + return a.get(); + } + if (create) + { + std::unique_ptr a(new AllocationDetails); + a->address = address; + m_allocations.push_back(std::move(a)); + return a.get(); + } + return nullptr; +} + void RSModuleDescriptor::Dump(Stream &strm) const { @@ -1482,3 +1666,4 @@ return command_object; } +RenderScriptRuntime::~RenderScriptRuntime() = default;