1 //===-- UnwindPlan.h --------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_SYMBOL_UNWINDPLAN_H 10 #define LLDB_SYMBOL_UNWINDPLAN_H 11 12 #include <map> 13 #include <memory> 14 #include <vector> 15 16 #include "lldb/Core/AddressRange.h" 17 #include "lldb/Utility/ConstString.h" 18 #include "lldb/Utility/Stream.h" 19 #include "lldb/lldb-private.h" 20 21 namespace lldb_private { 22 23 // The UnwindPlan object specifies how to unwind out of a function - where this 24 // function saves the caller's register values before modifying them (for non- 25 // volatile aka saved registers) and how to find this frame's Canonical Frame 26 // Address (CFA) or Aligned Frame Address (AFA). 27 28 // CFA is a DWARF's Canonical Frame Address. 29 // Most commonly, registers are saved on the stack, offset some bytes from the 30 // Canonical Frame Address, or CFA, which is the starting address of this 31 // function's stack frame (the CFA is same as the eh_frame's CFA, whatever that 32 // may be on a given architecture). The CFA address for the stack frame does 33 // not change during the lifetime of the function. 34 35 // AFA is an artificially introduced Aligned Frame Address. 36 // It is used only for stack frames with realignment (e.g. when some of the 37 // locals has an alignment requirement higher than the stack alignment right 38 // after the function call). It is used to access register values saved on the 39 // stack after the realignment (and so they are inaccessible through the CFA). 40 // AFA usually equals the stack pointer value right after the realignment. 41 42 // Internally, the UnwindPlan is structured as a vector of register locations 43 // organized by code address in the function, showing which registers have been 44 // saved at that point and where they are saved. It can be thought of as the 45 // expanded table form of the DWARF CFI encoded information. 46 47 // Other unwind information sources will be converted into UnwindPlans before 48 // being added to a FuncUnwinders object. The unwind source may be an eh_frame 49 // FDE, a DWARF debug_frame FDE, or assembly language based prologue analysis. 50 // The UnwindPlan is the canonical form of this information that the unwinder 51 // code will use when walking the stack. 52 53 class UnwindPlan { 54 public: 55 class Row { 56 public: 57 class AbstractRegisterLocation { 58 public: 59 enum RestoreType { 60 unspecified, // not specified, we may be able to assume this 61 // is the same register. gcc doesn't specify all 62 // initial values so we really don't know... 63 undefined, // reg is not available, e.g. volatile reg 64 same, // reg is unchanged 65 atCFAPlusOffset, // reg = deref(CFA + offset) 66 isCFAPlusOffset, // reg = CFA + offset 67 atAFAPlusOffset, // reg = deref(AFA + offset) 68 isAFAPlusOffset, // reg = AFA + offset 69 inOtherRegister, // reg = other reg 70 atDWARFExpression, // reg = deref(eval(dwarf_expr)) 71 isDWARFExpression, // reg = eval(dwarf_expr) 72 isConstant // reg = constant 73 }; 74 75 AbstractRegisterLocation() : m_location() {} 76 77 bool operator==(const AbstractRegisterLocation &rhs) const; 78 79 bool operator!=(const AbstractRegisterLocation &rhs) const { 80 return !(*this == rhs); 81 } 82 83 void SetUnspecified() { m_type = unspecified; } 84 85 void SetUndefined() { m_type = undefined; } 86 87 void SetSame() { m_type = same; } 88 89 bool IsSame() const { return m_type == same; } 90 91 bool IsUnspecified() const { return m_type == unspecified; } 92 93 bool IsUndefined() const { return m_type == undefined; } 94 95 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; } 96 97 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; } 98 99 bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; } 100 101 bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; } 102 103 bool IsInOtherRegister() const { return m_type == inOtherRegister; } 104 105 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; } 106 107 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 108 109 bool IsConstant() const { return m_type == isConstant; } 110 111 void SetIsConstant(uint64_t value) { 112 m_type = isConstant; 113 m_location.constant_value = value; 114 } 115 116 uint64_t GetConstant() const { return m_location.constant_value; } 117 118 void SetAtCFAPlusOffset(int32_t offset) { 119 m_type = atCFAPlusOffset; 120 m_location.offset = offset; 121 } 122 123 void SetIsCFAPlusOffset(int32_t offset) { 124 m_type = isCFAPlusOffset; 125 m_location.offset = offset; 126 } 127 128 void SetAtAFAPlusOffset(int32_t offset) { 129 m_type = atAFAPlusOffset; 130 m_location.offset = offset; 131 } 132 133 void SetIsAFAPlusOffset(int32_t offset) { 134 m_type = isAFAPlusOffset; 135 m_location.offset = offset; 136 } 137 138 void SetInRegister(uint32_t reg_num) { 139 m_type = inOtherRegister; 140 m_location.reg_num = reg_num; 141 } 142 143 uint32_t GetRegisterNumber() const { 144 if (m_type == inOtherRegister) 145 return m_location.reg_num; 146 return LLDB_INVALID_REGNUM; 147 } 148 149 RestoreType GetLocationType() const { return m_type; } 150 151 int32_t GetOffset() const { 152 switch(m_type) 153 { 154 case atCFAPlusOffset: 155 case isCFAPlusOffset: 156 case atAFAPlusOffset: 157 case isAFAPlusOffset: 158 return m_location.offset; 159 default: 160 return 0; 161 } 162 } 163 164 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 165 if (m_type == atDWARFExpression || m_type == isDWARFExpression) { 166 *opcodes = m_location.expr.opcodes; 167 len = m_location.expr.length; 168 } else { 169 *opcodes = nullptr; 170 len = 0; 171 } 172 } 173 174 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len); 175 176 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len); 177 178 const uint8_t *GetDWARFExpressionBytes() { 179 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 180 return m_location.expr.opcodes; 181 return nullptr; 182 } 183 184 int GetDWARFExpressionLength() { 185 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 186 return m_location.expr.length; 187 return 0; 188 } 189 190 void Dump(Stream &s, const UnwindPlan *unwind_plan, 191 const UnwindPlan::Row *row, Thread *thread, bool verbose) const; 192 193 private: 194 RestoreType m_type = unspecified; // How do we locate this register? 195 union { 196 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset 197 int32_t offset; 198 // For m_type == inOtherRegister 199 uint32_t reg_num; // The register number 200 // For m_type == atDWARFExpression or m_type == isDWARFExpression 201 struct { 202 const uint8_t *opcodes; 203 uint16_t length; 204 } expr; 205 // For m_type == isConstant 206 uint64_t constant_value; 207 } m_location; 208 }; 209 210 class FAValue { 211 public: 212 enum ValueType { 213 unspecified, // not specified 214 isRegisterPlusOffset, // FA = register + offset 215 isRegisterDereferenced, // FA = [reg] 216 isDWARFExpression, // FA = eval(dwarf_expr) 217 isRaSearch, // FA = SP + offset + ??? 218 isConstant, // FA = constant 219 }; 220 221 FAValue() : m_value() {} 222 223 bool operator==(const FAValue &rhs) const; 224 225 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); } 226 227 void SetUnspecified() { m_type = unspecified; } 228 229 bool IsUnspecified() const { return m_type == unspecified; } 230 231 void SetRaSearch(int32_t offset) { 232 m_type = isRaSearch; 233 m_value.ra_search_offset = offset; 234 } 235 236 bool IsRegisterPlusOffset() const { 237 return m_type == isRegisterPlusOffset; 238 } 239 240 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) { 241 m_type = isRegisterPlusOffset; 242 m_value.reg.reg_num = reg_num; 243 m_value.reg.offset = offset; 244 } 245 246 bool IsRegisterDereferenced() const { 247 return m_type == isRegisterDereferenced; 248 } 249 250 void SetIsRegisterDereferenced(uint32_t reg_num) { 251 m_type = isRegisterDereferenced; 252 m_value.reg.reg_num = reg_num; 253 } 254 255 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 256 257 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) { 258 m_type = isDWARFExpression; 259 m_value.expr.opcodes = opcodes; 260 m_value.expr.length = len; 261 } 262 263 bool IsConstant() const { return m_type == isConstant; } 264 265 void SetIsConstant(uint64_t constant) { 266 m_type = isConstant; 267 m_value.constant = constant; 268 } 269 270 uint64_t GetConstant() const { return m_value.constant; } 271 272 uint32_t GetRegisterNumber() const { 273 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset) 274 return m_value.reg.reg_num; 275 return LLDB_INVALID_REGNUM; 276 } 277 278 ValueType GetValueType() const { return m_type; } 279 280 int32_t GetOffset() const { 281 switch (m_type) { 282 case isRegisterPlusOffset: 283 return m_value.reg.offset; 284 case isRaSearch: 285 return m_value.ra_search_offset; 286 default: 287 return 0; 288 } 289 } 290 291 void IncOffset(int32_t delta) { 292 if (m_type == isRegisterPlusOffset) 293 m_value.reg.offset += delta; 294 } 295 296 void SetOffset(int32_t offset) { 297 if (m_type == isRegisterPlusOffset) 298 m_value.reg.offset = offset; 299 } 300 301 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 302 if (m_type == isDWARFExpression) { 303 *opcodes = m_value.expr.opcodes; 304 len = m_value.expr.length; 305 } else { 306 *opcodes = nullptr; 307 len = 0; 308 } 309 } 310 311 const uint8_t *GetDWARFExpressionBytes() { 312 if (m_type == isDWARFExpression) 313 return m_value.expr.opcodes; 314 return nullptr; 315 } 316 317 int GetDWARFExpressionLength() { 318 if (m_type == isDWARFExpression) 319 return m_value.expr.length; 320 return 0; 321 } 322 323 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const; 324 325 private: 326 ValueType m_type = unspecified; // How do we compute CFA value? 327 union { 328 struct { 329 // For m_type == isRegisterPlusOffset or m_type == 330 // isRegisterDereferenced 331 uint32_t reg_num; // The register number 332 // For m_type == isRegisterPlusOffset 333 int32_t offset; 334 } reg; 335 // For m_type == isDWARFExpression 336 struct { 337 const uint8_t *opcodes; 338 uint16_t length; 339 } expr; 340 // For m_type == isRaSearch 341 int32_t ra_search_offset; 342 // For m_type = isConstant 343 uint64_t constant; 344 } m_value; 345 }; // class FAValue 346 347 Row(); 348 349 bool operator==(const Row &rhs) const; 350 351 bool GetRegisterInfo(uint32_t reg_num, 352 AbstractRegisterLocation ®ister_location) const; 353 354 void SetRegisterInfo(uint32_t reg_num, 355 const AbstractRegisterLocation register_location); 356 357 void RemoveRegisterInfo(uint32_t reg_num); 358 359 lldb::addr_t GetOffset() const { return m_offset; } 360 361 void SetOffset(lldb::addr_t offset) { m_offset = offset; } 362 363 void SlideOffset(lldb::addr_t offset) { m_offset += offset; } 364 365 FAValue &GetCFAValue() { return m_cfa_value; } 366 367 FAValue &GetAFAValue() { return m_afa_value; } 368 369 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset, 370 bool can_replace); 371 372 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset, 373 bool can_replace); 374 375 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace, 376 bool can_replace_only_if_unspecified); 377 378 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace); 379 380 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num, 381 bool can_replace); 382 383 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace); 384 385 /// This method does not make a copy of the \a opcodes memory, it is 386 /// assumed to have the same lifetime as the Module this UnwindPlan will 387 /// be registered in. 388 bool SetRegisterLocationToIsDWARFExpression(uint32_t reg_num, 389 const uint8_t *opcodes, 390 uint32_t len, bool can_replace); 391 392 bool SetRegisterLocationToIsConstant(uint32_t reg_num, uint64_t constant, 393 bool can_replace); 394 395 // When this UnspecifiedRegistersAreUndefined mode is 396 // set, any register that is not specified by this Row will 397 // be described as Undefined. 398 // This will prevent the unwinder from iterating down the 399 // stack looking for a spill location, or a live register value 400 // at frame 0. 401 // It would be used for an UnwindPlan row where we can't track 402 // spilled registers -- for instance a jitted stack frame where 403 // we have no unwind information or start address -- and registers 404 // MAY have been spilled and overwritten, so providing the 405 // spilled/live value from a newer frame may show an incorrect value. 406 void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) { 407 m_unspecified_registers_are_undefined = unspec_is_undef; 408 } 409 410 bool GetUnspecifiedRegistersAreUndefined() { 411 return m_unspecified_registers_are_undefined; 412 } 413 414 void Clear(); 415 416 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread, 417 lldb::addr_t base_addr) const; 418 419 protected: 420 typedef std::map<uint32_t, AbstractRegisterLocation> collection; 421 lldb::addr_t m_offset = 0; // Offset into the function for this row 422 423 FAValue m_cfa_value; 424 FAValue m_afa_value; 425 collection m_register_locations; 426 bool m_unspecified_registers_are_undefined = false; 427 }; // class Row 428 429 typedef std::shared_ptr<Row> RowSP; 430 431 UnwindPlan(lldb::RegisterKind reg_kind) 432 : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM), 433 m_plan_is_sourced_from_compiler(eLazyBoolCalculate), 434 m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate), 435 m_plan_is_for_signal_trap(eLazyBoolCalculate) {} 436 437 // Performs a deep copy of the plan, including all the rows (expensive). 438 UnwindPlan(const UnwindPlan &rhs) 439 : m_plan_valid_address_range(rhs.m_plan_valid_address_range), 440 m_register_kind(rhs.m_register_kind), 441 m_return_addr_register(rhs.m_return_addr_register), 442 m_source_name(rhs.m_source_name), 443 m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler), 444 m_plan_is_valid_at_all_instruction_locations( 445 rhs.m_plan_is_valid_at_all_instruction_locations), 446 m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap), 447 m_lsda_address(rhs.m_lsda_address), 448 m_personality_func_addr(rhs.m_personality_func_addr) { 449 m_row_list.reserve(rhs.m_row_list.size()); 450 for (const RowSP &row_sp : rhs.m_row_list) 451 m_row_list.emplace_back(new Row(*row_sp)); 452 } 453 454 ~UnwindPlan() = default; 455 456 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const; 457 458 void AppendRow(const RowSP &row_sp); 459 460 void InsertRow(const RowSP &row_sp, bool replace_existing = false); 461 462 // Returns a pointer to the best row for the given offset into the function's 463 // instructions. If offset is -1 it indicates that the function start is 464 // unknown - the final row in the UnwindPlan is returned. In practice, the 465 // UnwindPlan for a function with no known start address will be the 466 // architectural default UnwindPlan which will only have one row. 467 UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const; 468 469 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; } 470 471 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; } 472 473 void SetReturnAddressRegister(uint32_t regnum) { 474 m_return_addr_register = regnum; 475 } 476 477 uint32_t GetReturnAddressRegister() { return m_return_addr_register; } 478 479 uint32_t GetInitialCFARegister() const { 480 if (m_row_list.empty()) 481 return LLDB_INVALID_REGNUM; 482 return m_row_list.front()->GetCFAValue().GetRegisterNumber(); 483 } 484 485 // This UnwindPlan may not be valid at every address of the function span. 486 // For instance, a FastUnwindPlan will not be valid at the prologue setup 487 // instructions - only in the body of the function. 488 void SetPlanValidAddressRange(const AddressRange &range); 489 490 const AddressRange &GetAddressRange() const { 491 return m_plan_valid_address_range; 492 } 493 494 bool PlanValidAtAddress(Address addr); 495 496 bool IsValidRowIndex(uint32_t idx) const; 497 498 const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const; 499 500 const UnwindPlan::RowSP GetLastRow() const; 501 502 lldb_private::ConstString GetSourceName() const; 503 504 void SetSourceName(const char *); 505 506 // Was this UnwindPlan emitted by a compiler? 507 lldb_private::LazyBool GetSourcedFromCompiler() const { 508 return m_plan_is_sourced_from_compiler; 509 } 510 511 // Was this UnwindPlan emitted by a compiler? 512 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) { 513 m_plan_is_sourced_from_compiler = from_compiler; 514 } 515 516 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 517 // valid at call sites, e.g. for exception handling. 518 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const { 519 return m_plan_is_valid_at_all_instruction_locations; 520 } 521 522 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 523 // valid at call sites, e.g. for exception handling. 524 void SetUnwindPlanValidAtAllInstructions( 525 lldb_private::LazyBool valid_at_all_insn) { 526 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn; 527 } 528 529 // Is this UnwindPlan for a signal trap frame? If so, then its saved pc 530 // may have been set manually by the signal dispatch code and therefore 531 // not follow a call to the child frame. 532 lldb_private::LazyBool GetUnwindPlanForSignalTrap() const { 533 return m_plan_is_for_signal_trap; 534 } 535 536 void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) { 537 m_plan_is_for_signal_trap = is_for_signal_trap; 538 } 539 540 int GetRowCount() const; 541 542 void Clear() { 543 m_row_list.clear(); 544 m_plan_valid_address_range.Clear(); 545 m_register_kind = lldb::eRegisterKindDWARF; 546 m_source_name.Clear(); 547 m_plan_is_sourced_from_compiler = eLazyBoolCalculate; 548 m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate; 549 m_plan_is_for_signal_trap = eLazyBoolCalculate; 550 m_lsda_address.Clear(); 551 m_personality_func_addr.Clear(); 552 } 553 554 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const; 555 556 Address GetLSDAAddress() const { return m_lsda_address; } 557 558 void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; } 559 560 Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; } 561 562 void SetPersonalityFunctionPtr(Address presonality_func_ptr) { 563 m_personality_func_addr = presonality_func_ptr; 564 } 565 566 private: 567 typedef std::vector<RowSP> collection; 568 collection m_row_list; 569 AddressRange m_plan_valid_address_range; 570 lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers 571 // are in terms of - will need to be 572 // translated to lldb native reg nums at unwind time 573 uint32_t m_return_addr_register; // The register that has the return address 574 // for the caller frame 575 // e.g. the lr on arm 576 lldb_private::ConstString 577 m_source_name; // for logging, where this UnwindPlan originated from 578 lldb_private::LazyBool m_plan_is_sourced_from_compiler; 579 lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations; 580 lldb_private::LazyBool m_plan_is_for_signal_trap; 581 582 Address m_lsda_address; // Where the language specific data area exists in the 583 // module - used 584 // in exception handling. 585 Address m_personality_func_addr; // The address of a pointer to the 586 // personality function - used in 587 // exception handling. 588 }; // class UnwindPlan 589 590 } // namespace lldb_private 591 592 #endif // LLDB_SYMBOL_UNWINDPLAN_H 593