Skip to content

Commit 1aaff52

Browse files
Merge pull request #11845 from felipepiovezan/felipe/UnwindAssemblyInstEmulation_gc63_p1
🍒 [lldb][nfc] Cherry pick NFC improvements to UnwindAssemblyInstEmulation
2 parents 2ed64ba + a24bec5 commit 1aaff52

File tree

4 files changed

+143
-131
lines changed

4 files changed

+143
-131
lines changed

lldb/include/lldb/Core/Disassembler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ class InstructionList {
297297

298298
lldb::InstructionSP GetInstructionAtIndex(size_t idx) const;
299299

300+
llvm::ArrayRef<lldb::InstructionSP> Instructions() const {
301+
return m_instructions;
302+
}
303+
300304
/// Get the instruction at the given address.
301305
///
302306
/// \return

lldb/include/lldb/Core/EmulateInstruction.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,8 +385,8 @@ class EmulateInstruction : public PluginInterface {
385385
const RegisterInfo *reg_info,
386386
const RegisterValue &reg_value);
387387

388-
// Type to represent the condition of an instruction. The UINT32 value is
389-
// reserved for the unconditional case and all other value can be used in an
388+
// Type to represent the condition of an instruction. The UINT32_MAX value is
389+
// reserved for the unconditional case and all other values can be used in an
390390
// architecture dependent way.
391391
typedef uint32_t InstructionCondition;
392392
static const InstructionCondition UnconditionalCondition = UINT32_MAX;

lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp

Lines changed: 131 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,33 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
5050
range, function_text.data(), function_text.size(), unwind_plan);
5151
}
5252

53+
static void DumpUnwindRowsToLog(Log *log, AddressRange range,
54+
const UnwindPlan &unwind_plan) {
55+
if (!log || !log->GetVerbose())
56+
return;
57+
StreamString strm;
58+
lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
59+
strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
60+
base_addr, base_addr + range.GetByteSize());
61+
unwind_plan.Dump(strm, nullptr, base_addr);
62+
log->PutString(strm.GetString());
63+
}
64+
65+
static void DumpInstToLog(Log *log, Instruction &inst,
66+
InstructionList inst_list) {
67+
if (!log || !log->GetVerbose())
68+
return;
69+
const bool show_address = true;
70+
const bool show_bytes = true;
71+
const bool show_control_flow_kind = false;
72+
StreamString strm;
73+
lldb_private::FormatEntity::Entry format;
74+
FormatEntity::Parse("${frame.pc}: ", format);
75+
inst.Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address, show_bytes,
76+
show_control_flow_kind, nullptr, nullptr, nullptr, &format, 0);
77+
log->PutString(strm.GetString());
78+
}
79+
5380
bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
5481
AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
5582
UnwindPlan &unwind_plan) {
@@ -82,146 +109,123 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
82109
m_range_ptr = &range;
83110
m_unwind_plan_ptr = &unwind_plan;
84111

85-
const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
86-
const bool show_address = true;
87-
const bool show_bytes = true;
88-
const bool show_control_flow_kind = false;
89-
90112
m_state.cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(
91113
unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister());
92114
m_state.fp_is_cfa = false;
93115
m_state.register_values.clear();
94116

95117
m_pushed_regs.clear();
96118

97-
// Initialize the CFA with a known value. In the 32 bit case it will be
98-
// 0x80000000, and in the 64 bit case 0x8000000000000000. We use the address
99-
// byte size to be safe for any future address sizes
100-
m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
101119
RegisterValue cfa_reg_value;
102-
cfa_reg_value.SetUInt(m_initial_sp, m_state.cfa_reg_info.byte_size);
120+
cfa_reg_value.SetUInt(m_initial_cfa, m_state.cfa_reg_info.byte_size);
103121
SetRegisterValue(m_state.cfa_reg_info, cfa_reg_value);
104122

105-
const InstructionList &inst_list = disasm_sp->GetInstructionList();
106-
const size_t num_instructions = inst_list.GetSize();
107-
108-
if (num_instructions > 0) {
109-
Instruction *inst = inst_list.GetInstructionAtIndex(0).get();
110-
const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
111-
112-
// Map for storing the unwind state at a given offset. When we see a forward
113-
// branch we add a new entry to this map with the actual unwind plan row and
114-
// register context for the target address of the branch as the current data
115-
// have to be valid for the target address of the branch too if we are in
116-
// the same function.
117-
std::map<lldb::addr_t, UnwindState> saved_unwind_states;
118-
119-
// Make a copy of the current instruction Row and save it in m_state so
120-
// we can add updates as we process the instructions.
121-
m_state.row = *unwind_plan.GetLastRow();
122-
123-
// Add the initial state to the save list with offset 0.
124-
auto condition_block_start_state =
125-
saved_unwind_states.emplace(0, m_state).first;
126-
127-
// The architecture dependent condition code of the last processed
128-
// instruction.
129-
EmulateInstruction::InstructionCondition last_condition =
130-
EmulateInstruction::UnconditionalCondition;
131-
132-
for (size_t idx = 0; idx < num_instructions; ++idx) {
133-
m_curr_row_modified = false;
134-
m_forward_branch_offset = 0;
135-
136-
inst = inst_list.GetInstructionAtIndex(idx).get();
137-
if (!inst)
138-
continue;
139-
140-
lldb::addr_t current_offset =
141-
inst->GetAddress().GetFileAddress() - base_addr;
142-
auto it = saved_unwind_states.upper_bound(current_offset);
143-
assert(it != saved_unwind_states.begin() &&
144-
"Unwind row for the function entry missing");
145-
--it; // Move it to the row corresponding to the current offset
146-
147-
// If the offset of m_curr_row don't match with the offset we see in
148-
// saved_unwind_states then we have to update current unwind state to
149-
// the saved values. It is happening after we processed an epilogue and a
150-
// return to caller instruction.
151-
if (it->second.row.GetOffset() != m_state.row.GetOffset())
152-
m_state = it->second;
153-
154-
m_inst_emulator_up->SetInstruction(inst->GetOpcode(), inst->GetAddress(),
155-
nullptr);
156-
157-
if (last_condition != m_inst_emulator_up->GetInstructionCondition()) {
158-
// If the last instruction was conditional with a different condition
159-
// than the current condition then restore the state.
160-
if (last_condition != EmulateInstruction::UnconditionalCondition) {
161-
m_state = condition_block_start_state->second;
162-
m_state.row.SetOffset(current_offset);
163-
// The last instruction might already created a row for this offset
164-
// and we want to overwrite it.
165-
saved_unwind_states.insert_or_assign(current_offset, m_state);
166-
}
123+
InstructionList inst_list = disasm_sp->GetInstructionList();
167124

168-
// We are starting a new conditional block at the actual offset
169-
condition_block_start_state = it;
170-
}
125+
if (inst_list.GetSize() == 0) {
126+
DumpUnwindRowsToLog(log, range, unwind_plan);
127+
return unwind_plan.GetRowCount() > 0;
128+
}
171129

172-
if (log && log->GetVerbose()) {
173-
StreamString strm;
174-
lldb_private::FormatEntity::Entry format;
175-
FormatEntity::Parse("${frame.pc}: ", format);
176-
inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
177-
show_bytes, show_control_flow_kind, nullptr, nullptr,
178-
nullptr, &format, 0);
179-
log->PutString(strm.GetString());
180-
}
130+
Instruction &first_inst = *inst_list.GetInstructionAtIndex(0);
131+
const lldb::addr_t base_addr = first_inst.GetAddress().GetFileAddress();
181132

182-
last_condition = m_inst_emulator_up->GetInstructionCondition();
133+
// Map for storing the unwind state at a given offset. When we see a forward
134+
// branch we add a new entry to this map with the actual unwind plan row and
135+
// register context for the target address of the branch as the current data
136+
// have to be valid for the target address of the branch too if we are in
137+
// the same function.
138+
std::map<lldb::addr_t, UnwindState> saved_unwind_states;
183139

184-
m_inst_emulator_up->EvaluateInstruction(
185-
eEmulateInstructionOptionIgnoreConditions);
140+
// Make a copy of the current instruction Row and save it in m_state so
141+
// we can add updates as we process the instructions.
142+
m_state.row = *unwind_plan.GetLastRow();
186143

187-
// If the current instruction is a branch forward then save the current
188-
// CFI information for the offset where we are branching.
189-
if (m_forward_branch_offset != 0 &&
190-
range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +
191-
m_forward_branch_offset)) {
192-
if (auto [it, inserted] = saved_unwind_states.emplace(
193-
current_offset + m_forward_branch_offset, m_state);
194-
inserted)
195-
it->second.row.SetOffset(current_offset + m_forward_branch_offset);
196-
}
144+
// Add the initial state to the save list with offset 0.
145+
auto condition_block_start_state =
146+
saved_unwind_states.emplace(0, m_state).first;
197147

198-
// Were there any changes to the CFI while evaluating this instruction?
199-
if (m_curr_row_modified) {
200-
// Save the modified row if we don't already have a CFI row in the
201-
// current address
202-
if (saved_unwind_states.count(current_offset +
203-
inst->GetOpcode().GetByteSize()) == 0) {
204-
m_state.row.SetOffset(current_offset +
205-
inst->GetOpcode().GetByteSize());
206-
saved_unwind_states.emplace(
207-
current_offset + inst->GetOpcode().GetByteSize(), m_state);
208-
}
148+
// The architecture dependent condition code of the last processed
149+
// instruction.
150+
EmulateInstruction::InstructionCondition last_condition =
151+
EmulateInstruction::UnconditionalCondition;
152+
153+
for (const InstructionSP &inst : inst_list.Instructions()) {
154+
if (!inst)
155+
continue;
156+
DumpInstToLog(log, *inst, inst_list);
157+
158+
m_curr_row_modified = false;
159+
m_forward_branch_offset = 0;
160+
161+
lldb::addr_t current_offset =
162+
inst->GetAddress().GetFileAddress() - base_addr;
163+
auto it = saved_unwind_states.upper_bound(current_offset);
164+
assert(it != saved_unwind_states.begin() &&
165+
"Unwind row for the function entry missing");
166+
--it; // Move it to the row corresponding to the current offset
167+
168+
// If the offset of m_state.row doesn't match with the offset we see in
169+
// saved_unwind_states then we have to update current unwind state to
170+
// the saved values. It is happening after we processed an epilogue and a
171+
// return to caller instruction.
172+
if (it->second.row.GetOffset() != m_state.row.GetOffset())
173+
m_state = it->second;
174+
175+
m_inst_emulator_up->SetInstruction(inst->GetOpcode(), inst->GetAddress(),
176+
nullptr);
177+
const EmulateInstruction::InstructionCondition new_condition =
178+
m_inst_emulator_up->GetInstructionCondition();
179+
180+
if (last_condition != new_condition) {
181+
// If the last instruction was conditional with a different condition
182+
// than the current condition then restore the state.
183+
if (last_condition != EmulateInstruction::UnconditionalCondition) {
184+
m_state = condition_block_start_state->second;
185+
m_state.row.SetOffset(current_offset);
186+
// The last instruction might already created a row for this offset
187+
// and we want to overwrite it.
188+
saved_unwind_states.insert_or_assign(current_offset, m_state);
209189
}
190+
191+
// We are starting a new conditional block at the actual offset
192+
condition_block_start_state = it;
210193
}
211-
for (auto &[_, state] : saved_unwind_states) {
212-
unwind_plan.InsertRow(std::move(state.row),
213-
/*replace_existing=*/true);
194+
195+
last_condition = new_condition;
196+
197+
m_inst_emulator_up->EvaluateInstruction(
198+
eEmulateInstructionOptionIgnoreConditions);
199+
200+
// If the current instruction is a branch forward then save the current
201+
// CFI information for the offset where we are branching.
202+
if (m_forward_branch_offset != 0 &&
203+
range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +
204+
m_forward_branch_offset)) {
205+
if (auto [it, inserted] = saved_unwind_states.emplace(
206+
current_offset + m_forward_branch_offset, m_state);
207+
inserted)
208+
it->second.row.SetOffset(current_offset + m_forward_branch_offset);
214209
}
215-
}
216210

217-
if (log && log->GetVerbose()) {
218-
StreamString strm;
219-
lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
220-
strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
221-
base_addr, base_addr + range.GetByteSize());
222-
unwind_plan.Dump(strm, nullptr, base_addr);
223-
log->PutString(strm.GetString());
211+
// Were there any changes to the CFI while evaluating this instruction?
212+
if (m_curr_row_modified) {
213+
// Save the modified row if we don't already have a CFI row in the
214+
// current address
215+
if (saved_unwind_states.count(current_offset +
216+
inst->GetOpcode().GetByteSize()) == 0) {
217+
m_state.row.SetOffset(current_offset + inst->GetOpcode().GetByteSize());
218+
saved_unwind_states.emplace(
219+
current_offset + inst->GetOpcode().GetByteSize(), m_state);
220+
}
221+
}
224222
}
223+
224+
for (auto &[_, state] : saved_unwind_states)
225+
unwind_plan.InsertRow(std::move(state.row),
226+
/*replace_existing=*/true);
227+
228+
DumpUnwindRowsToLog(log, range, unwind_plan);
225229
return unwind_plan.GetRowCount() > 0;
226230
}
227231

@@ -382,7 +386,7 @@ size_t UnwindAssemblyInstEmulation::WriteMemory(
382386
if (reg_num != LLDB_INVALID_REGNUM &&
383387
generic_regnum != LLDB_REGNUM_GENERIC_SP) {
384388
if (m_pushed_regs.try_emplace(reg_num, addr).second) {
385-
const int32_t offset = addr - m_initial_sp;
389+
const int32_t offset = addr - m_initial_cfa;
386390
m_state.row.SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
387391
/*can_replace=*/true);
388392
m_curr_row_modified = true;
@@ -503,12 +507,12 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
503507
case EmulateInstruction::eContextRelativeBranchImmediate: {
504508
if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate &&
505509
context.info.ISAAndImmediate.unsigned_data32 > 0) {
506-
m_forward_branch_offset =
507-
context.info.ISAAndImmediateSigned.signed_data32;
510+
m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
508511
} else if (context.GetInfoType() ==
509512
EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
510513
context.info.ISAAndImmediateSigned.signed_data32 > 0) {
511-
m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
514+
m_forward_branch_offset =
515+
context.info.ISAAndImmediateSigned.signed_data32;
512516
} else if (context.GetInfoType() ==
513517
EmulateInstruction::eInfoTypeImmediate &&
514518
context.info.unsigned_immediate > 0) {
@@ -549,7 +553,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
549553
sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()];
550554
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
551555
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
552-
cfa_reg_num, m_initial_sp - sp_reg_val.GetAsUInt64());
556+
cfa_reg_num, m_initial_cfa - sp_reg_val.GetAsUInt64());
553557
}
554558
}
555559
}
@@ -580,7 +584,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
580584
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
581585
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
582586
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
583-
cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
587+
cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
584588
m_curr_row_modified = true;
585589
}
586590
break;
@@ -593,7 +597,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
593597
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
594598
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
595599
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
596-
cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
600+
cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
597601
m_curr_row_modified = true;
598602
}
599603
break;
@@ -604,7 +608,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
604608
if (!m_state.fp_is_cfa) {
605609
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
606610
m_state.row.GetCFAValue().GetRegisterNumber(),
607-
m_initial_sp - reg_value.GetAsUInt64());
611+
m_initial_cfa - reg_value.GetAsUInt64());
608612
m_curr_row_modified = true;
609613
}
610614
break;

lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,17 @@ class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly {
6363
UnwindAssemblyInstEmulation(const lldb_private::ArchSpec &arch,
6464
lldb_private::EmulateInstruction *inst_emulator)
6565
: UnwindAssembly(arch), m_inst_emulator_up(inst_emulator),
66-
m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr), m_initial_sp(0),
66+
m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr),
6767
m_curr_row_modified(false), m_forward_branch_offset(0) {
6868
if (m_inst_emulator_up) {
6969
m_inst_emulator_up->SetBaton(this);
7070
m_inst_emulator_up->SetCallbacks(ReadMemory, WriteMemory, ReadRegister,
7171
WriteRegister);
7272
}
73+
// Initialize the CFA with a known value. In the 32 bit case it will be
74+
// 0x80000000, and in the 64 bit case 0x8000000000000000. We use the address
75+
// byte size to be safe for any future address sizes
76+
m_initial_cfa = (1ull << ((m_arch.GetAddressByteSize() * 8) - 1));
7377
}
7478

7579
static size_t
@@ -134,8 +138,8 @@ class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly {
134138
lldb_private::AddressRange *m_range_ptr;
135139
lldb_private::UnwindPlan *m_unwind_plan_ptr;
136140
UnwindState m_state;
141+
uint64_t m_initial_cfa;
137142
typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
138-
uint64_t m_initial_sp;
139143
PushedRegisterToAddrMap m_pushed_regs;
140144

141145
// While processing the instruction stream, we need to communicate some state

0 commit comments

Comments
 (0)