xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/unwind/unwind.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "sandboxed_api/sandbox2/unwind/unwind.h"
16 
17 #include <cxxabi.h>
18 #include <sys/ptrace.h>
19 #include <sys/types.h>
20 
21 #include <cerrno>
22 #include <cstdint>
23 #include <cstdlib>
24 #include <map>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include "absl/cleanup/cleanup.h"
31 #include "absl/status/status.h"
32 #include "absl/status/statusor.h"
33 #include "absl/strings/match.h"
34 #include "absl/strings/str_cat.h"
35 #include "absl/strings/string_view.h"
36 //#include "libunwind-ptrace.h" Android: libunwind was removed in aosp/1670175
37 #include "sandboxed_api/config.h"
38 #include "sandboxed_api/sandbox2/comms.h"
39 #include "sandboxed_api/sandbox2/unwind/ptrace_hook.h"
40 #include "sandboxed_api/sandbox2/unwind/unwind.pb.h"
41 #include "sandboxed_api/sandbox2/util/maps_parser.h"
42 #include "sandboxed_api/sandbox2/util/minielf.h"
43 #include "sandboxed_api/util/file_helpers.h"
44 #include "sandboxed_api/util/raw_logging.h"
45 #include "sandboxed_api/util/status_macros.h"
46 
47 namespace sandbox2 {
48 namespace {
49 
DemangleSymbol(const std::string & maybe_mangled)50 std::string DemangleSymbol(const std::string& maybe_mangled) {
51   int status;
52   size_t length;
53   std::unique_ptr<char, decltype(&std::free)> symbol(
54       abi::__cxa_demangle(maybe_mangled.c_str(), /*output_buffer=*/nullptr,
55                           &length, &status),
56       std::free);
57   if (symbol && status == 0) {
58     return std::string(symbol.get(), length);
59   }
60   return maybe_mangled;
61 }
62 
ReadMemory(pid_t pid,uintptr_t addr)63 absl::StatusOr<uintptr_t> ReadMemory(pid_t pid, uintptr_t addr) {
64   errno = 0;
65   uintptr_t val = ptrace(PTRACE_PEEKDATA, pid, addr, 0);
66   if (errno != 0) {
67     return absl::ErrnoToStatus(errno, "ptrace() failed");
68   }
69   return val;
70 }
71 
UnwindUsingFramePointer(pid_t pid,int max_frames,uintptr_t fp)72 absl::StatusOr<std::vector<uintptr_t>> UnwindUsingFramePointer(pid_t pid,
73                                                                int max_frames,
74                                                                uintptr_t fp) {
75 #if defined(SAPI_PPC64_LE)
76   constexpr int kIPOffset = 2;
77 #else
78   constexpr int kIPOffset = 1;
79 #endif
80   std::vector<uintptr_t> ips;
81   for (int i = 0; fp != 0 && i < max_frames; ++i) {
82     SAPI_ASSIGN_OR_RETURN(uintptr_t ip,
83                           ReadMemory(pid, fp + kIPOffset * sizeof(void*)));
84     ips.push_back(ip);
85     SAPI_ASSIGN_OR_RETURN(fp, ReadMemory(pid, fp));
86   }
87   return ips;
88 }
89 
90 #if 0 // Android: libunwind is not available
91 absl::StatusOr<std::vector<uintptr_t>> RunLibUnwind(pid_t pid, int max_frames) {
92   static unw_addr_space_t as =
93       unw_create_addr_space(&_UPT_accessors, 0 /* byte order */);
94   if (as == nullptr) {
95     return absl::InternalError("unw_create_addr_space() failed");
96   }
97 
98   void* context = _UPT_create(pid);
99   if (context == nullptr) {
100     return absl::InternalError("_UPT_create() failed");
101   }
102   absl::Cleanup context_cleanup = [&context] { _UPT_destroy(context); };
103 
104   unw_cursor_t cursor;
105   if (int rc = unw_init_remote(&cursor, as, context); rc < 0) {
106     // Could be UNW_EINVAL (8), UNW_EUNSPEC (1) or UNW_EBADREG (3).
107     return absl::InternalError(
108         absl::StrCat("unw_init_remote() failed with error ", rc));
109   }
110   std::vector<uintptr_t> ips;
111   for (int i = 0; i < max_frames; ++i) {
112     unw_word_t ip;
113     unw_word_t fp = 0;
114     int rc = unw_get_reg(&cursor, UNW_REG_IP, &ip);
115     if (rc < 0) {
116       // Could be UNW_EUNSPEC or UNW_EBADREG.
117       SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc);
118       break;
119     }
120 #if defined(SAPI_ARM64)
121     constexpr int kFpReg = UNW_AARCH64_X29;
122 #elif defined(SAPI_ARM)
123     constexpr int kFpReg = UNW_ARM_R11;
124 #elif defined(SAPI_X86_64)
125     constexpr int kFpReg = UNW_X86_64_RBP;
126 #elif defined(SAPI_PPC64_LE)
127     constexpr int kFpReg = UNW_PPC64_R1;
128 #endif
129     rc = unw_get_reg(&cursor, kFpReg, &fp);
130     if (rc < 0) {
131       SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc);
132     }
133     ips.push_back(ip);
134     rc = unw_step(&cursor);
135     if (rc <= 0) {
136       if (rc < 0) {
137         SAPI_RAW_LOG(WARNING, "unw_step() failed with error %d", rc);
138       }
139       if (fp != 0) {
140         SAPI_RAW_LOG(INFO, "Falling back to frame based unwinding at FP: %lx",
141                      fp);
142         absl::StatusOr<std::vector<uintptr_t>> fp_ips =
143             UnwindUsingFramePointer(pid, max_frames - ips.size(), fp);
144         if (!fp_ips.ok()) {
145           SAPI_RAW_LOG(WARNING, "FP based unwinding failed: %s",
146                        std::string(fp_ips.status().message()).c_str());
147           break;
148         }
149         ips.insert(ips.end(), fp_ips->begin(), fp_ips->end());
150       }
151       break;
152     }
153   }
154   return ips;
155 }
156 #endif
157 
SymbolizeStacktrace(pid_t pid,const std::vector<uintptr_t> & ips)158 absl::StatusOr<std::vector<std::string>> SymbolizeStacktrace(
159     pid_t pid, const std::vector<uintptr_t>& ips) {
160   SAPI_ASSIGN_OR_RETURN(auto addr_to_symbol, LoadSymbolsMap(pid));
161   std::vector<std::string> stack_trace;
162   stack_trace.reserve(ips.size());
163   // Symbolize stacktrace
164   for (uintptr_t ip : ips) {
165     const std::string symbol =
166         GetSymbolAt(addr_to_symbol, static_cast<uint64_t>(ip));
167     stack_trace.push_back(absl::StrCat(symbol, "(0x", absl::Hex(ip), ")"));
168   }
169   return stack_trace;
170 }
171 
172 }  // namespace
173 
GetSymbolAt(const SymbolMap & addr_to_symbol,uint64_t addr)174 std::string GetSymbolAt(const SymbolMap& addr_to_symbol, uint64_t addr) {
175   auto entry_for_next_symbol = addr_to_symbol.lower_bound(addr);
176   if (entry_for_next_symbol != addr_to_symbol.end() &&
177       entry_for_next_symbol != addr_to_symbol.begin()) {
178     // Matches the addr exactly:
179     if (entry_for_next_symbol->first == addr) {
180       return DemangleSymbol(entry_for_next_symbol->second);
181     }
182 
183     // Might be inside a function, return symbol+offset;
184     const auto entry_for_previous_symbol = --entry_for_next_symbol;
185     if (!entry_for_previous_symbol->second.empty()) {
186       return absl::StrCat(DemangleSymbol(entry_for_previous_symbol->second),
187                           "+0x",
188                           absl::Hex(addr - entry_for_previous_symbol->first));
189     }
190   }
191   return "";
192 }
193 
LoadSymbolsMap(pid_t pid)194 absl::StatusOr<SymbolMap> LoadSymbolsMap(pid_t pid) {
195   const std::string maps_filename = absl::StrCat("/proc/", pid, "/maps");
196   std::string maps_content;
197   SAPI_RETURN_IF_ERROR(sapi::file::GetContents(maps_filename, &maps_content,
198                                                sapi::file::Defaults()));
199 
200   SAPI_ASSIGN_OR_RETURN(std::vector<MapsEntry> maps,
201                         ParseProcMaps(maps_content));
202 
203   // Get symbols for each file entry in the maps entry.
204   // This is not a very efficient way, so we might want to optimize it.
205   SymbolMap addr_to_symbol;
206   for (const MapsEntry& entry : maps) {
207     if (!entry.is_executable ||
208         entry.inode == 0 ||  // Only parse file-backed entries
209         entry.path.empty() ||
210         absl::EndsWith(entry.path, " (deleted)")  // Skip deleted files
211     ) {
212       continue;
213     }
214 
215     // Store details about start + end of this map.
216     // The maps entries are ordered and thus sorted with increasing adresses.
217     // This means if there is a symbol @ entry.end, it will be overwritten in
218     // the next iteration.
219     std::string map = absl::StrCat("map:", entry.path);
220     if (entry.pgoff) {
221       absl::StrAppend(&map, "+0x", absl::Hex(entry.pgoff));
222     }
223     addr_to_symbol[entry.start] = map;
224     addr_to_symbol[entry.end] = "";
225 
226     absl::StatusOr<ElfFile> elf =
227         ElfFile::ParseFromFile(entry.path, ElfFile::kLoadSymbols);
228     if (!elf.ok()) {
229       SAPI_RAW_LOG(WARNING, "Could not load symbols for %s: %s",
230                    entry.path.c_str(),
231                    std::string(elf.status().message()).c_str());
232       continue;
233     }
234 
235     for (const ElfFile::Symbol& symbol : elf->symbols()) {
236       // Skip Mapping Symbols on ARM
237       // ARM documentation for Mapping Symbols:
238       // https://developer.arm.com/documentation/dui0803/a/Accessing-and-managing-symbols-with-armlink/About-mapping-symbols
239       if constexpr (sapi::host_cpu::IsArm64() || sapi::host_cpu::IsArm()) {
240         if (absl::StartsWith(symbol.name, "$x") ||
241             absl::StartsWith(symbol.name, "$d") ||
242             absl::StartsWith(symbol.name, "$t") ||
243             absl::StartsWith(symbol.name, "$a") ||
244             absl::StartsWith(symbol.name, "$v")) {
245           continue;
246         }
247       }
248 
249       if (elf->position_independent()) {
250         if (symbol.address >= entry.pgoff &&
251             symbol.address - entry.pgoff < entry.end - entry.start) {
252           addr_to_symbol[symbol.address + entry.start - entry.pgoff] =
253               symbol.name;
254         }
255       } else {
256         if (symbol.address >= entry.start && symbol.address < entry.end) {
257           addr_to_symbol[symbol.address] = symbol.name;
258         }
259       }
260     }
261   }
262   return addr_to_symbol;
263 }
264 
RunLibUnwindAndSymbolizer(Comms * comms)265 bool RunLibUnwindAndSymbolizer(Comms* comms) {
266   UnwindSetup setup;
267   if (!comms->RecvProtoBuf(&setup)) {
268     return false;
269   }
270   int mem_fd;
271   if (!comms->RecvFD(&mem_fd)) {
272     return false;
273   }
274 
275   EnablePtraceEmulationWithUserRegs(setup.pid(), setup.regs(), mem_fd);
276 
277   absl::StatusOr<std::vector<std::string>> stack_trace =
278       RunLibUnwindAndSymbolizer(setup.pid(), setup.default_max_frames());
279 
280   if (!comms->SendStatus(stack_trace.status())) {
281     return false;
282   }
283 
284   if (!stack_trace.ok()) {
285     return true;
286   }
287 
288   UnwindResult msg;
289   *msg.mutable_stacktrace() = {stack_trace->begin(), stack_trace->end()};
290   return comms->SendProtoBuf(msg);
291 }
292 
293 #if 0
294 absl::StatusOr<std::vector<std::string>> RunLibUnwindAndSymbolizer(
295     pid_t pid, int max_frames) {
296   SAPI_ASSIGN_OR_RETURN(std::vector<uintptr_t> ips,
297                         RunLibUnwind(pid, max_frames));
298   return SymbolizeStacktrace(pid, ips);
299 }
300 #endif
301 
302 }  // namespace sandbox2
303