1 #pragma once 2 #include <stdint.h> 3 #include <ostream> 4 5 #include <torch/csrc/profiler/unwind/lexer.h> 6 #include <torch/csrc/profiler/unwind/unwind_error.h> 7 8 // Overview of the format described in 9 // https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html 10 namespace torch::unwind { 11 12 struct EHFrameHdr { EHFrameHdrEHFrameHdr13 EHFrameHdr(void* base) : base_(base) { 14 Lexer L(base, base); 15 version_ = L.read<uint8_t>(); 16 eh_frame_ptr_enc_ = L.read<uint8_t>(); 17 fde_count_enc_ = L.read<uint8_t>(); 18 table_enc_ = L.read<uint8_t>(); 19 if (table_enc_ == DW_EH_PE_omit) { 20 table_size_ = 0; 21 } else { 22 switch (table_enc_ & 0xF) { 23 case DW_EH_PE_udata2: 24 case DW_EH_PE_sdata2: 25 table_size_ = 2; 26 break; 27 case DW_EH_PE_udata4: 28 case DW_EH_PE_sdata4: 29 table_size_ = 4; 30 break; 31 case DW_EH_PE_udata8: 32 case DW_EH_PE_sdata8: 33 table_size_ = 8; 34 break; 35 case DW_EH_PE_uleb128: 36 case DW_EH_PE_sleb128: 37 throw UnwindError("uleb/sleb table encoding not supported"); 38 break; 39 default: 40 throw UnwindError("unknown table encoding"); 41 } 42 } 43 eh_frame_ = (void*)L.readEncodedOr(eh_frame_ptr_enc_, 0); 44 fde_count_ = L.readEncodedOr(fde_count_enc_, 0); 45 table_start_ = L.loc(); 46 } nentriesEHFrameHdr47 size_t nentries() const { 48 return fde_count_; 49 } 50 lowpcEHFrameHdr51 uint64_t lowpc(size_t i) const { 52 return Lexer(table_start_, base_) 53 .skip(2 * i * table_size_) 54 .readEncoded(table_enc_); 55 } fdeEHFrameHdr56 void* fde(size_t i) const { 57 return (void*)Lexer(table_start_, base_) 58 .skip((2 * i + 1) * table_size_) 59 .readEncoded(table_enc_); 60 } 61 entryForAddrEHFrameHdr62 void* entryForAddr(uint64_t addr) const { 63 if (!table_size_ || !nentries()) { 64 throw UnwindError("search table not present"); 65 } 66 uint64_t low = 0; 67 uint64_t high = nentries(); 68 while (low + 1 < high) { 69 auto mid = (low + high) / 2; 70 if (addr < lowpc(mid)) { 71 high = mid; 72 } else { 73 low = mid; 74 } 75 } 76 return fde(low); 77 } 78 79 friend std::ostream& operator<<(std::ostream& out, const EHFrameHdr& self) { 80 out << "EHFrameHeader(version=" << self.version_ 81 << ",table_size=" << self.table_size_ 82 << ",fde_count=" << self.fde_count_ << ")"; 83 return out; 84 } 85 86 private: 87 void* base_; 88 void* table_start_; 89 uint8_t version_; 90 uint8_t eh_frame_ptr_enc_; 91 uint8_t fde_count_enc_; 92 uint8_t table_enc_; 93 void* eh_frame_ = nullptr; 94 int64_t fde_count_; 95 uint32_t table_size_; 96 }; 97 98 } // namespace torch::unwind 99