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 liblldb_UnwindPlan_h 10#define liblldb_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 21namespace 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 53class UnwindPlan { 54public: 55 class Row { 56 public: 57 class RegisterLocation { 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 }; 73 74 RegisterLocation() : m_type(unspecified), m_location() {} 75 76 bool operator==(const RegisterLocation &rhs) const; 77 78 bool operator!=(const RegisterLocation &rhs) const { 79 return !(*this == rhs); 80 } 81 82 void SetUnspecified() { m_type = unspecified; } 83 84 void SetUndefined() { m_type = undefined; } 85 86 void SetSame() { m_type = same; } 87 88 bool IsSame() const { return m_type == same; } 89 90 bool IsUnspecified() const { return m_type == unspecified; } 91 92 bool IsUndefined() const { return m_type == undefined; } 93 94 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; } 95 96 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; } 97 98 bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; } 99 100 bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; } 101 102 bool IsInOtherRegister() const { return m_type == inOtherRegister; } 103 104 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; } 105 106 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 107 108 void SetAtCFAPlusOffset(int32_t offset) { 109 m_type = atCFAPlusOffset; 110 m_location.offset = offset; 111 } 112 113 void SetIsCFAPlusOffset(int32_t offset) { 114 m_type = isCFAPlusOffset; 115 m_location.offset = offset; 116 } 117 118 void SetAtAFAPlusOffset(int32_t offset) { 119 m_type = atAFAPlusOffset; 120 m_location.offset = offset; 121 } 122 123 void SetIsAFAPlusOffset(int32_t offset) { 124 m_type = isAFAPlusOffset; 125 m_location.offset = offset; 126 } 127 128 void SetInRegister(uint32_t reg_num) { 129 m_type = inOtherRegister; 130 m_location.reg_num = reg_num; 131 } 132 133 uint32_t GetRegisterNumber() const { 134 if (m_type == inOtherRegister) 135 return m_location.reg_num; 136 return LLDB_INVALID_REGNUM; 137 } 138 139 RestoreType GetLocationType() const { return m_type; } 140 141 int32_t GetOffset() const { 142 switch(m_type) 143 { 144 case atCFAPlusOffset: 145 case isCFAPlusOffset: 146 case atAFAPlusOffset: 147 case isAFAPlusOffset: 148 return m_location.offset; 149 default: 150 return 0; 151 } 152 } 153 154 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 155 if (m_type == atDWARFExpression || m_type == isDWARFExpression) { 156 *opcodes = m_location.expr.opcodes; 157 len = m_location.expr.length; 158 } else { 159 *opcodes = nullptr; 160 len = 0; 161 } 162 } 163 164 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len); 165 166 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len); 167 168 const uint8_t *GetDWARFExpressionBytes() { 169 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 170 return m_location.expr.opcodes; 171 return nullptr; 172 } 173 174 int GetDWARFExpressionLength() { 175 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 176 return m_location.expr.length; 177 return 0; 178 } 179 180 void Dump(Stream &s, const UnwindPlan *unwind_plan, 181 const UnwindPlan::Row *row, Thread *thread, bool verbose) const; 182 183 private: 184 RestoreType m_type; // How do we locate this register? 185 union { 186 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset 187 int32_t offset; 188 // For m_type == inOtherRegister 189 uint32_t reg_num; // The register number 190 // For m_type == atDWARFExpression or m_type == isDWARFExpression 191 struct { 192 const uint8_t *opcodes; 193 uint16_t length; 194 } expr; 195 } m_location; 196 }; 197 198 class FAValue { 199 public: 200 enum ValueType { 201 unspecified, // not specified 202 isRegisterPlusOffset, // FA = register + offset 203 isRegisterDereferenced, // FA = [reg] 204 isDWARFExpression, // FA = eval(dwarf_expr) 205 isRaSearch, // FA = SP + offset + ??? 206 }; 207 208 FAValue() : m_type(unspecified), m_value() {} 209 210 bool operator==(const FAValue &rhs) const; 211 212 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); } 213 214 void SetUnspecified() { m_type = unspecified; } 215 216 bool IsUnspecified() const { return m_type == unspecified; } 217 218 void SetRaSearch(int32_t offset) { 219 m_type = isRaSearch; 220 m_value.ra_search_offset = offset; 221 } 222 223 bool IsRegisterPlusOffset() const { 224 return m_type == isRegisterPlusOffset; 225 } 226 227 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) { 228 m_type = isRegisterPlusOffset; 229 m_value.reg.reg_num = reg_num; 230 m_value.reg.offset = offset; 231 } 232 233 bool IsRegisterDereferenced() const { 234 return m_type == isRegisterDereferenced; 235 } 236 237 void SetIsRegisterDereferenced(uint32_t reg_num) { 238 m_type = isRegisterDereferenced; 239 m_value.reg.reg_num = reg_num; 240 } 241 242 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 243 244 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) { 245 m_type = isDWARFExpression; 246 m_value.expr.opcodes = opcodes; 247 m_value.expr.length = len; 248 } 249 250 uint32_t GetRegisterNumber() const { 251 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset) 252 return m_value.reg.reg_num; 253 return LLDB_INVALID_REGNUM; 254 } 255 256 ValueType GetValueType() const { return m_type; } 257 258 int32_t GetOffset() const { 259 switch (m_type) { 260 case isRegisterPlusOffset: 261 return m_value.reg.offset; 262 case isRaSearch: 263 return m_value.ra_search_offset; 264 default: 265 return 0; 266 } 267 } 268 269 void IncOffset(int32_t delta) { 270 if (m_type == isRegisterPlusOffset) 271 m_value.reg.offset += delta; 272 } 273 274 void SetOffset(int32_t offset) { 275 if (m_type == isRegisterPlusOffset) 276 m_value.reg.offset = offset; 277 } 278 279 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 280 if (m_type == isDWARFExpression) { 281 *opcodes = m_value.expr.opcodes; 282 len = m_value.expr.length; 283 } else { 284 *opcodes = nullptr; 285 len = 0; 286 } 287 } 288 289 const uint8_t *GetDWARFExpressionBytes() { 290 if (m_type == isDWARFExpression) 291 return m_value.expr.opcodes; 292 return nullptr; 293 } 294 295 int GetDWARFExpressionLength() { 296 if (m_type == isDWARFExpression) 297 return m_value.expr.length; 298 return 0; 299 } 300 301 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const; 302 303 private: 304 ValueType m_type; // How do we compute CFA value? 305 union { 306 struct { 307 // For m_type == isRegisterPlusOffset or m_type == 308 // isRegisterDereferenced 309 uint32_t reg_num; // The register number 310 // For m_type == isRegisterPlusOffset 311 int32_t offset; 312 } reg; 313 // For m_type == isDWARFExpression 314 struct { 315 const uint8_t *opcodes; 316 uint16_t length; 317 } expr; 318 // For m_type == isRaSearch 319 int32_t ra_search_offset; 320 } m_value; 321 }; // class FAValue 322 323 public: 324 Row(); 325 326 Row(const UnwindPlan::Row &rhs) = default; 327 328 bool operator==(const Row &rhs) const; 329 330 bool GetRegisterInfo(uint32_t reg_num, 331 RegisterLocation ®ister_location) const; 332 333 void SetRegisterInfo(uint32_t reg_num, 334 const RegisterLocation register_location); 335 336 void RemoveRegisterInfo(uint32_t reg_num); 337 338 lldb::addr_t GetOffset() const { return m_offset; } 339 340 void SetOffset(lldb::addr_t offset) { m_offset = offset; } 341 342 void SlideOffset(lldb::addr_t offset) { m_offset += offset; } 343 344 FAValue &GetCFAValue() { return m_cfa_value; } 345 346 FAValue &GetAFAValue() { return m_afa_value; } 347 348 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset, 349 bool can_replace); 350 351 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset, 352 bool can_replace); 353 354 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace, 355 bool can_replace_only_if_unspecified); 356 357 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace); 358 359 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num, 360 bool can_replace); 361 362 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace); 363 364 void Clear(); 365 366 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread, 367 lldb::addr_t base_addr) const; 368 369 protected: 370 typedef std::map<uint32_t, RegisterLocation> collection; 371 lldb::addr_t m_offset; // Offset into the function for this row 372 373 FAValue m_cfa_value; 374 FAValue m_afa_value; 375 collection m_register_locations; 376 }; // class Row 377 378public: 379 typedef std::shared_ptr<Row> RowSP; 380 381 UnwindPlan(lldb::RegisterKind reg_kind) 382 : m_row_list(), m_plan_valid_address_range(), m_register_kind(reg_kind), 383 m_return_addr_register(LLDB_INVALID_REGNUM), m_source_name(), 384 m_plan_is_sourced_from_compiler(eLazyBoolCalculate), 385 m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate), 386 m_plan_is_for_signal_trap(eLazyBoolCalculate), 387 m_lsda_address(), m_personality_func_addr() {} 388 389 // Performs a deep copy of the plan, including all the rows (expensive). 390 UnwindPlan(const UnwindPlan &rhs) 391 : m_plan_valid_address_range(rhs.m_plan_valid_address_range), 392 m_register_kind(rhs.m_register_kind), 393 m_return_addr_register(rhs.m_return_addr_register), 394 m_source_name(rhs.m_source_name), 395 m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler), 396 m_plan_is_valid_at_all_instruction_locations( 397 rhs.m_plan_is_valid_at_all_instruction_locations), 398 m_lsda_address(rhs.m_lsda_address), 399 m_personality_func_addr(rhs.m_personality_func_addr) { 400 m_row_list.reserve(rhs.m_row_list.size()); 401 for (const RowSP &row_sp : rhs.m_row_list) 402 m_row_list.emplace_back(new Row(*row_sp)); 403 } 404 405 ~UnwindPlan() = default; 406 407 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const; 408 409 void AppendRow(const RowSP &row_sp); 410 411 void InsertRow(const RowSP &row_sp, bool replace_existing = false); 412 413 // Returns a pointer to the best row for the given offset into the function's 414 // instructions. If offset is -1 it indicates that the function start is 415 // unknown - the final row in the UnwindPlan is returned. In practice, the 416 // UnwindPlan for a function with no known start address will be the 417 // architectural default UnwindPlan which will only have one row. 418 UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const; 419 420 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; } 421 422 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; } 423 424 void SetReturnAddressRegister(uint32_t regnum) { 425 m_return_addr_register = regnum; 426 } 427 428 uint32_t GetReturnAddressRegister(void) { return m_return_addr_register; } 429 430 uint32_t GetInitialCFARegister() const { 431 if (m_row_list.empty()) 432 return LLDB_INVALID_REGNUM; 433 return m_row_list.front()->GetCFAValue().GetRegisterNumber(); 434 } 435 436 // This UnwindPlan may not be valid at every address of the function span. 437 // For instance, a FastUnwindPlan will not be valid at the prologue setup 438 // instructions - only in the body of the function. 439 void SetPlanValidAddressRange(const AddressRange &range); 440 441 const AddressRange &GetAddressRange() const { 442 return m_plan_valid_address_range; 443 } 444 445 bool PlanValidAtAddress(Address addr); 446 447 bool IsValidRowIndex(uint32_t idx) const; 448 449 const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const; 450 451 const UnwindPlan::RowSP GetLastRow() const; 452 453 lldb_private::ConstString GetSourceName() const; 454 455 void SetSourceName(const char *); 456 457 // Was this UnwindPlan emitted by a compiler? 458 lldb_private::LazyBool GetSourcedFromCompiler() const { 459 return m_plan_is_sourced_from_compiler; 460 } 461 462 // Was this UnwindPlan emitted by a compiler? 463 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) { 464 m_plan_is_sourced_from_compiler = from_compiler; 465 } 466 467 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 468 // valid at call sites, e.g. for exception handling. 469 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const { 470 return m_plan_is_valid_at_all_instruction_locations; 471 } 472 473 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 474 // valid at call sites, e.g. for exception handling. 475 void SetUnwindPlanValidAtAllInstructions( 476 lldb_private::LazyBool valid_at_all_insn) { 477 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn; 478 } 479 480 // Is this UnwindPlan for a signal trap frame? If so, then its saved pc 481 // may have been set manually by the signal dispatch code and therefore 482 // not follow a call to the child frame. 483 lldb_private::LazyBool GetUnwindPlanForSignalTrap() const { 484 return m_plan_is_for_signal_trap; 485 } 486 487 void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) { 488 m_plan_is_for_signal_trap = is_for_signal_trap; 489 } 490 491 int GetRowCount() const; 492 493 void Clear() { 494 m_row_list.clear(); 495 m_plan_valid_address_range.Clear(); 496 m_register_kind = lldb::eRegisterKindDWARF; 497 m_source_name.Clear(); 498 m_plan_is_sourced_from_compiler = eLazyBoolCalculate; 499 m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate; 500 m_plan_is_for_signal_trap = eLazyBoolCalculate; 501 m_lsda_address.Clear(); 502 m_personality_func_addr.Clear(); 503 } 504 505 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const; 506 507 Address GetLSDAAddress() const { return m_lsda_address; } 508 509 void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; } 510 511 Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; } 512 513 void SetPersonalityFunctionPtr(Address presonality_func_ptr) { 514 m_personality_func_addr = presonality_func_ptr; 515 } 516 517private: 518 typedef std::vector<RowSP> collection; 519 collection m_row_list; 520 AddressRange m_plan_valid_address_range; 521 lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers 522 // are in terms of - will need to be 523 // translated to lldb native reg nums at unwind time 524 uint32_t m_return_addr_register; // The register that has the return address 525 // for the caller frame 526 // e.g. the lr on arm 527 lldb_private::ConstString 528 m_source_name; // for logging, where this UnwindPlan originated from 529 lldb_private::LazyBool m_plan_is_sourced_from_compiler; 530 lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations; 531 lldb_private::LazyBool m_plan_is_for_signal_trap; 532 533 Address m_lsda_address; // Where the language specific data area exists in the 534 // module - used 535 // in exception handling. 536 Address m_personality_func_addr; // The address of a pointer to the 537 // personality function - used in 538 // exception handling. 539}; // class UnwindPlan 540 541} // namespace lldb_private 542 543#endif // liblldb_UnwindPlan_h 544