1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _LIBUNWINDSTACK_DWARF_CFA_H 18 #define _LIBUNWINDSTACK_DWARF_CFA_H 19 20 #include <stdint.h> 21 22 #include <stack> 23 #include <string> 24 #include <type_traits> 25 #include <vector> 26 27 #include <unwindstack/DwarfError.h> 28 #include <unwindstack/DwarfLocation.h> 29 #include <unwindstack/DwarfMemory.h> 30 #include <unwindstack/DwarfStructs.h> 31 32 namespace unwindstack { 33 34 // DWARF Standard home: http://dwarfstd.org/ 35 // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf 36 // See section 6.4.2.1 for a description of the DW_CFA_xxx values. 37 38 class DwarfCfaInfo { 39 public: 40 enum DisplayType : uint8_t { 41 DWARF_DISPLAY_NONE = 0, 42 DWARF_DISPLAY_REGISTER, 43 DWARF_DISPLAY_NUMBER, 44 DWARF_DISPLAY_SIGNED_NUMBER, 45 DWARF_DISPLAY_EVAL_BLOCK, 46 DWARF_DISPLAY_ADDRESS, 47 DWARF_DISPLAY_SET_LOC, 48 DWARF_DISPLAY_ADVANCE_LOC, 49 }; 50 51 struct Info { 52 // It may seem cleaner to just change the type of 'name' to 'const char *'. 53 // However, having a pointer here would require relocation at runtime, 54 // causing 'kTable' to be placed in data.rel.ro section instead of rodata 55 // section, adding memory pressure to the system. Note that this is only 56 // safe because this is only used in C++ code. C++ standard, unlike C 57 // standard, mandates the array size to be large enough to hold the NULL 58 // terminator when initialized with a string literal. 59 const char name[36]; 60 uint8_t supported_version; 61 uint8_t num_operands; 62 uint8_t operands[2]; 63 uint8_t display_operands[2]; 64 }; 65 66 const static Info kTable[64]; 67 }; 68 69 template <typename AddressType> 70 class DwarfCfa { 71 // Signed version of AddressType 72 typedef typename std::make_signed<AddressType>::type SignedType; 73 74 public: DwarfCfa(DwarfMemory * memory,const DwarfFde * fde)75 DwarfCfa(DwarfMemory* memory, const DwarfFde* fde) : memory_(memory), fde_(fde) {} 76 virtual ~DwarfCfa() = default; 77 78 bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset, 79 dwarf_loc_regs_t* loc_regs); 80 81 bool Log(uint32_t indent, uint64_t pc, uint64_t start_offset, uint64_t end_offset); 82 last_error()83 const DwarfErrorData& last_error() { return last_error_; } LastErrorCode()84 DwarfErrorCode LastErrorCode() { return last_error_.code; } LastErrorAddress()85 uint64_t LastErrorAddress() { return last_error_.address; } 86 cur_pc()87 AddressType cur_pc() { return cur_pc_; } 88 set_cie_loc_regs(const dwarf_loc_regs_t * cie_loc_regs)89 void set_cie_loc_regs(const dwarf_loc_regs_t* cie_loc_regs) { cie_loc_regs_ = cie_loc_regs; } 90 91 protected: 92 std::string GetOperandString(uint8_t operand, uint64_t value, uint64_t* cur_pc); 93 94 bool LogOffsetRegisterString(uint32_t indent, uint64_t cfa_offset, uint8_t reg); 95 96 bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc); 97 98 private: 99 DwarfErrorData last_error_; 100 DwarfMemory* memory_; 101 const DwarfFde* fde_; 102 103 AddressType cur_pc_; 104 const dwarf_loc_regs_t* cie_loc_regs_ = nullptr; 105 std::vector<AddressType> operands_; 106 std::stack<dwarf_loc_regs_t> loc_reg_state_; 107 108 // CFA processing functions. 109 bool cfa_nop(dwarf_loc_regs_t*); 110 bool cfa_set_loc(dwarf_loc_regs_t*); 111 bool cfa_advance_loc(dwarf_loc_regs_t*); 112 bool cfa_offset(dwarf_loc_regs_t*); 113 bool cfa_restore(dwarf_loc_regs_t*); 114 bool cfa_undefined(dwarf_loc_regs_t*); 115 bool cfa_same_value(dwarf_loc_regs_t*); 116 bool cfa_register(dwarf_loc_regs_t*); 117 bool cfa_remember_state(dwarf_loc_regs_t*); 118 bool cfa_restore_state(dwarf_loc_regs_t*); 119 bool cfa_def_cfa(dwarf_loc_regs_t*); 120 bool cfa_def_cfa_register(dwarf_loc_regs_t*); 121 bool cfa_def_cfa_offset(dwarf_loc_regs_t*); 122 bool cfa_def_cfa_expression(dwarf_loc_regs_t*); 123 bool cfa_expression(dwarf_loc_regs_t*); 124 bool cfa_offset_extended_sf(dwarf_loc_regs_t*); 125 bool cfa_def_cfa_sf(dwarf_loc_regs_t*); 126 bool cfa_def_cfa_offset_sf(dwarf_loc_regs_t*); 127 bool cfa_val_offset(dwarf_loc_regs_t*); 128 bool cfa_val_offset_sf(dwarf_loc_regs_t*); 129 bool cfa_val_expression(dwarf_loc_regs_t*); 130 bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*); 131 132 using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*); 133 constexpr static process_func kCallbackTable[64] = { 134 // 0x00 DW_CFA_nop 135 &DwarfCfa::cfa_nop, 136 // 0x01 DW_CFA_set_loc 137 &DwarfCfa::cfa_set_loc, 138 // 0x02 DW_CFA_advance_loc1 139 &DwarfCfa::cfa_advance_loc, 140 // 0x03 DW_CFA_advance_loc2 141 &DwarfCfa::cfa_advance_loc, 142 // 0x04 DW_CFA_advance_loc4 143 &DwarfCfa::cfa_advance_loc, 144 // 0x05 DW_CFA_offset_extended 145 &DwarfCfa::cfa_offset, 146 // 0x06 DW_CFA_restore_extended 147 &DwarfCfa::cfa_restore, 148 // 0x07 DW_CFA_undefined 149 &DwarfCfa::cfa_undefined, 150 // 0x08 DW_CFA_same_value 151 &DwarfCfa::cfa_same_value, 152 // 0x09 DW_CFA_register 153 &DwarfCfa::cfa_register, 154 // 0x0a DW_CFA_remember_state 155 &DwarfCfa::cfa_remember_state, 156 // 0x0b DW_CFA_restore_state 157 &DwarfCfa::cfa_restore_state, 158 // 0x0c DW_CFA_def_cfa 159 &DwarfCfa::cfa_def_cfa, 160 // 0x0d DW_CFA_def_cfa_register 161 &DwarfCfa::cfa_def_cfa_register, 162 // 0x0e DW_CFA_def_cfa_offset 163 &DwarfCfa::cfa_def_cfa_offset, 164 // 0x0f DW_CFA_def_cfa_expression 165 &DwarfCfa::cfa_def_cfa_expression, 166 // 0x10 DW_CFA_expression 167 &DwarfCfa::cfa_expression, 168 // 0x11 DW_CFA_offset_extended_sf 169 &DwarfCfa::cfa_offset_extended_sf, 170 // 0x12 DW_CFA_def_cfa_sf 171 &DwarfCfa::cfa_def_cfa_sf, 172 // 0x13 DW_CFA_def_cfa_offset_sf 173 &DwarfCfa::cfa_def_cfa_offset_sf, 174 // 0x14 DW_CFA_val_offset 175 &DwarfCfa::cfa_val_offset, 176 // 0x15 DW_CFA_val_offset_sf 177 &DwarfCfa::cfa_val_offset_sf, 178 // 0x16 DW_CFA_val_expression 179 &DwarfCfa::cfa_val_expression, 180 // 0x17 illegal cfa 181 nullptr, 182 // 0x18 illegal cfa 183 nullptr, 184 // 0x19 illegal cfa 185 nullptr, 186 // 0x1a illegal cfa 187 nullptr, 188 // 0x1b illegal cfa 189 nullptr, 190 // 0x1c DW_CFA_lo_user (Treat this as illegal) 191 nullptr, 192 // 0x1d illegal cfa 193 nullptr, 194 // 0x1e illegal cfa 195 nullptr, 196 // 0x1f illegal cfa 197 nullptr, 198 // 0x20 illegal cfa 199 nullptr, 200 // 0x21 illegal cfa 201 nullptr, 202 // 0x22 illegal cfa 203 nullptr, 204 // 0x23 illegal cfa 205 nullptr, 206 // 0x24 illegal cfa 207 nullptr, 208 // 0x25 illegal cfa 209 nullptr, 210 // 0x26 illegal cfa 211 nullptr, 212 // 0x27 illegal cfa 213 nullptr, 214 // 0x28 illegal cfa 215 nullptr, 216 // 0x29 illegal cfa 217 nullptr, 218 // 0x2a illegal cfa 219 nullptr, 220 // 0x2b illegal cfa 221 nullptr, 222 // 0x2c illegal cfa 223 nullptr, 224 // 0x2d DW_CFA_GNU_window_save (Treat this as illegal) 225 nullptr, 226 // 0x2e DW_CFA_GNU_args_size 227 &DwarfCfa::cfa_nop, 228 // 0x2f DW_CFA_GNU_negative_offset_extended 229 &DwarfCfa::cfa_gnu_negative_offset_extended, 230 // 0x30 illegal cfa 231 nullptr, 232 // 0x31 illegal cfa 233 nullptr, 234 // 0x32 illegal cfa 235 nullptr, 236 // 0x33 illegal cfa 237 nullptr, 238 // 0x34 illegal cfa 239 nullptr, 240 // 0x35 illegal cfa 241 nullptr, 242 // 0x36 illegal cfa 243 nullptr, 244 // 0x37 illegal cfa 245 nullptr, 246 // 0x38 illegal cfa 247 nullptr, 248 // 0x39 illegal cfa 249 nullptr, 250 // 0x3a illegal cfa 251 nullptr, 252 // 0x3b illegal cfa 253 nullptr, 254 // 0x3c illegal cfa 255 nullptr, 256 // 0x3d illegal cfa 257 nullptr, 258 // 0x3e illegal cfa 259 nullptr, 260 // 0x3f DW_CFA_hi_user (Treat this as illegal) 261 nullptr, 262 }; 263 }; 264 265 } // namespace unwindstack 266 267 #endif // _LIBUNWINDSTACK_DWARF_CFA_H 268