@@ -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+
5380bool 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 = ⦥
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 ;
0 commit comments