1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
#pragma once
#include <cxxabi.h>
#include <elf.h>
#include <torch/csrc/profiler/unwind/dwarf_enums.h>
#include <torch/csrc/profiler/unwind/dwarf_symbolize_enums.h>
#include <torch/csrc/profiler/unwind/mem_file.h>
#include <torch/csrc/profiler/unwind/range_table.h>
#include <torch/csrc/profiler/unwind/unwind_error.h>
#include <cstdint>
namespace torch::unwind {
static std::string demangle(const std::string& mangled_name) {
int status = 0;
char* realname =
abi::__cxa_demangle(mangled_name.c_str(), nullptr, nullptr, &status);
if (status == 0) {
std::string demangled_name(realname);
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
free(realname);
return demangled_name;
} else {
return mangled_name;
}
}
struct Sections {
Sections() = default;
void parse(const char* name) {
library_ = std::make_unique<MemFile>(name);
strtab = library_->getSection(".strtab", false);
symtab = library_->getSection(".symtab", true);
debug_info = library_->getSection(".debug_info", true);
if (debug_info.size > 0) {
debug_abbrev = library_->getSection(".debug_abbrev", false);
debug_str = library_->getSection(".debug_str", false);
debug_line = library_->getSection(".debug_line", false);
// dwarf 5
debug_line_str = library_->getSection(".debug_line_str", true);
debug_rnglists = library_->getSection(".debug_rnglists", true);
debug_addr = library_->getSection(".debug_addr", true);
// dwarf 4
debug_ranges = library_->getSection(".debug_ranges", true);
}
parseSymtab();
}
Section debug_info;
Section debug_abbrev;
Section debug_str;
Section debug_line;
Section debug_line_str;
Section debug_rnglists;
Section debug_ranges;
Section debug_addr;
Section symtab;
Section strtab;
const char* readString(CheckedLexer& data, uint64_t encoding, bool is_64bit) {
switch (encoding) {
case DW_FORM_string: {
return data.readCString();
}
case DW_FORM_strp: {
return debug_str.string(readSegmentOffset(data, is_64bit));
}
case DW_FORM_line_strp: {
return debug_line_str.string(readSegmentOffset(data, is_64bit));
}
default:
UNWIND_CHECK(false, "unsupported string encoding {:x}", encoding);
}
}
uint64_t readSegmentOffset(CheckedLexer& data, bool is_64bit) {
return is_64bit ? data.read<uint64_t>() : data.read<uint32_t>();
}
std::optional<uint64_t> findDebugInfoOffset(uint64_t address) {
return debug_info_offsets_.find(address);
}
size_t compilationUnitCount() {
return debug_info_offsets_.size() / 2;
}
void addDebugInfoRange(
uint64_t start,
uint64_t end,
uint64_t debug_info_offset) {
debug_info_offsets_.add(start, debug_info_offset, false);
debug_info_offsets_.add(end, std::nullopt, false);
}
std::optional<std::string> findSubprogramName(uint64_t address) {
if (auto e = symbol_table_.find(address)) {
return demangle(strtab.string(*e));
}
return std::nullopt;
}
private:
void parseSymtab() {
auto L = symtab.lexer(0);
char* end = symtab.data + symtab.size;
while (L.loc() < end) {
auto symbol = L.read<Elf64_Sym>();
if (symbol.st_shndx == SHN_UNDEF ||
ELF64_ST_TYPE(symbol.st_info) != STT_FUNC) {
continue;
}
symbol_table_.add(symbol.st_value, symbol.st_name, false);
symbol_table_.add(symbol.st_value + symbol.st_size, std::nullopt, false);
}
}
std::unique_ptr<MemFile> library_;
RangeTable<uint64_t> debug_info_offsets_;
RangeTable<uint64_t> symbol_table_;
};
} // namespace torch::unwind
|