@@ -50,6 +50,18 @@ 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+
5365bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (
5466 AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
5567 UnwindPlan &unwind_plan) {
@@ -105,123 +117,118 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
105117 const InstructionList &inst_list = disasm_sp->GetInstructionList ();
106118 const size_t num_instructions = inst_list.GetSize ();
107119
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_state.row doesn'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- }
120+ if (num_instructions == 0 ) {
121+ DumpUnwindRowsToLog (log, range, unwind_plan);
122+ return unwind_plan.GetRowCount () > 0 ;
123+ }
167124
168- // We are starting a new conditional block at the actual offset
169- condition_block_start_state = it;
170- }
125+ Instruction *inst = inst_list.GetInstructionAtIndex (0 ).get ();
126+ const lldb::addr_t base_addr = inst->GetAddress ().GetFileAddress ();
171127
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- }
128+ // Map for storing the unwind state at a given offset. When we see a forward
129+ // branch we add a new entry to this map with the actual unwind plan row and
130+ // register context for the target address of the branch as the current data
131+ // have to be valid for the target address of the branch too if we are in
132+ // the same function.
133+ std::map<lldb::addr_t , UnwindState> saved_unwind_states;
181134
182- last_condition = m_inst_emulator_up->GetInstructionCondition ();
135+ // Make a copy of the current instruction Row and save it in m_state so
136+ // we can add updates as we process the instructions.
137+ m_state.row = *unwind_plan.GetLastRow ();
183138
184- m_inst_emulator_up->EvaluateInstruction (
185- eEmulateInstructionOptionIgnoreConditions);
139+ // Add the initial state to the save list with offset 0.
140+ auto condition_block_start_state =
141+ saved_unwind_states.emplace (0 , m_state).first ;
186142
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);
143+ // The architecture dependent condition code of the last processed
144+ // instruction.
145+ EmulateInstruction::InstructionCondition last_condition =
146+ EmulateInstruction::UnconditionalCondition;
147+
148+ for (size_t idx = 0 ; idx < num_instructions; ++idx) {
149+ m_curr_row_modified = false ;
150+ m_forward_branch_offset = 0 ;
151+
152+ inst = inst_list.GetInstructionAtIndex (idx).get ();
153+ if (!inst)
154+ continue ;
155+
156+ lldb::addr_t current_offset =
157+ inst->GetAddress ().GetFileAddress () - base_addr;
158+ auto it = saved_unwind_states.upper_bound (current_offset);
159+ assert (it != saved_unwind_states.begin () &&
160+ " Unwind row for the function entry missing" );
161+ --it; // Move it to the row corresponding to the current offset
162+
163+ // If the offset of m_state.row doesn't match with the offset we see in
164+ // saved_unwind_states then we have to update current unwind state to
165+ // the saved values. It is happening after we processed an epilogue and a
166+ // return to caller instruction.
167+ if (it->second .row .GetOffset () != m_state.row .GetOffset ())
168+ m_state = it->second ;
169+
170+ m_inst_emulator_up->SetInstruction (inst->GetOpcode (), inst->GetAddress (),
171+ nullptr );
172+
173+ if (last_condition != m_inst_emulator_up->GetInstructionCondition ()) {
174+ // If the last instruction was conditional with a different condition
175+ // than the current condition then restore the state.
176+ if (last_condition != EmulateInstruction::UnconditionalCondition) {
177+ m_state = condition_block_start_state->second ;
178+ m_state.row .SetOffset (current_offset);
179+ // The last instruction might already created a row for this offset
180+ // and we want to overwrite it.
181+ saved_unwind_states.insert_or_assign (current_offset, m_state);
196182 }
197183
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- }
209- }
184+ // We are starting a new conditional block at the actual offset
185+ condition_block_start_state = it;
210186 }
211- for (auto &[_, state] : saved_unwind_states) {
212- unwind_plan.InsertRow (std::move (state.row ),
213- /* replace_existing=*/ true );
187+
188+ if (log && log->GetVerbose ()) {
189+ StreamString strm;
190+ lldb_private::FormatEntity::Entry format;
191+ FormatEntity::Parse (" ${frame.pc}: " , format);
192+ inst->Dump (&strm, inst_list.GetMaxOpcocdeByteSize (), show_address,
193+ show_bytes, show_control_flow_kind, nullptr , nullptr , nullptr ,
194+ &format, 0 );
195+ log->PutString (strm.GetString ());
214196 }
215- }
216197
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 ());
198+ last_condition = m_inst_emulator_up->GetInstructionCondition ();
199+
200+ m_inst_emulator_up->EvaluateInstruction (
201+ eEmulateInstructionOptionIgnoreConditions);
202+
203+ // If the current instruction is a branch forward then save the current
204+ // CFI information for the offset where we are branching.
205+ if (m_forward_branch_offset != 0 &&
206+ range.ContainsFileAddress (inst->GetAddress ().GetFileAddress () +
207+ m_forward_branch_offset)) {
208+ if (auto [it, inserted] = saved_unwind_states.emplace (
209+ current_offset + m_forward_branch_offset, m_state);
210+ inserted)
211+ it->second .row .SetOffset (current_offset + m_forward_branch_offset);
212+ }
213+
214+ // Were there any changes to the CFI while evaluating this instruction?
215+ if (m_curr_row_modified) {
216+ // Save the modified row if we don't already have a CFI row in the
217+ // current address
218+ if (saved_unwind_states.count (current_offset +
219+ inst->GetOpcode ().GetByteSize ()) == 0 ) {
220+ m_state.row .SetOffset (current_offset + inst->GetOpcode ().GetByteSize ());
221+ saved_unwind_states.emplace (
222+ current_offset + inst->GetOpcode ().GetByteSize (), m_state);
223+ }
224+ }
224225 }
226+
227+ for (auto &[_, state] : saved_unwind_states)
228+ unwind_plan.InsertRow (std::move (state.row ),
229+ /* replace_existing=*/ true );
230+
231+ DumpUnwindRowsToLog (log, range, unwind_plan);
225232 return unwind_plan.GetRowCount () > 0 ;
226233}
227234
0 commit comments