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