/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SIMPLE_PERF_THREAD_TREE_H_ #define SIMPLE_PERF_THREAD_TREE_H_ #include #include #include #include #include #include "dso.h" namespace simpleperf { struct Record; constexpr char DEFAULT_KERNEL_MMAP_NAME[] = "[kernel.kallsyms]"; constexpr char DEFAULT_EXECNAME_FOR_THREAD_MMAP[] = "//anon"; namespace map_flags { constexpr uint32_t PROT_JIT_SYMFILE_MAP = 0x4000; } // namespace map_flags struct MapEntry { uint64_t start_addr; uint64_t len; uint64_t pgoff; Dso* dso; bool in_kernel; uint32_t flags; MapEntry(uint64_t start_addr, uint64_t len, uint64_t pgoff, Dso* dso, bool in_kernel, uint32_t flags = 0) : start_addr(start_addr), len(len), pgoff(pgoff), dso(dso), in_kernel(in_kernel), flags(flags) {} MapEntry() {} uint64_t get_end_addr() const { return start_addr + len; } uint64_t Contains(uint64_t addr) const { return addr >= start_addr && addr < get_end_addr(); } uint64_t GetVaddrInFile(uint64_t addr) const { if (Contains(addr)) { return dso->IpToVaddrInFile(addr, start_addr, pgoff); } return 0; } }; struct MapSet { std::map maps; // Map from start_addr to a MapEntry. uint64_t version = 0u; // incremented each time changing maps const MapEntry* FindMapByAddr(uint64_t addr) const; }; struct ThreadEntry { int pid; int tid; const char* comm; // It always refers to the latest comm. std::shared_ptr maps; // maps is shared by threads in the same process. }; struct FileFeature; // ThreadTree contains thread information (in ThreadEntry) and mmap information // (in MapEntry) of the monitored threads. It also has interface to access // symbols in executable binaries mapped in the monitored threads. class ThreadTree { public: ThreadTree() : show_ip_for_unknown_symbol_(false), show_mark_for_unknown_symbol_(false), unknown_symbol_("unknown", 0, std::numeric_limits::max()) { unknown_dso_ = Dso::CreateDso(DSO_UNKNOWN_FILE, "unknown"); unknown_map_ = MapEntry(0, std::numeric_limits::max(), 0, unknown_dso_.get(), false); // We can't dump comm for pid 0 from /proc, so add it's name here. SetThreadName(0, 0, "swapper"); } virtual ~ThreadTree() {} void DisableThreadExitRecords() { disable_thread_exit_records_ = true; } void SetThreadName(int pid, int tid, const std::string& comm); bool ForkThread(int pid, int tid, int ppid, int ptid); virtual ThreadEntry* FindThread(int tid) const; ThreadEntry* FindThreadOrNew(int pid, int tid); void ExitThread(int pid, int tid); void AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff, const std::string& filename); const MapSet& GetKernelMaps() { return kernel_maps_; } void AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff, const std::string& filename, uint32_t flags = 0); // Add process symbols that do not correspond to any real dso. // For example, these might be symbols generated by a JIT. void AddSymbolsForProcess(int pid, std::vector* symbols); const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip, bool in_kernel); // Find map for an ip address when we don't know whether it is in kernel. const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip); const Symbol* FindSymbol(const MapEntry* map, uint64_t ip, uint64_t* pvaddr_in_file, Dso** pdso = nullptr); const Symbol* FindKernelSymbol(uint64_t ip); bool IsUnknownDso(const Dso* dso) const { return dso == unknown_dso_.get(); } const Symbol* UnknownSymbol() const { return &unknown_symbol_; } void ShowIpForUnknownSymbol() { show_ip_for_unknown_symbol_ = true; } void ShowMarkForUnknownSymbol() { show_mark_for_unknown_symbol_ = true; unknown_symbol_ = Symbol("*unknown", 0, ULLONG_MAX); } // Clear thread and map information, but keep loaded dso information. It saves // the time to reload dso information. void ClearThreadAndMap(); bool AddDsoInfo(FileFeature& file); void AddDexFileOffset(const std::string& file_path, uint64_t dex_file_offset); // Update thread tree with information provided by record. void Update(const Record& record); std::vector GetAllDsos() const; Dso* FindUserDsoOrNew(const std::string& filename, uint64_t start_addr = 0, DsoType dso_type = DSO_ELF_FILE); private: ThreadEntry* CreateThread(int pid, int tid); Dso* FindKernelDsoOrNew(); Dso* FindKernelModuleDsoOrNew(const std::string& filename, uint64_t memory_start, uint64_t memory_end); const MapEntry* AllocateMap(const MapEntry& entry); void InsertMap(MapSet& maps, const MapEntry& entry); // Add thread maps to cover symbols in dso. void AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso); std::unordered_map> thread_tree_; std::vector> thread_comm_storage_; MapSet kernel_maps_; std::vector> map_storage_; MapEntry unknown_map_; std::unique_ptr kernel_dso_; std::unordered_map> module_dso_tree_; std::unordered_map> user_dso_tree_; std::unique_ptr unknown_dso_; bool show_ip_for_unknown_symbol_; bool show_mark_for_unknown_symbol_; Symbol unknown_symbol_; bool disable_thread_exit_records_ = false; }; } // namespace simpleperf #endif // SIMPLE_PERF_THREAD_TREE_H_