Skip to content

Commit 7ad2bcc

Browse files
[𝘀𝗽𝗿] initial version
Created using spr 1.3.7
2 parents e493e90 + 9e09134 commit 7ad2bcc

File tree

2 files changed

+48
-24
lines changed

2 files changed

+48
-24
lines changed

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

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "lldb/Utility/Log.h"
2626
#include "lldb/Utility/Status.h"
2727
#include "lldb/Utility/StreamString.h"
28+
#include "llvm/ADT/SmallSet.h"
29+
#include <deque>
2830

2931
using namespace lldb;
3032
using namespace lldb_private;
@@ -150,29 +152,38 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
150152
EmulateInstruction::InstructionCondition last_condition =
151153
EmulateInstruction::UnconditionalCondition;
152154

153-
for (const InstructionSP &inst : inst_list.Instructions()) {
154-
if (!inst)
155-
continue;
156-
DumpInstToLog(log, *inst, inst_list);
155+
std::deque<std::size_t> to_visit = {0};
156+
llvm::SmallSet<std::size_t, 0> enqueued = {0};
157+
158+
// Instructions reachable through jumps are inserted on the front.
159+
// The next instruction in inserted on the back.
160+
// Pop from the back to ensure non-branching instructions are visited
161+
// sequentially.
162+
while (!to_visit.empty()) {
163+
std::size_t current_index = to_visit.back();
164+
Instruction &inst = *inst_list.GetInstructionAtIndex(current_index);
165+
to_visit.pop_back();
166+
DumpInstToLog(log, inst, inst_list);
157167

158168
m_curr_row_modified = false;
159-
m_forward_branch_offset = 0;
169+
m_branch_offset = 0;
160170

161171
lldb::addr_t current_offset =
162-
inst->GetAddress().GetFileAddress() - base_addr;
172+
inst.GetAddress().GetFileAddress() - base_addr;
163173
auto it = saved_unwind_states.upper_bound(current_offset);
164174
assert(it != saved_unwind_states.begin() &&
165175
"Unwind row for the function entry missing");
166176
--it; // Move it to the row corresponding to the current offset
167177

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.
178+
// When state is forwarded through a branch, the offset of m_state.row is
179+
// different from the offset available in saved_unwind_states. Use the
180+
// forwarded state in this case, as the previous instruction may have been
181+
// an unconditional jump.
182+
// FIXME: this assignment can always be done unconditionally.
172183
if (it->second.row.GetOffset() != m_state.row.GetOffset())
173184
m_state = it->second;
174185

175-
m_inst_emulator_up->SetInstruction(inst->GetOpcode(), inst->GetAddress(),
186+
m_inst_emulator_up->SetInstruction(inst.GetOpcode(), inst.GetAddress(),
176187
nullptr);
177188
const EmulateInstruction::InstructionCondition new_condition =
178189
m_inst_emulator_up->GetInstructionCondition();
@@ -199,26 +210,39 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
199210

200211
// If the current instruction is a branch forward then save the current
201212
// 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)) {
213+
Address branch_address = inst.GetAddress();
214+
branch_address.Slide(m_branch_offset);
215+
if (m_branch_offset != 0 &&
216+
range.ContainsFileAddress(branch_address.GetFileAddress())) {
205217
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);
218+
current_offset + m_branch_offset, m_state);
219+
inserted) {
220+
it->second.row.SetOffset(current_offset + m_branch_offset);
221+
if (std::size_t dest_instr_index =
222+
inst_list.GetIndexOfInstructionAtAddress(branch_address);
223+
dest_instr_index < inst_list.GetSize()) {
224+
to_visit.push_front(dest_instr_index);
225+
enqueued.insert(dest_instr_index);
226+
}
227+
}
209228
}
210229

211230
// Were there any changes to the CFI while evaluating this instruction?
212231
if (m_curr_row_modified) {
213232
// Save the modified row if we don't already have a CFI row in the
214233
// current address
215234
const lldb::addr_t next_inst_offset =
216-
current_offset + inst->GetOpcode().GetByteSize();
235+
current_offset + inst.GetOpcode().GetByteSize();
217236
if (saved_unwind_states.count(next_inst_offset) == 0) {
218237
m_state.row.SetOffset(next_inst_offset);
219238
saved_unwind_states.emplace(next_inst_offset, m_state);
220239
}
221240
}
241+
242+
const size_t next_idx = current_index + 1;
243+
const bool never_enqueued = enqueued.insert(next_idx).second;
244+
if (never_enqueued && next_idx < inst_list.GetSize())
245+
to_visit.push_back(next_idx);
222246
}
223247

224248
for (auto &[_, state] : saved_unwind_states)
@@ -507,20 +531,20 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
507531
case EmulateInstruction::eContextRelativeBranchImmediate: {
508532
if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate &&
509533
context.info.ISAAndImmediate.unsigned_data32 > 0) {
510-
m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
534+
m_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
511535
} else if (context.GetInfoType() ==
512536
EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
513537
context.info.ISAAndImmediateSigned.signed_data32 > 0) {
514-
m_forward_branch_offset =
538+
m_branch_offset =
515539
context.info.ISAAndImmediateSigned.signed_data32;
516540
} else if (context.GetInfoType() ==
517541
EmulateInstruction::eInfoTypeImmediate &&
518542
context.info.unsigned_immediate > 0) {
519-
m_forward_branch_offset = context.info.unsigned_immediate;
543+
m_branch_offset = context.info.unsigned_immediate;
520544
} else if (context.GetInfoType() ==
521545
EmulateInstruction::eInfoTypeImmediateSigned &&
522546
context.info.signed_immediate > 0) {
523-
m_forward_branch_offset = context.info.signed_immediate;
547+
m_branch_offset = context.info.signed_immediate;
524548
}
525549
} break;
526550

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly {
6464
lldb_private::EmulateInstruction *inst_emulator)
6565
: UnwindAssembly(arch), m_inst_emulator_up(inst_emulator),
6666
m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr),
67-
m_curr_row_modified(false), m_forward_branch_offset(0) {
67+
m_curr_row_modified(false) {
6868
if (m_inst_emulator_up) {
6969
m_inst_emulator_up->SetBaton(this);
7070
m_inst_emulator_up->SetCallbacks(ReadMemory, WriteMemory, ReadRegister,
@@ -152,7 +152,7 @@ class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly {
152152
bool m_curr_row_modified;
153153
// The instruction is branching forward with the given offset. 0 value means
154154
// no branching.
155-
uint32_t m_forward_branch_offset;
155+
uint32_t m_branch_offset = 0;
156156
};
157157

158158
#endif // LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_INSTEMULATION_UNWINDASSEMBLYINSTEMULATION_H

0 commit comments

Comments
 (0)