diff options
Diffstat (limited to 'simpleperf/JITDebugReader.h')
-rw-r--r-- | simpleperf/JITDebugReader.h | 121 |
1 files changed, 69 insertions, 52 deletions
diff --git a/simpleperf/JITDebugReader.h b/simpleperf/JITDebugReader.h index b9e984d5..4483ddf0 100644 --- a/simpleperf/JITDebugReader.h +++ b/simpleperf/JITDebugReader.h @@ -38,6 +38,52 @@ namespace simpleperf { inline constexpr const char* kJITAppCacheFile = "jit_app_cache"; inline constexpr const char* kJITZygoteCacheFile = "jit_zygote_cache"; +inline constexpr const char* kDexFileInMemoryPrefix = "dexfile_in_memory"; + +namespace JITDebugReader_impl { + +enum class DescriptorType { + kDEX, + kJIT, +}; + +// An arch-independent representation of JIT/dex debug descriptor. +struct Descriptor { + DescriptorType type; + int version = 0; + uint32_t action_seqlock = 0; // incremented before and after any modification + uint64_t action_timestamp = 0; // CLOCK_MONOTONIC time of last action + uint64_t first_entry_addr = 0; +}; + +// An arch-independent representation of JIT/dex code entry. +struct CodeEntry { + uint64_t addr; + uint64_t symfile_addr; + uint64_t symfile_size; + uint64_t timestamp; // CLOCK_MONOTONIC time of last action +}; + +struct Process { + pid_t pid = -1; + bool initialized = false; + bool died = false; + bool is_64bit = false; + // remote addr of jit descriptor + uint64_t jit_descriptor_addr = 0; + // remote addr of dex descriptor + uint64_t dex_descriptor_addr = 0; + + // The state we know about the remote jit debug descriptor. + Descriptor last_jit_descriptor; + // The state we know about the remote dex debug descriptor. + Descriptor last_dex_descriptor; + + // memory space for /memfd:jit-zygote-cache + std::vector<std::pair<uint64_t, uint64_t>> jit_zygote_cache_ranges_; +}; + +} // namespace JITDebugReader_impl // JITDebugInfo represents the debug info of a JITed Java method or a dex file. struct JITDebugInfo { @@ -47,6 +93,7 @@ struct JITDebugInfo { } type; pid_t pid; // Process of the debug info uint64_t timestamp; // Monotonic timestamp for the creation of the debug info + union { struct { uint64_t jit_code_addr; // The start addr of the JITed code @@ -59,10 +106,13 @@ struct JITDebugInfo { std::string file_path; uint64_t file_offset; - // The map for dex file extracted in memory. On Android Q, ART extracts dex files in apk files - // directly into memory, and names it using prctl(). The kernel doesn't generate a new mmap - // record for it. So we need to dump it manually. - std::shared_ptr<ThreadMmap> extracted_dex_file_map; + // dex_file_map may be a dex file extracted in memory. On Android >= Q, ART may extract dex files + // in apk files directly into memory, and name it using prctl(). The kernel doesn't generate a + // new mmap record for it. So we need to dump it manually. + // Or dex_file_map may be a dex file created in memory. In that case, symbols are read from the + // dex file. + std::shared_ptr<ThreadMmap> dex_file_map; + std::vector<Symbol> symbols; JITDebugInfo(pid_t pid, uint64_t timestamp, uint64_t jit_code_addr, uint64_t jit_code_len, const std::string& file_path, uint64_t file_offset) @@ -75,15 +125,16 @@ struct JITDebugInfo { file_offset(file_offset) {} JITDebugInfo(pid_t pid, uint64_t timestamp, uint64_t dex_file_offset, - const std::string& file_path, - const std::shared_ptr<ThreadMmap>& extracted_dex_file_map) + const std::string& file_path, const std::shared_ptr<ThreadMmap>& dex_file_map, + std::vector<Symbol> symbols) : type(JIT_DEBUG_DEX_FILE), pid(pid), timestamp(timestamp), dex_file_offset(dex_file_offset), file_path(file_path), file_offset(0), - extracted_dex_file_map(extracted_dex_file_map) {} + dex_file_map(dex_file_map), + symbols(std::move(symbols)) {} bool operator>(const JITDebugInfo& other) const { return timestamp > other.timestamp; } }; @@ -94,6 +145,10 @@ class TempSymFile; // corresponding debug interface in ART is at art/runtime/jit/debugger_interface.cc. class JITDebugReader { public: + using Descriptor = JITDebugReader_impl::Descriptor; + using CodeEntry = JITDebugReader_impl::CodeEntry; + using Process = JITDebugReader_impl::Process; + enum class SymFileOption { kDropSymFiles, // JIT symfiles are dropped after recording. kKeepSymFiles, // JIT symfiles are kept after recording, usually for debug unwinding. @@ -113,7 +168,7 @@ class JITDebugReader { bool SyncWithRecords() const { return sync_option_ == SyncOption::kSyncWithRecords; } - typedef std::function<bool(const std::vector<JITDebugInfo>&, bool)> debug_info_callback_t; + typedef std::function<bool(std::vector<JITDebugInfo>, bool)> debug_info_callback_t; bool RegisterDebugInfoCallback(IOEventLoop* loop, const debug_info_callback_t& callback); // There are two ways to select which processes to monitor. One is using MonitorProcess(), the @@ -134,48 +189,11 @@ class JITDebugReader { path.find(std::string("_") + kJITZygoteCacheFile + ":") != path.npos; } - private: - enum class DescriptorType { - kDEX, - kJIT, - }; - - // An arch-independent representation of JIT/dex debug descriptor. - struct Descriptor { - DescriptorType type; - int version = 0; - uint32_t action_seqlock = 0; // incremented before and after any modification - uint64_t action_timestamp = 0; // CLOCK_MONOTONIC time of last action - uint64_t first_entry_addr = 0; - }; - - // An arch-independent representation of JIT/dex code entry. - struct CodeEntry { - uint64_t addr; - uint64_t symfile_addr; - uint64_t symfile_size; - uint64_t timestamp; // CLOCK_MONOTONIC time of last action - }; - - struct Process { - pid_t pid = -1; - bool initialized = false; - bool died = false; - bool is_64bit = false; - // remote addr of jit descriptor - uint64_t jit_descriptor_addr = 0; - // remote addr of dex descriptor - uint64_t dex_descriptor_addr = 0; - - // The state we know about the remote jit debug descriptor. - Descriptor last_jit_descriptor; - // The state we know about the remote dex debug descriptor. - Descriptor last_dex_descriptor; - - // memory space for /memfd:jit-zygote-cache - std::vector<std::pair<uint64_t, uint64_t>> jit_zygote_cache_ranges_; - }; + // exported for testing + void ReadDexFileDebugInfo(Process& process, const std::vector<CodeEntry>& dex_entries, + std::vector<JITDebugInfo>* debug_info); + private: // The location of descriptors in libart.so. struct DescriptorsLocation { bool is_64bit = false; @@ -208,9 +226,8 @@ class JITDebugReader { bool ReadJITCodeDebugInfo(Process& process, const std::vector<CodeEntry>& jit_entries, std::vector<JITDebugInfo>* debug_info); TempSymFile* GetTempSymFile(Process& process, const CodeEntry& jit_entry); - void ReadDexFileDebugInfo(Process& process, const std::vector<CodeEntry>& dex_entries, - std::vector<JITDebugInfo>* debug_info); - bool AddDebugInfo(const std::vector<JITDebugInfo>& debug_info, bool sync_kernel_records); + std::vector<Symbol> ReadDexFileSymbolsInMemory(Process& process, uint64_t addr, uint64_t size); + bool AddDebugInfo(std::vector<JITDebugInfo> debug_info, bool sync_kernel_records); const std::string symfile_prefix_; SymFileOption symfile_option_; |