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