1 /* 2 * Copyright (C) 2021 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 #pragma once 18 19 #include <cstddef> 20 #include <filesystem> 21 #include <memory> 22 #include <string> 23 #include <unordered_map> 24 #include <vector> 25 26 #include <unwindstack/Arch.h> 27 #include <unwindstack/JitDebug.h> 28 #include <unwindstack/Memory.h> 29 #include <unwindstack/Regs.h> 30 #include <unwindstack/Unwinder.h> 31 32 #include "MemoryOffline.h" 33 34 // These utils facilitate performing offline unwinds. Offline unwinds are similar to local 35 // unwinds, however, instead of pausing the process to gather the current execution state 36 // (stack, registers, Elf / maps), a snapshot of the process is taken. This snapshot data 37 // is used at a later time (when the process is no longer running) to unwind the process 38 // at the point the snapshot was taken. 39 // 40 // Offline unwinds simulate one of the most common use cases of the Unwinder. These types of 41 // unwinds are performed by two of the largest clients of libunwindstack: Perfetto and Simpleperf. 42 // 43 // Offline unwind snapshots were obtained using the following approach: 44 // 1. (Optional) Flash a virtual or physical device with the internal Android build rather than 45 // an AOSP build to have additional and more complex apps to unwind. 46 // 2. Determine the pid of the app/process you want to unwind. View all of the running 47 // processes with `adb shell ps -A` or `adb shell ps -A | grep name.of.process` if you know 48 // the (package) name of the process. 49 // 3. (Optional) If you want to ensure that an application is compiled or that the compiled code is 50 // erased (e.g. want interpreter / JIT frames in the unwind), run `adb shell cmd package compile` 51 // based on the options provided here 52 // (https://source.android.com/devices/tech/dalvik/jit-compiler). 53 // 4. Ensure the process is running and in a "desired state" when you execute 54 // `adb shell /bin/unwind_for_offline [options] pid`. For example: 55 // a. If you are unwinding the bluetooth process and want the unwind to contain the bluetooth 56 // ELF (libbluetooth.so), try to pair with a device over bluetooth. Make sure you use the 57 // `-t` and `-e` flags. 58 // b. You will likely see more variation in the thread snapshots (especially if you are trying 59 // to capture JIT/interpreter frames) if you ensure the app is not-idle when you run 60 // `unwind_for_offline`. E.g. immediately run unwind_for_offline after searching for a 61 // landmark in Google Maps. 62 // 5. Grab the desired snapshot directories with `adb pull ...` 63 // 6. (Optional) Reduce the size of copied ELFs: 64 // a. Use tools/share_common_elfs.sh to eliminate copies of the same ELF files that are already 65 // used by other 'libunwindstack/offline_files/' subdirectories. 66 // b. Strip ELFs of all sections that are not needed for unwinding and/or symbolization. 67 // c. Compress/Zip the entire snapshot directory. 68 // 7. Use the path to the snapshot directory(ies) for the `offline_files_dirs` parameter to 69 // `OfflineUnwindUtils::Init`. 70 // 71 // See b/192012600 for additional information regarding Offline Unwind Benchmarks. 72 namespace unwindstack { 73 74 void DecompressFiles(const std::string& directory); 75 76 std::string GetOfflineFilesDirectory(); 77 78 std::string DumpFrames(const Unwinder& unwinder); 79 80 bool AddMemory(std::string file_name, MemoryOfflineParts* parts, std::string* error_msg); 81 82 // Enum that indicates how `UnwindSample::process_memory` of `OfflineUnwindUtils::samples_` 83 // should be initialized. 84 enum class ProcessMemoryFlag { 85 kNone = 0, 86 kIncludeJitMemory, 87 kNoMemory, 88 }; 89 90 // A `UnwindSampleInfo` object contains the information necessary for OfflineUnwindUtils 91 // to initialize a single offline unwind sample. 92 struct UnwindSampleInfo { 93 std::string offline_files_dir; 94 ArchEnum arch; 95 std::string frame_info_filename = "output.txt"; 96 ProcessMemoryFlag memory_flag = ProcessMemoryFlag::kNone; 97 bool create_maps = true; 98 }; 99 100 // The `OfflineUnwindUtils` class helps perform offline unwinds by handling the creation of the 101 // `Regs`, `Maps`, and `Memory` objects needed for unwinding. 102 // 103 // `OfflineUnwindUtils` assists in two unwind use cases: 104 // 1. Single unwinds: unwind from a single sample/snapshot (one set of offline unwind files). 105 // 2. Consecutive/Multiple unwinds: unwind from a multiple samples/snapshots. 106 // 107 // `Init` contains two overloads for these two unwind cases. Other than `Init` and 108 // `ReturnToCurrentWorkingDirectory`, the remainder of the public API includes a `sample_name` 109 // parameter to indicate which sample/snapshot we are referencing. Specifying this value is 110 // REQUIRED for the multiple unwind use case. However, in the single use case, the caller has 111 // the choice of either providing the sample name or using the default value. 112 class OfflineUnwindUtils { 113 public: 114 // If the sample name passed to Get* is an invalid sample, nullptr is returned. 115 Regs* GetRegs(const std::string& sample_name = kSingleSample) const; 116 117 Maps* GetMaps(const std::string& sample_name = kSingleSample) const; 118 119 std::shared_ptr<Memory> GetProcessMemory(const std::string& sample_name = kSingleSample) const; 120 121 JitDebug* GetJitDebug(const std::string& sample_name = kSingleSample) const; 122 123 const std::string* GetOfflineFilesPath(const std::string& sample_name = kSingleSample) const; 124 125 const std::string* GetFrameInfoFilepath(const std::string& sample_name = kSingleSample) const; 126 127 // Note: If the caller sets elements of `set_maps` to false or `memory_types` to 128 // kNoMemory, they are responsible for calling `CreateMaps` or `CreateProcessMemory` before 129 // expecting `GetMaps` or `GetProcessMemory` to return anything but nullptr. 130 bool Init(const std::vector<UnwindSampleInfo>& sample_infos, std::string* error_msg); 131 132 bool Init(const UnwindSampleInfo& sample_info, std::string* error_msg); 133 134 // This must be called explicitly for the multiple unwind use case sometime before 135 // Unwinder::Unwind is called. This is required because the Unwinder must init each 136 // ELF object with a MemoryFileAtOffset memory object. Because the maps.txt provides a relative 137 // path to the ELF files, we must be in the directory of the maps.txt when unwinding. 138 // 139 // Note: Init performs the check that this sample directory exists. If Init fails, 140 // `initted_` is not set to true and this function will return false. 141 bool ChangeToSampleDirectory(std::string* error_msg, 142 const std::string& initial_sample_name = kSingleSample) const; 143 ReturnToCurrentWorkingDirectory()144 void ReturnToCurrentWorkingDirectory() { 145 if (!cwd_.empty()) std::filesystem::current_path(cwd_); 146 } 147 148 bool GetExpectedNumFrames(size_t* expected_num_frames, std::string* error_msg, 149 const std::string& sample_name = kSingleSample) const; 150 151 bool CreateMaps(std::string* error_msg, const std::string& sample_name = kSingleSample); 152 153 bool CreateProcessMemory(std::string* error_msg, const std::string& sample_name = kSingleSample); 154 155 static constexpr char kSingleSample[] = ""; 156 157 private: 158 // An `UnwindSample` encapsulates the information necessary to perform an offline unwind for a 159 // single offline sample/snapshot. 160 struct UnwindSample { 161 std::string offline_files_path; 162 std::string frame_info_filepath; 163 std::string map_buffer; 164 std::unique_ptr<Regs> regs; 165 std::unique_ptr<Maps> maps; 166 std::shared_ptr<Memory> process_memory; 167 std::unique_ptr<JitDebug> jit_debug; 168 }; 169 170 bool CreateRegs(ArchEnum arch, std::string* error_msg, 171 const std::string& sample_name = kSingleSample); 172 173 // Needed to support using the default value `kSingleSample` for the single unwind use case. 174 const std::string& GetAdjustedSampleName(const std::string& sample_name) const; 175 176 bool IsValidUnwindSample(const std::string& sample_name, std::string* error_msg) const; 177 178 static std::unordered_map<std::string, uint32_t> arm_regs_; 179 static std::unordered_map<std::string, uint32_t> arm64_regs_; 180 static std::unordered_map<std::string, uint32_t> riscv64_regs_; 181 static std::unordered_map<std::string, uint32_t> x86_regs_; 182 static std::unordered_map<std::string, uint32_t> x86_64_regs_; 183 184 std::string cwd_; 185 std::unordered_map<std::string, UnwindSample> samples_; 186 bool initted_ = false; 187 }; 188 189 } // namespace unwindstack 190