1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 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 * http://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 #ifndef PANDA_DEBUG_INFO_H_ 16 #define PANDA_DEBUG_INFO_H_ 17 18 #include <set> 19 #include <list> 20 #include <string> 21 #include <libdwarf/libdwarf.h> 22 #include "macros.h" 23 #include "utils/span.h" 24 25 namespace panda { 26 27 class DebugInfo { 28 public: 29 enum ErrorCode { SUCCESS, NO_DEBUG_INFO, ERROR }; 30 31 explicit DebugInfo() = default; 32 ~DebugInfo()33 ~DebugInfo() 34 { 35 Destroy(); 36 } 37 38 ErrorCode ReadFromFile(const char *filename); 39 40 /* 41 * Find location (name, source file, line) of the specified pc in source code 42 */ 43 bool GetSrcLocation(uintptr_t pc, std::string *function, std::string *src_file, uint32_t *line); 44 45 void Destroy(); 46 47 DEFAULT_MOVE_SEMANTIC(DebugInfo); 48 NO_COPY_SEMANTIC(DebugInfo); 49 50 private: 51 /** 52 * Cache entry for a compilation unit (object file). 53 * It contains the pointer to the corresponding DIE (Debug Information Entity), 54 * offset of the DIE in .debug_info, decoded line numbers for the compilation unit 55 * and function cache. 56 */ 57 class CompUnit { 58 public: CompUnit(Dwarf_Die cu_die,Dwarf_Debug dbg)59 CompUnit(Dwarf_Die cu_die, Dwarf_Debug dbg) : dbg_(dbg), cu_die_(cu_die) {} 60 CompUnit(CompUnit && e)61 CompUnit(CompUnit &&e) : dbg_(e.dbg_), cu_die_(e.cu_die_), line_ctx_(e.line_ctx_) 62 { 63 e.cu_die_ = nullptr; 64 e.line_ctx_ = nullptr; 65 } 66 67 ~CompUnit(); 68 69 CompUnit &operator=(CompUnit &&e) 70 { 71 dbg_ = e.dbg_; 72 cu_die_ = e.cu_die_; 73 e.cu_die_ = nullptr; 74 line_ctx_ = e.line_ctx_; 75 e.line_ctx_ = nullptr; 76 return *this; 77 } 78 GetDie()79 Dwarf_Die GetDie() const 80 { 81 return cu_die_; 82 } 83 84 Dwarf_Line_Context GetLineContext(); 85 86 NO_COPY_SEMANTIC(CompUnit); 87 88 private: 89 Dwarf_Debug dbg_; 90 Dwarf_Die cu_die_; 91 Dwarf_Line_Context line_ctx_ {nullptr}; 92 }; 93 94 class Range { 95 public: 96 Range(Dwarf_Addr low_pc, Dwarf_Addr high_pc, CompUnit *cu = nullptr, 97 const std::string &function = std::string()) // NOLINT(modernize-pass-by-value) low_pc_(low_pc)98 : low_pc_(low_pc), high_pc_(high_pc), cu_(cu), function_(function) 99 { 100 } 101 GetLowPc()102 Dwarf_Addr GetLowPc() const 103 { 104 return low_pc_; 105 } 106 GetHighPc()107 Dwarf_Addr GetHighPc() const 108 { 109 return high_pc_; 110 } 111 Contain(Dwarf_Addr addr)112 bool Contain(Dwarf_Addr addr) const 113 { 114 return low_pc_ <= addr && addr < high_pc_; 115 } 116 Contain(const Range & r)117 bool Contain(const Range &r) const 118 { 119 return low_pc_ <= r.low_pc_ && r.high_pc_ <= high_pc_; 120 } 121 GetCu()122 CompUnit *GetCu() const 123 { 124 return cu_; 125 } 126 GetFunction()127 std::string GetFunction() const 128 { 129 return function_; 130 } 131 SetFunction(const std::string & function)132 void SetFunction(const std::string &function) 133 { 134 this->function_ = function; 135 } 136 137 bool operator<(const Range &r) const 138 { 139 return high_pc_ < r.high_pc_; 140 } 141 142 bool operator==(const Range &r) const 143 { 144 return low_pc_ == r.low_pc_ && high_pc_ == r.high_pc_; 145 } 146 147 private: 148 Dwarf_Addr low_pc_; 149 Dwarf_Addr high_pc_; 150 CompUnit *cu_ = nullptr; 151 std::string function_; 152 }; 153 154 private: 155 bool FindCompUnitByPc(uintptr_t pc, Dwarf_Die *cu_die); 156 void TraverseChildren(CompUnit *cu, Dwarf_Die die); 157 void TraverseSiblings(CompUnit *cu, Dwarf_Die die); 158 void GetFunctionName(Dwarf_Die die, std::string *function); 159 void AddFunction(CompUnit *cu, Dwarf_Addr low_pc, Dwarf_Addr high_pc, const std::string &function); 160 bool GetSrcFileAndLine(uintptr_t pc, Dwarf_Line_Context line_ctx, std::string *src_file, uint32_t *line); 161 Dwarf_Line GetLastLineWithPc(Dwarf_Addr pc, Span<Dwarf_Line>::ConstIterator it, 162 Span<Dwarf_Line>::ConstIterator end); 163 void GetSrcFileAndLine(Dwarf_Line line, std::string *out_src_file, uint32_t *out_line); 164 bool PcMatches(uintptr_t pc, Dwarf_Die die); 165 bool GetDieRange(Dwarf_Die die, Dwarf_Addr *out_low_pc, Dwarf_Addr *out_high_pc); 166 bool GetDieRangeForPc(uintptr_t pc, Dwarf_Die die, Dwarf_Addr *out_low_pc, Dwarf_Addr *out_high_pc); 167 bool FindRangeForPc(uintptr_t pc, const Span<Dwarf_Ranges> &ranges, Dwarf_Addr base_addr, Dwarf_Addr *out_low_pc, 168 Dwarf_Addr *out_high_pc); 169 170 private: 171 static constexpr int INVALID_FD = -1; 172 173 int fd_ {INVALID_FD}; 174 Dwarf_Debug dbg_ {nullptr}; 175 Dwarf_Arange *aranges_ {nullptr}; 176 Dwarf_Signed arange_count_ {0}; 177 std::list<CompUnit> cu_list_; 178 std::set<Range> ranges_; 179 }; 180 181 } // namespace panda 182 #endif // PANDA_DEBUG_INFO_H_ 183