1 //===-- UnwindAssemblyInstEmulation.cpp -----------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "UnwindAssemblyInstEmulation.h"
11 #include "lldb/Core/Address.h"
12 #include "lldb/Core/Disassembler.h"
13 #include "lldb/Core/DumpDataExtractor.h"
14 #include "lldb/Core/DumpRegisterValue.h"
15 #include "lldb/Core/FormatEntity.h"
16 #include "lldb/Core/PluginManager.h"
17 #include "lldb/Target/ExecutionContext.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Utility/ArchSpec.h"
22 #include "lldb/Utility/DataBufferHeap.h"
23 #include "lldb/Utility/DataExtractor.h"
24 #include "lldb/Utility/LLDBLog.h"
25 #include "lldb/Utility/Log.h"
26 #include "lldb/Utility/Status.h"
27 #include "lldb/Utility/StreamString.h"
30 using namespace lldb_private
;
32 LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation
)
34 // UnwindAssemblyInstEmulation method definitions
36 bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
37 AddressRange
&range
, Thread
&thread
, UnwindPlan
&unwind_plan
) {
38 std::vector
<uint8_t> function_text(range
.GetByteSize());
39 ProcessSP
process_sp(thread
.GetProcess());
42 const bool force_live_memory
= true;
43 if (process_sp
->GetTarget().ReadMemory(
44 range
.GetBaseAddress(), function_text
.data(), range
.GetByteSize(),
45 error
, force_live_memory
) != range
.GetByteSize()) {
49 return GetNonCallSiteUnwindPlanFromAssembly(
50 range
, function_text
.data(), function_text
.size(), unwind_plan
);
53 bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
54 AddressRange
&range
, uint8_t *opcode_data
, size_t opcode_size
,
55 UnwindPlan
&unwind_plan
) {
56 if (opcode_data
== nullptr || opcode_size
== 0)
59 if (range
.GetByteSize() > 0 && range
.GetBaseAddress().IsValid() &&
60 m_inst_emulator_up
.get()) {
62 // The instruction emulation subclass setup the unwind plan for the first
64 m_inst_emulator_up
->CreateFunctionEntryUnwind(unwind_plan
);
66 // CreateFunctionEntryUnwind should have created the first row. If it
67 // doesn't, then we are done.
68 if (unwind_plan
.GetRowCount() == 0)
71 const bool prefer_file_cache
= true;
72 DisassemblerSP
disasm_sp(Disassembler::DisassembleBytes(
73 m_arch
, nullptr, nullptr, range
.GetBaseAddress(), opcode_data
,
74 opcode_size
, 99999, prefer_file_cache
));
76 Log
*log
= GetLog(LLDBLog::Unwind
);
81 m_unwind_plan_ptr
= &unwind_plan
;
83 const uint32_t addr_byte_size
= m_arch
.GetAddressByteSize();
84 const bool show_address
= true;
85 const bool show_bytes
= true;
86 const bool show_control_flow_kind
= true;
87 m_cfa_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
88 unwind_plan
.GetRegisterKind(), unwind_plan
.GetInitialCFARegister());
90 m_register_values
.clear();
91 m_pushed_regs
.clear();
93 // Initialize the CFA with a known value. In the 32 bit case it will be
94 // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the
95 // address byte size to be safe for any future address sizes
96 m_initial_sp
= (1ull << ((addr_byte_size
* 8) - 1));
97 RegisterValue cfa_reg_value
;
98 cfa_reg_value
.SetUInt(m_initial_sp
, m_cfa_reg_info
.byte_size
);
99 SetRegisterValue(m_cfa_reg_info
, cfa_reg_value
);
101 const InstructionList
&inst_list
= disasm_sp
->GetInstructionList();
102 const size_t num_instructions
= inst_list
.GetSize();
104 if (num_instructions
> 0) {
105 Instruction
*inst
= inst_list
.GetInstructionAtIndex(0).get();
106 const lldb::addr_t base_addr
= inst
->GetAddress().GetFileAddress();
108 // Map for storing the unwind plan row and the value of the registers
109 // at a given offset. When we see a forward branch we add a new entry
110 // to this map with the actual unwind plan row and register context for
111 // the target address of the branch as the current data have to be
112 // valid for the target address of the branch too if we are in the same
114 std::map
<lldb::addr_t
, std::pair
<UnwindPlan::RowSP
, RegisterValueMap
>>
117 // Make a copy of the current instruction Row and save it in m_curr_row
118 // so we can add updates as we process the instructions.
119 UnwindPlan::RowSP last_row
= unwind_plan
.GetLastRow();
120 UnwindPlan::Row
*newrow
= new UnwindPlan::Row
;
122 *newrow
= *last_row
.get();
123 m_curr_row
.reset(newrow
);
125 // Add the initial state to the save list with offset 0.
126 saved_unwind_states
.insert({0, {last_row
, m_register_values
}});
128 // cache the stack pointer register number (in whatever register
129 // numbering this UnwindPlan uses) for quick reference during
130 // instruction parsing.
131 RegisterInfo sp_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
132 eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_SP
);
134 // The architecture dependent condition code of the last processed
136 EmulateInstruction::InstructionCondition last_condition
=
137 EmulateInstruction::UnconditionalCondition
;
138 lldb::addr_t condition_block_start_offset
= 0;
140 for (size_t idx
= 0; idx
< num_instructions
; ++idx
) {
141 m_curr_row_modified
= false;
142 m_forward_branch_offset
= 0;
144 inst
= inst_list
.GetInstructionAtIndex(idx
).get();
146 lldb::addr_t current_offset
=
147 inst
->GetAddress().GetFileAddress() - base_addr
;
148 auto it
= saved_unwind_states
.upper_bound(current_offset
);
149 assert(it
!= saved_unwind_states
.begin() &&
150 "Unwind row for the function entry missing");
151 --it
; // Move it to the row corresponding to the current offset
153 // If the offset of m_curr_row don't match with the offset we see
154 // in saved_unwind_states then we have to update m_curr_row and
155 // m_register_values based on the saved values. It is happening
156 // after we processed an epilogue and a return to caller
158 if (it
->second
.first
->GetOffset() != m_curr_row
->GetOffset()) {
159 UnwindPlan::Row
*newrow
= new UnwindPlan::Row
;
160 *newrow
= *it
->second
.first
;
161 m_curr_row
.reset(newrow
);
162 m_register_values
= it
->second
.second
;
163 // re-set the CFA register ivars to match the
165 if (sp_reg_info
.name
&&
166 m_curr_row
->GetCFAValue().IsRegisterPlusOffset()) {
167 uint32_t row_cfa_regnum
=
168 m_curr_row
->GetCFAValue().GetRegisterNumber();
169 lldb::RegisterKind row_kind
=
170 m_unwind_plan_ptr
->GetRegisterKind();
171 // set m_cfa_reg_info to the row's CFA reg.
172 m_cfa_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
173 row_kind
, row_cfa_regnum
);
175 if (sp_reg_info
.kinds
[row_kind
] == row_cfa_regnum
)
182 m_inst_emulator_up
->SetInstruction(inst
->GetOpcode(),
183 inst
->GetAddress(), nullptr);
185 if (last_condition
!=
186 m_inst_emulator_up
->GetInstructionCondition()) {
187 if (m_inst_emulator_up
->GetInstructionCondition() !=
188 EmulateInstruction::UnconditionalCondition
&&
189 saved_unwind_states
.count(current_offset
) == 0) {
190 // If we don't have a saved row for the current offset then
191 // save our current state because we will have to restore it
192 // after the conditional block.
194 std::make_shared
<UnwindPlan::Row
>(*m_curr_row
.get());
195 saved_unwind_states
.insert(
196 {current_offset
, {new_row
, m_register_values
}});
199 // If the last instruction was conditional with a different
200 // condition then the then current condition then restore the
202 if (last_condition
!=
203 EmulateInstruction::UnconditionalCondition
) {
204 const auto &saved_state
=
205 saved_unwind_states
.at(condition_block_start_offset
);
207 std::make_shared
<UnwindPlan::Row
>(*saved_state
.first
);
208 m_curr_row
->SetOffset(current_offset
);
209 m_register_values
= saved_state
.second
;
210 // re-set the CFA register ivars to match the
212 if (sp_reg_info
.name
&&
213 m_curr_row
->GetCFAValue().IsRegisterPlusOffset()) {
214 uint32_t row_cfa_regnum
=
215 m_curr_row
->GetCFAValue().GetRegisterNumber();
216 lldb::RegisterKind row_kind
=
217 m_unwind_plan_ptr
->GetRegisterKind();
218 // set m_cfa_reg_info to the row's CFA reg.
219 m_cfa_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
220 row_kind
, row_cfa_regnum
);
222 if (sp_reg_info
.kinds
[row_kind
] == row_cfa_regnum
)
227 bool replace_existing
=
228 true; // The last instruction might already
229 // created a row for this offset and
230 // we want to overwrite it.
231 unwind_plan
.InsertRow(
232 std::make_shared
<UnwindPlan::Row
>(*m_curr_row
),
236 // We are starting a new conditional block at the actual offset
237 condition_block_start_offset
= current_offset
;
240 if (log
&& log
->GetVerbose()) {
242 lldb_private::FormatEntity::Entry format
;
243 FormatEntity::Parse("${frame.pc}: ", format
);
244 inst
->Dump(&strm
, inst_list
.GetMaxOpcocdeByteSize(), show_address
,
245 show_bytes
, show_control_flow_kind
, nullptr, nullptr,
246 nullptr, &format
, 0);
247 log
->PutString(strm
.GetString());
250 last_condition
= m_inst_emulator_up
->GetInstructionCondition();
252 m_inst_emulator_up
->EvaluateInstruction(
253 eEmulateInstructionOptionIgnoreConditions
);
255 // If the current instruction is a branch forward then save the
256 // current CFI information for the offset where we are branching.
257 if (m_forward_branch_offset
!= 0 &&
258 range
.ContainsFileAddress(inst
->GetAddress().GetFileAddress() +
259 m_forward_branch_offset
)) {
261 std::make_shared
<UnwindPlan::Row
>(*m_curr_row
.get());
262 newrow
->SetOffset(current_offset
+ m_forward_branch_offset
);
263 saved_unwind_states
.insert(
264 {current_offset
+ m_forward_branch_offset
,
265 {newrow
, m_register_values
}});
266 unwind_plan
.InsertRow(newrow
);
269 // Were there any changes to the CFI while evaluating this
271 if (m_curr_row_modified
) {
272 // Save the modified row if we don't already have a CFI row in
273 // the current address
274 if (saved_unwind_states
.count(
275 current_offset
+ inst
->GetOpcode().GetByteSize()) == 0) {
276 m_curr_row
->SetOffset(current_offset
+
277 inst
->GetOpcode().GetByteSize());
278 unwind_plan
.InsertRow(m_curr_row
);
279 saved_unwind_states
.insert(
280 {current_offset
+ inst
->GetOpcode().GetByteSize(),
281 {m_curr_row
, m_register_values
}});
283 // Allocate a new Row for m_curr_row, copy the current state
285 UnwindPlan::Row
*newrow
= new UnwindPlan::Row
;
286 *newrow
= *m_curr_row
.get();
287 m_curr_row
.reset(newrow
);
295 if (log
&& log
->GetVerbose()) {
297 lldb::addr_t base_addr
= range
.GetBaseAddress().GetFileAddress();
298 strm
.Printf("Resulting unwind rows for [0x%" PRIx64
" - 0x%" PRIx64
"):",
299 base_addr
, base_addr
+ range
.GetByteSize());
300 unwind_plan
.Dump(strm
, nullptr, base_addr
);
301 log
->PutString(strm
.GetString());
303 return unwind_plan
.GetRowCount() > 0;
308 bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite(
309 AddressRange
&func
, Thread
&thread
, UnwindPlan
&unwind_plan
) {
313 bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange
&func
,
315 UnwindPlan
&unwind_plan
) {
319 bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn(
320 AddressRange
&func
, const ExecutionContext
&exe_ctx
,
321 Address
&first_non_prologue_insn
) {
326 UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec
&arch
) {
327 std::unique_ptr
<EmulateInstruction
> inst_emulator_up(
328 EmulateInstruction::FindPlugin(arch
, eInstructionTypePrologueEpilogue
,
330 // Make sure that all prologue instructions are handled
331 if (inst_emulator_up
)
332 return new UnwindAssemblyInstEmulation(arch
, inst_emulator_up
.release());
336 void UnwindAssemblyInstEmulation::Initialize() {
337 PluginManager::RegisterPlugin(GetPluginNameStatic(),
338 GetPluginDescriptionStatic(), CreateInstance
);
341 void UnwindAssemblyInstEmulation::Terminate() {
342 PluginManager::UnregisterPlugin(CreateInstance
);
345 llvm::StringRef
UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() {
346 return "Instruction emulation based unwind information.";
349 uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair(
350 const RegisterInfo
®_info
) {
351 lldb::RegisterKind reg_kind
;
353 if (EmulateInstruction::GetBestRegisterKindAndNumber(®_info
, reg_kind
,
355 return (uint64_t)reg_kind
<< 24 | reg_num
;
359 void UnwindAssemblyInstEmulation::SetRegisterValue(
360 const RegisterInfo
®_info
, const RegisterValue
®_value
) {
361 m_register_values
[MakeRegisterKindValuePair(reg_info
)] = reg_value
;
364 bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo
®_info
,
365 RegisterValue
®_value
) {
366 const uint64_t reg_id
= MakeRegisterKindValuePair(reg_info
);
367 RegisterValueMap::const_iterator pos
= m_register_values
.find(reg_id
);
368 if (pos
!= m_register_values
.end()) {
369 reg_value
= pos
->second
;
370 return true; // We had a real value that comes from an opcode that wrote
373 // We are making up a value that is recognizable...
374 reg_value
.SetUInt(reg_id
, reg_info
.byte_size
);
378 size_t UnwindAssemblyInstEmulation::ReadMemory(
379 EmulateInstruction
*instruction
, void *baton
,
380 const EmulateInstruction::Context
&context
, lldb::addr_t addr
, void *dst
,
382 Log
*log
= GetLog(LLDBLog::Unwind
);
384 if (log
&& log
->GetVerbose()) {
387 "UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64
388 ", dst = %p, dst_len = %" PRIu64
", context = ",
389 addr
, dst
, (uint64_t)dst_len
);
390 context
.Dump(strm
, instruction
);
391 log
->PutString(strm
.GetString());
393 memset(dst
, 0, dst_len
);
397 size_t UnwindAssemblyInstEmulation::WriteMemory(
398 EmulateInstruction
*instruction
, void *baton
,
399 const EmulateInstruction::Context
&context
, lldb::addr_t addr
,
400 const void *dst
, size_t dst_len
) {
401 if (baton
&& dst
&& dst_len
)
402 return ((UnwindAssemblyInstEmulation
*)baton
)
403 ->WriteMemory(instruction
, context
, addr
, dst
, dst_len
);
407 size_t UnwindAssemblyInstEmulation::WriteMemory(
408 EmulateInstruction
*instruction
, const EmulateInstruction::Context
&context
,
409 lldb::addr_t addr
, const void *dst
, size_t dst_len
) {
410 DataExtractor
data(dst
, dst_len
,
411 instruction
->GetArchitecture().GetByteOrder(),
412 instruction
->GetArchitecture().GetAddressByteSize());
414 Log
*log
= GetLog(LLDBLog::Unwind
);
416 if (log
&& log
->GetVerbose()) {
419 strm
.PutCString("UnwindAssemblyInstEmulation::WriteMemory (");
420 DumpDataExtractor(data
, &strm
, 0, eFormatBytes
, 1, dst_len
, UINT32_MAX
,
422 strm
.PutCString(", context = ");
423 context
.Dump(strm
, instruction
);
424 log
->PutString(strm
.GetString());
427 const bool cant_replace
= false;
429 switch (context
.type
) {
431 case EmulateInstruction::eContextInvalid
:
432 case EmulateInstruction::eContextReadOpcode
:
433 case EmulateInstruction::eContextImmediate
:
434 case EmulateInstruction::eContextAdjustBaseRegister
:
435 case EmulateInstruction::eContextRegisterPlusOffset
:
436 case EmulateInstruction::eContextAdjustPC
:
437 case EmulateInstruction::eContextRegisterStore
:
438 case EmulateInstruction::eContextRegisterLoad
:
439 case EmulateInstruction::eContextRelativeBranchImmediate
:
440 case EmulateInstruction::eContextAbsoluteBranchRegister
:
441 case EmulateInstruction::eContextSupervisorCall
:
442 case EmulateInstruction::eContextTableBranchReadMemory
:
443 case EmulateInstruction::eContextWriteRegisterRandomBits
:
444 case EmulateInstruction::eContextWriteMemoryRandomBits
:
445 case EmulateInstruction::eContextArithmetic
:
446 case EmulateInstruction::eContextAdvancePC
:
447 case EmulateInstruction::eContextReturnFromException
:
448 case EmulateInstruction::eContextPopRegisterOffStack
:
449 case EmulateInstruction::eContextAdjustStackPointer
:
452 case EmulateInstruction::eContextPushRegisterOnStack
: {
453 uint32_t reg_num
= LLDB_INVALID_REGNUM
;
454 uint32_t generic_regnum
= LLDB_INVALID_REGNUM
;
455 assert(context
.GetInfoType() ==
456 EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset
&&
457 "unhandled case, add code to handle this!");
458 const uint32_t unwind_reg_kind
= m_unwind_plan_ptr
->GetRegisterKind();
459 reg_num
= context
.info
.RegisterToRegisterPlusOffset
.data_reg
460 .kinds
[unwind_reg_kind
];
461 generic_regnum
= context
.info
.RegisterToRegisterPlusOffset
.data_reg
462 .kinds
[eRegisterKindGeneric
];
464 if (reg_num
!= LLDB_INVALID_REGNUM
&&
465 generic_regnum
!= LLDB_REGNUM_GENERIC_SP
) {
466 if (m_pushed_regs
.find(reg_num
) == m_pushed_regs
.end()) {
467 m_pushed_regs
[reg_num
] = addr
;
468 const int32_t offset
= addr
- m_initial_sp
;
469 m_curr_row
->SetRegisterLocationToAtCFAPlusOffset(reg_num
, offset
,
471 m_curr_row_modified
= true;
480 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction
*instruction
,
482 const RegisterInfo
*reg_info
,
483 RegisterValue
®_value
) {
485 if (baton
&& reg_info
)
486 return ((UnwindAssemblyInstEmulation
*)baton
)
487 ->ReadRegister(instruction
, reg_info
, reg_value
);
490 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction
*instruction
,
491 const RegisterInfo
*reg_info
,
492 RegisterValue
®_value
) {
493 bool synthetic
= GetRegisterValue(*reg_info
, reg_value
);
495 Log
*log
= GetLog(LLDBLog::Unwind
);
497 if (log
&& log
->GetVerbose()) {
500 strm
.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => "
501 "synthetic_value = %i, value = ",
502 reg_info
->name
, synthetic
);
503 DumpRegisterValue(reg_value
, strm
, *reg_info
, false, false, eFormatDefault
);
504 log
->PutString(strm
.GetString());
509 bool UnwindAssemblyInstEmulation::WriteRegister(
510 EmulateInstruction
*instruction
, void *baton
,
511 const EmulateInstruction::Context
&context
, const RegisterInfo
*reg_info
,
512 const RegisterValue
®_value
) {
513 if (baton
&& reg_info
)
514 return ((UnwindAssemblyInstEmulation
*)baton
)
515 ->WriteRegister(instruction
, context
, reg_info
, reg_value
);
518 bool UnwindAssemblyInstEmulation::WriteRegister(
519 EmulateInstruction
*instruction
, const EmulateInstruction::Context
&context
,
520 const RegisterInfo
*reg_info
, const RegisterValue
®_value
) {
521 Log
*log
= GetLog(LLDBLog::Unwind
);
523 if (log
&& log
->GetVerbose()) {
527 "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",
529 DumpRegisterValue(reg_value
, strm
, *reg_info
, false, false, eFormatDefault
);
530 strm
.PutCString(", context = ");
531 context
.Dump(strm
, instruction
);
532 log
->PutString(strm
.GetString());
535 SetRegisterValue(*reg_info
, reg_value
);
537 switch (context
.type
) {
538 case EmulateInstruction::eContextInvalid
:
539 case EmulateInstruction::eContextReadOpcode
:
540 case EmulateInstruction::eContextImmediate
:
541 case EmulateInstruction::eContextAdjustBaseRegister
:
542 case EmulateInstruction::eContextRegisterPlusOffset
:
543 case EmulateInstruction::eContextAdjustPC
:
544 case EmulateInstruction::eContextRegisterStore
:
545 case EmulateInstruction::eContextSupervisorCall
:
546 case EmulateInstruction::eContextTableBranchReadMemory
:
547 case EmulateInstruction::eContextWriteRegisterRandomBits
:
548 case EmulateInstruction::eContextWriteMemoryRandomBits
:
549 case EmulateInstruction::eContextAdvancePC
:
550 case EmulateInstruction::eContextReturnFromException
:
551 case EmulateInstruction::eContextPushRegisterOnStack
:
552 case EmulateInstruction::eContextRegisterLoad
:
554 // const uint32_t reg_num =
555 // reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
556 // if (reg_num != LLDB_INVALID_REGNUM)
558 // const bool can_replace_only_if_unspecified = true;
560 // m_curr_row.SetRegisterLocationToUndefined (reg_num,
561 // can_replace_only_if_unspecified,
562 // can_replace_only_if_unspecified);
563 // m_curr_row_modified = true;
568 case EmulateInstruction::eContextArithmetic
: {
569 // If we adjusted the current frame pointer by a constant then adjust the
571 // with the same amount.
572 lldb::RegisterKind kind
= m_unwind_plan_ptr
->GetRegisterKind();
573 if (m_fp_is_cfa
&& reg_info
->kinds
[kind
] == m_cfa_reg_info
.kinds
[kind
] &&
574 context
.GetInfoType() ==
575 EmulateInstruction::eInfoTypeRegisterPlusOffset
&&
576 context
.info
.RegisterPlusOffset
.reg
.kinds
[kind
] ==
577 m_cfa_reg_info
.kinds
[kind
]) {
578 const int64_t offset
= context
.info
.RegisterPlusOffset
.signed_offset
;
579 m_curr_row
->GetCFAValue().IncOffset(-1 * offset
);
580 m_curr_row_modified
= true;
584 case EmulateInstruction::eContextAbsoluteBranchRegister
:
585 case EmulateInstruction::eContextRelativeBranchImmediate
: {
586 if (context
.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate
&&
587 context
.info
.ISAAndImmediate
.unsigned_data32
> 0) {
588 m_forward_branch_offset
=
589 context
.info
.ISAAndImmediateSigned
.signed_data32
;
590 } else if (context
.GetInfoType() ==
591 EmulateInstruction::eInfoTypeISAAndImmediateSigned
&&
592 context
.info
.ISAAndImmediateSigned
.signed_data32
> 0) {
593 m_forward_branch_offset
= context
.info
.ISAAndImmediate
.unsigned_data32
;
594 } else if (context
.GetInfoType() ==
595 EmulateInstruction::eInfoTypeImmediate
&&
596 context
.info
.unsigned_immediate
> 0) {
597 m_forward_branch_offset
= context
.info
.unsigned_immediate
;
598 } else if (context
.GetInfoType() ==
599 EmulateInstruction::eInfoTypeImmediateSigned
&&
600 context
.info
.signed_immediate
> 0) {
601 m_forward_branch_offset
= context
.info
.signed_immediate
;
605 case EmulateInstruction::eContextPopRegisterOffStack
: {
606 const uint32_t reg_num
=
607 reg_info
->kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
608 const uint32_t generic_regnum
= reg_info
->kinds
[eRegisterKindGeneric
];
609 if (reg_num
!= LLDB_INVALID_REGNUM
&&
610 generic_regnum
!= LLDB_REGNUM_GENERIC_SP
) {
611 switch (context
.GetInfoType()) {
612 case EmulateInstruction::eInfoTypeAddress
:
613 if (m_pushed_regs
.find(reg_num
) != m_pushed_regs
.end() &&
614 context
.info
.address
== m_pushed_regs
[reg_num
]) {
615 m_curr_row
->SetRegisterLocationToSame(reg_num
,
616 false /*must_replace*/);
617 m_curr_row_modified
= true;
619 // FP has been restored to its original value, we are back
620 // to using SP to calculate the CFA.
623 lldb::RegisterKind sp_reg_kind
= eRegisterKindGeneric
;
624 uint32_t sp_reg_num
= LLDB_REGNUM_GENERIC_SP
;
625 RegisterInfo sp_reg_info
=
626 *m_inst_emulator_up
->GetRegisterInfo(sp_reg_kind
, sp_reg_num
);
627 RegisterValue sp_reg_val
;
628 if (GetRegisterValue(sp_reg_info
, sp_reg_val
)) {
629 m_cfa_reg_info
= sp_reg_info
;
630 const uint32_t cfa_reg_num
=
631 sp_reg_info
.kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
632 assert(cfa_reg_num
!= LLDB_INVALID_REGNUM
);
633 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
634 cfa_reg_num
, m_initial_sp
- sp_reg_val
.GetAsUInt64());
639 case EmulateInstruction::eInfoTypeISA
:
641 (generic_regnum
== LLDB_REGNUM_GENERIC_PC
||
642 generic_regnum
== LLDB_REGNUM_GENERIC_FLAGS
) &&
643 "eInfoTypeISA used for popping a register other the PC/FLAGS");
644 if (generic_regnum
!= LLDB_REGNUM_GENERIC_FLAGS
) {
645 m_curr_row
->SetRegisterLocationToSame(reg_num
,
646 false /*must_replace*/);
647 m_curr_row_modified
= true;
651 assert(false && "unhandled case, add code to handle this!");
657 case EmulateInstruction::eContextSetFramePointer
:
660 m_cfa_reg_info
= *reg_info
;
661 const uint32_t cfa_reg_num
=
662 reg_info
->kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
663 assert(cfa_reg_num
!= LLDB_INVALID_REGNUM
);
664 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
665 cfa_reg_num
, m_initial_sp
- reg_value
.GetAsUInt64());
666 m_curr_row_modified
= true;
670 case EmulateInstruction::eContextRestoreStackPointer
:
673 m_cfa_reg_info
= *reg_info
;
674 const uint32_t cfa_reg_num
=
675 reg_info
->kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
676 assert(cfa_reg_num
!= LLDB_INVALID_REGNUM
);
677 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
678 cfa_reg_num
, m_initial_sp
- reg_value
.GetAsUInt64());
679 m_curr_row_modified
= true;
683 case EmulateInstruction::eContextAdjustStackPointer
:
684 // If we have created a frame using the frame pointer, don't follow
685 // subsequent adjustments to the stack pointer.
687 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
688 m_curr_row
->GetCFAValue().GetRegisterNumber(),
689 m_initial_sp
- reg_value
.GetAsUInt64());
690 m_curr_row_modified
= true;