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