File indexing completed on 2026-05-10 08:42:53
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLDB_SYMBOL_UNWINDPLAN_H
0010 #define LLDB_SYMBOL_UNWINDPLAN_H
0011
0012 #include <map>
0013 #include <memory>
0014 #include <vector>
0015
0016 #include "lldb/Core/AddressRange.h"
0017 #include "lldb/Utility/ConstString.h"
0018 #include "lldb/Utility/Stream.h"
0019 #include "lldb/lldb-private.h"
0020
0021 namespace lldb_private {
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 class UnwindPlan {
0054 public:
0055 class Row {
0056 public:
0057 class AbstractRegisterLocation {
0058 public:
0059 enum RestoreType {
0060 unspecified,
0061
0062
0063 undefined,
0064 same,
0065 atCFAPlusOffset,
0066 isCFAPlusOffset,
0067 atAFAPlusOffset,
0068 isAFAPlusOffset,
0069 inOtherRegister,
0070 atDWARFExpression,
0071 isDWARFExpression,
0072 isConstant
0073 };
0074
0075 AbstractRegisterLocation() : m_location() {}
0076
0077 bool operator==(const AbstractRegisterLocation &rhs) const;
0078
0079 bool operator!=(const AbstractRegisterLocation &rhs) const {
0080 return !(*this == rhs);
0081 }
0082
0083 void SetUnspecified() { m_type = unspecified; }
0084
0085 void SetUndefined() { m_type = undefined; }
0086
0087 void SetSame() { m_type = same; }
0088
0089 bool IsSame() const { return m_type == same; }
0090
0091 bool IsUnspecified() const { return m_type == unspecified; }
0092
0093 bool IsUndefined() const { return m_type == undefined; }
0094
0095 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
0096
0097 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
0098
0099 bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
0100
0101 bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
0102
0103 bool IsInOtherRegister() const { return m_type == inOtherRegister; }
0104
0105 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
0106
0107 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
0108
0109 bool IsConstant() const { return m_type == isConstant; }
0110
0111 void SetIsConstant(uint64_t value) {
0112 m_type = isConstant;
0113 m_location.constant_value = value;
0114 }
0115
0116 uint64_t GetConstant() const { return m_location.constant_value; }
0117
0118 void SetAtCFAPlusOffset(int32_t offset) {
0119 m_type = atCFAPlusOffset;
0120 m_location.offset = offset;
0121 }
0122
0123 void SetIsCFAPlusOffset(int32_t offset) {
0124 m_type = isCFAPlusOffset;
0125 m_location.offset = offset;
0126 }
0127
0128 void SetAtAFAPlusOffset(int32_t offset) {
0129 m_type = atAFAPlusOffset;
0130 m_location.offset = offset;
0131 }
0132
0133 void SetIsAFAPlusOffset(int32_t offset) {
0134 m_type = isAFAPlusOffset;
0135 m_location.offset = offset;
0136 }
0137
0138 void SetInRegister(uint32_t reg_num) {
0139 m_type = inOtherRegister;
0140 m_location.reg_num = reg_num;
0141 }
0142
0143 uint32_t GetRegisterNumber() const {
0144 if (m_type == inOtherRegister)
0145 return m_location.reg_num;
0146 return LLDB_INVALID_REGNUM;
0147 }
0148
0149 RestoreType GetLocationType() const { return m_type; }
0150
0151 int32_t GetOffset() const {
0152 switch(m_type)
0153 {
0154 case atCFAPlusOffset:
0155 case isCFAPlusOffset:
0156 case atAFAPlusOffset:
0157 case isAFAPlusOffset:
0158 return m_location.offset;
0159 default:
0160 return 0;
0161 }
0162 }
0163
0164 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
0165 if (m_type == atDWARFExpression || m_type == isDWARFExpression) {
0166 *opcodes = m_location.expr.opcodes;
0167 len = m_location.expr.length;
0168 } else {
0169 *opcodes = nullptr;
0170 len = 0;
0171 }
0172 }
0173
0174 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len);
0175
0176 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len);
0177
0178 const uint8_t *GetDWARFExpressionBytes() {
0179 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
0180 return m_location.expr.opcodes;
0181 return nullptr;
0182 }
0183
0184 int GetDWARFExpressionLength() {
0185 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
0186 return m_location.expr.length;
0187 return 0;
0188 }
0189
0190 void Dump(Stream &s, const UnwindPlan *unwind_plan,
0191 const UnwindPlan::Row *row, Thread *thread, bool verbose) const;
0192
0193 private:
0194 RestoreType m_type = unspecified;
0195 union {
0196
0197 int32_t offset;
0198
0199 uint32_t reg_num;
0200
0201 struct {
0202 const uint8_t *opcodes;
0203 uint16_t length;
0204 } expr;
0205
0206 uint64_t constant_value;
0207 } m_location;
0208 };
0209
0210 class FAValue {
0211 public:
0212 enum ValueType {
0213 unspecified,
0214 isRegisterPlusOffset,
0215 isRegisterDereferenced,
0216 isDWARFExpression,
0217 isRaSearch,
0218 isConstant,
0219 };
0220
0221 FAValue() : m_value() {}
0222
0223 bool operator==(const FAValue &rhs) const;
0224
0225 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
0226
0227 void SetUnspecified() { m_type = unspecified; }
0228
0229 bool IsUnspecified() const { return m_type == unspecified; }
0230
0231 void SetRaSearch(int32_t offset) {
0232 m_type = isRaSearch;
0233 m_value.ra_search_offset = offset;
0234 }
0235
0236 bool IsRegisterPlusOffset() const {
0237 return m_type == isRegisterPlusOffset;
0238 }
0239
0240 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
0241 m_type = isRegisterPlusOffset;
0242 m_value.reg.reg_num = reg_num;
0243 m_value.reg.offset = offset;
0244 }
0245
0246 bool IsRegisterDereferenced() const {
0247 return m_type == isRegisterDereferenced;
0248 }
0249
0250 void SetIsRegisterDereferenced(uint32_t reg_num) {
0251 m_type = isRegisterDereferenced;
0252 m_value.reg.reg_num = reg_num;
0253 }
0254
0255 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
0256
0257 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
0258 m_type = isDWARFExpression;
0259 m_value.expr.opcodes = opcodes;
0260 m_value.expr.length = len;
0261 }
0262
0263 bool IsConstant() const { return m_type == isConstant; }
0264
0265 void SetIsConstant(uint64_t constant) {
0266 m_type = isConstant;
0267 m_value.constant = constant;
0268 }
0269
0270 uint64_t GetConstant() const { return m_value.constant; }
0271
0272 uint32_t GetRegisterNumber() const {
0273 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
0274 return m_value.reg.reg_num;
0275 return LLDB_INVALID_REGNUM;
0276 }
0277
0278 ValueType GetValueType() const { return m_type; }
0279
0280 int32_t GetOffset() const {
0281 switch (m_type) {
0282 case isRegisterPlusOffset:
0283 return m_value.reg.offset;
0284 case isRaSearch:
0285 return m_value.ra_search_offset;
0286 default:
0287 return 0;
0288 }
0289 }
0290
0291 void IncOffset(int32_t delta) {
0292 if (m_type == isRegisterPlusOffset)
0293 m_value.reg.offset += delta;
0294 }
0295
0296 void SetOffset(int32_t offset) {
0297 if (m_type == isRegisterPlusOffset)
0298 m_value.reg.offset = offset;
0299 }
0300
0301 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
0302 if (m_type == isDWARFExpression) {
0303 *opcodes = m_value.expr.opcodes;
0304 len = m_value.expr.length;
0305 } else {
0306 *opcodes = nullptr;
0307 len = 0;
0308 }
0309 }
0310
0311 const uint8_t *GetDWARFExpressionBytes() {
0312 if (m_type == isDWARFExpression)
0313 return m_value.expr.opcodes;
0314 return nullptr;
0315 }
0316
0317 int GetDWARFExpressionLength() {
0318 if (m_type == isDWARFExpression)
0319 return m_value.expr.length;
0320 return 0;
0321 }
0322
0323 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
0324
0325 private:
0326 ValueType m_type = unspecified;
0327 union {
0328 struct {
0329
0330
0331 uint32_t reg_num;
0332
0333 int32_t offset;
0334 } reg;
0335
0336 struct {
0337 const uint8_t *opcodes;
0338 uint16_t length;
0339 } expr;
0340
0341 int32_t ra_search_offset;
0342
0343 uint64_t constant;
0344 } m_value;
0345 };
0346
0347 Row();
0348
0349 bool operator==(const Row &rhs) const;
0350
0351 bool GetRegisterInfo(uint32_t reg_num,
0352 AbstractRegisterLocation ®ister_location) const;
0353
0354 void SetRegisterInfo(uint32_t reg_num,
0355 const AbstractRegisterLocation register_location);
0356
0357 void RemoveRegisterInfo(uint32_t reg_num);
0358
0359 lldb::addr_t GetOffset() const { return m_offset; }
0360
0361 void SetOffset(lldb::addr_t offset) { m_offset = offset; }
0362
0363 void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
0364
0365 FAValue &GetCFAValue() { return m_cfa_value; }
0366
0367 FAValue &GetAFAValue() { return m_afa_value; }
0368
0369 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
0370 bool can_replace);
0371
0372 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
0373 bool can_replace);
0374
0375 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
0376 bool can_replace_only_if_unspecified);
0377
0378 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
0379
0380 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
0381 bool can_replace);
0382
0383 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
0384
0385
0386
0387
0388 bool SetRegisterLocationToIsDWARFExpression(uint32_t reg_num,
0389 const uint8_t *opcodes,
0390 uint32_t len, bool can_replace);
0391
0392 bool SetRegisterLocationToIsConstant(uint32_t reg_num, uint64_t constant,
0393 bool can_replace);
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406 void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) {
0407 m_unspecified_registers_are_undefined = unspec_is_undef;
0408 }
0409
0410 bool GetUnspecifiedRegistersAreUndefined() {
0411 return m_unspecified_registers_are_undefined;
0412 }
0413
0414 void Clear();
0415
0416 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
0417 lldb::addr_t base_addr) const;
0418
0419 protected:
0420 typedef std::map<uint32_t, AbstractRegisterLocation> collection;
0421 lldb::addr_t m_offset = 0;
0422
0423 FAValue m_cfa_value;
0424 FAValue m_afa_value;
0425 collection m_register_locations;
0426 bool m_unspecified_registers_are_undefined = false;
0427 };
0428
0429 typedef std::shared_ptr<Row> RowSP;
0430
0431 UnwindPlan(lldb::RegisterKind reg_kind)
0432 : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM),
0433 m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
0434 m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
0435 m_plan_is_for_signal_trap(eLazyBoolCalculate) {}
0436
0437
0438 UnwindPlan(const UnwindPlan &rhs)
0439 : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
0440 m_register_kind(rhs.m_register_kind),
0441 m_return_addr_register(rhs.m_return_addr_register),
0442 m_source_name(rhs.m_source_name),
0443 m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
0444 m_plan_is_valid_at_all_instruction_locations(
0445 rhs.m_plan_is_valid_at_all_instruction_locations),
0446 m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap),
0447 m_lsda_address(rhs.m_lsda_address),
0448 m_personality_func_addr(rhs.m_personality_func_addr) {
0449 m_row_list.reserve(rhs.m_row_list.size());
0450 for (const RowSP &row_sp : rhs.m_row_list)
0451 m_row_list.emplace_back(new Row(*row_sp));
0452 }
0453
0454 ~UnwindPlan() = default;
0455
0456 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
0457
0458 void AppendRow(const RowSP &row_sp);
0459
0460 void InsertRow(const RowSP &row_sp, bool replace_existing = false);
0461
0462
0463
0464
0465
0466
0467 UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
0468
0469 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
0470
0471 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
0472
0473 void SetReturnAddressRegister(uint32_t regnum) {
0474 m_return_addr_register = regnum;
0475 }
0476
0477 uint32_t GetReturnAddressRegister() { return m_return_addr_register; }
0478
0479 uint32_t GetInitialCFARegister() const {
0480 if (m_row_list.empty())
0481 return LLDB_INVALID_REGNUM;
0482 return m_row_list.front()->GetCFAValue().GetRegisterNumber();
0483 }
0484
0485
0486
0487
0488 void SetPlanValidAddressRange(const AddressRange &range);
0489
0490 const AddressRange &GetAddressRange() const {
0491 return m_plan_valid_address_range;
0492 }
0493
0494 bool PlanValidAtAddress(Address addr);
0495
0496 bool IsValidRowIndex(uint32_t idx) const;
0497
0498 const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
0499
0500 const UnwindPlan::RowSP GetLastRow() const;
0501
0502 lldb_private::ConstString GetSourceName() const;
0503
0504 void SetSourceName(const char *);
0505
0506
0507 lldb_private::LazyBool GetSourcedFromCompiler() const {
0508 return m_plan_is_sourced_from_compiler;
0509 }
0510
0511
0512 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
0513 m_plan_is_sourced_from_compiler = from_compiler;
0514 }
0515
0516
0517
0518 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
0519 return m_plan_is_valid_at_all_instruction_locations;
0520 }
0521
0522
0523
0524 void SetUnwindPlanValidAtAllInstructions(
0525 lldb_private::LazyBool valid_at_all_insn) {
0526 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
0527 }
0528
0529
0530
0531
0532 lldb_private::LazyBool GetUnwindPlanForSignalTrap() const {
0533 return m_plan_is_for_signal_trap;
0534 }
0535
0536 void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) {
0537 m_plan_is_for_signal_trap = is_for_signal_trap;
0538 }
0539
0540 int GetRowCount() const;
0541
0542 void Clear() {
0543 m_row_list.clear();
0544 m_plan_valid_address_range.Clear();
0545 m_register_kind = lldb::eRegisterKindDWARF;
0546 m_source_name.Clear();
0547 m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
0548 m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
0549 m_plan_is_for_signal_trap = eLazyBoolCalculate;
0550 m_lsda_address.Clear();
0551 m_personality_func_addr.Clear();
0552 }
0553
0554 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
0555
0556 Address GetLSDAAddress() const { return m_lsda_address; }
0557
0558 void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
0559
0560 Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
0561
0562 void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
0563 m_personality_func_addr = presonality_func_ptr;
0564 }
0565
0566 private:
0567 typedef std::vector<RowSP> collection;
0568 collection m_row_list;
0569 AddressRange m_plan_valid_address_range;
0570 lldb::RegisterKind m_register_kind;
0571
0572
0573 uint32_t m_return_addr_register;
0574
0575
0576 lldb_private::ConstString
0577 m_source_name;
0578 lldb_private::LazyBool m_plan_is_sourced_from_compiler;
0579 lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
0580 lldb_private::LazyBool m_plan_is_for_signal_trap;
0581
0582 Address m_lsda_address;
0583
0584
0585 Address m_personality_func_addr;
0586
0587
0588 };
0589
0590 }
0591
0592 #endif