• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/profiling/common/unwind_support.h"
18 
19 #include <cinttypes>
20 
21 #include <procinfo/process_map.h>
22 #include <unwindstack/Maps.h>
23 #include <unwindstack/Memory.h>
24 
25 #include "perfetto/ext/base/file_utils.h"
26 
27 namespace perfetto {
28 namespace profiling {
29 
StackOverlayMemory(std::shared_ptr<unwindstack::Memory> mem,uint64_t sp,const uint8_t * stack,size_t size)30 StackOverlayMemory::StackOverlayMemory(std::shared_ptr<unwindstack::Memory> mem,
31                                        uint64_t sp,
32                                        const uint8_t* stack,
33                                        size_t size)
34     : mem_(std::move(mem)), sp_(sp), stack_end_(sp + size), stack_(stack) {}
35 
Read(uint64_t addr,void * dst,size_t size)36 size_t StackOverlayMemory::Read(uint64_t addr, void* dst, size_t size) {
37   if (addr >= sp_ && addr + size <= stack_end_ && addr + size > sp_) {
38     size_t offset = static_cast<size_t>(addr - sp_);
39     memcpy(dst, stack_ + offset, size);
40     return size;
41   }
42 
43   return mem_->Read(addr, dst, size);
44 }
45 
FDMemory(base::ScopedFile mem_fd)46 FDMemory::FDMemory(base::ScopedFile mem_fd) : mem_fd_(std::move(mem_fd)) {}
47 
Read(uint64_t addr,void * dst,size_t size)48 size_t FDMemory::Read(uint64_t addr, void* dst, size_t size) {
49   ssize_t rd = pread64(*mem_fd_, dst, size, static_cast<off64_t>(addr));
50   if (PERFETTO_UNLIKELY(rd == -1)) {
51     PERFETTO_PLOG("Failed remote pread of %zu bytes at address %" PRIx64, size,
52                   addr);
53     return 0;
54   }
55   return static_cast<size_t>(rd);
56 }
57 
FDMaps(base::ScopedFile fd)58 FDMaps::FDMaps(base::ScopedFile fd) : fd_(std::move(fd)) {}
59 
Parse()60 bool FDMaps::Parse() {
61   // If the process has already exited, lseek or ReadFileDescriptor will
62   // return false.
63   if (lseek(*fd_, 0, SEEK_SET) == -1)
64     return false;
65 
66   std::string content;
67   if (!base::ReadFileDescriptor(*fd_, &content))
68     return false;
69 
70   unwindstack::SharedString name("");
71   std::shared_ptr<unwindstack::MapInfo> prev_map;
72   return android::procinfo::ReadMapFileContent(
73       &content[0], [&](const android::procinfo::MapInfo& mapinfo) {
74         // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
75         auto flags = mapinfo.flags;
76         if (strncmp(mapinfo.name.c_str(), "/dev/", 5) == 0 &&
77             strncmp(mapinfo.name.c_str() + 5, "ashmem/", 7) != 0) {
78           flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
79         }
80         // Share the string if it matches for consecutive maps.
81         if (name != mapinfo.name) {
82           name = unwindstack::SharedString(mapinfo.name);
83         }
84         maps_.emplace_back(unwindstack::MapInfo::Create(
85             prev_map, mapinfo.start, mapinfo.end, mapinfo.pgoff, flags, name));
86         prev_map = maps_.back();
87       });
88 }
89 
Reset()90 void FDMaps::Reset() {
91   maps_.clear();
92 }
93 
UnwindingMetadata(base::ScopedFile maps_fd,base::ScopedFile mem_fd)94 UnwindingMetadata::UnwindingMetadata(base::ScopedFile maps_fd,
95                                      base::ScopedFile mem_fd)
96     : fd_maps(std::move(maps_fd)),
97       fd_mem(std::make_shared<FDMemory>(std::move(mem_fd))) {
98   if (!fd_maps.Parse())
99     PERFETTO_DLOG("Failed initial maps parse");
100 }
101 
ReparseMaps()102 void UnwindingMetadata::ReparseMaps() {
103   reparses++;
104   fd_maps.Reset();
105   fd_maps.Parse();
106 #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
107   jit_debug.reset();
108   dex_files.reset();
109 #endif
110 }
111 
112 #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
GetJitDebug(unwindstack::ArchEnum arch)113 unwindstack::JitDebug* UnwindingMetadata::GetJitDebug(
114     unwindstack::ArchEnum arch) {
115   if (jit_debug.get() == nullptr) {
116     std::vector<std::string> search_libs{"libart.so", "libartd.so"};
117     jit_debug = unwindstack::CreateJitDebug(arch, fd_mem, search_libs);
118   }
119   return jit_debug.get();
120 }
121 
GetDexFiles(unwindstack::ArchEnum arch)122 unwindstack::DexFiles* UnwindingMetadata::GetDexFiles(
123     unwindstack::ArchEnum arch) {
124   if (dex_files.get() == nullptr) {
125     std::vector<std::string> search_libs{"libart.so", "libartd.so"};
126     dex_files = unwindstack::CreateDexFiles(arch, fd_mem, search_libs);
127   }
128   return dex_files.get();
129 }
130 #endif
131 
GetBuildId(const unwindstack::FrameData & frame)132 const std::string& UnwindingMetadata::GetBuildId(
133     const unwindstack::FrameData& frame) {
134   if (frame.map_info != nullptr && !frame.map_info->name().empty()) {
135     return frame.map_info->GetBuildID();
136   }
137 
138   return empty_string_;
139 }
140 
StringifyLibUnwindstackError(unwindstack::ErrorCode e)141 std::string StringifyLibUnwindstackError(unwindstack::ErrorCode e) {
142   switch (e) {
143     case unwindstack::ERROR_NONE:
144       return "NONE";
145     case unwindstack::ERROR_MEMORY_INVALID:
146       return "MEMORY_INVALID";
147     case unwindstack::ERROR_UNWIND_INFO:
148       return "UNWIND_INFO";
149     case unwindstack::ERROR_UNSUPPORTED:
150       return "UNSUPPORTED";
151     case unwindstack::ERROR_INVALID_MAP:
152       return "INVALID_MAP";
153     case unwindstack::ERROR_MAX_FRAMES_EXCEEDED:
154       return "MAX_FRAME_EXCEEDED";
155     case unwindstack::ERROR_REPEATED_FRAME:
156       return "REPEATED_FRAME";
157     case unwindstack::ERROR_INVALID_ELF:
158       return "INVALID_ELF";
159     case unwindstack::ERROR_SYSTEM_CALL:
160       return "SYSTEM_CALL";
161     case unwindstack::ERROR_THREAD_DOES_NOT_EXIST:
162       return "THREAD_DOES_NOT_EXIST";
163     case unwindstack::ERROR_THREAD_TIMEOUT:
164       return "THREAD_TIMEOUT";
165     case unwindstack::ERROR_BAD_ARCH:
166       return "BAD_ARCH";
167     case unwindstack::ERROR_MAPS_PARSE:
168       return "MAPS_PARSE";
169     case unwindstack::ERROR_INVALID_PARAMETER:
170       return "INVALID_PARAMETER";
171     case unwindstack::ERROR_PTRACE_CALL:
172       return "PTRACE_CALL";
173   }
174 }
175 
176 }  // namespace profiling
177 }  // namespace perfetto
178