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