LLDB mainline
UnwindAssemblyInstEmulation.cpp
Go to the documentation of this file.
1//===-- UnwindAssemblyInstEmulation.cpp -----------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "lldb/Core/Address.h"
17#include "lldb/Symbol/Symbol.h"
19#include "lldb/Target/Target.h"
20#include "lldb/Target/Thread.h"
25#include "lldb/Utility/Log.h"
26#include "lldb/Utility/Status.h"
28#include "llvm/ADT/SmallSet.h"
29#include <deque>
30
31using namespace lldb;
32using namespace lldb_private;
33
35
36// UnwindAssemblyInstEmulation method definitions
37
39 AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) {
40 std::vector<uint8_t> function_text(range.GetByteSize());
41 TargetSP target_sp(thread.CalculateTarget());
42 if (target_sp) {
44 if (target_sp->ReadMemory(range.GetBaseAddress(), function_text.data(),
45 range.GetByteSize(),
46 error) != range.GetByteSize()) {
47 return false;
48 }
49 }
51 range, function_text.data(), function_text.size(), unwind_plan);
52}
53
54static void DumpUnwindRowsToLog(Log *log, AddressRange range,
55 const UnwindPlan &unwind_plan) {
56 if (!log || !log->GetVerbose())
57 return;
58 StreamString strm;
59 lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
60 strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
61 base_addr, base_addr + range.GetByteSize());
62 unwind_plan.Dump(strm, nullptr, base_addr);
63 log->PutString(strm.GetString());
64}
65
66static void DumpInstToLog(Log *log, Instruction &inst,
67 const InstructionList &inst_list) {
68 if (!log || !log->GetVerbose())
69 return;
70 const bool show_address = true;
71 const bool show_bytes = true;
72 const bool show_control_flow_kind = false;
73 StreamString strm;
75 FormatEntity::Parse("${frame.pc}: ", format);
76 inst.Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address, show_bytes,
77 show_control_flow_kind, nullptr, nullptr, nullptr, &format, 0);
78 log->PutString(strm.GetString());
79}
80
82 AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
83 UnwindPlan &unwind_plan) {
84 if (opcode_data == nullptr || opcode_size == 0)
85 return false;
86
87 if (range.GetByteSize() == 0 || !range.GetBaseAddress().IsValid() ||
89 return false;
90
91 // The instruction emulation subclass setup the unwind plan for the first
92 // instruction.
93 m_inst_emulator_up->CreateFunctionEntryUnwind(unwind_plan);
94
95 // CreateFunctionEntryUnwind should have created the first row. If it doesn't,
96 // then we are done.
97 if (unwind_plan.GetRowCount() == 0)
98 return false;
99
100 const bool prefer_file_cache = true;
102 m_arch, nullptr, nullptr, nullptr, nullptr, range.GetBaseAddress(),
103 opcode_data, opcode_size, 99999, prefer_file_cache));
104
105 if (!disasm_sp)
106 return false;
107
108 Log *log = GetLog(LLDBLog::Unwind);
109
110 m_range_ptr = &range;
111 m_unwind_plan_ptr = &unwind_plan;
112
113 m_state.cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(
114 unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister());
115 m_state.fp_is_cfa = false;
116 m_state.register_values.clear();
117
118 m_pushed_regs.clear();
119
120 RegisterValue cfa_reg_value;
121 cfa_reg_value.SetUInt(m_initial_cfa, m_state.cfa_reg_info.byte_size);
122 SetRegisterValue(m_state.cfa_reg_info, cfa_reg_value);
123
124 InstructionList inst_list = disasm_sp->GetInstructionList();
125
126 if (inst_list.GetSize() == 0) {
127 DumpUnwindRowsToLog(log, range, unwind_plan);
128 return unwind_plan.GetRowCount() > 0;
129 }
130
131 Instruction &first_inst = *inst_list.GetInstructionAtIndex(0);
132 const lldb::addr_t base_addr = first_inst.GetAddress().GetFileAddress();
133
134 // Map for storing the unwind state at a given offset. When we see a forward
135 // branch we add a new entry to this map with the actual unwind plan row and
136 // register context for the target address of the branch as the current data
137 // have to be valid for the target address of the branch too if we are in
138 // the same function.
139 std::map<lldb::addr_t, UnwindState> saved_unwind_states;
140
141 // Make a copy of the current instruction Row and save it in m_state so
142 // we can add updates as we process the instructions.
143 m_state.row = *unwind_plan.GetLastRow();
144
145 // Add the initial state to the save list with offset 0.
146 auto condition_block_start_state =
147 saved_unwind_states.emplace(0, m_state).first;
148
149 // The architecture dependent condition code of the last processed
150 // instruction.
153
154 std::deque<std::size_t> to_visit = {0};
155 llvm::SmallSet<std::size_t, 0> enqueued = {0};
156
157 // Instructions reachable through jumps are inserted on the front.
158 // The next instruction is inserted on the back.
159 // Pop from the back to ensure non-branching instructions are visited
160 // sequentially.
161 while (!to_visit.empty()) {
162 const std::size_t current_index = to_visit.back();
163 Instruction &inst = *inst_list.GetInstructionAtIndex(current_index);
164 to_visit.pop_back();
165 DumpInstToLog(log, inst, inst_list);
166
167 m_curr_row_modified = false;
168 m_branch_offset = 0;
169 m_branch_is_call = false;
170
171 lldb::addr_t current_offset =
172 inst.GetAddress().GetFileAddress() - base_addr;
173 auto it = saved_unwind_states.upper_bound(current_offset);
174 assert(it != saved_unwind_states.begin() &&
175 "Unwind row for the function entry missing");
176 --it; // Move it to the row corresponding to the current offset
177
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.
183 if (it->second.row.GetOffset() != m_state.row.GetOffset())
184 m_state = it->second;
185
186 m_inst_emulator_up->SetInstruction(inst.GetOpcode(), inst.GetAddress(),
187 nullptr);
188 const EmulateInstruction::InstructionCondition new_condition =
189 m_inst_emulator_up->GetInstructionCondition();
190
191 if (last_condition != new_condition) {
192 // If the last instruction was conditional with a different condition
193 // than the current condition then restore the state.
194 if (last_condition != EmulateInstruction::UnconditionalCondition) {
195 m_state = condition_block_start_state->second;
196 m_state.row.SetOffset(current_offset);
197 // The last instruction might already created a row for this offset
198 // and we want to overwrite it.
199 saved_unwind_states.insert_or_assign(current_offset, m_state);
200 }
201
202 // We are starting a new conditional block at the actual offset
203 condition_block_start_state = it;
204 }
205
206 last_condition = new_condition;
207
208 m_inst_emulator_up->EvaluateInstruction(
209 eEmulateInstructionOptionIgnoreConditions);
210
211 Address branch_address = inst.GetAddress();
212 branch_address.Slide(m_branch_offset);
213 if (m_branch_offset != 0) {
214 if (range.ContainsFileAddress(branch_address.GetFileAddress())) {
215 // The current instruction is a branch: save the current CFI information
216 // for the offset where we are branching.
217 if (auto [it, inserted] = saved_unwind_states.emplace(
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 }
228 } else if (m_branch_is_call) {
229 // The current instruction is a function call: this might be a call to
230 // outlined instructions that used to belong to this function, so try
231 // emulate the callee.
232 assert(!range.ContainsFileAddress(branch_address.GetFileAddress()) &&
233 "function call to instruction inside current function!");
234 EmulateOutlinedFunction(branch_address);
235 }
236 }
237
238 // If inst is a barrier, do not propagate state to the next instruction.
239 if (inst.IsBarrier())
240 continue;
241
242 // Were there any changes to the CFI while evaluating this instruction?
244 // Save the modified row if we don't already have a CFI row in the
245 // current address
246 const lldb::addr_t next_inst_offset =
247 current_offset + inst.GetOpcode().GetByteSize();
248 if (saved_unwind_states.count(next_inst_offset) == 0) {
249 m_state.row.SetOffset(next_inst_offset);
250 saved_unwind_states.emplace(next_inst_offset, m_state);
251 }
252 }
253
254 const size_t next_idx = current_index + 1;
255 const bool never_enqueued = enqueued.insert(next_idx).second;
256 if (never_enqueued && next_idx < inst_list.GetSize())
257 to_visit.push_back(next_idx);
258 }
259
260 for (auto &[_, state] : saved_unwind_states)
261 unwind_plan.InsertRow(std::move(state.row),
262 /*replace_existing=*/true);
263
264 DumpUnwindRowsToLog(log, range, unwind_plan);
265 return unwind_plan.GetRowCount() > 0;
266}
267
269 Symbol *symbol = func_addr.CalculateSymbolContextSymbol();
270 if (!symbol)
271 return false;
272
273 // The machine outliner names every outlined function OUTLINED_FUNCTION_<n>.
274 if (!symbol->GetName().GetStringRef().starts_with("OUTLINED_FUNCTION_"))
275 return false;
276
277 // Only a call to the helper's entry can be followed; the symbol lookup above
278 // also matches addresses inside it.
279 Address helper_addr = symbol->GetAddress();
280 if (helper_addr.GetFileAddress() != func_addr.GetFileAddress())
281 return false;
282
283 SectionSP section_sp = helper_addr.GetSection();
284 if (!section_sp)
285 return false;
286
287 const size_t byte_size = symbol->GetByteSize();
288 std::vector<uint8_t> text(byte_size);
289 if (section_sp->GetSectionData(text.data(), byte_size,
290 helper_addr.GetOffset()) != byte_size)
291 return false;
292
294 m_arch, nullptr, nullptr, nullptr, nullptr, helper_addr, text.data(),
295 text.size(), 99999, /*data_from_file=*/true));
296 if (!disasm_sp)
297 return false;
298 InstructionList &insts = disasm_sp->GetInstructionList();
299 const size_t num_insts = insts.GetSize();
300 if (num_insts == 0)
301 return false;
302
303 // Only straight-line outlined functions are supported.
304 for (size_t i = 0; i + 1 < num_insts; ++i)
305 if (insts.GetInstructionAtIndex(i)->DoesBranch())
306 return false;
307 // The last instruction should be a return back to the caller.
308 if (!insts.GetInstructionAtIndex(num_insts - 1)->DoesBranch())
309 return false;
310
311 for (size_t i = 0; i + 1 < num_insts; ++i) {
312 Instruction &inst = *insts.GetInstructionAtIndex(i);
313 m_inst_emulator_up->SetInstruction(inst.GetOpcode(), inst.GetAddress(),
314 nullptr);
315 m_inst_emulator_up->EvaluateInstruction(
316 eEmulateInstructionOptionIgnoreConditions);
317 }
318
319 LLDB_LOGF(GetLog(LLDBLog::Unwind), "followed outlined function %s",
320 symbol->GetName().AsCString(""));
321 return true;
322}
323
325 AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
326 return false;
327}
328
330 Thread &thread,
331 UnwindPlan &unwind_plan) {
332 return false;
333}
334
336 AddressRange &func, const ExecutionContext &exe_ctx,
337 Address &first_non_prologue_insn) {
338 return false;
339}
340
343 std::unique_ptr<EmulateInstruction> inst_emulator_up(
345 nullptr));
346 // Make sure that all prologue instructions are handled
347 if (inst_emulator_up)
348 return new UnwindAssemblyInstEmulation(arch, inst_emulator_up.release());
349 return nullptr;
350}
351
356
360
362 return "Instruction emulation based unwind information.";
363}
364
366 const RegisterInfo &reg_info) {
367 lldb::RegisterKind reg_kind;
368 uint32_t reg_num;
370 reg_num))
371 return (uint64_t)reg_kind << 24 | reg_num;
372 return 0ull;
373}
374
376 const RegisterInfo &reg_info, const RegisterValue &reg_value) {
377 m_state.register_values[MakeRegisterKindValuePair(reg_info)] = reg_value;
378}
379
381 RegisterValue &reg_value) {
382 const uint64_t reg_id = MakeRegisterKindValuePair(reg_info);
383 RegisterValueMap::const_iterator pos = m_state.register_values.find(reg_id);
384 if (pos != m_state.register_values.end()) {
385 reg_value = pos->second;
386 return true; // We had a real value that comes from an opcode that wrote
387 // to it...
388 }
389 // We are making up a value that is recognizable...
390 reg_value.SetUInt(reg_id, reg_info.byte_size);
391 return false;
392}
393
395 EmulateInstruction *instruction, void *baton,
396 const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,
397 size_t dst_len) {
398 Log *log = GetLog(LLDBLog::Unwind);
399
400 if (log && log->GetVerbose()) {
401 StreamString strm;
402 strm.Printf(
403 "UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64
404 ", dst = %p, dst_len = %" PRIu64 ", context = ",
405 addr, dst, (uint64_t)dst_len);
406 context.Dump(strm, instruction);
407 log->PutString(strm.GetString());
408 }
409 memset(dst, 0, dst_len);
410 return dst_len;
411}
412
414 EmulateInstruction *instruction, void *baton,
415 const EmulateInstruction::Context &context, lldb::addr_t addr,
416 const void *dst, size_t dst_len) {
417 if (baton && dst && dst_len)
418 return ((UnwindAssemblyInstEmulation *)baton)
419 ->WriteMemory(instruction, context, addr, dst, dst_len);
420 return 0;
421}
422
424 EmulateInstruction *instruction, const EmulateInstruction::Context &context,
425 lldb::addr_t addr, const void *dst, size_t dst_len) {
426 DataExtractor data(dst, dst_len,
427 instruction->GetArchitecture().GetByteOrder(),
428 instruction->GetArchitecture().GetAddressByteSize());
429
430 Log *log = GetLog(LLDBLog::Unwind);
431
432 if (log && log->GetVerbose()) {
433 StreamString strm;
434
435 strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory (");
436 DumpDataExtractor(data, &strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX,
437 addr, 0, 0);
438 strm.PutCString(", context = ");
439 context.Dump(strm, instruction);
440 log->PutString(strm.GetString());
441 }
442
443 switch (context.type) {
444 default:
464 break;
465
467 uint32_t reg_num = LLDB_INVALID_REGNUM;
468 uint32_t generic_regnum = LLDB_INVALID_REGNUM;
469 assert(context.GetInfoType() ==
471 "unhandled case, add code to handle this!");
472 const RegisterInfo &data_reg =
474 const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
475 reg_num = data_reg.kinds[unwind_reg_kind];
476 generic_regnum = data_reg.kinds[eRegisterKindGeneric];
477
478 // Only a register that still holds the value it had on entry to the
479 // function should be saved, otherwise we would be recording the location of
480 // a local.
481 const bool holds_entry_value =
482 m_state.register_values.count(MakeRegisterKindValuePair(data_reg)) == 0;
483
484 if (reg_num != LLDB_INVALID_REGNUM &&
485 generic_regnum != LLDB_REGNUM_GENERIC_SP && holds_entry_value) {
486 if (m_pushed_regs.try_emplace(reg_num, addr).second) {
487 const int32_t offset = addr - m_initial_cfa;
488 m_state.row.SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
489 /*can_replace=*/true);
490 m_curr_row_modified = true;
491 }
492 }
493 } break;
494 }
495
496 return dst_len;
497}
498
500 void *baton,
501 const RegisterInfo *reg_info,
502 RegisterValue &reg_value) {
503
504 if (baton && reg_info)
505 return ((UnwindAssemblyInstEmulation *)baton)
506 ->ReadRegister(instruction, reg_info, reg_value);
507 return false;
508}
510 const RegisterInfo *reg_info,
511 RegisterValue &reg_value) {
512 bool synthetic = GetRegisterValue(*reg_info, reg_value);
513
514 Log *log = GetLog(LLDBLog::Unwind);
515
516 if (log && log->GetVerbose()) {
517
518 StreamString strm;
519 strm.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => "
520 "synthetic_value = %i, value = ",
521 reg_info->name, synthetic);
522 DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault);
523 log->PutString(strm.GetString());
524 }
525 return true;
526}
527
529 EmulateInstruction *instruction, void *baton,
530 const EmulateInstruction::Context &context, const RegisterInfo *reg_info,
531 const RegisterValue &reg_value) {
532 if (baton && reg_info)
533 return ((UnwindAssemblyInstEmulation *)baton)
534 ->WriteRegister(instruction, context, reg_info, reg_value);
535 return false;
536}
538 EmulateInstruction *instruction, const EmulateInstruction::Context &context,
539 const RegisterInfo *reg_info, const RegisterValue &reg_value) {
540 Log *log = GetLog(LLDBLog::Unwind);
541
542 if (log && log->GetVerbose()) {
543
544 StreamString strm;
545 strm.Printf(
546 "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",
547 reg_info->name);
548 DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault);
549 strm.PutCString(", context = ");
550 context.Dump(strm, instruction);
551 log->PutString(strm.GetString());
552 }
553
554 SetRegisterValue(*reg_info, reg_value);
555
556 switch (context.type) {
572 // {
573 // const uint32_t reg_num =
574 // reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
575 // if (reg_num != LLDB_INVALID_REGNUM)
576 // {
577 // const bool can_replace_only_if_unspecified = true;
578 //
579 // m_curr_row.SetRegisterLocationToUndefined (reg_num,
580 // can_replace_only_if_unspecified,
581 // can_replace_only_if_unspecified);
582 // m_curr_row_modified = true;
583 // }
584 // }
585 break;
586
588 // If we adjusted the current frame pointer by a constant then adjust the
589 // CFA offset
590 // with the same amount.
591 lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind();
592 if (m_state.fp_is_cfa &&
593 reg_info->kinds[kind] == m_state.cfa_reg_info.kinds[kind] &&
594 context.GetInfoType() ==
596 context.info.RegisterPlusOffset.reg.kinds[kind] ==
597 m_state.cfa_reg_info.kinds[kind]) {
598 const int64_t offset = context.info.RegisterPlusOffset.signed_offset;
599 m_state.row.GetCFAValue().IncOffset(-1 * offset);
600 m_curr_row_modified = true;
601 }
602 } break;
603
606 // If the instruction writes to the return address register, this is a
607 // function call.
609 m_branch_is_call = true;
611 context.info.ISAAndImmediate.unsigned_data32 != 0) {
613 } else if (context.GetInfoType() ==
617 } else if (context.GetInfoType() ==
619 context.info.unsigned_immediate != 0) {
621 } else if (context.GetInfoType() ==
623 context.info.signed_immediate != 0) {
625 }
626 } break;
627
629 const uint32_t reg_num =
630 reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
631 const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
632 if (reg_num != LLDB_INVALID_REGNUM &&
633 generic_regnum != LLDB_REGNUM_GENERIC_SP) {
634 switch (context.GetInfoType()) {
636 if (auto it = m_pushed_regs.find(reg_num);
637 it != m_pushed_regs.end() && context.info.address == it->second) {
638 m_state.row.SetRegisterLocationToSame(reg_num,
639 false /*must_replace*/);
640 m_curr_row_modified = true;
641
642 // FP has been restored to its original value, we are back
643 // to using SP to calculate the CFA.
644 if (m_state.fp_is_cfa) {
645 m_state.fp_is_cfa = false;
647 uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP;
648 RegisterInfo sp_reg_info =
649 *m_inst_emulator_up->GetRegisterInfo(sp_reg_kind, sp_reg_num);
650 RegisterValue sp_reg_val;
651 if (GetRegisterValue(sp_reg_info, sp_reg_val)) {
652 m_state.cfa_reg_info = sp_reg_info;
653 const uint32_t cfa_reg_num =
654 sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()];
655 assert(cfa_reg_num != LLDB_INVALID_REGNUM);
656 m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
657 cfa_reg_num, m_initial_cfa - sp_reg_val.GetAsUInt64());
658 }
659 }
660 }
661 break;
663 assert(
664 (generic_regnum == LLDB_REGNUM_GENERIC_PC ||
665 generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) &&
666 "eInfoTypeISA used for popping a register other the PC/FLAGS");
667 if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) {
668 m_state.row.SetRegisterLocationToSame(reg_num,
669 false /*must_replace*/);
670 m_curr_row_modified = true;
671 }
672 break;
673 default:
674 assert(false && "unhandled case, add code to handle this!");
675 break;
676 }
677 }
678 } break;
679
681 if (!m_state.fp_is_cfa) {
682 m_state.fp_is_cfa = true;
683 m_state.cfa_reg_info = *reg_info;
684 const uint32_t cfa_reg_num =
685 reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
686 assert(cfa_reg_num != LLDB_INVALID_REGNUM);
687 m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
688 cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
689 m_curr_row_modified = true;
690 }
691 break;
692
694 if (m_state.fp_is_cfa) {
695 m_state.fp_is_cfa = false;
696 m_state.cfa_reg_info = *reg_info;
697 const uint32_t cfa_reg_num =
698 reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
699 assert(cfa_reg_num != LLDB_INVALID_REGNUM);
700 m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
701 cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
702 m_curr_row_modified = true;
703 }
704 break;
705
707 // If we have created a frame using the frame pointer, don't follow
708 // subsequent adjustments to the stack pointer.
709 if (!m_state.fp_is_cfa) {
710 m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
711 m_state.row.GetCFAValue().GetRegisterNumber(),
712 m_initial_cfa - reg_value.GetAsUInt64());
713 m_curr_row_modified = true;
714 }
715 break;
716 }
717 return true;
718}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:389
#define LLDB_PLUGIN_DEFINE(PluginName)
static void DumpInstToLog(Log *log, Instruction &inst, const InstructionList &inst_list)
static void DumpUnwindRowsToLog(Log *log, AddressRange range, const UnwindPlan &unwind_plan)
bool GetRegisterValue(const lldb_private::RegisterInfo &reg_info, lldb_private::RegisterValue &reg_value)
static llvm::StringRef GetPluginNameStatic()
bool GetFastUnwindPlan(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
std::unique_ptr< lldb_private::EmulateInstruction > m_inst_emulator_up
lldb_private::UnwindPlan * m_unwind_plan_ptr
static size_t WriteMemory(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::EmulateInstruction::Context &context, lldb::addr_t addr, const void *dst, size_t length)
static bool WriteRegister(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::EmulateInstruction::Context &context, const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &reg_value)
static llvm::StringRef GetPluginDescriptionStatic()
bool AugmentUnwindPlanFromCallSite(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
static size_t ReadMemory(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, size_t length)
lldb_private::AddressRange * m_range_ptr
static bool ReadRegister(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &reg_value)
static uint64_t MakeRegisterKindValuePair(const lldb_private::RegisterInfo &reg_info)
static lldb_private::UnwindAssembly * CreateInstance(const lldb_private::ArchSpec &arch)
bool GetNonCallSiteUnwindPlanFromAssembly(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
void SetRegisterValue(const lldb_private::RegisterInfo &reg_info, const lldb_private::RegisterValue &reg_value)
bool EmulateOutlinedFunction(lldb_private::Address func_addr)
Follow a call into a compiler-outlined helper and emulate its body in the caller's state.
UnwindAssemblyInstEmulation(const lldb_private::ArchSpec &arch, lldb_private::EmulateInstruction *inst_emulator)
bool FirstNonPrologueInsn(lldb_private::AddressRange &func, const lldb_private::ExecutionContext &exe_ctx, lldb_private::Address &first_non_prologue_insn) override
A section + offset based address range class.
Address & GetBaseAddress()
Get accessor for the base address of the range.
bool ContainsFileAddress(const Address &so_addr) const
Check if a section offset address is contained in this range.
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
A section + offset based address class.
Definition Address.h:62
lldb::SectionSP GetSection() const
Get const accessor for the section.
Definition Address.h:426
bool Slide(int64_t offset)
Definition Address.h:446
lldb::addr_t GetFileAddress() const
Get the file address.
Definition Address.cpp:283
lldb::addr_t GetOffset() const
Get the section relative offset value.
Definition Address.h:329
bool IsValid() const
Check if the object state is valid.
Definition Address.h:355
Symbol * CalculateSymbolContextSymbol() const
Definition Address.cpp:888
An architecture specification class.
Definition ArchSpec.h:32
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition ArchSpec.cpp:891
lldb::ByteOrder GetByteOrder() const
Returns the byte order for the architecture specification.
Definition ArchSpec.cpp:940
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
const char * AsCString(const char *value_if_empty) const
Get the string value as a C string.
An data extractor class.
static lldb::DisassemblerSP DisassembleBytes(const ArchSpec &arch, const char *plugin_name, const char *flavor, const char *cpu, const char *features, const Address &start, const void *bytes, size_t length, uint32_t max_num_instructions, bool data_from_file)
"lldb/Core/EmulateInstruction.h" A class that allows emulation of CPU opcodes.
static bool GetBestRegisterKindAndNumber(const RegisterInfo *reg_info, lldb::RegisterKind &reg_kind, uint32_t &reg_num)
const ArchSpec & GetArchitecture() const
static const InstructionCondition UnconditionalCondition
static EmulateInstruction * FindPlugin(const ArchSpec &arch, InstructionType supported_inst_type, const char *plugin_name)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
uint32_t GetIndexOfInstructionAtAddress(const Address &addr)
lldb::InstructionSP GetInstructionAtIndex(size_t idx) const
uint32_t GetMaxOpcocdeByteSize() const
const Address & GetAddress() const
const Opcode & GetOpcode() const
virtual bool IsBarrier()=0
virtual void Dump(Stream *s, uint32_t max_opcode_byte_size, bool show_address, bool show_bytes, bool show_control_flow_kind, const ExecutionContext *exe_ctx, const SymbolContext *sym_ctx, const SymbolContext *prev_sym_ctx, const FormatEntity::Entry *disassembly_addr_format, size_t max_address_text_size)
Dump the text representation of this Instruction to a Stream.
bool GetVerbose() const
Definition Log.cpp:329
void PutString(llvm::StringRef str)
Definition Log.cpp:164
uint32_t GetByteSize() const
Definition Opcode.h:236
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
bool SetUInt(uint64_t uint, uint32_t byte_size)
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
An error handling class.
Definition Status.h:118
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
lldb::addr_t GetByteSize() const
Definition Symbol.cpp:469
ConstString GetName() const
Definition Symbol.cpp:612
Address GetAddress() const
Definition Symbol.h:98
uint32_t GetInitialCFARegister() const
Definition UnwindPlan.h:471
void InsertRow(Row row, bool replace_existing=false)
lldb::RegisterKind GetRegisterKind() const
Definition UnwindPlan.h:461
const UnwindPlan::Row * GetLastRow() const
void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const
#define LLDB_REGNUM_GENERIC_RA
#define LLDB_REGNUM_GENERIC_SP
#define LLDB_REGNUM_GENERIC_FLAGS
#define UINT32_MAX
#define LLDB_INVALID_REGNUM
#define LLDB_REGNUM_GENERIC_PC
Status Parse(const llvm::StringRef &format, Entry &entry)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
void DumpRegisterValue(const RegisterValue &reg_val, Stream &s, const RegisterInfo &reg_info, bool prefix_with_name, bool prefix_with_alt_name, lldb::Format format, uint32_t reg_name_right_align_at=0, ExecutionContextScope *exe_scope=nullptr, bool print_type=false, lldb::TargetSP target_sp=nullptr)
lldb::offset_t DumpDataExtractor(const DataExtractor &DE, Stream *s, lldb::offset_t offset, lldb::Format item_format, size_t item_byte_size, size_t item_count, size_t num_per_line, uint64_t base_addr, uint32_t item_bit_size, uint32_t item_bit_offset, ExecutionContextScope *exe_scope=nullptr, bool show_memory_tags=false)
Dumps item_count objects into the stream s.
std::shared_ptr< lldb_private::Disassembler > DisassemblerSP
std::shared_ptr< lldb_private::Section > SectionSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP
RegisterKind
Register numbering types.
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
void Dump(Stream &s, EmulateInstruction *instruction) const
union lldb_private::EmulateInstruction::Context::ContextInfo info
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.
const char * name
Name of this register, can't be NULL.
struct lldb_private::EmulateInstruction::Context::ContextInfo::ISAAndImmediateSigned ISAAndImmediateSigned
struct lldb_private::EmulateInstruction::Context::ContextInfo::RegisterPlusOffset RegisterPlusOffset
struct lldb_private::EmulateInstruction::Context::ContextInfo::RegisterToRegisterPlusOffset RegisterToRegisterPlusOffset
struct lldb_private::EmulateInstruction::Context::ContextInfo::ISAAndImmediate ISAAndImmediate