diff --git a/sandboxed_api/sandbox2/unwind/BUILD.bazel b/sandboxed_api/sandbox2/unwind/BUILD.bazel index e091a5b..553e998 100644 --- a/sandboxed_api/sandbox2/unwind/BUILD.bazel +++ b/sandboxed_api/sandbox2/unwind/BUILD.bazel @@ -51,6 +51,7 @@ cc_library( "_Ux86_64_step", ] ]), + visibility = ["//visibility:public"], deps = [ ":ptrace_hook", ":unwind_cc_proto", diff --git a/sandboxed_api/sandbox2/unwind/unwind.cc b/sandboxed_api/sandbox2/unwind/unwind.cc index d030773..fb02caf 100644 --- a/sandboxed_api/sandbox2/unwind/unwind.cc +++ b/sandboxed_api/sandbox2/unwind/unwind.cc @@ -54,83 +54,6 @@ std::string DemangleSymbol(const std::string& maybe_mangled) { return maybe_mangled; } -std::string GetSymbolAt(const std::map& addr_to_symbol, - uint64_t addr) { - auto entry_for_next_symbol = addr_to_symbol.lower_bound(addr); - if (entry_for_next_symbol != addr_to_symbol.end() && - entry_for_next_symbol != addr_to_symbol.begin()) { - // Matches the addr exactly: - if (entry_for_next_symbol->first == addr) { - return DemangleSymbol(entry_for_next_symbol->second); - } - - // Might be inside a function, return symbol+offset; - const auto entry_for_previous_symbol = --entry_for_next_symbol; - if (!entry_for_previous_symbol->second.empty()) { - return absl::StrCat(DemangleSymbol(entry_for_previous_symbol->second), - "+0x", - absl::Hex(addr - entry_for_previous_symbol->first)); - } - } - return ""; -} - -absl::StatusOr> LoadSymbolsMap(pid_t pid) { - const std::string maps_filename = absl::StrCat("/proc/", pid, "/maps"); - std::string maps_content; - SAPI_RETURN_IF_ERROR(sapi::file::GetContents(maps_filename, &maps_content, - sapi::file::Defaults())); - - SAPI_ASSIGN_OR_RETURN(std::vector maps, - ParseProcMaps(maps_content)); - - // Get symbols for each file entry in the maps entry. - // This is not a very efficient way, so we might want to optimize it. - std::map addr_to_symbol; - for (const MapsEntry& entry : maps) { - if (!entry.is_executable || - entry.inode == 0 || // Only parse file-backed entries - entry.path.empty() || - absl::EndsWith(entry.path, " (deleted)") // Skip deleted files - ) { - continue; - } - - // Store details about start + end of this map. - // The maps entries are ordered and thus sorted with increasing adresses. - // This means if there is a symbol @ entry.end, it will be overwritten in - // the next iteration. - std::string map = absl::StrCat("map:", entry.path); - if (entry.pgoff) { - absl::StrAppend(&map, "+0x", absl::Hex(entry.pgoff)); - } - addr_to_symbol[entry.start] = map; - addr_to_symbol[entry.end] = ""; - - absl::StatusOr elf = - ElfFile::ParseFromFile(entry.path, ElfFile::kLoadSymbols); - if (!elf.ok()) { - SAPI_RAW_LOG(WARNING, "Could not load symbols for %s: %s", - entry.path.c_str(), - std::string(elf.status().message()).c_str()); - continue; - } - - for (const ElfFile::Symbol& symbol : elf->symbols()) { - if (elf->position_independent()) { - if (symbol.address < entry.end - entry.start) { - addr_to_symbol[symbol.address + entry.start] = symbol.name; - } - } else { - if (symbol.address >= entry.start && symbol.address < entry.end) { - addr_to_symbol[symbol.address] = symbol.name; - } - } - } - } - return addr_to_symbol; -} - absl::StatusOr> RunLibUnwind(pid_t pid, int max_frames) { unw_cursor_t cursor; static unw_addr_space_t as = @@ -190,6 +113,82 @@ absl::StatusOr> SymbolizeStacktrace( } // namespace +std::string GetSymbolAt(const SymbolMap& addr_to_symbol, uint64_t addr) { + auto entry_for_next_symbol = addr_to_symbol.lower_bound(addr); + if (entry_for_next_symbol != addr_to_symbol.end() && + entry_for_next_symbol != addr_to_symbol.begin()) { + // Matches the addr exactly: + if (entry_for_next_symbol->first == addr) { + return DemangleSymbol(entry_for_next_symbol->second); + } + + // Might be inside a function, return symbol+offset; + const auto entry_for_previous_symbol = --entry_for_next_symbol; + if (!entry_for_previous_symbol->second.empty()) { + return absl::StrCat(DemangleSymbol(entry_for_previous_symbol->second), + "+0x", + absl::Hex(addr - entry_for_previous_symbol->first)); + } + } + return ""; +} + +absl::StatusOr LoadSymbolsMap(pid_t pid) { + const std::string maps_filename = absl::StrCat("/proc/", pid, "/maps"); + std::string maps_content; + SAPI_RETURN_IF_ERROR(sapi::file::GetContents(maps_filename, &maps_content, + sapi::file::Defaults())); + + SAPI_ASSIGN_OR_RETURN(std::vector maps, + ParseProcMaps(maps_content)); + + // Get symbols for each file entry in the maps entry. + // This is not a very efficient way, so we might want to optimize it. + SymbolMap addr_to_symbol; + for (const MapsEntry& entry : maps) { + if (!entry.is_executable || + entry.inode == 0 || // Only parse file-backed entries + entry.path.empty() || + absl::EndsWith(entry.path, " (deleted)") // Skip deleted files + ) { + continue; + } + + // Store details about start + end of this map. + // The maps entries are ordered and thus sorted with increasing adresses. + // This means if there is a symbol @ entry.end, it will be overwritten in + // the next iteration. + std::string map = absl::StrCat("map:", entry.path); + if (entry.pgoff) { + absl::StrAppend(&map, "+0x", absl::Hex(entry.pgoff)); + } + addr_to_symbol[entry.start] = map; + addr_to_symbol[entry.end] = ""; + + absl::StatusOr elf = + ElfFile::ParseFromFile(entry.path, ElfFile::kLoadSymbols); + if (!elf.ok()) { + SAPI_RAW_LOG(WARNING, "Could not load symbols for %s: %s", + entry.path.c_str(), + std::string(elf.status().message()).c_str()); + continue; + } + + for (const ElfFile::Symbol& symbol : elf->symbols()) { + if (elf->position_independent()) { + if (symbol.address < entry.end - entry.start) { + addr_to_symbol[symbol.address + entry.start] = symbol.name; + } + } else { + if (symbol.address >= entry.start && symbol.address < entry.end) { + addr_to_symbol[symbol.address] = symbol.name; + } + } + } + } + return addr_to_symbol; +} + bool RunLibUnwindAndSymbolizer(Comms* comms) { UnwindSetup setup; if (!comms->RecvProtoBuf(&setup)) { diff --git a/sandboxed_api/sandbox2/unwind/unwind.h b/sandboxed_api/sandbox2/unwind/unwind.h index b9c4638..a278fbc 100644 --- a/sandboxed_api/sandbox2/unwind/unwind.h +++ b/sandboxed_api/sandbox2/unwind/unwind.h @@ -26,6 +26,15 @@ namespace sandbox2 { +// Used to map from an address to a human-readable symbol. +using SymbolMap = std::map; + +// Returns the symbol at `addr`, possibly with an offset into said symbol. +std::string GetSymbolAt(const SymbolMap& addr_to_symbol, uint64_t addr); + +// Loads and returns a symbol map for a process with the provided `pid`. +absl::StatusOr LoadSymbolsMap(pid_t pid); + // Runs libunwind and the symbolizer and sends the results via comms. bool RunLibUnwindAndSymbolizer(Comms* comms);