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