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
2931using namespace lldb ;
3032using 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 ;
159169 m_forward_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.
213+ Address branch_address = inst.GetAddress ();
214+ branch_address.Slide (m_forward_branch_offset);
202215 if (m_forward_branch_offset != 0 &&
203- range.ContainsFileAddress (inst->GetAddress ().GetFileAddress () +
204- m_forward_branch_offset)) {
216+ range.ContainsFileAddress (branch_address.GetFileAddress ())) {
205217 if (auto [it, inserted] = saved_unwind_states.emplace (
206218 current_offset + m_forward_branch_offset, m_state);
207- inserted)
219+ inserted) {
208220 it->second .row .SetOffset (current_offset + m_forward_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)
0 commit comments