/* * Copyright (C) 2018 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. */ #include "src/profiling/common/unwind_support.h" #include #include #include #include #include "perfetto/ext/base/file_utils.h" namespace perfetto { namespace profiling { StackOverlayMemory::StackOverlayMemory(std::shared_ptr mem, uint64_t sp, const uint8_t* stack, size_t size) : mem_(std::move(mem)), sp_(sp), stack_end_(sp + size), stack_(stack) {} size_t StackOverlayMemory::Read(uint64_t addr, void* dst, size_t size) { if (addr >= sp_ && addr + size <= stack_end_ && addr + size > sp_) { size_t offset = static_cast(addr - sp_); memcpy(dst, stack_ + offset, size); return size; } return mem_->Read(addr, dst, size); } FDMemory::FDMemory(base::ScopedFile mem_fd) : mem_fd_(std::move(mem_fd)) {} size_t FDMemory::Read(uint64_t addr, void* dst, size_t size) { ssize_t rd = pread64(*mem_fd_, dst, size, static_cast(addr)); if (PERFETTO_UNLIKELY(rd == -1)) { PERFETTO_PLOG("Failed remote pread of %zu bytes at address %" PRIx64, size, addr); return 0; } return static_cast(rd); } FDMaps::FDMaps(base::ScopedFile fd) : fd_(std::move(fd)) {} bool FDMaps::Parse() { // If the process has already exited, lseek or ReadFileDescriptor will // return false. if (lseek(*fd_, 0, SEEK_SET) == -1) return false; std::string content; if (!base::ReadFileDescriptor(*fd_, &content)) return false; unwindstack::SharedString name(""); unwindstack::MapInfo* prev_map = nullptr; unwindstack::MapInfo* prev_real_map = nullptr; return android::procinfo::ReadMapFileContent( &content[0], [&](const android::procinfo::MapInfo& mapinfo) { // Mark a device map in /dev/ and not in /dev/ashmem/ specially. auto flags = mapinfo.flags; if (strncmp(mapinfo.name.c_str(), "/dev/", 5) == 0 && strncmp(mapinfo.name.c_str() + 5, "ashmem/", 7) != 0) { flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP; } // Share the string if it matches for consecutive maps. if (name != mapinfo.name) { name = unwindstack::SharedString(mapinfo.name); } maps_.emplace_back(new unwindstack::MapInfo( prev_map, prev_real_map, mapinfo.start, mapinfo.end, mapinfo.pgoff, flags, name)); prev_map = maps_.back().get(); if (!prev_map->IsBlank()) { prev_real_map = prev_map; } }); } void FDMaps::Reset() { maps_.clear(); } UnwindingMetadata::UnwindingMetadata(base::ScopedFile maps_fd, base::ScopedFile mem_fd) : fd_maps(std::move(maps_fd)), fd_mem(std::make_shared(std::move(mem_fd))) { if (!fd_maps.Parse()) PERFETTO_DLOG("Failed initial maps parse"); } void UnwindingMetadata::ReparseMaps() { reparses++; fd_maps.Reset(); fd_maps.Parse(); #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) jit_debug.reset(); dex_files.reset(); #endif } #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) unwindstack::JitDebug* UnwindingMetadata::GetJitDebug(unwindstack::ArchEnum arch) { if (jit_debug.get() == nullptr) { std::vector search_libs{"libart.so", "libartd.so"}; jit_debug = unwindstack::CreateJitDebug(arch, fd_mem, search_libs); } return jit_debug.get(); } unwindstack::DexFiles* UnwindingMetadata::GetDexFiles(unwindstack::ArchEnum arch) { if (dex_files.get() == nullptr) { std::vector search_libs{"libart.so", "libartd.so"}; dex_files = unwindstack::CreateDexFiles(arch, fd_mem, search_libs); } return dex_files.get(); } #endif const std::string& UnwindingMetadata::GetBuildId( const unwindstack::FrameData& frame) { if (!frame.map_name.empty()) { unwindstack::MapInfo* map_info = fd_maps.Find(frame.pc); if (map_info) return map_info->GetBuildID(); } return empty_string_; } std::string StringifyLibUnwindstackError(unwindstack::ErrorCode e) { switch (e) { case unwindstack::ERROR_NONE: return "NONE"; case unwindstack::ERROR_MEMORY_INVALID: return "MEMORY_INVALID"; case unwindstack::ERROR_UNWIND_INFO: return "UNWIND_INFO"; case unwindstack::ERROR_UNSUPPORTED: return "UNSUPPORTED"; case unwindstack::ERROR_INVALID_MAP: return "INVALID_MAP"; case unwindstack::ERROR_MAX_FRAMES_EXCEEDED: return "MAX_FRAME_EXCEEDED"; case unwindstack::ERROR_REPEATED_FRAME: return "REPEATED_FRAME"; case unwindstack::ERROR_INVALID_ELF: return "INVALID_ELF"; case unwindstack::ERROR_SYSTEM_CALL: return "SYSTEM_CALL"; case unwindstack::ERROR_THREAD_DOES_NOT_EXIST: return "THREAD_DOES_NOT_EXIST"; case unwindstack::ERROR_THREAD_TIMEOUT: return "THREAD_TIMEOUT"; } } } // namespace profiling } // namespace perfetto